use crate::{
brush::Brush,
core::{algebra::Vector2, math::Rect, pool::Handle},
define_constructor,
message::{CursorIcon, KeyCode, MessageDirection, UiMessage},
HorizontalAlignment, LayoutEvent, MouseButton, MouseState, RcUiNodeHandle, Thickness, UiNode,
UserInterface, VerticalAlignment, BRUSH_FOREGROUND, BRUSH_PRIMARY,
};
use fyrox_core::{
algebra::{Matrix3, Point2},
uuid::Uuid,
};
use std::{
any::Any,
cell::{Cell, RefCell},
rc::Rc,
sync::mpsc::Sender,
};
#[derive(Debug, Clone, PartialEq)]
pub enum WidgetMessage {
MouseDown {
pos: Vector2<f32>,
button: MouseButton,
},
MouseUp {
pos: Vector2<f32>,
button: MouseButton,
},
MouseMove {
pos: Vector2<f32>,
state: MouseState,
},
MouseWheel {
pos: Vector2<f32>,
amount: f32,
},
MouseLeave,
MouseEnter,
Text(char),
KeyDown(KeyCode),
KeyUp(KeyCode),
Focus,
Unfocus,
DragStarted(Handle<UiNode>),
DragOver(Handle<UiNode>),
Drop(Handle<UiNode>),
Topmost,
Lowermost,
Unlink,
Remove,
LinkWith(Handle<UiNode>),
LinkWithReverse(Handle<UiNode>),
Background(Brush),
Foreground(Brush),
Name(String),
Width(f32),
Height(f32),
VerticalAlignment(VerticalAlignment),
HorizontalAlignment(HorizontalAlignment),
MaxSize(Vector2<f32>),
MinSize(Vector2<f32>),
Row(usize),
Column(usize),
Margin(Thickness),
HitTestVisibility(bool),
Visibility(bool),
ZIndex(usize),
DesiredPosition(Vector2<f32>),
Enabled(bool),
Center,
AdjustPositionToFit,
Cursor(Option<CursorIcon>),
Opacity(Option<f32>),
LayoutTransform(Matrix3<f32>),
RenderTransform(Matrix3<f32>),
DoubleClick { button: MouseButton },
ContextMenu(Option<RcUiNodeHandle>),
Tooltip(Option<RcUiNodeHandle>),
}
impl WidgetMessage {
define_constructor!(WidgetMessage:Remove => fn remove(), layout: false);
define_constructor!(WidgetMessage:Unlink => fn unlink(), layout: false);
define_constructor!(WidgetMessage:LinkWith => fn link(Handle<UiNode>), layout: false);
define_constructor!(WidgetMessage:LinkWithReverse => fn link_reverse(Handle<UiNode>), layout: false);
define_constructor!(WidgetMessage:Background => fn background(Brush), layout: false);
define_constructor!(WidgetMessage:Foreground => fn foreground(Brush), layout: false);
define_constructor!(WidgetMessage:Visibility => fn visibility(bool), layout: false);
define_constructor!(WidgetMessage:Width => fn width(f32), layout: false);
define_constructor!(WidgetMessage:Height => fn height(f32), layout: false);
define_constructor!(WidgetMessage:DesiredPosition => fn desired_position(Vector2<f32>), layout: false);
define_constructor!(WidgetMessage:Center => fn center(), layout: true);
define_constructor!(WidgetMessage:AdjustPositionToFit => fn adjust_position_to_fit(), layout: true);
define_constructor!(WidgetMessage:Topmost => fn topmost(), layout: false);
define_constructor!(WidgetMessage:Lowermost => fn lowermost(), layout: false);
define_constructor!(WidgetMessage:Enabled => fn enabled(bool), layout: false);
define_constructor!(WidgetMessage:Name => fn name(String), layout: false);
define_constructor!(WidgetMessage:Row => fn row(usize), layout: false);
define_constructor!(WidgetMessage:Column => fn column(usize), layout: false);
define_constructor!(WidgetMessage:Cursor => fn cursor(Option<CursorIcon>), layout: false);
define_constructor!(WidgetMessage:ZIndex => fn z_index(usize), layout: false);
define_constructor!(WidgetMessage:HitTestVisibility => fn hit_test_visibility(bool), layout: false);
define_constructor!(WidgetMessage:Margin => fn margin(Thickness), layout: false);
define_constructor!(WidgetMessage:MinSize => fn min_size(Vector2<f32>), layout: false);
define_constructor!(WidgetMessage:MaxSize => fn max_size(Vector2<f32>), layout: false);
define_constructor!(WidgetMessage:HorizontalAlignment => fn horizontal_alignment(HorizontalAlignment), layout: false);
define_constructor!(WidgetMessage:VerticalAlignment => fn vertical_alignment(VerticalAlignment), layout: false);
define_constructor!(WidgetMessage:Opacity => fn opacity(Option<f32>), layout: false);
define_constructor!(WidgetMessage:LayoutTransform => fn layout_transform(Matrix3<f32>), layout: false);
define_constructor!(WidgetMessage:RenderTransform => fn render_transform(Matrix3<f32>), layout: false);
define_constructor!(WidgetMessage:ContextMenu => fn context_menu(Option<RcUiNodeHandle>), layout: false);
define_constructor!(WidgetMessage:Tooltip => fn tooltip(Option<RcUiNodeHandle>), layout: false);
define_constructor!(WidgetMessage:Focus => fn focus(), layout: false);
define_constructor!(WidgetMessage:Unfocus => fn unfocus(), layout: false);
define_constructor!(WidgetMessage:MouseDown => fn mouse_down(pos: Vector2<f32>, button: MouseButton), layout: false);
define_constructor!(WidgetMessage:MouseUp => fn mouse_up(pos: Vector2<f32>, button: MouseButton), layout: false);
define_constructor!(WidgetMessage:MouseMove => fn mouse_move(pos: Vector2<f32>, state: MouseState), layout: false);
define_constructor!(WidgetMessage:MouseWheel => fn mouse_wheel(pos: Vector2<f32>, amount: f32), layout: false);
define_constructor!(WidgetMessage:MouseLeave => fn mouse_leave(), layout: false);
define_constructor!(WidgetMessage:MouseEnter => fn mouse_enter(), layout: false);
define_constructor!(WidgetMessage:Text => fn text(char), layout: false);
define_constructor!(WidgetMessage:KeyDown => fn key_down(KeyCode), layout: false);
define_constructor!(WidgetMessage:KeyUp => fn key_up(KeyCode), layout: false);
define_constructor!(WidgetMessage:DragStarted => fn drag_started(Handle<UiNode>), layout: false);
define_constructor!(WidgetMessage:DragOver => fn drag_over(Handle<UiNode>), layout: false);
define_constructor!(WidgetMessage:Drop => fn drop(Handle<UiNode>), layout: false);
define_constructor!(WidgetMessage:DoubleClick => fn double_click(button: MouseButton), layout: false);
}
#[derive(Debug, Clone)]
pub struct Widget {
pub handle: Handle<UiNode>,
pub name: String,
pub desired_local_position: Vector2<f32>,
pub width: f32,
pub height: f32,
pub min_size: Vector2<f32>,
pub max_size: Vector2<f32>,
pub background: Brush,
pub foreground: Brush,
pub row: usize,
pub column: usize,
pub vertical_alignment: VerticalAlignment,
pub horizontal_alignment: HorizontalAlignment,
pub margin: Thickness,
pub visibility: bool,
pub global_visibility: bool,
pub children: Vec<Handle<UiNode>>,
pub parent: Handle<UiNode>,
pub command_indices: RefCell<Vec<usize>>,
pub is_mouse_directly_over: bool,
pub hit_test_visibility: bool,
pub z_index: usize,
pub allow_drag: bool,
pub allow_drop: bool,
pub user_data: Option<Rc<dyn Any>>,
pub draw_on_top: bool,
pub enabled: bool,
pub cursor: Option<CursorIcon>,
pub opacity: Option<f32>,
pub tooltip: Option<RcUiNodeHandle>,
pub tooltip_time: f32,
pub context_menu: Option<RcUiNodeHandle>,
pub clip_to_bounds: bool,
pub layout_transform: Matrix3<f32>,
pub render_transform: Matrix3<f32>,
pub visual_transform: Matrix3<f32>,
pub preview_messages: bool,
pub handle_os_events: bool,
pub layout_events_sender: Option<Sender<LayoutEvent>>,
pub id: Uuid,
pub measure_valid: Cell<bool>,
pub arrange_valid: Cell<bool>,
pub prev_measure: Cell<Vector2<f32>>,
pub prev_arrange: Cell<Rect<f32>>,
pub desired_size: Cell<Vector2<f32>>,
pub actual_local_position: Cell<Vector2<f32>>,
pub actual_local_size: Cell<Vector2<f32>>,
pub prev_global_visibility: bool,
pub clip_bounds: Cell<Rect<f32>>,
}
impl Widget {
#[inline]
pub fn handle(&self) -> Handle<UiNode> {
self.handle
}
#[inline]
pub fn name(&self) -> &str {
self.name.as_str()
}
#[inline]
pub fn set_name<P: AsRef<str>>(&mut self, name: P) -> &mut Self {
self.name = name.as_ref().to_owned();
self
}
#[inline]
pub fn actual_local_size(&self) -> Vector2<f32> {
self.actual_local_size.get()
}
#[inline]
pub fn actual_initial_size(&self) -> Vector2<f32> {
Rect::new(
0.0,
0.0,
self.actual_local_size.get().x,
self.actual_local_size.get().y,
)
.transform(&self.visual_transform.try_inverse().unwrap_or_default())
.size
}
#[inline]
pub fn actual_global_size(&self) -> Vector2<f32> {
self.screen_bounds().size
}
#[inline]
pub fn set_min_size(&mut self, value: Vector2<f32>) -> &mut Self {
self.min_size = value;
self
}
#[inline]
pub fn set_min_width(&mut self, value: f32) -> &mut Self {
self.min_size.x = value;
self
}
#[inline]
pub fn set_min_height(&mut self, value: f32) -> &mut Self {
self.min_size.y = value;
self
}
#[inline]
pub fn min_size(&self) -> Vector2<f32> {
self.min_size
}
#[inline]
pub fn min_width(&self) -> f32 {
self.min_size.x
}
#[inline]
pub fn min_height(&self) -> f32 {
self.min_size.y
}
#[inline]
pub fn is_drag_allowed(&self) -> bool {
self.allow_drag
}
#[inline]
pub fn is_drop_allowed(&self) -> bool {
self.allow_drop
}
#[inline]
pub fn screen_to_local(&self, point: Vector2<f32>) -> Vector2<f32> {
self.visual_transform
.try_inverse()
.unwrap_or_default()
.transform_point(&Point2::from(point))
.coords
}
#[inline]
pub fn invalidate_layout(&self) {
self.invalidate_measure();
self.invalidate_arrange();
}
#[inline]
pub fn invalidate_measure(&self) {
self.measure_valid.set(false);
if let Some(layout_events_sender) = self.layout_events_sender.as_ref() {
let _ = layout_events_sender.send(LayoutEvent::MeasurementInvalidated(self.handle));
}
}
#[inline]
pub fn invalidate_arrange(&self) {
self.arrange_valid.set(false);
if let Some(layout_events_sender) = self.layout_events_sender.as_ref() {
let _ = layout_events_sender.send(LayoutEvent::ArrangementInvalidated(self.handle));
}
}
#[inline]
pub fn is_hit_test_visible(&self) -> bool {
self.hit_test_visibility
}
#[inline]
pub fn set_max_size(&mut self, value: Vector2<f32>) -> &mut Self {
self.max_size = value;
self
}
#[inline]
pub fn max_size(&self) -> Vector2<f32> {
self.max_size
}
#[inline]
pub fn max_width(&self) -> f32 {
self.max_size.x
}
#[inline]
pub fn max_height(&self) -> f32 {
self.max_size.y
}
#[inline]
pub fn set_z_index(&mut self, z_index: usize) -> &mut Self {
self.z_index = z_index;
self
}
#[inline]
pub fn z_index(&self) -> usize {
self.z_index
}
#[inline]
pub fn set_background(&mut self, brush: Brush) -> &mut Self {
self.background = brush;
self
}
#[inline]
pub fn background(&self) -> Brush {
self.background.clone()
}
#[inline]
pub fn set_foreground(&mut self, brush: Brush) -> &mut Self {
self.foreground = brush;
self
}
#[inline]
pub fn foreground(&self) -> Brush {
self.foreground.clone()
}
#[inline]
pub fn set_width(&mut self, width: f32) -> &mut Self {
self.width = width.clamp(self.min_size.x, self.max_size.x);
self
}
#[inline]
pub fn width(&self) -> f32 {
self.width
}
pub fn is_draw_on_top(&self) -> bool {
self.draw_on_top
}
#[inline]
pub fn set_height(&mut self, height: f32) -> &mut Self {
self.height = height.clamp(self.min_size.y, self.max_size.y);
self
}
#[inline]
pub fn height(&self) -> f32 {
self.height
}
#[inline]
pub fn set_desired_local_position(&mut self, pos: Vector2<f32>) -> &mut Self {
self.desired_local_position = pos;
self
}
#[inline]
pub fn screen_position(&self) -> Vector2<f32> {
Vector2::new(self.visual_transform[6], self.visual_transform[7])
}
#[inline]
pub(crate) fn add_child(&mut self, child: Handle<UiNode>, in_front: bool) {
self.invalidate_layout();
if in_front && !self.children.is_empty() {
self.children.insert(0, child)
} else {
self.children.push(child)
}
}
#[inline(always)]
pub fn children(&self) -> &[Handle<UiNode>] {
&self.children
}
#[inline]
pub(crate) fn clear_children(&mut self) {
self.invalidate_layout();
self.children.clear();
}
#[inline]
pub(crate) fn remove_child(&mut self, child: Handle<UiNode>) {
if let Some(i) = self.children.iter().position(|h| *h == child) {
self.children.remove(i);
self.invalidate_layout();
}
}
#[inline]
pub fn parent(&self) -> Handle<UiNode> {
self.parent
}
#[inline]
pub fn set_parent(&mut self, parent: Handle<UiNode>) {
self.parent = parent;
}
#[inline]
pub fn column(&self) -> usize {
self.column
}
#[inline]
pub fn set_row(&mut self, row: usize) -> &mut Self {
self.row = row;
self
}
#[inline]
pub fn row(&self) -> usize {
self.row
}
#[inline]
pub fn desired_size(&self) -> Vector2<f32> {
self.desired_size.get()
}
#[inline]
pub fn desired_local_position(&self) -> Vector2<f32> {
self.desired_local_position
}
#[inline]
pub fn screen_bounds(&self) -> Rect<f32> {
self.bounding_rect().transform(&self.visual_transform)
}
#[inline]
pub fn bounding_rect(&self) -> Rect<f32> {
Rect::new(
0.0,
0.0,
self.actual_local_size.get().x,
self.actual_local_size.get().y,
)
}
#[inline]
pub fn visual_transform(&self) -> &Matrix3<f32> {
&self.visual_transform
}
#[inline]
pub fn render_transform(&self) -> &Matrix3<f32> {
&self.render_transform
}
#[inline]
pub fn layout_transform(&self) -> &Matrix3<f32> {
&self.layout_transform
}
pub fn has_descendant(&self, node_handle: Handle<UiNode>, ui: &UserInterface) -> bool {
for child_handle in self.children.iter() {
if *child_handle == node_handle {
return true;
}
let result = ui
.nodes
.borrow(*child_handle)
.has_descendant(node_handle, ui);
if result {
return true;
}
}
false
}
pub fn find_by_criteria_up<Func: Fn(&UiNode) -> bool>(
&self,
ui: &UserInterface,
func: Func,
) -> Handle<UiNode> {
let mut parent_handle = self.parent;
while parent_handle.is_some() {
if let Some(parent_node) = ui.nodes.try_borrow(parent_handle) {
if func(parent_node) {
return parent_handle;
}
parent_handle = parent_node.parent;
} else {
break;
}
}
Handle::NONE
}
pub fn handle_routed_message(&mut self, _ui: &mut UserInterface, msg: &mut UiMessage) {
if msg.destination() == self.handle() && msg.direction() == MessageDirection::ToWidget {
if let Some(msg) = msg.data::<WidgetMessage>() {
match msg {
&WidgetMessage::Opacity(opacity) => self.opacity = opacity,
WidgetMessage::Background(background) => self.background = background.clone(),
WidgetMessage::Foreground(foreground) => self.foreground = foreground.clone(),
WidgetMessage::Name(name) => self.name = name.clone(),
&WidgetMessage::Width(width) => {
if self.width != width {
self.width = width;
self.invalidate_layout();
}
}
&WidgetMessage::Height(height) => {
if self.height != height {
self.height = height;
self.invalidate_layout();
}
}
WidgetMessage::VerticalAlignment(vertical_alignment) => {
if self.vertical_alignment != *vertical_alignment {
self.vertical_alignment = *vertical_alignment;
self.invalidate_layout();
}
}
WidgetMessage::HorizontalAlignment(horizontal_alignment) => {
if self.horizontal_alignment != *horizontal_alignment {
self.horizontal_alignment = *horizontal_alignment;
self.invalidate_layout();
}
}
WidgetMessage::MaxSize(max_size) => {
if self.max_size != *max_size {
self.max_size = *max_size;
self.invalidate_layout();
}
}
WidgetMessage::MinSize(min_size) => {
if self.min_size != *min_size {
self.min_size = *min_size;
self.invalidate_layout();
}
}
&WidgetMessage::Row(row) => {
if self.row != row {
self.row = row;
self.invalidate_layout();
}
}
&WidgetMessage::Column(column) => {
if self.column != column {
self.column = column;
self.invalidate_layout();
}
}
&WidgetMessage::Margin(margin) => {
if self.margin != margin {
self.margin = margin;
self.invalidate_layout();
}
}
WidgetMessage::HitTestVisibility(hit_test_visibility) => {
self.hit_test_visibility = *hit_test_visibility
}
&WidgetMessage::Visibility(visibility) => {
self.set_visibility(visibility);
}
&WidgetMessage::DesiredPosition(pos) => {
if self.desired_local_position != pos {
self.desired_local_position = pos;
self.invalidate_layout();
}
}
&WidgetMessage::Enabled(enabled) => {
self.enabled = enabled;
}
&WidgetMessage::Cursor(icon) => {
self.cursor = icon;
}
WidgetMessage::LayoutTransform(transform) => {
if &self.layout_transform != transform {
self.layout_transform = *transform;
self.invalidate_layout();
}
}
WidgetMessage::RenderTransform(transform) => {
self.render_transform = *transform;
}
_ => (),
}
}
}
}
#[inline]
pub fn set_vertical_alignment(&mut self, vertical_alignment: VerticalAlignment) -> &mut Self {
self.vertical_alignment = vertical_alignment;
self
}
#[inline]
pub fn vertical_alignment(&self) -> VerticalAlignment {
self.vertical_alignment
}
#[inline]
pub fn set_horizontal_alignment(
&mut self,
horizontal_alignment: HorizontalAlignment,
) -> &mut Self {
self.horizontal_alignment = horizontal_alignment;
self
}
#[inline]
pub fn horizontal_alignment(&self) -> HorizontalAlignment {
self.horizontal_alignment
}
#[inline]
pub fn set_column(&mut self, column: usize) -> &mut Self {
self.column = column;
self
}
#[inline]
pub fn set_margin(&mut self, margin: Thickness) -> &mut Self {
self.margin = margin;
self
}
#[inline]
pub fn margin(&self) -> Thickness {
self.margin
}
#[inline]
pub fn measure_override(
&self,
ui: &UserInterface,
available_size: Vector2<f32>,
) -> Vector2<f32> {
let mut size: Vector2<f32> = Vector2::default();
for &child in self.children.iter() {
ui.measure_node(child, available_size);
let desired_size = ui.node(child).desired_size();
size.x = size.x.max(desired_size.x);
size.y = size.y.max(desired_size.y);
}
size
}
#[inline]
pub fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
let final_rect = Rect::new(0.0, 0.0, final_size.x, final_size.y);
for &child in self.children.iter() {
ui.arrange_node(child, &final_rect);
}
final_size
}
#[inline]
pub(crate) fn commit_arrange(&self, position: Vector2<f32>, size: Vector2<f32>) {
self.actual_local_size.set(size);
self.actual_local_position.set(position);
self.arrange_valid.set(true);
}
#[inline]
pub(crate) fn set_children(&mut self, children: Vec<Handle<UiNode>>) {
self.invalidate_layout();
self.request_update_visibility();
self.children = children;
}
#[inline(always)]
pub fn is_arrange_valid(&self) -> bool {
self.arrange_valid.get()
}
#[inline]
pub(crate) fn commit_measure(&self, desired_size: Vector2<f32>) {
self.desired_size.set(desired_size);
self.measure_valid.set(true);
}
#[inline(always)]
pub fn is_measure_valid(&self) -> bool {
self.measure_valid.get()
}
#[inline]
pub fn actual_local_position(&self) -> Vector2<f32> {
self.actual_local_position.get()
}
#[inline]
pub fn center(&self) -> Vector2<f32> {
self.actual_local_position() + self.actual_local_size().scale(0.5)
}
#[inline]
pub(crate) fn set_global_visibility(&mut self, value: bool) {
self.prev_global_visibility = self.global_visibility;
self.global_visibility = value;
}
#[inline]
pub fn is_globally_visible(&self) -> bool {
self.global_visibility
}
#[inline]
pub fn set_visibility(&mut self, visibility: bool) -> &mut Self {
if self.visibility != visibility {
self.visibility = visibility;
self.invalidate_layout();
self.request_update_visibility();
}
self
}
#[inline]
pub fn request_update_visibility(&self) {
if let Some(layout_events_sender) = self.layout_events_sender.as_ref() {
let _ = layout_events_sender.send(LayoutEvent::VisibilityChanged(self.handle));
}
}
#[inline]
pub fn visibility(&self) -> bool {
self.visibility
}
#[inline]
pub fn set_enabled(&mut self, enabled: bool) -> &mut Self {
self.enabled = enabled;
self
}
#[inline]
pub fn enabled(&self) -> bool {
self.enabled
}
#[inline]
pub fn set_cursor(&mut self, cursor: Option<CursorIcon>) {
self.cursor = cursor;
}
#[inline]
pub fn cursor(&self) -> Option<CursorIcon> {
self.cursor
}
#[inline]
pub fn user_data_ref<T: 'static>(&self) -> Option<&T> {
self.user_data.as_ref().and_then(|v| v.downcast_ref::<T>())
}
#[inline]
pub fn clip_bounds(&self) -> Rect<f32> {
self.clip_bounds.get()
}
#[inline]
pub fn set_opacity(&mut self, opacity: Option<f32>) -> &mut Self {
self.opacity = opacity;
self
}
#[inline]
pub fn opacity(&self) -> Option<f32> {
self.opacity
}
#[inline]
pub fn tooltip(&self) -> Option<RcUiNodeHandle> {
self.tooltip.clone()
}
#[inline]
pub fn set_tooltip(&mut self, tooltip: Option<RcUiNodeHandle>) -> &mut Self {
self.tooltip = tooltip;
self
}
#[inline]
pub fn tooltip_time(&self) -> f32 {
self.tooltip_time
}
#[inline]
pub fn set_tooltip_time(&mut self, tooltip_time: f32) -> &mut Self {
self.tooltip_time = tooltip_time;
self
}
#[inline]
pub fn context_menu(&self) -> Option<RcUiNodeHandle> {
self.context_menu.clone()
}
#[inline]
pub fn set_context_menu(&mut self, context_menu: Option<RcUiNodeHandle>) -> &mut Self {
self.context_menu = context_menu;
self
}
}
#[macro_export]
macro_rules! define_widget_deref {
($ty: ty) => {
impl Deref for $ty {
type Target = Widget;
fn deref(&self) -> &Self::Target {
&self.widget
}
}
impl DerefMut for $ty {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.widget
}
}
};
}
pub struct WidgetBuilder {
pub name: String,
pub width: f32,
pub height: f32,
pub desired_position: Vector2<f32>,
pub vertical_alignment: VerticalAlignment,
pub horizontal_alignment: HorizontalAlignment,
pub max_size: Option<Vector2<f32>>,
pub min_size: Option<Vector2<f32>>,
pub background: Option<Brush>,
pub foreground: Option<Brush>,
pub row: usize,
pub column: usize,
pub margin: Thickness,
pub children: Vec<Handle<UiNode>>,
pub is_hit_test_visible: bool,
pub visibility: bool,
pub z_index: usize,
pub allow_drag: bool,
pub allow_drop: bool,
pub user_data: Option<Rc<dyn Any>>,
pub draw_on_top: bool,
pub enabled: bool,
pub cursor: Option<CursorIcon>,
pub opacity: Option<f32>,
pub tooltip: Option<RcUiNodeHandle>,
pub tooltip_time: f32,
pub context_menu: Option<RcUiNodeHandle>,
pub preview_messages: bool,
pub handle_os_events: bool,
pub layout_transform: Matrix3<f32>,
pub render_transform: Matrix3<f32>,
pub clip_to_bounds: bool,
pub id: Uuid,
}
impl Default for WidgetBuilder {
fn default() -> Self {
Self::new()
}
}
impl WidgetBuilder {
pub fn new() -> Self {
Self {
name: Default::default(),
width: f32::NAN,
height: f32::NAN,
vertical_alignment: VerticalAlignment::Stretch,
horizontal_alignment: HorizontalAlignment::Stretch,
max_size: None,
min_size: None,
background: None,
foreground: None,
row: 0,
column: 0,
margin: Thickness::zero(),
desired_position: Vector2::default(),
children: Vec::new(),
is_hit_test_visible: true,
visibility: true,
z_index: 0,
allow_drag: false,
allow_drop: false,
user_data: None,
draw_on_top: false,
enabled: true,
cursor: None,
opacity: None,
tooltip: Default::default(),
tooltip_time: 0.1,
context_menu: Default::default(),
preview_messages: false,
handle_os_events: false,
layout_transform: Matrix3::identity(),
render_transform: Matrix3::identity(),
clip_to_bounds: true,
id: Uuid::new_v4(),
}
}
pub fn with_preview_messages(mut self, state: bool) -> Self {
self.preview_messages = state;
self
}
pub fn with_handle_os_events(mut self, state: bool) -> Self {
self.handle_os_events = state;
self
}
pub fn with_width(mut self, width: f32) -> Self {
self.width = width;
self
}
pub fn with_height(mut self, height: f32) -> Self {
self.height = height;
self
}
pub fn with_clip_to_bounds(mut self, clip_to_bounds: bool) -> Self {
self.clip_to_bounds = clip_to_bounds;
self
}
pub fn with_enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
pub fn with_vertical_alignment(mut self, valign: VerticalAlignment) -> Self {
self.vertical_alignment = valign;
self
}
pub fn with_horizontal_alignment(mut self, halign: HorizontalAlignment) -> Self {
self.horizontal_alignment = halign;
self
}
pub fn with_max_size(mut self, max_size: Vector2<f32>) -> Self {
self.max_size = Some(max_size);
self
}
pub fn with_min_size(mut self, min_size: Vector2<f32>) -> Self {
self.min_size = Some(min_size);
self
}
pub fn with_background(mut self, brush: Brush) -> Self {
self.background = Some(brush);
self
}
pub fn with_foreground(mut self, brush: Brush) -> Self {
self.foreground = Some(brush);
self
}
pub fn on_row(mut self, row: usize) -> Self {
self.row = row;
self
}
pub fn on_column(mut self, column: usize) -> Self {
self.column = column;
self
}
pub fn with_margin(mut self, margin: Thickness) -> Self {
self.margin = margin;
self
}
pub fn with_desired_position(mut self, desired_position: Vector2<f32>) -> Self {
self.desired_position = desired_position;
self
}
pub fn with_layout_transform(mut self, layout_transform: Matrix3<f32>) -> Self {
self.layout_transform = layout_transform;
self
}
pub fn with_render_transform(mut self, render_transform: Matrix3<f32>) -> Self {
self.render_transform = render_transform;
self
}
pub fn with_z_index(mut self, z_index: usize) -> Self {
self.z_index = z_index;
self
}
pub fn with_child(mut self, handle: Handle<UiNode>) -> Self {
if handle.is_some() {
self.children.push(handle);
}
self
}
pub fn with_draw_on_top(mut self, draw_on_top: bool) -> Self {
self.draw_on_top = draw_on_top;
self
}
pub fn with_children<I: IntoIterator<Item = Handle<UiNode>>>(mut self, children: I) -> Self {
for child in children.into_iter() {
if child.is_some() {
self.children.push(child)
}
}
self
}
pub fn with_name(mut self, name: &str) -> Self {
self.name = String::from(name);
self
}
pub fn with_hit_test_visibility(mut self, state: bool) -> Self {
self.is_hit_test_visible = state;
self
}
pub fn with_visibility(mut self, visibility: bool) -> Self {
self.visibility = visibility;
self
}
pub fn with_allow_drop(mut self, allow_drop: bool) -> Self {
self.allow_drop = allow_drop;
self
}
pub fn with_allow_drag(mut self, allow_drag: bool) -> Self {
self.allow_drag = allow_drag;
self
}
pub fn with_user_data(mut self, user_data: Rc<dyn Any>) -> Self {
self.user_data = Some(user_data);
self
}
pub fn with_cursor(mut self, cursor: Option<CursorIcon>) -> Self {
self.cursor = cursor;
self
}
pub fn with_opacity(mut self, opacity: Option<f32>) -> Self {
self.opacity = opacity;
self
}
pub fn with_id(mut self, id: Uuid) -> Self {
self.id = id;
self
}
pub fn with_tooltip(mut self, tooltip: RcUiNodeHandle) -> Self {
self.tooltip = Some(tooltip);
self
}
pub fn with_opt_tooltip(mut self, tooltip: Option<RcUiNodeHandle>) -> Self {
self.tooltip = tooltip;
self
}
pub fn with_tooltip_time(mut self, tooltip_time: f32) -> Self {
self.tooltip_time = tooltip_time;
self
}
pub fn with_context_menu(mut self, context_menu: RcUiNodeHandle) -> Self {
self.context_menu = Some(context_menu);
self
}
pub fn build(self) -> Widget {
Widget {
handle: Default::default(),
name: self.name,
desired_local_position: self.desired_position,
width: self.width,
height: self.height,
desired_size: Cell::new(Vector2::default()),
actual_local_position: Cell::new(Vector2::default()),
actual_local_size: Cell::new(Vector2::default()),
min_size: self.min_size.unwrap_or_default(),
max_size: self
.max_size
.unwrap_or_else(|| Vector2::new(f32::INFINITY, f32::INFINITY)),
background: self.background.unwrap_or_else(|| BRUSH_PRIMARY.clone()),
foreground: self.foreground.unwrap_or_else(|| BRUSH_FOREGROUND.clone()),
row: self.row,
column: self.column,
vertical_alignment: self.vertical_alignment,
horizontal_alignment: self.horizontal_alignment,
margin: self.margin,
visibility: self.visibility,
global_visibility: true,
prev_global_visibility: false,
children: self.children,
parent: Handle::NONE,
command_indices: Default::default(),
is_mouse_directly_over: false,
measure_valid: Cell::new(false),
arrange_valid: Cell::new(false),
hit_test_visibility: self.is_hit_test_visible,
prev_measure: Default::default(),
prev_arrange: Default::default(),
z_index: self.z_index,
allow_drag: self.allow_drag,
allow_drop: self.allow_drop,
user_data: self.user_data.clone(),
draw_on_top: self.draw_on_top,
enabled: self.enabled,
cursor: self.cursor,
clip_bounds: Cell::new(Default::default()),
opacity: self.opacity,
tooltip: self.tooltip,
tooltip_time: self.tooltip_time,
context_menu: self.context_menu,
preview_messages: self.preview_messages,
handle_os_events: self.handle_os_events,
layout_events_sender: None,
layout_transform: self.layout_transform,
render_transform: self.render_transform,
visual_transform: Matrix3::identity(),
clip_to_bounds: self.clip_to_bounds,
id: self.id,
}
}
}