[refactor] extract paint code from Ui/Context to new struct Painter
This commit is contained in:
parent
5c14a15f8c
commit
11df21e39e
18 changed files with 333 additions and 309 deletions
|
@ -87,7 +87,7 @@ impl State {
|
||||||
*p = rect.center() + v;
|
*p = rect.center() + v;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_paint_cmd(PaintCmd::Path {
|
ui.painter().add(PaintCmd::Path {
|
||||||
path: Path::from_point_loop(&points),
|
path: Path::from_point_loop(&points),
|
||||||
closed: true,
|
closed: true,
|
||||||
fill: None,
|
fill: None,
|
||||||
|
@ -219,7 +219,7 @@ impl CollapsingHeader {
|
||||||
state.toggle(ui);
|
state.toggle(ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
let where_to_put_background = ui.paint_list_len();
|
let bg_index = ui.painter().add(PaintCmd::Noop);
|
||||||
|
|
||||||
{
|
{
|
||||||
let (mut icon_rect, _) = ui.style().icon_rectangles(interact.rect);
|
let (mut icon_rect, _) = ui.style().icon_rectangles(interact.rect);
|
||||||
|
@ -234,15 +234,16 @@ impl CollapsingHeader {
|
||||||
state.paint_icon(ui, &icon_interact);
|
state.paint_icon(ui, &icon_interact);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_galley(
|
let painter = ui.painter();
|
||||||
|
painter.add_galley(
|
||||||
text_pos,
|
text_pos,
|
||||||
galley,
|
galley,
|
||||||
label.text_style,
|
label.text_style,
|
||||||
Some(ui.style().interact(&interact).stroke_color),
|
ui.style().interact(&interact).stroke_color,
|
||||||
);
|
);
|
||||||
|
|
||||||
ui.insert_paint_cmd(
|
painter.set(
|
||||||
where_to_put_background,
|
bg_index,
|
||||||
PaintCmd::Rect {
|
PaintCmd::Rect {
|
||||||
corner_radius: ui.style().interact(&interact).corner_radius,
|
corner_radius: ui.style().interact(&interact).corner_radius,
|
||||||
fill: ui.style().interact(&interact).bg_fill,
|
fill: ui.style().interact(&interact).bg_fill,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Frame container
|
//! Frame container
|
||||||
|
|
||||||
use crate::{paint::*, *};
|
use crate::{layers::PaintCmdIdx, paint::*, *};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
|
@ -62,7 +62,7 @@ impl Frame {
|
||||||
pub struct Prepared {
|
pub struct Prepared {
|
||||||
pub frame: Frame,
|
pub frame: Frame,
|
||||||
outer_rect_bounds: Rect,
|
outer_rect_bounds: Rect,
|
||||||
where_to_put_background: usize,
|
where_to_put_background: PaintCmdIdx,
|
||||||
pub content_ui: Ui,
|
pub content_ui: Ui,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ impl Frame {
|
||||||
pub fn begin(self, ui: &mut Ui) -> Prepared {
|
pub fn begin(self, ui: &mut Ui) -> Prepared {
|
||||||
let outer_rect_bounds = ui.available();
|
let outer_rect_bounds = ui.available();
|
||||||
let inner_rect = outer_rect_bounds.shrink2(self.margin);
|
let inner_rect = outer_rect_bounds.shrink2(self.margin);
|
||||||
let where_to_put_background = ui.paint_list_len();
|
let where_to_put_background = ui.painter().add(PaintCmd::Noop);
|
||||||
let content_ui = ui.child_ui(inner_rect);
|
let content_ui = ui.child_ui(inner_rect);
|
||||||
Prepared {
|
Prepared {
|
||||||
frame: self,
|
frame: self,
|
||||||
|
@ -105,7 +105,7 @@ impl Prepared {
|
||||||
..
|
..
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
ui.insert_paint_cmd(
|
ui.painter().set(
|
||||||
where_to_put_background,
|
where_to_put_background,
|
||||||
PaintCmd::Rect {
|
PaintCmd::Rect {
|
||||||
corner_radius: frame.corner_radius,
|
corner_radius: frame.corner_radius,
|
||||||
|
|
|
@ -226,7 +226,7 @@ impl Resize {
|
||||||
// so we must follow the contents:
|
// so we must follow the contents:
|
||||||
|
|
||||||
state.desired_size = state.desired_size.max(state.last_content_size);
|
state.desired_size = state.desired_size.max(state.last_content_size);
|
||||||
state.desired_size = ui.round_vec_to_pixels(state.desired_size);
|
state.desired_size = ui.painter().round_vec_to_pixels(state.desired_size);
|
||||||
|
|
||||||
// We are as large as we look
|
// We are as large as we look
|
||||||
ui.allocate_space(state.desired_size);
|
ui.allocate_space(state.desired_size);
|
||||||
|
@ -240,7 +240,7 @@ impl Resize {
|
||||||
if self.outline && corner_interact.is_some() {
|
if self.outline && corner_interact.is_some() {
|
||||||
let rect = Rect::from_min_size(content_ui.top_left(), state.desired_size);
|
let rect = Rect::from_min_size(content_ui.top_left(), state.desired_size);
|
||||||
let rect = rect.expand(2.0); // breathing room for content
|
let rect = rect.expand(2.0); // breathing room for content
|
||||||
ui.add_paint_cmd(paint::PaintCmd::Rect {
|
ui.painter().add(paint::PaintCmd::Rect {
|
||||||
rect,
|
rect,
|
||||||
corner_radius: 3.0,
|
corner_radius: 3.0,
|
||||||
fill: None,
|
fill: None,
|
||||||
|
@ -259,12 +259,12 @@ impl Resize {
|
||||||
ui.memory().resize.insert(id, state);
|
ui.memory().resize.insert(id, state);
|
||||||
|
|
||||||
if ui.ctx().style().debug_resize {
|
if ui.ctx().style().debug_resize {
|
||||||
ui.ctx().debug_rect(
|
ui.ctx().debug_painter().debug_rect(
|
||||||
Rect::from_min_size(content_ui.top_left(), state.desired_size),
|
Rect::from_min_size(content_ui.top_left(), state.desired_size),
|
||||||
color::GREEN,
|
color::GREEN,
|
||||||
"desired_size",
|
"desired_size",
|
||||||
);
|
);
|
||||||
ui.ctx().debug_rect(
|
ui.ctx().debug_painter().debug_rect(
|
||||||
Rect::from_min_size(content_ui.top_left(), state.last_content_size),
|
Rect::from_min_size(content_ui.top_left(), state.last_content_size),
|
||||||
color::LIGHT_BLUE,
|
color::LIGHT_BLUE,
|
||||||
"last_content_size",
|
"last_content_size",
|
||||||
|
@ -277,11 +277,13 @@ fn paint_resize_corner(ui: &mut Ui, interact: &InteractInfo) {
|
||||||
let color = ui.style().interact(interact).stroke_color;
|
let color = ui.style().interact(interact).stroke_color;
|
||||||
let width = ui.style().interact(interact).stroke_width;
|
let width = ui.style().interact(interact).stroke_width;
|
||||||
|
|
||||||
let corner = ui.round_pos_to_pixels(interact.rect.right_bottom());
|
let painter = ui.painter();
|
||||||
|
|
||||||
|
let corner = painter.round_pos_to_pixels(interact.rect.right_bottom());
|
||||||
let mut w = 2.0;
|
let mut w = 2.0;
|
||||||
|
|
||||||
while w < 12.0 {
|
while w < 12.0 {
|
||||||
ui.add_paint_cmd(paint::PaintCmd::line_segment(
|
painter.add(paint::PaintCmd::line_segment(
|
||||||
[pos2(corner.x - w, corner.y), pos2(corner.x, corner.y - w)],
|
[pos2(corner.x - w, corner.y), pos2(corner.x, corner.y - w)],
|
||||||
color,
|
color,
|
||||||
width,
|
width,
|
||||||
|
|
|
@ -268,14 +268,14 @@ impl Prepared {
|
||||||
let handle_fill = style.interact(&interact).fill;
|
let handle_fill = style.interact(&interact).fill;
|
||||||
let handle_outline = style.interact(&interact).rect_outline;
|
let handle_outline = style.interact(&interact).rect_outline;
|
||||||
|
|
||||||
ui.add_paint_cmd(paint::PaintCmd::Rect {
|
ui.painter().add(paint::PaintCmd::Rect {
|
||||||
rect: outer_scroll_rect,
|
rect: outer_scroll_rect,
|
||||||
corner_radius,
|
corner_radius,
|
||||||
fill: Some(ui.style().dark_bg_color),
|
fill: Some(ui.style().dark_bg_color),
|
||||||
outline: None,
|
outline: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add_paint_cmd(paint::PaintCmd::Rect {
|
ui.painter().add(paint::PaintCmd::Rect {
|
||||||
rect: handle_rect.expand(-2.0),
|
rect: handle_rect.expand(-2.0),
|
||||||
corner_radius,
|
corner_radius,
|
||||||
fill: Some(handle_fill),
|
fill: Some(handle_fill),
|
||||||
|
|
|
@ -511,7 +511,7 @@ fn paint_frame_interaction(
|
||||||
path.add_circle_quadrant(pos2(max.x - cr, min.y + cr), cr, 3.0);
|
path.add_circle_quadrant(pos2(max.x - cr, min.y + cr), cr, 3.0);
|
||||||
path.add_line_segment([pos2(max.x, min.y + cr), pos2(max.x, max.y - cr)]);
|
path.add_line_segment([pos2(max.x, min.y + cr), pos2(max.x, max.y - cr)]);
|
||||||
}
|
}
|
||||||
ui.add_paint_cmd(PaintCmd::Path {
|
ui.painter().add(PaintCmd::Path {
|
||||||
path,
|
path,
|
||||||
closed: false,
|
closed: false,
|
||||||
fill: None,
|
fill: None,
|
||||||
|
@ -614,7 +614,7 @@ impl TitleBar {
|
||||||
let left = outer_rect.left();
|
let left = outer_rect.left();
|
||||||
let right = outer_rect.right();
|
let right = outer_rect.right();
|
||||||
let y = content_rect.top() + ui.style().item_spacing.y * 0.5;
|
let y = content_rect.top() + ui.style().item_spacing.y * 0.5;
|
||||||
ui.add_paint_cmd(PaintCmd::LineSegment {
|
ui.painter().add(PaintCmd::LineSegment {
|
||||||
points: [pos2(left, y), pos2(right, y)],
|
points: [pos2(left, y), pos2(right, y)],
|
||||||
style: ui.style().interact.inactive.rect_outline.unwrap(),
|
style: ui.style().interact.inactive.rect_outline.unwrap(),
|
||||||
});
|
});
|
||||||
|
@ -650,12 +650,12 @@ fn close_button(ui: &mut Ui, rect: Rect) -> InteractInfo {
|
||||||
|
|
||||||
let stroke_color = ui.style().interact(&interact).stroke_color;
|
let stroke_color = ui.style().interact(&interact).stroke_color;
|
||||||
let stroke_width = ui.style().interact(&interact).stroke_width;
|
let stroke_width = ui.style().interact(&interact).stroke_width;
|
||||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
ui.painter().add(PaintCmd::line_segment(
|
||||||
[rect.left_top(), rect.right_bottom()],
|
[rect.left_top(), rect.right_bottom()],
|
||||||
stroke_color,
|
stroke_color,
|
||||||
stroke_width,
|
stroke_width,
|
||||||
));
|
));
|
||||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
ui.painter().add(PaintCmd::line_segment(
|
||||||
[rect.right_top(), rect.left_bottom()],
|
[rect.right_top(), rect.left_bottom()],
|
||||||
stroke_color,
|
stroke_color,
|
||||||
stroke_width,
|
stroke_width,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use {ahash::AHashMap, parking_lot::Mutex};
|
use {ahash::AHashMap, parking_lot::Mutex};
|
||||||
|
|
||||||
use crate::{layout::align_rect, paint::*, *};
|
use crate::{paint::*, *};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
struct PaintStats {
|
struct PaintStats {
|
||||||
|
@ -234,7 +234,7 @@ impl Context {
|
||||||
|
|
||||||
/// Generate a id from the given source.
|
/// Generate a id from the given source.
|
||||||
/// If it is not unique, an error will be printed at the given position.
|
/// If it is not unique, an error will be printed at the given position.
|
||||||
pub fn make_unique_id<IdSource>(&self, source: IdSource, pos: Pos2) -> Id
|
pub fn make_unique_id<IdSource>(self: &Arc<Self>, source: IdSource, pos: Pos2) -> Id
|
||||||
where
|
where
|
||||||
IdSource: std::hash::Hash + std::fmt::Debug + Copy,
|
IdSource: std::hash::Hash + std::fmt::Debug + Copy,
|
||||||
{
|
{
|
||||||
|
@ -246,19 +246,25 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the given Id is not unique, an error will be printed at the given position.
|
/// If the given Id is not unique, an error will be printed at the given position.
|
||||||
pub fn register_unique_id(&self, id: Id, source_name: impl std::fmt::Debug, pos: Pos2) -> Id {
|
pub fn register_unique_id(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
id: Id,
|
||||||
|
source_name: impl std::fmt::Debug,
|
||||||
|
pos: Pos2,
|
||||||
|
) -> Id {
|
||||||
if let Some(clash_pos) = self.used_ids.lock().insert(id, pos) {
|
if let Some(clash_pos) = self.used_ids.lock().insert(id, pos) {
|
||||||
|
let painter = self.debug_painter();
|
||||||
if clash_pos.distance(pos) < 4.0 {
|
if clash_pos.distance(pos) < 4.0 {
|
||||||
self.show_error(
|
painter.error(
|
||||||
pos,
|
pos,
|
||||||
&format!("use of non-unique ID {:?} (name clash?)", source_name),
|
&format!("use of non-unique ID {:?} (name clash?)", source_name),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.show_error(
|
painter.error(
|
||||||
clash_pos,
|
clash_pos,
|
||||||
&format!("first use of non-unique ID {:?} (name clash?)", source_name),
|
&format!("first use of non-unique ID {:?} (name clash?)", source_name),
|
||||||
);
|
);
|
||||||
self.show_error(
|
painter.error(
|
||||||
pos,
|
pos,
|
||||||
&format!(
|
&format!(
|
||||||
"second use of non-unique ID {:?} (name clash?)",
|
"second use of non-unique ID {:?} (name clash?)",
|
||||||
|
@ -422,103 +428,12 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
/// ## Painting
|
||||||
|
impl Context {
|
||||||
pub fn show_error(&self, pos: Pos2, text: impl Into<String>) {
|
pub fn debug_painter(self: &Arc<Self>) -> Painter {
|
||||||
let text = text.into();
|
Painter::new(self.clone(), Layer::debug(), self.rect())
|
||||||
let align = (Align::Min, Align::Min);
|
|
||||||
let layer = Layer::debug();
|
|
||||||
let text_style = TextStyle::Monospace;
|
|
||||||
let font = &self.fonts()[text_style];
|
|
||||||
let galley = font.layout_multiline(text, f32::INFINITY);
|
|
||||||
let rect = align_rect(Rect::from_min_size(pos, galley.size), align);
|
|
||||||
self.add_paint_cmd(
|
|
||||||
layer,
|
|
||||||
PaintCmd::Rect {
|
|
||||||
corner_radius: 0.0,
|
|
||||||
fill: Some(color::gray(0, 240)),
|
|
||||||
outline: Some(LineStyle::new(1.0, color::RED)),
|
|
||||||
rect: rect.expand(2.0),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
self.add_galley(layer, rect.min, galley, text_style, Some(color::RED));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn debug_text(&self, pos: Pos2, text: impl Into<String>) {
|
|
||||||
let text = text.into();
|
|
||||||
let layer = Layer::debug();
|
|
||||||
let align = (Align::Min, Align::Min);
|
|
||||||
self.floating_text(
|
|
||||||
layer,
|
|
||||||
pos,
|
|
||||||
text,
|
|
||||||
TextStyle::Monospace,
|
|
||||||
align,
|
|
||||||
Some(color::YELLOW),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn debug_rect(&self, rect: Rect, color: Color, name: impl Into<String>) {
|
|
||||||
let text = format!("{} {:?}", name.into(), rect);
|
|
||||||
let layer = Layer::debug();
|
|
||||||
self.add_paint_cmd(
|
|
||||||
layer,
|
|
||||||
PaintCmd::Rect {
|
|
||||||
corner_radius: 0.0,
|
|
||||||
fill: None,
|
|
||||||
outline: Some(LineStyle::new(2.0, color)),
|
|
||||||
rect,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let align = (Align::Min, Align::Min);
|
|
||||||
let text_style = TextStyle::Monospace;
|
|
||||||
self.floating_text(layer, rect.min, text, text_style, align, Some(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Show some text anywhere on screen.
|
|
||||||
/// To center the text at the given position, use `align: (Center, Center)`.
|
|
||||||
pub fn floating_text(
|
|
||||||
&self,
|
|
||||||
layer: Layer,
|
|
||||||
pos: Pos2,
|
|
||||||
text: String,
|
|
||||||
text_style: TextStyle,
|
|
||||||
align: (Align, Align),
|
|
||||||
text_color: Option<Color>,
|
|
||||||
) -> Rect {
|
|
||||||
let font = &self.fonts()[text_style];
|
|
||||||
let galley = font.layout_multiline(text, f32::INFINITY);
|
|
||||||
let rect = align_rect(Rect::from_min_size(pos, galley.size), align);
|
|
||||||
self.add_galley(layer, rect.min, galley, text_style, text_color);
|
|
||||||
rect
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Already layed out text.
|
|
||||||
pub fn add_galley(
|
|
||||||
&self,
|
|
||||||
layer: Layer,
|
|
||||||
pos: Pos2,
|
|
||||||
galley: font::Galley,
|
|
||||||
text_style: TextStyle,
|
|
||||||
color: Option<Color>,
|
|
||||||
) {
|
|
||||||
let color = color.unwrap_or_else(|| self.style().text_color);
|
|
||||||
self.add_paint_cmd(
|
|
||||||
layer,
|
|
||||||
PaintCmd::Text {
|
|
||||||
pos,
|
|
||||||
galley,
|
|
||||||
text_style,
|
|
||||||
color,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_paint_cmd(&self, layer: Layer, paint_cmd: PaintCmd) {
|
|
||||||
self.graphics()
|
|
||||||
.layer(layer)
|
|
||||||
.push((Rect::everything(), paint_cmd))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -469,7 +469,7 @@ impl BoxPainting {
|
||||||
outline: Some(LineStyle::new(self.stroke_width, gray(255, 255))),
|
outline: Some(LineStyle::new(self.stroke_width, gray(255, 255))),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ui.add_paint_cmds(cmds);
|
ui.painter().extend(cmds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,7 +498,8 @@ impl Painting {
|
||||||
let rect = ui.allocate_space(ui.available_finite().size());
|
let rect = ui.allocate_space(ui.available_finite().size());
|
||||||
let interact = ui.interact(rect, ui.id(), Sense::drag());
|
let interact = ui.interact(rect, ui.id(), Sense::drag());
|
||||||
let rect = interact.rect;
|
let rect = interact.rect;
|
||||||
ui.set_clip_rect(ui.clip_rect().intersect(rect)); // Make sure we don't paint out of bounds
|
let clip_rect = ui.clip_rect().intersect(rect); // Make sure we don't paint out of bounds
|
||||||
|
let painter = Painter::new(ui.ctx().clone(), ui.layer(), clip_rect);
|
||||||
|
|
||||||
if self.lines.is_empty() {
|
if self.lines.is_empty() {
|
||||||
self.lines.push(vec![]);
|
self.lines.push(vec![]);
|
||||||
|
@ -520,7 +521,7 @@ impl Painting {
|
||||||
for line in &self.lines {
|
for line in &self.lines {
|
||||||
if line.len() >= 2 {
|
if line.len() >= 2 {
|
||||||
let points: Vec<Pos2> = line.iter().map(|p| rect.min + *p).collect();
|
let points: Vec<Pos2> = line.iter().map(|p| rect.min + *p).collect();
|
||||||
ui.add_paint_cmd(PaintCmd::Path {
|
painter.add(PaintCmd::Path {
|
||||||
path: Path::from_open_points(&points),
|
path: Path::from_open_points(&points),
|
||||||
closed: false,
|
closed: false,
|
||||||
outline: Some(LineStyle::new(2.0, LIGHT_GRAY)),
|
outline: Some(LineStyle::new(2.0, LIGHT_GRAY)),
|
||||||
|
|
|
@ -50,18 +50,18 @@ impl FractalClock {
|
||||||
ui.ctx().request_repaint();
|
ui.ctx().request_repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fractal_ui(ui, ui.available_finite());
|
let painter = Painter::new(ui.ctx().clone(), ui.layer(), ui.available_finite());
|
||||||
|
self.fractal_ui(&painter);
|
||||||
|
|
||||||
let frame = Frame::popup(ui.style())
|
Frame::popup(ui.style())
|
||||||
.fill(Some(color::gray(34, 160)))
|
.fill(Some(color::gray(34, 160)))
|
||||||
.outline(None);
|
.outline(None)
|
||||||
|
.show(&mut ui.left_column(320.0), |ui| {
|
||||||
frame.show(&mut ui.left_column(320.0), |ui| {
|
CollapsingHeader::new("Settings").show(ui, |ui| self.options_ui(ui));
|
||||||
CollapsingHeader::new("Settings").show(ui, |ui| self.options_ui(ui));
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Make sure we allocate what we used (everything)
|
// Make sure we allocate what we used (everything)
|
||||||
ui.allocate_space(ui.available_finite().size());
|
ui.allocate_space(painter.clip_rect().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn options_ui(&mut self, ui: &mut Ui) {
|
fn options_ui(&mut self, ui: &mut Ui) {
|
||||||
|
@ -96,7 +96,9 @@ impl FractalClock {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fractal_ui(&mut self, ui: &mut Ui, rect: Rect) {
|
fn fractal_ui(&mut self, painter: &Painter) {
|
||||||
|
let rect = painter.clip_rect();
|
||||||
|
|
||||||
struct Hand {
|
struct Hand {
|
||||||
length: f32,
|
length: f32,
|
||||||
angle: f32,
|
angle: f32,
|
||||||
|
@ -126,13 +128,13 @@ impl FractalClock {
|
||||||
];
|
];
|
||||||
|
|
||||||
let scale = self.zoom * rect.width().min(rect.height());
|
let scale = self.zoom * rect.width().min(rect.height());
|
||||||
let mut paint_line = |points: [Pos2; 2], color: Color, width: f32| {
|
let paint_line = |points: [Pos2; 2], color: Color, width: f32| {
|
||||||
let line = [
|
let line = [
|
||||||
rect.center() + scale * points[0].to_vec2(),
|
rect.center() + scale * points[0].to_vec2(),
|
||||||
rect.center() + scale * points[1].to_vec2(),
|
rect.center() + scale * points[1].to_vec2(),
|
||||||
];
|
];
|
||||||
|
|
||||||
ui.add_paint_cmd(PaintCmd::line_segment([line[0], line[1]], color, width));
|
painter.add(PaintCmd::line_segment([line[0], line[1]], color, width));
|
||||||
};
|
};
|
||||||
|
|
||||||
let hand_rotations = [
|
let hand_rotations = [
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl Texture {
|
||||||
};
|
};
|
||||||
let mut triangles = Triangles::default();
|
let mut triangles = Triangles::default();
|
||||||
triangles.add_rect(top_left, bottom_right);
|
triangles.add_rect(top_left, bottom_right);
|
||||||
ui.add_paint_cmd(PaintCmd::Triangles(triangles));
|
ui.painter().add(PaintCmd::Triangles(triangles));
|
||||||
|
|
||||||
if ui.hovered(rect) {
|
if ui.hovered(rect) {
|
||||||
show_tooltip(ui.ctx(), |ui| {
|
show_tooltip(ui.ctx(), |ui| {
|
||||||
|
@ -55,7 +55,7 @@ impl Texture {
|
||||||
};
|
};
|
||||||
let mut triangles = Triangles::default();
|
let mut triangles = Triangles::default();
|
||||||
triangles.add_rect(top_left, bottom_right);
|
triangles.add_rect(top_left, bottom_right);
|
||||||
ui.add_paint_cmd(PaintCmd::Triangles(triangles));
|
ui.painter().add(PaintCmd::Triangles(triangles));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub enum Order {
|
||||||
Debug,
|
Debug,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An ideintifer for a paint layer.
|
/// An identifier for a paint layer.
|
||||||
/// Also acts as an identifier for `Area`:s.
|
/// Also acts as an identifier for `Area`:s.
|
||||||
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
@ -34,15 +34,38 @@ impl Layer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub struct PaintCmdIdx(usize);
|
||||||
|
|
||||||
/// Each `PaintCmd` is paired with a clip rectangle.
|
/// Each `PaintCmd` is paired with a clip rectangle.
|
||||||
type PaintList = Vec<(Rect, PaintCmd)>;
|
#[derive(Clone, Default)]
|
||||||
|
pub struct PaintList(Vec<(Rect, PaintCmd)>);
|
||||||
|
|
||||||
|
impl PaintList {
|
||||||
|
/// Returns the index of the new command that can be used with `PaintList::set`.
|
||||||
|
pub fn add(&mut self, clip_rect: Rect, cmd: PaintCmd) -> PaintCmdIdx {
|
||||||
|
let idx = PaintCmdIdx(self.0.len());
|
||||||
|
self.0.push((clip_rect, cmd));
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend(&mut self, clip_rect: Rect, mut cmds: Vec<PaintCmd>) {
|
||||||
|
self.0.extend(cmds.drain(..).map(|cmd| (clip_rect, cmd)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify an existing command.
|
||||||
|
pub fn set(&mut self, idx: PaintCmdIdx, clip_rect: Rect, cmd: PaintCmd) {
|
||||||
|
assert!(idx.0 < self.0.len());
|
||||||
|
self.0[idx.0] = (clip_rect, cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: improve this
|
// TODO: improve this
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct GraphicLayers(AHashMap<Layer, PaintList>);
|
pub struct GraphicLayers(AHashMap<Layer, PaintList>);
|
||||||
|
|
||||||
impl GraphicLayers {
|
impl GraphicLayers {
|
||||||
pub fn layer(&mut self, layer: Layer) -> &mut PaintList {
|
pub fn list(&mut self, layer: Layer) -> &mut PaintList {
|
||||||
self.0.entry(layer).or_default()
|
self.0.entry(layer).or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,12 +77,12 @@ impl GraphicLayers {
|
||||||
|
|
||||||
for layer in area_order {
|
for layer in area_order {
|
||||||
if let Some(commands) = self.0.get_mut(layer) {
|
if let Some(commands) = self.0.get_mut(layer) {
|
||||||
all_commands.extend(commands.drain(..));
|
all_commands.extend(commands.0.drain(..));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(commands) = self.0.get_mut(&Layer::debug()) {
|
if let Some(commands) = self.0.get_mut(&Layer::debug()) {
|
||||||
all_commands.extend(commands.drain(..));
|
all_commands.extend(commands.0.drain(..));
|
||||||
}
|
}
|
||||||
|
|
||||||
all_commands.into_iter()
|
all_commands.into_iter()
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub mod math;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod movement_tracker;
|
mod movement_tracker;
|
||||||
pub mod paint;
|
pub mod paint;
|
||||||
|
mod painter;
|
||||||
mod style;
|
mod style;
|
||||||
mod types;
|
mod types;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
@ -52,6 +53,7 @@ pub use {
|
||||||
memory::Memory,
|
memory::Memory,
|
||||||
movement_tracker::MovementTracker,
|
movement_tracker::MovementTracker,
|
||||||
paint::{color, Color, PaintJobs, TextStyle, Texture},
|
paint::{color, Color, PaintJobs, TextStyle, Texture},
|
||||||
|
painter::Painter,
|
||||||
style::Style,
|
style::Style,
|
||||||
types::*,
|
types::*,
|
||||||
ui::Ui,
|
ui::Ui,
|
||||||
|
|
|
@ -6,6 +6,8 @@ use {
|
||||||
// TODO: rename, e.g. `paint::Cmd`?
|
// TODO: rename, e.g. `paint::Cmd`?
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum PaintCmd {
|
pub enum PaintCmd {
|
||||||
|
/// Paint nothing. This can be useful as a placeholder.
|
||||||
|
Noop,
|
||||||
Circle {
|
Circle {
|
||||||
center: Pos2,
|
center: Pos2,
|
||||||
fill: Option<Color>,
|
fill: Option<Color>,
|
||||||
|
|
|
@ -564,6 +564,7 @@ pub fn tessellate_paint_command(
|
||||||
path.clear();
|
path.clear();
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
|
PaintCmd::Noop => {}
|
||||||
PaintCmd::Circle {
|
PaintCmd::Circle {
|
||||||
center,
|
center,
|
||||||
fill,
|
fill,
|
||||||
|
|
165
egui/src/painter.rs
Normal file
165
egui/src/painter.rs
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
align_rect, color,
|
||||||
|
layers::PaintCmdIdx,
|
||||||
|
math::{Pos2, Rect, Vec2},
|
||||||
|
paint::{font, Fonts, LineStyle, PaintCmd, TextStyle},
|
||||||
|
Align, Color, Context, Layer,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Helper to paint shapes and text to a specific region on a specific layer.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Painter {
|
||||||
|
/// Source of fonts and destination of paint commands
|
||||||
|
ctx: Arc<Context>,
|
||||||
|
|
||||||
|
/// Where we paint
|
||||||
|
layer: Layer,
|
||||||
|
|
||||||
|
/// Everything painted in this `Painter` will be clipped against this.
|
||||||
|
/// This means nothing outside of this rectangle will be visible on screen.
|
||||||
|
clip_rect: Rect,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Painter {
|
||||||
|
pub fn new(ctx: Arc<Context>, layer: Layer, clip_rect: Rect) -> Self {
|
||||||
|
Self {
|
||||||
|
ctx,
|
||||||
|
layer,
|
||||||
|
clip_rect,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## Accessors etc
|
||||||
|
impl Painter {
|
||||||
|
pub fn ctx(&self) -> &Arc<Context> {
|
||||||
|
&self.ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Available fonts
|
||||||
|
pub fn fonts(&self) -> &Fonts {
|
||||||
|
self.ctx.fonts()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Where we paint
|
||||||
|
pub fn layer(&self) -> Layer {
|
||||||
|
self.layer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Everything painted in this `Painter` will be clipped against this.
|
||||||
|
/// This means nothing outside of this rectangle will be visible on screen.
|
||||||
|
pub fn clip_rect(&self) -> Rect {
|
||||||
|
self.clip_rect
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Everything painted in this `Painter` will be clipped against this.
|
||||||
|
/// This means nothing outside of this rectangle will be visible on screen.
|
||||||
|
pub fn set_clip_rect(&mut self, clip_rect: Rect) {
|
||||||
|
self.clip_rect = clip_rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn round_to_pixel(&self, point: f32) -> f32 {
|
||||||
|
self.ctx().round_to_pixel(point)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn round_vec_to_pixels(&self, vec: Vec2) -> Vec2 {
|
||||||
|
self.ctx().round_vec_to_pixels(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn round_pos_to_pixels(&self, pos: Pos2) -> Pos2 {
|
||||||
|
self.ctx().round_pos_to_pixels(pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## Low level
|
||||||
|
impl Painter {
|
||||||
|
/// It is up to the caller to make sure there is room for this.
|
||||||
|
/// Can be used for free painting.
|
||||||
|
/// NOTE: all coordinates are screen coordinates!
|
||||||
|
pub fn add(&self, paint_cmd: PaintCmd) -> PaintCmdIdx {
|
||||||
|
self.ctx
|
||||||
|
.graphics()
|
||||||
|
.list(self.layer)
|
||||||
|
.add(self.clip_rect, paint_cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend(&self, cmds: Vec<PaintCmd>) {
|
||||||
|
self.ctx
|
||||||
|
.graphics()
|
||||||
|
.list(self.layer)
|
||||||
|
.extend(self.clip_rect, cmds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify an existing command.
|
||||||
|
pub fn set(&self, idx: PaintCmdIdx, cmd: PaintCmd) {
|
||||||
|
self.ctx
|
||||||
|
.graphics()
|
||||||
|
.list(self.layer)
|
||||||
|
.set(idx, self.clip_rect, cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## Debug painting
|
||||||
|
impl Painter {
|
||||||
|
pub fn debug_rect(&mut self, rect: Rect, color: Color, text: impl Into<String>) {
|
||||||
|
self.add(PaintCmd::Rect {
|
||||||
|
corner_radius: 0.0,
|
||||||
|
fill: None,
|
||||||
|
outline: Some(LineStyle::new(1.0, color)),
|
||||||
|
rect,
|
||||||
|
});
|
||||||
|
let align = (Align::Min, Align::Min);
|
||||||
|
let text_style = TextStyle::Monospace;
|
||||||
|
self.floating_text(rect.min, text.into(), text_style, align, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(&self, pos: Pos2, text: impl Into<String>) {
|
||||||
|
let text = text.into();
|
||||||
|
let align = (Align::Min, Align::Min);
|
||||||
|
let text_style = TextStyle::Monospace;
|
||||||
|
let font = &self.fonts()[text_style];
|
||||||
|
let galley = font.layout_multiline(text, f32::INFINITY);
|
||||||
|
let rect = align_rect(Rect::from_min_size(pos, galley.size), align);
|
||||||
|
self.add(PaintCmd::Rect {
|
||||||
|
corner_radius: 0.0,
|
||||||
|
fill: Some(color::gray(0, 240)),
|
||||||
|
outline: Some(LineStyle::new(1.0, color::RED)),
|
||||||
|
rect: rect.expand(2.0),
|
||||||
|
});
|
||||||
|
self.add_galley(rect.min, galley, text_style, color::RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## Text
|
||||||
|
impl Painter {
|
||||||
|
/// Show some text anywhere in the ui.
|
||||||
|
/// To center the text at the given position, use `align: (Center, Center)`.
|
||||||
|
/// If you want to draw text floating on top of everything,
|
||||||
|
/// consider using `Context.floating_text` instead.
|
||||||
|
pub fn floating_text(
|
||||||
|
&self,
|
||||||
|
pos: Pos2,
|
||||||
|
text: impl Into<String>,
|
||||||
|
text_style: TextStyle,
|
||||||
|
align: (Align, Align),
|
||||||
|
text_color: Color,
|
||||||
|
) -> Rect {
|
||||||
|
let font = &self.fonts()[text_style];
|
||||||
|
let galley = font.layout_multiline(text.into(), f32::INFINITY);
|
||||||
|
let rect = align_rect(Rect::from_min_size(pos, galley.size), align);
|
||||||
|
self.add_galley(rect.min, galley, text_style, text_color);
|
||||||
|
rect
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Already layed out text.
|
||||||
|
pub fn add_galley(&self, pos: Pos2, galley: font::Galley, text_style: TextStyle, color: Color) {
|
||||||
|
self.add(PaintCmd::Text {
|
||||||
|
pos,
|
||||||
|
galley,
|
||||||
|
text_style,
|
||||||
|
color,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
186
egui/src/ui.rs
186
egui/src/ui.rs
|
@ -5,9 +5,6 @@ use crate::{color::*, containers::*, layout::*, paint::*, widgets::*, *};
|
||||||
/// Represents a region of the screen
|
/// Represents a region of the screen
|
||||||
/// with a type of layout (horizontal or vertical).
|
/// with a type of layout (horizontal or vertical).
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
/// How we access input, output and memory
|
|
||||||
ctx: Arc<Context>,
|
|
||||||
|
|
||||||
/// ID of this ui.
|
/// ID of this ui.
|
||||||
/// Generated based on id of parent ui together with
|
/// Generated based on id of parent ui together with
|
||||||
/// another source of child identity (e.g. window title).
|
/// another source of child identity (e.g. window title).
|
||||||
|
@ -15,12 +12,7 @@ pub struct Ui {
|
||||||
/// Hopefully unique.
|
/// Hopefully unique.
|
||||||
id: Id,
|
id: Id,
|
||||||
|
|
||||||
/// Where to put the graphics output of this Ui
|
painter: Painter,
|
||||||
layer: Layer,
|
|
||||||
|
|
||||||
/// Everything painted in this ui will be clipped against this.
|
|
||||||
/// This means nothing outside of this rectangle will be visible on screen.
|
|
||||||
clip_rect: Rect,
|
|
||||||
|
|
||||||
/// The `rect` represents where in screen-space the ui is
|
/// The `rect` represents where in screen-space the ui is
|
||||||
/// and its max size (original available_space).
|
/// and its max size (original available_space).
|
||||||
|
@ -62,11 +54,10 @@ impl Ui {
|
||||||
|
|
||||||
pub fn new(ctx: Arc<Context>, layer: Layer, id: Id, rect: Rect) -> Self {
|
pub fn new(ctx: Arc<Context>, layer: Layer, id: Id, rect: Rect) -> Self {
|
||||||
let style = ctx.style();
|
let style = ctx.style();
|
||||||
|
let clip_rect = rect.expand(style.clip_rect_margin);
|
||||||
Ui {
|
Ui {
|
||||||
ctx,
|
|
||||||
id,
|
id,
|
||||||
layer,
|
painter: Painter::new(ctx, layer, clip_rect),
|
||||||
clip_rect: rect.expand(style.clip_rect_margin),
|
|
||||||
desired_rect: rect,
|
desired_rect: rect,
|
||||||
child_bounds: Rect::from_min_size(rect.min, Vec2::zero()), // TODO: Rect::nothing() ?
|
child_bounds: Rect::from_min_size(rect.min, Vec2::zero()), // TODO: Rect::nothing() ?
|
||||||
style,
|
style,
|
||||||
|
@ -77,14 +68,11 @@ impl Ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn child_ui(&mut self, child_rect: Rect) -> Self {
|
pub fn child_ui(&mut self, child_rect: Rect) -> Self {
|
||||||
let clip_rect = self.clip_rect(); // Keep it unless the child excplicitly desires differently
|
|
||||||
let id = self.make_position_id(); // TODO: is this a good idea?
|
let id = self.make_position_id(); // TODO: is this a good idea?
|
||||||
self.child_count += 1;
|
self.child_count += 1;
|
||||||
Ui {
|
Ui {
|
||||||
ctx: self.ctx.clone(),
|
|
||||||
id,
|
id,
|
||||||
layer: self.layer,
|
painter: self.painter.clone(),
|
||||||
clip_rect,
|
|
||||||
desired_rect: child_rect,
|
desired_rect: child_rect,
|
||||||
child_bounds: Rect::from_min_size(child_rect.min, Vec2::zero()), // TODO: Rect::nothing() ?
|
child_bounds: Rect::from_min_size(child_rect.min, Vec2::zero()), // TODO: Rect::nothing() ?
|
||||||
style: self.style.clone(),
|
style: self.style.clone(),
|
||||||
|
@ -96,18 +84,6 @@ impl Ui {
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
pub fn round_to_pixel(&self, point: f32) -> f32 {
|
|
||||||
self.ctx.round_to_pixel(point)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn round_vec_to_pixels(&self, vec: Vec2) -> Vec2 {
|
|
||||||
self.ctx.round_vec_to_pixels(vec)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn round_pos_to_pixels(&self, pos: Pos2) -> Pos2 {
|
|
||||||
self.ctx.round_pos_to_pixels(pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn id(&self) -> Id {
|
pub fn id(&self) -> Id {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
@ -122,34 +98,45 @@ impl Ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctx(&self) -> &Arc<Context> {
|
pub fn ctx(&self) -> &Arc<Context> {
|
||||||
&self.ctx
|
self.painter.ctx()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use this to paint stuff within this `Ui`.
|
||||||
|
pub fn painter(&self) -> &Painter {
|
||||||
|
&self.painter
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use this to paint stuff within this `Ui`.
|
||||||
|
pub fn layer(&self) -> Layer {
|
||||||
|
self.painter().layer()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&self) -> &InputState {
|
pub fn input(&self) -> &InputState {
|
||||||
self.ctx.input()
|
self.ctx().input()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn memory(&self) -> parking_lot::MutexGuard<'_, Memory> {
|
pub fn memory(&self) -> parking_lot::MutexGuard<'_, Memory> {
|
||||||
self.ctx.memory()
|
self.ctx().memory()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn output(&self) -> parking_lot::MutexGuard<'_, Output> {
|
pub fn output(&self) -> parking_lot::MutexGuard<'_, Output> {
|
||||||
self.ctx.output()
|
self.ctx().output()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fonts(&self) -> &Fonts {
|
pub fn fonts(&self) -> &Fonts {
|
||||||
self.ctx.fonts()
|
self.ctx().fonts()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Screen-space rectangle for clipping what we paint in this ui.
|
/// Screen-space rectangle for clipping what we paint in this ui.
|
||||||
/// This is used, for instance, to avoid painting outside a window that is smaller
|
/// This is used, for instance, to avoid painting outside a window that is smaller than its contents.
|
||||||
/// than its contents.
|
|
||||||
pub fn clip_rect(&self) -> Rect {
|
pub fn clip_rect(&self) -> Rect {
|
||||||
self.clip_rect
|
self.painter.clip_rect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Screen-space rectangle for clipping what we paint in this ui.
|
||||||
|
/// This is used, for instance, to avoid painting outside a window that is smaller than its contents.
|
||||||
pub fn set_clip_rect(&mut self, clip_rect: Rect) {
|
pub fn set_clip_rect(&mut self, clip_rect: Rect) {
|
||||||
self.clip_rect = clip_rect;
|
self.painter.set_clip_rect(clip_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -269,7 +256,8 @@ impl Ui {
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
pub fn contains_mouse(&self, rect: Rect) -> bool {
|
pub fn contains_mouse(&self, rect: Rect) -> bool {
|
||||||
self.ctx.contains_mouse(self.layer, self.clip_rect, rect)
|
self.ctx()
|
||||||
|
.contains_mouse(self.layer(), self.clip_rect(), rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_kb_focus(&self, id: Id) -> bool {
|
pub fn has_kb_focus(&self, id: Id) -> bool {
|
||||||
|
@ -293,7 +281,7 @@ impl Ui {
|
||||||
{
|
{
|
||||||
let id = self.id.with(&id_source);
|
let id = self.id.with(&id_source);
|
||||||
// TODO: clip name clash error messages to clip rect
|
// TODO: clip name clash error messages to clip rect
|
||||||
self.ctx.register_unique_id(id, id_source, self.cursor)
|
self.ctx().register_unique_id(id, id_source, self.cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ideally, all widgets should use this. TODO
|
/// Ideally, all widgets should use this. TODO
|
||||||
|
@ -309,13 +297,13 @@ impl Ui {
|
||||||
self.id.with(&explicit_id_source)
|
self.id.with(&explicit_id_source)
|
||||||
} else {
|
} else {
|
||||||
let id = self.id.with(default_id_source);
|
let id = self.id.with(default_id_source);
|
||||||
if self.ctx.is_unique_id(id) {
|
if self.ctx().is_unique_id(id) {
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
self.make_position_id()
|
self.make_position_id()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.ctx
|
self.ctx()
|
||||||
.register_unique_id(id, default_id_source.unwrap_or_default(), self.cursor)
|
.register_unique_id(id, default_id_source.unwrap_or_default(), self.cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,13 +322,13 @@ impl Ui {
|
||||||
/// # Interaction
|
/// # Interaction
|
||||||
impl Ui {
|
impl Ui {
|
||||||
pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> InteractInfo {
|
pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> InteractInfo {
|
||||||
self.ctx
|
self.ctx()
|
||||||
.interact(self.layer, self.clip_rect, rect, Some(id), sense)
|
.interact(self.layer(), self.clip_rect(), rect, Some(id), sense)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interact_hover(&self, rect: Rect) -> InteractInfo {
|
pub fn interact_hover(&self, rect: Rect) -> InteractInfo {
|
||||||
self.ctx
|
self.ctx()
|
||||||
.interact(self.layer, self.clip_rect, rect, None, Sense::nothing())
|
.interact(self.layer(), self.clip_rect(), rect, None, Sense::nothing())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hovered(&self, rect: Rect) -> bool {
|
pub fn hovered(&self, rect: Rect) -> bool {
|
||||||
|
@ -365,7 +353,7 @@ impl Ui {
|
||||||
double_clicked,
|
double_clicked,
|
||||||
active,
|
active,
|
||||||
rect,
|
rect,
|
||||||
ctx: self.ctx.clone(),
|
ctx: self.ctx().clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,8 +373,8 @@ impl Ui {
|
||||||
///
|
///
|
||||||
/// You may get LESS space than you asked for if the current layout won't fit what you asked for.
|
/// You may get LESS space than you asked for if the current layout won't fit what you asked for.
|
||||||
pub fn allocate_space(&mut self, child_size: Vec2) -> Rect {
|
pub fn allocate_space(&mut self, child_size: Vec2) -> Rect {
|
||||||
let child_size = self.round_vec_to_pixels(child_size);
|
let child_size = self.painter().round_vec_to_pixels(child_size);
|
||||||
self.cursor = self.round_pos_to_pixels(self.cursor);
|
self.cursor = self.painter().round_pos_to_pixels(self.cursor);
|
||||||
|
|
||||||
// For debug rendering
|
// For debug rendering
|
||||||
let too_wide = child_size.x > self.available().width();
|
let too_wide = child_size.x > self.available().width();
|
||||||
|
@ -395,7 +383,7 @@ impl Ui {
|
||||||
let rect = self.reserve_space_impl(child_size);
|
let rect = self.reserve_space_impl(child_size);
|
||||||
|
|
||||||
if self.style().debug_widget_rects {
|
if self.style().debug_widget_rects {
|
||||||
self.add_paint_cmd(PaintCmd::Rect {
|
self.painter.add(PaintCmd::Rect {
|
||||||
rect,
|
rect,
|
||||||
corner_radius: 0.0,
|
corner_radius: 0.0,
|
||||||
outline: Some(LineStyle::new(1.0, LIGHT_BLUE)),
|
outline: Some(LineStyle::new(1.0, LIGHT_BLUE)),
|
||||||
|
@ -405,8 +393,10 @@ impl Ui {
|
||||||
let color = color::srgba(200, 0, 0, 255);
|
let color = color::srgba(200, 0, 0, 255);
|
||||||
let width = 2.5;
|
let width = 2.5;
|
||||||
|
|
||||||
let mut paint_line_seg =
|
let paint_line_seg = |a, b| {
|
||||||
|a, b| self.add_paint_cmd(PaintCmd::line_segment([a, b], color, width));
|
self.painter
|
||||||
|
.add(PaintCmd::line_segment([a, b], color, width))
|
||||||
|
};
|
||||||
|
|
||||||
if too_wide {
|
if too_wide {
|
||||||
paint_line_seg(rect.left_top(), rect.left_bottom());
|
paint_line_seg(rect.left_top(), rect.left_bottom());
|
||||||
|
@ -437,96 +427,6 @@ impl Ui {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Painting related stuff
|
|
||||||
impl Ui {
|
|
||||||
/// It is up to the caller to make sure there is room for this.
|
|
||||||
/// Can be used for free painting.
|
|
||||||
/// NOTE: all coordinates are screen coordinates!
|
|
||||||
pub fn add_paint_cmd(&mut self, paint_cmd: PaintCmd) {
|
|
||||||
self.ctx
|
|
||||||
.graphics()
|
|
||||||
.layer(self.layer)
|
|
||||||
.push((self.clip_rect(), paint_cmd))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_paint_cmds(&mut self, mut cmds: Vec<PaintCmd>) {
|
|
||||||
let clip_rect = self.clip_rect();
|
|
||||||
self.ctx
|
|
||||||
.graphics()
|
|
||||||
.layer(self.layer)
|
|
||||||
.extend(cmds.drain(..).map(|cmd| (clip_rect, cmd)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Insert a paint cmd before existing ones
|
|
||||||
pub fn insert_paint_cmd(&mut self, pos: usize, paint_cmd: PaintCmd) {
|
|
||||||
self.ctx
|
|
||||||
.graphics()
|
|
||||||
.layer(self.layer)
|
|
||||||
.insert(pos, (self.clip_rect(), paint_cmd));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn paint_list_len(&self) -> usize {
|
|
||||||
self.ctx.graphics().layer(self.layer).len()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Paint some debug text at current cursor
|
|
||||||
pub fn debug_text(&self, text: impl Into<String>) {
|
|
||||||
self.debug_text_at(self.cursor, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn debug_text_at(&self, pos: Pos2, text: impl Into<String>) {
|
|
||||||
self.ctx.debug_text(pos, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn debug_rect(&mut self, rect: Rect, text: impl Into<String>) {
|
|
||||||
self.add_paint_cmd(PaintCmd::Rect {
|
|
||||||
corner_radius: 0.0,
|
|
||||||
fill: None,
|
|
||||||
outline: Some(LineStyle::new(1.0, color::RED)),
|
|
||||||
rect,
|
|
||||||
});
|
|
||||||
let align = (Align::Min, Align::Min);
|
|
||||||
let text_style = TextStyle::Monospace;
|
|
||||||
self.floating_text(rect.min, text.into(), text_style, align, Some(color::RED));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Show some text anywhere in the ui.
|
|
||||||
/// To center the text at the given position, use `align: (Center, Center)`.
|
|
||||||
/// If you want to draw text floating on top of everything,
|
|
||||||
/// consider using `Context.floating_text` instead.
|
|
||||||
pub fn floating_text(
|
|
||||||
&mut self,
|
|
||||||
pos: Pos2,
|
|
||||||
text: impl Into<String>,
|
|
||||||
text_style: TextStyle,
|
|
||||||
align: (Align, Align),
|
|
||||||
text_color: Option<Color>,
|
|
||||||
) -> Rect {
|
|
||||||
let font = &self.fonts()[text_style];
|
|
||||||
let galley = font.layout_multiline(text.into(), f32::INFINITY);
|
|
||||||
let rect = align_rect(Rect::from_min_size(pos, galley.size), align);
|
|
||||||
self.add_galley(rect.min, galley, text_style, text_color);
|
|
||||||
rect
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Already layed out text.
|
|
||||||
pub fn add_galley(
|
|
||||||
&mut self,
|
|
||||||
pos: Pos2,
|
|
||||||
galley: font::Galley,
|
|
||||||
text_style: TextStyle,
|
|
||||||
color: Option<Color>,
|
|
||||||
) {
|
|
||||||
let color = color.unwrap_or_else(|| self.style().text_color);
|
|
||||||
self.add_paint_cmd(PaintCmd::Text {
|
|
||||||
pos,
|
|
||||||
galley,
|
|
||||||
text_style,
|
|
||||||
color,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Adding widgets
|
/// # Adding widgets
|
||||||
impl Ui {
|
impl Ui {
|
||||||
pub fn add(&mut self, widget: impl Widget) -> GuiResponse {
|
pub fn add(&mut self, widget: impl Widget) -> GuiResponse {
|
||||||
|
@ -637,9 +537,9 @@ impl Ui {
|
||||||
|
|
||||||
// draw a grey line on the left to mark the indented section
|
// draw a grey line on the left to mark the indented section
|
||||||
let line_start = child_rect.min - indent * 0.5;
|
let line_start = child_rect.min - indent * 0.5;
|
||||||
let line_start = self.round_pos_to_pixels(line_start);
|
let line_start = self.painter().round_pos_to_pixels(line_start);
|
||||||
let line_end = pos2(line_start.x, line_start.y + size.y - 2.0);
|
let line_end = pos2(line_start.x, line_start.y + size.y - 2.0);
|
||||||
self.add_paint_cmd(PaintCmd::line_segment(
|
self.painter.add(PaintCmd::line_segment(
|
||||||
[line_start, line_end],
|
[line_start, line_end],
|
||||||
gray(150, 255),
|
gray(150, 255),
|
||||||
self.style.line_width,
|
self.style.line_width,
|
||||||
|
|
|
@ -102,7 +102,9 @@ impl Label {
|
||||||
// This should be the easiest method of putting text anywhere.
|
// This should be the easiest method of putting text anywhere.
|
||||||
|
|
||||||
pub fn paint_galley(&self, ui: &mut Ui, pos: Pos2, galley: font::Galley) {
|
pub fn paint_galley(&self, ui: &mut Ui, pos: Pos2, galley: font::Galley) {
|
||||||
ui.add_galley(pos, galley, self.text_style, self.text_color);
|
let text_color = self.text_color.unwrap_or_else(|| ui.style().text_color);
|
||||||
|
ui.painter()
|
||||||
|
.add_galley(pos, galley, self.text_style, text_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,10 +190,10 @@ impl Widget for Hyperlink {
|
||||||
for line in &galley.lines {
|
for line in &galley.lines {
|
||||||
let pos = interact.rect.min;
|
let pos = interact.rect.min;
|
||||||
let y = pos.y + line.y_max;
|
let y = pos.y + line.y_max;
|
||||||
let y = ui.round_to_pixel(y);
|
let y = ui.painter().round_to_pixel(y);
|
||||||
let min_x = pos.x + line.min_x();
|
let min_x = pos.x + line.min_x();
|
||||||
let max_x = pos.x + line.max_x();
|
let max_x = pos.x + line.max_x();
|
||||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
ui.painter().add(PaintCmd::line_segment(
|
||||||
[pos2(min_x, y), pos2(max_x, y)],
|
[pos2(min_x, y), pos2(max_x, y)],
|
||||||
color,
|
color,
|
||||||
ui.style().line_width,
|
ui.style().line_width,
|
||||||
|
@ -199,7 +201,8 @@ impl Widget for Hyperlink {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_galley(interact.rect.min, galley, text_style, Some(color));
|
ui.painter()
|
||||||
|
.add_galley(interact.rect.min, galley, text_style, color);
|
||||||
|
|
||||||
interact
|
interact
|
||||||
}
|
}
|
||||||
|
@ -279,7 +282,7 @@ impl Widget for Button {
|
||||||
let interact = ui.interact(rect, id, sense);
|
let interact = ui.interact(rect, id, sense);
|
||||||
let text_cursor = interact.rect.left_center() + vec2(padding.x, -0.5 * galley.size.y);
|
let text_cursor = interact.rect.left_center() + vec2(padding.x, -0.5 * galley.size.y);
|
||||||
let bg_fill = fill.or(ui.style().interact(&interact).bg_fill);
|
let bg_fill = fill.or(ui.style().interact(&interact).bg_fill);
|
||||||
ui.add_paint_cmd(PaintCmd::Rect {
|
ui.painter().add(PaintCmd::Rect {
|
||||||
corner_radius: ui.style().interact(&interact).corner_radius,
|
corner_radius: ui.style().interact(&interact).corner_radius,
|
||||||
fill: bg_fill,
|
fill: bg_fill,
|
||||||
outline: ui.style().interact(&interact).rect_outline,
|
outline: ui.style().interact(&interact).rect_outline,
|
||||||
|
@ -287,7 +290,8 @@ impl Widget for Button {
|
||||||
});
|
});
|
||||||
let stroke_color = ui.style().interact(&interact).stroke_color;
|
let stroke_color = ui.style().interact(&interact).stroke_color;
|
||||||
let text_color = text_color.unwrap_or(stroke_color);
|
let text_color = text_color.unwrap_or(stroke_color);
|
||||||
ui.add_galley(text_cursor, galley, text_style, Some(text_color));
|
ui.painter()
|
||||||
|
.add_galley(text_cursor, galley, text_style, text_color);
|
||||||
interact
|
interact
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +344,7 @@ impl<'a> Widget for Checkbox<'a> {
|
||||||
*checked = !*checked;
|
*checked = !*checked;
|
||||||
}
|
}
|
||||||
let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect);
|
let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect);
|
||||||
ui.add_paint_cmd(PaintCmd::Rect {
|
ui.painter().add(PaintCmd::Rect {
|
||||||
corner_radius: ui.style().interact(&interact).corner_radius,
|
corner_radius: ui.style().interact(&interact).corner_radius,
|
||||||
fill: ui.style().interact(&interact).bg_fill,
|
fill: ui.style().interact(&interact).bg_fill,
|
||||||
outline: ui.style().interact(&interact).rect_outline,
|
outline: ui.style().interact(&interact).rect_outline,
|
||||||
|
@ -350,7 +354,7 @@ impl<'a> Widget for Checkbox<'a> {
|
||||||
let stroke_color = ui.style().interact(&interact).stroke_color;
|
let stroke_color = ui.style().interact(&interact).stroke_color;
|
||||||
|
|
||||||
if *checked {
|
if *checked {
|
||||||
ui.add_paint_cmd(PaintCmd::Path {
|
ui.painter().add(PaintCmd::Path {
|
||||||
path: Path::from_open_points(&[
|
path: Path::from_open_points(&[
|
||||||
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
||||||
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
||||||
|
@ -363,7 +367,8 @@ impl<'a> Widget for Checkbox<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let text_color = text_color.unwrap_or(stroke_color);
|
let text_color = text_color.unwrap_or(stroke_color);
|
||||||
ui.add_galley(text_cursor, galley, text_style, Some(text_color));
|
ui.painter()
|
||||||
|
.add_galley(text_cursor, galley, text_style, text_color);
|
||||||
interact
|
interact
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,7 +422,9 @@ impl Widget for RadioButton {
|
||||||
|
|
||||||
let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect);
|
let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect);
|
||||||
|
|
||||||
ui.add_paint_cmd(PaintCmd::Circle {
|
let painter = ui.painter();
|
||||||
|
|
||||||
|
painter.add(PaintCmd::Circle {
|
||||||
center: big_icon_rect.center(),
|
center: big_icon_rect.center(),
|
||||||
fill: bg_fill,
|
fill: bg_fill,
|
||||||
outline: ui.style().interact(&interact).rect_outline, // TODO
|
outline: ui.style().interact(&interact).rect_outline, // TODO
|
||||||
|
@ -425,7 +432,7 @@ impl Widget for RadioButton {
|
||||||
});
|
});
|
||||||
|
|
||||||
if checked {
|
if checked {
|
||||||
ui.add_paint_cmd(PaintCmd::Circle {
|
painter.add(PaintCmd::Circle {
|
||||||
center: small_icon_rect.center(),
|
center: small_icon_rect.center(),
|
||||||
fill: Some(stroke_color),
|
fill: Some(stroke_color),
|
||||||
outline: None,
|
outline: None,
|
||||||
|
@ -434,7 +441,7 @@ impl Widget for RadioButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
let text_color = text_color.unwrap_or(stroke_color);
|
let text_color = text_color.unwrap_or(stroke_color);
|
||||||
ui.add_galley(text_cursor, galley, text_style, Some(text_color));
|
painter.add_galley(text_cursor, galley, text_style, text_color);
|
||||||
interact
|
interact
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -520,7 +527,7 @@ impl Widget for Separator {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ui.add_paint_cmd(PaintCmd::LineSegment {
|
ui.painter().add(PaintCmd::LineSegment {
|
||||||
points,
|
points,
|
||||||
style: LineStyle::new(line_width, color),
|
style: LineStyle::new(line_width, color),
|
||||||
});
|
});
|
||||||
|
|
|
@ -107,7 +107,7 @@ impl<'a> Widget for Slider<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let text_on_top = self.text_on_top.unwrap_or_default();
|
let text_on_top = self.text_on_top.unwrap_or_default();
|
||||||
let text_color = self.text_color;
|
let text_color = self.text_color.unwrap_or_else(|| ui.style().text_color);
|
||||||
let value = (self.get_set_value)(None);
|
let value = (self.get_set_value)(None);
|
||||||
let full_text = format!("{}: {:.*}", text, self.precision, value);
|
let full_text = format!("{}: {:.*}", text, self.precision, value);
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ impl<'a> Widget for Slider<'a> {
|
||||||
if text_on_top {
|
if text_on_top {
|
||||||
let galley = font.layout_single_line(full_text);
|
let galley = font.layout_single_line(full_text);
|
||||||
let pos = ui.allocate_space(galley.size).min;
|
let pos = ui.allocate_space(galley.size).min;
|
||||||
ui.add_galley(pos, galley, text_style, text_color);
|
ui.painter().add_galley(pos, galley, text_style, text_color);
|
||||||
slider_sans_text.ui(ui)
|
slider_sans_text.ui(ui)
|
||||||
} else {
|
} else {
|
||||||
ui.columns(2, |columns| {
|
ui.columns(2, |columns| {
|
||||||
|
@ -162,21 +162,21 @@ impl<'a> Widget for Slider<'a> {
|
||||||
let value = self.get_value_f32();
|
let value = self.get_value_f32();
|
||||||
|
|
||||||
let rect = interact.rect;
|
let rect = interact.rect;
|
||||||
let rail_radius = ui.round_to_pixel((height / 8.0).max(2.0));
|
let rail_radius = ui.painter().round_to_pixel((height / 8.0).max(2.0));
|
||||||
let rail_rect = Rect::from_min_max(
|
let rail_rect = Rect::from_min_max(
|
||||||
pos2(interact.rect.left(), rect.center().y - rail_radius),
|
pos2(interact.rect.left(), rect.center().y - rail_radius),
|
||||||
pos2(interact.rect.right(), rect.center().y + rail_radius),
|
pos2(interact.rect.right(), rect.center().y + rail_radius),
|
||||||
);
|
);
|
||||||
let marker_center_x = remap_clamp(value, range, left..=right);
|
let marker_center_x = remap_clamp(value, range, left..=right);
|
||||||
|
|
||||||
ui.add_paint_cmd(PaintCmd::Rect {
|
ui.painter().add(PaintCmd::Rect {
|
||||||
rect: rail_rect,
|
rect: rail_rect,
|
||||||
corner_radius: rail_radius,
|
corner_radius: rail_radius,
|
||||||
fill: Some(ui.style().background_fill),
|
fill: Some(ui.style().background_fill),
|
||||||
outline: Some(LineStyle::new(1.0, color::gray(200, 255))), // TODO
|
outline: Some(LineStyle::new(1.0, color::gray(200, 255))), // TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add_paint_cmd(PaintCmd::Circle {
|
ui.painter().add(PaintCmd::Circle {
|
||||||
center: pos2(marker_center_x, rail_rect.center().y),
|
center: pos2(marker_center_x, rail_rect.center().y),
|
||||||
radius: handle_radius,
|
radius: handle_radius,
|
||||||
fill: Some(ui.style().interact(&interact).fill),
|
fill: Some(ui.style().interact(&interact).fill),
|
||||||
|
|
|
@ -129,9 +129,11 @@ impl<'t> Widget for TextEdit<'t> {
|
||||||
// dbg!(&galley);
|
// dbg!(&galley);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let painter = ui.painter();
|
||||||
|
|
||||||
{
|
{
|
||||||
let bg_rect = interact.rect.expand(2.0); // breathing room for content
|
let bg_rect = interact.rect.expand(2.0); // breathing room for content
|
||||||
ui.add_paint_cmd(PaintCmd::Rect {
|
painter.add(PaintCmd::Rect {
|
||||||
rect: bg_rect,
|
rect: bg_rect,
|
||||||
corner_radius: ui.style().interact.style(&interact).corner_radius,
|
corner_radius: ui.style().interact.style(&interact).corner_radius,
|
||||||
fill: Some(ui.style().dark_bg_color),
|
fill: Some(ui.style().dark_bg_color),
|
||||||
|
@ -146,7 +148,7 @@ impl<'t> Widget for TextEdit<'t> {
|
||||||
if show_cursor {
|
if show_cursor {
|
||||||
if let Some(cursor) = state.cursor {
|
if let Some(cursor) = state.cursor {
|
||||||
let cursor_pos = interact.rect.min + galley.char_start_pos(cursor);
|
let cursor_pos = interact.rect.min + galley.char_start_pos(cursor);
|
||||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
painter.add(PaintCmd::line_segment(
|
||||||
[cursor_pos, cursor_pos + vec2(0.0, line_spacing)],
|
[cursor_pos, cursor_pos + vec2(0.0, line_spacing)],
|
||||||
color::WHITE,
|
color::WHITE,
|
||||||
ui.style().text_cursor_width,
|
ui.style().text_cursor_width,
|
||||||
|
@ -156,7 +158,8 @@ impl<'t> Widget for TextEdit<'t> {
|
||||||
ui.ctx().request_repaint(); // TODO: only when cursor blinks on or off
|
ui.ctx().request_repaint(); // TODO: only when cursor blinks on or off
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_galley(interact.rect.min, galley, text_style, text_color);
|
let text_color = text_color.unwrap_or_else(|| ui.style().text_color);
|
||||||
|
painter.add_galley(interact.rect.min, galley, text_style, text_color);
|
||||||
ui.memory().text_edit.insert(id, state);
|
ui.memory().text_edit.insert(id, state);
|
||||||
interact
|
interact
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue