| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383 |
- /* 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 darkfi::system::msleep;
- use darkfi_serial::Encodable;
- use sled_overlay::sled;
- use crate::{
- app::{
- node::{
- create_button, create_chatedit, create_chatview, create_editbox, create_emoji_picker,
- create_image, create_layer, create_text, create_vector_art,
- },
- populate_tree, App,
- },
- error::Error,
- expr::{self, Compiler, Op},
- gfx::{GraphicsEventPublisherPtr, Point, Rectangle, RenderApi, Vertex},
- mesh::{Color, MeshBuilder},
- prop::{
- Property, PropertyBool, PropertyFloat32, PropertyStr, PropertySubType, PropertyType, Role,
- },
- scene::{SceneNodePtr, Slot},
- shape,
- text::TextShaperPtr,
- ui::{
- emoji_picker, Button, ChatEdit, ChatView, EditBox, EmojiPicker, Image, Layer, ShapeVertex,
- Text, VectorArt, VectorShape, Window,
- },
- ExecutorPtr,
- };
- const LIGHTMODE: bool = false;
- mod android_ui_consts {
- use crate::gfx::{Point, Rectangle};
- pub const CHANNEL_LABEL_BASELINE: f32 = 82.;
- pub const BACKARROW_SCALE: f32 = 30.;
- pub const BACKARROW_X: f32 = 50.;
- pub const BACKARROW_Y: f32 = 70.;
- pub const CHATEDIT_MIN_HEIGHT: f32 = 140.;
- pub const CHATEDIT_HEIGHT: f32 = 140.;
- pub const CHATEDIT_SINGLE_LINE_Y: f32 = 120.;
- pub const CHATEDIT_BOTTOM_PAD: f32 = 10.;
- pub const CHATEDIT_CURSOR_ASCENT: f32 = 50.;
- pub const CHATEDIT_CURSOR_DESCENT: f32 = 20.;
- pub const CHATEDIT_SELECT_ASCENT: f32 = 50.;
- pub const CHATEDIT_SELECT_DESCENT: f32 = 20.;
- pub const CHATEDIT_HANDLE_DESCENT: f32 = 10.;
- pub const CHATEDIT_LINESPACING: f32 = 70.;
- pub const CHATEDIT_NEG_W: f32 = 300.;
- pub const CHATEDIT_LHS_PAD: f32 = 150.;
- pub const TEXTBAR_BASELINE: f32 = 60.;
- pub const TEXT_DESCENT: f32 = 20.;
- pub const EMOJI_BTN_X: f32 = 60.;
- pub const EMOJI_BG_W: f32 = 120.;
- pub const EMOJI_SCALE: f32 = 40.;
- pub const EMOJI_NEG_Y: f32 = 85.;
- pub const EMOJIBTN_BOX: [f32; 4] = [20., 118., 80., 75.];
- pub const EMOJI_CLOSE_SCALE: f32 = 20.;
- pub const SENDARROW_NEG_X: f32 = 80.;
- pub const SENDARROW_NEG_Y: f32 = 80.;
- pub const SENDBTN_BOX: [f32; 4] = [116., 120., 80., 70.];
- pub const FONTSIZE: f32 = 40.;
- pub const TIMESTAMP_FONTSIZE: f32 = 30.;
- pub const TIMESTAMP_WIDTH: f32 = 135.;
- pub const MESSAGE_SPACING: f32 = 15.;
- pub const LINE_HEIGHT: f32 = 58.;
- pub const CHATVIEW_BASELINE: f32 = 36.;
- pub const CMD_HELP_HEIGHT: f32 = 110.;
- pub const CMD_HELP_GAP: f32 = 10.;
- pub const CMD_HELP_CMD_FONTSIZE: f32 = 48.;
- pub const CMD_HELP_BASELINE: f32 = 74.;
- pub const CMD_HELP_CMD_LABEL_X_INSET: f32 = 40.;
- pub const CMD_HELP_NICK_CMD_WIDTH: f32 = 280.;
- pub const CMD_HELP_NICK_DESC_WIDTH: f32 = 1000.;
- pub const CMD_HELP_NICK_DESC_X: f32 = 320.;
- pub const ACTION_POPUP_Y_OFF: f32 = 200.;
- pub const ACTION_COPY_RECT: Rectangle = Rectangle::new(0., 0., 200., 160.);
- pub const ACTION_PASTE_RECT: Rectangle = Rectangle::new(220., 0., 240., 160.);
- pub const ACTION_SELECT_ALL_RECT: Rectangle = Rectangle::new(480., 0., 400., 160.);
- pub const ACTION_LABEL_POS: Point = Point::new(40., 92.);
- }
- #[cfg(target_os = "android")]
- mod ui_consts {
- pub use super::android_ui_consts::*;
- }
- #[cfg(feature = "emulate-android")]
- mod ui_consts {
- pub use super::android_ui_consts::*;
- }
- #[cfg(all(
- any(target_os = "linux", target_os = "macos", target_os = "windows"),
- not(feature = "emulate-android")
- ))]
- mod ui_consts {
- use crate::gfx::{Point, Rectangle};
- // Chat UI
- pub const CHANNEL_LABEL_BASELINE: f32 = 37.;
- pub const BACKARROW_SCALE: f32 = 15.;
- pub const BACKARROW_X: f32 = 38.;
- pub const BACKARROW_Y: f32 = 26.;
- pub const CHATEDIT_MIN_HEIGHT: f32 = 60.;
- pub const CHATEDIT_HEIGHT: f32 = 60.;
- pub const CHATEDIT_SINGLE_LINE_Y: f32 = 58.;
- pub const CHATEDIT_BOTTOM_PAD: f32 = 5.;
- pub const CHATEDIT_CURSOR_ASCENT: f32 = 25.;
- pub const CHATEDIT_CURSOR_DESCENT: f32 = 8.;
- pub const CHATEDIT_SELECT_ASCENT: f32 = 30.;
- pub const CHATEDIT_SELECT_DESCENT: f32 = 10.;
- pub const CHATEDIT_HANDLE_DESCENT: f32 = 35.;
- pub const CHATEDIT_LINESPACING: f32 = 35.;
- pub const CHATEDIT_NEG_W: f32 = 190.;
- pub const CHATEDIT_LHS_PAD: f32 = 100.;
- pub const TEXTBAR_BASELINE: f32 = 34.;
- pub const TEXT_DESCENT: f32 = 10.;
- pub const EMOJI_BTN_X: f32 = 38.;
- pub const EMOJI_BG_W: f32 = 80.;
- pub const EMOJI_SCALE: f32 = 20.;
- pub const EMOJI_NEG_Y: f32 = 34.;
- pub const EMOJIBTN_BOX: [f32; 4] = [16., 50., 44., 36.];
- pub const EMOJI_CLOSE_SCALE: f32 = 10.;
- pub const SENDARROW_NEG_X: f32 = 50.;
- pub const SENDARROW_NEG_Y: f32 = 32.;
- pub const SENDBTN_BOX: [f32; 4] = [72., 50., 45., 34.];
- pub const FONTSIZE: f32 = 20.;
- pub const TIMESTAMP_FONTSIZE: f32 = 12.;
- pub const TIMESTAMP_WIDTH: f32 = 60.;
- pub const MESSAGE_SPACING: f32 = 5.;
- pub const LINE_HEIGHT: f32 = 30.;
- pub const CHATVIEW_BASELINE: f32 = 20.;
- pub const CMD_HELP_HEIGHT: f32 = 55.;
- pub const CMD_HELP_GAP: f32 = 5.;
- pub const CMD_HELP_CMD_FONTSIZE: f32 = 24.;
- pub const CMD_HELP_BASELINE: f32 = 37.;
- pub const CMD_HELP_CMD_LABEL_X_INSET: f32 = 20.;
- pub const CMD_HELP_NICK_CMD_WIDTH: f32 = 140.;
- pub const CMD_HELP_NICK_DESC_WIDTH: f32 = 500.;
- pub const CMD_HELP_NICK_DESC_X: f32 = 160.;
- pub const ACTION_POPUP_Y_OFF: f32 = 100.;
- pub const ACTION_COPY_RECT: Rectangle = Rectangle::new(0., 0., 100., 80.);
- pub const ACTION_PASTE_RECT: Rectangle = Rectangle::new(110., 0., 120., 80.);
- pub const ACTION_SELECT_ALL_RECT: Rectangle = Rectangle::new(240., 0., 200., 80.);
- pub const ACTION_LABEL_POS: Point = Point::new(20., 46.);
- }
- use super::EMOJI_PICKER_ICON_SIZE;
- use ui_consts::*;
- struct Clipboard {
- #[cfg(not(target_os = "android"))]
- clip: arboard::Clipboard,
- }
- impl Clipboard {
- fn new() -> Self {
- Self {
- #[cfg(not(target_os = "android"))]
- clip: arboard::Clipboard::new().unwrap(),
- }
- }
- fn get(&mut self) -> Option<String> {
- #[cfg(target_os = "android")]
- return miniquad::window::clipboard_get();
- #[cfg(not(target_os = "android"))]
- return self.clip.get_text().ok();
- }
- fn set(&mut self, data: &str) {
- #[cfg(target_os = "android")]
- return miniquad::window::clipboard_set(data);
- #[cfg(not(target_os = "android"))]
- return self.clip.set_text(data).unwrap();
- }
- }
- fn android_keyboard_height() -> f32 {
- #[cfg(target_os = "android")]
- return crate::android::get_keyboard_height() as f32;
- unreachable!()
- }
- pub async fn make(
- app: &App,
- window: SceneNodePtr,
- channel: &str,
- db: &sled::Db,
- emoji_meshes: emoji_picker::EmojiMeshesPtr,
- ) {
- let window_scale = PropertyFloat32::wrap(&window, Role::Internal, "scale", 0).unwrap();
- let mut cc = Compiler::new();
- cc.add_const_f32("CHATEDIT_HEIGHT", CHATEDIT_HEIGHT);
- cc.add_const_f32("CHATEDIT_SINGLE_LINE_Y", CHATEDIT_SINGLE_LINE_Y);
- cc.add_const_f32("CHATEDIT_BOTTOM_PAD", CHATEDIT_BOTTOM_PAD);
- cc.add_const_f32("CHATEDIT_NEG_W", CHATEDIT_NEG_W);
- cc.add_const_f32("CHATEDIT_MIN_HEIGHT", CHATEDIT_MIN_HEIGHT);
- cc.add_const_f32("SENDARROW_NEG_X", SENDARROW_NEG_X);
- cc.add_const_f32("SENDARROW_NEG_Y", SENDARROW_NEG_Y);
- cc.add_const_f32("EMOJI_NEG_Y", EMOJI_NEG_Y);
- cc.add_const_f32("EMOJIBTN_BOX_1", EMOJIBTN_BOX[1]);
- cc.add_const_f32("SENDBTN_BOX_0", SENDBTN_BOX[0]);
- cc.add_const_f32("SENDBTN_BOX_1", SENDBTN_BOX[1]);
- cc.add_const_f32("ACTION_POPUP_Y_OFF", ACTION_POPUP_Y_OFF);
- cc.add_const_f32("CMD_HELP_HEIGHT", CMD_HELP_HEIGHT);
- cc.add_const_f32("CMD_HELP_GAP", CMD_HELP_GAP);
- // Main view
- let layer_node = create_layer(&(channel.to_string() + "_chat_layer"));
- let prop = layer_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();
- layer_node.set_property_bool(Role::App, "is_visible", false).unwrap();
- layer_node.set_property_u32(Role::App, "z_index", 1).unwrap();
- let layer_node =
- layer_node.setup(|me| Layer::new(me, app.render_api.clone(), app.ex.clone())).await;
- window.link(layer_node.clone());
- // Create the toolbar bg
- let node = create_vector_art("toolbar_bg");
- 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_f32(Role::App, 3, CHATEDIT_HEIGHT).unwrap();
- node.set_property_u32(Role::App, "z_index", 2).unwrap();
- let mut shape = VectorShape::new();
- shape.add_filled_box(
- expr::const_f32(0.),
- expr::const_f32(0.),
- expr::const_f32(EMOJI_BG_W),
- expr::load_var("h"),
- [0., 0.11, 0.11, 1.],
- );
- shape.add_filled_box(
- expr::const_f32(EMOJI_BG_W),
- expr::const_f32(0.),
- expr::const_f32(EMOJI_BG_W + 1.),
- expr::load_var("h"),
- [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 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);
- // Create the back button
- let node = create_button("back_btn");
- node.set_property_bool(Role::App, "is_active", true).unwrap();
- 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_f32(Role::App, 2, EMOJI_BG_W).unwrap();
- prop.set_f32(Role::App, 3, CHATEDIT_HEIGHT).unwrap();
- let (slot, recvr) = Slot::new("back_clicked");
- node.register("click", slot).unwrap();
- // Menu doesn't exist yet ;)
- let sg_root = app.sg_root.clone();
- let chatview_is_visible = PropertyBool::wrap(&layer_node, Role::App, "is_visible", 0).unwrap();
- let listen_click = app.ex.spawn(async move {
- while let Ok(_) = recvr.recv().await {
- info!(target: "app::chat", "clicked back");
- let menu_node = sg_root.clone().lookup_node("/window/menu_layer").unwrap();
- menu_node.set_property_bool(Role::App, "is_visible", true).unwrap();
- chatview_is_visible.set(false);
- }
- });
- app.tasks.lock().unwrap().push(listen_click);
- let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
- layer_node.clone().link(node);
- // Create some text
- let node = create_text("channel_label");
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, CHATEDIT_LHS_PAD).unwrap();
- prop.set_f32(Role::App, 1, 0.).unwrap();
- prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap();
- prop.set_f32(Role::App, 3, CHATEDIT_HEIGHT).unwrap();
- node.set_property_f32(Role::App, "baseline", CHANNEL_LABEL_BASELINE).unwrap();
- node.set_property_f32(Role::App, "font_size", FONTSIZE).unwrap();
- node.set_property_str(Role::App, "text", &("#".to_string() + channel)).unwrap();
- //node.set_property_bool(Role::App, "debug", true).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();
- prop.set_f32(Role::App, 1, 1.).unwrap();
- prop.set_f32(Role::App, 2, 1.).unwrap();
- prop.set_f32(Role::App, 3, 1.).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;
- layer_node.clone().link(node);
- // Create the emoji picker
- let mut node = create_emoji_picker("emoji_picker");
- let prop = Property::new("dynamic_h", PropertyType::Float32, PropertySubType::Pixel);
- node.add_property(prop).unwrap();
- let emoji_dynamic_h_prop = node.get_property("dynamic_h").unwrap();
- //emoji_dynamic_h_prop.set_f32(Role::App, 0, 400.).unwrap();
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, 0.).unwrap();
- let code = cc.compile("h - dynamic_h").unwrap();
- prop.set_expr(Role::App, 1, code).unwrap();
- prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap();
- prop.set_expr(Role::App, 3, expr::load_var("dynamic_h")).unwrap();
- prop.add_depend(&emoji_dynamic_h_prop, 0, "dynamic_h");
- let emoji_h_prop = PropertyFloat32::wrap(&node, Role::App, "dynamic_h", 0).unwrap();
- //node.set_property_f32(Role::App, "baseline", CHANNEL_LABEL_BASELINE).unwrap();
- //node.set_property_f32(Role::App, "font_size", FONTSIZE).unwrap();
- node.set_property_f32(Role::App, "emoji_size", EMOJI_PICKER_ICON_SIZE).unwrap();
- node.set_property_u32(Role::App, "z_index", 2).unwrap();
- let node = node
- .setup(|me| {
- EmojiPicker::new(
- me,
- window_scale.clone(),
- app.render_api.clone(),
- emoji_meshes,
- app.ex.clone(),
- )
- })
- .await;
- let emoji_picker_node = node.clone();
- layer_node.clone().link(node);
- // Create the editbox bg
- let node = create_vector_art("emoji_picker_bg");
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, 0.).unwrap();
- let code = cc.compile("h - dynamic_h").unwrap();
- prop.set_expr(Role::App, 1, code).unwrap();
- prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap();
- prop.set_expr(Role::App, 3, expr::load_var("dynamic_h")).unwrap();
- prop.add_depend(&emoji_dynamic_h_prop, 0, "dynamic_h");
- node.set_property_u32(Role::App, "z_index", 2).unwrap();
- let mut shape = VectorShape::new();
- // Main bg
- shape.add_filled_box(
- expr::const_f32(0.),
- expr::const_f32(0.),
- expr::load_var("w"),
- expr::load_var("h"),
- [0., 0.11, 0.11, 1.],
- );
- // Top line
- shape.add_filled_box(
- expr::const_f32(EMOJI_BG_W),
- expr::const_f32(0.),
- expr::load_var("w"),
- expr::const_f32(1.),
- [0.41, 0.6, 0.65, 1.],
- );
- // Bottom line
- //shape.add_filled_box(
- // expr::const_f32(0.),
- // cc.compile("h - 1").unwrap(),
- // expr::load_var("w"),
- // expr::load_var("h"),
- // [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);
- // Main content view
- let chat_layer_node = layer_node;
- let layer_node = create_layer("content");
- let prop = layer_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 - emoji_h").unwrap();
- prop.set_expr(Role::App, 3, code).unwrap();
- prop.add_depend(&emoji_dynamic_h_prop, 0, "emoji_h");
- layer_node.set_property_bool(Role::App, "is_visible", true).unwrap();
- layer_node.set_property_u32(Role::App, "z_index", 1).unwrap();
- layer_node.set_property_u32(Role::App, "priority", 1).unwrap();
- let layer_node =
- layer_node.setup(|me| Layer::new(me, app.render_api.clone(), app.ex.clone())).await;
- chat_layer_node.clone().link(layer_node.clone());
- // ChatView
- let node = create_chatview("chatty");
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, 10.).unwrap();
- prop.set_f32(Role::App, 1, CHATEDIT_HEIGHT).unwrap();
- let code = cc.compile("w - 30").unwrap();
- prop.set_expr(Role::App, 2, code).unwrap();
- let code = cc
- .compile(
- "
- height = if editz_h < CHATEDIT_MIN_HEIGHT {
- CHATEDIT_MIN_HEIGHT
- } else {
- editz_h
- };
- h - CHATEDIT_HEIGHT - height - 2 * CHATEDIT_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();
- node.set_property_f32(Role::App, "timestamp_font_size", TIMESTAMP_FONTSIZE).unwrap();
- node.set_property_f32(Role::App, "timestamp_width", TIMESTAMP_WIDTH).unwrap();
- node.set_property_f32(Role::App, "line_height", LINE_HEIGHT).unwrap();
- node.set_property_f32(Role::App, "message_spacing", MESSAGE_SPACING).unwrap();
- node.set_property_f32(Role::App, "baseline", CHATVIEW_BASELINE).unwrap();
- node.set_property_u32(Role::App, "z_index", 2).unwrap();
- //node.set_property_bool(Role::App, "debug", true).unwrap();
- #[cfg(target_os = "android")]
- node.set_property_f32(Role::App, "scroll_start_accel", 40.).unwrap();
- #[cfg(target_os = "linux")]
- node.set_property_f32(Role::App, "scroll_start_accel", 15.).unwrap();
- node.set_property_f32(Role::App, "scroll_resist", 0.9).unwrap();
- let prop = node.get_property("timestamp_color").unwrap();
- prop.set_f32(Role::App, 0, 0.407).unwrap();
- prop.set_f32(Role::App, 1, 0.604).unwrap();
- prop.set_f32(Role::App, 2, 0.647).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- let prop = node.get_property("text_color").unwrap();
- if LIGHTMODE {
- prop.set_f32(Role::App, 0, 0.).unwrap();
- prop.set_f32(Role::App, 1, 0.).unwrap();
- prop.set_f32(Role::App, 2, 0.).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- } else {
- prop.set_f32(Role::App, 0, 1.).unwrap();
- prop.set_f32(Role::App, 1, 1.).unwrap();
- prop.set_f32(Role::App, 2, 1.).unwrap();
- prop.set_f32(Role::App, 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(Role::App, c).unwrap();
- }
- let prop = node.get_property("hi_bg_color").unwrap();
- if LIGHTMODE {
- prop.set_f32(Role::App, 0, 0.5).unwrap();
- prop.set_f32(Role::App, 1, 0.5).unwrap();
- prop.set_f32(Role::App, 2, 0.5).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- } else {
- prop.set_f32(Role::App, 0, 0.5).unwrap();
- prop.set_f32(Role::App, 1, 0.5).unwrap();
- prop.set_f32(Role::App, 2, 0.5).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- }
- let tree_name = channel.to_string() + "__chat_tree";
- let chat_tree = db.open_tree(tree_name.as_bytes()).unwrap();
- if chat_tree.is_empty() {
- populate_tree(&chat_tree);
- }
- debug!(target: "app", "db has {} lines", chat_tree.len());
- let node = node
- .setup(|me| {
- ChatView::new(
- me,
- chat_tree,
- window_scale.clone(),
- app.render_api.clone(),
- app.text_shaper.clone(),
- app.ex.clone(),
- )
- })
- .await;
- layer_node.clone().link(node);
- // Create the editbox bg
- 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(
- "
- height = if editz_h < CHATEDIT_MIN_HEIGHT {
- CHATEDIT_MIN_HEIGHT
- } else {
- editz_h
- };
- h - height - 2 * CHATEDIT_BOTTOM_PAD
- ",
- )
- .unwrap();
- prop.set_expr(Role::App, 1, code).unwrap();
- prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap();
- let code = cc
- .compile(
- "
- height = if editz_h < CHATEDIT_MIN_HEIGHT {
- CHATEDIT_MIN_HEIGHT
- } else {
- editz_h
- };
- height + 2 * CHATEDIT_BOTTOM_PAD
- ",
- )
- .unwrap();
- prop.set_expr(Role::App, 3, code).unwrap();
- node.set_property_u32(Role::App, "z_index", 4).unwrap();
- node.set_property_u32(Role::App, "priority", 2).unwrap();
- 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.),
- expr::load_var("w"),
- 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(1.),
- expr::const_f32(EMOJI_BG_W),
- expr::load_var("h"),
- [0., 0.11, 0.11, 1.],
- );
- // Top line
- 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.],
- );
- // Side line
- shape.add_filled_box(
- expr::const_f32(EMOJI_BG_W),
- expr::const_f32(0.),
- expr::const_f32(EMOJI_BG_W + 1.),
- expr::load_var("h"),
- [0.41, 0.6, 0.65, 1.],
- );
- // Bottom line
- //shape.add_filled_box(
- // expr::const_f32(0.),
- // cc.compile("h - 1").unwrap(),
- // expr::load_var("w"),
- // expr::load_var("h"),
- // [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("send_btn_bg");
- let prop = node.get_property("rect").unwrap();
- let code = cc.compile("w - SENDARROW_NEG_X").unwrap();
- prop.set_expr(Role::App, 0, code).unwrap();
- let code = cc.compile("h - SENDARROW_NEG_Y").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", 5).unwrap();
- 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 emoji_btn_is_visible = PropertyBool::wrap(&node, Role::App, "is_visible", 0).unwrap();
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, EMOJI_BTN_X).unwrap();
- let code = cc.compile("h - EMOJI_NEG_Y").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", 5).unwrap();
- 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);
- // Create the emoji button
- let node = create_vector_art("emoji_close_btn_bg");
- node.set_property_bool(Role::App, "is_visible", false).unwrap();
- let prop = node.get_property("rect").unwrap();
- let emoji_close_is_visible = PropertyBool::wrap(&node, Role::App, "is_visible", 0).unwrap();
- prop.set_f32(Role::App, 0, EMOJI_BTN_X).unwrap();
- let code = cc.compile("h - EMOJI_NEG_Y").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", 5).unwrap();
- let shape = shape::create_close_icon().scaled(EMOJI_CLOSE_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
- let node = create_chatedit("editz");
- node.set_property_bool(Role::App, "is_active", true).unwrap();
- node.set_property_bool(Role::App, "is_focused", true).unwrap();
- node.set_property_f32(Role::App, "max_height", 600.).unwrap();
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, CHATEDIT_LHS_PAD).unwrap();
- let code = cc
- .compile(
- "
- height = if rect_h < CHATEDIT_MIN_HEIGHT {
- CHATEDIT_SINGLE_LINE_Y
- } else {
- rect_h
- };
- parent_h - (height + CHATEDIT_BOTTOM_PAD)
- ",
- )
- .unwrap();
- prop.set_expr(Role::App, 1, code).unwrap();
- let code = cc.compile("parent_w - CHATEDIT_NEG_W").unwrap();
- prop.set_expr(Role::App, 2, code).unwrap();
- prop.set_f32(Role::App, 3, CHATEDIT_HEIGHT).unwrap();
- chatview_rect_prop.add_depend(&prop, 3, "editz_h");
- editbox_bg_rect_prop.add_depend(&prop, 3, "editz_h");
- let prop = node.get_property("padding").unwrap();
- prop.set_f32(Role::App, 0, 0.).unwrap();
- prop.set_f32(Role::App, 1, TEXTBAR_BASELINE / 2.).unwrap();
- node.set_property_f32(Role::App, "baseline", TEXTBAR_BASELINE).unwrap();
- node.set_property_f32(Role::App, "linespacing", CHATEDIT_LINESPACING).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();
- if LIGHTMODE {
- prop.set_f32(Role::App, 0, 0.).unwrap();
- prop.set_f32(Role::App, 1, 0.).unwrap();
- prop.set_f32(Role::App, 2, 0.).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- } else {
- prop.set_f32(Role::App, 0, 1.).unwrap();
- prop.set_f32(Role::App, 1, 1.).unwrap();
- prop.set_f32(Role::App, 2, 1.).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- }
- let prop = node.get_property("text_hi_color").unwrap();
- prop.set_f32(Role::App, 0, 0.44).unwrap();
- prop.set_f32(Role::App, 1, 0.96).unwrap();
- prop.set_f32(Role::App, 2, 1.).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- let prop = node.get_property("text_cmd_color").unwrap();
- prop.set_f32(Role::App, 0, 0.64).unwrap();
- prop.set_f32(Role::App, 1, 1.).unwrap();
- prop.set_f32(Role::App, 2, 0.83).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- let prop = node.get_property("cursor_color").unwrap();
- prop.set_f32(Role::App, 0, 0.816).unwrap();
- prop.set_f32(Role::App, 1, 0.627).unwrap();
- prop.set_f32(Role::App, 2, 1.).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- node.set_property_f32(Role::App, "cursor_ascent", CHATEDIT_CURSOR_ASCENT).unwrap();
- node.set_property_f32(Role::App, "cursor_descent", CHATEDIT_CURSOR_DESCENT).unwrap();
- node.set_property_f32(Role::App, "select_ascent", CHATEDIT_SELECT_ASCENT).unwrap();
- node.set_property_f32(Role::App, "select_descent", CHATEDIT_SELECT_DESCENT).unwrap();
- node.set_property_f32(Role::App, "handle_descent", CHATEDIT_HANDLE_DESCENT).unwrap();
- let prop = node.get_property("hi_bg_color").unwrap();
- if LIGHTMODE {
- prop.set_f32(Role::App, 0, 0.5).unwrap();
- prop.set_f32(Role::App, 1, 0.5).unwrap();
- prop.set_f32(Role::App, 2, 0.5).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- } else {
- prop.set_f32(Role::App, 0, 0.).unwrap();
- prop.set_f32(Role::App, 1, 0.27).unwrap();
- prop.set_f32(Role::App, 2, 0.22).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- }
- let prop = node.get_property("cmd_bg_color").unwrap();
- if LIGHTMODE {
- prop.set_f32(Role::App, 0, 0.5).unwrap();
- prop.set_f32(Role::App, 1, 0.5).unwrap();
- prop.set_f32(Role::App, 2, 0.5).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- } else {
- prop.set_f32(Role::App, 0, 0.).unwrap();
- prop.set_f32(Role::App, 1, 0.30).unwrap();
- prop.set_f32(Role::App, 2, 0.25).unwrap();
- prop.set_f32(Role::App, 3, 1.).unwrap();
- }
- node.set_property_u32(Role::App, "z_index", 6).unwrap();
- node.set_property_u32(Role::App, "priority", 3).unwrap();
- //node.set_property_bool(Role::App, "debug", true).unwrap();
- let editz_text = PropertyStr::wrap(&node, Role::App, "text", 0).unwrap();
- let editz_select_text = node.get_property("select_text").unwrap();
- //let editbox_focus = PropertyBool::wrap(node, Role::App, "is_focused", 0).unwrap();
- //let darkirc_backend = app.darkirc_backend.clone();
- //let task = app.ex.spawn(async move {
- // while let Ok(_) = btn_click_recvr.recv().await {
- // let text = editbox_text.get();
- // editbox_text.prop().unset(Role::App, 0).unwrap();
- // // Clicking outside the editbox makes it lose focus
- // // So lets focus it again
- // editbox_focus.set(true);
- // debug!(target: "app", "sending text {text}");
- // let privmsg =
- // Privmsg { channel: "#random".to_string(), nick: "king".to_string(), msg: text };
- // darkirc_backend.send(privmsg).await;
- // }
- //});
- //tasks.push(task);
- let node = node
- .setup(|me| {
- ChatEdit::new(
- me,
- window_scale.clone(),
- app.render_api.clone(),
- app.text_shaper.clone(),
- app.ex.clone(),
- )
- })
- .await;
- let chatedit_node = node.clone();
- layer_node.clone().link(node);
- let (slot, recvr) = Slot::new("emoji_selected");
- emoji_picker_node.register("emoji_select", slot).unwrap();
- let chatedit_node2 = chatedit_node.clone();
- let listen_click = app.ex.spawn(async move {
- while let Ok(data) = recvr.recv().await {
- // No need to decode the data. Just pass it straight along
- chatedit_node2.call_method("insert_text", data).await.unwrap();
- }
- });
- app.tasks.lock().unwrap().push(listen_click);
- // No way to get the top of the editbox until eval has been called.
- // But this is on top so it happens before the eval. So the value is 0.
- // Not sure the best way to fix this.
- /*
- // Create the editbox fg shadow
- let node = create_vector_art("editbox_fg");
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, EMOJI_BG_W).unwrap();
- let code = cc.compile("editz_bg_top_y").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, 300.).unwrap();
- //prop.set_expr(Role::App, 2, expr::load_var("w")).unwrap();
- //prop.set_expr(Role::App, 3, expr::load_var("editz_bg_h")).unwrap();
- node.set_property_u32(Role::App, "z_index", 4).unwrap();
- prop.add_depend(&editbox_bg_rect_prop, 1, "editz_bg_top_y");
- prop.add_depend(&editbox_bg_rect_prop, 3, "editz_bg_h");
- let mut shape = VectorShape::new();
- // Left hand darker box
- shape.add_gradient_box(
- expr::const_f32(0.),
- expr::const_f32(0.),
- expr::load_var("w"),
- expr::const_f32(40.),
- [
- [0., 0., 0., 1.],
- [0., 0., 0., 1.],
- [0., 0., 0., 0.],
- [0., 0., 0., 0.],
- ]
- );
- 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_button("send_btn");
- node.set_property_bool(Role::App, "is_active", true).unwrap();
- let prop = node.get_property("rect").unwrap();
- let code = cc.compile("w - SENDBTN_BOX_0").unwrap();
- prop.set_expr(Role::App, 0, code).unwrap();
- let code = cc.compile("h - SENDBTN_BOX_1").unwrap();
- prop.set_expr(Role::App, 1, code).unwrap();
- prop.set_f32(Role::App, 2, SENDBTN_BOX[2]).unwrap();
- prop.set_f32(Role::App, 3, SENDBTN_BOX[3]).unwrap();
- let (slot, recvr) = Slot::new("send_clicked");
- node.register("click", slot).unwrap();
- let editz_text2 = editz_text.clone();
- let channel2 = channel.to_string();
- let listen_click = app.ex.spawn(async move {
- while let Ok(_) = recvr.recv().await {
- let text = editz_text2.get();
- info!(target: "app::chat", "Send '{text}' to channel: #{channel2}");
- editz_text2.set("");
- }
- });
- app.tasks.lock().unwrap().push(listen_click);
- let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
- layer_node.clone().link(node);
- // Create the emoji button
- let node = create_button("emoji_btn");
- node.set_property_bool(Role::App, "is_active", true).unwrap();
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, EMOJIBTN_BOX[0]).unwrap();
- let code = cc.compile("h - EMOJIBTN_BOX_1").unwrap();
- prop.set_expr(Role::App, 1, code).unwrap();
- prop.set_f32(Role::App, 2, EMOJIBTN_BOX[2]).unwrap();
- prop.set_f32(Role::App, 3, EMOJIBTN_BOX[3]).unwrap();
- let (slot, recvr) = Slot::new("reqkeyb");
- chatedit_node.register("keyboard_request", slot).unwrap();
- let emoji_btn_is_visible2 = emoji_btn_is_visible.clone();
- let listen_click = app.ex.spawn(async move {
- while let Ok(_) = recvr.recv().await {
- if emoji_btn_is_visible2.get() {
- debug!(target: "app::chat", "Emoji picker not visible so showing keyboard");
- miniquad::window::show_keyboard(true);
- }
- }
- });
- app.tasks.lock().unwrap().push(listen_click);
- let (slot, recvr) = Slot::new("emoji_clicked");
- node.register("click", slot).unwrap();
- let listen_click = app.ex.spawn(async move {
- let mut panel_height = if cfg!(target_os = "android") {
- let keyb_height = android_keyboard_height();
- if keyb_height > 0. {
- keyb_height
- } else {
- 600.
- }
- } else {
- 400.
- };
- while let Ok(_) = recvr.recv().await {
- info!(target: "app::chat", "clicked emoji");
- if cfg!(target_os = "android") {
- let keyb_height = android_keyboard_height();
- if keyb_height > panel_height {
- panel_height = keyb_height
- }
- }
- if emoji_btn_is_visible.get() {
- miniquad::window::show_keyboard(false);
- assert!(!emoji_close_is_visible.get());
- assert!(emoji_h_prop.get() < 0.001);
- emoji_btn_is_visible.set(false);
- emoji_close_is_visible.set(true);
- emoji_h_prop.set(panel_height as f32);
- //for i in 1..=20 {
- // emoji_h_prop.set((20 * i) as f32);
- // msleep(10).await;
- //}
- } else {
- miniquad::window::show_keyboard(true);
- assert!(emoji_close_is_visible.get());
- assert!(emoji_h_prop.get() > 0.);
- emoji_btn_is_visible.set(true);
- emoji_close_is_visible.set(false);
- emoji_h_prop.set(0. as f32);
- //for i in 1..=20 {
- // emoji_h_prop.set((400 - 20 * i) as f32);
- // msleep(10).await;
- //}
- }
- }
- });
- app.tasks.lock().unwrap().push(listen_click);
- let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
- layer_node.clone().link(node);
- // Commands help hint
- let cmd_layer_node = create_layer("cmd_hint_layer");
- let prop = cmd_layer_node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, 5.).unwrap();
- let code = cc.compile("editz_bg_top_y - CMD_HELP_HEIGHT - CMD_HELP_GAP").unwrap();
- //let code = cc.compile("h - 60 - 80").unwrap();
- //let code = cc.compile("h - 60 - 300").unwrap();
- prop.set_expr(Role::App, 1, code).unwrap();
- let code = cc.compile("w - 2 * CMD_HELP_GAP").unwrap();
- prop.set_expr(Role::App, 2, code).unwrap();
- prop.set_f32(Role::App, 3, CMD_HELP_HEIGHT).unwrap();
- prop.add_depend(&editbox_bg_rect_prop, 1, "editz_bg_top_y");
- cmd_layer_node.set_property_bool(Role::App, "is_visible", false).unwrap();
- cmd_layer_node.set_property_u32(Role::App, "z_index", 3).unwrap();
- let cmd_layer_node =
- cmd_layer_node.setup(|me| Layer::new(me, app.render_api.clone(), app.ex.clone())).await;
- layer_node.clone().link(cmd_layer_node.clone());
- let cmd_hint_is_visible =
- PropertyBool::wrap(&cmd_layer_node, Role::App, "is_visible", 0).unwrap();
- let editz_text_sub = editz_text.prop().subscribe_modify();
- let editz_text_task = app.ex.spawn(async move {
- while let Ok(_) = editz_text_sub.receive().await {
- let text = editz_text.get();
- info!(target: "app::chat", "text changed: {text}");
- // We want to avoid setting the property multiple times to the same value
- // because then it triggers unnecessary redraw work.
- if let Some(first_char) = text.chars().next() {
- if first_char == '/' {
- if !cmd_hint_is_visible.get() {
- cmd_hint_is_visible.set(true);
- }
- } else {
- if cmd_hint_is_visible.get() {
- cmd_hint_is_visible.set(false);
- }
- }
- } else {
- if cmd_hint_is_visible.get() {
- cmd_hint_is_visible.set(false);
- }
- }
- }
- });
- app.tasks.lock().unwrap().push(editz_text_task);
- // Create the actionbar bg
- let node = create_vector_art("cmd_hint_bg");
- 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();
- let mut shape = VectorShape::new();
- shape.add_filled_box(
- expr::const_f32(CMD_HELP_GAP),
- expr::const_f32(CMD_HELP_GAP),
- cc.compile("w - CMD_HELP_GAP").unwrap(),
- cc.compile("h - CMD_HELP_GAP").unwrap(),
- [0., 0.11, 0.11, 0.4],
- );
- shape.add_filled_box(
- expr::const_f32(CMD_HELP_GAP),
- expr::const_f32(CMD_HELP_GAP),
- expr::const_f32(CMD_HELP_NICK_CMD_WIDTH),
- cc.compile("h - CMD_HELP_GAP").unwrap(),
- [0., 0.3, 0.25, 1.],
- );
- shape.add_filled_box(
- expr::const_f32(CMD_HELP_NICK_CMD_WIDTH),
- expr::const_f32(CMD_HELP_GAP),
- expr::const_f32(CMD_HELP_NICK_DESC_WIDTH),
- cc.compile("h - CMD_HELP_GAP").unwrap(),
- [0., 0.11, 0.11, 1.],
- );
- shape.add_outline(
- expr::const_f32(0.),
- expr::const_f32(0.),
- expr::load_var("w"),
- expr::load_var("h"),
- 1.,
- [0.29, 0.51, 0.45, 1.],
- );
- let node =
- node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
- cmd_layer_node.clone().link(node);
- // Create some text
- let node = create_text("cmd_nick_label");
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, CMD_HELP_CMD_LABEL_X_INSET).unwrap();
- prop.set_f32(Role::App, 1, 0.).unwrap();
- prop.set_f32(Role::App, 2, 1000.).unwrap();
- prop.set_f32(Role::App, 3, 1000.).unwrap();
- node.set_property_f32(Role::App, "baseline", CMD_HELP_BASELINE).unwrap();
- node.set_property_f32(Role::App, "font_size", CMD_HELP_CMD_FONTSIZE).unwrap();
- node.set_property_str(Role::App, "text", "/nick").unwrap();
- //node.set_property_bool(Role::App, "debug", true).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.64).unwrap();
- prop.set_f32(Role::App, 1, 1.).unwrap();
- prop.set_f32(Role::App, 2, 0.83).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;
- cmd_layer_node.clone().link(node);
- // Create some text
- let node = create_text("cmd_nick_desc_label");
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, CMD_HELP_NICK_DESC_X).unwrap();
- prop.set_f32(Role::App, 1, 0.).unwrap();
- prop.set_f32(Role::App, 2, 1000.).unwrap();
- prop.set_f32(Role::App, 3, 1000.).unwrap();
- node.set_property_f32(Role::App, "baseline", CMD_HELP_BASELINE).unwrap();
- node.set_property_f32(Role::App, "font_size", FONTSIZE).unwrap();
- node.set_property_str(Role::App, "text", "Change your nickname").unwrap();
- //node.set_property_bool(Role::App, "debug", true).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, 0.94).unwrap();
- prop.set_f32(Role::App, 2, 1.).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;
- cmd_layer_node.clone().link(node);
- // Create debug box
- /*
- let mut node = create_vector_art("debugtool");
- let mut prop = Property::new("hoff", PropertyType::Float32, PropertySubType::Pixel);
- node.add_property(prop).unwrap();
- node.set_property_f32(Role::App, "hoff", 40.).unwrap();
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, EMOJIBTN_BOX[0]).unwrap();
- let code = cc.compile("h - EMOJIBTN_BOX_1").unwrap();
- prop.set_expr(Role::App, 1, code).unwrap();
- prop.set_f32(Role::App, 2, EMOJIBTN_BOX[2]).unwrap();
- prop.set_f32(Role::App, 3, EMOJIBTN_BOX[3]).unwrap();
- let hoff_prop = node.get_property("hoff").unwrap();
- prop.add_depend(&hoff_prop, 0, "hoff");
- node.set_property_u32(Role::App, "z_index", 6).unwrap();
- let mut shape = VectorShape::new();
- shape.add_outline(
- expr::const_f32(0.),
- expr::const_f32(0.),
- expr::load_var("w"),
- expr::load_var("h"),
- 2.,
- [1., 0., 0., 1.],
- );
- let node =
- node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
- layer_node.clone().link(node);
- */
- // Overlay popup
- let content_layer_node = layer_node.clone();
- let layer_node = create_layer("overlay_layer");
- let prop = layer_node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, 40.).unwrap();
- let code = cc.compile("editz_bg_top_y - ACTION_POPUP_Y_OFF").unwrap();
- //let code = cc.compile("h - 60 - 80").unwrap();
- //let code = cc.compile("h - 60 - 300").unwrap();
- prop.set_expr(Role::App, 1, code).unwrap();
- prop.set_f32(Role::App, 2, ACTION_SELECT_ALL_RECT.rhs()).unwrap();
- prop.set_f32(Role::App, 3, ACTION_SELECT_ALL_RECT.h).unwrap();
- prop.add_depend(&editbox_bg_rect_prop, 1, "editz_bg_top_y");
- layer_node.set_property_bool(Role::App, "is_visible", false).unwrap();
- layer_node.set_property_u32(Role::App, "z_index", 8).unwrap();
- // Priority higher than chatview but lower than chatedit
- layer_node.set_property_u32(Role::App, "priority", 1).unwrap();
- let layer_node =
- layer_node.setup(|me| Layer::new(me, app.render_api.clone(), app.ex.clone())).await;
- content_layer_node.link(layer_node.clone());
- let actions_is_visible = PropertyBool::wrap(&layer_node, Role::App, "is_visible", 0).unwrap();
- // Create the actionbar bg
- let node = create_vector_art("actionbar_bg");
- 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_f32(Role::App, 2, ACTION_SELECT_ALL_RECT.rhs()).unwrap();
- prop.set_f32(Role::App, 3, ACTION_SELECT_ALL_RECT.h).unwrap();
- node.set_property_u32(Role::App, "z_index", 0).unwrap();
- let mut shape = VectorShape::new();
- let color1 = [0., 0.13, 0.08, 0.75];
- let color2 = [0., 0., 0., 1.];
- let gradient = [color1.clone(), color1, color2.clone(), color2];
- let hicolor = [0., 0.94, 1., 1.];
- // Copy box
- shape.add_gradient_box(
- expr::const_f32(ACTION_COPY_RECT.x),
- expr::const_f32(ACTION_COPY_RECT.y),
- expr::const_f32(ACTION_COPY_RECT.rhs()),
- expr::const_f32(ACTION_COPY_RECT.bhs()),
- gradient.clone(),
- );
- // Copy outline
- shape.add_outline(
- expr::const_f32(ACTION_COPY_RECT.x),
- expr::const_f32(ACTION_COPY_RECT.y),
- expr::const_f32(ACTION_COPY_RECT.rhs()),
- expr::const_f32(ACTION_COPY_RECT.bhs()),
- 1.,
- hicolor.clone(),
- );
- // Paste box
- shape.add_gradient_box(
- expr::const_f32(ACTION_PASTE_RECT.x),
- expr::const_f32(ACTION_PASTE_RECT.y),
- expr::const_f32(ACTION_PASTE_RECT.rhs()),
- expr::const_f32(ACTION_PASTE_RECT.bhs()),
- gradient.clone(),
- );
- // Paste outline
- shape.add_outline(
- expr::const_f32(ACTION_PASTE_RECT.x),
- expr::const_f32(ACTION_PASTE_RECT.y),
- expr::const_f32(ACTION_PASTE_RECT.rhs()),
- expr::const_f32(ACTION_PASTE_RECT.bhs()),
- 1.,
- hicolor.clone(),
- );
- // Select all box
- shape.add_gradient_box(
- expr::const_f32(ACTION_SELECT_ALL_RECT.x),
- expr::const_f32(ACTION_SELECT_ALL_RECT.y),
- expr::const_f32(ACTION_SELECT_ALL_RECT.rhs()),
- expr::const_f32(ACTION_SELECT_ALL_RECT.bhs()),
- gradient,
- );
- // Select all outline
- shape.add_outline(
- expr::const_f32(ACTION_SELECT_ALL_RECT.x),
- expr::const_f32(ACTION_SELECT_ALL_RECT.y),
- expr::const_f32(ACTION_SELECT_ALL_RECT.rhs()),
- expr::const_f32(ACTION_SELECT_ALL_RECT.bhs()),
- 1.,
- hicolor,
- );
- 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("actions_label");
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, ACTION_LABEL_POS.x).unwrap();
- prop.set_f32(Role::App, 1, ACTION_LABEL_POS.y).unwrap();
- prop.set_f32(Role::App, 2, ACTION_SELECT_ALL_RECT.rhs()).unwrap();
- prop.set_f32(Role::App, 3, ACTION_SELECT_ALL_RECT.h).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", "copy paste select all").unwrap();
- //node.set_property_bool(Role::App, "debug", true).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, 0.94).unwrap();
- prop.set_f32(Role::App, 2, 1.).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;
- layer_node.clone().link(node);
- // Copy button
- let node = create_button("copy_btn");
- node.set_property_bool(Role::App, "is_active", true).unwrap();
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, ACTION_COPY_RECT.x).unwrap();
- prop.set_f32(Role::App, 1, ACTION_COPY_RECT.y).unwrap();
- prop.set_f32(Role::App, 2, ACTION_COPY_RECT.w).unwrap();
- prop.set_f32(Role::App, 3, ACTION_COPY_RECT.h).unwrap();
- let (slot, recvr) = Slot::new("copy_clicked");
- node.register("click", slot).unwrap();
- let actions_is_visible2 = actions_is_visible.clone();
- let editz_select_text2 = editz_select_text.clone();
- let listen_click = app.ex.spawn(async move {
- let mut clip = Clipboard::new();
- while let Ok(_) = recvr.recv().await {
- info!(target: "app::chat", "clicked copy");
- actions_is_visible2.set(false);
- let select_text = editz_select_text2.get_str(0).unwrap();
- clip.set(&select_text);
- }
- });
- app.tasks.lock().unwrap().push(listen_click);
- let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
- layer_node.clone().link(node);
- // Paste button
- let node = create_button("paste_btn");
- node.set_property_bool(Role::App, "is_active", true).unwrap();
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, ACTION_PASTE_RECT.x).unwrap();
- prop.set_f32(Role::App, 1, ACTION_PASTE_RECT.y).unwrap();
- prop.set_f32(Role::App, 2, ACTION_PASTE_RECT.w).unwrap();
- prop.set_f32(Role::App, 3, ACTION_PASTE_RECT.h).unwrap();
- let (slot, recvr) = Slot::new("paste_clicked");
- node.register("click", slot).unwrap();
- let actions_is_visible2 = actions_is_visible.clone();
- let listen_click = app.ex.spawn(async move {
- let mut clip = Clipboard::new();
- while let Ok(_) = recvr.recv().await {
- if let Some(text) = clip.get() {
- info!(target: "app::chat", "clicked paste: {text}");
- let mut data = vec![];
- text.encode(&mut data).unwrap();
- chatedit_node.call_method("insert_text", data).await.unwrap();
- } else {
- info!(target: "app::chat", "clicked paste but clip is empty");
- }
- actions_is_visible2.set(false);
- }
- });
- app.tasks.lock().unwrap().push(listen_click);
- let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
- layer_node.clone().link(node);
- // Select all button
- let node = create_button("select_all_btn");
- node.set_property_bool(Role::App, "is_active", true).unwrap();
- let prop = node.get_property("rect").unwrap();
- prop.set_f32(Role::App, 0, ACTION_SELECT_ALL_RECT.x).unwrap();
- prop.set_f32(Role::App, 1, ACTION_SELECT_ALL_RECT.y).unwrap();
- prop.set_f32(Role::App, 2, ACTION_SELECT_ALL_RECT.w).unwrap();
- prop.set_f32(Role::App, 3, ACTION_SELECT_ALL_RECT.h).unwrap();
- let (slot, recvr) = Slot::new("select_all_clicked");
- node.register("click", slot).unwrap();
- let actions_is_visible2 = actions_is_visible.clone();
- let listen_click = app.ex.spawn(async move {
- while let Ok(_) = recvr.recv().await {
- info!(target: "app::chat", "clicked select_all");
- }
- });
- app.tasks.lock().unwrap().push(listen_click);
- let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
- layer_node.clone().link(node);
- let editz_select_sub = editz_select_text.subscribe_modify();
- let editz_select_task = app.ex.spawn(async move {
- while let Ok(_) = editz_select_sub.receive().await {
- if editz_select_text.is_null(0).unwrap() {
- info!(target: "app::chat", "selection changed: null");
- actions_is_visible.set(false);
- } else {
- let select_text = editz_select_text.get_str(0).unwrap();
- info!(target: "app::chat", "selection changed: {select_text}");
- actions_is_visible.set(true);
- }
- }
- });
- app.tasks.lock().unwrap().push(editz_select_task);
- }
|