Просмотр исходного кода

wallet: add new schema with various vector iconography and new theming for next release

darkfi 1 год назад
Родитель
Сommit
c54590e369

+ 28 - 0
bin/darkwallet/data/back-arrow.obj

@@ -0,0 +1,28 @@
+# Blender 4.3.1
+# www.blender.org
+mtllib back_arrow.mtl
+o back_arrow
+v -0.877643 0.000000 -0.031110
+v 0.992314 0.000000 -0.031110
+v -0.993081 0.000000 0.000168
+v -0.154072 0.000000 -0.752301
+v -0.198105 0.000000 -0.794808
+v -0.877643 0.000000 0.031110
+v 0.992314 0.000000 0.031110
+v -0.993081 0.000000 -0.000168
+v -0.154072 0.000000 0.752301
+v -0.198105 0.000000 0.794808
+vn -0.0000 1.0000 -0.0000
+vn -0.0000 -1.0000 -0.0000
+vt 0.000000 1.000000
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+s 0
+f 1/1/1 5/2/1 3/2/1
+f 2/3/2 6/1/2 1/2/2
+f 1/2/2 6/1/2 8/2/2
+f 6/1/2 10/2/2 8/2/2
+f 1/1/1 4/1/1 5/2/1
+f 2/3/2 7/4/2 6/1/2
+f 6/1/2 9/1/2 10/2/2

+ 161 - 0
bin/darkwallet/data/emoji-selector.obj

@@ -0,0 +1,161 @@
+# Blender 4.3.1
+# www.blender.org
+mtllib emoji-selector.mtl
+o emoji_selector
+v -0.299137 0.000000 -0.077869
+v -0.247956 0.000000 -0.006422
+v -0.258195 0.000000 -0.252576
+v -0.192966 0.000000 -0.231704
+v -0.234915 0.000000 -0.415540
+v -0.164066 0.000000 -0.441229
+v -0.408315 0.000000 -0.607404
+v -0.377605 0.000000 -0.675640
+v -0.675640 0.000000 -0.615431
+v -0.705138 0.000000 -0.685273
+v -0.910051 0.000000 -0.364965
+v -0.983702 0.000000 -0.390654
+v -0.861884 0.000000 -0.187551
+v -0.941957 0.000000 -0.212437
+v -0.816929 0.000000 -0.085598
+v -0.871313 0.000000 -0.035826
+v -0.756720 0.000000 -0.048670
+v -0.809499 0.000000 -0.004518
+v -0.750298 0.000000 -0.045459
+v -0.796655 0.000000 0.025185
+v -0.342487 0.000000 -0.045459
+v -0.302946 0.000000 0.023580
+v -0.324826 0.000000 -0.073557
+v -0.285285 0.000000 -0.004518
+v 0.294399 0.000000 -0.075557
+v 0.243218 0.000000 -0.004110
+v 0.253458 0.000000 -0.250264
+v 0.188228 0.000000 -0.229392
+v 0.230177 0.000000 -0.413228
+v 0.159328 0.000000 -0.438917
+v 0.403577 0.000000 -0.605092
+v 0.372867 0.000000 -0.673328
+v 0.670902 0.000000 -0.613119
+v 0.700400 0.000000 -0.682961
+v 0.905313 0.000000 -0.362653
+v 0.978964 0.000000 -0.388342
+v 0.857147 0.000000 -0.185239
+v 0.937220 0.000000 -0.210125
+v 0.812191 0.000000 -0.083286
+v 0.866575 0.000000 -0.033514
+v 0.751983 0.000000 -0.046358
+v 0.804761 0.000000 -0.002206
+v 0.745560 0.000000 -0.043147
+v 0.791917 0.000000 0.027497
+v 0.337749 0.000000 -0.043147
+v 0.298209 0.000000 0.025892
+v 0.320088 0.000000 -0.071245
+v 0.280548 0.000000 -0.002206
+v -0.260481 0.000000 0.280672
+v -0.302414 0.000000 0.210381
+v -0.312982 0.000000 0.409139
+v -0.378212 0.000000 0.390579
+v -0.348979 0.000000 0.551295
+v -0.423296 0.000000 0.571204
+v -0.115467 0.000000 0.815986
+v -0.146177 0.000000 0.883066
+v 0.113710 0.000000 0.813610
+v 0.144364 0.000000 0.885764
+v 0.342181 0.000000 0.557428
+v 0.419043 0.000000 0.572681
+v 0.313950 0.000000 0.417031
+v 0.378413 0.000000 0.390629
+v 0.256172 0.000000 0.276612
+v 0.299407 0.000000 0.207885
+v 0.204883 0.000000 0.276478
+v 0.253760 0.000000 0.206681
+v 0.192886 0.000000 0.245393
+v 0.245375 0.000000 0.175863
+v -0.196323 0.000000 0.245950
+v -0.246267 0.000000 0.175755
+v -0.203580 0.000000 0.278671
+v -0.259304 0.000000 0.205008
+v -0.288443 0.000000 0.349093
+v -0.350323 0.000000 0.309817
+vn -0.0000 1.0000 -0.0000
+vn -0.0000 -1.0000 -0.0000
+vt 0.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 1.000000 0.571062
+vt 0.000000 0.532600
+vt 1.000000 0.000000
+s 0
+f 1/1/1 4/2/1 3/3/1
+f 4/2/1 5/3/1 3/3/1
+f 6/2/1 7/3/1 5/3/1
+f 8/2/1 9/3/1 7/3/1
+f 10/2/1 11/3/1 9/3/1
+f 11/3/1 14/2/1 13/3/1
+f 13/3/1 16/2/1 15/3/1
+f 15/3/1 18/2/1 17/3/1
+f 18/2/1 19/3/1 17/3/1
+f 19/3/1 22/2/1 21/3/1
+f 21/3/1 24/2/1 23/3/1
+f 24/2/1 1/3/1 23/3/1
+f 25/1/2 28/2/2 27/3/2
+f 28/2/2 29/3/2 27/3/2
+f 30/2/2 31/3/2 29/3/2
+f 32/2/2 33/3/2 31/3/2
+f 34/2/2 35/3/2 33/3/2
+f 35/3/2 38/2/2 37/3/2
+f 37/3/2 40/2/2 39/3/2
+f 39/3/2 42/2/2 41/3/2
+f 42/2/2 43/3/2 41/3/2
+f 43/3/2 46/2/2 45/3/2
+f 45/3/2 48/2/2 47/3/2
+f 48/2/2 25/3/2 47/3/2
+f 49/1/1 74/4/1 73/5/1
+f 52/2/1 53/3/1 51/3/1
+f 53/3/1 56/2/1 55/3/1
+f 55/3/1 58/2/1 57/3/1
+f 58/2/1 59/3/1 57/3/1
+f 59/3/1 62/2/1 61/3/1
+f 62/2/1 63/3/1 61/3/1
+f 63/3/1 66/2/1 65/3/1
+f 66/2/1 67/3/1 65/3/1
+f 67/3/1 70/2/1 69/3/1
+f 69/3/1 72/2/1 71/3/1
+f 72/2/1 49/3/1 71/3/1
+f 73/5/1 52/2/1 51/3/1
+f 1/1/1 2/6/1 4/2/1
+f 4/2/1 6/2/1 5/3/1
+f 6/2/1 8/2/1 7/3/1
+f 8/2/1 10/2/1 9/3/1
+f 10/2/1 12/2/1 11/3/1
+f 11/3/1 12/2/1 14/2/1
+f 13/3/1 14/2/1 16/2/1
+f 15/3/1 16/2/1 18/2/1
+f 18/2/1 20/2/1 19/3/1
+f 19/3/1 20/2/1 22/2/1
+f 21/3/1 22/2/1 24/2/1
+f 24/2/1 2/2/1 1/3/1
+f 25/1/2 26/6/2 28/2/2
+f 28/2/2 30/2/2 29/3/2
+f 30/2/2 32/2/2 31/3/2
+f 32/2/2 34/2/2 33/3/2
+f 34/2/2 36/2/2 35/3/2
+f 35/3/2 36/2/2 38/2/2
+f 37/3/2 38/2/2 40/2/2
+f 39/3/2 40/2/2 42/2/2
+f 42/2/2 44/2/2 43/3/2
+f 43/3/2 44/2/2 46/2/2
+f 45/3/2 46/2/2 48/2/2
+f 48/2/2 26/2/2 25/3/2
+f 49/1/1 50/6/1 74/4/1
+f 52/2/1 54/2/1 53/3/1
+f 53/3/1 54/2/1 56/2/1
+f 55/3/1 56/2/1 58/2/1
+f 58/2/1 60/2/1 59/3/1
+f 59/3/1 60/2/1 62/2/1
+f 62/2/1 64/2/1 63/3/1
+f 63/3/1 64/2/1 66/2/1
+f 66/2/1 68/2/1 67/3/1
+f 67/3/1 68/2/1 70/2/1
+f 69/3/1 70/2/1 72/2/1
+f 72/2/1 50/2/1 49/3/1
+f 73/5/1 74/4/1 52/2/1

+ 90 - 0
bin/darkwallet/data/obj_to_rust.py

@@ -0,0 +1,90 @@
+#!/usr/bin/python
+import sys
+
+COLOR = "[0., 1., 1., 1.]"
+
+class Obj:
+
+    def __init__(self, name):
+        self.name = name
+        self.v = []
+        self.f = []
+
+    def push_vert(self, args):
+        assert len(args) == 3
+        (x, y, z) = [float(v) for v in args]
+        assert y == 0
+        vert = (x, z)
+        self.v.append(vert)
+
+    def push_face(self, args):
+        idxs = [arg.split("/")[0] for arg in args]
+        assert len(idxs) == 3
+        idxs = [int(idx) - 1 for idx in idxs]
+        for idx in idxs:
+            assert idx < len(self.v)
+        self.f.extend(idxs)
+
+def parse_obj(fname):
+    objs = []
+    obj = None
+
+    for line in open(fname):
+        line = line.rstrip("\n")
+        if line[0] == '#':
+            continue
+
+        line = line.split(" ")
+        cmd = line[0]
+        args = line[1:]
+
+        match cmd:
+            case 'o':
+                if obj is not None:
+                    objs.append(obj)
+                name = args[0]
+                #print(f"New object {name}")
+                obj = Obj(name)
+                continue
+            case 'v':
+                obj.push_vert(args)
+            case 'f':
+                obj.push_face(args)
+
+            case _:
+                #print(f"Skipping {cmd}: {args}")
+                pass
+
+    if obj is not None:
+        objs.append(obj)
+    return objs
+
+def output(obj):
+    name = obj.name
+    print("use crate::ui::{VectorShape, ShapeVertex};")
+    print(f"pub fn create_{name}() -> VectorShape {{")
+    print("    VectorShape {")
+    print("        verts: vec![")
+    for (x, y) in obj.v:
+        print(f"            ShapeVertex::from_xy({x}, {y}, {COLOR}),")
+    print("        ],")
+    indices = ", ".join([str(f) for f in obj.f])
+    print(f"        indices: vec![{indices}]")
+    print("    }")
+    print("}")
+
+def main(argv):
+    if len(argv) != 2:
+        print("obj_to_rust OBJFILE", file=sys.stderr)
+        return -1
+
+    objs = parse_obj(argv[1])
+
+    for obj in objs:
+        output(obj)
+
+    return 0
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv))
+

+ 19 - 0
bin/darkwallet/data/send-arrow.obj

@@ -0,0 +1,19 @@
+# Blender 4.3.1
+# www.blender.org
+mtllib arrow.mtl
+o arrow
+v -0.763722 0.000000 -0.082607
+v -0.137017 0.000000 0.190169
+v 0.992481 0.000000 -0.087373
+v -0.137017 0.000000 -0.368093
+v -0.934894 0.000000 -0.730526
+v -0.893590 0.000000 0.560546
+vn -0.0000 1.0000 -0.0000
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+s 0
+f 1/1/1 2/2/1 4/3/1
+f 4/3/1 2/2/1 3/3/1
+f 1/1/1 4/3/1 5/1/1
+f 2/2/1 1/1/1 6/2/1

+ 104 - 53
bin/darkwallet/src/app/schema.rs

@@ -26,6 +26,7 @@ use crate::{
     prop::{
         Property, PropertyBool, PropertyFloat32, PropertyStr, PropertySubType, PropertyType, Role,
     },
+    shape,
     scene::{SceneNodePtr, Slot},
     text::TextShaperPtr,
     ui::{
@@ -46,6 +47,10 @@ use super::{
 const LIGHTMODE: bool = false;
 
 mod android_ui_consts {
+    pub const CHANNEL_LABEL_Y: f32 = 90.;
+    pub const BACKARROW_SCALE: f32 = 30.;
+    pub const BACKARROW_X: f32 = 50.;
+    pub const BACKARROW_Y: f32 = 70.;
     pub const EDITCHAT_HEIGHT: f32 = 163.;
     pub const EDITCHAT_BOTTOM_PAD: f32 = 30.;
     pub const EDITCHAT_CURSOR_ASCENT: f32 = 50.;
@@ -56,9 +61,13 @@ mod android_ui_consts {
     pub const EDITCHAT_LINESPACING: f32 = 70.;
     pub const TEXTBAR_BASELINE: f32 = 60.;
     pub const TEXT_DESCENT: f32 = 20.;
-    pub const EDITCHAT_LHS_PAD: f32 = 30.;
+    pub const EMOJI_BTN_X: f32 = 60.;
+    pub const EMOJI_BG_W: f32 = 120.;
+    pub const EMOJI_SCALE: f32 = 40.;
+    pub const EDITCHAT_LHS_PAD: f32 = 150.;
     pub const SENDLABEL_WIDTH: f32 = 200.;
     pub const SENDLABEL_LHS_PAD: f32 = 40.;
+    pub const SEND_BTN_NEG_X: f32 = 50.;
     pub const FONTSIZE: f32 = 40.;
     pub const TIMESTAMP_FONTSIZE: f32 = 30.;
     pub const TIMESTAMP_WIDTH: f32 = 135.;
@@ -91,8 +100,13 @@ mod ui_consts {
     pub const CHATDB_PATH: &str = "chatdb";
     pub const KING_PATH: &str = "assets/king.png";
     pub const BG_PATH: &str = "assets/bg.png";
+
+    pub const CHANNEL_LABEL_Y: f32 = 30.;
+    pub const BACKARROW_SCALE: f32 = 15.;
+    pub const BACKARROW_X: f32 = 38.;
+    pub const BACKARROW_Y: f32 = 23.;
     pub const EDITCHAT_HEIGHT: f32 = 50.;
-    pub const EDITCHAT_BOTTOM_PAD: f32 = 6.;
+    pub const EDITCHAT_BOTTOM_PAD: f32 = 20.;
     pub const EDITCHAT_CURSOR_ASCENT: f32 = 25.;
     pub const EDITCHAT_CURSOR_DESCENT: f32 = 8.;
     pub const EDITCHAT_SELECT_ASCENT: f32 = 30.;
@@ -101,9 +115,13 @@ mod ui_consts {
     pub const EDITCHAT_LINESPACING: f32 = 35.;
     pub const TEXTBAR_BASELINE: f32 = 34.;
     pub const TEXT_DESCENT: f32 = 10.;
-    pub const EDITCHAT_LHS_PAD: f32 = 20.;
+    pub const EMOJI_BTN_X: f32 = 40.;
+    pub const EMOJI_BG_W: f32 = 80.;
+    pub const EMOJI_SCALE: f32 = 20.;
+    pub const EDITCHAT_LHS_PAD: f32 = 100.;
     pub const SENDLABEL_WIDTH: f32 = 120.;
     pub const SENDLABEL_LHS_PAD: f32 = 30.;
+    pub const SEND_BTN_NEG_X: f32 = 50.;
     pub const FONTSIZE: f32 = 20.;
     pub const TIMESTAMP_FONTSIZE: f32 = 12.;
     pub const TIMESTAMP_WIDTH: f32 = 60.;
@@ -123,6 +141,8 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) {
     cc.add_const_f32("EDITCHAT_BOTTOM_PAD", EDITCHAT_BOTTOM_PAD);
     cc.add_const_f32("SENDLABEL_WIDTH", SENDLABEL_WIDTH);
     cc.add_const_f32("SENDLABEL_LHS_PAD", SENDLABEL_LHS_PAD);
+    cc.add_const_f32("SEND_BTN_NEG_X", SEND_BTN_NEG_X);
+    cc.add_const_f32("EMOJI_SCALE", EMOJI_SCALE);
 
     // Main view
     let layer_node = create_layer("view");
@@ -215,18 +235,41 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) {
     shape.add_filled_box(
         expr::const_f32(0.),
         expr::const_f32(0.),
-        expr::load_var("w"),
+        expr::const_f32(EMOJI_BG_W),
         expr::load_var("h"),
-        [0.05, 0.05, 0.05, 1.],
+        [0., 0.11, 0.11, 1.],
     );
     shape.add_filled_box(
+        expr::const_f32(EMOJI_BG_W),
         expr::const_f32(0.),
-        cc.compile("h - 1").unwrap(),
-        expr::load_var("w"),
+        expr::const_f32(EMOJI_BG_W + 1.),
         expr::load_var("h"),
-        [0.4, 0.4, 0.4, 1.],
+        [0.41, 0.6, 0.65, 1.],
     );
+    shape.add_filled_box(
+        expr::const_f32(0.),
+        expr::load_var("h"),
+        expr::load_var("w"),
+        cc.compile("h + 1").unwrap(),
+        [0.41, 0.6, 0.65, 1.],
+    );
+
+    let node =
+        node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
+    layer_node.clone().link(node);
+
+    // Create the send button
+    let node = create_vector_art("back_btn_bg");
+    let prop = node.get_property("rect").unwrap();
+    prop.set_f32(Role::App, 0, BACKARROW_X).unwrap();
+    prop.set_f32(Role::App, 1, BACKARROW_Y).unwrap();
+    prop.set_f32(Role::App, 2, 500.).unwrap();
+    prop.set_f32(Role::App, 3, 500.).unwrap();
+    node.set_property_u32(Role::App, "z_index", 3).unwrap();
+
+    let send_btn_rect_prop = prop.clone();
 
+    let shape = shape::create_back_arrow().scaled(BACKARROW_SCALE);
     let node =
         node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
     layer_node.clone().link(node);
@@ -234,14 +277,14 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) {
     // Create some text
     let node = create_text("channel_label");
     let prop = node.get_property("rect").unwrap();
-    prop.set_f32(Role::App, 0, SENDLABEL_LHS_PAD).unwrap();
-    prop.set_f32(Role::App, 1, 0.).unwrap();
+    prop.set_f32(Role::App, 0, EDITCHAT_LHS_PAD).unwrap();
+    prop.set_f32(Role::App, 1, CHANNEL_LABEL_Y).unwrap();
     prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap();
     prop.set_f32(Role::App, 3, EDITCHAT_HEIGHT).unwrap();
     node.set_property_u32(Role::App, "z_index", 2).unwrap();
-    node.set_property_f32(Role::App, "baseline", TEXTBAR_BASELINE).unwrap();
+    node.set_property_f32(Role::App, "baseline", 0.).unwrap();
     node.set_property_f32(Role::App, "font_size", FONTSIZE).unwrap();
-    node.set_property_str(Role::App, "text", "random").unwrap();
+    node.set_property_str(Role::App, "text", "#random").unwrap();
     //node.set_property_str(Role::App, "text", "anon1").unwrap();
     let prop = node.get_property("text_color").unwrap();
     prop.set_f32(Role::App, 0, 1.).unwrap();
@@ -270,7 +313,7 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) {
     prop.set_f32(Role::App, 1, EDITCHAT_HEIGHT).unwrap();
     let code = cc.compile("w - 30").unwrap();
     prop.set_expr(Role::App, 2, code).unwrap();
-    let code = cc.compile("h - EDITCHAT_HEIGHT - editz_h - EDITCHAT_BOTTOM_PAD").unwrap();
+    let code = cc.compile("h - EDITCHAT_HEIGHT - editz_h - 2 * EDITCHAT_BOTTOM_PAD").unwrap();
     prop.set_expr(Role::App, 3, code).unwrap();
     let chatview_rect_prop = prop.clone();
     node.set_property_f32(Role::App, "font_size", FONTSIZE).unwrap();
@@ -340,9 +383,9 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) {
 
     let db = sled::open(CHATDB_PATH).expect("cannot open sleddb");
     let chat_tree = db.open_tree(b"chat").unwrap();
-    //if chat_tree.is_empty() {
-    //    populate_tree(&chat_tree);
-    //}
+    if chat_tree.is_empty() {
+        populate_tree(&chat_tree);
+    }
     debug!(target: "app", "db has {} lines", chat_tree.len());
     let node = node
         .setup(|me| {
@@ -372,69 +415,75 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) {
     let editbox_bg_rect_prop = prop.clone();
 
     let mut shape = VectorShape::new();
+    // Main green background
     shape.add_filled_box(
         expr::const_f32(0.),
         expr::const_f32(0.),
-        cc.compile("w - SENDLABEL_WIDTH").unwrap(),
+        cc.compile("w").unwrap(),
         expr::load_var("h"),
         [0., 0.13, 0.08, 1.],
     );
+    // Left hand darker box
     shape.add_filled_box(
         expr::const_f32(0.),
-        expr::const_f32(0.),
-        expr::load_var("w"),
         expr::const_f32(1.),
-        [0.41, 0.6, 0.65, 1.],
+        expr::const_f32(EMOJI_BG_W),
+        expr::load_var("h"),
+        [0., 0.11, 0.11, 1.],
     );
+    // Top line
     shape.add_filled_box(
-        cc.compile("w - SENDLABEL_WIDTH").unwrap(),
         expr::const_f32(0.),
-        cc.compile("w - SENDLABEL_WIDTH - 1").unwrap(),
-        expr::load_var("h"),
+        expr::const_f32(0.),
+        expr::load_var("w"),
+        expr::const_f32(1.),
         [0.41, 0.6, 0.65, 1.],
     );
+    // Side line
     shape.add_filled_box(
-        cc.compile("w - SENDLABEL_WIDTH + 1").unwrap(),
+        expr::const_f32(EMOJI_BG_W),
         expr::const_f32(0.),
-        expr::load_var("w"),
+        expr::const_f32(EMOJI_BG_W + 1.),
         expr::load_var("h"),
-        [0.04, 0.04, 0.04, 1.],
+        [0.41, 0.6, 0.65, 1.],
     );
     let node =
         node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
     layer_node.clone().link(node);
 
-    // Create some text
-    let node = create_text("send_label");
+    // Create the send button
+    let node = create_vector_art("send_btn_bg");
     let prop = node.get_property("rect").unwrap();
-    let code = cc.compile("w - (SENDLABEL_WIDTH - SENDLABEL_LHS_PAD)").unwrap();
+    let code = cc.compile("w - SEND_BTN_NEG_X").unwrap();
     prop.set_expr(Role::App, 0, code).unwrap();
-    let code = cc.compile("h - EDITCHAT_HEIGHT").unwrap();
+    let code = cc.compile("h - 2 * EMOJI_SCALE").unwrap();
     prop.set_expr(Role::App, 1, code).unwrap();
-    prop.set_f32(Role::App, 2, SENDLABEL_WIDTH).unwrap();
-    prop.set_f32(Role::App, 3, EDITCHAT_HEIGHT).unwrap();
-    node.set_property_f32(Role::App, "baseline", TEXTBAR_BASELINE).unwrap();
-    node.set_property_f32(Role::App, "font_size", FONTSIZE).unwrap();
-    node.set_property_str(Role::App, "text", "send").unwrap();
-    //node.set_property_str(Role::App, "text", "anon1").unwrap();
-    let prop = node.get_property("text_color").unwrap();
-    prop.set_f32(Role::App, 0, 0.).unwrap();
-    prop.set_f32(Role::App, 1, 1.).unwrap();
-    prop.set_f32(Role::App, 2, 0.94).unwrap();
-    prop.set_f32(Role::App, 3, 1.).unwrap();
+    prop.set_f32(Role::App, 2, 500.).unwrap();
+    prop.set_f32(Role::App, 3, 500.).unwrap();
     node.set_property_u32(Role::App, "z_index", 3).unwrap();
 
-    let node = node
-        .setup(|me| {
-            Text::new(
-                me,
-                window_scale.clone(),
-                app.render_api.clone(),
-                app.text_shaper.clone(),
-                app.ex.clone(),
-            )
-        })
-        .await;
+    let send_btn_rect_prop = prop.clone();
+
+    let shape = shape::create_send_arrow().scaled(EMOJI_SCALE);
+    let node =
+        node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
+    layer_node.clone().link(node);
+
+    // Create the emoji button
+    let node = create_vector_art("emoji_btn_bg");
+    let prop = node.get_property("rect").unwrap();
+    prop.set_f32(Role::App, 0, EMOJI_BTN_X).unwrap();
+    let code = cc.compile("h - 2 * EMOJI_SCALE").unwrap();
+    prop.set_expr(Role::App, 1, code).unwrap();
+    prop.set_f32(Role::App, 2, 500.).unwrap();
+    prop.set_f32(Role::App, 3, 500.).unwrap();
+    node.set_property_u32(Role::App, "z_index", 3).unwrap();
+
+    let emoji_btn_rect_prop = prop.clone();
+
+    let shape = shape::create_emoji_selector().scaled(EMOJI_SCALE);
+    let node =
+        node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
     layer_node.clone().link(node);
 
     // Text edit
@@ -448,12 +497,14 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) {
     prop.set_f32(Role::App, 0, EDITCHAT_LHS_PAD).unwrap();
     let code = cc.compile("parent_h - rect_h - EDITCHAT_BOTTOM_PAD").unwrap();
     prop.set_expr(Role::App, 1, code).unwrap();
-    let code = cc.compile("parent_w - (SENDLABEL_WIDTH + SENDLABEL_LHS_PAD)").unwrap();
+    let code = cc.compile("parent_w - (40 + SENDLABEL_WIDTH + SENDLABEL_LHS_PAD)").unwrap();
     prop.set_expr(Role::App, 2, code).unwrap();
     prop.set_f32(Role::App, 3, EDITCHAT_HEIGHT).unwrap();
 
     chatview_rect_prop.add_depend(&prop, 3, "editz_h");
     editbox_bg_rect_prop.add_depend(&prop, 3, "editz_h");
+    send_btn_rect_prop.add_depend(&prop, 3, "editz_h");
+    emoji_btn_rect_prop.add_depend(&prop, 3, "editz_h");
 
     node.set_property_f32(Role::App, "baseline", TEXTBAR_BASELINE).unwrap();
     node.set_property_f32(Role::App, "linespacing", EDITCHAT_LINESPACING).unwrap();

+ 1 - 0
bin/darkwallet/src/main.rs

@@ -66,6 +66,7 @@ mod prop;
 mod pubsub;
 //mod py;
 mod ringbuf;
+mod shape;
 mod scene;
 use scene::SceneNode as SceneNode3;
 mod text;

+ 18 - 0
bin/darkwallet/src/shape/back_arrow.rs

@@ -0,0 +1,18 @@
+use crate::ui::{VectorShape, ShapeVertex};
+pub fn create_back_arrow() -> VectorShape {
+    VectorShape {
+        verts: vec![
+            ShapeVertex::from_xy(-0.877643, -0.03111, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.992314, -0.03111, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.993081, 0.000168, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.154072, -0.752301, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.198105, -0.794808, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.877643, 0.03111, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.992314, 0.03111, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.993081, -0.000168, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.154072, 0.752301, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.198105, 0.794808, [0., 1., 1., 1.]),
+        ],
+        indices: vec![0, 4, 2, 1, 5, 0, 0, 5, 7, 5, 9, 7, 0, 3, 4, 1, 6, 5, 5, 8, 9]
+    }
+}

+ 82 - 0
bin/darkwallet/src/shape/emoji_sel.rs

@@ -0,0 +1,82 @@
+use crate::ui::{VectorShape, ShapeVertex};
+pub fn create_emoji_selector() -> VectorShape {
+    VectorShape {
+        verts: vec![
+            ShapeVertex::from_xy(-0.299137, -0.077869, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.247956, -0.006422, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.258195, -0.252576, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.192966, -0.231704, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.234915, -0.41554, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.164066, -0.441229, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.408315, -0.607404, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.377605, -0.67564, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.67564, -0.615431, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.705138, -0.685273, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.910051, -0.364965, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.983702, -0.390654, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.861884, -0.187551, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.941957, -0.212437, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.816929, -0.085598, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.871313, -0.035826, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.75672, -0.04867, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.809499, -0.004518, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.750298, -0.045459, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.796655, 0.025185, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.342487, -0.045459, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.302946, 0.02358, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.324826, -0.073557, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.285285, -0.004518, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.294399, -0.075557, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.243218, -0.00411, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.253458, -0.250264, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.188228, -0.229392, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.230177, -0.413228, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.159328, -0.438917, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.403577, -0.605092, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.372867, -0.673328, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.670902, -0.613119, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.7004, -0.682961, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.905313, -0.362653, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.978964, -0.388342, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.857147, -0.185239, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.93722, -0.210125, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.812191, -0.083286, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.866575, -0.033514, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.751983, -0.046358, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.804761, -0.002206, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.74556, -0.043147, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.791917, 0.027497, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.337749, -0.043147, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.298209, 0.025892, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.320088, -0.071245, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.280548, -0.002206, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.260481, 0.280672, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.302414, 0.210381, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.312982, 0.409139, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.378212, 0.390579, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.348979, 0.551295, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.423296, 0.571204, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.115467, 0.815986, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.146177, 0.883066, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.11371, 0.81361, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.144364, 0.885764, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.342181, 0.557428, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.419043, 0.572681, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.31395, 0.417031, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.378413, 0.390629, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.256172, 0.276612, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.299407, 0.207885, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.204883, 0.276478, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.25376, 0.206681, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.192886, 0.245393, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.245375, 0.175863, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.196323, 0.24595, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.246267, 0.175755, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.20358, 0.278671, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.259304, 0.205008, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.288443, 0.349093, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.350323, 0.309817, [0., 1., 1., 1.]),
+        ],
+        indices: vec![0, 3, 2, 3, 4, 2, 5, 6, 4, 7, 8, 6, 9, 10, 8, 10, 13, 12, 12, 15, 14, 14, 17, 16, 17, 18, 16, 18, 21, 20, 20, 23, 22, 23, 0, 22, 24, 27, 26, 27, 28, 26, 29, 30, 28, 31, 32, 30, 33, 34, 32, 34, 37, 36, 36, 39, 38, 38, 41, 40, 41, 42, 40, 42, 45, 44, 44, 47, 46, 47, 24, 46, 48, 73, 72, 51, 52, 50, 52, 55, 54, 54, 57, 56, 57, 58, 56, 58, 61, 60, 61, 62, 60, 62, 65, 64, 65, 66, 64, 66, 69, 68, 68, 71, 70, 71, 48, 70, 72, 51, 50, 0, 1, 3, 3, 5, 4, 5, 7, 6, 7, 9, 8, 9, 11, 10, 10, 11, 13, 12, 13, 15, 14, 15, 17, 17, 19, 18, 18, 19, 21, 20, 21, 23, 23, 1, 0, 24, 25, 27, 27, 29, 28, 29, 31, 30, 31, 33, 32, 33, 35, 34, 34, 35, 37, 36, 37, 39, 38, 39, 41, 41, 43, 42, 42, 43, 45, 44, 45, 47, 47, 25, 24, 48, 49, 73, 51, 53, 52, 52, 53, 55, 54, 55, 57, 57, 59, 58, 58, 59, 61, 61, 63, 62, 62, 63, 65, 65, 67, 66, 66, 67, 69, 68, 69, 71, 71, 49, 48, 72, 73, 51]
+    }
+}

+ 29 - 0
bin/darkwallet/src/shape/mod.rs

@@ -0,0 +1,29 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2024 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use crate::ui::{VectorShape, ShapeVertex};
+
+mod back_arrow;
+pub use back_arrow::create_back_arrow;
+
+mod send_arrow;
+pub use send_arrow::create_send_arrow;
+
+mod emoji_sel;
+pub use emoji_sel::create_emoji_selector;
+

+ 14 - 0
bin/darkwallet/src/shape/send_arrow.rs

@@ -0,0 +1,14 @@
+use crate::ui::{VectorShape, ShapeVertex};
+pub fn create_send_arrow() -> VectorShape {
+    VectorShape {
+        verts: vec![
+            ShapeVertex::from_xy(-0.763722, -0.082607, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.137017, 0.190169, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(0.992481, -0.087373, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.137017, -0.368093, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.934894, -0.730526, [0., 1., 1., 1.]),
+            ShapeVertex::from_xy(-0.89359, 0.560546, [0., 1., 1., 1.]),
+        ],
+        indices: vec![0, 1, 3, 3, 1, 2, 0, 3, 4, 1, 0, 5]
+    }
+}

+ 5 - 5
bin/darkwallet/src/ui/chatedit.rs

@@ -613,10 +613,10 @@ impl ChatEdit {
             is_mouse_hover: AtomicBool::new(false),
         });
 
-        //self_.text_wrap.lock().editable.set_text(
-        //    "".to_string(),
-        //    "A berry is a small, pulpy, and often edible fruit. Typically, berries are juicy, rounded, brightly colored, sweet, sour or tart, and do not have a stone or pit, although many pips or seeds may be present. Common examples of berries in the culinary sense are strawberries, raspberries, blueberries, blackberries, white currants, blackcurrants, and redcurrants. In Britain, soft fruit is a horticultural term for such fruits.".to_string()
-        //);
+        self_.text_wrap.lock().editable.set_text(
+            "".to_string(),
+            "A berry is a small, pulpy, and often edible fruit. Typically, berries are juicy, rounded, brightly colored, sweet, sour or tart, and do not have a stone or pit, although many pips or seeds may be present. Common examples of berries in the culinary sense are strawberries, raspberries, blueberries, blackberries, white currants, blackcurrants, and redcurrants. In Britain, soft fruit is a horticultural term for such fruits.".to_string()
+        );
         //self_
         //    .text_wrap
         //    .lock()
@@ -1080,7 +1080,7 @@ impl ChatEdit {
             KeyCode::Kp8 => self.insert_char('8').await,
             KeyCode::Kp9 => self.insert_char('9').await,
             KeyCode::KpDecimal => self.insert_char('.').await,
-            KeyCode::Enter | KeyCode::KpEnter => self.insert_char('\n').await,
+            //KeyCode::Enter | KeyCode::KpEnter => self.insert_char('\n').await,
             KeyCode::Delete => {
                 self.delete(0, 1);
                 self.clamp_scroll(&mut self.text_wrap.lock());

+ 30 - 0
bin/darkwallet/src/ui/vector_art/shape.rs

@@ -41,6 +41,29 @@ impl ShapeVertex {
     pub fn from_xy(x: f32, y: f32, color: Color) -> Self {
         Self { x: vec![Op::ConstFloat32(x)], y: vec![Op::ConstFloat32(y)], color }
     }
+
+    pub fn scale(mut self, scale: f32) -> Self {
+        let last_x = self.x.pop().unwrap();
+        let last_y = self.y.pop().unwrap();
+        let mut x = self.x;
+        x.push(
+            Op::Mul((
+                Box::new(Op::ConstFloat32(scale)),
+                Box::new(last_x)
+            ))
+        );
+        let mut y = self.y;
+        y.push(
+            Op::Mul((
+                Box::new(Op::ConstFloat32(scale)),
+                Box::new(last_y)
+            ))
+        );
+        Self {
+            x, y,
+            color: self.color
+        }
+    }
 }
 
 #[derive(Debug)]
@@ -144,4 +167,11 @@ impl VectorShape {
             color.clone(),
         );
     }
+
+    pub fn scaled(self, scale: f32) -> Self {
+        Self {
+            verts: self.verts.into_iter().map(|v| v.scale(scale)).collect(),
+            indices: self.indices
+        }
+    }
 }