[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;
|
||||
}
|
||||
|
||||
ui.add_paint_cmd(PaintCmd::Path {
|
||||
ui.painter().add(PaintCmd::Path {
|
||||
path: Path::from_point_loop(&points),
|
||||
closed: true,
|
||||
fill: None,
|
||||
|
@ -219,7 +219,7 @@ impl CollapsingHeader {
|
|||
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);
|
||||
|
@ -234,15 +234,16 @@ impl CollapsingHeader {
|
|||
state.paint_icon(ui, &icon_interact);
|
||||
}
|
||||
|
||||
ui.add_galley(
|
||||
let painter = ui.painter();
|
||||
painter.add_galley(
|
||||
text_pos,
|
||||
galley,
|
||||
label.text_style,
|
||||
Some(ui.style().interact(&interact).stroke_color),
|
||||
ui.style().interact(&interact).stroke_color,
|
||||
);
|
||||
|
||||
ui.insert_paint_cmd(
|
||||
where_to_put_background,
|
||||
painter.set(
|
||||
bg_index,
|
||||
PaintCmd::Rect {
|
||||
corner_radius: ui.style().interact(&interact).corner_radius,
|
||||
fill: ui.style().interact(&interact).bg_fill,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Frame container
|
||||
|
||||
use crate::{paint::*, *};
|
||||
use crate::{layers::PaintCmdIdx, paint::*, *};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Frame {
|
||||
|
@ -62,7 +62,7 @@ impl Frame {
|
|||
pub struct Prepared {
|
||||
pub frame: Frame,
|
||||
outer_rect_bounds: Rect,
|
||||
where_to_put_background: usize,
|
||||
where_to_put_background: PaintCmdIdx,
|
||||
pub content_ui: Ui,
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ impl Frame {
|
|||
pub fn begin(self, ui: &mut Ui) -> Prepared {
|
||||
let outer_rect_bounds = ui.available();
|
||||
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);
|
||||
Prepared {
|
||||
frame: self,
|
||||
|
@ -105,7 +105,7 @@ impl Prepared {
|
|||
..
|
||||
} = self;
|
||||
|
||||
ui.insert_paint_cmd(
|
||||
ui.painter().set(
|
||||
where_to_put_background,
|
||||
PaintCmd::Rect {
|
||||
corner_radius: frame.corner_radius,
|
||||
|
|
|
@ -226,7 +226,7 @@ impl Resize {
|
|||
// so we must follow the contents:
|
||||
|
||||
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
|
||||
ui.allocate_space(state.desired_size);
|
||||
|
@ -240,7 +240,7 @@ impl Resize {
|
|||
if self.outline && corner_interact.is_some() {
|
||||
let rect = Rect::from_min_size(content_ui.top_left(), state.desired_size);
|
||||
let rect = rect.expand(2.0); // breathing room for content
|
||||
ui.add_paint_cmd(paint::PaintCmd::Rect {
|
||||
ui.painter().add(paint::PaintCmd::Rect {
|
||||
rect,
|
||||
corner_radius: 3.0,
|
||||
fill: None,
|
||||
|
@ -259,12 +259,12 @@ impl Resize {
|
|||
ui.memory().resize.insert(id, state);
|
||||
|
||||
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),
|
||||
color::GREEN,
|
||||
"desired_size",
|
||||
);
|
||||
ui.ctx().debug_rect(
|
||||
ui.ctx().debug_painter().debug_rect(
|
||||
Rect::from_min_size(content_ui.top_left(), state.last_content_size),
|
||||
color::LIGHT_BLUE,
|
||||
"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 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;
|
||||
|
||||
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)],
|
||||
color,
|
||||
width,
|
||||
|
|
|
@ -268,14 +268,14 @@ impl Prepared {
|
|||
let handle_fill = style.interact(&interact).fill;
|
||||
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,
|
||||
corner_radius,
|
||||
fill: Some(ui.style().dark_bg_color),
|
||||
outline: None,
|
||||
});
|
||||
|
||||
ui.add_paint_cmd(paint::PaintCmd::Rect {
|
||||
ui.painter().add(paint::PaintCmd::Rect {
|
||||
rect: handle_rect.expand(-2.0),
|
||||
corner_radius,
|
||||
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_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,
|
||||
closed: false,
|
||||
fill: None,
|
||||
|
@ -614,7 +614,7 @@ impl TitleBar {
|
|||
let left = outer_rect.left();
|
||||
let right = outer_rect.right();
|
||||
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)],
|
||||
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_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()],
|
||||
stroke_color,
|
||||
stroke_width,
|
||||
));
|
||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
||||
ui.painter().add(PaintCmd::line_segment(
|
||||
[rect.right_top(), rect.left_bottom()],
|
||||
stroke_color,
|
||||
stroke_width,
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
|||
|
||||
use {ahash::AHashMap, parking_lot::Mutex};
|
||||
|
||||
use crate::{layout::align_rect, paint::*, *};
|
||||
use crate::{paint::*, *};
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct PaintStats {
|
||||
|
@ -234,7 +234,7 @@ impl Context {
|
|||
|
||||
/// Generate a id from the given source.
|
||||
/// 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
|
||||
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.
|
||||
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) {
|
||||
let painter = self.debug_painter();
|
||||
if clash_pos.distance(pos) < 4.0 {
|
||||
self.show_error(
|
||||
painter.error(
|
||||
pos,
|
||||
&format!("use of non-unique ID {:?} (name clash?)", source_name),
|
||||
);
|
||||
} else {
|
||||
self.show_error(
|
||||
painter.error(
|
||||
clash_pos,
|
||||
&format!("first use of non-unique ID {:?} (name clash?)", source_name),
|
||||
);
|
||||
self.show_error(
|
||||
painter.error(
|
||||
pos,
|
||||
&format!(
|
||||
"second use of non-unique ID {:?} (name clash?)",
|
||||
|
@ -422,103 +428,12 @@ impl Context {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
pub fn show_error(&self, pos: Pos2, text: impl Into<String>) {
|
||||
let text = text.into();
|
||||
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))
|
||||
/// ## Painting
|
||||
impl Context {
|
||||
pub fn debug_painter(self: &Arc<Self>) -> Painter {
|
||||
Painter::new(self.clone(), Layer::debug(), self.rect())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -469,7 +469,7 @@ impl BoxPainting {
|
|||
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 interact = ui.interact(rect, ui.id(), Sense::drag());
|
||||
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() {
|
||||
self.lines.push(vec![]);
|
||||
|
@ -520,7 +521,7 @@ impl Painting {
|
|||
for line in &self.lines {
|
||||
if line.len() >= 2 {
|
||||
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),
|
||||
closed: false,
|
||||
outline: Some(LineStyle::new(2.0, LIGHT_GRAY)),
|
||||
|
|
|
@ -50,18 +50,18 @@ impl FractalClock {
|
|||
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)))
|
||||
.outline(None);
|
||||
|
||||
frame.show(&mut ui.left_column(320.0), |ui| {
|
||||
.outline(None)
|
||||
.show(&mut ui.left_column(320.0), |ui| {
|
||||
CollapsingHeader::new("Settings").show(ui, |ui| self.options_ui(ui));
|
||||
});
|
||||
|
||||
// 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) {
|
||||
|
@ -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 {
|
||||
length: f32,
|
||||
angle: f32,
|
||||
|
@ -126,13 +128,13 @@ impl FractalClock {
|
|||
];
|
||||
|
||||
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 = [
|
||||
rect.center() + scale * points[0].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 = [
|
||||
|
|
|
@ -30,7 +30,7 @@ impl Texture {
|
|||
};
|
||||
let mut triangles = Triangles::default();
|
||||
triangles.add_rect(top_left, bottom_right);
|
||||
ui.add_paint_cmd(PaintCmd::Triangles(triangles));
|
||||
ui.painter().add(PaintCmd::Triangles(triangles));
|
||||
|
||||
if ui.hovered(rect) {
|
||||
show_tooltip(ui.ctx(), |ui| {
|
||||
|
@ -55,7 +55,7 @@ impl Texture {
|
|||
};
|
||||
let mut triangles = Triangles::default();
|
||||
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,
|
||||
}
|
||||
|
||||
/// An ideintifer for a paint layer.
|
||||
/// An identifier for a paint layer.
|
||||
/// Also acts as an identifier for `Area`:s.
|
||||
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
||||
#[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.
|
||||
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
|
||||
#[derive(Clone, Default)]
|
||||
pub struct GraphicLayers(AHashMap<Layer, PaintList>);
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -54,12 +77,12 @@ impl GraphicLayers {
|
|||
|
||||
for layer in area_order {
|
||||
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()) {
|
||||
all_commands.extend(commands.drain(..));
|
||||
all_commands.extend(commands.0.drain(..));
|
||||
}
|
||||
|
||||
all_commands.into_iter()
|
||||
|
|
|
@ -35,6 +35,7 @@ pub mod math;
|
|||
mod memory;
|
||||
mod movement_tracker;
|
||||
pub mod paint;
|
||||
mod painter;
|
||||
mod style;
|
||||
mod types;
|
||||
mod ui;
|
||||
|
@ -52,6 +53,7 @@ pub use {
|
|||
memory::Memory,
|
||||
movement_tracker::MovementTracker,
|
||||
paint::{color, Color, PaintJobs, TextStyle, Texture},
|
||||
painter::Painter,
|
||||
style::Style,
|
||||
types::*,
|
||||
ui::Ui,
|
||||
|
|
|
@ -6,6 +6,8 @@ use {
|
|||
// TODO: rename, e.g. `paint::Cmd`?
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PaintCmd {
|
||||
/// Paint nothing. This can be useful as a placeholder.
|
||||
Noop,
|
||||
Circle {
|
||||
center: Pos2,
|
||||
fill: Option<Color>,
|
||||
|
|
|
@ -564,6 +564,7 @@ pub fn tessellate_paint_command(
|
|||
path.clear();
|
||||
|
||||
match command {
|
||||
PaintCmd::Noop => {}
|
||||
PaintCmd::Circle {
|
||||
center,
|
||||
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
|
||||
/// with a type of layout (horizontal or vertical).
|
||||
pub struct Ui {
|
||||
/// How we access input, output and memory
|
||||
ctx: Arc<Context>,
|
||||
|
||||
/// ID of this ui.
|
||||
/// Generated based on id of parent ui together with
|
||||
/// another source of child identity (e.g. window title).
|
||||
|
@ -15,12 +12,7 @@ pub struct Ui {
|
|||
/// Hopefully unique.
|
||||
id: Id,
|
||||
|
||||
/// Where to put the graphics output of this Ui
|
||||
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,
|
||||
painter: Painter,
|
||||
|
||||
/// The `rect` represents where in screen-space the ui is
|
||||
/// 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 {
|
||||
let style = ctx.style();
|
||||
let clip_rect = rect.expand(style.clip_rect_margin);
|
||||
Ui {
|
||||
ctx,
|
||||
id,
|
||||
layer,
|
||||
clip_rect: rect.expand(style.clip_rect_margin),
|
||||
painter: Painter::new(ctx, layer, clip_rect),
|
||||
desired_rect: rect,
|
||||
child_bounds: Rect::from_min_size(rect.min, Vec2::zero()), // TODO: Rect::nothing() ?
|
||||
style,
|
||||
|
@ -77,14 +68,11 @@ impl Ui {
|
|||
}
|
||||
|
||||
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?
|
||||
self.child_count += 1;
|
||||
Ui {
|
||||
ctx: self.ctx.clone(),
|
||||
id,
|
||||
layer: self.layer,
|
||||
clip_rect,
|
||||
painter: self.painter.clone(),
|
||||
desired_rect: child_rect,
|
||||
child_bounds: Rect::from_min_size(child_rect.min, Vec2::zero()), // TODO: Rect::nothing() ?
|
||||
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 {
|
||||
self.id
|
||||
}
|
||||
|
@ -122,34 +98,45 @@ impl Ui {
|
|||
}
|
||||
|
||||
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 {
|
||||
self.ctx.input()
|
||||
self.ctx().input()
|
||||
}
|
||||
|
||||
pub fn memory(&self) -> parking_lot::MutexGuard<'_, Memory> {
|
||||
self.ctx.memory()
|
||||
self.ctx().memory()
|
||||
}
|
||||
|
||||
pub fn output(&self) -> parking_lot::MutexGuard<'_, Output> {
|
||||
self.ctx.output()
|
||||
self.ctx().output()
|
||||
}
|
||||
|
||||
pub fn fonts(&self) -> &Fonts {
|
||||
self.ctx.fonts()
|
||||
self.ctx().fonts()
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// This is used, for instance, to avoid painting outside a window that is smaller than its contents.
|
||||
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) {
|
||||
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 {
|
||||
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 {
|
||||
|
@ -293,7 +281,7 @@ impl Ui {
|
|||
{
|
||||
let id = self.id.with(&id_source);
|
||||
// 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
|
||||
|
@ -309,13 +297,13 @@ impl Ui {
|
|||
self.id.with(&explicit_id_source)
|
||||
} else {
|
||||
let id = self.id.with(default_id_source);
|
||||
if self.ctx.is_unique_id(id) {
|
||||
if self.ctx().is_unique_id(id) {
|
||||
id
|
||||
} else {
|
||||
self.make_position_id()
|
||||
}
|
||||
};
|
||||
self.ctx
|
||||
self.ctx()
|
||||
.register_unique_id(id, default_id_source.unwrap_or_default(), self.cursor)
|
||||
}
|
||||
|
||||
|
@ -334,13 +322,13 @@ impl Ui {
|
|||
/// # Interaction
|
||||
impl Ui {
|
||||
pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> InteractInfo {
|
||||
self.ctx
|
||||
.interact(self.layer, self.clip_rect, rect, Some(id), sense)
|
||||
self.ctx()
|
||||
.interact(self.layer(), self.clip_rect(), rect, Some(id), sense)
|
||||
}
|
||||
|
||||
pub fn interact_hover(&self, rect: Rect) -> InteractInfo {
|
||||
self.ctx
|
||||
.interact(self.layer, self.clip_rect, rect, None, Sense::nothing())
|
||||
self.ctx()
|
||||
.interact(self.layer(), self.clip_rect(), rect, None, Sense::nothing())
|
||||
}
|
||||
|
||||
pub fn hovered(&self, rect: Rect) -> bool {
|
||||
|
@ -365,7 +353,7 @@ impl Ui {
|
|||
double_clicked,
|
||||
active,
|
||||
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.
|
||||
pub fn allocate_space(&mut self, child_size: Vec2) -> Rect {
|
||||
let child_size = self.round_vec_to_pixels(child_size);
|
||||
self.cursor = self.round_pos_to_pixels(self.cursor);
|
||||
let child_size = self.painter().round_vec_to_pixels(child_size);
|
||||
self.cursor = self.painter().round_pos_to_pixels(self.cursor);
|
||||
|
||||
// For debug rendering
|
||||
let too_wide = child_size.x > self.available().width();
|
||||
|
@ -395,7 +383,7 @@ impl Ui {
|
|||
let rect = self.reserve_space_impl(child_size);
|
||||
|
||||
if self.style().debug_widget_rects {
|
||||
self.add_paint_cmd(PaintCmd::Rect {
|
||||
self.painter.add(PaintCmd::Rect {
|
||||
rect,
|
||||
corner_radius: 0.0,
|
||||
outline: Some(LineStyle::new(1.0, LIGHT_BLUE)),
|
||||
|
@ -405,8 +393,10 @@ impl Ui {
|
|||
let color = color::srgba(200, 0, 0, 255);
|
||||
let width = 2.5;
|
||||
|
||||
let mut paint_line_seg =
|
||||
|a, b| self.add_paint_cmd(PaintCmd::line_segment([a, b], color, width));
|
||||
let paint_line_seg = |a, b| {
|
||||
self.painter
|
||||
.add(PaintCmd::line_segment([a, b], color, width))
|
||||
};
|
||||
|
||||
if too_wide {
|
||||
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
|
||||
impl Ui {
|
||||
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
|
||||
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);
|
||||
self.add_paint_cmd(PaintCmd::line_segment(
|
||||
self.painter.add(PaintCmd::line_segment(
|
||||
[line_start, line_end],
|
||||
gray(150, 255),
|
||||
self.style.line_width,
|
||||
|
|
|
@ -102,7 +102,9 @@ impl Label {
|
|||
// This should be the easiest method of putting text anywhere.
|
||||
|
||||
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 {
|
||||
let pos = interact.rect.min;
|
||||
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 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)],
|
||||
color,
|
||||
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
|
||||
}
|
||||
|
@ -279,7 +282,7 @@ impl Widget for Button {
|
|||
let interact = ui.interact(rect, id, sense);
|
||||
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);
|
||||
ui.add_paint_cmd(PaintCmd::Rect {
|
||||
ui.painter().add(PaintCmd::Rect {
|
||||
corner_radius: ui.style().interact(&interact).corner_radius,
|
||||
fill: bg_fill,
|
||||
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 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
|
||||
}
|
||||
}
|
||||
|
@ -340,7 +344,7 @@ impl<'a> Widget for Checkbox<'a> {
|
|||
*checked = !*checked;
|
||||
}
|
||||
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,
|
||||
fill: ui.style().interact(&interact).bg_fill,
|
||||
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;
|
||||
|
||||
if *checked {
|
||||
ui.add_paint_cmd(PaintCmd::Path {
|
||||
ui.painter().add(PaintCmd::Path {
|
||||
path: Path::from_open_points(&[
|
||||
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
||||
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);
|
||||
ui.add_galley(text_cursor, galley, text_style, Some(text_color));
|
||||
ui.painter()
|
||||
.add_galley(text_cursor, galley, text_style, text_color);
|
||||
interact
|
||||
}
|
||||
}
|
||||
|
@ -417,7 +422,9 @@ impl Widget for RadioButton {
|
|||
|
||||
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(),
|
||||
fill: bg_fill,
|
||||
outline: ui.style().interact(&interact).rect_outline, // TODO
|
||||
|
@ -425,7 +432,7 @@ impl Widget for RadioButton {
|
|||
});
|
||||
|
||||
if checked {
|
||||
ui.add_paint_cmd(PaintCmd::Circle {
|
||||
painter.add(PaintCmd::Circle {
|
||||
center: small_icon_rect.center(),
|
||||
fill: Some(stroke_color),
|
||||
outline: None,
|
||||
|
@ -434,7 +441,7 @@ impl Widget for RadioButton {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -520,7 +527,7 @@ impl Widget for Separator {
|
|||
)
|
||||
}
|
||||
};
|
||||
ui.add_paint_cmd(PaintCmd::LineSegment {
|
||||
ui.painter().add(PaintCmd::LineSegment {
|
||||
points,
|
||||
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_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 full_text = format!("{}: {:.*}", text, self.precision, value);
|
||||
|
||||
|
@ -116,7 +116,7 @@ impl<'a> Widget for Slider<'a> {
|
|||
if text_on_top {
|
||||
let galley = font.layout_single_line(full_text);
|
||||
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)
|
||||
} else {
|
||||
ui.columns(2, |columns| {
|
||||
|
@ -162,21 +162,21 @@ impl<'a> Widget for Slider<'a> {
|
|||
let value = self.get_value_f32();
|
||||
|
||||
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(
|
||||
pos2(interact.rect.left(), rect.center().y - rail_radius),
|
||||
pos2(interact.rect.right(), rect.center().y + rail_radius),
|
||||
);
|
||||
let marker_center_x = remap_clamp(value, range, left..=right);
|
||||
|
||||
ui.add_paint_cmd(PaintCmd::Rect {
|
||||
ui.painter().add(PaintCmd::Rect {
|
||||
rect: rail_rect,
|
||||
corner_radius: rail_radius,
|
||||
fill: Some(ui.style().background_fill),
|
||||
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),
|
||||
radius: handle_radius,
|
||||
fill: Some(ui.style().interact(&interact).fill),
|
||||
|
|
|
@ -129,9 +129,11 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
// dbg!(&galley);
|
||||
}
|
||||
|
||||
let painter = ui.painter();
|
||||
|
||||
{
|
||||
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,
|
||||
corner_radius: ui.style().interact.style(&interact).corner_radius,
|
||||
fill: Some(ui.style().dark_bg_color),
|
||||
|
@ -146,7 +148,7 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
if show_cursor {
|
||||
if let Some(cursor) = state.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)],
|
||||
color::WHITE,
|
||||
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.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);
|
||||
interact
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue