mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add ImageFrame widget
This commit is contained in:
parent
8a3ce232fa
commit
66ebdb2355
@ -12,6 +12,7 @@ pub use event::Event;
|
||||
pub use graphic::Graphic;
|
||||
pub use scale::{Scale, ScaleMode};
|
||||
pub use widgets::{
|
||||
image_frame::ImageFrame,
|
||||
image_slider::ImageSlider,
|
||||
ingame::{Ingame, IngameAnchor, Ingameable},
|
||||
toggle_button::ToggleButton,
|
||||
|
321
voxygen/src/ui/widgets/image_frame.rs
Normal file
321
voxygen/src/ui/widgets/image_frame.rs
Normal file
@ -0,0 +1,321 @@
|
||||
//! A widget for selecting a single value along some linear range.
|
||||
use conrod_core::{
|
||||
builder_methods, image,
|
||||
position::Range,
|
||||
utils,
|
||||
widget::{self, Image, Rectangle},
|
||||
widget_ids, Color, Colorable, Positionable, Rect, Sizeable, UiCell, Widget, WidgetCommon,
|
||||
};
|
||||
|
||||
/// Linear value selection.
|
||||
///
|
||||
/// If the slider's width is greater than its height, it will automatically become a horizontal
|
||||
/// slider, otherwise it will be a vertical slider.
|
||||
///
|
||||
/// Its reaction is triggered if the value is updated or if the mouse button is released while
|
||||
/// the cursor is above the rectangle.
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct ImageFrame {
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
// TODO: use type that is not just an array
|
||||
// Edge images [t, b, r, l]
|
||||
edges: [image::Id; 4],
|
||||
edge_src_rects: [Option<Rect>; 4],
|
||||
// Corner images [tr, tl, br, bl]
|
||||
corners: [image::Id; 4],
|
||||
corner_src_rects: [Option<Rect>; 4],
|
||||
// Center
|
||||
center: Center,
|
||||
// Thickness of the frame border, determines the size used for the edge and corner images
|
||||
border_size: BorderSize,
|
||||
// Color to apply to all images making up the image frame
|
||||
color: Option<Color>,
|
||||
// TODO: would it be useful to have an optional close button be a part of this?
|
||||
}
|
||||
|
||||
enum Center {
|
||||
Plain(Color),
|
||||
Image(image::Id, Option<Rect>),
|
||||
}
|
||||
impl From<Color> for Center {
|
||||
fn from(color: Color) -> Self {
|
||||
Center::Plain(color)
|
||||
}
|
||||
}
|
||||
impl From<image::Id> for Center {
|
||||
fn from(image: image::Id) -> Self {
|
||||
Center::Image(image, None)
|
||||
}
|
||||
}
|
||||
impl From<(image::Id, Rect)> for Center {
|
||||
fn from((image, src_rect): (image::Id, Rect)) -> Self {
|
||||
Center::Image(image, Some(src_rect))
|
||||
}
|
||||
}
|
||||
|
||||
struct BorderSize {
|
||||
top: f64,
|
||||
bottom: f64,
|
||||
right: f64,
|
||||
left: f64,
|
||||
}
|
||||
impl From<f64> for BorderSize {
|
||||
fn from(width: f64) -> Self {
|
||||
BorderSize {
|
||||
top: width,
|
||||
bottom: width,
|
||||
right: width,
|
||||
left: width,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<[f64; 2]> for BorderSize {
|
||||
fn from([vertical, horizontal]: [f64; 2]) -> Self {
|
||||
BorderSize {
|
||||
top: horizontal,
|
||||
bottom: horizontal,
|
||||
right: vertical,
|
||||
left: vertical,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<[f64; 4]> for BorderSize {
|
||||
fn from(vals: [f64; 4]) -> Self {
|
||||
BorderSize {
|
||||
top: vals[0],
|
||||
bottom: vals[1],
|
||||
right: vals[2],
|
||||
left: vals[3],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
center_plain,
|
||||
center_image,
|
||||
right,
|
||||
top_right,
|
||||
top,
|
||||
top_left,
|
||||
left,
|
||||
bottom_left,
|
||||
bottom,
|
||||
bottom_right,
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the state of the ImageFrame widget.
|
||||
pub struct State {
|
||||
ids: Ids,
|
||||
}
|
||||
|
||||
impl ImageFrame {
|
||||
fn new(
|
||||
edges: [image::Id; 4],
|
||||
corners: [image::Id; 4],
|
||||
center: impl Into<Center>,
|
||||
border_size: impl Into<BorderSize>,
|
||||
) -> Self {
|
||||
Self {
|
||||
common: widget::CommonBuilder::default(),
|
||||
edges,
|
||||
edge_src_rects: [None; 4],
|
||||
corners,
|
||||
corner_src_rects: [None; 4],
|
||||
center: center.into(),
|
||||
border_size: border_size.into(),
|
||||
color: None,
|
||||
}
|
||||
}
|
||||
|
||||
builder_methods! {
|
||||
pub edge_src_rects { edge_src_rects = [Option<Rect>; 4] }
|
||||
pub corner_src_rects { corner_src_rects = [Option<Rect>; 4] }
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for ImageFrame {
|
||||
type State = State;
|
||||
type Style = ();
|
||||
type Event = ();
|
||||
|
||||
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
||||
State {
|
||||
ids: Ids::new(id_gen),
|
||||
}
|
||||
}
|
||||
|
||||
fn style(&self) -> Self::Style {
|
||||
()
|
||||
}
|
||||
|
||||
/// Update the state of the ImageFrame
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs {
|
||||
id,
|
||||
state,
|
||||
rect,
|
||||
ui,
|
||||
..
|
||||
} = args;
|
||||
|
||||
let (frame_w, frame_h) = rect.w_h();
|
||||
|
||||
let t_height = self.border_size.top.min(frame_h);
|
||||
let b_height = self.border_size.bottom.min(frame_h);
|
||||
let r_width = self.border_size.right.min(frame_w);
|
||||
let l_width = self.border_size.left.min(frame_w);
|
||||
let inner_width = (frame_w - r_width - l_width).max(0.0);
|
||||
let inner_height = (frame_h - t_height - b_height).max(0.0);
|
||||
|
||||
let r_rect = Rect::from_xy_dim(
|
||||
[rect.x() + (inner_width + r_width) / 2.0, rect.y()],
|
||||
[r_width, inner_height],
|
||||
);
|
||||
let tr_rect = Rect::from_xy_dim(
|
||||
[
|
||||
rect.x() + (inner_width + r_width) / 2.0,
|
||||
rect.y() + (inner_height + t_height) / 2.0,
|
||||
],
|
||||
[r_width, t_height],
|
||||
);
|
||||
let t_rect = Rect::from_xy_dim(
|
||||
[rect.x(), rect.y() + (inner_height + t_height) / 2.0],
|
||||
[inner_width, t_height],
|
||||
);
|
||||
let tl_rect = Rect::from_xy_dim(
|
||||
[
|
||||
rect.x() - (inner_width + l_width) / 2.0,
|
||||
rect.y() + (inner_height + t_height) / 2.0,
|
||||
],
|
||||
[l_width, t_height],
|
||||
);
|
||||
let l_rect = Rect::from_xy_dim(
|
||||
[rect.x() - (inner_width + l_width) / 2.0, rect.y()],
|
||||
[l_width, inner_height],
|
||||
);
|
||||
let bl_rect = Rect::from_xy_dim(
|
||||
[
|
||||
rect.x() - (inner_width + l_width) / 2.0,
|
||||
rect.y() - (inner_height + b_height) / 2.0,
|
||||
],
|
||||
[l_width, b_height],
|
||||
);
|
||||
let b_rect = Rect::from_xy_dim(
|
||||
[rect.x(), rect.y() - (inner_height + b_height) / 2.0],
|
||||
[inner_width, b_height],
|
||||
);
|
||||
let br_rect = Rect::from_xy_dim(
|
||||
[
|
||||
rect.x() + (inner_width + r_width) / 2.0,
|
||||
rect.y() - (inner_height + b_height) / 2.0,
|
||||
],
|
||||
[r_width, b_height],
|
||||
);
|
||||
|
||||
let maybe_color = self.color;
|
||||
let set_image = |image_id, rect: Rect, maybe_src_rect, widget_id, ui: &mut UiCell| {
|
||||
Image::new(image_id)
|
||||
.xy(rect.xy())
|
||||
.wh(rect.dim())
|
||||
.parent(id)
|
||||
.graphics_for(id)
|
||||
.color(maybe_color)
|
||||
.set(widget_id, ui);
|
||||
};
|
||||
// Right edge
|
||||
set_image(
|
||||
self.edges[2],
|
||||
r_rect,
|
||||
self.edge_src_rects[2],
|
||||
state.ids.right,
|
||||
ui,
|
||||
);
|
||||
// Top-right corner
|
||||
set_image(
|
||||
self.corners[0],
|
||||
tr_rect,
|
||||
self.corner_src_rects[0],
|
||||
state.ids.top_right,
|
||||
ui,
|
||||
);
|
||||
// Top edge
|
||||
set_image(
|
||||
self.edges[0],
|
||||
t_rect,
|
||||
self.edge_src_rects[0],
|
||||
state.ids.top,
|
||||
ui,
|
||||
);
|
||||
// Top-left corner
|
||||
set_image(
|
||||
self.corners[1],
|
||||
tl_rect,
|
||||
self.corner_src_rects[1],
|
||||
state.ids.top_left,
|
||||
ui,
|
||||
);
|
||||
// Left edge
|
||||
set_image(
|
||||
self.edges[3],
|
||||
l_rect,
|
||||
self.edge_src_rects[3],
|
||||
state.ids.left,
|
||||
ui,
|
||||
);
|
||||
// Bottom-left corner
|
||||
set_image(
|
||||
self.corners[3],
|
||||
bl_rect,
|
||||
self.corner_src_rects[3],
|
||||
state.ids.bottom_left,
|
||||
ui,
|
||||
);
|
||||
// Bottom edge
|
||||
set_image(
|
||||
self.edges[1],
|
||||
b_rect,
|
||||
self.edge_src_rects[1],
|
||||
state.ids.bottom,
|
||||
ui,
|
||||
);
|
||||
// Bottom-right corner
|
||||
set_image(
|
||||
self.corners[2],
|
||||
br_rect,
|
||||
self.corner_src_rects[2],
|
||||
state.ids.bottom_right,
|
||||
ui,
|
||||
);
|
||||
|
||||
// Center,
|
||||
match self.center {
|
||||
Center::Plain(color) => {
|
||||
Rectangle::fill_with([inner_width, inner_height], color)
|
||||
.xy(rect.xy())
|
||||
.parent(id)
|
||||
.graphics_for(id)
|
||||
.and_then(maybe_color, |w, c| w.color(c))
|
||||
.set(state.ids.center_plain, ui);
|
||||
}
|
||||
Center::Image(image_id, maybe_src_rect) => {
|
||||
set_image(
|
||||
image_id,
|
||||
Rect::from_xy_dim(rect.xy(), [inner_width, inner_height]),
|
||||
maybe_src_rect,
|
||||
state.ids.center_image,
|
||||
ui,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Colorable for ImageFrame {
|
||||
fn color(mut self, color: Color) -> Self {
|
||||
self.color = Some(color);
|
||||
self
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ widget_ids! {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the state of the Slider widget.
|
||||
/// Represents the state of the ImageSlider widget.
|
||||
pub struct State {
|
||||
ids: Ids,
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod image_frame;
|
||||
pub mod image_slider;
|
||||
pub mod ingame;
|
||||
pub mod toggle_button;
|
||||
|
@ -274,7 +274,6 @@ impl<'a> Widget for Tooltip<'a> {
|
||||
.graphics_for(id)
|
||||
.parent(id)
|
||||
.color(color)
|
||||
//.floating(true)
|
||||
.set(state.ids.back_rect, ui);
|
||||
|
||||
// Title of tooltip
|
||||
@ -286,7 +285,6 @@ impl<'a> Widget for Tooltip<'a> {
|
||||
.with_style(self.style.title)
|
||||
// Apply transparency
|
||||
.color(style.title.color(ui.theme()).alpha(self.transparency))
|
||||
//.floating(true)
|
||||
.set(state.ids.title, ui);
|
||||
|
||||
// Description of tooltip
|
||||
@ -298,7 +296,6 @@ impl<'a> Widget for Tooltip<'a> {
|
||||
.with_style(self.style.desc)
|
||||
// Apply transparency
|
||||
.color(style.desc.color(ui.theme()).alpha(self.transparency))
|
||||
// .floating(true)
|
||||
.set(state.ids.desc, ui);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user