mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 06:10:06 -04:00
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:
@@ -45,6 +45,7 @@ pub struct Area {
|
||||
pub(crate) id: Id,
|
||||
movable: bool,
|
||||
interactable: bool,
|
||||
enabled: bool,
|
||||
order: Order,
|
||||
default_pos: Option<Pos2>,
|
||||
new_pos: Option<Pos2>,
|
||||
@@ -56,6 +57,7 @@ impl Area {
|
||||
id: Id::new(id_source),
|
||||
movable: true,
|
||||
interactable: true,
|
||||
enabled: true,
|
||||
order: Order::Middle,
|
||||
default_pos: None,
|
||||
new_pos: None,
|
||||
@@ -71,6 +73,15 @@ impl Area {
|
||||
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?
|
||||
pub fn movable(mut self, movable: bool) -> Self {
|
||||
self.movable = movable;
|
||||
@@ -78,8 +89,12 @@ impl Area {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
pub fn is_movable(&self) -> bool {
|
||||
self.movable
|
||||
self.movable && self.enabled
|
||||
}
|
||||
|
||||
/// If false, clicks goes straight through to what is behind us.
|
||||
@@ -121,6 +136,7 @@ pub(crate) struct Prepared {
|
||||
layer_id: LayerId,
|
||||
state: State,
|
||||
movable: bool,
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl Area {
|
||||
@@ -130,6 +146,7 @@ impl Area {
|
||||
movable,
|
||||
order,
|
||||
interactable,
|
||||
enabled,
|
||||
default_pos,
|
||||
new_pos,
|
||||
} = self;
|
||||
@@ -149,6 +166,7 @@ impl Area {
|
||||
layer_id,
|
||||
state,
|
||||
movable,
|
||||
enabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,13 +232,15 @@ impl Prepared {
|
||||
clip_rect = clip_rect.intersect(central_area);
|
||||
}
|
||||
|
||||
Ui::new(
|
||||
let mut ui = Ui::new(
|
||||
ctx.clone(),
|
||||
self.layer_id,
|
||||
self.layer_id.id,
|
||||
max_rect,
|
||||
clip_rect,
|
||||
)
|
||||
);
|
||||
ui.set_enabled(self.enabled);
|
||||
ui
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)] // intentional to swallow up `content_ui`.
|
||||
@@ -229,6 +249,7 @@ impl Prepared {
|
||||
layer_id,
|
||||
mut state,
|
||||
movable,
|
||||
enabled,
|
||||
} = self;
|
||||
|
||||
state.size = content_ui.min_rect().size();
|
||||
@@ -247,6 +268,7 @@ impl Prepared {
|
||||
interact_id,
|
||||
state.rect(),
|
||||
sense,
|
||||
enabled,
|
||||
);
|
||||
|
||||
if move_response.dragged() && movable {
|
||||
|
||||
@@ -23,7 +23,7 @@ impl Frame {
|
||||
Self {
|
||||
margin: Vec2::new(8.0, 6.0),
|
||||
corner_radius: 4.0,
|
||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
||||
stroke: style.visuals.window_stroke(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,8 @@ impl Frame {
|
||||
Self {
|
||||
margin: Vec2::new(8.0, 2.0),
|
||||
corner_radius: 0.0,
|
||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
||||
fill: style.visuals.window_fill(),
|
||||
stroke: style.visuals.window_stroke(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ impl Frame {
|
||||
Self {
|
||||
margin: Vec2::new(8.0, 8.0),
|
||||
corner_radius: 0.0,
|
||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
||||
fill: style.visuals.window_fill(),
|
||||
stroke: Default::default(),
|
||||
..Default::default()
|
||||
}
|
||||
@@ -53,8 +53,8 @@ impl Frame {
|
||||
margin: style.spacing.window_padding,
|
||||
corner_radius: style.visuals.window_corner_radius,
|
||||
shadow: style.visuals.window_shadow,
|
||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
||||
fill: style.visuals.window_fill(),
|
||||
stroke: style.visuals.window_stroke(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ impl Frame {
|
||||
margin: Vec2::splat(1.0),
|
||||
corner_radius: 2.0,
|
||||
shadow: Shadow::small(),
|
||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
||||
fill: style.visuals.window_fill(),
|
||||
stroke: style.visuals.window_stroke(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ impl Frame {
|
||||
margin: style.spacing.window_padding,
|
||||
corner_radius: 5.0,
|
||||
shadow: Shadow::small(),
|
||||
fill: style.visuals.widgets.noninteractive.bg_fill,
|
||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
||||
fill: style.visuals.window_fill(),
|
||||
stroke: style.visuals.window_stroke(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ impl Frame {
|
||||
margin: Vec2::new(10.0, 10.0),
|
||||
corner_radius: 5.0,
|
||||
fill: Color32::from_black_alpha(250),
|
||||
stroke: style.visuals.widgets.noninteractive.bg_stroke,
|
||||
stroke: style.visuals.window_stroke(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,12 @@ impl<'open> Window<'open> {
|
||||
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))`
|
||||
/// Not sure this is a good interface for this.
|
||||
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
|
||||
|| collapsing_header::State::is_open(ctx, collapsing_id).unwrap_or_default();
|
||||
let possible = PossibleInteractions {
|
||||
movable: area.is_movable(),
|
||||
resizable: resize.is_resizable() && is_maximized,
|
||||
movable: area.is_enabled() && area.is_movable(),
|
||||
resizable: area.is_enabled() && resize.is_resizable() && is_maximized,
|
||||
};
|
||||
|
||||
let area = area.movable(false); // We move it manually
|
||||
|
||||
@@ -218,6 +218,7 @@ impl CtxRef {
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/// Use `ui.interact` instead
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn interact(
|
||||
&self,
|
||||
clip_rect: Rect,
|
||||
@@ -226,6 +227,7 @@ impl CtxRef {
|
||||
id: Id,
|
||||
rect: Rect,
|
||||
sense: Sense,
|
||||
enabled: bool,
|
||||
) -> 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 interact_rect = rect.expand2(
|
||||
@@ -234,7 +236,7 @@ impl CtxRef {
|
||||
.at_most(Vec2::splat(5.0)),
|
||||
); // make it easier to click
|
||||
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`.
|
||||
@@ -244,8 +246,11 @@ impl CtxRef {
|
||||
id: Id,
|
||||
rect: Rect,
|
||||
sense: Sense,
|
||||
enabled: bool,
|
||||
hovered: bool,
|
||||
) -> Response {
|
||||
let hovered = hovered && enabled; // can't even hover disabled widgets
|
||||
|
||||
let has_kb_focus = self.memory().has_kb_focus(id);
|
||||
let lost_kb_focus = self.memory().lost_kb_focus(id);
|
||||
|
||||
@@ -255,6 +260,7 @@ impl CtxRef {
|
||||
id,
|
||||
rect,
|
||||
sense,
|
||||
enabled,
|
||||
hovered,
|
||||
clicked: Default::default(),
|
||||
double_clicked: Default::default(),
|
||||
@@ -266,7 +272,7 @@ impl CtxRef {
|
||||
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:
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@ pub struct Painter {
|
||||
/// Everything painted in this `Painter` will be clipped against this.
|
||||
/// This means nothing outside of this rectangle will be visible on screen.
|
||||
clip_rect: Rect,
|
||||
|
||||
/// 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 {
|
||||
@@ -30,6 +34,7 @@ impl Painter {
|
||||
ctx,
|
||||
layer_id,
|
||||
clip_rect,
|
||||
fade_to_color: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +44,7 @@ impl Painter {
|
||||
ctx: self.ctx,
|
||||
layer_id,
|
||||
clip_rect: self.clip_rect,
|
||||
fade_to_color: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +53,11 @@ impl Painter {
|
||||
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`.
|
||||
///
|
||||
/// The clip-rect of the returned `Painter` will be the intersection
|
||||
@@ -106,10 +117,17 @@ impl Painter {
|
||||
|
||||
/// ## Low level
|
||||
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.
|
||||
/// Can be used for free painting.
|
||||
/// 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
|
||||
.graphics()
|
||||
.list(self.layer_id)
|
||||
@@ -119,8 +137,14 @@ impl Painter {
|
||||
/// Add many shapes at once.
|
||||
///
|
||||
/// 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 self.fade_to_color.is_some() {
|
||||
for shape in &mut shapes {
|
||||
self.transform_shape(shape);
|
||||
}
|
||||
}
|
||||
|
||||
self.ctx
|
||||
.graphics()
|
||||
.list(self.layer_id)
|
||||
@@ -129,7 +153,8 @@ impl Painter {
|
||||
}
|
||||
|
||||
/// 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
|
||||
.graphics()
|
||||
.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).
|
||||
pub sense: Sense,
|
||||
|
||||
/// Was the widget enabled?
|
||||
/// If `false`, there was no interaction attempted (not even hover).
|
||||
pub(crate) enabled: bool,
|
||||
|
||||
// OUT:
|
||||
/// The pointer is hovering above this widget or the widget was clicked/tapped this frame.
|
||||
pub(crate) hovered: bool,
|
||||
@@ -68,6 +72,7 @@ impl std::fmt::Debug for Response {
|
||||
id,
|
||||
rect,
|
||||
sense,
|
||||
enabled,
|
||||
hovered,
|
||||
clicked,
|
||||
double_clicked,
|
||||
@@ -83,6 +88,7 @@ impl std::fmt::Debug for Response {
|
||||
.field("id", id)
|
||||
.field("rect", rect)
|
||||
.field("sense", sense)
|
||||
.field("enabled", enabled)
|
||||
.field("hovered", hovered)
|
||||
.field("clicked", clicked)
|
||||
.field("double_clicked", double_clicked)
|
||||
@@ -117,6 +123,13 @@ impl Response {
|
||||
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.
|
||||
pub fn hovered(&self) -> bool {
|
||||
self.hovered
|
||||
@@ -208,8 +221,14 @@ impl Response {
|
||||
/// if response.clicked() { /* … */ }
|
||||
/// ```
|
||||
pub fn interact(&self, sense: Sense) -> Self {
|
||||
self.ctx
|
||||
.interact_with_hovered(self.layer_id, self.id, self.rect, sense, self.hovered)
|
||||
self.ctx.interact_with_hovered(
|
||||
self.layer_id,
|
||||
self.id,
|
||||
self.rect,
|
||||
sense,
|
||||
self.enabled,
|
||||
self.hovered,
|
||||
)
|
||||
}
|
||||
|
||||
/// Move the scroll to this UI with the specified alignment.
|
||||
@@ -247,6 +266,7 @@ impl Response {
|
||||
id: self.id,
|
||||
rect: self.rect.union(other.rect),
|
||||
sense: self.sense.union(other.sense),
|
||||
enabled: self.enabled || other.enabled,
|
||||
hovered: self.hovered || other.hovered,
|
||||
clicked: [
|
||||
self.clicked[0] || other.clicked[0],
|
||||
|
||||
@@ -184,12 +184,20 @@ impl Visuals {
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
@@ -210,8 +218,6 @@ pub struct Widgets {
|
||||
/// * `noninteractive.bg_fill` is the background color of windows.
|
||||
/// * `noninteractive.fg_stroke` is the normal text color.
|
||||
pub noninteractive: WidgetVisuals,
|
||||
/// The style of a disabled button.
|
||||
pub disabled: WidgetVisuals,
|
||||
/// The style of an interactive widget, such as a button, at rest.
|
||||
pub inactive: WidgetVisuals,
|
||||
/// The style of an interactive widget while you hover it.
|
||||
@@ -224,8 +230,6 @@ impl Widgets {
|
||||
pub fn style(&self, response: &Response) -> &WidgetVisuals {
|
||||
if response.is_pointer_button_down_on() || response.has_kb_focus {
|
||||
&self.active
|
||||
} else if response.sense == crate::Sense::hover() {
|
||||
&self.disabled
|
||||
} else if response.hovered() {
|
||||
&self.hovered
|
||||
} else {
|
||||
@@ -374,19 +378,12 @@ impl Widgets {
|
||||
pub fn dark() -> Self {
|
||||
Self {
|
||||
noninteractive: WidgetVisuals {
|
||||
bg_fill: Color32::from_gray(30), // window background
|
||||
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
|
||||
corner_radius: 4.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 {
|
||||
bg_fill: Color32::from_gray(70),
|
||||
bg_stroke: Default::default(),
|
||||
@@ -414,16 +411,9 @@ impl Widgets {
|
||||
pub fn light() -> Self {
|
||||
Self {
|
||||
noninteractive: WidgetVisuals {
|
||||
bg_fill: Color32::from_gray(220), // window background
|
||||
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
|
||||
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.
|
||||
fg_stroke: Stroke::new(1.0, Color32::from_gray(70)), // normal text color
|
||||
corner_radius: 4.0,
|
||||
expansion: 0.0,
|
||||
},
|
||||
@@ -542,7 +532,6 @@ impl Widgets {
|
||||
active,
|
||||
hovered,
|
||||
inactive,
|
||||
disabled,
|
||||
noninteractive,
|
||||
} = self;
|
||||
|
||||
@@ -550,10 +539,6 @@ impl Widgets {
|
||||
ui.label("The style of a widget that you cannot interact with.");
|
||||
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.label("The style of an interactive widget, such as a button, at rest.");
|
||||
inactive.ui(ui)
|
||||
|
||||
@@ -46,6 +46,10 @@ pub struct Ui {
|
||||
|
||||
/// Handles the `Ui` size and the placement of new widgets.
|
||||
placer: Placer,
|
||||
|
||||
/// If false we are unresponsive to input,
|
||||
/// and all widgets will assume a gray style.
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl Ui {
|
||||
@@ -60,6 +64,7 @@ impl Ui {
|
||||
painter: Painter::new(ctx, layer_id, clip_rect),
|
||||
style,
|
||||
placer: Placer::new(max_rect, Layout::default()),
|
||||
enabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +77,7 @@ impl Ui {
|
||||
painter: self.painter.clone(),
|
||||
style: self.style.clone(),
|
||||
placer: Placer::new(max_rect, layout),
|
||||
enabled: self.enabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +172,39 @@ impl Ui {
|
||||
&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 {
|
||||
self.placer.layout()
|
||||
}
|
||||
@@ -427,6 +466,7 @@ impl Ui {
|
||||
id,
|
||||
rect,
|
||||
sense,
|
||||
self.enabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,8 @@ impl Button {
|
||||
|
||||
/// 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())`.
|
||||
///
|
||||
/// This is a convenience for [`Ui::set_enabled`].
|
||||
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||
if !enabled {
|
||||
self.sense = Sense::hover();
|
||||
@@ -76,8 +78,8 @@ impl Button {
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Button {
|
||||
fn ui(self, ui: &mut Ui) -> Response {
|
||||
impl Button {
|
||||
fn enabled_ui(self, ui: &mut Ui) -> Response {
|
||||
let Button {
|
||||
text,
|
||||
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
|
||||
|
||||
@@ -160,15 +160,15 @@ impl Label {
|
||||
..
|
||||
} = *self;
|
||||
|
||||
let text_color = self.text_color.unwrap_or_else(|| {
|
||||
if strong {
|
||||
ui.visuals().strong_text_color()
|
||||
} else if weak {
|
||||
ui.visuals().weak_text_color()
|
||||
} else {
|
||||
ui.visuals().text_color()
|
||||
}
|
||||
});
|
||||
let text_color = if let Some(text_color) = self.text_color {
|
||||
text_color
|
||||
} else if strong {
|
||||
ui.visuals().strong_text_color()
|
||||
} else if weak {
|
||||
ui.visuals().weak_text_color()
|
||||
} else {
|
||||
ui.visuals().text_color()
|
||||
};
|
||||
|
||||
if code {
|
||||
background_color = ui.visuals().code_bg_color;
|
||||
|
||||
@@ -48,16 +48,19 @@ impl Widget for SelectableLabel {
|
||||
|
||||
if selected || response.hovered() {
|
||||
let rect = rect.expand(visuals.expansion);
|
||||
|
||||
let fill = if selected {
|
||||
ui.visuals().selection.bg_fill
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let stroke = if selected {
|
||||
ui.visuals().selection.stroke
|
||||
} else {
|
||||
visuals.bg_stroke
|
||||
};
|
||||
|
||||
let corner_radius = 2.0;
|
||||
ui.painter().rect(rect, corner_radius, fill, stroke);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user