fyrox_ui/
uuid.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! UUID editor is used to show an arbitrary UUID and give an ability to generate a new value. See [`UuidEditor`] docs for
22//! more info and usage examples.
23
24#![warn(missing_docs)]
25
26use crate::{
27    button::{ButtonBuilder, ButtonMessage},
28    core::{pool::Handle, reflect::prelude::*, type_traits::prelude::*, visitor::prelude::*},
29    define_constructor, define_widget_deref,
30    grid::{Column, GridBuilder, Row},
31    message::{MessageDirection, UiMessage},
32    text::{TextBuilder, TextMessage},
33    widget::{Widget, WidgetBuilder},
34    BuildContext, Control, Thickness, UiNode, UserInterface, VerticalAlignment,
35};
36use fyrox_core::uuid_provider;
37use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
38use std::ops::{Deref, DerefMut};
39
40/// A set of messages that is used to fetch or modify values of [`UuidEditor`] widgets.
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum UuidEditorMessage {
43    /// Fetches or modifies a value of a [`UuidEditor`] widget.
44    Value(Uuid),
45}
46
47impl UuidEditorMessage {
48    define_constructor!(
49        /// Creates [`UuidEditorMessage::Value`] message.
50        UuidEditorMessage:Value => fn value(Uuid), layout: false
51    );
52}
53
54/// UUID editor is used to show an arbitrary UUID and give an ability to generate a new value. It is widely used in
55/// [`crate::inspector::Inspector`] to show and edit UUIDs.
56///
57/// ## Example
58///
59/// ```rust
60/// # use fyrox_ui::{
61/// #     core::{pool::Handle, uuid::Uuid},
62/// #     uuid::UuidEditorBuilder,
63/// #     widget::WidgetBuilder,
64/// #     BuildContext, UiNode,
65/// # };
66/// fn create_uuid_editor(ctx: &mut BuildContext) -> Handle<UiNode> {
67///     UuidEditorBuilder::new(WidgetBuilder::new())
68///         .with_value(Uuid::new_v4())
69///         .build(ctx)
70/// }
71/// ```
72#[derive(Default, Clone, Visit, Reflect, Debug, ComponentProvider)]
73pub struct UuidEditor {
74    widget: Widget,
75    value: Uuid,
76    text: Handle<UiNode>,
77    generate: Handle<UiNode>,
78}
79
80impl ConstructorProvider<UiNode, UserInterface> for UuidEditor {
81    fn constructor() -> GraphNodeConstructor<UiNode, UserInterface> {
82        GraphNodeConstructor::new::<Self>()
83            .with_variant("Uuid Editor", |ui| {
84                UuidEditorBuilder::new(WidgetBuilder::new().with_name("Uuid Editor"))
85                    .build(&mut ui.build_ctx())
86                    .into()
87            })
88            .with_group("Input")
89    }
90}
91
92define_widget_deref!(UuidEditor);
93
94uuid_provider!(UuidEditor = "667f7f48-2448-42da-91dd-cd743ca7117e");
95
96impl Control for UuidEditor {
97    fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
98        self.widget.handle_routed_message(ui, message);
99
100        if message.destination() == self.handle && message.direction() == MessageDirection::ToWidget
101        {
102            if let Some(UuidEditorMessage::Value(value)) = message.data() {
103                if self.value != *value {
104                    self.value = *value;
105                    ui.send_message(message.reverse());
106
107                    ui.send_message(TextMessage::text(
108                        self.text,
109                        MessageDirection::ToWidget,
110                        value.to_string(),
111                    ));
112                }
113            }
114        } else if message.destination() == self.generate {
115            if let Some(ButtonMessage::Click) = message.data() {
116                ui.send_message(UuidEditorMessage::value(
117                    self.handle,
118                    MessageDirection::ToWidget,
119                    Uuid::new_v4(),
120                ));
121            }
122        }
123    }
124}
125
126/// Creates [`UuidEditor`] widgets and add them to the user interface.
127pub struct UuidEditorBuilder {
128    widget_builder: WidgetBuilder,
129    value: Uuid,
130}
131
132impl UuidEditorBuilder {
133    /// Creates new builder instance.
134    pub fn new(widget_builder: WidgetBuilder) -> Self {
135        Self {
136            widget_builder,
137            value: Default::default(),
138        }
139    }
140
141    /// Sets a desired value of the [`UuidEditor`].
142    pub fn with_value(mut self, value: Uuid) -> Self {
143        self.value = value;
144        self
145    }
146
147    /// Finishes widget building.
148    pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
149        let text;
150        let generate;
151        let grid = GridBuilder::new(
152            WidgetBuilder::new()
153                .with_child({
154                    text = TextBuilder::new(
155                        WidgetBuilder::new()
156                            .on_column(0)
157                            .on_row(0)
158                            .with_margin(Thickness::uniform(1.0))
159                            .with_vertical_alignment(VerticalAlignment::Center),
160                    )
161                    .with_text(self.value.to_string())
162                    .build(ctx);
163                    text
164                })
165                .with_child({
166                    generate = ButtonBuilder::new(
167                        WidgetBuilder::new()
168                            .on_column(1)
169                            .on_row(0)
170                            .with_width(24.0)
171                            .with_margin(Thickness::uniform(1.0)),
172                    )
173                    .with_text("^/v")
174                    .build(ctx);
175                    generate
176                }),
177        )
178        .add_row(Row::stretch())
179        .add_column(Column::stretch())
180        .add_column(Column::auto())
181        .build(ctx);
182
183        let uuid_editor = UuidEditor {
184            widget: self.widget_builder.with_child(grid).build(ctx),
185            value: self.value,
186            text,
187            generate,
188        };
189
190        ctx.add_node(UiNode::new(uuid_editor))
191    }
192}
193
194#[cfg(test)]
195mod test {
196    use crate::uuid::UuidEditorBuilder;
197    use crate::{test::test_widget_deletion, widget::WidgetBuilder};
198
199    #[test]
200    fn test_deletion() {
201        test_widget_deletion(|ctx| UuidEditorBuilder::new(WidgetBuilder::new()).build(ctx));
202    }
203}