Add widget ImageButton
This commit is contained in:
parent
b508f931c2
commit
18ebac116f
5 changed files with 126 additions and 20 deletions
|
@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
### Added ⭐
|
### Added ⭐
|
||||||
|
|
||||||
|
* `ImageButton` - `ui.add(ImageButton::new(...))`
|
||||||
* `ui.vertical_centered` and `ui.vertical_centered_justified`
|
* `ui.vertical_centered` and `ui.vertical_centered_justified`
|
||||||
|
|
||||||
### Changed 🔧
|
### Changed 🔧
|
||||||
|
|
|
@ -159,7 +159,7 @@ impl Visuals {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Selected text, selected elements etc
|
/// Selected text, selected elements etc
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct Selection {
|
pub struct Selection {
|
||||||
pub bg_fill: Srgba,
|
pub bg_fill: Srgba,
|
||||||
|
|
93
egui/src/widgets/button.rs
Normal file
93
egui/src/widgets/button.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ImageButton {
|
||||||
|
image: widgets::Image,
|
||||||
|
sense: Sense,
|
||||||
|
frame: bool,
|
||||||
|
selected: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImageButton {
|
||||||
|
pub fn new(texture_id: TextureId, desired_size: impl Into<Vec2>) -> Self {
|
||||||
|
Self {
|
||||||
|
image: widgets::Image::new(texture_id, desired_size),
|
||||||
|
sense: Sense::click(),
|
||||||
|
frame: true,
|
||||||
|
selected: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Select UV range. Default is (0,0) in top-left, (1,1) bottom right.
|
||||||
|
pub fn uv(mut self, uv: impl Into<Rect>) -> Self {
|
||||||
|
self.image = self.image.uv(uv);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Multiply image color with this. Default is WHITE (no tint).
|
||||||
|
pub fn tint(mut self, tint: impl Into<Srgba>) -> Self {
|
||||||
|
self.image = self.image.tint(tint);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If `true`, mark this button as "selected".
|
||||||
|
pub fn selected(mut self, selected: bool) -> Self {
|
||||||
|
self.selected = selected;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Turn off the frame
|
||||||
|
pub fn frame(mut self, frame: bool) -> Self {
|
||||||
|
self.frame = frame;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// By default, buttons senses clicks.
|
||||||
|
/// Change this to a drag-button with `Sense::drag()`.
|
||||||
|
pub fn sense(mut self, sense: Sense) -> Self {
|
||||||
|
self.sense = sense;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for ImageButton {
|
||||||
|
fn ui(self, ui: &mut Ui) -> Response {
|
||||||
|
let Self {
|
||||||
|
image,
|
||||||
|
sense,
|
||||||
|
frame,
|
||||||
|
selected,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
let button_padding = ui.style().spacing.button_padding;
|
||||||
|
let desired_size = image.desired_size() + 2.0 * button_padding;
|
||||||
|
let rect = ui.allocate_space(desired_size);
|
||||||
|
let id = ui.make_position_id();
|
||||||
|
let response = ui.interact(rect, id, sense);
|
||||||
|
|
||||||
|
if ui.clip_rect().intersects(rect) {
|
||||||
|
let visuals = ui.style().interact(&response);
|
||||||
|
|
||||||
|
if selected {
|
||||||
|
let selection = ui.style().visuals.selection;
|
||||||
|
ui.painter()
|
||||||
|
.rect(response.rect, 0.0, selection.bg_fill, selection.stroke);
|
||||||
|
} else if frame {
|
||||||
|
ui.painter().rect(
|
||||||
|
response.rect,
|
||||||
|
visuals.corner_radius,
|
||||||
|
visuals.bg_fill,
|
||||||
|
visuals.bg_stroke,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let image_rect = ui.layout().align_size_within_rect(
|
||||||
|
image.desired_size(),
|
||||||
|
response.rect.shrink2(button_padding),
|
||||||
|
);
|
||||||
|
image.paint_at(ui, image_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
response
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,29 +39,40 @@ impl Image {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for Image {
|
impl Image {
|
||||||
fn ui(self, ui: &mut Ui) -> Response {
|
pub fn desired_size(&self) -> Vec2 {
|
||||||
|
self.desired_size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paint_at(&self, ui: &mut Ui, rect: Rect) {
|
||||||
use paint::*;
|
use paint::*;
|
||||||
let Self {
|
let Self {
|
||||||
texture_id,
|
texture_id,
|
||||||
uv,
|
uv,
|
||||||
desired_size,
|
desired_size: _,
|
||||||
bg_fill,
|
bg_fill,
|
||||||
tint,
|
tint,
|
||||||
} = self;
|
} = self;
|
||||||
let rect = ui.allocate_space(desired_size);
|
|
||||||
if bg_fill != Default::default() {
|
if *bg_fill != Default::default() {
|
||||||
let mut triangles = Triangles::default();
|
let mut triangles = Triangles::default();
|
||||||
triangles.add_colored_rect(rect, bg_fill);
|
triangles.add_colored_rect(rect, *bg_fill);
|
||||||
ui.painter().add(PaintCmd::triangles(triangles));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// TODO: builder pattern for Triangles
|
|
||||||
let mut triangles = Triangles::with_texture(texture_id);
|
|
||||||
triangles.add_rect_with_uv(rect, uv, tint);
|
|
||||||
ui.painter().add(PaintCmd::triangles(triangles));
|
ui.painter().add(PaintCmd::triangles(triangles));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// TODO: builder pattern for Triangles
|
||||||
|
let mut triangles = Triangles::with_texture(*texture_id);
|
||||||
|
triangles.add_rect_with_uv(rect, *uv, *tint);
|
||||||
|
ui.painter().add(PaintCmd::triangles(triangles));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for Image {
|
||||||
|
fn ui(self, ui: &mut Ui) -> Response {
|
||||||
|
let rect = ui.allocate_space(self.desired_size);
|
||||||
|
self.paint_at(ui, rect);
|
||||||
ui.interact_hover(rect)
|
ui.interact_hover(rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,14 @@
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
mod button;
|
||||||
pub mod color_picker;
|
pub mod color_picker;
|
||||||
mod drag_value;
|
mod drag_value;
|
||||||
mod image;
|
mod image;
|
||||||
mod slider;
|
mod slider;
|
||||||
pub(crate) mod text_edit;
|
pub(crate) mod text_edit;
|
||||||
|
|
||||||
pub use {drag_value::DragValue, image::Image, slider::*, text_edit::*};
|
pub use {button::*, drag_value::DragValue, image::Image, slider::*, text_edit::*};
|
||||||
|
|
||||||
use paint::*;
|
use paint::*;
|
||||||
|
|
||||||
|
@ -380,12 +381,6 @@ impl Widget for Button {
|
||||||
small,
|
small,
|
||||||
frame,
|
frame,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let mut button_padding = ui.style().spacing.button_padding;
|
|
||||||
if small {
|
|
||||||
button_padding.y = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let font = &ui.fonts()[text_style];
|
let font = &ui.fonts()[text_style];
|
||||||
|
|
||||||
let single_line = ui.layout().is_horizontal();
|
let single_line = ui.layout().is_horizontal();
|
||||||
|
@ -395,10 +390,16 @@ impl Widget for Button {
|
||||||
font.layout_multiline(text, ui.available_width())
|
font.layout_multiline(text, ui.available_width())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut button_padding = ui.style().spacing.button_padding;
|
||||||
|
if small {
|
||||||
|
button_padding.y = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
let mut desired_size = galley.size + 2.0 * button_padding;
|
let mut desired_size = galley.size + 2.0 * button_padding;
|
||||||
if !small {
|
if !small {
|
||||||
desired_size.y = desired_size.y.at_least(ui.style().spacing.interact_size.y);
|
desired_size.y = desired_size.y.at_least(ui.style().spacing.interact_size.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rect = ui.allocate_space(desired_size);
|
let rect = ui.allocate_space(desired_size);
|
||||||
|
|
||||||
let id = ui.make_position_id();
|
let id = ui.make_position_id();
|
||||||
|
|
Loading…
Reference in a new issue