diff --git a/bin/darkwallet/src/app/node.rs b/bin/darkwallet/src/app/node.rs index 5c203a9b4..420d229b8 100644 --- a/bin/darkwallet/src/app/node.rs +++ b/bin/darkwallet/src/app/node.rs @@ -268,6 +268,9 @@ pub fn create_chatedit(name: &str) -> SceneNode { let prop = Property::new("baseline", PropertyType::Float32, PropertySubType::Pixel); node.add_property(prop).unwrap(); + let prop = Property::new("descent", PropertyType::Float32, PropertySubType::Pixel); + node.add_property(prop).unwrap(); + let mut prop = Property::new("scroll", PropertyType::Float32, PropertySubType::Pixel); prop.set_range_f32(0., f32::MAX); node.add_property(prop).unwrap(); diff --git a/bin/darkwallet/src/app/schema.rs b/bin/darkwallet/src/app/schema.rs index 9492fa112..0b14f924e 100644 --- a/bin/darkwallet/src/app/schema.rs +++ b/bin/darkwallet/src/app/schema.rs @@ -47,12 +47,13 @@ const LIGHTMODE: bool = false; mod android_ui_consts { pub const EDITCHAT_HEIGHT: f32 = 163.; - pub const EDITCHAT_BOTTOM_PAD: f32 = 70.; + pub const EDITCHAT_BOTTOM_PAD: f32 = 50.; pub const EDITCHAT_CURSOR_ASCENT: f32 = 50.; pub const EDITCHAT_CURSOR_DESCENT: f32 = 20.; pub const EDITCHAT_SELECT_ASCENT: f32 = 40.; pub const EDITCHAT_SELECT_DESCENT: f32 = 8.; pub const TEXTBAR_BASELINE: f32 = 93.; + pub const TEXT_DESCENT: f32 = 20.; pub const EDITCHAT_LHS_PAD: f32 = 30.; pub const SENDLABEL_WIDTH: f32 = 200.; pub const SENDLABEL_LHS_PAD: f32 = 40.; @@ -89,12 +90,13 @@ mod ui_consts { pub const KING_PATH: &str = "assets/king.png"; pub const BG_PATH: &str = "assets/bg.png"; pub const EDITCHAT_HEIGHT: f32 = 50.; - pub const EDITCHAT_BOTTOM_PAD: f32 = 16.; + pub const EDITCHAT_BOTTOM_PAD: f32 = 6.; pub const EDITCHAT_CURSOR_ASCENT: f32 = 25.; pub const EDITCHAT_CURSOR_DESCENT: f32 = 8.; pub const EDITCHAT_SELECT_ASCENT: f32 = 30.; pub const EDITCHAT_SELECT_DESCENT: f32 = 10.; pub const TEXTBAR_BASELINE: f32 = 34.; + pub const TEXT_DESCENT: f32 = 10.; pub const EDITCHAT_LHS_PAD: f32 = 20.; pub const SENDLABEL_WIDTH: f32 = 120.; pub const SENDLABEL_LHS_PAD: f32 = 30.; @@ -730,12 +732,15 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) { let node = create_vector_art("editbox_bg"); let prop = node.get_property("rect").unwrap(); prop.set_f32(Role::App, 0, 0.).unwrap(); - let code = cc.compile("h - EDITCHAT_HEIGHT").unwrap(); + let code = cc.compile("h - editz_h").unwrap(); prop.set_expr(Role::App, 1, code).unwrap(); prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap(); - prop.set_f32(Role::App, 3, EDITCHAT_HEIGHT).unwrap(); + let code = cc.compile("editz_h").unwrap(); + prop.set_expr(Role::App, 3, code).unwrap(); node.set_property_u32(Role::App, "z_index", 2).unwrap(); + let editbox_bg_rect_prop = prop.clone(); + let mut shape = VectorShape::new(); shape.add_filled_box( expr::const_f32(0.), @@ -818,8 +823,10 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) { 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"); node.set_property_f32(Role::App, "baseline", TEXTBAR_BASELINE).unwrap(); + node.set_property_f32(Role::App, "descent", TEXT_DESCENT).unwrap(); node.set_property_f32(Role::App, "font_size", FONTSIZE).unwrap(); //node.set_property_str(Role::App, "text", "hello king!๐Ÿ˜๐Ÿ†jelly ๐Ÿ†1234").unwrap(); let prop = node.get_property("text_color").unwrap(); @@ -912,72 +919,4 @@ pub(super) async fn make(app: &App, window: SceneNodePtr) { let node = node.setup(|me| Button::new(me, app.ex.clone())).await; layer_node.clone().link(node); - - // Create a popup layer to show upgrade msg - let node = create_layer("upgrade_popup"); - let prop = node.get_property("rect").unwrap(); - prop.set_f32(Role::App, 0, 0.).unwrap(); - prop.set_f32(Role::App, 1, 0.).unwrap(); - prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap(); - let code = cc.compile("h / 2").unwrap(); - prop.set_expr(Role::App, 3, code).unwrap(); - node.set_property_bool(Role::App, "is_visible", false).unwrap(); - node.set_property_u32(Role::App, "z_index", 10).unwrap(); - let popup_layer_node = - node.setup(|me| Layer::new(me, app.render_api.clone(), app.ex.clone())).await; - layer_node.clone().link(popup_layer_node.clone()); - - // Background for popup - let node = create_vector_art("upgradebg"); - let prop = node.get_property("rect").unwrap(); - prop.set_f32(Role::App, 0, 0.).unwrap(); - prop.set_f32(Role::App, 1, 0.).unwrap(); - prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap(); - prop.set_expr(Role::App, 3, expr::load_var("h")).unwrap(); - node.set_property_u32(Role::App, "z_index", 0).unwrap(); - - // Setup the pimpl - let verts = vec![ - ShapeVertex::from_xy(0., 0., [1., 0., 0., 1.]), - ShapeVertex::new(expr::load_var("w"), expr::const_f32(0.), [1., 0., 1., 1.]), - ShapeVertex::new(expr::const_f32(0.), expr::load_var("h"), [0., 0., 1., 1.]), - ShapeVertex::new(expr::load_var("w"), expr::load_var("h"), [1., 1., 0., 1.]), - ]; - let indices = vec![0, 2, 1, 1, 2, 3]; - let shape = VectorShape { verts, indices }; - let node = - node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await; - popup_layer_node.clone().link(node); - - // Create some text - let node = create_text("send_label"); - let prop = node.get_property("rect").unwrap(); - prop.set_f32(Role::App, 0, 10.).unwrap(); - prop.set_f32(Role::App, 1, 10.).unwrap(); - prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap(); - prop.set_expr(Role::App, 3, expr::load_var("h")).unwrap(); - node.set_property_f32(Role::App, "baseline", TEXTBAR_BASELINE).unwrap(); - node.set_property_f32(Role::App, "font_size", 2. * FONTSIZE).unwrap(); - node.set_property_str(Role::App, "text", "YO THERE'S A NEW VERSION!!! UPGRADE TIEM!!!") - .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(); - node.set_property_u32(Role::App, "z_index", 1).unwrap(); - - let node = node - .setup(|me| { - Text::new( - me, - window_scale.clone(), - app.render_api.clone(), - app.text_shaper.clone(), - app.ex.clone(), - ) - }) - .await; - popup_layer_node.clone().link(node); } diff --git a/bin/darkwallet/src/ui/chatedit.rs b/bin/darkwallet/src/ui/chatedit.rs index f3ccd15e7..a26d7b74b 100644 --- a/bin/darkwallet/src/ui/chatedit.rs +++ b/bin/darkwallet/src/ui/chatedit.rs @@ -147,6 +147,7 @@ pub struct ChatEdit { max_height: PropertyFloat32, rect: PropertyRect, baseline: PropertyFloat32, + descent: PropertyFloat32, scroll: PropertyFloat32, scroll_speed: PropertyFloat32, cursor_pos: PropertyUint32, @@ -201,6 +202,7 @@ impl ChatEdit { let max_height = PropertyFloat32::wrap(node_ref, Role::Internal, "max_height", 0).unwrap(); let rect = PropertyRect::wrap(node_ref, Role::Internal, "rect").unwrap(); let baseline = PropertyFloat32::wrap(node_ref, Role::Internal, "baseline", 0).unwrap(); + let descent = PropertyFloat32::wrap(node_ref, Role::Internal, "descent", 0).unwrap(); let scroll = PropertyFloat32::wrap(node_ref, Role::Internal, "scroll", 0).unwrap(); let scroll_speed = PropertyFloat32::wrap(node_ref, Role::Internal, "scroll_speed", 0).unwrap(); @@ -252,6 +254,7 @@ impl ChatEdit { max_height, rect, baseline: baseline.clone(), + descent, scroll: scroll.clone(), scroll_speed, cursor_pos, @@ -326,8 +329,7 @@ impl ChatEdit { let total_height = wrapped_lines_len as f32 * baseline; //let height = std::cmp::min(total_height, self.max_height.get()); - let height = total_height; - debug!("height = {height}"); + let height = total_height + self.descent.get(); self.rect.prop().set_f32(Role::Internal, 3, height); @@ -341,7 +343,6 @@ impl ChatEdit { ("rect_h".to_string(), height), ], ); - debug!("rect = {:?}", self.rect.get()); let mut clip = self.rect.get(); clip.x = 0.; @@ -416,43 +417,60 @@ impl ChatEdit { mesh.alloc(&self.render_api).draw_untextured() } - fn cursor_px_offset(&self) -> f32 { + fn get_cursor_pos(&self) -> Point { assert!(self.is_focused.get()); - let (cursor_pos, glyphs) = { - let editable = self.editable.lock().unwrap(); - let rendered = editable.render(); - let cursor_pos = editable.get_cursor_pos(&rendered); - (cursor_pos, rendered.glyphs) - }; - let font_size = self.font_size.get(); let window_scale = self.window_scale.get(); let baseline = self.baseline.get(); - let scroll = self.scroll.get(); - // Add composer glyphs too - let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline); + + let width = self.rect.prop().get_f32(2).unwrap(); + + let (cursor_pos, wrap_glyphs) = { + let editable = self.editable.lock().unwrap(); + let rendered = editable.render(); + let cursor_pos = editable.get_cursor_pos(&rendered); + let glyphs = text::wrap(width, font_size, window_scale, &rendered.glyphs); + (cursor_pos, glyphs) + }; + + // Convert cursor glyph pos to a coord (x, y) + let mut glyph_idx = 0; // Used for drawing the cursor when it's at the end of the line. let mut rhs = 0.; + let mut y_pos = 0.; if cursor_pos == 0 { - return 0.; + return Point::zero(); } - for (glyph_idx, (mut glyph_rect, glyph)) in glyph_pos_iter.zip(glyphs.iter()).enumerate() { - glyph_rect.x -= scroll; + for (line_idx, glyphs) in wrap_glyphs.iter().enumerate() { + debug!("glyph_idx = {glyph_idx}, y_pos = {y_pos}, rhs = {rhs}"); + let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, glyphs, baseline); - if cursor_pos == glyph_idx { - return glyph_rect.x; + if line_idx > 0 { + // +1 for the EOL whitespace + glyph_idx += 1; + y_pos += baseline; } - rhs = glyph_rect.rhs(); + for (mut glyph_rect, glyph) in glyph_pos_iter.zip(glyphs.iter()) { + if cursor_pos == glyph_idx { + let rhs = glyph_rect.rhs(); + debug!("retvrn {rhs}, {y_pos}"); + return Point::new(rhs, y_pos) + } + + rhs = glyph_rect.rhs(); + + glyph_idx += 1; + } } - assert!(cursor_pos == glyphs.len()); - - rhs += eol_nudge(font_size, &glyphs); - rhs + if !wrap_glyphs.is_empty() { + rhs += eol_nudge(font_size, &wrap_glyphs.last().unwrap()); + } + Point::new(rhs, y_pos) } fn mark_selected_glyphs(&self, glyphs: &Vec, selections: Vec) -> Vec { @@ -1209,11 +1227,7 @@ impl ChatEdit { let rect_w = self.rect.get().w; - let mut cursor_pos = Point::zero(); - cursor_pos.x += self.cursor_px_offset(); - if cursor_pos.x > rect_w { - return vec![] - } + let cursor_pos = self.get_cursor_pos(); cursor_instrs.push(GfxDrawInstruction::Move(cursor_pos)); let cursor_mesh = { @@ -1439,10 +1453,23 @@ impl UIObject for ChatEdit { let window_scale = self.window_scale.get(); let baseline = self.baseline.get(); + // Convert y offset within rect to an x off based off line wrapping + let y_off = mouse_pos.y - rect.y; + let mut x_off = 0.; + + let width = self.rect.prop().get_f32(2).unwrap(); + let rendered = self.editable.lock().unwrap().render(); + let wrapped_glyphs = text::wrap(width, font_size, window_scale, &rendered.glyphs); + for glyphs in wrapped_glyphs { + let glyph_pos_iter = GlyphPositionIter::new(font_size, window_scale, &glyphs, baseline); + let last_rect = glyph_pos_iter.last().unwrap(); + x_off += last_rect.rhs(); + } + { let mut editable = self.editable.lock().unwrap(); let rendered = editable.render(); - let x = mouse_pos.x - rect.x + self.scroll.get(); + let x = x_off + mouse_pos.x - rect.x + self.scroll.get(); let cpos = rendered.x_to_pos(x, font_size, window_scale, baseline); let cidx = rendered.pos_to_idx(cpos); diff --git a/bin/darkwallet/src/ui/vector_art/mod.rs b/bin/darkwallet/src/ui/vector_art/mod.rs index 4b9d59934..1ef5a1d6a 100644 --- a/bin/darkwallet/src/ui/vector_art/mod.rs +++ b/bin/darkwallet/src/ui/vector_art/mod.rs @@ -106,7 +106,6 @@ impl VectorArt { //debug!(target: "ui::vector_art", "=> {verts:#?}"); let vertex_buffer = self.render_api.new_vertex_buffer(verts); - // You are one lazy motherfucker let index_buffer = self.render_api.new_index_buffer(self.shape.indices.clone()); let mesh = GfxDrawMesh { vertex_buffer,