darkfi 2 лет назад
Родитель
Сommit
0bcd7d9386
3 измененных файлов с 118 добавлено и 7 удалено
  1. 44 0
      bin/darkwallet/src/app.rs
  2. 3 0
      bin/darkwallet/src/mesh.rs
  3. 71 7
      bin/darkwallet/src/ui/chatview.rs

+ 44 - 0
bin/darkwallet/src/app.rs

@@ -569,6 +569,35 @@ impl App {
         node.set_property_f32("baseline", 10.).unwrap();
         node.set_property_f32("baseline", 10.).unwrap();
         node.set_property_u32("z_index", 1).unwrap();
         node.set_property_u32("z_index", 1).unwrap();
 
 
+        let prop = node.get_property("timestamp_color").unwrap();
+        prop.set_f32(0, 0.5).unwrap();
+        prop.set_f32(1, 0.5).unwrap();
+        prop.set_f32(2, 0.5).unwrap();
+        prop.set_f32(3, 0.5).unwrap();
+        let prop = node.get_property("text_color").unwrap();
+        prop.set_f32(0, 1.).unwrap();
+        prop.set_f32(1, 1.).unwrap();
+        prop.set_f32(2, 1.).unwrap();
+        prop.set_f32(3, 1.).unwrap();
+
+        let prop = node.get_property("nick_colors").unwrap();
+        #[rustfmt::skip]
+        let nick_colors = [
+            0.00, 0.94, 1.00, 1.,
+            0.36, 1.00, 0.69, 1.,
+            0.29, 1.00, 0.45, 1.,
+            0.00, 0.73, 0.38, 1.,
+            0.21, 0.67, 0.67, 1.,
+            0.56, 0.61, 1.00, 1.,
+            0.84, 0.48, 1.00, 1.,
+            1.00, 0.61, 0.94, 1.,
+            1.00, 0.36, 0.48, 1.,
+            1.00, 0.30, 0.00, 1.
+        ];
+        for c in nick_colors {
+            prop.push_f32(c).unwrap();
+        }
+
         drop(sg);
         drop(sg);
         let db = sled::open(CHATDB_PATH).expect("cannot open sleddb");
         let db = sled::open(CHATDB_PATH).expect("cannot open sleddb");
         let chat_tree = db.open_tree(b"chat").unwrap();
         let chat_tree = db.open_tree(b"chat").unwrap();
@@ -793,6 +822,21 @@ fn create_chatview(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
     let prop = Property::new("line_height", PropertyType::Float32, PropertySubType::Pixel);
     let prop = Property::new("line_height", PropertyType::Float32, PropertySubType::Pixel);
     node.add_property(prop).unwrap();
     node.add_property(prop).unwrap();
 
 
+    let mut prop = Property::new("timestamp_color", PropertyType::Float32, PropertySubType::Color);
+    prop.set_array_len(4);
+    prop.set_range_f32(0., 1.);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("text_color", PropertyType::Float32, PropertySubType::Color);
+    prop.set_array_len(4);
+    prop.set_range_f32(0., 1.);
+    node.add_property(prop).unwrap();
+
+    let mut prop = Property::new("nick_colors", PropertyType::Float32, PropertySubType::Pixel);
+    prop.set_unbounded();
+    prop.set_range_f32(0., 1.);
+    node.add_property(prop).unwrap();
+
     let prop = Property::new("baseline", PropertyType::Float32, PropertySubType::Pixel);
     let prop = Property::new("baseline", PropertyType::Float32, PropertySubType::Pixel);
     node.add_property(prop).unwrap();
     node.add_property(prop).unwrap();
 
 

+ 3 - 0
bin/darkwallet/src/mesh.rs

@@ -26,9 +26,12 @@ pub type Color = [f32; 4];
 
 
 pub const COLOR_RED: Color = [1., 0., 0., 1.];
 pub const COLOR_RED: Color = [1., 0., 0., 1.];
 pub const COLOR_DARKGREY: Color = [0.2, 0.2, 0.2, 1.];
 pub const COLOR_DARKGREY: Color = [0.2, 0.2, 0.2, 1.];
+pub const COLOR_LIGHTGREY: Color = [0.7, 0.7, 0.7, 1.];
 pub const COLOR_GREEN: Color = [0., 1., 0., 1.];
 pub const COLOR_GREEN: Color = [0., 1., 0., 1.];
 pub const COLOR_BLUE: Color = [0., 0., 1., 1.];
 pub const COLOR_BLUE: Color = [0., 0., 1., 1.];
 pub const COLOR_WHITE: Color = [1., 1., 1., 1.];
 pub const COLOR_WHITE: Color = [1., 1., 1., 1.];
+pub const COLOR_BLACK: Color = [1., 1., 1., 1.];
+pub const COLOR_GREY: Color = [0.5, 0.5, 0.5, 1.];
 
 
 #[derive(Clone)]
 #[derive(Clone)]
 pub struct MeshInfo {
 pub struct MeshInfo {

+ 71 - 7
bin/darkwallet/src/ui/chatview.rs

@@ -21,6 +21,7 @@ use miniquad::TouchPhase;
 use rand::{rngs::OsRng, Rng};
 use rand::{rngs::OsRng, Rng};
 use std::{
 use std::{
     collections::BTreeMap,
     collections::BTreeMap,
+    hash::{DefaultHasher, Hash, Hasher},
     sync::{Arc, Mutex as SyncMutex, Weak},
     sync::{Arc, Mutex as SyncMutex, Weak},
 };
 };
 
 
@@ -30,7 +31,7 @@ use crate::{
         DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, Point, Rectangle,
         DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, Point, Rectangle,
         RenderApi, RenderApiPtr, Vertex,
         RenderApi, RenderApiPtr, Vertex,
     },
     },
-    mesh::{Color, MeshBuilder, MeshInfo, COLOR_BLUE, COLOR_WHITE},
+    mesh::{Color, MeshBuilder, MeshInfo, COLOR_BLUE, COLOR_GREY, COLOR_WHITE},
     prop::{
     prop::{
         PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr, PropertyUint32,
         PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr, PropertyUint32,
     },
     },
@@ -44,6 +45,10 @@ use super::{eval_rect, get_parent_rect, read_rect, DrawUpdate, OnModify, Stoppab
 
 
 const DEBUG_RENDER: bool = false;
 const DEBUG_RENDER: bool = false;
 
 
+fn is_whitespace(s: &str) -> bool {
+    s.chars().all(char::is_whitespace)
+}
+
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 pub struct ChatMsg {
 pub struct ChatMsg {
     pub nick: String,
     pub nick: String,
@@ -104,6 +109,9 @@ pub struct ChatView {
     font_size: PropertyFloat32,
     font_size: PropertyFloat32,
     line_height: PropertyFloat32,
     line_height: PropertyFloat32,
     baseline: PropertyFloat32,
     baseline: PropertyFloat32,
+    timestamp_color: PropertyColor,
+    text_color: PropertyColor,
+    nick_colors: PropertyPtr,
     z_index: PropertyUint32,
     z_index: PropertyUint32,
 }
 }
 
 
@@ -126,7 +134,10 @@ impl ChatView {
         let scroll = PropertyFloat32::wrap(node, "scroll", 0).unwrap();
         let scroll = PropertyFloat32::wrap(node, "scroll", 0).unwrap();
         let font_size = PropertyFloat32::wrap(node, "font_size", 0).unwrap();
         let font_size = PropertyFloat32::wrap(node, "font_size", 0).unwrap();
         let line_height = PropertyFloat32::wrap(node, "line_height", 0).unwrap();
         let line_height = PropertyFloat32::wrap(node, "line_height", 0).unwrap();
-        let baseline = PropertyFloat32::wrap(node, "line_height", 0).unwrap();
+        let baseline = PropertyFloat32::wrap(node, "baseline", 0).unwrap();
+        let timestamp_color = PropertyColor::wrap(node, "timestamp_color").unwrap();
+        let text_color = PropertyColor::wrap(node, "text_color").unwrap();
+        let nick_colors = node.get_property("nick_colors").expect("ChatView::nick_colors");
         let z_index = PropertyUint32::wrap(node, "z_index", 0).unwrap();
         let z_index = PropertyUint32::wrap(node, "z_index", 0).unwrap();
 
 
         drop(scene_graph);
         drop(scene_graph);
@@ -188,6 +199,9 @@ impl ChatView {
                 font_size,
                 font_size,
                 line_height,
                 line_height,
                 baseline,
                 baseline,
+                timestamp_color,
+                text_color,
+                nick_colors,
                 z_index,
                 z_index,
             }
             }
         });
         });
@@ -252,7 +266,7 @@ impl ChatView {
         debug!(target: "ui::chatview", "inside rect");
         debug!(target: "ui::chatview", "inside rect");
         let scroll = self.scroll.get();
         let scroll = self.scroll.get();
         self.scroll.set(scroll + wheel_y * 50.);
         self.scroll.set(scroll + wheel_y * 50.);
-        // Render will auto update from on_modify hook
+        self.scrollview().await;
     }
     }
 
 
     async fn handle_mouse_move(&self, mouse_x: f32, mouse_y: f32) {
     async fn handle_mouse_move(&self, mouse_x: f32, mouse_y: f32) {
@@ -460,35 +474,63 @@ impl ChatView {
         let mut draws = vec![];
         let mut draws = vec![];
         let color = COLOR_WHITE;
         let color = COLOR_WHITE;
 
 
+        let timestamp_color = self.timestamp_color.get();
+        let text_color = self.text_color.get();
+        let nick_colors = self.read_nick_colors();
+
         // This is a little hack to nudge the bottom line up slightly, otherwise
         // This is a little hack to nudge the bottom line up slightly, otherwise
         // chars like p will cross the bottom.
         // chars like p will cross the bottom.
-        let descent = line_height / 2.;
+        let descent = baseline / 2.;
 
 
         // Pages start at the bottom.
         // Pages start at the bottom.
-        let mut current_idx = 1;
+        let mut current_idx = 0;
         'pageloop: for page in pages {
         'pageloop: for page in pages {
             let mut mesh = MeshBuilder::new();
             let mut mesh = MeshBuilder::new();
 
 
             for msg in page.msgs {
             for msg in page.msgs {
                 let glyphs = msg.glyphs;
                 let glyphs = msg.glyphs;
 
 
+                let nick_color = self.select_nick_color(&msg.chatmsg.nick, &nick_colors);
+
+                // Keep track of the 'section'
+                // Section 0 is the timestamp
+                // Section 1 is the nickname (colorized)
+                // Finally is just the message itself
+                let mut section = 2;
+
                 let mut lines = text2::wrap(clip.w, font_size, &glyphs);
                 let mut lines = text2::wrap(clip.w, font_size, &glyphs);
                 // We are drawing bottom up but line wrap gives us lines in normal order
                 // We are drawing bottom up but line wrap gives us lines in normal order
                 lines.reverse();
                 lines.reverse();
-                for line in lines {
-                    let off_y = descent + current_idx as f32 * line_height;
+                let last_idx = lines.len() - 1;
+                for (i, line) in lines.into_iter().enumerate() {
+                    let off_y = descent + baseline + current_idx as f32 * line_height;
 
 
                     //if px_height > clip.h {
                     //if px_height > clip.h {
                     //    break 'pageloop;
                     //    break 'pageloop;
                     //}
                     //}
 
 
+                    if i == last_idx {
+                        section = 0;
+                    }
+
                     // Render line
                     // Render line
                     let mut glyph_pos_iter = GlyphPositionIter::new(font_size, &line, baseline);
                     let mut glyph_pos_iter = GlyphPositionIter::new(font_size, &line, baseline);
                     for (mut glyph_rect, glyph) in glyph_pos_iter.zip(line.iter()) {
                     for (mut glyph_rect, glyph) in glyph_pos_iter.zip(line.iter()) {
                         let uv_rect =
                         let uv_rect =
                             page.atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
                             page.atlas.fetch_uv(glyph.glyph_id).expect("missing glyph UV rect");
                         glyph_rect.y -= off_y;
                         glyph_rect.y -= off_y;
+
+                        let color = match section {
+                            0 => timestamp_color,
+                            1 => nick_color,
+                            _ => text_color,
+                        };
+
                         mesh.draw_box(&glyph_rect, color, uv_rect);
                         mesh.draw_box(&glyph_rect, color, uv_rect);
+
+                        if section < 2 && is_whitespace(&glyph.substr) {
+                            section += 1;
+                        }
                     }
                     }
 
 
                     current_idx += 1;
                     current_idx += 1;
@@ -524,6 +566,28 @@ impl ChatView {
         draws
         draws
     }
     }
 
 
+    fn read_nick_colors(&self) -> Vec<Color> {
+        let mut colors = vec![];
+        let mut color = [0f32; 4];
+        for i in 0..self.nick_colors.get_len() {
+            color[i % 4] = self.nick_colors.get_f32(i).expect("prop logic err");
+
+            if i > 0 && i % 4 == 0 {
+                let color = std::mem::take(&mut color);
+                colors.push(color);
+            }
+        }
+        colors
+    }
+
+    fn select_nick_color(&self, nick: &str, nick_colors: &[Color]) -> Color {
+        let mut hasher = DefaultHasher::new();
+        nick.hash(&mut hasher);
+        let i = hasher.finish() as usize;
+        let color = nick_colors[i % nick_colors.len()];
+        color
+    }
+
     pub async fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle) -> Option<DrawUpdate> {
     pub async fn draw(&self, sg: &SceneGraph, parent_rect: &Rectangle) -> Option<DrawUpdate> {
         debug!(target: "ui::chatview", "ChatView::draw()");
         debug!(target: "ui::chatview", "ChatView::draw()");
         // Only used for debug messages
         // Only used for debug messages