Add ui.set_enabled(false) to disable all widgets in a Ui
Closes https://github.com/emilk/egui/issues/50
This commit is contained in:
parent
d07a17ac6a
commit
bca722ddf8
20 changed files with 303 additions and 77 deletions
|
@ -13,7 +13,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
* Add support for secondary and middle mouse buttons.
|
* Add support for secondary and middle mouse buttons.
|
||||||
* Add `Label` methods for code, strong, strikethrough, underline and italics.
|
* Add `Label` methods for code, strong, strikethrough, underline and italics.
|
||||||
* Add `ui.group(|ui| { … })` to visually group some widgets within a frame
|
* Add `ui.group(|ui| { … })` to visually group some widgets within a frame.
|
||||||
|
* Add `ui.set_enabled(false)` to disable all widgets in a `Ui` (grayed out and non-interactive).
|
||||||
* Add `TextEdit::hint_text` for showing a weak hint text when empty.
|
* Add `TextEdit::hint_text` for showing a weak hint text when empty.
|
||||||
* `egui::popup::popup_below_widget`: show a popup area below another widget.
|
* `egui::popup::popup_below_widget`: show a popup area below another widget.
|
||||||
* Add `Slider::clamp_to_range(bool)`: if set, clamp the incoming and outgoing values to the slider range.
|
* Add `Slider::clamp_to_range(bool)`: if set, clamp the incoming and outgoing values to the slider range.
|
||||||
|
|
|
@ -45,6 +45,7 @@ pub struct Area {
|
||||||
pub(crate) id: Id,
|
pub(crate) id: Id,
|
||||||
movable: bool,
|
movable: bool,
|
||||||
interactable: bool,
|
interactable: bool,
|
||||||
|
enabled: bool,
|
||||||
order: Order,
|
order: Order,
|
||||||
default_pos: Option<Pos2>,
|
default_pos: Option<Pos2>,
|
||||||
new_pos: Option<Pos2>,
|
new_pos: Option<Pos2>,
|
||||||
|
@ -56,6 +57,7 @@ impl Area {
|
||||||
id: Id::new(id_source),
|
id: Id::new(id_source),
|
||||||
movable: true,
|
movable: true,
|
||||||
interactable: true,
|
interactable: true,
|
||||||
|
enabled: true,
|
||||||
order: Order::Middle,
|
order: Order::Middle,
|
||||||
default_pos: None,
|
default_pos: None,
|
||||||
new_pos: None,
|
new_pos: None,
|
||||||
|
@ -71,6 +73,15 @@ impl Area {
|
||||||
LayerId::new(self.order, self.id)
|
LayerId::new(self.order, self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If false, no content responds to click
|
||||||
|
/// and widgets will be shown grayed out.
|
||||||
|
/// You won't be able to move the window.
|
||||||
|
/// Default: `true`.
|
||||||
|
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||||
|
self.enabled = enabled;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// moveable by dragging the area?
|
/// moveable by dragging the area?
|
||||||
pub fn movable(mut self, movable: bool) -> Self {
|
pub fn movable(mut self, movable: bool) -> Self {
|
||||||
self.movable = movable;
|
self.movable = movable;
|
||||||
|
@ -78,8 +89,12 @@ impl Area {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
self.enabled
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_movable(&self) -> bool {
|
pub fn is_movable(&self) -> bool {
|
||||||
self.movable
|
self.movable && self.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If false, clicks goes straight through to what is behind us.
|
/// If false, clicks goes straight through to what is behind us.
|
||||||
|
@ -121,6 +136,7 @@ pub(crate) struct Prepared {
|
||||||
layer_id: LayerId,
|
layer_id: LayerId,
|
||||||
state: State,
|
state: State,
|
||||||
movable: bool,
|
movable: bool,
|
||||||
|
enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Area {
|
impl Area {
|
||||||
|
@ -130,6 +146,7 @@ impl Area {
|
||||||
movable,
|
movable,
|
||||||
order,
|
order,
|
||||||
interactable,
|
interactable,
|
||||||
|
enabled,
|
||||||
default_pos,
|
default_pos,
|
||||||
new_pos,
|
new_pos,
|
||||||
} = self;
|
} = self;
|
||||||
|
@ -149,6 +166,7 @@ impl Area {
|
||||||
layer_id,
|
layer_id,
|
||||||
state,
|
state,
|
||||||
movable,
|
movable,
|
||||||
|
enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,13 +232,15 @@ impl Prepared {
|
||||||
clip_rect = clip_rect.intersect(central_area);
|
clip_rect = clip_rect.intersect(central_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ui::new(
|
let mut ui = Ui::new(
|
||||||
ctx.clone(),
|
ctx.clone(),
|
||||||
self.layer_id,
|
self.layer_id,
|
||||||
self.layer_id.id,
|
self.layer_id.id,
|
||||||
max_rect,
|
max_rect,
|
||||||
clip_rect,
|
clip_rect,
|
||||||
)
|
);
|
||||||
|
ui.set_enabled(self.enabled);
|
||||||
|
ui
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_pass_by_value)] // intentional to swallow up `content_ui`.
|
#[allow(clippy::needless_pass_by_value)] // intentional to swallow up `content_ui`.
|
||||||
|
@ -229,6 +249,7 @@ impl Prepared {
|
||||||
layer_id,
|
layer_id,
|
||||||
mut state,
|
mut state,
|
||||||
movable,
|
movable,
|
||||||
|
enabled,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
state.size = content_ui.min_rect().size();
|
state.size = content_ui.min_rect().size();
|
||||||
|
@ -247,6 +268,7 @@ impl Prepared {
|
||||||
interact_id,
|
interact_id,
|
||||||
state.rect(),
|
state.rect(),
|
||||||
sense,
|
sense,
|
||||||
|
enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
if move_response.dragged() && movable {
|
if move_response.dragged() && movable {
|
||||||
|
|
|
@ -23,7 +23,7 @@ impl Frame {
|
||||||
Self {
|
Self {
|
||||||
margin: Vec2::new(8.0, 6.0),
|
margin: Vec2::new(8.0, 6.0),
|
||||||
corner_radius: 4.0,
|
corner_radius: 4.0,
|
||||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
stroke: style.visuals.window_stroke(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,8 @@ impl Frame {
|
||||||
Self {
|
Self {
|
||||||
margin: Vec2::new(8.0, 2.0),
|
margin: Vec2::new(8.0, 2.0),
|
||||||
corner_radius: 0.0,
|
corner_radius: 0.0,
|
||||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
fill: style.visuals.window_fill(),
|
||||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
stroke: style.visuals.window_stroke(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ impl Frame {
|
||||||
Self {
|
Self {
|
||||||
margin: Vec2::new(8.0, 8.0),
|
margin: Vec2::new(8.0, 8.0),
|
||||||
corner_radius: 0.0,
|
corner_radius: 0.0,
|
||||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
fill: style.visuals.window_fill(),
|
||||||
stroke: Default::default(),
|
stroke: Default::default(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,8 @@ impl Frame {
|
||||||
margin: style.spacing.window_padding,
|
margin: style.spacing.window_padding,
|
||||||
corner_radius: style.visuals.window_corner_radius,
|
corner_radius: style.visuals.window_corner_radius,
|
||||||
shadow: style.visuals.window_shadow,
|
shadow: style.visuals.window_shadow,
|
||||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
fill: style.visuals.window_fill(),
|
||||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
stroke: style.visuals.window_stroke(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +63,8 @@ impl Frame {
|
||||||
margin: Vec2::splat(1.0),
|
margin: Vec2::splat(1.0),
|
||||||
corner_radius: 2.0,
|
corner_radius: 2.0,
|
||||||
shadow: Shadow::small(),
|
shadow: Shadow::small(),
|
||||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
fill: style.visuals.window_fill(),
|
||||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
stroke: style.visuals.window_stroke(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,8 +73,8 @@ impl Frame {
|
||||||
margin: style.spacing.window_padding,
|
margin: style.spacing.window_padding,
|
||||||
corner_radius: 5.0,
|
corner_radius: 5.0,
|
||||||
shadow: Shadow::small(),
|
shadow: Shadow::small(),
|
||||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
fill: style.visuals.window_fill(),
|
||||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
stroke: style.visuals.window_stroke(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ impl Frame {
|
||||||
margin: Vec2::new(10.0, 10.0),
|
margin: Vec2::new(10.0, 10.0),
|
||||||
corner_radius: 5.0,
|
corner_radius: 5.0,
|
||||||
fill: Color32::from_black_alpha(250),
|
fill: Color32::from_black_alpha(250),
|
||||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
stroke: style.visuals.window_stroke(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,12 @@ impl<'open> Window<'open> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If `false` the window will be grayed out and non-interactive.
|
||||||
|
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||||
|
self.area = self.area.enabled(enabled);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Usage: `Window::new(...).mutate(|w| w.resize = w.resize.auto_expand_width(true))`
|
/// Usage: `Window::new(...).mutate(|w| w.resize = w.resize.auto_expand_width(true))`
|
||||||
/// Not sure this is a good interface for this.
|
/// Not sure this is a good interface for this.
|
||||||
pub fn mutate(mut self, mutate: impl Fn(&mut Self)) -> Self {
|
pub fn mutate(mut self, mutate: impl Fn(&mut Self)) -> Self {
|
||||||
|
@ -239,8 +245,8 @@ impl<'open> Window<'open> {
|
||||||
let is_maximized = !with_title_bar
|
let is_maximized = !with_title_bar
|
||||||
|| collapsing_header::State::is_open(ctx, collapsing_id).unwrap_or_default();
|
|| collapsing_header::State::is_open(ctx, collapsing_id).unwrap_or_default();
|
||||||
let possible = PossibleInteractions {
|
let possible = PossibleInteractions {
|
||||||
movable: area.is_movable(),
|
movable: area.is_enabled() && area.is_movable(),
|
||||||
resizable: resize.is_resizable() && is_maximized,
|
resizable: area.is_enabled() && resize.is_resizable() && is_maximized,
|
||||||
};
|
};
|
||||||
|
|
||||||
let area = area.movable(false); // We move it manually
|
let area = area.movable(false); // We move it manually
|
||||||
|
|
|
@ -218,6 +218,7 @@ impl CtxRef {
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
/// Use `ui.interact` instead
|
/// Use `ui.interact` instead
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn interact(
|
pub(crate) fn interact(
|
||||||
&self,
|
&self,
|
||||||
clip_rect: Rect,
|
clip_rect: Rect,
|
||||||
|
@ -226,6 +227,7 @@ impl CtxRef {
|
||||||
id: Id,
|
id: Id,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
sense: Sense,
|
sense: Sense,
|
||||||
|
enabled: bool,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let gap = 0.5; // Just to make sure we don't accidentally hover two things at once (a small eps should be sufficient).
|
let gap = 0.5; // Just to make sure we don't accidentally hover two things at once (a small eps should be sufficient).
|
||||||
let interact_rect = rect.expand2(
|
let interact_rect = rect.expand2(
|
||||||
|
@ -234,7 +236,7 @@ impl CtxRef {
|
||||||
.at_most(Vec2::splat(5.0)),
|
.at_most(Vec2::splat(5.0)),
|
||||||
); // make it easier to click
|
); // make it easier to click
|
||||||
let hovered = self.rect_contains_pointer(layer_id, clip_rect.intersect(interact_rect));
|
let hovered = self.rect_contains_pointer(layer_id, clip_rect.intersect(interact_rect));
|
||||||
self.interact_with_hovered(layer_id, id, rect, sense, hovered)
|
self.interact_with_hovered(layer_id, id, rect, sense, enabled, hovered)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// You specify if a thing is hovered, and the function gives a `Response`.
|
/// You specify if a thing is hovered, and the function gives a `Response`.
|
||||||
|
@ -244,8 +246,11 @@ impl CtxRef {
|
||||||
id: Id,
|
id: Id,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
sense: Sense,
|
sense: Sense,
|
||||||
|
enabled: bool,
|
||||||
hovered: bool,
|
hovered: bool,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
|
let hovered = hovered && enabled; // can't even hover disabled widgets
|
||||||
|
|
||||||
let has_kb_focus = self.memory().has_kb_focus(id);
|
let has_kb_focus = self.memory().has_kb_focus(id);
|
||||||
let lost_kb_focus = self.memory().lost_kb_focus(id);
|
let lost_kb_focus = self.memory().lost_kb_focus(id);
|
||||||
|
|
||||||
|
@ -255,6 +260,7 @@ impl CtxRef {
|
||||||
id,
|
id,
|
||||||
rect,
|
rect,
|
||||||
sense,
|
sense,
|
||||||
|
enabled,
|
||||||
hovered,
|
hovered,
|
||||||
clicked: Default::default(),
|
clicked: Default::default(),
|
||||||
double_clicked: Default::default(),
|
double_clicked: Default::default(),
|
||||||
|
@ -266,7 +272,7 @@ impl CtxRef {
|
||||||
lost_kb_focus,
|
lost_kb_focus,
|
||||||
};
|
};
|
||||||
|
|
||||||
if sense == Sense::hover() || !layer_id.allow_interaction() {
|
if !enabled || sense == Sense::hover() || !layer_id.allow_interaction() {
|
||||||
// Not interested or allowed input:
|
// Not interested or allowed input:
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,10 @@ pub struct Painter {
|
||||||
/// Everything painted in this `Painter` will be clipped against this.
|
/// Everything painted in this `Painter` will be clipped against this.
|
||||||
/// This means nothing outside of this rectangle will be visible on screen.
|
/// This means nothing outside of this rectangle will be visible on screen.
|
||||||
clip_rect: Rect,
|
clip_rect: Rect,
|
||||||
|
|
||||||
|
/// If set, all shapes will have their colors modified to be closer to this.
|
||||||
|
/// This is used to implement grayed out interfaces.
|
||||||
|
fade_to_color: Option<Color32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Painter {
|
impl Painter {
|
||||||
|
@ -30,6 +34,7 @@ impl Painter {
|
||||||
ctx,
|
ctx,
|
||||||
layer_id,
|
layer_id,
|
||||||
clip_rect,
|
clip_rect,
|
||||||
|
fade_to_color: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +44,7 @@ impl Painter {
|
||||||
ctx: self.ctx,
|
ctx: self.ctx,
|
||||||
layer_id,
|
layer_id,
|
||||||
clip_rect: self.clip_rect,
|
clip_rect: self.clip_rect,
|
||||||
|
fade_to_color: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +53,11 @@ impl Painter {
|
||||||
self.layer_id = layer_id;
|
self.layer_id = layer_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If set, colors will be modified to look like this
|
||||||
|
pub(crate) fn set_fade_to_color(&mut self, fade_to_color: Option<Color32>) {
|
||||||
|
self.fade_to_color = fade_to_color;
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a painter for a sub-region of this `Painter`.
|
/// Create a painter for a sub-region of this `Painter`.
|
||||||
///
|
///
|
||||||
/// The clip-rect of the returned `Painter` will be the intersection
|
/// The clip-rect of the returned `Painter` will be the intersection
|
||||||
|
@ -106,10 +117,17 @@ impl Painter {
|
||||||
|
|
||||||
/// ## Low level
|
/// ## Low level
|
||||||
impl Painter {
|
impl Painter {
|
||||||
|
fn transform_shape(&self, shape: &mut Shape) {
|
||||||
|
if let Some(fade_to_color) = self.fade_to_color {
|
||||||
|
tint_shape_towards(shape, fade_to_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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(&self, shape: Shape) -> ShapeIdx {
|
pub fn add(&self, mut shape: Shape) -> ShapeIdx {
|
||||||
|
self.transform_shape(&mut shape);
|
||||||
self.ctx
|
self.ctx
|
||||||
.graphics()
|
.graphics()
|
||||||
.list(self.layer_id)
|
.list(self.layer_id)
|
||||||
|
@ -119,8 +137,14 @@ impl Painter {
|
||||||
/// Add many shapes at once.
|
/// Add many shapes at once.
|
||||||
///
|
///
|
||||||
/// Calling this once is generally faster than calling [`Self::add`] multiple times.
|
/// Calling this once is generally faster than calling [`Self::add`] multiple times.
|
||||||
pub fn extend(&self, shapes: Vec<Shape>) {
|
pub fn extend(&self, mut shapes: Vec<Shape>) {
|
||||||
if !shapes.is_empty() {
|
if !shapes.is_empty() {
|
||||||
|
if self.fade_to_color.is_some() {
|
||||||
|
for shape in &mut shapes {
|
||||||
|
self.transform_shape(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.ctx
|
self.ctx
|
||||||
.graphics()
|
.graphics()
|
||||||
.list(self.layer_id)
|
.list(self.layer_id)
|
||||||
|
@ -129,7 +153,8 @@ impl Painter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modify an existing [`Shape`].
|
/// Modify an existing [`Shape`].
|
||||||
pub fn set(&self, idx: ShapeIdx, shape: Shape) {
|
pub fn set(&self, idx: ShapeIdx, mut shape: Shape) {
|
||||||
|
self.transform_shape(&mut shape);
|
||||||
self.ctx
|
self.ctx
|
||||||
.graphics()
|
.graphics()
|
||||||
.list(self.layer_id)
|
.list(self.layer_id)
|
||||||
|
@ -294,3 +319,9 @@ impl Painter {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tint_shape_towards(shape: &mut Shape, target: Color32) {
|
||||||
|
epaint::shape_transform::adjust_colors(shape, &|color| {
|
||||||
|
*color = crate::color::tint_color_towards(*color, target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,10 @@ pub struct Response {
|
||||||
/// The senses (click and/or drag) that the widget was interested in (if any).
|
/// The senses (click and/or drag) that the widget was interested in (if any).
|
||||||
pub sense: Sense,
|
pub sense: Sense,
|
||||||
|
|
||||||
|
/// Was the widget enabled?
|
||||||
|
/// If `false`, there was no interaction attempted (not even hover).
|
||||||
|
pub(crate) enabled: bool,
|
||||||
|
|
||||||
// OUT:
|
// OUT:
|
||||||
/// The pointer is hovering above this widget or the widget was clicked/tapped this frame.
|
/// The pointer is hovering above this widget or the widget was clicked/tapped this frame.
|
||||||
pub(crate) hovered: bool,
|
pub(crate) hovered: bool,
|
||||||
|
@ -68,6 +72,7 @@ impl std::fmt::Debug for Response {
|
||||||
id,
|
id,
|
||||||
rect,
|
rect,
|
||||||
sense,
|
sense,
|
||||||
|
enabled,
|
||||||
hovered,
|
hovered,
|
||||||
clicked,
|
clicked,
|
||||||
double_clicked,
|
double_clicked,
|
||||||
|
@ -83,6 +88,7 @@ impl std::fmt::Debug for Response {
|
||||||
.field("id", id)
|
.field("id", id)
|
||||||
.field("rect", rect)
|
.field("rect", rect)
|
||||||
.field("sense", sense)
|
.field("sense", sense)
|
||||||
|
.field("enabled", enabled)
|
||||||
.field("hovered", hovered)
|
.field("hovered", hovered)
|
||||||
.field("clicked", clicked)
|
.field("clicked", clicked)
|
||||||
.field("double_clicked", double_clicked)
|
.field("double_clicked", double_clicked)
|
||||||
|
@ -117,6 +123,13 @@ impl Response {
|
||||||
self.double_clicked[PointerButton::Primary as usize]
|
self.double_clicked[PointerButton::Primary as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Was the widget enabled?
|
||||||
|
/// If false, there was no interaction attempted
|
||||||
|
/// and the widget should be drawn in a gray disabled look.
|
||||||
|
pub fn enabled(&self) -> bool {
|
||||||
|
self.enabled
|
||||||
|
}
|
||||||
|
|
||||||
/// The pointer is hovering above this widget or the widget was clicked/tapped this frame.
|
/// The pointer is hovering above this widget or the widget was clicked/tapped this frame.
|
||||||
pub fn hovered(&self) -> bool {
|
pub fn hovered(&self) -> bool {
|
||||||
self.hovered
|
self.hovered
|
||||||
|
@ -208,8 +221,14 @@ impl Response {
|
||||||
/// if response.clicked() { /* … */ }
|
/// if response.clicked() { /* … */ }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn interact(&self, sense: Sense) -> Self {
|
pub fn interact(&self, sense: Sense) -> Self {
|
||||||
self.ctx
|
self.ctx.interact_with_hovered(
|
||||||
.interact_with_hovered(self.layer_id, self.id, self.rect, sense, self.hovered)
|
self.layer_id,
|
||||||
|
self.id,
|
||||||
|
self.rect,
|
||||||
|
sense,
|
||||||
|
self.enabled,
|
||||||
|
self.hovered,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move the scroll to this UI with the specified alignment.
|
/// Move the scroll to this UI with the specified alignment.
|
||||||
|
@ -247,6 +266,7 @@ impl Response {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
rect: self.rect.union(other.rect),
|
rect: self.rect.union(other.rect),
|
||||||
sense: self.sense.union(other.sense),
|
sense: self.sense.union(other.sense),
|
||||||
|
enabled: self.enabled || other.enabled,
|
||||||
hovered: self.hovered || other.hovered,
|
hovered: self.hovered || other.hovered,
|
||||||
clicked: [
|
clicked: [
|
||||||
self.clicked[0] || other.clicked[0],
|
self.clicked[0] || other.clicked[0],
|
||||||
|
|
|
@ -184,12 +184,20 @@ impl Visuals {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn weak_text_color(&self) -> Color32 {
|
pub fn weak_text_color(&self) -> Color32 {
|
||||||
self.widgets.disabled.text_color()
|
crate::color::tint_color_towards(self.text_color(), self.window_fill())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn strong_text_color(&self) -> Color32 {
|
pub fn strong_text_color(&self) -> Color32 {
|
||||||
self.widgets.active.text_color()
|
self.widgets.active.text_color()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn window_fill(&self) -> Color32 {
|
||||||
|
self.widgets.noninteractive.bg_fill
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_stroke(&self) -> Stroke {
|
||||||
|
self.widgets.noninteractive.bg_stroke
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Selected text, selected elements etc
|
/// Selected text, selected elements etc
|
||||||
|
@ -210,8 +218,6 @@ pub struct Widgets {
|
||||||
/// * `noninteractive.bg_fill` is the background color of windows.
|
/// * `noninteractive.bg_fill` is the background color of windows.
|
||||||
/// * `noninteractive.fg_stroke` is the normal text color.
|
/// * `noninteractive.fg_stroke` is the normal text color.
|
||||||
pub noninteractive: WidgetVisuals,
|
pub noninteractive: WidgetVisuals,
|
||||||
/// The style of a disabled button.
|
|
||||||
pub disabled: WidgetVisuals,
|
|
||||||
/// The style of an interactive widget, such as a button, at rest.
|
/// The style of an interactive widget, such as a button, at rest.
|
||||||
pub inactive: WidgetVisuals,
|
pub inactive: WidgetVisuals,
|
||||||
/// The style of an interactive widget while you hover it.
|
/// The style of an interactive widget while you hover it.
|
||||||
|
@ -224,8 +230,6 @@ impl Widgets {
|
||||||
pub fn style(&self, response: &Response) -> &WidgetVisuals {
|
pub fn style(&self, response: &Response) -> &WidgetVisuals {
|
||||||
if response.is_pointer_button_down_on() || response.has_kb_focus {
|
if response.is_pointer_button_down_on() || response.has_kb_focus {
|
||||||
&self.active
|
&self.active
|
||||||
} else if response.sense == crate::Sense::hover() {
|
|
||||||
&self.disabled
|
|
||||||
} else if response.hovered() {
|
} else if response.hovered() {
|
||||||
&self.hovered
|
&self.hovered
|
||||||
} else {
|
} else {
|
||||||
|
@ -374,19 +378,12 @@ impl Widgets {
|
||||||
pub fn dark() -> Self {
|
pub fn dark() -> Self {
|
||||||
Self {
|
Self {
|
||||||
noninteractive: WidgetVisuals {
|
noninteractive: WidgetVisuals {
|
||||||
|
bg_fill: Color32::from_gray(30), // window background
|
||||||
bg_stroke: Stroke::new(1.0, Color32::from_gray(65)), // window outline
|
bg_stroke: Stroke::new(1.0, Color32::from_gray(65)), // window outline
|
||||||
bg_fill: Color32::from_gray(30), // window background
|
|
||||||
fg_stroke: Stroke::new(1.0, Color32::from_gray(160)), // normal text color
|
fg_stroke: Stroke::new(1.0, Color32::from_gray(160)), // normal text color
|
||||||
corner_radius: 4.0,
|
corner_radius: 4.0,
|
||||||
expansion: 0.0,
|
expansion: 0.0,
|
||||||
},
|
},
|
||||||
disabled: WidgetVisuals {
|
|
||||||
bg_fill: Color32::from_gray(40), // Should look grayed out
|
|
||||||
bg_stroke: Stroke::new(1.0, Color32::from_gray(70)),
|
|
||||||
fg_stroke: Stroke::new(1.0, Color32::from_gray(110)), // Should look grayed out. Also used for "weak" text color.
|
|
||||||
corner_radius: 4.0,
|
|
||||||
expansion: 0.0,
|
|
||||||
},
|
|
||||||
inactive: WidgetVisuals {
|
inactive: WidgetVisuals {
|
||||||
bg_fill: Color32::from_gray(70),
|
bg_fill: Color32::from_gray(70),
|
||||||
bg_stroke: Default::default(),
|
bg_stroke: Default::default(),
|
||||||
|
@ -414,16 +411,9 @@ impl Widgets {
|
||||||
pub fn light() -> Self {
|
pub fn light() -> Self {
|
||||||
Self {
|
Self {
|
||||||
noninteractive: WidgetVisuals {
|
noninteractive: WidgetVisuals {
|
||||||
|
bg_fill: Color32::from_gray(220), // window background
|
||||||
bg_stroke: Stroke::new(1.0, Color32::from_gray(180)), // window outline
|
bg_stroke: Stroke::new(1.0, Color32::from_gray(180)), // window outline
|
||||||
bg_fill: Color32::from_gray(220), // window background
|
fg_stroke: Stroke::new(1.0, Color32::from_gray(70)), // normal text color
|
||||||
fg_stroke: Stroke::new(1.0, Color32::from_gray(70)), // normal text color
|
|
||||||
corner_radius: 4.0,
|
|
||||||
expansion: 0.0,
|
|
||||||
},
|
|
||||||
disabled: WidgetVisuals {
|
|
||||||
bg_fill: Color32::from_gray(215), // Should look grayed out
|
|
||||||
bg_stroke: Stroke::new(1.0, Color32::from_gray(185)),
|
|
||||||
fg_stroke: Stroke::new(1.0, Color32::from_gray(145)), // Should look grayed out. Also used for "weak" text color.
|
|
||||||
corner_radius: 4.0,
|
corner_radius: 4.0,
|
||||||
expansion: 0.0,
|
expansion: 0.0,
|
||||||
},
|
},
|
||||||
|
@ -542,7 +532,6 @@ impl Widgets {
|
||||||
active,
|
active,
|
||||||
hovered,
|
hovered,
|
||||||
inactive,
|
inactive,
|
||||||
disabled,
|
|
||||||
noninteractive,
|
noninteractive,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
@ -550,10 +539,6 @@ impl Widgets {
|
||||||
ui.label("The style of a widget that you cannot interact with.");
|
ui.label("The style of a widget that you cannot interact with.");
|
||||||
noninteractive.ui(ui)
|
noninteractive.ui(ui)
|
||||||
});
|
});
|
||||||
ui.collapsing("interactive & disabled", |ui| {
|
|
||||||
ui.label("The style of a disabled button.");
|
|
||||||
disabled.ui(ui)
|
|
||||||
});
|
|
||||||
ui.collapsing("interactive & inactive", |ui| {
|
ui.collapsing("interactive & inactive", |ui| {
|
||||||
ui.label("The style of an interactive widget, such as a button, at rest.");
|
ui.label("The style of an interactive widget, such as a button, at rest.");
|
||||||
inactive.ui(ui)
|
inactive.ui(ui)
|
||||||
|
|
|
@ -46,6 +46,10 @@ pub struct Ui {
|
||||||
|
|
||||||
/// Handles the `Ui` size and the placement of new widgets.
|
/// Handles the `Ui` size and the placement of new widgets.
|
||||||
placer: Placer,
|
placer: Placer,
|
||||||
|
|
||||||
|
/// If false we are unresponsive to input,
|
||||||
|
/// and all widgets will assume a gray style.
|
||||||
|
enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ui {
|
impl Ui {
|
||||||
|
@ -60,6 +64,7 @@ impl Ui {
|
||||||
painter: Painter::new(ctx, layer_id, clip_rect),
|
painter: Painter::new(ctx, layer_id, clip_rect),
|
||||||
style,
|
style,
|
||||||
placer: Placer::new(max_rect, Layout::default()),
|
placer: Placer::new(max_rect, Layout::default()),
|
||||||
|
enabled: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +77,7 @@ impl Ui {
|
||||||
painter: self.painter.clone(),
|
painter: self.painter.clone(),
|
||||||
style: self.style.clone(),
|
style: self.style.clone(),
|
||||||
placer: Placer::new(max_rect, layout),
|
placer: Placer::new(max_rect, layout),
|
||||||
|
enabled: self.enabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +172,39 @@ impl Ui {
|
||||||
&self.painter
|
&self.painter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If `false`, the `Ui` does not allow any interaction and
|
||||||
|
/// the widgets in it will draw with a gray look.
|
||||||
|
pub fn enabled(&self) -> bool {
|
||||||
|
self.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calling `set_enabled(false)` will cause the `Ui` to deny all future interaction
|
||||||
|
/// and all the widgets will draw with a gray look.
|
||||||
|
///
|
||||||
|
/// Calling `set_enabled(true)` has no effect - it will NOT re-enable the `Ui` once disabled.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```
|
||||||
|
/// # let ui = &mut egui::Ui::__test();
|
||||||
|
/// # let mut enabled = true;
|
||||||
|
/// ui.group(|ui|{
|
||||||
|
/// ui.checkbox(&mut enabled, "Enable subsection");
|
||||||
|
/// ui.set_enabled(enabled);
|
||||||
|
/// if ui.button("Button that is not always clickable").clicked() {
|
||||||
|
/// /* … */
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
pub fn set_enabled(&mut self, enabled: bool) {
|
||||||
|
self.enabled &= enabled;
|
||||||
|
if self.enabled {
|
||||||
|
self.painter.set_fade_to_color(None);
|
||||||
|
} else {
|
||||||
|
self.painter
|
||||||
|
.set_fade_to_color(Some(self.visuals().window_fill()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn layout(&self) -> &Layout {
|
pub fn layout(&self) -> &Layout {
|
||||||
self.placer.layout()
|
self.placer.layout()
|
||||||
}
|
}
|
||||||
|
@ -427,6 +466,7 @@ impl Ui {
|
||||||
id,
|
id,
|
||||||
rect,
|
rect,
|
||||||
sense,
|
sense,
|
||||||
|
self.enabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,8 @@ impl Button {
|
||||||
|
|
||||||
/// If you set this to `false`, the button will be grayed out and un-clickable.
|
/// If you set this to `false`, the button will be grayed out and un-clickable.
|
||||||
/// `enabled(false)` has the same effect as calling `sense(Sense::hover())`.
|
/// `enabled(false)` has the same effect as calling `sense(Sense::hover())`.
|
||||||
|
///
|
||||||
|
/// This is a convenience for [`Ui::set_enabled`].
|
||||||
pub fn enabled(mut self, enabled: bool) -> Self {
|
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||||
if !enabled {
|
if !enabled {
|
||||||
self.sense = Sense::hover();
|
self.sense = Sense::hover();
|
||||||
|
@ -76,8 +78,8 @@ impl Button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for Button {
|
impl Button {
|
||||||
fn ui(self, ui: &mut Ui) -> Response {
|
fn enabled_ui(self, ui: &mut Ui) -> Response {
|
||||||
let Button {
|
let Button {
|
||||||
text,
|
text,
|
||||||
text_color,
|
text_color,
|
||||||
|
@ -136,6 +138,22 @@ impl Widget for Button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Widget for Button {
|
||||||
|
fn ui(self, ui: &mut Ui) -> Response {
|
||||||
|
let button_enabled = self.sense != Sense::hover();
|
||||||
|
if button_enabled || !ui.enabled() {
|
||||||
|
self.enabled_ui(ui)
|
||||||
|
} else {
|
||||||
|
// We need get a temporary disabled `Ui` to get that grayed out look:
|
||||||
|
ui.wrap(|ui| {
|
||||||
|
ui.set_enabled(false);
|
||||||
|
self.enabled_ui(ui)
|
||||||
|
})
|
||||||
|
.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// TODO: allow checkbox without a text label
|
// TODO: allow checkbox without a text label
|
||||||
|
|
|
@ -160,15 +160,15 @@ impl Label {
|
||||||
..
|
..
|
||||||
} = *self;
|
} = *self;
|
||||||
|
|
||||||
let text_color = self.text_color.unwrap_or_else(|| {
|
let text_color = if let Some(text_color) = self.text_color {
|
||||||
if strong {
|
text_color
|
||||||
ui.visuals().strong_text_color()
|
} else if strong {
|
||||||
} else if weak {
|
ui.visuals().strong_text_color()
|
||||||
ui.visuals().weak_text_color()
|
} else if weak {
|
||||||
} else {
|
ui.visuals().weak_text_color()
|
||||||
ui.visuals().text_color()
|
} else {
|
||||||
}
|
ui.visuals().text_color()
|
||||||
});
|
};
|
||||||
|
|
||||||
if code {
|
if code {
|
||||||
background_color = ui.visuals().code_bg_color;
|
background_color = ui.visuals().code_bg_color;
|
||||||
|
|
|
@ -48,16 +48,19 @@ impl Widget for SelectableLabel {
|
||||||
|
|
||||||
if selected || response.hovered() {
|
if selected || response.hovered() {
|
||||||
let rect = rect.expand(visuals.expansion);
|
let rect = rect.expand(visuals.expansion);
|
||||||
|
|
||||||
let fill = if selected {
|
let fill = if selected {
|
||||||
ui.visuals().selection.bg_fill
|
ui.visuals().selection.bg_fill
|
||||||
} else {
|
} else {
|
||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let stroke = if selected {
|
let stroke = if selected {
|
||||||
ui.visuals().selection.stroke
|
ui.visuals().selection.stroke
|
||||||
} else {
|
} else {
|
||||||
visuals.bg_stroke
|
visuals.bg_stroke
|
||||||
};
|
};
|
||||||
|
|
||||||
let corner_radius = 2.0;
|
let corner_radius = 2.0;
|
||||||
ui.painter().rect(rect, corner_radius, fill, stroke);
|
ui.painter().rect(rect, corner_radius, fill, stroke);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,20 +51,24 @@ pub fn drop_target<R>(
|
||||||
|
|
||||||
let style = if is_being_dragged && can_accept_what_is_being_dragged && response.hovered() {
|
let style = if is_being_dragged && can_accept_what_is_being_dragged && response.hovered() {
|
||||||
ui.visuals().widgets.active
|
ui.visuals().widgets.active
|
||||||
} else if is_being_dragged && can_accept_what_is_being_dragged {
|
|
||||||
ui.visuals().widgets.inactive
|
|
||||||
} else if is_being_dragged && !can_accept_what_is_being_dragged {
|
|
||||||
ui.visuals().widgets.disabled
|
|
||||||
} else {
|
} else {
|
||||||
ui.visuals().widgets.inactive
|
ui.visuals().widgets.inactive
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut fill = style.bg_fill;
|
||||||
|
let mut stroke = style.bg_stroke;
|
||||||
|
if is_being_dragged && !can_accept_what_is_being_dragged {
|
||||||
|
// gray out:
|
||||||
|
fill = color::tint_color_towards(fill, ui.visuals().window_fill());
|
||||||
|
stroke.color = color::tint_color_towards(stroke.color, ui.visuals().window_fill());
|
||||||
|
}
|
||||||
|
|
||||||
ui.painter().set(
|
ui.painter().set(
|
||||||
where_to_put_background,
|
where_to_put_background,
|
||||||
Shape::Rect {
|
Shape::Rect {
|
||||||
corner_radius: style.corner_radius,
|
corner_radius: style.corner_radius,
|
||||||
fill: style.bg_fill,
|
fill,
|
||||||
stroke: style.bg_stroke,
|
stroke,
|
||||||
rect,
|
rect,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -83,9 +83,12 @@ fn toggle_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
|
||||||
|
|
||||||
pub fn demo(ui: &mut egui::Ui, on: &mut bool) {
|
pub fn demo(ui: &mut egui::Ui, on: &mut bool) {
|
||||||
ui.horizontal_wrapped_for_text(egui::TextStyle::Button, |ui| {
|
ui.horizontal_wrapped_for_text(egui::TextStyle::Button, |ui| {
|
||||||
ui.label("It's easy to create your own widgets!");
|
|
||||||
ui.label("This toggle switch is just one function and 15 lines of code:");
|
|
||||||
toggle(ui, on).on_hover_text("Click to toggle");
|
toggle(ui, on).on_hover_text("Click to toggle");
|
||||||
ui.add(crate::__egui_github_link_file!());
|
ui.add(crate::__egui_github_link_file!());
|
||||||
});
|
})
|
||||||
|
.1
|
||||||
|
.on_hover_text(
|
||||||
|
"It's easy to create your own widgets!\n\
|
||||||
|
This toggle switch is just one function and 20 lines of code.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ enum Enum {
|
||||||
|
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct WidgetGallery {
|
pub struct WidgetGallery {
|
||||||
|
enabled: bool,
|
||||||
boolean: bool,
|
boolean: bool,
|
||||||
radio: Enum,
|
radio: Enum,
|
||||||
scalar: f32,
|
scalar: f32,
|
||||||
|
@ -18,6 +19,7 @@ pub struct WidgetGallery {
|
||||||
impl Default for WidgetGallery {
|
impl Default for WidgetGallery {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
enabled: true,
|
||||||
boolean: false,
|
boolean: false,
|
||||||
radio: Enum::First,
|
radio: Enum::First,
|
||||||
scalar: 42.0,
|
scalar: 42.0,
|
||||||
|
@ -46,6 +48,7 @@ impl super::Demo for WidgetGallery {
|
||||||
impl super::View for WidgetGallery {
|
impl super::View for WidgetGallery {
|
||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
let Self {
|
let Self {
|
||||||
|
enabled,
|
||||||
boolean,
|
boolean,
|
||||||
radio,
|
radio,
|
||||||
scalar,
|
scalar,
|
||||||
|
@ -53,6 +56,12 @@ impl super::View for WidgetGallery {
|
||||||
color,
|
color,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.radio_value(enabled, true, "Enabled");
|
||||||
|
ui.radio_value(enabled, false, "Disabled");
|
||||||
|
});
|
||||||
|
ui.set_enabled(*enabled);
|
||||||
|
|
||||||
let grid = egui::Grid::new("my_grid")
|
let grid = egui::Grid::new("my_grid")
|
||||||
.striped(true)
|
.striped(true)
|
||||||
.spacing([40.0, 4.0]);
|
.spacing([40.0, 4.0]);
|
||||||
|
@ -65,7 +74,7 @@ impl super::View for WidgetGallery {
|
||||||
ui.add(egui::Hyperlink::new("https://github.com/emilk/egui").text(" egui home page"));
|
ui.add(egui::Hyperlink::new("https://github.com/emilk/egui").text(" egui home page"));
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
ui.label("Text Input:");
|
ui.label("TextEdit:");
|
||||||
ui.add(egui::TextEdit::singleline(string).hint_text("Write something here"));
|
ui.add(egui::TextEdit::singleline(string).hint_text("Write something here"));
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
|
@ -73,7 +82,7 @@ impl super::View for WidgetGallery {
|
||||||
ui.checkbox(boolean, "Checkbox");
|
ui.checkbox(boolean, "Checkbox");
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
ui.label("Radio buttons:");
|
ui.label("RadioButton:");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.radio_value(radio, Enum::First, "First");
|
ui.radio_value(radio, Enum::First, "First");
|
||||||
ui.radio_value(radio, Enum::Second, "Second");
|
ui.radio_value(radio, Enum::Second, "Second");
|
||||||
|
@ -143,6 +152,10 @@ impl super::View for WidgetGallery {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
|
ui.label("Custom widget");
|
||||||
|
super::toggle_switch::demo(ui, boolean);
|
||||||
|
ui.end_row();
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
|
@ -134,8 +134,5 @@ impl Widgets {
|
||||||
|
|
||||||
ui.label("Multiline text input:");
|
ui.label("Multiline text input:");
|
||||||
ui.text_edit_multiline(&mut self.multiline_text_input);
|
ui.text_edit_multiline(&mut self.multiline_text_input);
|
||||||
|
|
||||||
ui.separator();
|
|
||||||
super::toggle_switch::demo(ui, &mut self.toggle_switch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub struct WindowOptions {
|
||||||
collapsible: bool,
|
collapsible: bool,
|
||||||
resizable: bool,
|
resizable: bool,
|
||||||
scroll: bool,
|
scroll: bool,
|
||||||
|
disabled_time: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WindowOptions {
|
impl Default for WindowOptions {
|
||||||
|
@ -18,6 +19,7 @@ impl Default for WindowOptions {
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
scroll: false,
|
scroll: false,
|
||||||
|
disabled_time: f64::NEG_INFINITY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,15 +38,22 @@ impl super::Demo for WindowOptions {
|
||||||
collapsible,
|
collapsible,
|
||||||
resizable,
|
resizable,
|
||||||
scroll,
|
scroll,
|
||||||
|
disabled_time,
|
||||||
} = self.clone();
|
} = self.clone();
|
||||||
|
|
||||||
|
let enabled = ctx.input().time - disabled_time > 2.0;
|
||||||
|
if !enabled {
|
||||||
|
ctx.request_repaint();
|
||||||
|
}
|
||||||
|
|
||||||
use super::View;
|
use super::View;
|
||||||
let mut window = egui::Window::new(title)
|
let mut window = egui::Window::new(title)
|
||||||
.id(egui::Id::new("demo_window_options")) // required since we change the title
|
.id(egui::Id::new("demo_window_options")) // required since we change the title
|
||||||
.resizable(resizable)
|
.resizable(resizable)
|
||||||
.collapsible(collapsible)
|
.collapsible(collapsible)
|
||||||
.title_bar(title_bar)
|
.title_bar(title_bar)
|
||||||
.scroll(scroll);
|
.scroll(scroll)
|
||||||
|
.enabled(enabled);
|
||||||
if closable {
|
if closable {
|
||||||
window = window.open(open);
|
window = window.open(open);
|
||||||
}
|
}
|
||||||
|
@ -63,6 +72,7 @@ impl super::View for WindowOptions {
|
||||||
collapsible,
|
collapsible,
|
||||||
resizable,
|
resizable,
|
||||||
scroll,
|
scroll,
|
||||||
|
disabled_time,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
@ -77,5 +87,9 @@ impl super::View for WindowOptions {
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
ui.add(crate::__egui_github_link_file!());
|
ui.add(crate::__egui_github_link_file!());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ui.button("Disable for 2 seconds").clicked() {
|
||||||
|
*disabled_time = ui.input().time;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -682,3 +682,30 @@ impl From<Hsva> for HsvaGamma {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Cheap and ugly.
|
||||||
|
/// Made for graying out disabled `Ui`:s.
|
||||||
|
pub fn tint_color_towards(color: Color32, target: Color32) -> Color32 {
|
||||||
|
let [mut r, mut g, mut b, mut a] = color.to_array();
|
||||||
|
|
||||||
|
if a == 0 {
|
||||||
|
r /= 2;
|
||||||
|
g /= 2;
|
||||||
|
b /= 2;
|
||||||
|
} else if a < 170 {
|
||||||
|
// Cheapish and looks ok.
|
||||||
|
// Works for e.g. grid stripes.
|
||||||
|
let div = (2 * 255 / a as i32) as u8;
|
||||||
|
r = r / 2 + target.r() / div;
|
||||||
|
g = g / 2 + target.g() / div;
|
||||||
|
b = b / 2 + target.b() / div;
|
||||||
|
a /= 2;
|
||||||
|
} else {
|
||||||
|
r = r / 2 + target.r() / 2;
|
||||||
|
g = g / 2 + target.g() / 2;
|
||||||
|
b = b / 2 + target.b() / 2;
|
||||||
|
}
|
||||||
|
Color32::from_rgba_premultiplied(r, g, b, a)
|
||||||
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ mod mesh;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
mod shadow;
|
mod shadow;
|
||||||
mod shape;
|
mod shape;
|
||||||
|
pub mod shape_transform;
|
||||||
pub mod stats;
|
pub mod stats;
|
||||||
mod stroke;
|
mod stroke;
|
||||||
pub mod tessellator;
|
pub mod tessellator;
|
||||||
|
|
35
epaint/src/shape_transform.rs
Normal file
35
epaint/src/shape_transform.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub fn adjust_colors(shape: &mut Shape, adjust_color: &impl Fn(&mut Color32)) {
|
||||||
|
match shape {
|
||||||
|
Shape::Noop => {}
|
||||||
|
Shape::Vec(shapes) => {
|
||||||
|
for shape in shapes {
|
||||||
|
adjust_colors(shape, adjust_color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Shape::Circle { fill, stroke, .. } => {
|
||||||
|
adjust_color(fill);
|
||||||
|
adjust_color(&mut stroke.color);
|
||||||
|
}
|
||||||
|
Shape::LineSegment { stroke, .. } => {
|
||||||
|
adjust_color(&mut stroke.color);
|
||||||
|
}
|
||||||
|
Shape::Path { fill, stroke, .. } => {
|
||||||
|
adjust_color(fill);
|
||||||
|
adjust_color(&mut stroke.color);
|
||||||
|
}
|
||||||
|
Shape::Rect { fill, stroke, .. } => {
|
||||||
|
adjust_color(fill);
|
||||||
|
adjust_color(&mut stroke.color);
|
||||||
|
}
|
||||||
|
Shape::Text { color, .. } => {
|
||||||
|
adjust_color(color);
|
||||||
|
}
|
||||||
|
Shape::Mesh(mesh) => {
|
||||||
|
for v in &mut mesh.vertices {
|
||||||
|
adjust_color(&mut v.color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue