[refactor] break up Style into Spacing, Interaction and Visuals
Also make sliders fixed-width
This commit is contained in:
parent
fe50f39590
commit
413ed6999e
15 changed files with 464 additions and 271 deletions
|
@ -182,15 +182,15 @@ impl CollapsingHeader {
|
|||
let id = ui.make_unique_child_id_full(id_source, Some(title));
|
||||
|
||||
let available = ui.available_finite();
|
||||
let text_pos = available.min + vec2(ui.style().indent, 0.0);
|
||||
let galley = label.layout_width(ui, available.width() - ui.style().indent);
|
||||
let text_pos = available.min + vec2(ui.style().spacing.indent, 0.0);
|
||||
let galley = label.layout_width(ui, available.width() - ui.style().spacing.indent);
|
||||
let text_max_x = text_pos.x + galley.size.x;
|
||||
let desired_width = text_max_x - available.left();
|
||||
let desired_width = desired_width.max(available.width());
|
||||
|
||||
let size = vec2(
|
||||
desired_width,
|
||||
galley.size.y + 2.0 * ui.style().button_padding.y,
|
||||
galley.size.y + 2.0 * ui.style().spacing.button_padding.y,
|
||||
);
|
||||
|
||||
let rect = ui.allocate_space(size);
|
||||
|
@ -205,9 +205,9 @@ impl CollapsingHeader {
|
|||
let bg_index = ui.painter().add(PaintCmd::Noop);
|
||||
|
||||
{
|
||||
let (mut icon_rect, _) = ui.style().icon_rectangles(response.rect);
|
||||
let (mut icon_rect, _) = ui.style().spacing.icon_rectangles(response.rect);
|
||||
icon_rect.set_center(pos2(
|
||||
response.rect.left() + ui.style().indent / 2.0,
|
||||
response.rect.left() + ui.style().spacing.indent / 2.0,
|
||||
response.rect.center().y,
|
||||
));
|
||||
let icon_response = Response {
|
||||
|
|
|
@ -15,10 +15,10 @@ pub struct Frame {
|
|||
impl Frame {
|
||||
pub fn window(style: &Style) -> Self {
|
||||
Self {
|
||||
margin: style.window_padding,
|
||||
corner_radius: style.window.corner_radius,
|
||||
fill: Some(style.background_fill),
|
||||
outline: style.interact.inactive.bg_outline, // because we can resize windows
|
||||
margin: style.spacing.window_padding,
|
||||
corner_radius: style.visuals.window_corner_radius,
|
||||
fill: Some(style.visuals.background_fill),
|
||||
outline: style.visuals.interacted.inactive.bg_outline, // because we can resize windows
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,16 +35,16 @@ impl Frame {
|
|||
Self {
|
||||
margin: Vec2::splat(1.0),
|
||||
corner_radius: 2.0,
|
||||
fill: Some(style.background_fill),
|
||||
fill: Some(style.visuals.background_fill),
|
||||
outline: Some(LineStyle::new(1.0, Srgba::gray(128))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn popup(style: &Style) -> Self {
|
||||
Self {
|
||||
margin: style.window_padding,
|
||||
margin: style.spacing.window_padding,
|
||||
corner_radius: 5.0,
|
||||
fill: Some(style.background_fill),
|
||||
fill: Some(style.visuals.background_fill),
|
||||
outline: Some(LineStyle::new(1.0, Srgba::gray(128))),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ impl Resize {
|
|||
|
||||
let corner_response = if self.resizable {
|
||||
// Resize-corner:
|
||||
let corner_size = Vec2::splat(ui.style().resize_corner_size);
|
||||
let corner_size = Vec2::splat(ui.style().visuals.resize_corner_size);
|
||||
let corner_rect =
|
||||
Rect::from_min_size(position + state.desired_size - corner_size, corner_size);
|
||||
let corner_response = ui.interact(corner_rect, id.with("corner"), Sense::drag());
|
||||
|
@ -169,7 +169,7 @@ impl Resize {
|
|||
|
||||
let inner_rect = Rect::from_min_size(position, state.desired_size);
|
||||
|
||||
let mut content_clip_rect = inner_rect.expand(ui.style().clip_rect_margin);
|
||||
let mut content_clip_rect = inner_rect.expand(ui.style().visuals.clip_rect_margin);
|
||||
|
||||
// If we pull the resize handle to shrink, we want to TRY to shrink it.
|
||||
// After laying out the contents, we might be much bigger.
|
||||
|
@ -177,7 +177,9 @@ impl Resize {
|
|||
// then we will clip the contents of the region even thought the result gets larger. This is simply ugly!
|
||||
// So we use the memory of last_content_size to make the clip rect large enough.
|
||||
content_clip_rect.max = content_clip_rect.max.max(
|
||||
inner_rect.min + state.last_content_size + Vec2::splat(ui.style().clip_rect_margin),
|
||||
inner_rect.min
|
||||
+ state.last_content_size
|
||||
+ Vec2::splat(ui.style().visuals.clip_rect_margin),
|
||||
);
|
||||
|
||||
content_clip_rect = content_clip_rect.intersect(ui.clip_rect()); // Respect parent region
|
||||
|
@ -236,7 +238,7 @@ impl Resize {
|
|||
rect,
|
||||
corner_radius: 3.0,
|
||||
fill: None,
|
||||
outline: Some(ui.style().thin_outline),
|
||||
outline: Some(ui.style().visuals.thin_outline),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -250,7 +252,7 @@ impl Resize {
|
|||
|
||||
ui.memory().resize.insert(id, state);
|
||||
|
||||
if ui.ctx().style().debug_resize {
|
||||
if ui.ctx().style().visuals.debug_resize {
|
||||
ui.ctx().debug_painter().debug_rect(
|
||||
Rect::from_min_size(content_ui.top_left(), state.desired_size),
|
||||
color::GREEN,
|
||||
|
|
|
@ -99,7 +99,7 @@ impl ScrollArea {
|
|||
inner_rect.min - state.offset,
|
||||
vec2(inner_size.x, f32::INFINITY),
|
||||
));
|
||||
let mut content_clip_rect = inner_rect.expand(ui.style().clip_rect_margin);
|
||||
let mut content_clip_rect = inner_rect.expand(ui.style().visuals.clip_rect_margin);
|
||||
content_clip_rect = content_clip_rect.intersect(ui.clip_rect());
|
||||
content_clip_rect.max.x = ui.clip_rect().max.x - current_scroll_bar_width; // Nice handling of forced resizing beyond the possible
|
||||
content_ui.set_clip_rect(content_clip_rect);
|
||||
|
@ -175,7 +175,7 @@ impl Prepared {
|
|||
if current_scroll_bar_width > 0.0 {
|
||||
let animation_t = current_scroll_bar_width / max_scroll_bar_width;
|
||||
// margin between contents and scroll bar
|
||||
let margin = animation_t * ui.style().item_spacing.x;
|
||||
let margin = animation_t * ui.style().spacing.item_spacing.x;
|
||||
let left = inner_rect.right() + margin;
|
||||
let right = outer_rect.right();
|
||||
let corner_radius = (right - left) / 2.0;
|
||||
|
@ -243,7 +243,7 @@ impl Prepared {
|
|||
ui.painter().add(paint::PaintCmd::Rect {
|
||||
rect: outer_scroll_rect,
|
||||
corner_radius,
|
||||
fill: Some(ui.style().dark_bg_color),
|
||||
fill: Some(ui.style().visuals.dark_bg_color),
|
||||
outline: None,
|
||||
});
|
||||
|
||||
|
@ -274,5 +274,5 @@ impl Prepared {
|
|||
}
|
||||
|
||||
fn max_scroll_bar_width_with_margin(ui: &Ui) -> f32 {
|
||||
ui.style().item_spacing.x + 16.0
|
||||
ui.style().spacing.item_spacing.x + 16.0
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ impl<'open> Window<'open> {
|
|||
let last_frame_outer_rect = area.state().rect();
|
||||
let interaction = if possible.movable || possible.resizable {
|
||||
let title_bar_height =
|
||||
title_label.font_height(ctx.fonts()) + 1.0 * ctx.style().item_spacing.y; // this could be better
|
||||
title_label.font_height(ctx.fonts()) + 1.0 * ctx.style().spacing.item_spacing.y; // this could be better
|
||||
let margins = 2.0 * frame.margin + vec2(0.0, title_bar_height);
|
||||
|
||||
window_interaction(
|
||||
|
@ -255,7 +255,7 @@ impl<'open> Window<'open> {
|
|||
.add_contents(&mut frame.content_ui, collapsing_id, |ui| {
|
||||
resize.show(ui, |ui| {
|
||||
// Add some spacing between title and content:
|
||||
ui.allocate_space(ui.style().item_spacing);
|
||||
ui.allocate_space(ui.style().spacing.item_spacing);
|
||||
|
||||
if let Some(scroll) = scroll {
|
||||
scroll.show(ui, add_contents)
|
||||
|
@ -294,14 +294,14 @@ impl<'open> Window<'open> {
|
|||
&mut area_content_ui,
|
||||
outer_rect,
|
||||
interaction,
|
||||
ctx.style().interact.active,
|
||||
ctx.style().visuals.interacted.active,
|
||||
);
|
||||
} else if let Some(hover_interaction) = hover_interaction {
|
||||
paint_frame_interaction(
|
||||
&mut area_content_ui,
|
||||
outer_rect,
|
||||
hover_interaction,
|
||||
ctx.style().interact.hovered,
|
||||
ctx.style().visuals.interacted.hovered,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -312,7 +312,7 @@ impl<'open> Window<'open> {
|
|||
}
|
||||
|
||||
fn paint_resize_corner(ui: &mut Ui, outer_rect: Rect, frame_outline: Option<LineStyle>) {
|
||||
let corner_size = Vec2::splat(ui.style().resize_corner_size);
|
||||
let corner_size = Vec2::splat(ui.style().visuals.resize_corner_size);
|
||||
let handle_offset = -Vec2::splat(2.0);
|
||||
let corner_rect =
|
||||
Rect::from_min_size(outer_rect.max - corner_size + handle_offset, corner_size);
|
||||
|
@ -468,32 +468,32 @@ fn resize_hover(
|
|||
return None;
|
||||
}
|
||||
|
||||
let side_interact_radius = ctx.style().resize_interact_radius_side;
|
||||
let corner_interact_radius = ctx.style().resize_interact_radius_corner;
|
||||
if rect.expand(side_interact_radius).contains(mouse_pos) {
|
||||
let side_grab_radius = ctx.style().interaction.resize_grab_radius_side;
|
||||
let corner_grab_radius = ctx.style().interaction.resize_grab_radius_corner;
|
||||
if rect.expand(side_grab_radius).contains(mouse_pos) {
|
||||
let (mut left, mut right, mut top, mut bottom) = Default::default();
|
||||
if possible.resizable {
|
||||
right = (rect.right() - mouse_pos.x).abs() <= side_interact_radius;
|
||||
bottom = (rect.bottom() - mouse_pos.y).abs() <= side_interact_radius;
|
||||
right = (rect.right() - mouse_pos.x).abs() <= side_grab_radius;
|
||||
bottom = (rect.bottom() - mouse_pos.y).abs() <= side_grab_radius;
|
||||
|
||||
if rect.right_bottom().distance(mouse_pos) < corner_interact_radius {
|
||||
if rect.right_bottom().distance(mouse_pos) < corner_grab_radius {
|
||||
right = true;
|
||||
bottom = true;
|
||||
}
|
||||
|
||||
if possible.movable {
|
||||
left = (rect.left() - mouse_pos.x).abs() <= side_interact_radius;
|
||||
top = (rect.top() - mouse_pos.y).abs() <= side_interact_radius;
|
||||
left = (rect.left() - mouse_pos.x).abs() <= side_grab_radius;
|
||||
top = (rect.top() - mouse_pos.y).abs() <= side_grab_radius;
|
||||
|
||||
if rect.right_top().distance(mouse_pos) < corner_interact_radius {
|
||||
if rect.right_top().distance(mouse_pos) < corner_grab_radius {
|
||||
right = true;
|
||||
top = true;
|
||||
}
|
||||
if rect.left_top().distance(mouse_pos) < corner_interact_radius {
|
||||
if rect.left_top().distance(mouse_pos) < corner_grab_radius {
|
||||
left = true;
|
||||
top = true;
|
||||
}
|
||||
if rect.left_bottom().distance(mouse_pos) < corner_interact_radius {
|
||||
if rect.left_bottom().distance(mouse_pos) < corner_grab_radius {
|
||||
left = true;
|
||||
bottom = true;
|
||||
}
|
||||
|
@ -530,9 +530,9 @@ fn paint_frame_interaction(
|
|||
ui: &mut Ui,
|
||||
rect: Rect,
|
||||
interaction: WindowInteraction,
|
||||
style: style::WidgetStyle,
|
||||
visuals: style::WidgetVisuals,
|
||||
) {
|
||||
let cr = ui.style().window.corner_radius;
|
||||
let cr = ui.style().visuals.window_corner_radius;
|
||||
let Rect { min, max } = rect;
|
||||
|
||||
let mut path = Path::default();
|
||||
|
@ -567,7 +567,7 @@ fn paint_frame_interaction(
|
|||
path,
|
||||
closed: false,
|
||||
fill: None,
|
||||
outline: style.bg_outline,
|
||||
outline: visuals.bg_outline,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -591,8 +591,8 @@ fn show_title_bar(
|
|||
let title_bar_and_rect = ui.horizontal_centered(|ui| {
|
||||
ui.set_desired_height(title_label.font_height(ui.fonts()));
|
||||
|
||||
let item_spacing = ui.style().item_spacing;
|
||||
let button_size = ui.style().start_icon_width;
|
||||
let item_spacing = ui.style().spacing.item_spacing;
|
||||
let button_size = ui.style().spacing.icon_width;
|
||||
|
||||
if collapsible {
|
||||
// TODO: make clickable radius larger
|
||||
|
@ -668,10 +668,10 @@ impl TitleBar {
|
|||
// paint separator between title and content:
|
||||
let left = outer_rect.left();
|
||||
let right = outer_rect.right();
|
||||
let y = content_rect.top() + ui.style().item_spacing.y * 0.5;
|
||||
let y = content_rect.top() + ui.style().spacing.item_spacing.y * 0.5;
|
||||
ui.painter().line_segment(
|
||||
[pos2(left, y), pos2(right, y)],
|
||||
ui.style().interact.inactive.bg_outline.unwrap(),
|
||||
ui.style().visuals.interacted.inactive.bg_outline.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -686,10 +686,10 @@ impl TitleBar {
|
|||
}
|
||||
|
||||
fn close_button_ui(&self, ui: &mut Ui) -> Response {
|
||||
let button_size = ui.style().start_icon_width;
|
||||
let button_size = ui.style().spacing.icon_width;
|
||||
let button_rect = Rect::from_min_size(
|
||||
pos2(
|
||||
self.rect.right() - ui.style().item_spacing.x - button_size,
|
||||
self.rect.right() - ui.style().spacing.item_spacing.x - button_size,
|
||||
self.rect.center().y - 0.5 * button_size,
|
||||
),
|
||||
Vec2::splat(button_size),
|
||||
|
|
|
@ -337,8 +337,8 @@ impl Context {
|
|||
// ---------------------------------------------------------------------
|
||||
|
||||
pub fn layer_at(&self, pos: Pos2) -> Option<Layer> {
|
||||
let resize_interact_radius_side = self.style().resize_interact_radius_side;
|
||||
self.memory().layer_at(pos, resize_interact_radius_side)
|
||||
let resize_grab_radius_side = self.style().interaction.resize_grab_radius_side;
|
||||
self.memory().layer_at(pos, resize_grab_radius_side)
|
||||
}
|
||||
|
||||
pub fn contains_mouse(&self, layer: Layer, clip_rect: Rect, rect: Rect) -> bool {
|
||||
|
@ -359,7 +359,7 @@ impl Context {
|
|||
interaction_id: Option<Id>,
|
||||
sense: Sense,
|
||||
) -> Response {
|
||||
let interact_rect = rect.expand2(0.5 * self.style().item_spacing); // make it easier to click. TODO: nice way to do this
|
||||
let interact_rect = rect.expand2(0.5 * self.style().spacing.item_spacing); // make it easier to click. TODO: nice way to do this
|
||||
let hovered = self.contains_mouse(layer, clip_rect, interact_rect);
|
||||
let has_kb_focus = interaction_id
|
||||
.map(|id| self.memory().has_kb_focus(id))
|
||||
|
|
|
@ -473,7 +473,7 @@ impl Default for Widgets {
|
|||
impl Widgets {
|
||||
pub fn ui(&mut self, ui: &mut Ui) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.style_mut().item_spacing.x = 0.0;
|
||||
ui.style_mut().spacing.item_spacing.x = 0.0;
|
||||
ui.add(label!("Text can have ").text_color(srgba(110, 255, 110, 255)));
|
||||
ui.add(label!("color ").text_color(srgba(128, 140, 255, 255)));
|
||||
ui.add(label!("and tooltips")).tooltip_text(
|
||||
|
@ -520,7 +520,7 @@ impl Widgets {
|
|||
{
|
||||
ui.label("An angle stored as radians, but edited in degrees:");
|
||||
ui.horizontal_centered(|ui| {
|
||||
ui.style_mut().item_spacing.x = 0.0;
|
||||
ui.style_mut().spacing.item_spacing.x = 0.0;
|
||||
ui.drag_angle(&mut self.angle);
|
||||
ui.label(format!(" = {} radians", self.angle));
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{paint::PaintCmd, *};
|
|||
// iOS style toggle switch
|
||||
pub fn toggle(ui: &mut Ui, on: &mut bool) -> Response {
|
||||
// First we must reserve some space to use:
|
||||
let desired_size = vec2(2.0, 1.0) * ui.style().clickable_diameter;
|
||||
let desired_size = vec2(2.0, 1.0) * ui.style().spacing.clickable_diameter;
|
||||
let rect = ui.allocate_space(desired_size);
|
||||
|
||||
// Now that we have an area, we want to check for clicks.
|
||||
|
|
|
@ -184,7 +184,7 @@ impl Layout {
|
|||
}
|
||||
|
||||
cursor_change.x += child_size.x;
|
||||
cursor_change.x += style.item_spacing.x; // Where to put next thing, if there is a next thing
|
||||
cursor_change.x += style.spacing.item_spacing.x; // Where to put next thing, if there is a next thing
|
||||
} else {
|
||||
if let Some(align) = self.align {
|
||||
child_move.x += match align {
|
||||
|
@ -197,7 +197,7 @@ impl Layout {
|
|||
child_size.x = child_size.x.max(available_size.x);
|
||||
};
|
||||
cursor_change.y += child_size.y;
|
||||
cursor_change.y += style.item_spacing.y; // Where to put next thing, if there is a next thing
|
||||
cursor_change.y += style.spacing.item_spacing.y; // Where to put next thing, if there is a next thing
|
||||
}
|
||||
|
||||
if self.is_reversed() {
|
||||
|
|
|
@ -61,17 +61,17 @@ pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect)
|
|||
ui.horizontal_centered(|ui| {
|
||||
Frame::menu_bar(ui.style()).show(ui, |ui| {
|
||||
let mut style = ui.style().clone();
|
||||
style.button_padding = vec2(2.0, 0.0);
|
||||
// style.interact.active.bg_fill = None;
|
||||
style.interact.active.bg_outline = None;
|
||||
// style.interact.hovered.bg_fill = None;
|
||||
style.interact.hovered.bg_outline = None;
|
||||
style.interact.inactive.bg_fill = None;
|
||||
style.interact.inactive.bg_outline = None;
|
||||
style.spacing.button_padding = vec2(2.0, 0.0);
|
||||
// style.visuals.interacted.active.bg_fill = None;
|
||||
style.visuals.interacted.active.bg_outline = None;
|
||||
// style.visuals.interacted.hovered.bg_fill = None;
|
||||
style.visuals.interacted.hovered.bg_outline = None;
|
||||
style.visuals.interacted.inactive.bg_fill = None;
|
||||
style.visuals.interacted.inactive.bg_outline = None;
|
||||
ui.set_style(style);
|
||||
|
||||
// Take full width and fixed height:
|
||||
let height = ui.style().menu_bar.height;
|
||||
let height = ui.style().spacing.menu_bar_height;
|
||||
ui.set_desired_height(height);
|
||||
ui.expand_to_size(vec2(ui.available().width(), height));
|
||||
|
||||
|
@ -108,7 +108,7 @@ fn menu_impl<'c>(
|
|||
let mut button = Button::new(title);
|
||||
|
||||
if bar_state.open_menu == Some(menu_id) {
|
||||
button = button.fill(Some(ui.style().interact.active.main_fill));
|
||||
button = button.fill(Some(ui.style().visuals.interacted.active.main_fill));
|
||||
}
|
||||
|
||||
let button_response = ui.add(button);
|
||||
|
@ -127,13 +127,13 @@ fn menu_impl<'c>(
|
|||
frame.show(ui, |ui| {
|
||||
resize.show(ui, |ui| {
|
||||
let mut style = ui.style().clone();
|
||||
style.button_padding = vec2(2.0, 0.0);
|
||||
// style.interact.active.bg_fill = None;
|
||||
style.interact.active.bg_outline = None;
|
||||
// style.interact.hovered.bg_fill = None;
|
||||
style.interact.hovered.bg_outline = None;
|
||||
style.interact.inactive.bg_fill = None;
|
||||
style.interact.inactive.bg_outline = None;
|
||||
style.spacing.button_padding = vec2(2.0, 0.0);
|
||||
// style.visuals.interacted.active.bg_fill = None;
|
||||
style.visuals.interacted.active.bg_outline = None;
|
||||
// style.visuals.interacted.hovered.bg_fill = None;
|
||||
style.visuals.interacted.hovered.bg_outline = None;
|
||||
style.visuals.interacted.inactive.bg_fill = None;
|
||||
style.visuals.interacted.inactive.bg_outline = None;
|
||||
ui.set_style(style);
|
||||
ui.set_layout(Layout::justified(Direction::Vertical));
|
||||
add_contents(ui)
|
||||
|
|
|
@ -2,43 +2,86 @@
|
|||
|
||||
use crate::{color::*, math::*, paint::LineStyle, types::*};
|
||||
|
||||
// TODO: split into Spacing and Style?
|
||||
/// Specifies the look and feel of a `Ui`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Style {
|
||||
pub spacing: Spacing,
|
||||
pub interaction: Interaction,
|
||||
pub visuals: Visuals,
|
||||
|
||||
/// How many seconds a typical animation should last
|
||||
pub animation_time: f32,
|
||||
}
|
||||
|
||||
impl Style {
|
||||
// TODO: rename style.interact() to maybe... `style.response_visuals` ?
|
||||
/// Use this style for interactive things
|
||||
pub fn interact(&self, response: &Response) -> &WidgetVisuals {
|
||||
self.visuals.interacted.style(response)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Spacing {
|
||||
/// Horizontal and vertical spacing between widgets
|
||||
pub item_spacing: Vec2,
|
||||
|
||||
/// Horizontal and vertical padding within a window frame.
|
||||
pub window_padding: Vec2,
|
||||
|
||||
/// Button size is text size plus this on each side
|
||||
pub button_padding: Vec2,
|
||||
|
||||
/// Horizontal and vertical spacing between widgets
|
||||
pub item_spacing: Vec2,
|
||||
|
||||
/// Indent collapsing regions etc by this much.
|
||||
pub indent: f32,
|
||||
|
||||
/// Anything clickable is (at least) this wide.
|
||||
pub clickable_diameter: f32,
|
||||
|
||||
/// Total width of a slider
|
||||
pub slider_width: f32,
|
||||
|
||||
/// Checkboxes, radio button and collapsing headers have an icon at the start.
|
||||
/// The text starts after this many pixels.
|
||||
pub start_icon_width: f32,
|
||||
pub icon_width: f32,
|
||||
|
||||
pub menu_bar_height: f32,
|
||||
}
|
||||
|
||||
impl Spacing {
|
||||
/// Returns small icon rectangle and big icon rectangle
|
||||
pub fn icon_rectangles(&self, rect: Rect) -> (Rect, Rect) {
|
||||
let box_side = self.icon_width;
|
||||
let big_icon_rect = Rect::from_center_size(
|
||||
pos2(rect.left() + box_side / 2.0, rect.center().y),
|
||||
vec2(box_side, box_side),
|
||||
);
|
||||
|
||||
let small_rect_side = 8.0; // TODO: make a parameter
|
||||
let small_icon_rect =
|
||||
Rect::from_center_size(big_icon_rect.center(), Vec2::splat(small_rect_side));
|
||||
|
||||
(small_icon_rect, big_icon_rect)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Interaction {
|
||||
/// Mouse must be the close to the side of a window to resize
|
||||
pub resize_interact_radius_side: f32,
|
||||
pub resize_grab_radius_side: f32,
|
||||
|
||||
/// Mouse must be the close to the corner of a window to resize
|
||||
pub resize_interact_radius_corner: f32,
|
||||
pub resize_grab_radius_corner: f32,
|
||||
}
|
||||
|
||||
pub resize_corner_size: f32,
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Visuals {
|
||||
pub interacted: Interacted,
|
||||
|
||||
// -----------------------------------------------
|
||||
// Purely visual:
|
||||
pub interact: Interact,
|
||||
|
||||
// TODO: an WidgetStyle ?
|
||||
pub text_color: Srgba,
|
||||
|
||||
/// For stuff like check marks in check boxes.
|
||||
|
@ -52,18 +95,14 @@ pub struct Style {
|
|||
/// e.g. the background of the slider or text edit
|
||||
pub dark_bg_color: Srgba,
|
||||
|
||||
pub window_corner_radius: f32,
|
||||
|
||||
pub resize_corner_size: f32,
|
||||
|
||||
/// Blink text cursor by this frequency. If None, always show the cursor.
|
||||
pub cursor_blink_hz: Option<f32>,
|
||||
pub text_cursor_width: f32,
|
||||
|
||||
// TODO: add ability to disable animations!
|
||||
/// How many seconds a typical animation should last
|
||||
pub animation_time: f32,
|
||||
|
||||
pub window: Window,
|
||||
|
||||
pub menu_bar: MenuBar,
|
||||
|
||||
/// Allow child widgets to be just on the border and still have an outline with some thickness
|
||||
pub clip_rect_margin: f32,
|
||||
|
||||
|
@ -73,86 +112,17 @@ pub struct Style {
|
|||
pub debug_resize: bool,
|
||||
}
|
||||
|
||||
impl Default for Style {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
window_padding: vec2(6.0, 6.0),
|
||||
button_padding: vec2(4.0, 1.0),
|
||||
item_spacing: vec2(8.0, 4.0),
|
||||
indent: 21.0,
|
||||
clickable_diameter: 22.0,
|
||||
start_icon_width: 14.0,
|
||||
resize_interact_radius_side: 5.0,
|
||||
resize_interact_radius_corner: 10.0,
|
||||
resize_corner_size: 16.0,
|
||||
interact: Default::default(),
|
||||
text_color: Srgba::gray(160),
|
||||
line_width: 1.0,
|
||||
thin_outline: LineStyle::new(0.5, GRAY),
|
||||
background_fill: Rgba::luminance_alpha(0.013, 0.95).into(),
|
||||
dark_bg_color: Srgba::black_alpha(140),
|
||||
cursor_blink_hz: None, // Some(1.0)
|
||||
text_cursor_width: 2.0,
|
||||
animation_time: 1.0 / 15.0,
|
||||
window: Window::default(),
|
||||
menu_bar: MenuBar::default(),
|
||||
clip_rect_margin: 3.0,
|
||||
debug_widget_rects: false,
|
||||
debug_resize: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Interact {
|
||||
pub active: WidgetStyle,
|
||||
pub hovered: WidgetStyle,
|
||||
pub inactive: WidgetStyle,
|
||||
pub disabled: WidgetStyle,
|
||||
pub struct Interacted {
|
||||
pub active: WidgetVisuals,
|
||||
pub hovered: WidgetVisuals,
|
||||
pub inactive: WidgetVisuals,
|
||||
pub disabled: WidgetVisuals,
|
||||
}
|
||||
|
||||
impl Default for Interact {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
active: WidgetStyle {
|
||||
bg_fill: Some(Srgba::black_alpha(128)),
|
||||
bg_outline: Some(LineStyle::new(2.0, WHITE)),
|
||||
corner_radius: 0.0,
|
||||
main_fill: srgba(120, 120, 200, 255),
|
||||
stroke_color: WHITE,
|
||||
stroke_width: 2.0,
|
||||
},
|
||||
hovered: WidgetStyle {
|
||||
bg_fill: None,
|
||||
bg_outline: Some(LineStyle::new(1.0, WHITE)),
|
||||
corner_radius: 2.0,
|
||||
main_fill: srgba(100, 100, 150, 255),
|
||||
stroke_color: Srgba::gray(240),
|
||||
stroke_width: 1.5,
|
||||
},
|
||||
inactive: WidgetStyle {
|
||||
bg_fill: None,
|
||||
bg_outline: Some(LineStyle::new(1.0, Srgba::gray(128))),
|
||||
corner_radius: 4.0,
|
||||
main_fill: srgba(60, 60, 80, 255),
|
||||
stroke_color: Srgba::gray(200), // Mustn't look grayed out!
|
||||
stroke_width: 1.0,
|
||||
},
|
||||
disabled: WidgetStyle {
|
||||
bg_fill: None,
|
||||
bg_outline: Some(LineStyle::new(0.5, Srgba::gray(128))),
|
||||
corner_radius: 4.0,
|
||||
main_fill: srgba(50, 50, 50, 255),
|
||||
stroke_color: Srgba::gray(128), // Should look grayed out
|
||||
stroke_width: 0.5,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Interact {
|
||||
pub fn style(&self, response: &Response) -> &WidgetStyle {
|
||||
impl Interacted {
|
||||
pub fn style(&self, response: &Response) -> &WidgetVisuals {
|
||||
if response.active || response.has_kb_focus {
|
||||
&self.active
|
||||
} else if response.sense == Sense::nothing() {
|
||||
|
@ -167,7 +137,7 @@ impl Interact {
|
|||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct WidgetStyle {
|
||||
pub struct WidgetVisuals {
|
||||
/// Background color of widget
|
||||
pub bg_fill: Option<Srgba>,
|
||||
|
||||
|
@ -189,82 +159,306 @@ pub struct WidgetStyle {
|
|||
pub stroke_width: f32,
|
||||
}
|
||||
|
||||
impl WidgetStyle {
|
||||
impl WidgetVisuals {
|
||||
pub fn line_style(&self) -> LineStyle {
|
||||
LineStyle::new(self.stroke_width, self.stroke_color)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Window {
|
||||
pub corner_radius: f32,
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
impl Default for Window {
|
||||
impl Default for Style {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
corner_radius: 10.0,
|
||||
spacing: Spacing::default(),
|
||||
interaction: Interaction::default(),
|
||||
visuals: Visuals::default(),
|
||||
animation_time: 1.0 / 15.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct MenuBar {
|
||||
pub height: f32,
|
||||
}
|
||||
|
||||
impl Default for MenuBar {
|
||||
impl Default for Spacing {
|
||||
fn default() -> Self {
|
||||
Self { height: 16.0 }
|
||||
Self {
|
||||
item_spacing: vec2(8.0, 4.0),
|
||||
window_padding: vec2(6.0, 6.0),
|
||||
button_padding: vec2(4.0, 1.0),
|
||||
indent: 21.0,
|
||||
clickable_diameter: 22.0,
|
||||
slider_width: 140.0,
|
||||
icon_width: 14.0,
|
||||
menu_bar_height: 16.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Style {
|
||||
// TODO: rename style.interact() to something better
|
||||
/// Use this style for interactive things
|
||||
pub fn interact(&self, response: &Response) -> &WidgetStyle {
|
||||
self.interact.style(response)
|
||||
}
|
||||
|
||||
/// Returns small icon rectangle and big icon rectangle
|
||||
pub fn icon_rectangles(&self, rect: Rect) -> (Rect, Rect) {
|
||||
let box_side = self.start_icon_width;
|
||||
let big_icon_rect = Rect::from_center_size(
|
||||
pos2(rect.left() + box_side / 2.0, rect.center().y),
|
||||
vec2(box_side, box_side),
|
||||
);
|
||||
|
||||
let small_rect_side = 8.0; // TODO: make a parameter
|
||||
let small_icon_rect =
|
||||
Rect::from_center_size(big_icon_rect.center(), Vec2::splat(small_rect_side));
|
||||
|
||||
(small_icon_rect, big_icon_rect)
|
||||
impl Default for Interaction {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
resize_grab_radius_side: 5.0,
|
||||
resize_grab_radius_corner: 10.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Visuals {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
interacted: Default::default(),
|
||||
text_color: Srgba::gray(160),
|
||||
line_width: 1.0,
|
||||
thin_outline: LineStyle::new(0.5, GRAY),
|
||||
background_fill: Rgba::luminance_alpha(0.013, 0.95).into(),
|
||||
dark_bg_color: Srgba::black_alpha(140),
|
||||
window_corner_radius: 10.0,
|
||||
resize_corner_size: 16.0,
|
||||
cursor_blink_hz: None, // Some(1.0)
|
||||
text_cursor_width: 2.0,
|
||||
clip_rect_margin: 3.0,
|
||||
debug_widget_rects: false,
|
||||
debug_resize: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Interacted {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
active: WidgetVisuals {
|
||||
bg_fill: Some(Srgba::black_alpha(128)),
|
||||
bg_outline: Some(LineStyle::new(2.0, WHITE)),
|
||||
corner_radius: 0.0,
|
||||
main_fill: srgba(120, 120, 200, 255),
|
||||
stroke_color: WHITE,
|
||||
stroke_width: 2.0,
|
||||
},
|
||||
hovered: WidgetVisuals {
|
||||
bg_fill: None,
|
||||
bg_outline: Some(LineStyle::new(1.0, WHITE)),
|
||||
corner_radius: 2.0,
|
||||
main_fill: srgba(100, 100, 150, 255),
|
||||
stroke_color: Srgba::gray(240),
|
||||
stroke_width: 1.5,
|
||||
},
|
||||
inactive: WidgetVisuals {
|
||||
bg_fill: None,
|
||||
bg_outline: Some(LineStyle::new(1.0, Srgba::gray(128))),
|
||||
corner_radius: 4.0,
|
||||
main_fill: srgba(60, 60, 80, 255),
|
||||
stroke_color: Srgba::gray(200), // Mustn't look grayed out!
|
||||
stroke_width: 1.0,
|
||||
},
|
||||
disabled: WidgetVisuals {
|
||||
bg_fill: None,
|
||||
bg_outline: Some(LineStyle::new(0.5, Srgba::gray(128))),
|
||||
corner_radius: 4.0,
|
||||
main_fill: srgba(50, 50, 50, 255),
|
||||
stroke_color: Srgba::gray(128), // Should look grayed out
|
||||
stroke_width: 0.5,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
use crate::{widgets::*, Ui};
|
||||
|
||||
impl Style {
|
||||
#[rustfmt::skip]
|
||||
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
||||
use crate::{widgets::*};
|
||||
if ui.add(Button::new("Reset style")).clicked {
|
||||
if ui.add(Button::new("Reset")).clicked {
|
||||
*self = Default::default();
|
||||
}
|
||||
|
||||
ui.add(Checkbox::new(&mut self.debug_widget_rects, "Paint debug rectangles around widgets"));
|
||||
ui.add(Checkbox::new(&mut self.debug_resize, "Debug Resize"));
|
||||
|
||||
ui.add(Slider::f32(&mut self.item_spacing.x, 0.0..=10.0).text("item_spacing.x"));
|
||||
ui.add(Slider::f32(&mut self.item_spacing.y, 0.0..=10.0).text("item_spacing.y"));
|
||||
ui.add(Slider::f32(&mut self.window_padding.x, 0.0..=10.0).text("window_padding.x"));
|
||||
ui.add(Slider::f32(&mut self.window_padding.y, 0.0..=10.0).text("window_padding.y"));
|
||||
ui.add(Slider::f32(&mut self.indent, 0.0..=100.0).text("indent"));
|
||||
ui.add(Slider::f32(&mut self.button_padding.x, 0.0..=20.0).text("button_padding.x"));
|
||||
ui.add(Slider::f32(&mut self.button_padding.y, 0.0..=20.0).text("button_padding.y"));
|
||||
ui.add(Slider::f32(&mut self.clickable_diameter, 0.0..=60.0).text("clickable_diameter"));
|
||||
ui.add(Slider::f32(&mut self.start_icon_width, 0.0..=60.0).text("start_icon_width"));
|
||||
ui.add(Slider::f32(&mut self.line_width, 0.0..=10.0).text("line_width"));
|
||||
ui.add(Slider::f32(&mut self.animation_time, 0.0..=1.0).text("animation_time"));
|
||||
let Self {
|
||||
spacing,
|
||||
interaction,
|
||||
visuals,
|
||||
animation_time,
|
||||
} = self;
|
||||
ui.collapsing("Spacing", |ui| spacing.ui(ui));
|
||||
ui.collapsing("Interaction", |ui| interaction.ui(ui));
|
||||
ui.collapsing("Visuals", |ui| visuals.ui(ui));
|
||||
ui.add(Slider::f32(animation_time, 0.0..=1.0).text("animation_time"));
|
||||
}
|
||||
}
|
||||
|
||||
impl Spacing {
|
||||
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
||||
if ui.add(Button::new("Reset")).clicked {
|
||||
*self = Default::default();
|
||||
}
|
||||
|
||||
let Self {
|
||||
item_spacing,
|
||||
window_padding,
|
||||
button_padding,
|
||||
indent,
|
||||
clickable_diameter,
|
||||
slider_width,
|
||||
icon_width,
|
||||
menu_bar_height,
|
||||
} = self;
|
||||
|
||||
ui_slider_vec2(ui, item_spacing, 0.0..=20.0, "item_spacing");
|
||||
ui_slider_vec2(ui, window_padding, 0.0..=20.0, "window_padding");
|
||||
ui_slider_vec2(ui, button_padding, 0.0..=20.0, "button_padding");
|
||||
ui.add(Slider::f32(indent, 0.0..=100.0).text("indent"));
|
||||
ui.add(Slider::f32(clickable_diameter, 0.0..=40.0).text("clickable_diameter"));
|
||||
ui.add(Slider::f32(slider_width, 0.0..=1000.0).text("slider_width"));
|
||||
ui.add(Slider::f32(icon_width, 0.0..=40.0).text("icon_width"));
|
||||
ui.add(Slider::f32(menu_bar_height, 0.0..=40.0).text("menu_bar_height"));
|
||||
}
|
||||
}
|
||||
|
||||
impl Interaction {
|
||||
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
||||
if ui.add(Button::new("Reset")).clicked {
|
||||
*self = Default::default();
|
||||
}
|
||||
|
||||
let Self {
|
||||
resize_grab_radius_side,
|
||||
resize_grab_radius_corner,
|
||||
} = self;
|
||||
|
||||
ui.add(Slider::f32(resize_grab_radius_side, 0.0..=20.0).text("resize_grab_radius_side"));
|
||||
ui.add(
|
||||
Slider::f32(resize_grab_radius_corner, 0.0..=20.0).text("resize_grab_radius_corner"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Interacted {
|
||||
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
||||
if ui.add(Button::new("Reset")).clicked {
|
||||
*self = Default::default();
|
||||
}
|
||||
|
||||
let Self {
|
||||
active,
|
||||
hovered,
|
||||
inactive,
|
||||
disabled,
|
||||
} = self;
|
||||
|
||||
ui.collapsing("active", |ui| active.ui(ui));
|
||||
ui.collapsing("hovered", |ui| hovered.ui(ui));
|
||||
ui.collapsing("inactive", |ui| inactive.ui(ui));
|
||||
ui.collapsing("disabled", |ui| disabled.ui(ui));
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetVisuals {
|
||||
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
||||
let Self {
|
||||
bg_fill,
|
||||
bg_outline,
|
||||
corner_radius,
|
||||
main_fill,
|
||||
stroke_color,
|
||||
stroke_width,
|
||||
} = self;
|
||||
|
||||
let _ = bg_fill; // ui_color(ui, bg_fill, "bg_fill"); // TODO
|
||||
let _ = bg_outline; // bg_outline.ui(ui, "bg_outline");// TODO
|
||||
ui.add(Slider::f32(corner_radius, 0.0..=10.0).text("corner_radius"));
|
||||
ui_color(ui, main_fill, "main_fill");
|
||||
ui_color(ui, stroke_color, "stroke_color");
|
||||
ui.add(Slider::f32(stroke_width, 0.0..=10.0).text("stroke_width"));
|
||||
}
|
||||
}
|
||||
|
||||
impl Visuals {
|
||||
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
||||
if ui.add(Button::new("Reset")).clicked {
|
||||
*self = Default::default();
|
||||
}
|
||||
|
||||
let Self {
|
||||
interacted,
|
||||
text_color,
|
||||
line_width,
|
||||
thin_outline,
|
||||
background_fill,
|
||||
dark_bg_color,
|
||||
window_corner_radius,
|
||||
resize_corner_size,
|
||||
cursor_blink_hz,
|
||||
text_cursor_width,
|
||||
clip_rect_margin,
|
||||
debug_widget_rects,
|
||||
debug_resize,
|
||||
} = self;
|
||||
|
||||
ui.collapsing("interacted", |ui| interacted.ui(ui));
|
||||
ui_color(ui, text_color, "text_color");
|
||||
ui.add(Slider::f32(line_width, 0.0..=10.0).text("line_width"));
|
||||
thin_outline.ui(ui, "thin_outline");
|
||||
ui_color(ui, background_fill, "background_fill");
|
||||
ui_color(ui, dark_bg_color, "dark_bg_color");
|
||||
ui.add(Slider::f32(window_corner_radius, 0.0..=20.0).text("window_corner_radius"));
|
||||
ui.add(Slider::f32(resize_corner_size, 0.0..=20.0).text("resize_corner_size"));
|
||||
let _ = cursor_blink_hz; // TODO
|
||||
ui.add(Slider::f32(text_cursor_width, 0.0..=2.0).text("text_cursor_width"));
|
||||
ui.add(Slider::f32(clip_rect_margin, 0.0..=20.0).text("clip_rect_margin"));
|
||||
|
||||
ui.add(Checkbox::new(
|
||||
debug_widget_rects,
|
||||
"Paint debug rectangles around widgets",
|
||||
));
|
||||
ui.add(Checkbox::new(debug_resize, "Debug Resize"));
|
||||
}
|
||||
}
|
||||
|
||||
impl LineStyle {
|
||||
pub fn ui(&mut self, ui: &mut crate::Ui, text: &str) {
|
||||
let Self { width, color } = self;
|
||||
ui.horizontal_centered(|ui| {
|
||||
ui.label(format!("{}: ", text));
|
||||
ui.add(Slider::f32(width, 0.0..=10.0));
|
||||
ui_color(ui, color, "color");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: improve and standardize ui_slider_vec2
|
||||
fn ui_slider_vec2(ui: &mut Ui, value: &mut Vec2, range: std::ops::RangeInclusive<f32>, text: &str) {
|
||||
ui.horizontal_centered(|ui| {
|
||||
ui.label(format!("{}: ", text));
|
||||
ui.add(Slider::f32(&mut value.x, range.clone()))
|
||||
.tooltip_text("x");
|
||||
ui.add(Slider::f32(&mut value.y, range)).tooltip_text("y");
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: improve color picker
|
||||
fn ui_color(ui: &mut Ui, srgba: &mut Srgba, text: &str) {
|
||||
ui.horizontal_centered(|ui| {
|
||||
// TODO: DragValue::u8
|
||||
// ui.label(format!("{} sRGBA: ", text));
|
||||
// ui.add(DragValue::u8(&mut srgba.r).speed(1))
|
||||
// .tooltip_text("r");
|
||||
// ui.add(DragValue::u8(&mut srgba.g).speed(1))
|
||||
// .tooltip_text("g");
|
||||
// ui.add(DragValue::u8(&mut srgba.b).speed(1))
|
||||
// .tooltip_text("b");
|
||||
// ui.add(DragValue::u8(&mut srgba.a).speed(1))
|
||||
// .tooltip_text("a");
|
||||
|
||||
ui.label(format!("{} RGBA: ", text));
|
||||
let mut rgba = Rgba::from(*srgba);
|
||||
ui.add(DragValue::f32(&mut rgba.r).speed(0.003))
|
||||
.tooltip_text("r");
|
||||
ui.add(DragValue::f32(&mut rgba.g).speed(0.003))
|
||||
.tooltip_text("g");
|
||||
ui.add(DragValue::f32(&mut rgba.b).speed(0.003))
|
||||
.tooltip_text("b");
|
||||
ui.add(DragValue::f32(&mut rgba.a).speed(0.003))
|
||||
.tooltip_text("a");
|
||||
if rgba != Rgba::from(*srgba) {
|
||||
*srgba = Srgba::from(rgba);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -38,8 +38,8 @@ pub struct Ui {
|
|||
/// Where the next widget will be put.
|
||||
/// Progresses along self.dir.
|
||||
/// Initially set to rect.min
|
||||
/// If something has already been added, this will point ot style.item_spacing beyond the latest child.
|
||||
/// The cursor can thus be style.item_spacing pixels outside of the child_bounds.
|
||||
/// If something has already been added, this will point ot style.spacing.item_spacing beyond the latest child.
|
||||
/// The cursor can thus be style.spacing.item_spacing pixels outside of the child_bounds.
|
||||
cursor: Pos2, // TODO: move into Layout?
|
||||
|
||||
/// How many children has been added to us?
|
||||
|
@ -54,7 +54,7 @@ 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);
|
||||
let clip_rect = rect.expand(style.visuals.clip_rect_margin);
|
||||
Ui {
|
||||
id,
|
||||
painter: Painter::new(ctx, layer, clip_rect),
|
||||
|
@ -75,7 +75,7 @@ impl Ui {
|
|||
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(),
|
||||
style: self.style().clone(),
|
||||
layout: self.layout,
|
||||
cursor: child_rect.min,
|
||||
child_count: 0,
|
||||
|
@ -366,7 +366,7 @@ impl Ui {
|
|||
|
||||
let rect = self.reserve_space_impl(desired_size);
|
||||
|
||||
if self.style().debug_widget_rects {
|
||||
if self.style().visuals.debug_widget_rects {
|
||||
self.painter.rect_outline(rect, 0.0, (1.0, LIGHT_BLUE));
|
||||
|
||||
let color = color::srgba(200, 0, 0, 255);
|
||||
|
@ -535,7 +535,7 @@ impl Ui {
|
|||
self.layout().dir() == Direction::Vertical,
|
||||
"You can only indent vertical layouts"
|
||||
);
|
||||
let indent = vec2(self.style.indent, 0.0);
|
||||
let indent = vec2(self.style().spacing.indent, 0.0);
|
||||
let child_rect = Rect::from_min_max(self.cursor + indent, self.bottom_right());
|
||||
let mut child_ui = Ui {
|
||||
id: self.id.with(id_source),
|
||||
|
@ -550,7 +550,7 @@ impl Ui {
|
|||
let line_end = pos2(line_start.x, line_start.y + size.y - 2.0);
|
||||
self.painter.line_segment(
|
||||
[line_start, line_end],
|
||||
(self.style.line_width, Srgba::gray(150)),
|
||||
(self.style().visuals.line_width, Srgba::gray(150)),
|
||||
);
|
||||
|
||||
(ret, self.allocate_space(indent + size))
|
||||
|
@ -631,7 +631,7 @@ impl Ui {
|
|||
F: FnOnce(&mut [Self]) -> R,
|
||||
{
|
||||
// TODO: ensure there is space
|
||||
let spacing = self.style.item_spacing.x;
|
||||
let spacing = self.style().spacing.item_spacing.x;
|
||||
let total_spacing = spacing * (num_columns as f32 - 1.0);
|
||||
let column_width = (self.available().width() - total_spacing) / (num_columns as f32);
|
||||
|
||||
|
|
|
@ -107,7 +107,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) {
|
||||
let text_color = self.text_color.unwrap_or_else(|| ui.style().text_color);
|
||||
let text_color = self
|
||||
.text_color
|
||||
.unwrap_or_else(|| ui.style().visuals.text_color);
|
||||
ui.painter()
|
||||
.galley(pos, galley, self.text_style, text_color);
|
||||
}
|
||||
|
@ -201,7 +203,7 @@ impl Widget for Hyperlink {
|
|||
let max_x = pos.x + line.max_x();
|
||||
ui.painter().line_segment(
|
||||
[pos2(min_x, y), pos2(max_x, y)],
|
||||
(ui.style().line_width, color),
|
||||
(ui.style().visuals.line_width, color),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -281,9 +283,9 @@ impl Widget for Button {
|
|||
let id = ui.make_position_id();
|
||||
let font = &ui.fonts()[text_style];
|
||||
let galley = font.layout_multiline(text, ui.available().width());
|
||||
let padding = ui.style().button_padding;
|
||||
let padding = ui.style().spacing.button_padding;
|
||||
let mut size = galley.size + 2.0 * padding;
|
||||
size.y = size.y.max(ui.style().clickable_diameter);
|
||||
size.y = size.y.max(ui.style().spacing.clickable_diameter);
|
||||
let rect = ui.allocate_space(size);
|
||||
let response = ui.interact(rect, id, sense);
|
||||
let text_cursor = response.rect.left_center() + vec2(padding.x, -0.5 * galley.size.y);
|
||||
|
@ -340,18 +342,19 @@ impl<'a> Widget for Checkbox<'a> {
|
|||
let text_style = TextStyle::Button;
|
||||
let font = &ui.fonts()[text_style];
|
||||
let galley = font.layout_single_line(text);
|
||||
let size = ui.style().button_padding
|
||||
+ vec2(ui.style().start_icon_width, 0.0)
|
||||
let size = ui.style().spacing.button_padding
|
||||
+ vec2(ui.style().spacing.icon_width, 0.0)
|
||||
+ galley.size
|
||||
+ ui.style().button_padding;
|
||||
+ ui.style().spacing.button_padding;
|
||||
let rect = ui.allocate_space(size);
|
||||
let response = ui.interact(rect, id, Sense::click());
|
||||
let text_cursor =
|
||||
response.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0);
|
||||
let text_cursor = response.rect.min
|
||||
+ ui.style().spacing.button_padding
|
||||
+ vec2(ui.style().spacing.icon_width, 0.0);
|
||||
if response.clicked {
|
||||
*checked = !*checked;
|
||||
}
|
||||
let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(response.rect);
|
||||
let (small_icon_rect, big_icon_rect) = ui.style().spacing.icon_rectangles(response.rect);
|
||||
ui.painter().add(PaintCmd::Rect {
|
||||
rect: big_icon_rect,
|
||||
corner_radius: ui.style().interact(&response).corner_radius,
|
||||
|
@ -369,7 +372,7 @@ impl<'a> Widget for Checkbox<'a> {
|
|||
pos2(small_icon_rect.right(), small_icon_rect.top()),
|
||||
]),
|
||||
closed: false,
|
||||
outline: Some(LineStyle::new(ui.style().line_width, stroke_color)),
|
||||
outline: Some(LineStyle::new(ui.style().visuals.line_width, stroke_color)),
|
||||
fill: None,
|
||||
});
|
||||
}
|
||||
|
@ -417,19 +420,20 @@ impl Widget for RadioButton {
|
|||
let text_style = TextStyle::Button;
|
||||
let font = &ui.fonts()[text_style];
|
||||
let galley = font.layout_multiline(text, ui.available().width());
|
||||
let size = ui.style().button_padding
|
||||
+ vec2(ui.style().start_icon_width, 0.0)
|
||||
let size = ui.style().spacing.button_padding
|
||||
+ vec2(ui.style().spacing.icon_width, 0.0)
|
||||
+ galley.size
|
||||
+ ui.style().button_padding;
|
||||
+ ui.style().spacing.button_padding;
|
||||
let rect = ui.allocate_space(size);
|
||||
let response = ui.interact(rect, id, Sense::click());
|
||||
let text_cursor =
|
||||
response.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0);
|
||||
let text_cursor = response.rect.min
|
||||
+ ui.style().spacing.button_padding
|
||||
+ vec2(ui.style().spacing.icon_width, 0.0);
|
||||
|
||||
let bg_fill = ui.style().interact(&response).bg_fill;
|
||||
let stroke_color = ui.style().interact(&response).stroke_color;
|
||||
|
||||
let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(response.rect);
|
||||
let (small_icon_rect, big_icon_rect) = ui.style().spacing.icon_rectangles(response.rect);
|
||||
|
||||
let painter = ui.painter();
|
||||
|
||||
|
@ -507,7 +511,7 @@ impl Widget for Separator {
|
|||
color,
|
||||
} = self;
|
||||
|
||||
let line_width = line_width.unwrap_or_else(|| ui.style().line_width);
|
||||
let line_width = line_width.unwrap_or_else(|| ui.style().visuals.line_width);
|
||||
|
||||
let available_space = ui.available_finite().size();
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ impl<'a> Slider<'a> {
|
|||
/// Just the slider, no text
|
||||
fn allocate_slide_space(&self, ui: &mut Ui, height: f32) -> Response {
|
||||
let id = self.id.unwrap_or_else(|| ui.make_position_id());
|
||||
let desired_size = vec2(ui.available().width(), height);
|
||||
let desired_size = vec2(ui.style().spacing.slider_width, height);
|
||||
let rect = ui.allocate_space(desired_size);
|
||||
ui.interact(rect, id, Sense::click_and_drag())
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ impl<'a> Slider<'a> {
|
|||
ui.painter().add(PaintCmd::Rect {
|
||||
rect: rail_rect,
|
||||
corner_radius: rail_radius,
|
||||
fill: Some(ui.style().background_fill),
|
||||
fill: Some(ui.style().visuals.background_fill),
|
||||
outline: Some(LineStyle::new(1.0, Srgba::gray(200))), // TODO
|
||||
});
|
||||
|
||||
|
@ -182,10 +182,12 @@ impl<'a> Slider<'a> {
|
|||
|
||||
/// Just the text label
|
||||
fn text_ui(&mut self, ui: &mut Ui, x_range: RangeInclusive<f32>) {
|
||||
let text_color = self.text_color.unwrap_or_else(|| ui.style().text_color);
|
||||
let text_color = self
|
||||
.text_color
|
||||
.unwrap_or_else(|| ui.style().visuals.text_color);
|
||||
|
||||
if let Some(label_text) = self.text.as_deref() {
|
||||
ui.style_mut().item_spacing.x = 0.0;
|
||||
ui.style_mut().spacing.item_spacing.x = 0.0;
|
||||
ui.add(
|
||||
Label::new(format!("{}: ", label_text))
|
||||
.multiline(false)
|
||||
|
@ -258,30 +260,21 @@ impl<'a> Widget for Slider<'a> {
|
|||
fn ui(mut self, ui: &mut Ui) -> Response {
|
||||
let text_style = TextStyle::Button;
|
||||
let font = &ui.fonts()[text_style];
|
||||
let height = font.line_spacing().max(ui.style().clickable_diameter);
|
||||
let height = font
|
||||
.line_spacing()
|
||||
.max(ui.style().spacing.clickable_diameter);
|
||||
|
||||
if let Some(text) = &self.text {
|
||||
self.id = self.id.or_else(|| Some(ui.make_unique_child_id(text)));
|
||||
|
||||
ui.columns(2, |columns| {
|
||||
let slider_ui = &mut columns[0];
|
||||
let slider_response = self.allocate_slide_space(slider_ui, height);
|
||||
self.slider_ui(slider_ui, &slider_response);
|
||||
ui.horizontal_centered(|ui| {
|
||||
let slider_response = self.allocate_slide_space(ui, height);
|
||||
self.slider_ui(ui, &slider_response);
|
||||
let x_range = x_range(&slider_response.rect);
|
||||
|
||||
// Place the text in line with the slider on the left:
|
||||
let text_ui = &mut columns[1];
|
||||
text_ui.set_desired_height(slider_response.rect.height());
|
||||
text_ui.inner_layout(
|
||||
Layout::horizontal(Align::Center),
|
||||
text_ui.available().size(),
|
||||
|ui| {
|
||||
self.text_ui(ui, x_range);
|
||||
},
|
||||
);
|
||||
|
||||
self.text_ui(ui, x_range);
|
||||
slider_response
|
||||
})
|
||||
.0
|
||||
} else {
|
||||
let response = self.allocate_slide_space(ui, height);
|
||||
self.slider_ui(ui, &response);
|
||||
|
|
|
@ -183,13 +183,13 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
painter.add(PaintCmd::Rect {
|
||||
rect: bg_rect,
|
||||
corner_radius: ui.style().interact(&response).corner_radius,
|
||||
fill: Some(ui.style().dark_bg_color),
|
||||
fill: Some(ui.style().visuals.dark_bg_color),
|
||||
outline: ui.style().interact(&response).bg_outline,
|
||||
});
|
||||
}
|
||||
|
||||
if ui.memory().has_kb_focus(id) {
|
||||
let cursor_blink_hz = ui.style().cursor_blink_hz;
|
||||
let cursor_blink_hz = ui.style().visuals.cursor_blink_hz;
|
||||
let show_cursor = if let Some(cursor_blink_hz) = cursor_blink_hz {
|
||||
ui.ctx().request_repaint(); // TODO: only when cursor blinks on or off
|
||||
(ui.input().time * cursor_blink_hz as f64 * 3.0).floor() as i64 % 3 != 0
|
||||
|
@ -202,7 +202,7 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
let cursor_pos = response.rect.min + galley.char_start_pos(cursor);
|
||||
painter.line_segment(
|
||||
[cursor_pos, cursor_pos + vec2(0.0, line_spacing)],
|
||||
(ui.style().text_cursor_width, color::WHITE),
|
||||
(ui.style().visuals.text_cursor_width, color::WHITE),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue