mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
wallet: remove old unused modules from proj
This commit is contained in:
@@ -32,13 +32,13 @@ use crate::{
|
||||
darkirc::{DarkIrcBackendPtr, Privmsg},
|
||||
error::Error,
|
||||
expr::Op,
|
||||
gfx2::{GraphicsEventPublisherPtr, RenderApiPtr, Vertex},
|
||||
gfx::{GraphicsEventPublisherPtr, RenderApiPtr, Vertex},
|
||||
prop::{Property, PropertyBool, PropertyStr, PropertySubType, PropertyType, Role},
|
||||
scene::{
|
||||
CallArgType, MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId,
|
||||
SceneNodeType, Slot,
|
||||
},
|
||||
text2::TextShaperPtr,
|
||||
text::TextShaperPtr,
|
||||
ui::{chatview, Button, ChatView, EditBox, Image, Mesh, RenderLayer, Stoppable, Text, Window},
|
||||
ExecutorPtr,
|
||||
};
|
||||
|
||||
@@ -1,436 +0,0 @@
|
||||
/* 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_serial::Encodable;
|
||||
|
||||
use crate::{
|
||||
expr::Op,
|
||||
gfx::Rectangle,
|
||||
prop::{Property, PropertySubType, PropertyType},
|
||||
scene::{
|
||||
SceneGraph, SceneNodeId,
|
||||
SceneNodeType,
|
||||
},
|
||||
};
|
||||
|
||||
struct Buffer {
|
||||
verts: Vec<u8>,
|
||||
faces: Vec<u8>,
|
||||
verts_len: u32,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn new() -> Self {
|
||||
Self { verts: vec![], faces: vec![], verts_len: 0 }
|
||||
}
|
||||
|
||||
fn vertex(&mut self, x: f32, y: f32, r: f32, g: f32, b: f32, a: f32, u: f32, v: f32) {
|
||||
// xy
|
||||
x.encode(&mut self.verts).unwrap();
|
||||
y.encode(&mut self.verts).unwrap();
|
||||
// rgba
|
||||
r.encode(&mut self.verts).unwrap();
|
||||
g.encode(&mut self.verts).unwrap();
|
||||
b.encode(&mut self.verts).unwrap();
|
||||
a.encode(&mut self.verts).unwrap();
|
||||
// uv
|
||||
u.encode(&mut self.verts).unwrap();
|
||||
v.encode(&mut self.verts).unwrap();
|
||||
self.verts_len += 1
|
||||
}
|
||||
|
||||
fn face(&mut self, i1: u32, i2: u32, i3: u32) {
|
||||
i1.encode(&mut self.faces).unwrap();
|
||||
i2.encode(&mut self.faces).unwrap();
|
||||
i3.encode(&mut self.faces).unwrap();
|
||||
}
|
||||
|
||||
pub fn draw_box(&mut self, rect: Rectangle<f32>, color: [f32; 4]) {
|
||||
let k = self.verts_len;
|
||||
let x = rect.x;
|
||||
let y = rect.y;
|
||||
let w = rect.w;
|
||||
let h = rect.h;
|
||||
let r = color[0];
|
||||
let g = color[1];
|
||||
let b = color[2];
|
||||
let a = color[3];
|
||||
|
||||
self.vertex(x, y, r, g, b, a, 0., 0.);
|
||||
self.vertex(x + w, y, r, g, b, a, 1., 0.);
|
||||
self.vertex(x, y + h, r, g, b, a, 0., 1.);
|
||||
self.vertex(x + w, y + h, r, g, b, a, 1., 1.);
|
||||
|
||||
self.face(k, k + 2, k + 1);
|
||||
self.face(k + 1, k + 2, k + 3);
|
||||
}
|
||||
|
||||
pub fn draw_outline(
|
||||
&mut self,
|
||||
rect: Rectangle<f32>,
|
||||
color: [f32; 4],
|
||||
pad: f32,
|
||||
layer_w: f32,
|
||||
layer_h: f32,
|
||||
) {
|
||||
let pad_x = pad / layer_w;
|
||||
let pad_y = pad / layer_h;
|
||||
|
||||
let x = rect.x;
|
||||
let y = rect.y;
|
||||
let w = rect.w;
|
||||
let h = rect.h;
|
||||
|
||||
// left
|
||||
self.draw_box(Rectangle { x, y, w: pad_x, h }, color);
|
||||
// top
|
||||
self.draw_box(Rectangle { x, y, w, h: pad_y }, color);
|
||||
// right
|
||||
let rhs = x + w;
|
||||
self.draw_box(Rectangle { x: rhs - pad_x, y, w: pad_x, h }, color);
|
||||
// bottom
|
||||
let bhs = y + h;
|
||||
self.draw_box(Rectangle { x, y: bhs - pad_y, w, h: pad_y }, color);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_layer(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
|
||||
let win_id = sg.lookup_node("/window").unwrap().id;
|
||||
|
||||
let node = sg.add_node(name, SceneNodeType::RenderLayer);
|
||||
let mut prop = Property::new("is_visible", PropertyType::Bool, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);
|
||||
prop.set_array_len(4);
|
||||
prop.allow_exprs();
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
node.id
|
||||
}
|
||||
|
||||
pub fn create_mesh(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
|
||||
let node = sg.add_node(name, SceneNodeType::RenderMesh);
|
||||
|
||||
let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);
|
||||
prop.set_array_len(4);
|
||||
prop.allow_exprs();
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("z_index", PropertyType::Uint32, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
node.id
|
||||
}
|
||||
|
||||
fn create_text(sg: &mut SceneGraph, name: &str, layer_node_id: SceneNodeId) -> SceneNodeId {
|
||||
let node = sg.add_node(name, SceneNodeType::RenderText);
|
||||
|
||||
let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);
|
||||
prop.set_array_len(4);
|
||||
prop.allow_exprs();
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("baseline", PropertyType::Float32, PropertySubType::Pixel);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("font_size", PropertyType::Float32, PropertySubType::Pixel);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("text", PropertyType::Str, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("color", PropertyType::Float32, PropertySubType::Color);
|
||||
prop.set_array_len(4);
|
||||
prop.set_range_f32(0., 1.);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("z_index", PropertyType::Uint32, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("debug", PropertyType::Bool, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let node_id = node.id;
|
||||
sg.link(node_id, layer_node_id).unwrap();
|
||||
node_id
|
||||
}
|
||||
|
||||
fn create_editbox(sg: &mut SceneGraph, name: &str, layer_node_id: SceneNodeId) -> SceneNodeId {
|
||||
let node = sg.add_node(name, SceneNodeType::EditBox);
|
||||
|
||||
let mut prop = Property::new("is_active", PropertyType::Bool, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);
|
||||
prop.set_array_len(4);
|
||||
prop.allow_exprs();
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("baseline", PropertyType::Float32, PropertySubType::Pixel);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("scroll", PropertyType::Float32, PropertySubType::Pixel);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("cursor_pos", PropertyType::Uint32, PropertySubType::Pixel);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("font_size", PropertyType::Float32, PropertySubType::Pixel);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("text", PropertyType::Str, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("text_color", PropertyType::Float32, PropertySubType::Color);
|
||||
prop.set_array_len(4);
|
||||
prop.set_range_f32(0., 1.);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("cursor_color", PropertyType::Float32, PropertySubType::Color);
|
||||
prop.set_array_len(4);
|
||||
prop.set_range_f32(0., 1.);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("hi_bg_color", PropertyType::Float32, PropertySubType::Color);
|
||||
prop.set_array_len(4);
|
||||
prop.set_range_f32(0., 1.);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("selected", PropertyType::Uint32, PropertySubType::Color);
|
||||
prop.set_array_len(2);
|
||||
prop.allow_null_values();
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("z_index", PropertyType::Uint32, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("debug", PropertyType::Bool, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let node_id = node.id;
|
||||
sg.link(node_id, layer_node_id).unwrap();
|
||||
node_id
|
||||
}
|
||||
|
||||
fn create_chatview(sg: &mut SceneGraph, name: &str, layer_node_id: SceneNodeId) -> SceneNodeId {
|
||||
let node = sg.add_node(name, SceneNodeType::ChatView);
|
||||
|
||||
let mut prop = Property::new("rect", PropertyType::Float32, PropertySubType::Pixel);
|
||||
prop.set_array_len(4);
|
||||
prop.allow_exprs();
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("z_index", PropertyType::Uint32, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let mut prop = Property::new("debug", PropertyType::Bool, PropertySubType::Null);
|
||||
node.add_property(prop).unwrap();
|
||||
|
||||
let node_id = node.id;
|
||||
|
||||
let mut arg_data = vec![];
|
||||
node_id.encode(&mut arg_data).unwrap();
|
||||
//let (tx, rx) = mpsc::sync_channel::<Result<Vec<u8>>>(0);
|
||||
let response_fn = Box::new(move |_result| {
|
||||
//tx.send(result).unwrap();
|
||||
});
|
||||
let win_node = sg.lookup_node_mut("/window").unwrap();
|
||||
win_node.call_method("create_chat_view", arg_data, response_fn).unwrap();
|
||||
//let _result = rx.recv().unwrap();
|
||||
|
||||
sg.link(node_id, layer_node_id).unwrap();
|
||||
node_id
|
||||
}
|
||||
|
||||
pub fn setup(sg: &mut SceneGraph) {
|
||||
let layer_node_id = create_layer(sg, "view");
|
||||
let node = sg.get_node(layer_node_id).unwrap();
|
||||
let prop = node.get_property("rect").unwrap();
|
||||
prop.set_u32(0, 0).unwrap();
|
||||
prop.set_u32(1, 0).unwrap();
|
||||
let code = vec![Op::Float32ToUint32((Box::new(Op::LoadVar("sw".to_string()))))];
|
||||
prop.set_expr(2, code).unwrap();
|
||||
let code = vec![Op::Float32ToUint32((Box::new(Op::LoadVar("sh".to_string()))))];
|
||||
prop.set_expr(3, code).unwrap();
|
||||
|
||||
// Make the black background
|
||||
// Maybe we should use a RenderPass for this instead
|
||||
let node_id = create_mesh(sg, "bg");
|
||||
let node = sg.get_node(node_id).unwrap();
|
||||
|
||||
let prop = node.get_property("rect").unwrap();
|
||||
prop.set_f32(0, 0.).unwrap();
|
||||
prop.set_f32(1, 0.).unwrap();
|
||||
let code = vec![Op::LoadVar("lw".to_string())];
|
||||
prop.set_expr(2, code).unwrap();
|
||||
let code = vec![Op::LoadVar("lh".to_string())];
|
||||
prop.set_expr(3, code).unwrap();
|
||||
|
||||
let prop = node.get_property("data").unwrap();
|
||||
|
||||
let mut buff = Buffer::new();
|
||||
buff.draw_box(Rectangle { x: 0., y: 0., w: 1., h: 1. }, [0.05, 0.05, 0.05, 1.]);
|
||||
prop.set_buf(0, buff.verts).unwrap();
|
||||
prop.set_buf(1, buff.faces).unwrap();
|
||||
|
||||
// Make the chatedit bg
|
||||
let node_id = create_mesh(sg, "chateditbg");
|
||||
let node = sg.get_node(node_id).unwrap();
|
||||
let prop = node.get_property("rect").unwrap();
|
||||
|
||||
let prop = node.get_property("rect").unwrap();
|
||||
prop.set_f32(0, 140.).unwrap();
|
||||
let code =
|
||||
vec![Op::Sub((Box::new(Op::LoadVar("lh".to_string())), Box::new(Op::ConstFloat32(60.))))];
|
||||
prop.set_expr(1, code).unwrap();
|
||||
let code =
|
||||
vec![Op::Sub((Box::new(Op::LoadVar("lw".to_string())), Box::new(Op::ConstFloat32(140.))))];
|
||||
prop.set_expr(2, code).unwrap();
|
||||
prop.set_f32(3, 60.).unwrap();
|
||||
|
||||
let prop = node.get_property("data").unwrap();
|
||||
|
||||
let mut buff = Buffer::new();
|
||||
buff.draw_box(Rectangle { x: 0., y: 0., w: 1., h: 1. }, [0., 0.13, 0.08, 1.]);
|
||||
// FIXME: layer dim is passed here manually!
|
||||
// we should just use separate objs
|
||||
buff.draw_outline(
|
||||
Rectangle { x: 0., y: 0., w: 1., h: 1. },
|
||||
[0.22, 0.22, 0.22, 1.],
|
||||
1.,
|
||||
1000.,
|
||||
50.,
|
||||
);
|
||||
prop.set_buf(0, buff.verts).unwrap();
|
||||
prop.set_buf(1, buff.faces).unwrap();
|
||||
|
||||
// Make the nicktext border
|
||||
let node_id = create_mesh(sg, "nickbg");
|
||||
let node = sg.get_node(node_id).unwrap();
|
||||
let prop = node.get_property("rect").unwrap();
|
||||
prop.set_f32(0, 0.).unwrap();
|
||||
let code =
|
||||
vec![Op::Sub((Box::new(Op::LoadVar("lh".to_string())), Box::new(Op::ConstFloat32(60.))))];
|
||||
prop.set_expr(1, code).unwrap();
|
||||
prop.set_f32(2, 130.).unwrap();
|
||||
prop.set_f32(3, 60.).unwrap();
|
||||
|
||||
let prop = node.get_property("data").unwrap();
|
||||
|
||||
let mut buff = Buffer::new();
|
||||
// FIXME: layer dim is passed here manually!
|
||||
// we should just use separate objs
|
||||
buff.draw_outline(
|
||||
Rectangle { x: 0., y: 0., w: 1., h: 1. },
|
||||
[0., 0.13, 0.08, 1.],
|
||||
1.,
|
||||
1000.,
|
||||
50.,
|
||||
);
|
||||
prop.set_buf(0, buff.verts).unwrap();
|
||||
prop.set_buf(1, buff.faces).unwrap();
|
||||
|
||||
// Nickname
|
||||
let node_id = create_text(sg, "nick", layer_node_id);
|
||||
let node = sg.get_node(node_id).unwrap();
|
||||
let prop = node.get_property("rect").unwrap();
|
||||
prop.set_f32(0, 20.).unwrap();
|
||||
let code =
|
||||
vec![Op::Sub((Box::new(Op::LoadVar("lh".to_string())), Box::new(Op::ConstFloat32(60.))))];
|
||||
prop.set_expr(1, code).unwrap();
|
||||
prop.set_f32(2, 120.).unwrap();
|
||||
prop.set_f32(3, 60.).unwrap();
|
||||
node.set_property_f32("baseline", 40.).unwrap();
|
||||
node.set_property_f32("font_size", 20.).unwrap();
|
||||
node.set_property_str("text", "anon1").unwrap();
|
||||
let prop = node.get_property("color").unwrap();
|
||||
prop.set_f32(0, 0.).unwrap();
|
||||
prop.set_f32(1, 1.).unwrap();
|
||||
prop.set_f32(2, 0.).unwrap();
|
||||
prop.set_f32(3, 1.).unwrap();
|
||||
node.set_property_u32("z_index", 1).unwrap();
|
||||
|
||||
// Text edit
|
||||
let node_id = create_editbox(sg, "editz", layer_node_id);
|
||||
let node = sg.get_node(node_id).unwrap();
|
||||
node.set_property_bool("is_active", true).unwrap();
|
||||
let prop = node.get_property("rect").unwrap();
|
||||
prop.set_f32(0, 150.).unwrap();
|
||||
let code =
|
||||
vec![Op::Sub((Box::new(Op::LoadVar("lh".to_string())), Box::new(Op::ConstFloat32(60.))))];
|
||||
prop.set_expr(1, code).unwrap();
|
||||
let code =
|
||||
vec![Op::Sub((Box::new(Op::LoadVar("lw".to_string())), Box::new(Op::ConstFloat32(120.))))];
|
||||
prop.set_expr(2, code).unwrap();
|
||||
prop.set_f32(3, 60.).unwrap();
|
||||
node.set_property_f32("baseline", 40.).unwrap();
|
||||
node.set_property_f32("font_size", 20.).unwrap();
|
||||
//node.set_property_str("text", "hello king!😁🍆jelly 🍆1234").unwrap();
|
||||
node.set_property_str("text", "hello king! jelly 1234").unwrap();
|
||||
let prop = node.get_property("text_color").unwrap();
|
||||
prop.set_f32(0, 1.).unwrap();
|
||||
prop.set_f32(1, 1.).unwrap();
|
||||
prop.set_f32(2, 1.).unwrap();
|
||||
prop.set_f32(3, 1.).unwrap();
|
||||
let prop = node.get_property("cursor_color").unwrap();
|
||||
prop.set_f32(0, 1.).unwrap();
|
||||
prop.set_f32(1, 0.5).unwrap();
|
||||
prop.set_f32(2, 0.5).unwrap();
|
||||
prop.set_f32(3, 1.).unwrap();
|
||||
let prop = node.get_property("hi_bg_color").unwrap();
|
||||
prop.set_f32(0, 1.).unwrap();
|
||||
prop.set_f32(1, 1.).unwrap();
|
||||
prop.set_f32(2, 1.).unwrap();
|
||||
prop.set_f32(3, 0.5).unwrap();
|
||||
let prop = node.get_property("selected").unwrap();
|
||||
prop.set_null(0).unwrap();
|
||||
prop.set_null(1).unwrap();
|
||||
node.set_property_u32("z_index", 1).unwrap();
|
||||
|
||||
let node_id = node.id;
|
||||
let mut arg_data = vec![];
|
||||
node_id.encode(&mut arg_data).unwrap();
|
||||
//let (tx, rx) = mpsc::sync_channel::<Result<Vec<u8>>>(0);
|
||||
let response_fn = Box::new(move |result| {
|
||||
//tx.send(result).unwrap();
|
||||
});
|
||||
let win_node = sg.lookup_node_mut("/window").unwrap();
|
||||
win_node.call_method("create_edit_box", arg_data, response_fn).unwrap();
|
||||
//let _result = rx.recv().unwrap();
|
||||
|
||||
// ChatView
|
||||
let node_id = create_chatview(sg, "chatty", layer_node_id);
|
||||
let node = sg.get_node(node_id).unwrap();
|
||||
let prop = node.get_property("rect").unwrap();
|
||||
prop.set_f32(0, 0.).unwrap();
|
||||
prop.set_f32(1, 0.).unwrap();
|
||||
let code = vec![Op::LoadVar("lw".to_string())];
|
||||
prop.set_expr(2, code).unwrap();
|
||||
let code =
|
||||
vec![Op::Sub((Box::new(Op::LoadVar("lh".to_string())), Box::new(Op::ConstFloat32(50.))))];
|
||||
prop.set_expr(3, code).unwrap();
|
||||
node.set_property_u32("z_index", 1).unwrap();
|
||||
|
||||
// On android lets scale the UI up
|
||||
let win_node = sg.lookup_node_mut("/window").unwrap();
|
||||
win_node.set_property_f32("scale", 1.6).unwrap();
|
||||
|
||||
let layer_node = sg.get_node(layer_node_id).unwrap();
|
||||
layer_node.set_property_bool("is_visible", true).unwrap();
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
/* 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 atomic_float::AtomicF32;
|
||||
use miniquad::{TextureId, UniformType};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{BufRead, BufReader},
|
||||
path::Path,
|
||||
sync::{
|
||||
atomic::Ordering,
|
||||
Arc, Mutex,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
gfx::{
|
||||
FreetypeFace, Point, Rectangle, RenderContext,
|
||||
COLOR_RED, COLOR_WHITE,
|
||||
},
|
||||
prop::PropertyBool,
|
||||
scene::{Pimpl, SceneGraph, SceneNodeId},
|
||||
text::{Glyph, TextShaper},
|
||||
};
|
||||
|
||||
fn read_lines<P>(filename: P) -> Vec<String>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
//let file = File::open(filename).unwrap();
|
||||
//BufReader::new(file).lines().map(|l| l.unwrap()).collect()
|
||||
// Just so we can package for android easily
|
||||
// Later this will be all replaced anyway
|
||||
let file = include_bytes!("../chat.txt");
|
||||
BufReader::new(&file[..]).lines().map(|l| l.unwrap()).collect()
|
||||
}
|
||||
|
||||
pub type ChatViewPtr = Arc<ChatView>;
|
||||
|
||||
pub struct ChatView {
|
||||
node_name: String,
|
||||
debug: PropertyBool,
|
||||
// Used for mouse interaction
|
||||
world_rect: Mutex<Rectangle<f32>>,
|
||||
mouse_pos: Mutex<Point<f32>>,
|
||||
text_shaper: TextShaper,
|
||||
scroll: AtomicF32,
|
||||
lines: Vec<String>,
|
||||
glyph_lines: Mutex<Vec<Vec<Glyph>>>,
|
||||
atlas: Mutex<HashMap<(u32, [u8; 4]), TextureId>>,
|
||||
}
|
||||
|
||||
impl ChatView {
|
||||
pub fn new(
|
||||
scene_graph: &mut SceneGraph,
|
||||
node_id: SceneNodeId,
|
||||
font_faces: Vec<FreetypeFace>,
|
||||
) -> Result<Pimpl> {
|
||||
let node = scene_graph.get_node(node_id).unwrap();
|
||||
let node_name = node.name.clone();
|
||||
let debug = PropertyBool::wrap(node, "debug", 0)?;
|
||||
|
||||
let text_shaper = TextShaper { font_faces };
|
||||
|
||||
let lines = read_lines("chat.txt");
|
||||
let mut glyph_lines = vec![];
|
||||
glyph_lines.resize(lines.len(), vec![]);
|
||||
|
||||
let self_ = Arc::new(Self {
|
||||
node_name: node_name.clone(),
|
||||
debug,
|
||||
world_rect: Mutex::new(Rectangle { x: 0., y: 0., w: 0., h: 0. }),
|
||||
mouse_pos: Mutex::new(Point { x: 0., y: 0. }),
|
||||
text_shaper,
|
||||
scroll: AtomicF32::new(0.),
|
||||
lines,
|
||||
glyph_lines: Mutex::new(glyph_lines),
|
||||
atlas: Mutex::new(HashMap::new()),
|
||||
});
|
||||
|
||||
/*
|
||||
let weak_self = Arc::downgrade(&self_);
|
||||
let slot_move = Slot {
|
||||
name: format!("{}::mouse_move", node_name),
|
||||
func: Box::new(move |data| {
|
||||
let mut cur = Cursor::new(&data);
|
||||
let x = f32::decode(&mut cur).unwrap();
|
||||
let y = f32::decode(&mut cur).unwrap();
|
||||
|
||||
let self_ = weak_self.upgrade();
|
||||
if let Some(self_) = self_ {
|
||||
let pos = &mut *self_.mouse_pos.lock().unwrap();
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
let weak_self = Arc::downgrade(&self_);
|
||||
let slot_wheel = Slot {
|
||||
name: format!("{}::mouse_wheel", node_name),
|
||||
func: Box::new(move |data| {
|
||||
let mut cur = Cursor::new(&data);
|
||||
let x = f32::decode(&mut cur).unwrap();
|
||||
let y = f32::decode(&mut cur).unwrap();
|
||||
|
||||
let self_ = weak_self.upgrade();
|
||||
if let Some(self_) = self_ {
|
||||
self_.mouse_scroll(x, y);
|
||||
}
|
||||
}),
|
||||
};
|
||||
*/
|
||||
|
||||
let mouse_node =
|
||||
scene_graph.lookup_node_mut("/window/input/mouse").expect("no mouse attached!");
|
||||
//mouse_node.register("wheel", slot_wheel);
|
||||
//mouse_node.register("move", slot_move);
|
||||
|
||||
// Save any properties we use
|
||||
Ok(Pimpl::ChatView(self_))
|
||||
}
|
||||
|
||||
pub fn render<'a>(
|
||||
&self,
|
||||
render: &mut RenderContext<'a>,
|
||||
node_id: SceneNodeId,
|
||||
layer_rect: &Rectangle<f32>,
|
||||
) -> Result<()> {
|
||||
let debug = self.debug.get();
|
||||
|
||||
let node = render.scene_graph.get_node(node_id).unwrap();
|
||||
let rect = RenderContext::get_dim(node, layer_rect)?;
|
||||
|
||||
// Used for detecting mouse clicks
|
||||
let mut world_rect = rect.clone();
|
||||
world_rect.x += layer_rect.x as f32;
|
||||
world_rect.y += layer_rect.y as f32;
|
||||
*self.world_rect.lock().unwrap() = world_rect;
|
||||
|
||||
let layer_w = layer_rect.w as f32;
|
||||
let layer_h = layer_rect.h as f32;
|
||||
let off_x = rect.x / layer_w;
|
||||
let off_y = rect.y / layer_h;
|
||||
// Use absolute pixel scale
|
||||
let scale_x = 1. / layer_w;
|
||||
let scale_y = 1. / layer_h;
|
||||
let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
|
||||
glam::Mat4::from_scale(glam::Vec3::new(scale_x, scale_y, 1.));
|
||||
|
||||
let mut uniforms_data = [0u8; 128];
|
||||
let data: [u8; 64] = unsafe { std::mem::transmute_copy(&render.proj) };
|
||||
uniforms_data[0..64].copy_from_slice(&data);
|
||||
let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
|
||||
uniforms_data[64..].copy_from_slice(&data);
|
||||
assert_eq!(128, 2 * UniformType::Mat4.size());
|
||||
|
||||
render.ctx.apply_uniforms_from_bytes(uniforms_data.as_ptr(), uniforms_data.len());
|
||||
|
||||
// Used for scaling the font size
|
||||
let window = render.scene_graph.lookup_node("/window").expect("no window attached!");
|
||||
let window_scale = window.get_property_f32("scale")?;
|
||||
let font_size = window_scale * 20.;
|
||||
|
||||
let bound = Rectangle { x: 0., y: 0., w: rect.w, h: rect.h };
|
||||
|
||||
let glyph_lines = &mut self.glyph_lines.lock().unwrap();
|
||||
let atlas = &mut self.atlas.lock().unwrap();
|
||||
|
||||
let scroll = self.scroll.load(Ordering::Relaxed);
|
||||
for (i, (line, glyph_line)) in self.lines.iter().zip(glyph_lines.iter_mut()).enumerate() {
|
||||
let line = line.replace("\t", " ");
|
||||
|
||||
// Split time and nick from the line
|
||||
let mut iter = line.split_whitespace();
|
||||
let Some(time) = iter.next() else {
|
||||
error!("line missing time");
|
||||
continue
|
||||
};
|
||||
let Some(nick) = iter.next() else {
|
||||
error!("line missing nick");
|
||||
continue
|
||||
};
|
||||
let Some(line) = iter.remainder() else {
|
||||
error!("line missing remainder");
|
||||
continue
|
||||
};
|
||||
|
||||
let linespacing = window_scale * 30.;
|
||||
let off_y = linespacing * i as f32 + scroll;
|
||||
if off_y + linespacing < 0. || off_y - linespacing > rect.h {
|
||||
continue;
|
||||
}
|
||||
|
||||
if glyph_line.is_empty() {
|
||||
*glyph_line = self.text_shaper.shape(line.to_string(), font_size, COLOR_WHITE);
|
||||
}
|
||||
|
||||
let times_color = [0.4, 0.4, 0.4, 1.];
|
||||
let times_color_u8 =
|
||||
[(255. * 0.4) as u8, (255. * 0.4) as u8, (255. * 0.4) as u8, (255. * 1.) as u8];
|
||||
let glyphs_time = self.text_shaper.shape(time.to_string(), font_size, times_color);
|
||||
let mut rhs = 0.;
|
||||
for glyph in glyphs_time {
|
||||
let mut pos = glyph.pos.clone();
|
||||
pos.y += off_y;
|
||||
rhs = pos.x + pos.w;
|
||||
|
||||
assert_eq!(glyph.bmp.len() as u16, glyph.bmp_width * glyph.bmp_height * 4);
|
||||
//debug!("gly {} {}", glyph.substr, glyph.bmp.len());
|
||||
let texture = if atlas.contains_key(&(glyph.id, times_color_u8.clone())) {
|
||||
*atlas.get(&(glyph.id, times_color_u8.clone())).unwrap()
|
||||
} else {
|
||||
let texture = render.ctx.new_texture_from_rgba8(
|
||||
glyph.bmp_width,
|
||||
glyph.bmp_height,
|
||||
&glyph.bmp,
|
||||
);
|
||||
atlas.insert((glyph.id, times_color_u8.clone()), texture);
|
||||
texture
|
||||
};
|
||||
render.render_clipped_box_with_texture2(&bound, &pos, COLOR_WHITE, texture);
|
||||
//render.ctx.delete_texture(texture);
|
||||
}
|
||||
|
||||
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.],
|
||||
];
|
||||
let nick_colors_u8 = [
|
||||
[(255. * 0.00) as u8, (255. * 0.94) as u8, (255. * 1.00) as u8, (255. * 1.) as u8],
|
||||
[(255. * 0.36) as u8, (255. * 1.00) as u8, (255. * 0.69) as u8, (255. * 1.) as u8],
|
||||
[(255. * 0.29) as u8, (255. * 1.00) as u8, (255. * 0.45) as u8, (255. * 1.) as u8],
|
||||
[(255. * 0.00) as u8, (255. * 0.73) as u8, (255. * 0.38) as u8, (255. * 1.) as u8],
|
||||
[(255. * 0.21) as u8, (255. * 0.67) as u8, (255. * 0.67) as u8, (255. * 1.) as u8],
|
||||
[(255. * 0.56) as u8, (255. * 0.61) as u8, (255. * 1.00) as u8, (255. * 1.) as u8],
|
||||
[(255. * 0.84) as u8, (255. * 0.48) as u8, (255. * 1.00) as u8, (255. * 1.) as u8],
|
||||
[(255. * 1.00) as u8, (255. * 0.61) as u8, (255. * 0.94) as u8, (255. * 1.) as u8],
|
||||
[(255. * 1.00) as u8, (255. * 0.36) as u8, (255. * 0.48) as u8, (255. * 1.) as u8],
|
||||
[(255. * 1.00) as u8, (255. * 0.30) as u8, (255. * 0.00) as u8, (255. * 1.) as u8],
|
||||
];
|
||||
|
||||
let nick_color = nick_colors[nick.len() % nick_colors.len()];
|
||||
let nick_color_u8 = nick_colors_u8[nick.len() % nick_colors.len()];
|
||||
let glyphs_nick = self.text_shaper.shape(nick.to_string(), font_size, nick_color);
|
||||
let off_x = rhs + window_scale * 20.;
|
||||
for glyph in glyphs_nick {
|
||||
let mut pos = glyph.pos.clone();
|
||||
pos.x += off_x;
|
||||
pos.y += off_y;
|
||||
rhs = pos.x + pos.w;
|
||||
|
||||
assert_eq!(glyph.bmp.len() as u16, glyph.bmp_width * glyph.bmp_height * 4);
|
||||
//debug!("gly {} {}", glyph.substr, glyph.bmp.len());
|
||||
//let texture = render.ctx.new_texture_from_rgba8(glyph.bmp_width, glyph.bmp_height, &glyph.bmp);
|
||||
let texture = if atlas.contains_key(&(glyph.id, nick_color_u8.clone())) {
|
||||
*atlas.get(&(glyph.id, nick_color_u8.clone())).unwrap()
|
||||
} else {
|
||||
let texture = render.ctx.new_texture_from_rgba8(
|
||||
glyph.bmp_width,
|
||||
glyph.bmp_height,
|
||||
&glyph.bmp,
|
||||
);
|
||||
atlas.insert((glyph.id, nick_color_u8.clone()), texture);
|
||||
texture
|
||||
};
|
||||
render.render_clipped_box_with_texture2(&bound, &pos, COLOR_WHITE, texture);
|
||||
//render.ctx.delete_texture(texture);
|
||||
}
|
||||
|
||||
let off_x = rhs + window_scale * 20.;
|
||||
for glyph in glyph_line {
|
||||
let mut pos = glyph.pos.clone();
|
||||
pos.x += off_x;
|
||||
pos.y += off_y;
|
||||
|
||||
assert_eq!(glyph.bmp.len() as u16, glyph.bmp_width * glyph.bmp_height * 4);
|
||||
//debug!("gly {} {}", glyph.substr, glyph.bmp.len());
|
||||
//let texture = render.ctx.new_texture_from_rgba8(glyph.bmp_width, glyph.bmp_height, &glyph.bmp);
|
||||
let texture = if atlas.contains_key(&(glyph.id, [255, 255, 255, 255])) {
|
||||
*atlas.get(&(glyph.id, [255, 255, 255, 255])).unwrap()
|
||||
} else {
|
||||
let texture = render.ctx.new_texture_from_rgba8(
|
||||
glyph.bmp_width,
|
||||
glyph.bmp_height,
|
||||
&glyph.bmp,
|
||||
);
|
||||
atlas.insert((glyph.id, [255, 255, 255, 255]), texture);
|
||||
texture
|
||||
};
|
||||
render.render_clipped_box_with_texture2(&bound, &pos, COLOR_WHITE, texture);
|
||||
//render.ctx.delete_texture(texture);
|
||||
}
|
||||
}
|
||||
|
||||
if debug {
|
||||
render.outline(0., 0., rect.w, rect.h, COLOR_RED, 1.);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mouse_scroll(self: Arc<Self>, _x: f32, y: f32) {
|
||||
let mouse_pos = &*self.mouse_pos.lock().unwrap();
|
||||
if !self.world_rect.lock().unwrap().contains(mouse_pos) {
|
||||
return;
|
||||
}
|
||||
drop(mouse_pos);
|
||||
|
||||
self.scroll.fetch_add(y * 10., Ordering::Relaxed);
|
||||
// y = 1 for scroll up
|
||||
// y = -1 for scroll down
|
||||
//println!("{}", y);
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ use darkfi_serial::{
|
||||
use crate::{
|
||||
net::ZeroMQAdapter,
|
||||
scene::{SceneGraph, SceneGraphPtr2},
|
||||
text2::TextShaper,
|
||||
text::TextShaper,
|
||||
ExecutorPtr,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,865 +0,0 @@
|
||||
/* 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 log::{debug, info};
|
||||
use miniquad::{window, KeyMods, MouseButton, TextureId, UniformType};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex,
|
||||
},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
gfx::{
|
||||
FreetypeFace, Point, Rectangle, RenderContext, COLOR_DARKGREY, COLOR_GREEN, COLOR_WHITE,
|
||||
},
|
||||
prop::{Property, PropertyBool, PropertyColor, PropertyFloat32, PropertyStr, PropertyUint32},
|
||||
scene::{Pimpl, SceneGraph, SceneNodeId},
|
||||
text::{Glyph, TextShaper},
|
||||
};
|
||||
|
||||
const CURSOR_WIDTH: f32 = 4.;
|
||||
|
||||
struct PressedKeysSmoothRepeat {
|
||||
/// When holding keys, we track from start and last sent time.
|
||||
/// This is useful for initial delay and smooth scrolling.
|
||||
pressed_keys: HashMap<String, RepeatingKeyTimer>,
|
||||
/// Initial delay before allowing keys
|
||||
start_delay: u32,
|
||||
/// Minimum time between repeated keys
|
||||
step_time: u32,
|
||||
}
|
||||
|
||||
impl PressedKeysSmoothRepeat {
|
||||
fn new(start_delay: u32, step_time: u32) -> Self {
|
||||
Self { pressed_keys: HashMap::new(), start_delay, step_time }
|
||||
}
|
||||
|
||||
fn key_down(&mut self, key: &str, repeat: bool) -> u32 {
|
||||
if !repeat {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Insert key if not exists
|
||||
if !self.pressed_keys.contains_key(key) {
|
||||
self.pressed_keys.insert(key.to_string(), RepeatingKeyTimer::new());
|
||||
}
|
||||
|
||||
let repeater = self.pressed_keys.get_mut(key).expect("repeat map");
|
||||
repeater.update(self.start_delay, self.step_time)
|
||||
}
|
||||
|
||||
fn key_up(&mut self, key: &str) {
|
||||
self.pressed_keys.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
struct RepeatingKeyTimer {
|
||||
start: Instant,
|
||||
actions: u32,
|
||||
}
|
||||
|
||||
impl RepeatingKeyTimer {
|
||||
fn new() -> Self {
|
||||
Self { start: Instant::now(), actions: 0 }
|
||||
}
|
||||
|
||||
fn update(&mut self, start_delay: u32, step_time: u32) -> u32 {
|
||||
let elapsed = self.start.elapsed().as_millis();
|
||||
if elapsed < start_delay as u128 {
|
||||
return 0
|
||||
}
|
||||
let total_actions = ((elapsed - start_delay as u128) / step_time as u128) as u32;
|
||||
let remaining_actions = total_actions - self.actions;
|
||||
self.actions = total_actions;
|
||||
remaining_actions
|
||||
}
|
||||
}
|
||||
|
||||
pub type EditBoxPtr = Arc<EditBox>;
|
||||
|
||||
pub struct EditBox {
|
||||
node_name: String,
|
||||
is_active: PropertyBool,
|
||||
debug: PropertyBool,
|
||||
baseline: PropertyFloat32,
|
||||
scroll: PropertyFloat32,
|
||||
cursor_pos: PropertyUint32,
|
||||
selected: Arc<Property>,
|
||||
text: PropertyStr,
|
||||
font_size: PropertyFloat32,
|
||||
text_color: PropertyColor,
|
||||
cursor_color: PropertyColor,
|
||||
hi_bg_color: PropertyColor,
|
||||
// Used for mouse clicks
|
||||
world_rect: Mutex<Rectangle<f32>>,
|
||||
glyphs: Mutex<Vec<Glyph>>,
|
||||
text_shaper: TextShaper,
|
||||
key_repeat: Mutex<PressedKeysSmoothRepeat>,
|
||||
mouse_btn_held: AtomicBool,
|
||||
window_scale: f32,
|
||||
screen_size: Arc<Property>,
|
||||
atlas: Mutex<HashMap<u32, TextureId>>,
|
||||
}
|
||||
|
||||
impl EditBox {
|
||||
pub fn new(
|
||||
scene_graph: &mut SceneGraph,
|
||||
node_id: SceneNodeId,
|
||||
font_faces: Vec<FreetypeFace>,
|
||||
) -> Result<Pimpl> {
|
||||
let node = scene_graph.get_node(node_id).unwrap();
|
||||
let node_name = node.name.clone();
|
||||
let is_active = PropertyBool::wrap(node, "is_active", 0)?;
|
||||
let debug = PropertyBool::wrap(node, "debug", 0)?;
|
||||
let baseline = PropertyFloat32::wrap(node, "baseline", 0)?;
|
||||
let scroll = PropertyFloat32::wrap(node, "scroll", 0)?;
|
||||
let cursor_pos = PropertyUint32::wrap(node, "cursor_pos", 0)?;
|
||||
let selected = node.get_property("selected").ok_or(Error::PropertyNotFound)?;
|
||||
let text = PropertyStr::wrap(node, "text", 0)?;
|
||||
let font_size = PropertyFloat32::wrap(node, "font_size", 0)?;
|
||||
let text_color = PropertyColor::wrap(node, "text_color")?;
|
||||
let cursor_color = PropertyColor::wrap(node, "cursor_color")?;
|
||||
let hi_bg_color = PropertyColor::wrap(node, "hi_bg_color")?;
|
||||
|
||||
let text_shaper = TextShaper { font_faces };
|
||||
|
||||
// TODO: catch window resize event and regen glyphs
|
||||
// Used for scaling the font size
|
||||
let window_node = scene_graph.lookup_node("/window").expect("no window attached!");
|
||||
let window_scale = window_node.get_property_f32("scale")?;
|
||||
let screen_size = window_node.get_property("screen_size").ok_or(Error::PropertyNotFound)?;
|
||||
|
||||
let self_ = Arc::new(Self {
|
||||
node_name: node_name.clone(),
|
||||
is_active,
|
||||
debug,
|
||||
baseline,
|
||||
scroll,
|
||||
cursor_pos,
|
||||
selected,
|
||||
text,
|
||||
font_size,
|
||||
text_color,
|
||||
cursor_color,
|
||||
hi_bg_color,
|
||||
world_rect: Mutex::new(Rectangle { x: 0., y: 0., w: 0., h: 0. }),
|
||||
glyphs: Mutex::new(vec![]),
|
||||
text_shaper,
|
||||
key_repeat: Mutex::new(PressedKeysSmoothRepeat::new(400, 50)),
|
||||
mouse_btn_held: AtomicBool::new(false),
|
||||
window_scale,
|
||||
screen_size,
|
||||
atlas: Mutex::new(HashMap::new()),
|
||||
});
|
||||
self_.regen_glyphs().unwrap();
|
||||
|
||||
/*
|
||||
let weak_self = Arc::downgrade(&self_);
|
||||
let slot_key_down = Slot {
|
||||
name: format!("{}::key_down", node_name),
|
||||
func: Box::new(move |data| {
|
||||
let mut cur = Cursor::new(&data);
|
||||
let keymods = KeyMods {
|
||||
shift: Decodable::decode(&mut cur).unwrap(),
|
||||
ctrl: Decodable::decode(&mut cur).unwrap(),
|
||||
alt: Decodable::decode(&mut cur).unwrap(),
|
||||
logo: Decodable::decode(&mut cur).unwrap(),
|
||||
};
|
||||
let repeat = bool::decode(&mut cur).unwrap();
|
||||
let key = String::decode(&mut cur).unwrap();
|
||||
|
||||
let self_ = weak_self.upgrade();
|
||||
if let Some(self_) = self_ {
|
||||
self_.key_down(key, keymods, repeat);
|
||||
}
|
||||
}),
|
||||
};
|
||||
let weak_self = Arc::downgrade(&self_);
|
||||
let slot_key_up = Slot {
|
||||
name: format!("{}::key_up", node_name),
|
||||
func: Box::new(move |data| {
|
||||
let mut cur = Cursor::new(&data);
|
||||
let keymods = KeyMods {
|
||||
shift: Decodable::decode(&mut cur).unwrap(),
|
||||
ctrl: Decodable::decode(&mut cur).unwrap(),
|
||||
alt: Decodable::decode(&mut cur).unwrap(),
|
||||
logo: Decodable::decode(&mut cur).unwrap(),
|
||||
};
|
||||
let key = String::decode(&mut cur).unwrap();
|
||||
|
||||
let self_ = weak_self.upgrade();
|
||||
if let Some(self_) = self_ {
|
||||
self_.key_up(key, keymods);
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
let keyb_node =
|
||||
scene_graph
|
||||
.lookup_node_mut("/window/input/keyboard")
|
||||
.expect("no keyboard attached!");
|
||||
keyb_node.register("key_down", slot_key_down).unwrap();
|
||||
keyb_node.register("key_up", slot_key_up).unwrap();
|
||||
|
||||
let weak_self = Arc::downgrade(&self_);
|
||||
let slot_btn_down = Slot {
|
||||
name: format!("{}::mouse_button_down", node_name),
|
||||
func: Box::new(move |data| {
|
||||
let mut cur = Cursor::new(&data);
|
||||
let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
|
||||
let x = f32::decode(&mut cur).unwrap();
|
||||
let y = f32::decode(&mut cur).unwrap();
|
||||
|
||||
let self_ = weak_self.upgrade();
|
||||
if let Some(self_) = self_ {
|
||||
self_.mouse_button_down(button, x, y);
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
let weak_self = Arc::downgrade(&self_);
|
||||
let slot_btn_up = Slot {
|
||||
name: format!("{}::mouse_button_up", node_name),
|
||||
func: Box::new(move |data| {
|
||||
let mut cur = Cursor::new(&data);
|
||||
let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
|
||||
let x = f32::decode(&mut cur).unwrap();
|
||||
let y = f32::decode(&mut cur).unwrap();
|
||||
|
||||
let self_ = weak_self.upgrade();
|
||||
if let Some(self_) = self_ {
|
||||
self_.mouse_button_up(button, x, y);
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
let weak_self = Arc::downgrade(&self_);
|
||||
let slot_move = Slot {
|
||||
name: format!("{}::mouse_move", node_name),
|
||||
func: Box::new(move |data| {
|
||||
let mut cur = Cursor::new(&data);
|
||||
let x = f32::decode(&mut cur).unwrap();
|
||||
let y = f32::decode(&mut cur).unwrap();
|
||||
|
||||
let self_ = weak_self.upgrade();
|
||||
if let Some(self_) = self_ {
|
||||
self_.mouse_move(x, y);
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
let mouse_node =
|
||||
scene_graph
|
||||
.lookup_node_mut("/window/input/mouse")
|
||||
.expect("no mouse attached!");
|
||||
mouse_node.register("button_down", slot_btn_down).unwrap();
|
||||
mouse_node.register("button_up", slot_btn_up).unwrap();
|
||||
mouse_node.register("move", slot_move).unwrap();
|
||||
|
||||
let weak_self = Arc::downgrade(&self_);
|
||||
let slot_resize = Slot {
|
||||
name: format!("{}::window_resize", node_name),
|
||||
func: Box::new(move |data| {
|
||||
let mut cur = Cursor::new(&data);
|
||||
let w = f32::decode(&mut cur).unwrap();
|
||||
let h = f32::decode(&mut cur).unwrap();
|
||||
|
||||
let self_ = weak_self.upgrade();
|
||||
if let Some(self_) = self_ {
|
||||
self_.window_resize(w, h);
|
||||
}
|
||||
}),
|
||||
};
|
||||
*/
|
||||
|
||||
let window_node = scene_graph.lookup_node_mut("/window").expect("no window attached!");
|
||||
//window_node.register("resize", slot_resize).unwrap();
|
||||
|
||||
// Save any properties we use
|
||||
Ok(Pimpl::EditBox(self_))
|
||||
}
|
||||
|
||||
pub fn render<'a>(
|
||||
&self,
|
||||
render: &mut RenderContext<'a>,
|
||||
node_id: SceneNodeId,
|
||||
layer_rect: &Rectangle<f32>,
|
||||
) -> Result<()> {
|
||||
let node = render.scene_graph.get_node(node_id).unwrap();
|
||||
|
||||
let rect = RenderContext::get_dim(node, layer_rect)?;
|
||||
|
||||
// Used for detecting mouse clicks
|
||||
let mut world_rect = rect.clone();
|
||||
world_rect.x += layer_rect.x as f32;
|
||||
world_rect.y += layer_rect.y as f32;
|
||||
world_rect.x *= self.window_scale;
|
||||
world_rect.y *= self.window_scale;
|
||||
world_rect.w *= self.window_scale;
|
||||
world_rect.h *= self.window_scale;
|
||||
*self.world_rect.lock().unwrap() = world_rect;
|
||||
|
||||
let layer_w = layer_rect.w as f32;
|
||||
let layer_h = layer_rect.h as f32;
|
||||
let off_x = rect.x / layer_w;
|
||||
let off_y = rect.y / layer_h;
|
||||
// Use absolute pixel scale
|
||||
let scale_x = 1. / layer_w;
|
||||
let scale_y = 1. / layer_h;
|
||||
//let model = glam::Mat4::IDENTITY;
|
||||
let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
|
||||
glam::Mat4::from_scale(glam::Vec3::new(scale_x, scale_y, 1.));
|
||||
|
||||
let mut uniforms_data = [0u8; 128];
|
||||
let data: [u8; 64] = unsafe { std::mem::transmute_copy(&render.proj) };
|
||||
uniforms_data[0..64].copy_from_slice(&data);
|
||||
let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
|
||||
uniforms_data[64..].copy_from_slice(&data);
|
||||
assert_eq!(128, 2 * UniformType::Mat4.size());
|
||||
|
||||
render.ctx.apply_uniforms_from_bytes(uniforms_data.as_ptr(), uniforms_data.len());
|
||||
|
||||
self.apply_cursor_scrolling(&rect);
|
||||
|
||||
let node = render.scene_graph.get_node(node_id).unwrap();
|
||||
let debug = self.debug.get();
|
||||
let baseline = self.baseline.get();
|
||||
let scroll = self.scroll.get();
|
||||
let cursor_pos = self.cursor_pos.get() as usize;
|
||||
let cursor_color = self.cursor_color.get();
|
||||
let text_color = self.text_color.get();
|
||||
|
||||
let glyphs = &*self.glyphs.lock().unwrap();
|
||||
let atlas = &mut self.atlas.lock().unwrap();
|
||||
|
||||
if !self.selected.is_null(0)? && !self.selected.is_null(1)? {
|
||||
self.render_selected(render, &rect, glyphs)?;
|
||||
}
|
||||
|
||||
let bound = Rectangle { x: 0., y: 0., w: rect.w, h: rect.h };
|
||||
|
||||
let mut rhs = 0.;
|
||||
for (glyph_idx, glyph) in glyphs.iter().enumerate() {
|
||||
let x1 = glyph.pos.x + scroll;
|
||||
let y1 = glyph.pos.y + baseline;
|
||||
let x2 = x1 + glyph.pos.w;
|
||||
let y2 = y1 + glyph.pos.h;
|
||||
|
||||
let texture = if atlas.contains_key(&glyph.id) {
|
||||
*atlas.get(&glyph.id).unwrap()
|
||||
} else {
|
||||
let texture = render.ctx.new_texture_from_rgba8(
|
||||
glyph.bmp_width,
|
||||
glyph.bmp_height,
|
||||
&glyph.bmp,
|
||||
);
|
||||
atlas.insert(glyph.id, texture);
|
||||
texture
|
||||
};
|
||||
//let texture = render.ctx.new_texture_from_rgba8(glyph.bmp_width, glyph.bmp_height, &glyph.bmp);
|
||||
render.render_clipped_box_with_texture(&bound, x1, y1, x2, y2, COLOR_WHITE, texture);
|
||||
//render.render_box_with_texture(x1, y1, x2, y2, COLOR_WHITE, texture);
|
||||
//render.ctx.delete_texture(texture);
|
||||
|
||||
// Glyph outlines
|
||||
//if debug {
|
||||
// render.outline(x1, y1, x2, y2, COLOR_BLUE, 1.);
|
||||
//}
|
||||
|
||||
if cursor_pos != 0 && cursor_pos == glyph_idx {
|
||||
render.render_box(x1 - CURSOR_WIDTH, 0., x1, rect.h, cursor_color);
|
||||
}
|
||||
|
||||
rhs = x2;
|
||||
}
|
||||
|
||||
if cursor_pos == 0 {
|
||||
render.render_box(0., 0., CURSOR_WIDTH, rect.h, cursor_color);
|
||||
} else if cursor_pos == glyphs.len() {
|
||||
render.render_box(rhs - CURSOR_WIDTH, 0., rhs, rect.h, cursor_color);
|
||||
}
|
||||
|
||||
if debug {
|
||||
let outline_color = if self.is_active.get() { COLOR_GREEN } else { COLOR_DARKGREY };
|
||||
// Baseline
|
||||
//render.hline(0., rhs, 0., COLOR_RED, 1.);
|
||||
render.outline(0., 0., rect.w, rect.h, outline_color, 1.);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn render_selected<'a>(
|
||||
&self,
|
||||
render: &mut RenderContext<'a>,
|
||||
rect: &Rectangle<f32>,
|
||||
glyphs: &Vec<Glyph>,
|
||||
) -> Result<()> {
|
||||
let start = self.selected.get_u32(0)? as usize;
|
||||
let end = self.selected.get_u32(1)? as usize;
|
||||
|
||||
let sel_start = std::cmp::min(start, end);
|
||||
let sel_end = std::cmp::max(start, end);
|
||||
|
||||
let scroll = self.scroll.get();
|
||||
let hi_bg_color = self.hi_bg_color.get();
|
||||
|
||||
let mut start_x = 0.;
|
||||
let mut end_x = 0.;
|
||||
|
||||
for (glyph_idx, glyph) in glyphs.iter().enumerate() {
|
||||
let x1 = glyph.pos.x + scroll;
|
||||
|
||||
if glyph_idx == sel_start {
|
||||
start_x = x1;
|
||||
}
|
||||
if glyph_idx == sel_end {
|
||||
end_x = x1;
|
||||
}
|
||||
}
|
||||
if sel_start == 0 {
|
||||
start_x = scroll;
|
||||
}
|
||||
if sel_end == glyphs.len() {
|
||||
let glyph = &glyphs.last().unwrap();
|
||||
let x2 = glyph.pos.x + scroll + glyph.pos.w;
|
||||
end_x = x2;
|
||||
}
|
||||
|
||||
// Apply clipping
|
||||
if start_x < 0. {
|
||||
start_x = 0.;
|
||||
}
|
||||
if end_x > rect.w {
|
||||
end_x = rect.w;
|
||||
}
|
||||
render.render_box(start_x, 0., end_x, rect.h, hi_bg_color);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_highlighted(&self) {
|
||||
assert!(!self.selected.is_null(0).unwrap());
|
||||
assert!(!self.selected.is_null(1).unwrap());
|
||||
|
||||
let start = self.selected.get_u32(0).unwrap() as usize;
|
||||
let end = self.selected.get_u32(1).unwrap() as usize;
|
||||
|
||||
let sel_start = std::cmp::min(start, end);
|
||||
let sel_end = std::cmp::max(start, end);
|
||||
|
||||
let glyphs = &*self.glyphs.lock().unwrap();
|
||||
|
||||
// Regen text
|
||||
let mut text = String::new();
|
||||
for (i, glyph) in glyphs.iter().enumerate() {
|
||||
let mut substr = glyph.substr.clone();
|
||||
if sel_start <= i && i < sel_end {
|
||||
continue
|
||||
}
|
||||
text.push_str(&substr);
|
||||
}
|
||||
debug!(
|
||||
"EditBox(\"{}\")::delete_highlighted() text=\"{}\", cursor_pos={}",
|
||||
self.node_name, text, sel_start
|
||||
);
|
||||
self.text.set(text);
|
||||
|
||||
self.selected.set_null(0).unwrap();
|
||||
self.selected.set_null(1).unwrap();
|
||||
self.cursor_pos.set(sel_start as u32);
|
||||
}
|
||||
|
||||
fn apply_cursor_scrolling(&self, rect: &Rectangle<f32>) {
|
||||
let cursor_pos = self.cursor_pos.get() as usize;
|
||||
let mut scroll = self.scroll.get();
|
||||
|
||||
let cursor_x = {
|
||||
let glyphs = &*self.glyphs.lock().unwrap();
|
||||
if cursor_pos == 0 {
|
||||
0.
|
||||
} else if cursor_pos == glyphs.len() {
|
||||
let glyph = &glyphs.last().unwrap();
|
||||
glyph.pos.x + glyph.pos.w
|
||||
} else {
|
||||
assert!(cursor_pos < glyphs.len());
|
||||
let glyph = &glyphs[cursor_pos];
|
||||
glyph.pos.x
|
||||
}
|
||||
};
|
||||
|
||||
let cursor_lhs = cursor_x + scroll;
|
||||
let cursor_rhs = cursor_lhs + CURSOR_WIDTH;
|
||||
|
||||
if cursor_rhs > rect.w {
|
||||
scroll = rect.w - cursor_x;
|
||||
} else if cursor_lhs < 0. {
|
||||
scroll = -cursor_x + CURSOR_WIDTH;
|
||||
}
|
||||
|
||||
self.scroll.set(scroll);
|
||||
}
|
||||
|
||||
fn regen_glyphs(&self) -> Result<()> {
|
||||
let font_size = self.window_scale * self.font_size.get();
|
||||
|
||||
debug!("shape start");
|
||||
let glyphs = self.text_shaper.shape(self.text.get(), font_size, self.text_color.get());
|
||||
debug!("shape end");
|
||||
if self.cursor_pos.get() > glyphs.len() as u32 {
|
||||
self.cursor_pos.set(glyphs.len() as u32);
|
||||
}
|
||||
*self.glyphs.lock().unwrap() = glyphs;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn key_down(self: Arc<Self>, key: String, mods: KeyMods, repeat: bool) {
|
||||
if !self.is_active.get() {
|
||||
return
|
||||
}
|
||||
let actions = {
|
||||
let mut repeater = self.key_repeat.lock().unwrap();
|
||||
repeater.key_down(&key, repeat)
|
||||
};
|
||||
for _ in 0..actions {
|
||||
self.do_key_down(&key, &mods)
|
||||
}
|
||||
}
|
||||
|
||||
fn do_key_down(&self, key: &str, mods: &KeyMods) {
|
||||
match key {
|
||||
"Left" => {
|
||||
let mut cursor_pos = self.cursor_pos.get();
|
||||
|
||||
// Start selection if shift is held
|
||||
if !mods.shift {
|
||||
self.selected.set_null(0).unwrap();
|
||||
self.selected.set_null(1).unwrap();
|
||||
} else if self.selected.is_null(0).unwrap() {
|
||||
assert!(self.selected.is_null(1).unwrap());
|
||||
self.selected.set_u32(0, cursor_pos).unwrap();
|
||||
}
|
||||
|
||||
if cursor_pos > 0 {
|
||||
cursor_pos -= 1;
|
||||
debug!(
|
||||
"EditBox(\"{}\")::key_down(Left) cursor_pos={}",
|
||||
self.node_name, cursor_pos
|
||||
);
|
||||
self.cursor_pos.set(cursor_pos);
|
||||
}
|
||||
|
||||
// Update selection
|
||||
if mods.shift {
|
||||
self.selected.set_u32(1, cursor_pos).unwrap();
|
||||
}
|
||||
}
|
||||
"Right" => {
|
||||
let mut cursor_pos = self.cursor_pos.get();
|
||||
|
||||
// Start selection if shift is held
|
||||
if !mods.shift {
|
||||
self.selected.set_null(0).unwrap();
|
||||
self.selected.set_null(1).unwrap();
|
||||
} else if self.selected.is_null(0).unwrap() {
|
||||
assert!(self.selected.is_null(1).unwrap());
|
||||
self.selected.set_u32(0, cursor_pos).unwrap();
|
||||
}
|
||||
|
||||
let glyphs_len = self.glyphs.lock().unwrap().len() as u32;
|
||||
if cursor_pos < glyphs_len {
|
||||
cursor_pos += 1;
|
||||
debug!(
|
||||
"EditBox(\"{}\")::key_down(Right) cursor_pos={}",
|
||||
self.node_name, cursor_pos
|
||||
);
|
||||
self.cursor_pos.set(cursor_pos);
|
||||
}
|
||||
|
||||
// Update selection
|
||||
if mods.shift {
|
||||
self.selected.set_u32(1, cursor_pos).unwrap();
|
||||
}
|
||||
}
|
||||
"Delete" => {
|
||||
let cursor_pos = self.cursor_pos.get();
|
||||
|
||||
let _text = if !self.selected.is_null(0).unwrap() {
|
||||
self.delete_highlighted();
|
||||
} else {
|
||||
let glyphs = &*self.glyphs.lock().unwrap();
|
||||
|
||||
if cursor_pos == glyphs.len() as u32 {
|
||||
return;
|
||||
}
|
||||
|
||||
// Regen text
|
||||
let mut text = String::new();
|
||||
for (i, glyph) in glyphs.iter().enumerate() {
|
||||
let mut substr = glyph.substr.clone();
|
||||
if cursor_pos as usize == i {
|
||||
// Lmk if anyone knows a better way to do substr.pop_front()
|
||||
let mut chars = substr.chars();
|
||||
chars.next();
|
||||
substr = chars.as_str().to_string();
|
||||
}
|
||||
text.push_str(&substr);
|
||||
}
|
||||
self.text.set(text);
|
||||
};
|
||||
self.regen_glyphs().unwrap();
|
||||
}
|
||||
"Backspace" => {
|
||||
let cursor_pos = self.cursor_pos.get();
|
||||
|
||||
let _text = if !self.selected.is_null(0).unwrap() {
|
||||
self.delete_highlighted();
|
||||
} else {
|
||||
if cursor_pos == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let glyphs = &*self.glyphs.lock().unwrap();
|
||||
|
||||
let mut text = String::new();
|
||||
for (i, glyph) in glyphs.iter().enumerate() {
|
||||
let mut substr = glyph.substr.clone();
|
||||
if cursor_pos as usize - 1 == i {
|
||||
substr.pop().unwrap();
|
||||
}
|
||||
text.push_str(&substr);
|
||||
}
|
||||
self.text.set(text);
|
||||
self.cursor_pos.set(cursor_pos - 1);
|
||||
};
|
||||
self.regen_glyphs().unwrap();
|
||||
}
|
||||
"C" => {
|
||||
if mods.ctrl {
|
||||
self.copy_highlighted_text().unwrap();
|
||||
} else {
|
||||
self.insert_char(key, mods);
|
||||
}
|
||||
}
|
||||
"V" => {
|
||||
if mods.ctrl {
|
||||
if let Some(text) = window::clipboard_get() {
|
||||
self.insert_text(text);
|
||||
}
|
||||
} else {
|
||||
self.insert_char(key, mods);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.insert_char(key, mods);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_char(&self, key: &str, mods: &KeyMods) {
|
||||
// First filter for only single digit keys
|
||||
let allowed_keys = [
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
|
||||
"R", "S", "T", "U", "V", "W", "X", "Y", "Z", " ", ":", ";", "'", "-", ".", "/", "=",
|
||||
"(", "\\", ")", "`", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
];
|
||||
if !allowed_keys.contains(&key) {
|
||||
return
|
||||
}
|
||||
|
||||
// If we want to only allow specific chars in a String here
|
||||
//let ch = key.chars().next().unwrap();
|
||||
// if !self.allowed_chars.chars().any(|c| c == ch) { return }
|
||||
|
||||
let key = if mods.shift { key.to_string() } else { key.to_lowercase() };
|
||||
|
||||
self.insert_text(key);
|
||||
}
|
||||
|
||||
fn insert_text(&self, key: String) {
|
||||
let mut text = String::new();
|
||||
|
||||
let cursor_pos = self.cursor_pos.get();
|
||||
|
||||
if cursor_pos == 0 {
|
||||
text = key;
|
||||
} else {
|
||||
let glyphs = &*self.glyphs.lock().unwrap();
|
||||
for (glyph_idx, glyph) in glyphs.iter().enumerate() {
|
||||
text.push_str(&glyph.substr);
|
||||
if cursor_pos == glyph_idx as u32 + 1 {
|
||||
text.push_str(&key);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.text.set(text);
|
||||
// Not always true lol
|
||||
self.cursor_pos.set(cursor_pos + 1);
|
||||
self.regen_glyphs().unwrap();
|
||||
}
|
||||
|
||||
fn copy_highlighted_text(&self) -> Result<()> {
|
||||
let start = self.selected.get_u32(0)? as usize;
|
||||
let end = self.selected.get_u32(1)? as usize;
|
||||
|
||||
let sel_start = std::cmp::min(start, end);
|
||||
let sel_end = std::cmp::max(start, end);
|
||||
|
||||
let mut text = String::new();
|
||||
|
||||
let glyphs = &*self.glyphs.lock().unwrap();
|
||||
for (glyph_idx, glyph) in glyphs.iter().enumerate() {
|
||||
if sel_start <= glyph_idx && glyph_idx < sel_end {
|
||||
text.push_str(&glyph.substr);
|
||||
}
|
||||
}
|
||||
|
||||
info!("Copied '{}'", text);
|
||||
window::clipboard_set(&text);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn key_up(self: Arc<Self>, key: String, mods: KeyMods) {
|
||||
let mut repeater = self.key_repeat.lock().unwrap();
|
||||
repeater.key_up(&key);
|
||||
}
|
||||
|
||||
fn mouse_button_down(self: Arc<Self>, button: MouseButton, x: f32, y: f32) {
|
||||
let mouse_pos = Point { x, y };
|
||||
let rect = self.world_rect.lock().unwrap().clone();
|
||||
debug!("mouse down event {} {} {} {} {} {}", x, y, rect.x, rect.y, rect.w, rect.h);
|
||||
|
||||
// clicking inside box will:
|
||||
// 1. make it active
|
||||
// 2. begin selection
|
||||
if rect.contains(&mouse_pos) {
|
||||
debug!("showkeyb!");
|
||||
window::show_keyboard(true);
|
||||
if !self.is_active.get() {
|
||||
self.is_active.set(true);
|
||||
println!("inside!");
|
||||
// Send signal
|
||||
}
|
||||
|
||||
let cpos = match self.find_closest_glyph_idx(x) {
|
||||
MouseClickGlyph::Pos(cpos) => cpos,
|
||||
_ => panic!("shouldn't be possible to reach here!"),
|
||||
};
|
||||
|
||||
// set cursor pos
|
||||
self.cursor_pos.set(cpos);
|
||||
|
||||
// begin selection
|
||||
self.selected.set_u32(0, cpos).unwrap();
|
||||
self.selected.set_u32(1, cpos).unwrap();
|
||||
self.mouse_btn_held.store(true, Ordering::Relaxed);
|
||||
}
|
||||
// click outside the box will:
|
||||
// 1. make it inactive
|
||||
else {
|
||||
if self.is_active.get() {
|
||||
self.is_active.set(false);
|
||||
// Send signal
|
||||
}
|
||||
}
|
||||
}
|
||||
fn mouse_button_up(self: Arc<Self>, button: MouseButton, x: f32, y: f32) {
|
||||
// releasing mouse button will:
|
||||
// 1. end selection
|
||||
self.mouse_btn_held.store(false, Ordering::Relaxed);
|
||||
}
|
||||
fn mouse_move(self: Arc<Self>, x: f32, y: f32) {
|
||||
if !self.mouse_btn_held.load(Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if active and selection_active, then use x to modify the selection.
|
||||
// also implement scrolling when cursor is to the left or right
|
||||
// just scroll to the end
|
||||
// also set cursor_pos too
|
||||
|
||||
let cpos = match self.find_closest_glyph_idx(x) {
|
||||
MouseClickGlyph::Lhs => 0,
|
||||
MouseClickGlyph::Pos(cpos) => cpos,
|
||||
MouseClickGlyph::Rhs(cpos) => cpos,
|
||||
};
|
||||
|
||||
self.cursor_pos.set(cpos);
|
||||
self.selected.set_u32(1, cpos).unwrap();
|
||||
}
|
||||
|
||||
// Uses screen x pos
|
||||
fn find_closest_glyph_idx(&self, x: f32) -> MouseClickGlyph {
|
||||
let rect = self.world_rect.lock().unwrap().clone();
|
||||
let glyphs = &*self.glyphs.lock().unwrap();
|
||||
|
||||
let mouse_x = x - rect.x;
|
||||
|
||||
if mouse_x > rect.w {
|
||||
// Highlight to the end
|
||||
let cpos = glyphs.len() as u32;
|
||||
return MouseClickGlyph::Rhs(cpos);
|
||||
// Scroll to the right handled in render
|
||||
} else if mouse_x < 0. {
|
||||
return MouseClickGlyph::Lhs;
|
||||
}
|
||||
|
||||
let scroll = self.scroll.get();
|
||||
|
||||
let mouse_x = x - rect.x;
|
||||
let mut cpos = 0;
|
||||
let lhs = 0.;
|
||||
let mut last_d = (lhs - mouse_x).abs();
|
||||
|
||||
for (i, glyph) in glyphs.iter().skip(1).enumerate() {
|
||||
// Because we skip the first item
|
||||
let glyph_idx = (i + 1) as u32;
|
||||
|
||||
let x1 = glyph.pos.x + scroll;
|
||||
let curr_d = (x1 - mouse_x).abs();
|
||||
if curr_d < last_d {
|
||||
last_d = curr_d;
|
||||
cpos = glyph_idx;
|
||||
}
|
||||
}
|
||||
// also check the right hand side
|
||||
let rhs = {
|
||||
let glyph = &glyphs.last().unwrap();
|
||||
glyph.pos.x + scroll + glyph.pos.w
|
||||
};
|
||||
let curr_d = (rhs - mouse_x).abs();
|
||||
if curr_d < last_d {
|
||||
//last_d = curr_d;
|
||||
cpos = glyphs.len() as u32;
|
||||
}
|
||||
|
||||
MouseClickGlyph::Pos(cpos)
|
||||
}
|
||||
|
||||
fn window_resize(self: Arc<Self>, w: f32, h: f32) {}
|
||||
}
|
||||
|
||||
enum MouseClickGlyph {
|
||||
Lhs,
|
||||
Pos(u32),
|
||||
Rhs(u32),
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,11 +32,12 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
mod shader;
|
||||
|
||||
use crate::{
|
||||
app::{AppPtr, AsyncRuntime},
|
||||
error::{Error, Result},
|
||||
pubsub::{Publisher, PublisherPtr, Subscription, SubscriptionId},
|
||||
shader,
|
||||
util::ansi_texture,
|
||||
};
|
||||
|
||||
@@ -734,15 +735,15 @@ impl Stage {
|
||||
sendr: async_channel::Sender<TextureId>,
|
||||
) {
|
||||
let texture = self.ctx.new_texture_from_rgba8(width, height, &data);
|
||||
//debug!(target: "gfx2", "Invoked method: new_texture({}, {}, ...) -> {:?}",
|
||||
//debug!(target: "gfx", "Invoked method: new_texture({}, {}, ...) -> {:?}",
|
||||
// width, height, texture);
|
||||
//debug!(target: "gfx2", "Invoked method: new_texture({}, {}, ...) -> {:?}\n{}",
|
||||
//debug!(target: "gfx", "Invoked method: new_texture({}, {}, ...) -> {:?}\n{}",
|
||||
// width, height, texture,
|
||||
// ansi_texture(width as usize, height as usize, &data));
|
||||
sendr.try_send(texture).unwrap();
|
||||
}
|
||||
fn method_delete_texture(&mut self, texture: TextureId) {
|
||||
//debug!(target: "gfx2", "Invoked method: delete_texture({:?})", texture);
|
||||
//debug!(target: "gfx", "Invoked method: delete_texture({:?})", texture);
|
||||
self.ctx.delete_texture(texture);
|
||||
}
|
||||
fn method_new_vertex_buffer(
|
||||
@@ -755,7 +756,7 @@ impl Stage {
|
||||
BufferUsage::Immutable,
|
||||
BufferSource::slice(&verts),
|
||||
);
|
||||
//debug!(target: "gfx2", "Invoked method: new_vertex_buffer({:?}) -> {:?}", verts, buffer);
|
||||
//debug!(target: "gfx", "Invoked method: new_vertex_buffer({:?}) -> {:?}", verts, buffer);
|
||||
sendr.try_send(buffer).unwrap();
|
||||
}
|
||||
fn method_new_index_buffer(
|
||||
@@ -768,15 +769,15 @@ impl Stage {
|
||||
BufferUsage::Immutable,
|
||||
BufferSource::slice(&indices),
|
||||
);
|
||||
//debug!(target: "gfx2", "Invoked method: new_index_buffer({:?}) -> {:?}", indices, buffer);
|
||||
//debug!(target: "gfx", "Invoked method: new_index_buffer({:?}) -> {:?}", indices, buffer);
|
||||
sendr.try_send(buffer).unwrap();
|
||||
}
|
||||
fn method_delete_buffer(&mut self, buffer: BufferId) {
|
||||
//debug!(target: "gfx2", "Invoked method: delete_buffer({:?})", buffer);
|
||||
//debug!(target: "gfx", "Invoked method: delete_buffer({:?})", buffer);
|
||||
self.ctx.delete_buffer(buffer);
|
||||
}
|
||||
fn method_replace_draw_calls(&mut self, dcs: Vec<(u64, DrawCall)>) {
|
||||
//debug!(target: "gfx2", "Invoked method: replace_draw_calls({:?})", dcs);
|
||||
//debug!(target: "gfx", "Invoked method: replace_draw_calls({:?})", dcs);
|
||||
for (key, val) in dcs {
|
||||
self.draw_calls.insert(key, val);
|
||||
}
|
||||
@@ -1,434 +0,0 @@
|
||||
/* 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 miniquad::{KeyCode, MouseButton};
|
||||
|
||||
pub trait KeyCodeAsStr {
|
||||
fn to_str(&self) -> &str;
|
||||
}
|
||||
|
||||
impl KeyCodeAsStr for KeyCode {
|
||||
fn to_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Space => " ",
|
||||
Self::Apostrophe => "'",
|
||||
Self::Comma => ",",
|
||||
Self::Minus => "-",
|
||||
Self::Period => ".",
|
||||
Self::Slash => "/",
|
||||
Self::Key0 => "0",
|
||||
Self::Key1 => "1",
|
||||
Self::Key2 => "2",
|
||||
Self::Key3 => "3",
|
||||
Self::Key4 => "4",
|
||||
Self::Key5 => "5",
|
||||
Self::Key6 => "6",
|
||||
Self::Key7 => "7",
|
||||
Self::Key8 => "8",
|
||||
Self::Key9 => "9",
|
||||
Self::Semicolon => ";",
|
||||
Self::Equal => "=",
|
||||
Self::A => "A",
|
||||
Self::B => "B",
|
||||
Self::C => "C",
|
||||
Self::D => "D",
|
||||
Self::E => "E",
|
||||
Self::F => "F",
|
||||
Self::G => "G",
|
||||
Self::H => "H",
|
||||
Self::I => "I",
|
||||
Self::J => "J",
|
||||
Self::K => "K",
|
||||
Self::L => "L",
|
||||
Self::M => "M",
|
||||
Self::N => "N",
|
||||
Self::O => "O",
|
||||
Self::P => "P",
|
||||
Self::Q => "Q",
|
||||
Self::R => "R",
|
||||
Self::S => "S",
|
||||
Self::T => "T",
|
||||
Self::U => "U",
|
||||
Self::V => "V",
|
||||
Self::W => "W",
|
||||
Self::X => "X",
|
||||
Self::Y => "Y",
|
||||
Self::Z => "Z",
|
||||
Self::LeftBracket => "(",
|
||||
Self::Backslash => "\\",
|
||||
Self::RightBracket => ")",
|
||||
Self::GraveAccent => "`",
|
||||
Self::World1 => "World1",
|
||||
Self::World2 => "World2",
|
||||
Self::Escape => "Escape",
|
||||
Self::Enter => "\n",
|
||||
Self::Tab => "Tab",
|
||||
Self::Backspace => "Backspace",
|
||||
Self::Insert => "Insert",
|
||||
Self::Delete => "Delete",
|
||||
Self::Right => "Right",
|
||||
Self::Left => "Left",
|
||||
Self::Down => "Down",
|
||||
Self::Up => "Up",
|
||||
Self::PageUp => "PageUp",
|
||||
Self::PageDown => "PageDown",
|
||||
Self::Home => "Home",
|
||||
Self::End => "End",
|
||||
Self::CapsLock => "CapsLock",
|
||||
Self::ScrollLock => "ScrollLock",
|
||||
Self::NumLock => "NumLock",
|
||||
Self::PrintScreen => "PrintScreen",
|
||||
Self::Pause => "Pause",
|
||||
Self::F1 => "F1",
|
||||
Self::F2 => "F2",
|
||||
Self::F3 => "F3",
|
||||
Self::F4 => "F4",
|
||||
Self::F5 => "F5",
|
||||
Self::F6 => "F6",
|
||||
Self::F7 => "F7",
|
||||
Self::F8 => "F8",
|
||||
Self::F9 => "F9",
|
||||
Self::F10 => "F10",
|
||||
Self::F11 => "F11",
|
||||
Self::F12 => "F12",
|
||||
Self::F13 => "F13",
|
||||
Self::F14 => "F14",
|
||||
Self::F15 => "F15",
|
||||
Self::F16 => "F16",
|
||||
Self::F17 => "F17",
|
||||
Self::F18 => "F18",
|
||||
Self::F19 => "F19",
|
||||
Self::F20 => "F20",
|
||||
Self::F21 => "F21",
|
||||
Self::F22 => "F22",
|
||||
Self::F23 => "F23",
|
||||
Self::F24 => "F24",
|
||||
Self::F25 => "F25",
|
||||
Self::Kp0 => "Kp0",
|
||||
Self::Kp1 => "Kp1",
|
||||
Self::Kp2 => "Kp2",
|
||||
Self::Kp3 => "Kp3",
|
||||
Self::Kp4 => "Kp4",
|
||||
Self::Kp5 => "Kp5",
|
||||
Self::Kp6 => "Kp6",
|
||||
Self::Kp7 => "Kp7",
|
||||
Self::Kp8 => "Kp8",
|
||||
Self::Kp9 => "Kp9",
|
||||
Self::KpDecimal => "KpDecimal",
|
||||
Self::KpDivide => "KpDivide",
|
||||
Self::KpMultiply => "KpMultiply",
|
||||
Self::KpSubtract => "KpSubtract",
|
||||
Self::KpAdd => "KpAdd",
|
||||
Self::KpEnter => "KpEnter",
|
||||
Self::KpEqual => "KpEqual",
|
||||
Self::LeftShift => "LeftShift",
|
||||
Self::LeftControl => "LeftControl",
|
||||
Self::LeftAlt => "LeftAlt",
|
||||
Self::LeftSuper => "LeftSuper",
|
||||
Self::RightShift => "RightShift",
|
||||
Self::RightControl => "RightControl",
|
||||
Self::RightAlt => "RightAlt",
|
||||
Self::RightSuper => "RightSuper",
|
||||
Self::Menu => "Menu",
|
||||
Self::Unknown => "Unknown",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait KeyCodeAsU16 {
|
||||
fn to_u16(&self) -> u16;
|
||||
fn from_u16(keysym: u16) -> Self;
|
||||
}
|
||||
|
||||
impl KeyCodeAsU16 for KeyCode {
|
||||
fn to_u16(&self) -> u16 {
|
||||
match self {
|
||||
Self::Space => 0x0020,
|
||||
Self::Apostrophe => 0x0027,
|
||||
Self::Comma => 0x002c,
|
||||
Self::Minus => 0x002d,
|
||||
Self::Period => 0x002e,
|
||||
Self::Slash => 0x002f,
|
||||
Self::Key0 => 0x0030,
|
||||
Self::Key1 => 0x0031,
|
||||
Self::Key2 => 0x0032,
|
||||
Self::Key3 => 0x0033,
|
||||
Self::Key4 => 0x0034,
|
||||
Self::Key5 => 0x0035,
|
||||
Self::Key6 => 0x0036,
|
||||
Self::Key7 => 0x0037,
|
||||
Self::Key8 => 0x0038,
|
||||
Self::Key9 => 0x0039,
|
||||
Self::Semicolon => 0x003b,
|
||||
Self::Equal => 0x003d,
|
||||
Self::A => 0x0041,
|
||||
Self::B => 0x0042,
|
||||
Self::C => 0x0043,
|
||||
Self::D => 0x0044,
|
||||
Self::E => 0x0045,
|
||||
Self::F => 0x0046,
|
||||
Self::G => 0x0047,
|
||||
Self::H => 0x0048,
|
||||
Self::I => 0x0049,
|
||||
Self::J => 0x004a,
|
||||
Self::K => 0x004b,
|
||||
Self::L => 0x004c,
|
||||
Self::M => 0x004d,
|
||||
Self::N => 0x004e,
|
||||
Self::O => 0x004f,
|
||||
Self::P => 0x0050,
|
||||
Self::Q => 0x0051,
|
||||
Self::R => 0x0052,
|
||||
Self::S => 0x0053,
|
||||
Self::T => 0x0054,
|
||||
Self::U => 0x0055,
|
||||
Self::V => 0x0056,
|
||||
Self::W => 0x0057,
|
||||
Self::X => 0x0058,
|
||||
Self::Y => 0x0059,
|
||||
Self::Z => 0x005a,
|
||||
Self::LeftBracket => 0x005b,
|
||||
Self::Backslash => 0x005c,
|
||||
Self::RightBracket => 0x005d,
|
||||
Self::GraveAccent => 0x0060,
|
||||
Self::World1 => 0x0100,
|
||||
Self::World2 => 0x0101,
|
||||
Self::Escape => 0xff1b,
|
||||
Self::Enter => 0xff0d,
|
||||
Self::Tab => 0xff09,
|
||||
Self::Backspace => 0xff08,
|
||||
Self::Insert => 0xff63,
|
||||
Self::Delete => 0xffff,
|
||||
Self::Right => 0xff53,
|
||||
Self::Left => 0xff51,
|
||||
Self::Down => 0xff54,
|
||||
Self::Up => 0xff52,
|
||||
Self::PageUp => 0xff55,
|
||||
Self::PageDown => 0xff56,
|
||||
Self::Home => 0xff50,
|
||||
Self::End => 0xff57,
|
||||
Self::CapsLock => 0xffe5,
|
||||
Self::ScrollLock => 0xff14,
|
||||
Self::NumLock => 0xff7f,
|
||||
Self::PrintScreen => 0xfd1d,
|
||||
Self::Pause => 0xff13,
|
||||
Self::F1 => 0xffbe,
|
||||
Self::F2 => 0xffbf,
|
||||
Self::F3 => 0xffc0,
|
||||
Self::F4 => 0xffc1,
|
||||
Self::F5 => 0xffc2,
|
||||
Self::F6 => 0xffc3,
|
||||
Self::F7 => 0xffc4,
|
||||
Self::F8 => 0xffc5,
|
||||
Self::F9 => 0xffc6,
|
||||
Self::F10 => 0xffc7,
|
||||
Self::F11 => 0xffc8,
|
||||
Self::F12 => 0xffc9,
|
||||
Self::F13 => 0xffca,
|
||||
Self::F14 => 0xffcb,
|
||||
Self::F15 => 0xffcc,
|
||||
Self::F16 => 0xffcd,
|
||||
Self::F17 => 0xffce,
|
||||
Self::F18 => 0xffcf,
|
||||
Self::F19 => 0xffd0,
|
||||
Self::F20 => 0xffd1,
|
||||
Self::F21 => 0xffd2,
|
||||
Self::F22 => 0xffd3,
|
||||
Self::F23 => 0xffd4,
|
||||
Self::F24 => 0xffd5,
|
||||
Self::F25 => 0xffd6,
|
||||
Self::Kp0 => 0xffb0,
|
||||
Self::Kp1 => 0xffb1,
|
||||
Self::Kp2 => 0xffb2,
|
||||
Self::Kp3 => 0xffb3,
|
||||
Self::Kp4 => 0xffb4,
|
||||
Self::Kp5 => 0xffb5,
|
||||
Self::Kp6 => 0xffb6,
|
||||
Self::Kp7 => 0xffb7,
|
||||
Self::Kp8 => 0xffb8,
|
||||
Self::Kp9 => 0xffb9,
|
||||
Self::KpDecimal => 0xffae,
|
||||
Self::KpDivide => 0xffaf,
|
||||
Self::KpMultiply => 0xffaa,
|
||||
Self::KpSubtract => 0xffad,
|
||||
Self::KpAdd => 0xffab,
|
||||
Self::KpEnter => 0xff8d,
|
||||
Self::KpEqual => 0xffbd,
|
||||
Self::LeftShift => 0xffe1,
|
||||
Self::LeftControl => 0xffe3,
|
||||
Self::LeftAlt => 0xffe9,
|
||||
Self::LeftSuper => 0xffeb,
|
||||
Self::RightShift => 0xffe2,
|
||||
Self::RightControl => 0xffe4,
|
||||
Self::RightAlt => 0xffea,
|
||||
Self::RightSuper => 0xffec,
|
||||
Self::Menu => 0xff67,
|
||||
Self::Unknown => 0x01ff,
|
||||
}
|
||||
}
|
||||
fn from_u16(keysym: u16) -> Self {
|
||||
match keysym {
|
||||
0x0020 => Self::Space,
|
||||
0x0027 => Self::Apostrophe,
|
||||
0x002c => Self::Comma,
|
||||
0x002d => Self::Minus,
|
||||
0x002e => Self::Period,
|
||||
0x002f => Self::Slash,
|
||||
0x0030 => Self::Key0,
|
||||
0x0031 => Self::Key1,
|
||||
0x0032 => Self::Key2,
|
||||
0x0033 => Self::Key3,
|
||||
0x0034 => Self::Key4,
|
||||
0x0035 => Self::Key5,
|
||||
0x0036 => Self::Key6,
|
||||
0x0037 => Self::Key7,
|
||||
0x0038 => Self::Key8,
|
||||
0x0039 => Self::Key9,
|
||||
0x003b => Self::Semicolon,
|
||||
0x003d => Self::Equal,
|
||||
0x0041 => Self::A,
|
||||
0x0042 => Self::B,
|
||||
0x0043 => Self::C,
|
||||
0x0044 => Self::D,
|
||||
0x0045 => Self::E,
|
||||
0x0046 => Self::F,
|
||||
0x0047 => Self::G,
|
||||
0x0048 => Self::H,
|
||||
0x0049 => Self::I,
|
||||
0x004a => Self::J,
|
||||
0x004b => Self::K,
|
||||
0x004c => Self::L,
|
||||
0x004d => Self::M,
|
||||
0x004e => Self::N,
|
||||
0x004f => Self::O,
|
||||
0x0050 => Self::P,
|
||||
0x0051 => Self::Q,
|
||||
0x0052 => Self::R,
|
||||
0x0053 => Self::S,
|
||||
0x0054 => Self::T,
|
||||
0x0055 => Self::U,
|
||||
0x0056 => Self::V,
|
||||
0x0057 => Self::W,
|
||||
0x0058 => Self::X,
|
||||
0x0059 => Self::Y,
|
||||
0x005a => Self::Z,
|
||||
0x005b => Self::LeftBracket,
|
||||
0x005c => Self::Backslash,
|
||||
0x005d => Self::RightBracket,
|
||||
0x0060 => Self::GraveAccent,
|
||||
0x0100 => Self::World1,
|
||||
0x0101 => Self::World2,
|
||||
0xff1b => Self::Escape,
|
||||
0xff0d => Self::Enter,
|
||||
0xff09 => Self::Tab,
|
||||
0xff08 => Self::Backspace,
|
||||
0xff63 => Self::Insert,
|
||||
0xffff => Self::Delete,
|
||||
0xff53 => Self::Right,
|
||||
0xff51 => Self::Left,
|
||||
0xff54 => Self::Down,
|
||||
0xff52 => Self::Up,
|
||||
0xff55 => Self::PageUp,
|
||||
0xff56 => Self::PageDown,
|
||||
0xff50 => Self::Home,
|
||||
0xff57 => Self::End,
|
||||
0xffe5 => Self::CapsLock,
|
||||
0xff14 => Self::ScrollLock,
|
||||
0xff7f => Self::NumLock,
|
||||
0xfd1d => Self::PrintScreen,
|
||||
0xff13 => Self::Pause,
|
||||
0xffbe => Self::F1,
|
||||
0xffbf => Self::F2,
|
||||
0xffc0 => Self::F3,
|
||||
0xffc1 => Self::F4,
|
||||
0xffc2 => Self::F5,
|
||||
0xffc3 => Self::F6,
|
||||
0xffc4 => Self::F7,
|
||||
0xffc5 => Self::F8,
|
||||
0xffc6 => Self::F9,
|
||||
0xffc7 => Self::F10,
|
||||
0xffc8 => Self::F11,
|
||||
0xffc9 => Self::F12,
|
||||
0xffca => Self::F13,
|
||||
0xffcb => Self::F14,
|
||||
0xffcc => Self::F15,
|
||||
0xffcd => Self::F16,
|
||||
0xffce => Self::F17,
|
||||
0xffcf => Self::F18,
|
||||
0xffd0 => Self::F19,
|
||||
0xffd1 => Self::F20,
|
||||
0xffd2 => Self::F21,
|
||||
0xffd3 => Self::F22,
|
||||
0xffd4 => Self::F23,
|
||||
0xffd5 => Self::F24,
|
||||
0xffd6 => Self::F25,
|
||||
0xffb0 => Self::Kp0,
|
||||
0xffb1 => Self::Kp1,
|
||||
0xffb2 => Self::Kp2,
|
||||
0xffb3 => Self::Kp3,
|
||||
0xffb4 => Self::Kp4,
|
||||
0xffb5 => Self::Kp5,
|
||||
0xffb6 => Self::Kp6,
|
||||
0xffb7 => Self::Kp7,
|
||||
0xffb8 => Self::Kp8,
|
||||
0xffb9 => Self::Kp9,
|
||||
0xffae => Self::KpDecimal,
|
||||
0xffaf => Self::KpDivide,
|
||||
0xffaa => Self::KpMultiply,
|
||||
0xffad => Self::KpSubtract,
|
||||
0xffab => Self::KpAdd,
|
||||
0xff8d => Self::KpEnter,
|
||||
0xffbd => Self::KpEqual,
|
||||
0xffe1 => Self::LeftShift,
|
||||
0xffe3 => Self::LeftControl,
|
||||
0xffe9 => Self::LeftAlt,
|
||||
0xffeb => Self::LeftSuper,
|
||||
0xffe2 => Self::RightShift,
|
||||
0xffe4 => Self::RightControl,
|
||||
0xffea => Self::RightAlt,
|
||||
0xffec => Self::RightSuper,
|
||||
0xff67 => Self::Menu,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MouseButtonAsU8 {
|
||||
fn to_u8(&self) -> u8;
|
||||
fn from_u8(btn: u8) -> Self;
|
||||
}
|
||||
|
||||
impl MouseButtonAsU8 for MouseButton {
|
||||
fn to_u8(&self) -> u8 {
|
||||
match self {
|
||||
Self::Left => 0,
|
||||
Self::Middle => 1,
|
||||
Self::Right => 2,
|
||||
Self::Unknown => 3,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_u8(btn: u8) -> Self {
|
||||
match btn {
|
||||
0 => Self::Left,
|
||||
1 => Self::Middle,
|
||||
2 => Self::Right,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,32 +51,25 @@ use log::LevelFilter;
|
||||
|
||||
mod app;
|
||||
mod darkirc;
|
||||
use darkirc::DarkIrcBackend;
|
||||
//mod chatapp;
|
||||
//mod chatview;
|
||||
//mod editbox;
|
||||
mod error;
|
||||
mod expr;
|
||||
//mod gfx;
|
||||
mod gfx2;
|
||||
mod keysym;
|
||||
mod gfx;
|
||||
mod mesh;
|
||||
mod net;
|
||||
//mod plugin;
|
||||
mod prop;
|
||||
mod pubsub;
|
||||
//mod py;
|
||||
//mod res;
|
||||
mod scene;
|
||||
mod shader;
|
||||
mod text2;
|
||||
mod text;
|
||||
mod ui;
|
||||
mod util;
|
||||
|
||||
use crate::{
|
||||
darkirc::DarkIrcBackend,
|
||||
net::ZeroMQAdapter,
|
||||
scene::{SceneGraph, SceneGraphPtr2},
|
||||
text2::TextShaper,
|
||||
text::TextShaper,
|
||||
};
|
||||
|
||||
pub type ExecutorPtr = Arc<smol::Executor<'static>>;
|
||||
@@ -134,8 +127,8 @@ fn main() {
|
||||
let (method_req, method_rep) = mpsc::channel();
|
||||
// The UI actually needs to be running for this to reply back.
|
||||
// Otherwise calls will just hang.
|
||||
let render_api = gfx2::RenderApi::new(method_req);
|
||||
let event_pub = gfx2::GraphicsEventPublisher::new();
|
||||
let render_api = gfx::RenderApi::new(method_req);
|
||||
let event_pub = gfx::GraphicsEventPublisher::new();
|
||||
|
||||
let text_shaper = TextShaper::new();
|
||||
|
||||
@@ -202,8 +195,8 @@ fn main() {
|
||||
});
|
||||
async_runtime.push_task(ev_relay_task);
|
||||
|
||||
//let stage = gfx2::Stage::new(method_rep, event_pub);
|
||||
gfx2::run_gui(app, async_runtime, method_rep, event_pub);
|
||||
//let stage = gfx::Stage::new(method_rep, event_pub);
|
||||
gfx::run_gui(app, async_runtime, method_rep, event_pub);
|
||||
debug!(target: "main", "Started GFX backend");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
gfx2::{DrawMesh, Point, Rectangle, RenderApi, Vertex},
|
||||
gfx::{DrawMesh, Point, Rectangle, RenderApi, Vertex},
|
||||
};
|
||||
use miniquad::{BufferId, TextureId};
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/* 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::error::{Error, Result};
|
||||
|
||||
pub type ResourceId = u32;
|
||||
|
||||
pub struct ResourceManager<T> {
|
||||
resources: Vec<(ResourceId, Option<T>)>,
|
||||
freed: Vec<usize>,
|
||||
id_counter: ResourceId,
|
||||
}
|
||||
|
||||
impl<T> ResourceManager<T> {
|
||||
pub fn new() -> Self {
|
||||
Self { resources: vec![], freed: vec![], id_counter: 0 }
|
||||
}
|
||||
|
||||
pub fn alloc(&mut self, rsrc: T) -> ResourceId {
|
||||
let id = self.id_counter;
|
||||
self.id_counter += 1;
|
||||
|
||||
if self.freed.is_empty() {
|
||||
let idx = self.resources.len();
|
||||
self.resources.push((id, Some(rsrc)));
|
||||
} else {
|
||||
let idx = self.freed.pop().unwrap();
|
||||
let _ = std::mem::replace(&mut self.resources[idx], (id, Some(rsrc)));
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
pub fn get(&self, id: ResourceId) -> Option<&T> {
|
||||
for (idx, (rsrc_id, rsrc)) in self.resources.iter().enumerate() {
|
||||
if self.freed.contains(&idx) {
|
||||
continue
|
||||
}
|
||||
if *rsrc_id == id {
|
||||
return rsrc.as_ref()
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn free(&mut self, id: ResourceId) -> Result<()> {
|
||||
for (idx, (rsrc_id, rsrc)) in self.resources.iter_mut().enumerate() {
|
||||
if self.freed.contains(&idx) {
|
||||
return Err(Error::ResourceNotFound)
|
||||
}
|
||||
if *rsrc_id == id {
|
||||
*rsrc = None;
|
||||
self.freed.push(idx);
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
Err(Error::ResourceNotFound)
|
||||
}
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/* 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 freetype as ft;
|
||||
|
||||
use crate::gfx::{FreetypeFace, Rectangle};
|
||||
|
||||
// From https://sourceforge.net/projects/freetype/files/freetype2/2.6/
|
||||
//
|
||||
// * An `FT_Face' object can only be safely used from one thread at
|
||||
// a time.
|
||||
//
|
||||
// * An `FT_Library' object can now be used without modification
|
||||
// from multiple threads at the same time.
|
||||
//
|
||||
// * `FT_Face' creation and destruction with the same `FT_Library'
|
||||
// object can only be done from one thread at a time.
|
||||
//
|
||||
// One can use a single `FT_Library' object across threads as long
|
||||
// as a mutex lock is used around `FT_New_Face' and `FT_Done_Face'.
|
||||
// Any calls to `FT_Load_Glyph' and similar API are safe and do not
|
||||
// need the lock to be held as long as the same `FT_Face' is not
|
||||
// used from multiple threads at the same time.
|
||||
|
||||
// Harfbuzz is threadsafe.
|
||||
|
||||
// Notes:
|
||||
// * All ft init and face creation should happen at startup.
|
||||
// * FT faces protected behind an async Mutex
|
||||
// * Glyph cache. Key is (glyph_id, font_size)
|
||||
// * Glyph texture cache: (glyph_id, font_size, color)
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Glyph {
|
||||
pub id: u32,
|
||||
// Substring this glyph corresponds to
|
||||
pub substr: String,
|
||||
|
||||
// The texture
|
||||
pub bmp: Vec<u8>,
|
||||
pub bmp_width: u16,
|
||||
pub bmp_height: u16,
|
||||
|
||||
pub pos: Rectangle<f32>,
|
||||
}
|
||||
|
||||
pub struct TextShaper {
|
||||
pub font_faces: Vec<FreetypeFace>,
|
||||
}
|
||||
|
||||
unsafe impl Send for TextShaper {}
|
||||
unsafe impl Sync for TextShaper {}
|
||||
|
||||
impl TextShaper {
|
||||
fn split_into_substrs(&self, text: String) -> Vec<(usize, String)> {
|
||||
let mut current_idx = 0;
|
||||
let mut current_str = String::new();
|
||||
let mut substrs = vec![];
|
||||
'next_char: for chr in text.chars() {
|
||||
let idx = 'get_idx: {
|
||||
for i in 0..self.font_faces.len() {
|
||||
let ft_face = &self.font_faces[i];
|
||||
if ft_face.get_char_index(chr as usize).is_some() {
|
||||
break 'get_idx i
|
||||
}
|
||||
}
|
||||
|
||||
warn!("no font fallback for char: '{}'", chr);
|
||||
// Skip this char
|
||||
continue 'next_char
|
||||
};
|
||||
if current_idx != idx {
|
||||
if !current_str.is_empty() {
|
||||
// Push
|
||||
substrs.push((current_idx, current_str.clone()));
|
||||
}
|
||||
|
||||
current_str.clear();
|
||||
current_idx = idx;
|
||||
}
|
||||
current_str.push(chr);
|
||||
}
|
||||
if !current_str.is_empty() {
|
||||
// Push
|
||||
substrs.push((current_idx, current_str));
|
||||
}
|
||||
substrs
|
||||
}
|
||||
|
||||
pub fn shape(&self, text: String, font_size: f32, text_color: [f32; 4]) -> Vec<Glyph> {
|
||||
let substrs = self.split_into_substrs(text.clone());
|
||||
|
||||
let mut glyphs: Vec<Glyph> = vec![];
|
||||
|
||||
let mut current_x = 0.;
|
||||
let mut current_y = 0.;
|
||||
|
||||
for (face_idx, text) in substrs {
|
||||
//debug!("substr {}", text);
|
||||
let face = &self.font_faces[face_idx];
|
||||
if face.has_fixed_sizes() {
|
||||
// emojis required a fixed size
|
||||
//face.set_char_size(109 * 64, 0, 72, 72).unwrap();
|
||||
face.select_size(0).unwrap();
|
||||
} else {
|
||||
face.set_char_size(font_size as isize * 64, 0, 72, 72).unwrap();
|
||||
}
|
||||
|
||||
let hb_font = harfbuzz_rs::Font::from_freetype_face(face.clone());
|
||||
let buffer = harfbuzz_rs::UnicodeBuffer::new()
|
||||
.set_cluster_level(harfbuzz_rs::ClusterLevel::MonotoneCharacters)
|
||||
.add_str(&text);
|
||||
let output = harfbuzz_rs::shape(&hb_font, buffer, &[]);
|
||||
|
||||
let positions = output.get_glyph_positions();
|
||||
let infos = output.get_glyph_infos();
|
||||
|
||||
let mut prev_cluster = 0;
|
||||
|
||||
for (i, (position, info)) in positions.iter().zip(infos).enumerate() {
|
||||
let gid = info.codepoint;
|
||||
// Index within this substr
|
||||
let curr_cluster = info.cluster as usize;
|
||||
|
||||
// Skip first time
|
||||
if i != 0 {
|
||||
let substr = text[prev_cluster..curr_cluster].to_string();
|
||||
glyphs.last_mut().unwrap().substr = substr;
|
||||
}
|
||||
|
||||
prev_cluster = curr_cluster;
|
||||
|
||||
let mut flags = ft::face::LoadFlag::DEFAULT;
|
||||
if face.has_color() {
|
||||
flags |= ft::face::LoadFlag::COLOR;
|
||||
}
|
||||
// FIXME: glyph 884 hangs on android
|
||||
// For now just avoid using emojis on android
|
||||
//debug!("load_glyph {}", gid);
|
||||
face.load_glyph(gid, flags).unwrap();
|
||||
//debug!("load_glyph {} [done]", gid);
|
||||
|
||||
let glyph = face.glyph();
|
||||
glyph.render_glyph(ft::RenderMode::Normal).unwrap();
|
||||
|
||||
let bmp = glyph.bitmap();
|
||||
let buffer = bmp.buffer();
|
||||
let bmp_width = bmp.width() as usize;
|
||||
let bmp_height = bmp.rows() as usize;
|
||||
let bearing_x = glyph.bitmap_left() as f32;
|
||||
let bearing_y = glyph.bitmap_top() as f32;
|
||||
|
||||
let pixel_mode = bmp.pixel_mode().unwrap();
|
||||
let bmp = match pixel_mode {
|
||||
ft::bitmap::PixelMode::Bgra => {
|
||||
let mut tdata = vec![];
|
||||
tdata.resize(4 * bmp_width * bmp_height, 0);
|
||||
// Convert from BGRA to RGBA
|
||||
for i in 0..bmp_width * bmp_height {
|
||||
let idx = i * 4;
|
||||
let b = buffer[idx];
|
||||
let g = buffer[idx + 1];
|
||||
let r = buffer[idx + 2];
|
||||
let a = buffer[idx + 3];
|
||||
tdata[idx] = r;
|
||||
tdata[idx + 1] = g;
|
||||
tdata[idx + 2] = b;
|
||||
tdata[idx + 3] = a;
|
||||
}
|
||||
tdata
|
||||
}
|
||||
ft::bitmap::PixelMode::Gray => {
|
||||
// Convert from greyscale to RGBA8
|
||||
let tdata: Vec<_> = buffer
|
||||
.iter()
|
||||
.flat_map(|coverage| {
|
||||
let r = (255. * text_color[0]) as u8;
|
||||
let g = (255. * text_color[1]) as u8;
|
||||
let b = (255. * text_color[2]) as u8;
|
||||
let α = ((*coverage as f32) * text_color[3]) as u8;
|
||||
vec![r, g, b, α]
|
||||
})
|
||||
.collect();
|
||||
tdata
|
||||
}
|
||||
_ => panic!("unsupport pixel mode: {:?}", pixel_mode),
|
||||
};
|
||||
|
||||
let pos = if face.has_fixed_sizes() {
|
||||
// Downscale by height
|
||||
let w = (bmp_width as f32 * font_size) / bmp_height as f32;
|
||||
let h = font_size;
|
||||
|
||||
// Shouldn't this use the bearing?
|
||||
let x = current_x;
|
||||
let y = current_y - h;
|
||||
|
||||
current_x += w;
|
||||
|
||||
Rectangle { x, y, w, h }
|
||||
} else {
|
||||
let (w, h) = (bmp_width as f32, bmp_height as f32);
|
||||
|
||||
let off_x = position.x_offset as f32 / 64.;
|
||||
let off_y = position.y_offset as f32 / 64.;
|
||||
|
||||
let x = current_x + off_x + bearing_x;
|
||||
let y = current_y - off_y - bearing_y;
|
||||
|
||||
let x_advance = position.x_advance as f32 / 64.;
|
||||
let y_advance = position.y_advance as f32 / 64.;
|
||||
current_x += x_advance;
|
||||
current_y += y_advance;
|
||||
|
||||
Rectangle { x, y, w, h }
|
||||
};
|
||||
|
||||
let glyph = Glyph {
|
||||
id: gid,
|
||||
substr: String::new(),
|
||||
bmp,
|
||||
bmp_width: bmp_width as u16,
|
||||
bmp_height: bmp_height as u16,
|
||||
pos,
|
||||
};
|
||||
|
||||
glyphs.push(glyph);
|
||||
}
|
||||
|
||||
let substr = text[prev_cluster..].to_string();
|
||||
glyphs.last_mut().unwrap().substr = substr;
|
||||
}
|
||||
|
||||
glyphs
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ use miniquad::TextureId;
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
gfx2::{Rectangle, RenderApi, RenderApiPtr},
|
||||
gfx::{Rectangle, RenderApi, RenderApiPtr},
|
||||
util::{ansi_texture, zip3},
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
gfx2::{Rectangle, RenderApi, RenderApiPtr},
|
||||
gfx::{Rectangle, RenderApi, RenderApiPtr},
|
||||
util::ansi_texture,
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ use miniquad::TextureId;
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
gfx2::{Rectangle, RenderApi, RenderApiPtr},
|
||||
gfx::{Rectangle, RenderApi, RenderApiPtr},
|
||||
util::ansi_texture,
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ use std::sync::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
gfx2::{
|
||||
gfx::{
|
||||
DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, Point, Rectangle,
|
||||
RenderApiPtr, Vertex,
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
gfx2::{
|
||||
gfx::{
|
||||
DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, Point, Rectangle,
|
||||
RenderApi, RenderApiPtr, Vertex,
|
||||
},
|
||||
@@ -46,7 +46,7 @@ use crate::{
|
||||
},
|
||||
pubsub::Subscription,
|
||||
scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
|
||||
text2::{self, Glyph, GlyphPositionIter, SpritePtr, TextShaper, TextShaperPtr},
|
||||
text::{self, Glyph, GlyphPositionIter, SpritePtr, TextShaper, TextShaperPtr},
|
||||
util::zip3,
|
||||
ExecutorPtr,
|
||||
};
|
||||
@@ -107,7 +107,7 @@ const PRELOAD_PAGES: usize = 10;
|
||||
#[derive(Clone)]
|
||||
struct Page {
|
||||
msgs: Vec<Message>,
|
||||
atlas: text2::RenderedAtlas,
|
||||
atlas: text::RenderedAtlas,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -120,7 +120,7 @@ type Page2Ptr = Arc<Page2>;
|
||||
|
||||
struct Page2 {
|
||||
msgs: Vec<Message>,
|
||||
atlas: SyncMutex<text2::RenderedAtlas>,
|
||||
atlas: SyncMutex<text::RenderedAtlas>,
|
||||
// One draw call per page.
|
||||
// Resizing the canvas means we recalc wrapping and the mesh changes
|
||||
mesh_inf: SyncMutex<Option<PageMeshInfo>>,
|
||||
@@ -128,7 +128,7 @@ struct Page2 {
|
||||
|
||||
impl Page2 {
|
||||
async fn new(msgs: Vec<Message>, render_api: &RenderApi) -> Arc<Self> {
|
||||
let mut atlas = text2::Atlas::new(render_api);
|
||||
let mut atlas = text::Atlas::new(render_api);
|
||||
for msg in &msgs {
|
||||
atlas.push(&msg.glyphs);
|
||||
}
|
||||
@@ -169,7 +169,7 @@ impl Page2 {
|
||||
// Finally is just the message itself
|
||||
let mut section = 2;
|
||||
|
||||
let mut lines = text2::wrap(clip.w, font_size, glyphs);
|
||||
let mut lines = text::wrap(clip.w, font_size, glyphs);
|
||||
// We are drawing bottom up but line wrap gives us lines in normal order
|
||||
lines.reverse();
|
||||
let last_idx = lines.len() - 1;
|
||||
|
||||
@@ -29,7 +29,7 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
gfx2::{
|
||||
gfx::{
|
||||
DrawCall, DrawInstruction, DrawMesh, GraphicsEventPublisherPtr, Point, Rectangle,
|
||||
RenderApi, RenderApiPtr, Vertex,
|
||||
},
|
||||
@@ -40,7 +40,7 @@ use crate::{
|
||||
},
|
||||
pubsub::Subscription,
|
||||
scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
|
||||
text2::{self, Glyph, GlyphPositionIter, SpritePtr, TextShaper, TextShaperPtr},
|
||||
text::{self, Glyph, GlyphPositionIter, SpritePtr, TextShaper, TextShaperPtr},
|
||||
util::zip3,
|
||||
ExecutorPtr,
|
||||
};
|
||||
@@ -361,7 +361,7 @@ impl EditBox {
|
||||
debug!(target: "ui::editbox", " cursor_pos={cursor_pos}, is_focused={is_focused}");
|
||||
|
||||
let glyphs = self.glyphs.lock().unwrap().clone();
|
||||
let atlas = text2::make_texture_atlas(&self.render_api, &glyphs).await.unwrap();
|
||||
let atlas = text::make_texture_atlas(&self.render_api, &glyphs).await.unwrap();
|
||||
|
||||
let mut mesh = MeshBuilder::with_clip(clip.clone());
|
||||
self.draw_selected(&mut mesh, &glyphs, clip.h).unwrap();
|
||||
|
||||
@@ -26,14 +26,14 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
gfx2::{DrawCall, DrawInstruction, DrawMesh, Rectangle, RenderApi, RenderApiPtr, Vertex},
|
||||
gfx::{DrawCall, DrawInstruction, DrawMesh, Rectangle, RenderApi, RenderApiPtr, Vertex},
|
||||
mesh::{Color, MeshBuilder, MeshInfo, COLOR_BLUE, COLOR_WHITE},
|
||||
prop::{
|
||||
PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr, PropertyUint32,
|
||||
Role,
|
||||
},
|
||||
scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
|
||||
text2::{self, Glyph, GlyphPositionIter, SpritePtr, TextShaper, TextShaperPtr},
|
||||
text::{self, Glyph, GlyphPositionIter, SpritePtr, TextShaper, TextShaperPtr},
|
||||
util::zip3,
|
||||
ExecutorPtr,
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ use rand::{rngs::OsRng, Rng};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use crate::{
|
||||
gfx2::{DrawCall, DrawInstruction, Rectangle, RenderApiPtr},
|
||||
gfx::{DrawCall, DrawInstruction, Rectangle, RenderApiPtr},
|
||||
prop::{PropertyBool, PropertyPtr, Role},
|
||||
scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
|
||||
ExecutorPtr,
|
||||
|
||||
@@ -20,7 +20,7 @@ use rand::{rngs::OsRng, Rng};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use crate::{
|
||||
gfx2::{DrawCall, DrawInstruction, DrawMesh, Rectangle, RenderApiPtr, Vertex},
|
||||
gfx::{DrawCall, DrawInstruction, DrawMesh, Rectangle, RenderApiPtr, Vertex},
|
||||
prop::{PropertyPtr, PropertyUint32, Role},
|
||||
scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
|
||||
ExecutorPtr,
|
||||
|
||||
@@ -22,7 +22,7 @@ use std::sync::{Arc, Weak};
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
expr::{SExprMachine, SExprVal},
|
||||
gfx2::{DrawCall, Rectangle},
|
||||
gfx::{DrawCall, Rectangle},
|
||||
prop::{PropertyPtr, Role},
|
||||
scene::{SceneGraph, SceneNode, SceneNodeId, SceneNodeType},
|
||||
ExecutorPtr,
|
||||
|
||||
@@ -22,14 +22,14 @@ use rand::{rngs::OsRng, Rng};
|
||||
use std::sync::{Arc, Mutex as SyncMutex, Weak};
|
||||
|
||||
use crate::{
|
||||
gfx2::{DrawCall, DrawInstruction, DrawMesh, Rectangle, RenderApi, RenderApiPtr, Vertex},
|
||||
gfx::{DrawCall, DrawInstruction, DrawMesh, Rectangle, RenderApi, RenderApiPtr, Vertex},
|
||||
mesh::{Color, MeshBuilder, MeshInfo, COLOR_BLUE, COLOR_WHITE},
|
||||
prop::{
|
||||
PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyStr, PropertyUint32,
|
||||
Role,
|
||||
},
|
||||
scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
|
||||
text2::{self, Glyph, GlyphPositionIter, SpritePtr, TextShaper, TextShaperPtr},
|
||||
text::{self, Glyph, GlyphPositionIter, SpritePtr, TextShaper, TextShaperPtr},
|
||||
util::zip3,
|
||||
ExecutorPtr,
|
||||
};
|
||||
@@ -137,7 +137,7 @@ impl Text {
|
||||
) -> TextRenderInfo {
|
||||
debug!(target: "ui::text", "Rendering label '{}'", text);
|
||||
let glyphs = text_shaper.shape(text, font_size).await;
|
||||
let atlas = text2::make_texture_atlas(render_api, &glyphs).await.unwrap();
|
||||
let atlas = text::make_texture_atlas(render_api, &glyphs).await.unwrap();
|
||||
|
||||
let mut mesh = MeshBuilder::new();
|
||||
let mut glyph_pos_iter = GlyphPositionIter::new(font_size, &glyphs, baseline);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use crate::{
|
||||
gfx2::{DrawCall, GraphicsEventPublisherPtr, Rectangle, RenderApiPtr},
|
||||
gfx::{DrawCall, GraphicsEventPublisherPtr, Rectangle, RenderApiPtr},
|
||||
prop::{PropertyPtr, Role},
|
||||
scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
|
||||
ExecutorPtr,
|
||||
|
||||
Reference in New Issue
Block a user