Add support for TextInput widget, rename widgets module to widget, update to glyph_brush 0.7.0

This commit is contained in:
Imbris 2020-05-29 00:40:22 -04:00
parent 75adcb20e8
commit e4bc035a62
20 changed files with 557 additions and 109 deletions

154
Cargo.lock generated
View File

@ -1,5 +1,15 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ab_glyph"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26a685fe66654266f321a8b572660953f4df36a2135706503a4c89981d76e1a2"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser 0.8.0",
]
[[package]]
name = "ab_glyph_rasterizer"
version = "0.1.3"
@ -117,6 +127,15 @@ dependencies = [
"num-traits 0.2.12",
]
[[package]]
name = "approx"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278"
dependencies = [
"num-traits 0.2.12",
]
[[package]]
name = "arc-swap"
version = "0.4.7"
@ -192,7 +211,7 @@ dependencies = [
"async-task",
"broadcaster",
"crossbeam-channel 0.4.4",
"crossbeam-deque",
"crossbeam-deque 0.7.3",
"crossbeam-utils 0.7.2",
"futures-core",
"futures-io",
@ -717,6 +736,12 @@ dependencies = [
"syn 1.0.42",
]
[[package]]
name = "const_fn"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab"
[[package]]
name = "constant_time_eq"
version = "0.1.5"
@ -943,7 +968,7 @@ checksum = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c"
dependencies = [
"cfg-if 0.1.10",
"crossbeam-channel 0.3.9",
"crossbeam-deque",
"crossbeam-deque 0.7.3",
"crossbeam-epoch 0.7.2",
"crossbeam-queue 0.1.2",
"crossbeam-utils 0.6.6",
@ -968,6 +993,16 @@ dependencies = [
"maybe-uninit",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils 0.8.0",
]
[[package]]
name = "crossbeam-deque"
version = "0.7.3"
@ -979,6 +1014,17 @@ dependencies = [
"maybe-uninit",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-epoch 0.9.0",
"crossbeam-utils 0.8.0",
]
[[package]]
name = "crossbeam-epoch"
version = "0.7.2"
@ -1008,6 +1054,20 @@ dependencies = [
"scopeguard",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f"
dependencies = [
"cfg-if 1.0.0",
"const_fn",
"crossbeam-utils 0.8.0",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-queue"
version = "0.1.2"
@ -1049,6 +1109,18 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5"
dependencies = [
"autocfg 1.0.1",
"cfg-if 1.0.0",
"const_fn",
"lazy_static",
]
[[package]]
name = "crossterm"
version = "0.17.7"
@ -1858,26 +1930,40 @@ dependencies = [
[[package]]
name = "glyph_brush"
version = "0.6.3"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fca6f9d679bff1322c76c9a1ad4b8553b30a94f3f75bea6936e19032c2f2ec3"
checksum = "afd3e2cfd503a5218dd56172a8bf7c8655a4a7cf745737c606a6edfeea1b343f"
dependencies = [
"glyph_brush_draw_cache",
"glyph_brush_layout",
"log",
"ordered-float 1.1.0",
"rustc-hash",
"rusttype 0.8.3",
"twox-hash",
]
[[package]]
name = "glyph_brush_layout"
version = "0.1.9"
name = "glyph_brush_draw_cache"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b70adc570f1dc71b6b32e241cbcc2b42175f5aea71951fbf41e68b04aec24c7"
checksum = "8cef969a091be5565c2c10b31fd2f115cbeed9f783a27c96ae240ff8ceee067c"
dependencies = [
"approx",
"rusttype 0.8.3",
"ab_glyph",
"crossbeam-channel 0.5.0",
"crossbeam-deque 0.8.0",
"linked-hash-map",
"rayon",
"rustc-hash",
]
[[package]]
name = "glyph_brush_layout"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10bc06d530bf20c1902f1b02799ab7372ff43f6119770c49b0bc3f21bd148820"
dependencies = [
"ab_glyph",
"approx 0.4.0",
"xi-unicode",
]
@ -2066,12 +2152,12 @@ dependencies = [
[[package]]
name = "iced_core"
version = "0.2.1"
source = "git+https://github.com/Imberflur/iced?branch=text-clone#0a775191abad5787af3aaa302d5599ef12060264"
source = "git+https://github.com/Imberflur/iced#cf514910c2c0db8633377d2719b244e388774cee"
[[package]]
name = "iced_futures"
version = "0.1.2"
source = "git+https://github.com/Imberflur/iced?branch=text-clone#0a775191abad5787af3aaa302d5599ef12060264"
source = "git+https://github.com/Imberflur/iced#cf514910c2c0db8633377d2719b244e388774cee"
dependencies = [
"futures 0.3.5",
"log",
@ -2081,11 +2167,10 @@ dependencies = [
[[package]]
name = "iced_native"
version = "0.2.2"
source = "git+https://github.com/Imberflur/iced?branch=text-clone#0a775191abad5787af3aaa302d5599ef12060264"
source = "git+https://github.com/Imberflur/iced#cf514910c2c0db8633377d2719b244e388774cee"
dependencies = [
"iced_core",
"iced_futures",
"raw-window-handle",
"twox-hash",
"unicode-segmentation",
]
@ -3112,7 +3197,16 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3"
dependencies = [
"ttf-parser",
"ttf-parser 0.6.2",
]
[[package]]
name = "owned_ttf_parser"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb477c7fd2a3a6e04e1dc6ca2e4e9b04f2df702021dc5a5d1cf078c587dc59f7"
dependencies = [
"ttf-parser 0.8.2",
]
[[package]]
@ -3627,7 +3721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270"
dependencies = [
"autocfg 1.0.1",
"crossbeam-deque",
"crossbeam-deque 0.7.3",
"either",
"rayon-core",
]
@ -3639,7 +3733,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf"
dependencies = [
"crossbeam-channel 0.4.4",
"crossbeam-deque",
"crossbeam-deque 0.7.3",
"crossbeam-utils 0.7.2",
"lazy_static",
"num_cpus",
@ -3810,8 +3904,8 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f61411055101f7b60ecf1041d87fb74205fb20b0c7a723f07ef39174cf6b4c0"
dependencies = [
"approx",
"crossbeam-deque",
"approx 0.3.2",
"crossbeam-deque 0.7.3",
"crossbeam-utils 0.7.2",
"linked-hash-map",
"num_cpus",
@ -3827,7 +3921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser",
"owned_ttf_parser 0.6.0",
]
[[package]]
@ -4590,7 +4684,7 @@ version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89"
dependencies = [
"crossbeam-deque",
"crossbeam-deque 0.7.3",
"crossbeam-queue 0.2.3",
"crossbeam-utils 0.7.2",
"futures 0.1.29",
@ -4764,6 +4858,12 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
[[package]]
name = "ttf-parser"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d973cfa0e6124166b50a1105a67c85de40bbc625082f35c0f56f84cb1fb0a827"
[[package]]
name = "tui"
version = "0.10.0"
@ -4788,7 +4888,7 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56"
dependencies = [
"rand 0.4.6",
"rand 0.7.3",
]
[[package]]
@ -4936,7 +5036,7 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2657d8704e5e0be82b60157c8dbc71a269273ad766984508fdc54030a0690c4d"
dependencies = [
"approx",
"approx 0.3.2",
"num-integer",
"num-traits 0.2.12",
"rustc_version",
@ -4949,7 +5049,7 @@ name = "vek"
version = "0.12.0"
source = "git+https://gitlab.com/veloren/vek.git?branch=fix_intrinsics#237a78528b505f34f6dde5dc77db3b642388fe4a"
dependencies = [
"approx",
"approx 0.3.2",
"num-integer",
"num-traits 0.2.12",
"rustc_version",
@ -5301,7 +5401,7 @@ version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da"
dependencies = [
"cfg-if",
"cfg-if 0.1.10",
"js-sys",
"wasm-bindgen",
"web-sys",
@ -5695,9 +5795,9 @@ checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
[[package]]
name = "xi-unicode"
version = "0.2.1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e71b85d8b1b8bfaf4b5c834187554d201a8cd621c2bbfa33efd41a3ecabd48b2"
checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a"
[[package]]
name = "xml-rs"

View File

@ -35,9 +35,9 @@ winit = {version = "0.22.2", features = ["serde"]}
conrod_core = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"}
conrod_winit = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"}
euc = {git = "https://github.com/zesterer/euc.git"}
iced = {package = "iced_native", git = "https://github.com/Imberflur/iced", branch = "text-clone"}
iced = {package = "iced_native", git = "https://github.com/Imberflur/iced"}
window_clipboard = "0.1.1"
glyph_brush = "0.6.3"
glyph_brush = "0.7.0"
# ECS
specs = {git = "https://github.com/amethyst/specs.git", rev = "7a2e348ab2223818bad487695c66c43db88050a5"}

View File

@ -241,6 +241,7 @@ impl IcedState {
.press_image(self.imgs.button_press)
.text_color(TEXT_COLOR)
.disabled_text_color(DISABLED_TEXT_COLOR);
let buttons = Column::with_children(vec![
self.servers_button.view(
i18n.get("common.servers"),
@ -445,7 +446,7 @@ impl<'a> MainMenuUi {
.unwrap()
.read_to_end(&mut buf)
.unwrap();
glyph_brush::rusttype::Font::from_bytes(buf).unwrap()
ui::ice::Font::try_from_vec(buf).unwrap()
};
let mut ice_ui = IcedUi::new(window, ice_font).unwrap();

View File

@ -10,12 +10,12 @@ use vek::*;
// Multiplied by current window size
const GLYPH_CACHE_SIZE: u16 = 1;
// Glyph cache tolerances
const SCALE_TOLERANCE: f32 = 0.1;
const SCALE_TOLERANCE: f32 = 0.5; // Note: Changed from 0.1 change back if not decent
const POSITION_TOLERANCE: f32 = 0.1;
type GlyphBrush = glyph_brush::GlyphBrush<'static, (Aabr<f32>, Aabr<f32>)>;
type GlyphBrush = glyph_brush::GlyphBrush<(Aabr<f32>, Aabr<f32>), ()>;
pub type Font = glyph_brush::rusttype::Font<'static>;
pub type Font = glyph_brush::ab_glyph::FontArc;
pub struct Cache {
glyph_brush: RefCell<GlyphBrush>,
@ -35,8 +35,8 @@ impl Cache {
let glyph_brush = GlyphBrushBuilder::using_font(default_font)
.initial_cache_size((glyph_cache_dims.x as u32, glyph_cache_dims.y as u32))
.gpu_cache_scale_tolerance(SCALE_TOLERANCE)
.gpu_cache_position_tolerance(POSITION_TOLERANCE)
.draw_cache_scale_tolerance(SCALE_TOLERANCE)
.draw_cache_position_tolerance(POSITION_TOLERANCE)
.build();
Ok(Self {

View File

@ -1,14 +1,18 @@
mod defaults;
mod primitive;
mod style;
mod widgets;
mod widget;
pub use defaults::Defaults;
pub use style::ButtonStyle;
pub(self) use primitive::Primitive;
use super::{
super::graphic::{self, Graphic, TexId},
cache::Cache,
widget, Font, Rotation,
widget::image,
Font, Rotation,
};
use crate::{
render::{
@ -52,36 +56,6 @@ enum State {
Plain,
}
pub enum Primitive {
// Allocation :(
Group {
primitives: Vec<Primitive>,
},
Image {
handle: (widget::image::Handle, Rotation),
bounds: iced::Rectangle,
color: Rgba<u8>,
},
Rectangle {
bounds: iced::Rectangle,
color: Rgba<u8>,
},
Text {
glyphs: Vec<(
glyph_brush::rusttype::PositionedGlyph<'static>,
glyph_brush::Color,
glyph_brush::FontId,
)>,
//size: f32,
bounds: iced::Rectangle,
linear_color: Rgba<f32>,
/*font: iced::Font,
*horizontal_alignment: iced::HorizontalAlignment,
*vertical_alignment: iced::VerticalAlignment, */
},
Nothing,
}
// Optimization idea inspired by what I think iced wgpu renderer may be doing:
// Could have layers of things which don't intersect and thus can be reordered
// arbitrarily
@ -107,6 +81,8 @@ pub struct IcedRenderer {
p_scale: f32,
// Pretend dims :) (i.e. scaled)
win_dims: Vec2<f32>,
// Scissor for the whole window
window_scissor: Aabr<u16>,
// Per-frame/update
current_state: State,
@ -145,6 +121,7 @@ impl IcedRenderer {
align,
p_scale,
win_dims: scaled_dims,
window_scissor: default_scissor(renderer),
start: 0,
//current_scissor: default_scissor(renderer),
})
@ -154,7 +131,7 @@ impl IcedRenderer {
self.cache.add_graphic(graphic)
}
fn image_dims(&self, handle: super::widget::image::Handle) -> (u32, u32) {
fn image_dims(&self, handle: image::Handle) -> (u32, u32) {
self
.cache
.graphic_cache()
@ -218,7 +195,7 @@ impl IcedRenderer {
let brush_result = glyph_cache.process_queued(
|rect, tex_data| {
let offset = [rect.min.x as u16, rect.min.y as u16];
let offset = [rect.min[0] as u16, rect.min[1] as u16];
let size = [rect.width() as u16, rect.height() as u16];
let new_data = tex_data
@ -377,6 +354,12 @@ impl IcedRenderer {
bounds,
color,
} => {
let color = srgba_to_linear(color.map(|e| e as f32 / 255.0));
// Don't draw a transparent image.
if color[3] == 0.0 {
return;
}
let (graphic_id, rotation) = handle;
let gl_aabr = self.gl_aabr(bounds);
@ -387,12 +370,6 @@ impl IcedRenderer {
_ => {},
}
let color = srgba_to_linear(color.map(|e| e as f32 / 255.0));
// Don't draw a transparent image.
if color[3] == 0.0 {
return;
}
let resolution = Vec2::new(
(gl_aabr.size().w * self.half_res.x).round() as u16,
(gl_aabr.size().h * self.half_res.y).round() as u16,
@ -445,10 +422,12 @@ impl IcedRenderer {
self.mesh
.push_quad(create_ui_quad(gl_aabr, uv_aabr, color, UiMode::Image));
},
Primitive::Rectangle { bounds, color } => {
let color = srgba_to_linear(color.map(|e| e as f32 / 255.0));
Primitive::Rectangle {
bounds,
linear_color,
} => {
// Don't draw a transparent rectangle.
if color[3] == 0.0 {
if linear_color[3] == 0.0 {
return;
}
@ -460,7 +439,7 @@ impl IcedRenderer {
min: Vec2::zero(),
max: Vec2::zero(),
},
color,
linear_color,
UiMode::Geometry,
));
},
@ -474,8 +453,6 @@ impl IcedRenderer {
} => {
self.switch_state(State::Plain);
// TODO: Scissor?
// TODO: makes sure we are not doing all this work for hidden text
// e.g. in chat
let glyph_cache = self.cache.glyph_cache_mut();
@ -486,20 +463,21 @@ impl IcedRenderer {
// Queue the glyphs to be cached.
glyph_cache.queue_pre_positioned(
glyphs,
// TODO: glyph_brush should document that these need to be the same length
vec![(); glyph_count],
// Since we already passed in `bounds` to position the glyphs some of this
// seems redundant...
glyph_brush::rusttype::Rect {
min: glyph_brush::rusttype::Point {
x: bounds.x * self.p_scale,
//y: (self.win_dims.y - bounds.y) * self.p_scale,
y: bounds.y * self.p_scale,
},
max: glyph_brush::rusttype::Point {
x: (bounds.x + bounds.width) * self.p_scale,
y: (bounds.y + bounds.height) * self.p_scale,
},
glyph_brush::ab_glyph::Rect {
min: glyph_brush::ab_glyph::point(
bounds.x * self.p_scale,
//(self.win_dims.y - bounds.y) * self.p_scale,
bounds.y * self.p_scale,
),
max: glyph_brush::ab_glyph::point(
(bounds.x + bounds.width) * self.p_scale,
(bounds.y + bounds.height) * self.p_scale,
),
},
0.0, // z (we don't use this)
);
// Leave ui and verts blank to fill in when processing cached glyphs
@ -522,6 +500,66 @@ impl IcedRenderer {
));
}
},
Primitive::Clip { bounds, content } => {
// Check for a change in the scissor.
let new_scissor = {
// Calculate minimum x and y coordinates while
// flipping y axis (from +down to +uo) and
// moving origin from top-left corner to bottom-left
let min_x = bounds.x;
let min_y = self.win_dims.y - bounds.y;
let intersection = Aabr {
min: Vec2 {
x: (min_x * self.p_scale) as u16,
y: (min_y * self.p_scale) as u16,
},
max: Vec2 {
x: ((min_x + bounds.width) * self.p_scale) as u16,
y: ((min_y + bounds.height) * self.p_scale) as u16,
},
}
.intersection(self.window_scissor);
if intersection.is_valid() {
intersection
} else {
Aabr::new_empty(Vec2::zero())
}
};
// Not expecting this case: new_cursor == current_scissor
// Finish the current command.
// TODO: ensure we never push empty commands (make fields private & debug assert
// in constructors?)
self.draw_commands.push(match self.current_state {
State::Plain => DrawCommand::plain(self.start..self.mesh.vertices().len()),
State::Image(id) => {
DrawCommand::image(self.start..self.mesh.vertices().len(), id)
},
});
self.start = self.mesh.vertices().len();
self.draw_commands.push(DrawCommand::Scissor(new_scissor));
// TODO: support nested clips?
// TODO: if last command is a clip changing back to the default replace it with
// this
// Renderer child
self.draw_primitive(*content, renderer);
// Reset scissor
self.draw_commands.push(match self.current_state {
State::Plain => DrawCommand::plain(self.start..self.mesh.vertices().len()),
State::Image(id) => {
DrawCommand::image(self.start..self.mesh.vertices().len(), id)
},
});
self.start = self.mesh.vertices().len();
self.draw_commands
.push(DrawCommand::Scissor(self.window_scissor));
},
Primitive::Nothing => {},
}
}

View File

@ -0,0 +1,31 @@
use crate::ui::{graphic, ice::widget::image};
pub enum Primitive {
// Allocation :(
Group {
primitives: Vec<Primitive>,
},
Image {
handle: (image::Handle, graphic::Rotation),
bounds: iced::Rectangle,
color: vek::Rgba<u8>,
},
Rectangle {
bounds: iced::Rectangle,
linear_color: vek::Rgba<f32>,
},
Text {
glyphs: Vec<glyph_brush::SectionGlyph>,
//size: f32,
bounds: iced::Rectangle,
linear_color: vek::Rgba<f32>,
/*font: iced::Font,
*horizontal_alignment: iced::HorizontalAlignment,
*vertical_alignment: iced::VerticalAlignment, */
},
Clip {
bounds: iced::Rectangle,
content: Box<Primitive>,
},
Nothing,
}

View File

@ -1,4 +1,4 @@
use super::super::widget::image;
use super::super::super::widget::image;
use iced::Color;
#[derive(Clone, Copy)]

View File

@ -2,6 +2,7 @@ use super::super::{
super::{widget::compound_graphic, Rotation},
IcedRenderer, Primitive,
};
use common::util::srgba_to_linear;
use compound_graphic::GraphicKind;
use iced::{mouse, Rectangle};
@ -24,7 +25,10 @@ impl compound_graphic::Renderer for IcedRenderer {
bounds,
color,
},
GraphicKind::Color(color) => Primitive::Rectangle { bounds, color },
GraphicKind::Color(color) => Primitive::Rectangle {
bounds,
linear_color: srgba_to_linear(color.map(|e| e as f32 * 255.0)),
},
})
.collect(),
},

View File

@ -8,3 +8,4 @@ mod image;
mod row;
mod space;
mod text;
mod text_input;

View File

@ -13,11 +13,15 @@ impl text::Renderer for IcedRenderer {
let p_scale = self.p_scale;
// TODO: would be nice if the method was mut
let section = glyph_brush::Section {
text: content,
scale: glyph_brush::rusttype::Scale::uniform(size as f32 * p_scale),
font_id: font.0,
screen_position: (0.0, 0.0),
bounds: (bounds.width * p_scale, bounds.height * p_scale),
..Default::default()
layout: Default::default(),
text: vec![glyph_brush::Text {
text: content,
scale: (size as f32 * p_scale).into(),
font_id: font.0,
extra: (),
}],
};
let maybe_rect = self.cache.glyph_calculator().glyph_bounds(section);
@ -57,30 +61,26 @@ impl text::Renderer for IcedRenderer {
let p_scale = self.p_scale;
let section = glyph_brush::Section {
text: content,
screen_position: (x * p_scale, y * p_scale),
bounds: (bounds.width * p_scale, bounds.height * p_scale),
scale: glyph_brush::rusttype::Scale::uniform(size as f32 * p_scale),
layout: glyph_brush::Layout::Wrap {
line_breaker: Default::default(),
h_align,
v_align,
},
font_id: font.0,
..Default::default()
text: vec![glyph_brush::Text {
text: content,
scale: (size as f32 * p_scale).into(),
font_id: font.0,
extra: (),
}],
};
let glyphs = self
.cache
.glyph_cache_mut()
.glyphs(section)
.map(|positioned_glyph| {
(
positioned_glyph.clone(), // :/
[0.0, 0.0, 0.0, 1.0], // Color
font.0,
)
})
.cloned()
.collect::<Vec<_>>();
(

View File

@ -0,0 +1,273 @@
use super::super::{super::FontId, IcedRenderer, Primitive};
use glyph_brush::GlyphCruncher;
use iced::{
mouse,
text_input::{self, cursor},
Color, Point, Rectangle,
};
const CURSOR_WIDTH: f32 = 1.0;
// Extra scroll offset past the cursor
const EXTRA_OFFSET: f32 = 5.0;
impl text_input::Renderer for IcedRenderer {
type Font = FontId;
type Style = ();
fn default_size(&self) -> u16 {
// TODO: make configurable
20
}
fn measure_value(&self, value: &str, size: u16, font: Self::Font) -> f32 {
// Using the physical scale might make this cached info usable below?
// Although we also have a position of the screen there so this could be useless
let p_scale = self.p_scale;
let section = glyph_brush::Section {
screen_position: (0.0, 0.0),
bounds: (f32::INFINITY, f32::INFINITY),
layout: Default::default(),
text: vec![glyph_brush::Text {
text: value,
scale: (size as f32 * p_scale).into(),
font_id: font.0,
extra: (),
}],
};
let mut glyph_calculator = self.cache.glyph_calculator();
let mut width = glyph_calculator
.glyph_bounds(section)
.map_or(0.0, |rect| rect.width() / p_scale);
// glyph_brush ignores the exterior spaces
// TODO: need better layout lib
let exterior_spaces = value.len() - value.trim().len();
if exterior_spaces > 0 {
use glyph_brush::ab_glyph::{Font, ScaleFont};
// Could cache this if it is slow
let font = glyph_calculator.fonts()[font.0].as_scaled(size as f32);
let space_width = font.h_advance(font.glyph_id(' '));
width += exterior_spaces as f32 * space_width;
}
width
}
fn offset(
&self,
text_bounds: Rectangle,
font: Self::Font,
size: u16,
value: &text_input::Value,
state: &text_input::State,
) -> f32 {
// Only need to offset if focused with cursor somewhere in the text
if state.is_focused() {
let cursor = state.cursor();
let focus_position = match cursor.state(value) {
cursor::State::Index(i) => i,
cursor::State::Selection { end, .. } => end,
};
let (_, offset) = measure_cursor_and_scroll_offset(
self,
text_bounds,
value,
size,
focus_position,
font,
);
offset
} else {
0.0
}
}
fn draw(
&mut self,
bounds: Rectangle,
text_bounds: Rectangle,
//defaults: &Self::Defaults, No defaults!!
cursor_position: Point,
font: Self::Font,
size: u16,
placeholder: &str,
value: &text_input::Value,
state: &text_input::State,
_style_sheet: &Self::Style,
) -> Self::Output {
let is_mouse_over = bounds.contains(cursor_position);
/*
let style = if state.is_focused() {
style.focused()
} else if is_mouse_over {
style.hovered()
} else {
style.active()
}; */
let p_scale = self.p_scale;
// Allocation :(
let text = value.to_string();
let text = if text.is_empty() { Some(&*text) } else { None };
// TODO: background from style, image?
// TODO: color from style
let color = if text.is_some() {
Color::WHITE
} else {
Color::from_rgba(1.0, 1.0, 1.0, 0.4)
};
let linear_color = color.into_linear().into();
let (cursor_primitive, scroll_offset) = if state.is_focused() {
let cursor = state.cursor();
let cursor_and_scroll_offset = |position| {
measure_cursor_and_scroll_offset(self, text_bounds, value, size, position, font)
};
let (cursor_primitive, offset) = match cursor.state(value) {
cursor::State::Index(position) => {
let (position, offset) = cursor_and_scroll_offset(position);
(
Primitive::Rectangle {
bounds: Rectangle {
x: text_bounds.x + position,
y: text_bounds.y,
width: CURSOR_WIDTH / p_scale,
height: text_bounds.height,
},
linear_color,
},
offset,
)
},
cursor::State::Selection { start, end } => {
let left = start.min(end);
let right = end.max(start);
let (left_position, left_offset) = cursor_and_scroll_offset(left);
let (right_position, right_offset) = cursor_and_scroll_offset(right);
let width = right_position - left_position;
(
Primitive::Rectangle {
bounds: Rectangle {
x: text_bounds.x + left_position,
y: text_bounds.y,
width,
height: text_bounds.height,
},
// TODO: selection color from stlye
linear_color: Color::from_rgba(1.0, 0.0, 1.0, 0.2).into_linear().into(),
},
if end == right {
right_offset
} else {
left_offset
},
)
},
};
(Some(cursor_primitive), offset)
} else {
(None, 0.0)
};
let section = glyph_brush::Section {
screen_position: (
text_bounds.x * p_scale + scroll_offset,
text_bounds.center_y() * p_scale,
),
bounds: (text_bounds.width * p_scale, text_bounds.height * p_scale),
layout: glyph_brush::Layout::SingleLine {
line_breaker: Default::default(),
h_align: glyph_brush::HorizontalAlign::Left,
v_align: glyph_brush::VerticalAlign::Center,
},
text: vec![glyph_brush::Text {
text: text.unwrap_or(placeholder),
scale: (size as f32 * p_scale).into(),
font_id: font.0,
extra: (),
}],
};
let glyphs = self
.cache
.glyph_cache_mut()
.glyphs(section)
.cloned()
.collect::<Vec<_>>();
let text_primitive = Primitive::Text {
glyphs,
//size: size as f32,
bounds,
linear_color,
/*font,
*horizontal_alignment,
*vertical_alignment, */
};
let primitive = match cursor_primitive {
Some(cursor_primitive) => Primitive::Group {
primitives: vec![cursor_primitive, text_primitive],
},
None => text_primitive,
};
// Probably already computed this somewhere
let text_width = self.measure_value(text.unwrap_or(placeholder), size, font);
let primitive = if text_width > text_bounds.width {
Primitive::Clip {
bounds: text_bounds,
content: Box::new(primitive),
/* Note: iced_wgpu uses offset here but we can't do that since we pass the text
* to the glyph_brush here */
}
} else {
primitive
};
(
primitive,
if is_mouse_over {
mouse::Interaction::Text
} else {
mouse::Interaction::default()
},
)
}
}
fn measure_cursor_and_scroll_offset(
renderer: &IcedRenderer,
text_bounds: Rectangle,
value: &text_input::Value,
size: u16,
cursor_index: usize,
font: FontId,
) -> (f32, f32) {
use text_input::Renderer;
// TODO: so much allocation (fyi .until() allocates)
let text_before_cursor = value.until(cursor_index).to_string();
let text_value_width = renderer.measure_value(&text_before_cursor, size, font);
let offset = ((text_value_width + EXTRA_OFFSET) - text_bounds.width).max(0.0);
(text_value_width, offset)
}