Refactor: remove GuiCmd
This commit is contained in:
parent
87288634e9
commit
192b59ebb0
6 changed files with 153 additions and 254 deletions
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
math::{clamp, remap_clamp, vec2},
|
math::{clamp, remap_clamp, vec2},
|
||||||
mesher::{Mesher, Vertex},
|
mesher::{Mesher, Vertex},
|
||||||
style::Style,
|
style::Style,
|
||||||
types::{Color, GuiCmd, GuiInput, PaintCmd},
|
types::{Color, GuiInput, PaintCmd},
|
||||||
widgets::*,
|
widgets::*,
|
||||||
FontSizes, Fonts, Mesh, RawInput, Texture,
|
FontSizes, Fonts, Mesh, RawInput, Texture,
|
||||||
};
|
};
|
||||||
|
@ -63,7 +63,7 @@ fn show_font_texture(texture: &Texture, gui: &mut Region) {
|
||||||
};
|
};
|
||||||
let mut mesh = Mesh::default();
|
let mut mesh = Mesh::default();
|
||||||
mesh.add_rect(top_left, bottom_right);
|
mesh.add_rect(top_left, bottom_right);
|
||||||
gui.add_graphic(GuiCmd::PaintCommands(vec![PaintCmd::Mesh(mesh)]));
|
gui.add_paint_cmd(PaintCmd::Mesh(mesh));
|
||||||
|
|
||||||
if let Some(mouse_pos) = gui.input().mouse_pos {
|
if let Some(mouse_pos) = gui.input().mouse_pos {
|
||||||
if interact.hovered {
|
if interact.hovered {
|
||||||
|
@ -102,7 +102,7 @@ fn show_font_texture(texture: &Texture, gui: &mut Region) {
|
||||||
};
|
};
|
||||||
let mut mesh = Mesh::default();
|
let mut mesh = Mesh::default();
|
||||||
mesh.add_rect(top_left, bottom_right);
|
mesh.add_rect(top_left, bottom_right);
|
||||||
gui.add_graphic(GuiCmd::PaintCommands(vec![PaintCmd::Mesh(mesh)]));
|
gui.add_paint_cmd(PaintCmd::Mesh(mesh));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,9 +153,7 @@ impl Emigui {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paint(&mut self) -> Mesh {
|
pub fn paint(&mut self) -> Mesh {
|
||||||
let gui_commands = self.data.graphics.lock().unwrap().drain();
|
let paint_commands: Vec<PaintCmd> = self.data.graphics.lock().unwrap().drain().collect();
|
||||||
let paint_commands = crate::style::into_paint_commands(gui_commands, &self.data.style());
|
|
||||||
|
|
||||||
let mut mesher = Mesher::new(self.last_input.pixels_per_point);
|
let mut mesher = Mesher::new(self.last_input.pixels_per_point);
|
||||||
mesher.paint(&self.data.fonts, &paint_commands);
|
mesher.paint(&self.data.fonts, &paint_commands);
|
||||||
let mesh = mesher.mesh;
|
let mesh = mesher.mesh;
|
||||||
|
|
|
@ -116,12 +116,12 @@ pub fn make_id<H: Hash>(source: &H) -> Id {
|
||||||
/// TODO: improve this
|
/// TODO: improve this
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct GraphicLayers {
|
pub struct GraphicLayers {
|
||||||
pub(crate) graphics: Vec<GuiCmd>,
|
pub(crate) graphics: Vec<PaintCmd>,
|
||||||
pub(crate) hovering_graphics: Vec<GuiCmd>,
|
pub(crate) hovering_graphics: Vec<PaintCmd>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GraphicLayers {
|
impl GraphicLayers {
|
||||||
pub fn drain(&mut self) -> impl ExactSizeIterator<Item = GuiCmd> {
|
pub fn drain(&mut self) -> impl ExactSizeIterator<Item = PaintCmd> {
|
||||||
// TODO: there must be a nicer way to do this?
|
// TODO: there must be a nicer way to do this?
|
||||||
let mut all_commands: Vec<_> = self.graphics.drain(..).collect();
|
let mut all_commands: Vec<_> = self.graphics.drain(..).collect();
|
||||||
all_commands.extend(self.hovering_graphics.drain(..));
|
all_commands.extend(self.hovering_graphics.drain(..));
|
||||||
|
@ -223,7 +223,15 @@ where
|
||||||
|
|
||||||
let mut graphics = data.graphics.lock().unwrap();
|
let mut graphics = data.graphics.lock().unwrap();
|
||||||
let popup_graphics = graphics.graphics.split_off(num_graphics_before);
|
let popup_graphics = graphics.graphics.split_off(num_graphics_before);
|
||||||
graphics.hovering_graphics.push(GuiCmd::Window { rect });
|
graphics.hovering_graphics.push(PaintCmd::Rect {
|
||||||
|
corner_radius: 5.0,
|
||||||
|
fill_color: Some(style.background_fill_color()),
|
||||||
|
outline: Some(Outline {
|
||||||
|
color: gray(255, 255), // TODO
|
||||||
|
width: 1.0,
|
||||||
|
}),
|
||||||
|
rect,
|
||||||
|
});
|
||||||
graphics.hovering_graphics.extend(popup_graphics);
|
graphics.hovering_graphics.extend(popup_graphics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,12 +269,17 @@ impl Region {
|
||||||
/// It is up to the caller to make sure there is room for this.
|
/// It is up to the caller to make sure there is room for this.
|
||||||
/// Can be used for free painting.
|
/// Can be used for free painting.
|
||||||
/// NOTE: all coordinates are screen coordinates!
|
/// NOTE: all coordinates are screen coordinates!
|
||||||
pub fn add_graphic(&mut self, gui_cmd: GuiCmd) {
|
pub fn add_paint_cmd(&mut self, paint_cmd: PaintCmd) {
|
||||||
self.data.graphics.lock().unwrap().graphics.push(gui_cmd)
|
self.data.graphics.lock().unwrap().graphics.push(paint_cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_paint_cmd(&mut self, paint_cmd: PaintCmd) {
|
pub fn add_paint_cmds(&mut self, mut cmds: Vec<PaintCmd>) {
|
||||||
self.add_graphic(GuiCmd::PaintCommands(vec![paint_cmd]))
|
self.data
|
||||||
|
.graphics
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.graphics
|
||||||
|
.append(&mut cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options for this region, and any child regions we may spawn.
|
/// Options for this region, and any child regions we may spawn.
|
||||||
|
@ -315,11 +328,11 @@ impl Region {
|
||||||
let text_style = TextStyle::Button;
|
let text_style = TextStyle::Button;
|
||||||
let font = &self.fonts()[text_style];
|
let font = &self.fonts()[text_style];
|
||||||
let (text, text_size) = font.layout_multiline(&text, self.width());
|
let (text, text_size) = font.layout_multiline(&text, self.width());
|
||||||
let text_cursor = self.cursor + self.style().button_padding;
|
let text_cursor = self.cursor + self.style.button_padding;
|
||||||
let interact = self.reserve_space(
|
let interact = self.reserve_space(
|
||||||
vec2(
|
vec2(
|
||||||
self.available_space.x,
|
self.available_space.x,
|
||||||
text_size.y + 2.0 * self.style().button_padding.y,
|
text_size.y + 2.0 * self.style.button_padding.y,
|
||||||
),
|
),
|
||||||
Some(id),
|
Some(id),
|
||||||
);
|
);
|
||||||
|
@ -336,9 +349,40 @@ impl Region {
|
||||||
memory.open_foldables.contains(&id)
|
memory.open_foldables.contains(&id)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.add_graphic(GuiCmd::FoldableHeader { interact, open });
|
let fill_color = self.style.interact_fill_color(&interact);
|
||||||
|
let stroke_color = self.style.interact_stroke_color(&interact);
|
||||||
|
|
||||||
|
self.add_paint_cmd(PaintCmd::Rect {
|
||||||
|
corner_radius: 3.0,
|
||||||
|
fill_color: Some(fill_color),
|
||||||
|
outline: None,
|
||||||
|
rect: interact.rect,
|
||||||
|
});
|
||||||
|
|
||||||
|
let (small_icon_rect, _) = self.style.icon_rectangles(&interact.rect);
|
||||||
|
// Draw a minus:
|
||||||
|
self.add_paint_cmd(PaintCmd::Line {
|
||||||
|
points: vec![
|
||||||
|
vec2(small_icon_rect.min().x, small_icon_rect.center().y),
|
||||||
|
vec2(small_icon_rect.max().x, small_icon_rect.center().y),
|
||||||
|
],
|
||||||
|
color: stroke_color,
|
||||||
|
width: self.style.line_width,
|
||||||
|
});
|
||||||
|
if !open {
|
||||||
|
// Draw it as a plus:
|
||||||
|
self.add_paint_cmd(PaintCmd::Line {
|
||||||
|
points: vec![
|
||||||
|
vec2(small_icon_rect.center().x, small_icon_rect.min().y),
|
||||||
|
vec2(small_icon_rect.center().x, small_icon_rect.max().y),
|
||||||
|
],
|
||||||
|
color: stroke_color,
|
||||||
|
width: self.style.line_width,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
self.add_text(
|
self.add_text(
|
||||||
text_cursor + vec2(self.style().start_icon_width, 0.0),
|
text_cursor + vec2(self.style.start_icon_width, 0.0),
|
||||||
text_style,
|
text_style,
|
||||||
text,
|
text,
|
||||||
None,
|
None,
|
||||||
|
@ -359,7 +403,7 @@ impl Region {
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Region),
|
F: FnOnce(&mut Region),
|
||||||
{
|
{
|
||||||
let indent = vec2(self.style().indent, 0.0);
|
let indent = vec2(self.style.indent, 0.0);
|
||||||
let mut child_region = Region {
|
let mut child_region = Region {
|
||||||
data: self.data.clone(),
|
data: self.data.clone(),
|
||||||
style: self.style,
|
style: self.style,
|
||||||
|
@ -435,7 +479,7 @@ impl Region {
|
||||||
F: FnOnce(&mut [Region]) -> R,
|
F: FnOnce(&mut [Region]) -> R,
|
||||||
{
|
{
|
||||||
// TODO: ensure there is space
|
// TODO: ensure there is space
|
||||||
let padding = self.style().item_spacing.x;
|
let padding = self.style.item_spacing.x;
|
||||||
let total_padding = padding * (num_columns as f32 - 1.0);
|
let total_padding = padding * (num_columns as f32 - 1.0);
|
||||||
let column_width = (self.available_space.x - total_padding) / (num_columns as f32);
|
let column_width = (self.available_space.x - total_padding) / (num_columns as f32);
|
||||||
|
|
||||||
|
@ -473,7 +517,7 @@ impl Region {
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
pub fn reserve_space(&mut self, size: Vec2, interaction_id: Option<Id>) -> InteractInfo {
|
pub fn reserve_space(&mut self, size: Vec2, interaction_id: Option<Id>) -> InteractInfo {
|
||||||
let pos = self.reserve_space_without_padding(size + self.style().item_spacing);
|
let pos = self.reserve_space_without_padding(size + self.style.item_spacing);
|
||||||
let rect = Rect::from_min_size(pos, size);
|
let rect = Rect::from_min_size(pos, size);
|
||||||
let mut memory = self.data.memory.lock().unwrap();
|
let mut memory = self.data.memory.lock().unwrap();
|
||||||
|
|
||||||
|
@ -580,8 +624,9 @@ impl Region {
|
||||||
text: Vec<TextFragment>,
|
text: Vec<TextFragment>,
|
||||||
color: Option<Color>,
|
color: Option<Color>,
|
||||||
) {
|
) {
|
||||||
|
let color = color.unwrap_or_else(|| self.style().text_color());
|
||||||
for fragment in text {
|
for fragment in text {
|
||||||
self.add_graphic(GuiCmd::Text {
|
self.add_paint_cmd(PaintCmd::Text {
|
||||||
color,
|
color,
|
||||||
pos: pos + vec2(0.0, fragment.y_offset),
|
pos: pos + vec2(0.0, fragment.y_offset),
|
||||||
text: fragment.text,
|
text: fragment.text,
|
||||||
|
|
|
@ -43,16 +43,16 @@ impl Default for Style {
|
||||||
|
|
||||||
impl Style {
|
impl Style {
|
||||||
/// e.g. the background of the slider
|
/// e.g. the background of the slider
|
||||||
fn background_fill_color(&self) -> Color {
|
pub fn background_fill_color(&self) -> Color {
|
||||||
gray(34, 200)
|
gray(34, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_color(&self) -> Color {
|
pub fn text_color(&self) -> Color {
|
||||||
gray(255, 200)
|
gray(255, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fill color of the interactive part of a component (button, slider grab, checkbox, ...)
|
/// Fill color of the interactive part of a component (button, slider grab, checkbox, ...)
|
||||||
fn interact_fill_color(&self, interact: &InteractInfo) -> Color {
|
pub fn interact_fill_color(&self, interact: &InteractInfo) -> Color {
|
||||||
if interact.active {
|
if interact.active {
|
||||||
srgba(100, 100, 200, 255)
|
srgba(100, 100, 200, 255)
|
||||||
} else if interact.hovered {
|
} else if interact.hovered {
|
||||||
|
@ -63,7 +63,7 @@ impl Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stroke and text color of the interactive part of a component (button, slider grab, checkbox, ...)
|
/// Stroke and text color of the interactive part of a component (button, slider grab, checkbox, ...)
|
||||||
fn interact_stroke_color(&self, interact: &InteractInfo) -> Color {
|
pub fn interact_stroke_color(&self, interact: &InteractInfo) -> Color {
|
||||||
if interact.active {
|
if interact.active {
|
||||||
gray(255, 255)
|
gray(255, 255)
|
||||||
} else if interact.hovered {
|
} else if interact.hovered {
|
||||||
|
@ -74,7 +74,7 @@ impl Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns small icon rectangle and big icon rectangle
|
/// Returns small icon rectangle and big icon rectangle
|
||||||
fn icon_rectangles(&self, rect: &Rect) -> (Rect, Rect) {
|
pub fn icon_rectangles(&self, rect: &Rect) -> (Rect, Rect) {
|
||||||
let box_side = 16.0;
|
let box_side = 16.0;
|
||||||
let big_icon_rect = Rect::from_center_size(
|
let big_icon_rect = Rect::from_center_size(
|
||||||
vec2(rect.min().x + 4.0 + box_side * 0.5, rect.center().y),
|
vec2(rect.min().x + 4.0 + box_side * 0.5, rect.center().y),
|
||||||
|
@ -86,170 +86,3 @@ impl Style {
|
||||||
(small_icon_rect, big_icon_rect)
|
(small_icon_rect, big_icon_rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
fn translate_cmd(out_commands: &mut Vec<PaintCmd>, style: &Style, cmd: GuiCmd) {
|
|
||||||
match cmd {
|
|
||||||
GuiCmd::PaintCommands(mut commands) => out_commands.append(&mut commands),
|
|
||||||
GuiCmd::Button { interact } => {
|
|
||||||
out_commands.push(PaintCmd::Rect {
|
|
||||||
corner_radius: 10.0,
|
|
||||||
fill_color: Some(style.interact_fill_color(&interact)),
|
|
||||||
outline: None,
|
|
||||||
rect: interact.rect,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
GuiCmd::Checkbox { checked, interact } => {
|
|
||||||
let (small_icon_rect, big_icon_rect) = style.icon_rectangles(&interact.rect);
|
|
||||||
out_commands.push(PaintCmd::Rect {
|
|
||||||
corner_radius: 3.0,
|
|
||||||
fill_color: Some(style.interact_fill_color(&interact)),
|
|
||||||
outline: None,
|
|
||||||
rect: big_icon_rect,
|
|
||||||
});
|
|
||||||
|
|
||||||
let stroke_color = style.interact_stroke_color(&interact);
|
|
||||||
|
|
||||||
if checked {
|
|
||||||
out_commands.push(PaintCmd::Line {
|
|
||||||
points: vec![
|
|
||||||
vec2(small_icon_rect.min().x, small_icon_rect.center().y),
|
|
||||||
vec2(small_icon_rect.center().x, small_icon_rect.max().y),
|
|
||||||
vec2(small_icon_rect.max().x, small_icon_rect.min().y),
|
|
||||||
],
|
|
||||||
color: stroke_color,
|
|
||||||
width: style.line_width,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GuiCmd::FoldableHeader { interact, open } => {
|
|
||||||
let fill_color = style.interact_fill_color(&interact);
|
|
||||||
let stroke_color = style.interact_stroke_color(&interact);
|
|
||||||
|
|
||||||
out_commands.push(PaintCmd::Rect {
|
|
||||||
corner_radius: 3.0,
|
|
||||||
fill_color: Some(fill_color),
|
|
||||||
outline: None,
|
|
||||||
rect: interact.rect,
|
|
||||||
});
|
|
||||||
|
|
||||||
let (small_icon_rect, _) = style.icon_rectangles(&interact.rect);
|
|
||||||
// Draw a minus:
|
|
||||||
out_commands.push(PaintCmd::Line {
|
|
||||||
points: vec![
|
|
||||||
vec2(small_icon_rect.min().x, small_icon_rect.center().y),
|
|
||||||
vec2(small_icon_rect.max().x, small_icon_rect.center().y),
|
|
||||||
],
|
|
||||||
color: stroke_color,
|
|
||||||
width: style.line_width,
|
|
||||||
});
|
|
||||||
if !open {
|
|
||||||
// Draw it as a plus:
|
|
||||||
out_commands.push(PaintCmd::Line {
|
|
||||||
points: vec![
|
|
||||||
vec2(small_icon_rect.center().x, small_icon_rect.min().y),
|
|
||||||
vec2(small_icon_rect.center().x, small_icon_rect.max().y),
|
|
||||||
],
|
|
||||||
color: stroke_color,
|
|
||||||
width: style.line_width,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GuiCmd::RadioButton { checked, interact } => {
|
|
||||||
let fill_color = style.interact_fill_color(&interact);
|
|
||||||
let stroke_color = style.interact_stroke_color(&interact);
|
|
||||||
|
|
||||||
let (small_icon_rect, big_icon_rect) = style.icon_rectangles(&interact.rect);
|
|
||||||
|
|
||||||
out_commands.push(PaintCmd::Circle {
|
|
||||||
center: big_icon_rect.center(),
|
|
||||||
fill_color: Some(fill_color),
|
|
||||||
outline: None,
|
|
||||||
radius: big_icon_rect.size.x / 2.0,
|
|
||||||
});
|
|
||||||
|
|
||||||
if checked {
|
|
||||||
out_commands.push(PaintCmd::Circle {
|
|
||||||
center: small_icon_rect.center(),
|
|
||||||
fill_color: Some(stroke_color),
|
|
||||||
outline: None,
|
|
||||||
radius: small_icon_rect.size.x / 2.0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GuiCmd::Slider {
|
|
||||||
interact,
|
|
||||||
max,
|
|
||||||
min,
|
|
||||||
value,
|
|
||||||
} => {
|
|
||||||
let rect = interact.rect;
|
|
||||||
let thickness = rect.size().y;
|
|
||||||
let thin_size = vec2(rect.size.x, thickness / 5.0);
|
|
||||||
let thin_rect = Rect::from_center_size(rect.center(), thin_size);
|
|
||||||
let marker_center_x = remap_clamp(value, min, max, rect.min().x, rect.max().x);
|
|
||||||
|
|
||||||
out_commands.push(PaintCmd::Rect {
|
|
||||||
corner_radius: 4.0,
|
|
||||||
fill_color: Some(style.background_fill_color()),
|
|
||||||
outline: Some(Outline {
|
|
||||||
color: gray(200, 255), // TODO
|
|
||||||
width: 1.0,
|
|
||||||
}),
|
|
||||||
rect: thin_rect,
|
|
||||||
});
|
|
||||||
|
|
||||||
out_commands.push(PaintCmd::Circle {
|
|
||||||
center: vec2(marker_center_x, thin_rect.center().y),
|
|
||||||
fill_color: Some(style.interact_fill_color(&interact)),
|
|
||||||
outline: Some(Outline {
|
|
||||||
color: style.interact_stroke_color(&interact),
|
|
||||||
width: 1.5,
|
|
||||||
}),
|
|
||||||
radius: thickness / 3.0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
GuiCmd::Text {
|
|
||||||
color,
|
|
||||||
pos,
|
|
||||||
text,
|
|
||||||
text_style,
|
|
||||||
x_offsets,
|
|
||||||
} => {
|
|
||||||
let color = color.unwrap_or_else(|| style.text_color());
|
|
||||||
out_commands.push(PaintCmd::Text {
|
|
||||||
color,
|
|
||||||
text_style,
|
|
||||||
pos,
|
|
||||||
text,
|
|
||||||
x_offsets,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
GuiCmd::Window { rect } => {
|
|
||||||
out_commands.push(PaintCmd::Rect {
|
|
||||||
corner_radius: 5.0,
|
|
||||||
fill_color: Some(style.background_fill_color()),
|
|
||||||
outline: Some(Outline {
|
|
||||||
color: gray(255, 255), // TODO
|
|
||||||
width: 1.0,
|
|
||||||
}),
|
|
||||||
rect,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_paint_commands<GuiCmdIterator>(
|
|
||||||
gui_commands: GuiCmdIterator,
|
|
||||||
style: &Style,
|
|
||||||
) -> Vec<PaintCmd>
|
|
||||||
where
|
|
||||||
GuiCmdIterator: Iterator<Item = GuiCmd>,
|
|
||||||
{
|
|
||||||
let mut paint_commands = vec![];
|
|
||||||
for gui_cmd in gui_commands {
|
|
||||||
translate_cmd(&mut paint_commands, style, gui_cmd)
|
|
||||||
}
|
|
||||||
paint_commands
|
|
||||||
}
|
|
||||||
|
|
|
@ -111,47 +111,6 @@ pub struct InteractInfo {
|
||||||
pub rect: Rect,
|
pub rect: Rect,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
|
||||||
pub enum GuiCmd {
|
|
||||||
PaintCommands(Vec<PaintCmd>),
|
|
||||||
/// The background for a button
|
|
||||||
Button {
|
|
||||||
interact: InteractInfo,
|
|
||||||
},
|
|
||||||
Checkbox {
|
|
||||||
checked: bool,
|
|
||||||
interact: InteractInfo,
|
|
||||||
},
|
|
||||||
/// The header button background for a foldable region
|
|
||||||
FoldableHeader {
|
|
||||||
interact: InteractInfo,
|
|
||||||
open: bool,
|
|
||||||
},
|
|
||||||
RadioButton {
|
|
||||||
checked: bool,
|
|
||||||
interact: InteractInfo,
|
|
||||||
},
|
|
||||||
Slider {
|
|
||||||
interact: InteractInfo,
|
|
||||||
max: f32,
|
|
||||||
min: f32,
|
|
||||||
value: f32,
|
|
||||||
},
|
|
||||||
/// A string of text with a position for each character.
|
|
||||||
Text {
|
|
||||||
color: Option<Color>,
|
|
||||||
pos: Vec2,
|
|
||||||
text: String,
|
|
||||||
text_style: TextStyle,
|
|
||||||
/// Start each character in the text, as offset from pos.
|
|
||||||
x_offsets: Vec<f32>,
|
|
||||||
},
|
|
||||||
/// Background of e.g. a popup
|
|
||||||
Window {
|
|
||||||
rect: Rect,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
fonts::TextStyle,
|
fonts::TextStyle,
|
||||||
layout::{make_id, Align, Direction, GuiResponse, Id, Region},
|
layout::{make_id, Align, Direction, GuiResponse, Id, Region},
|
||||||
math::{remap_clamp, vec2, Vec2},
|
math::{remap_clamp, vec2, Rect, Vec2},
|
||||||
types::{Color, GuiCmd, PaintCmd},
|
types::{gray, Color, Outline, PaintCmd},
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -91,7 +91,12 @@ impl Widget for Button {
|
||||||
size.y = size.y.max(region.style().clickable_diameter);
|
size.y = size.y.max(region.style().clickable_diameter);
|
||||||
let interact = region.reserve_space(size, Some(id));
|
let interact = region.reserve_space(size, Some(id));
|
||||||
let text_cursor = interact.rect.left_center() + vec2(padding.x, -0.5 * text_size.y);
|
let text_cursor = interact.rect.left_center() + vec2(padding.x, -0.5 * text_size.y);
|
||||||
region.add_graphic(GuiCmd::Button { interact });
|
region.add_paint_cmd(PaintCmd::Rect {
|
||||||
|
corner_radius: 10.0,
|
||||||
|
fill_color: Some(region.style().interact_fill_color(&interact)),
|
||||||
|
outline: None,
|
||||||
|
rect: interact.rect,
|
||||||
|
});
|
||||||
region.add_text(text_cursor, text_style, text, self.text_color);
|
region.add_text(text_cursor, text_style, text, self.text_color);
|
||||||
region.response(interact)
|
region.response(interact)
|
||||||
}
|
}
|
||||||
|
@ -140,10 +145,28 @@ impl<'a> Widget for Checkbox<'a> {
|
||||||
if interact.clicked {
|
if interact.clicked {
|
||||||
*self.checked = !*self.checked;
|
*self.checked = !*self.checked;
|
||||||
}
|
}
|
||||||
region.add_graphic(GuiCmd::Checkbox {
|
let (small_icon_rect, big_icon_rect) = region.style().icon_rectangles(&interact.rect);
|
||||||
checked: *self.checked,
|
region.add_paint_cmd(PaintCmd::Rect {
|
||||||
interact,
|
corner_radius: 3.0,
|
||||||
|
fill_color: Some(region.style().interact_fill_color(&interact)),
|
||||||
|
outline: None,
|
||||||
|
rect: big_icon_rect,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let stroke_color = region.style().interact_stroke_color(&interact);
|
||||||
|
|
||||||
|
if *self.checked {
|
||||||
|
region.add_paint_cmd(PaintCmd::Line {
|
||||||
|
points: vec![
|
||||||
|
vec2(small_icon_rect.min().x, small_icon_rect.center().y),
|
||||||
|
vec2(small_icon_rect.center().x, small_icon_rect.max().y),
|
||||||
|
vec2(small_icon_rect.max().x, small_icon_rect.min().y),
|
||||||
|
],
|
||||||
|
color: stroke_color,
|
||||||
|
width: region.style().line_width,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
region.add_text(text_cursor, text_style, text, self.text_color);
|
region.add_text(text_cursor, text_style, text, self.text_color);
|
||||||
region.response(interact)
|
region.response(interact)
|
||||||
}
|
}
|
||||||
|
@ -193,10 +216,28 @@ impl Widget for RadioButton {
|
||||||
let text_cursor = interact.rect.min()
|
let text_cursor = interact.rect.min()
|
||||||
+ region.style().button_padding
|
+ region.style().button_padding
|
||||||
+ vec2(region.style().start_icon_width, 0.0);
|
+ vec2(region.style().start_icon_width, 0.0);
|
||||||
region.add_graphic(GuiCmd::RadioButton {
|
|
||||||
checked: self.checked,
|
let fill_color = region.style().interact_fill_color(&interact);
|
||||||
interact,
|
let stroke_color = region.style().interact_stroke_color(&interact);
|
||||||
|
|
||||||
|
let (small_icon_rect, big_icon_rect) = region.style().icon_rectangles(&interact.rect);
|
||||||
|
|
||||||
|
region.add_paint_cmd(PaintCmd::Circle {
|
||||||
|
center: big_icon_rect.center(),
|
||||||
|
fill_color: Some(fill_color),
|
||||||
|
outline: None,
|
||||||
|
radius: big_icon_rect.size.x / 2.0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if self.checked {
|
||||||
|
region.add_paint_cmd(PaintCmd::Circle {
|
||||||
|
center: small_icon_rect.center(),
|
||||||
|
fill_color: Some(stroke_color),
|
||||||
|
outline: None,
|
||||||
|
radius: small_icon_rect.size.x / 2.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
region.add_text(text_cursor, text_style, text, self.text_color);
|
region.add_text(text_cursor, text_style, text, self.text_color);
|
||||||
region.response(interact)
|
region.response(interact)
|
||||||
}
|
}
|
||||||
|
@ -349,12 +390,36 @@ impl<'a> Widget for Slider<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
region.add_graphic(GuiCmd::Slider {
|
// Paint it:
|
||||||
interact,
|
{
|
||||||
max,
|
let value = (self.get_set_value)(None);
|
||||||
min,
|
|
||||||
value: (self.get_set_value)(None),
|
let rect = interact.rect;
|
||||||
});
|
let thickness = rect.size().y;
|
||||||
|
let thin_size = vec2(rect.size.x, thickness / 5.0);
|
||||||
|
let thin_rect = Rect::from_center_size(rect.center(), thin_size);
|
||||||
|
let marker_center_x = remap_clamp(value, min, max, rect.min().x, rect.max().x);
|
||||||
|
|
||||||
|
region.add_paint_cmd(PaintCmd::Rect {
|
||||||
|
corner_radius: 4.0,
|
||||||
|
fill_color: Some(region.style().background_fill_color()),
|
||||||
|
outline: Some(Outline {
|
||||||
|
color: gray(200, 255), // TODO
|
||||||
|
width: 1.0,
|
||||||
|
}),
|
||||||
|
rect: thin_rect,
|
||||||
|
});
|
||||||
|
|
||||||
|
region.add_paint_cmd(PaintCmd::Circle {
|
||||||
|
center: vec2(marker_center_x, thin_rect.center().y),
|
||||||
|
fill_color: Some(region.style().interact_fill_color(&interact)),
|
||||||
|
outline: Some(Outline {
|
||||||
|
color: region.style().interact_stroke_color(&interact),
|
||||||
|
width: 1.5,
|
||||||
|
}),
|
||||||
|
radius: thickness / 3.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
region.response(interact)
|
region.response(interact)
|
||||||
}
|
}
|
||||||
|
@ -412,12 +477,11 @@ impl Widget for Separator {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let paint_cmd = PaintCmd::Line {
|
region.add_paint_cmd(PaintCmd::Line {
|
||||||
points,
|
points,
|
||||||
color: Color::WHITE,
|
color: Color::WHITE,
|
||||||
width: self.line_width,
|
width: self.line_width,
|
||||||
};
|
});
|
||||||
region.add_graphic(GuiCmd::PaintCommands(vec![paint_cmd]));
|
|
||||||
region.response(interact)
|
region.response(interact)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,7 @@ impl App {
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
gui.add_graphic(GuiCmd::PaintCommands(cmds));
|
gui.add_paint_cmds(cmds);
|
||||||
});
|
});
|
||||||
|
|
||||||
gui.foldable("Slider example", |gui| {
|
gui.foldable("Slider example", |gui| {
|
||||||
|
|
Loading…
Reference in a new issue