mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
PartialEq impls + improvements for ui
This commit is contained in:
@@ -47,6 +47,7 @@ use crate::{
|
||||
plugins::inspector::EditorEnvironment,
|
||||
};
|
||||
use fyrox::core::dyntype::DynTypeWrapper;
|
||||
use fyrox::gui::inspector::InspectorEnvironmentContainer;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
cell::Cell,
|
||||
@@ -141,7 +142,7 @@ impl DynTypePropertyEditorBuilder {
|
||||
self,
|
||||
variant_selector: Handle<UiNode>,
|
||||
dyn_type_uuid: Option<Uuid>,
|
||||
environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
environment: Option<InspectorEnvironmentContainer>,
|
||||
layer_index: usize,
|
||||
generate_property_string_values: bool,
|
||||
filter: PropertyFilter,
|
||||
|
||||
@@ -51,7 +51,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use fyrox::gui::button::Button;
|
||||
use fyrox::gui::inspector::InspectorContextArgs;
|
||||
use fyrox::gui::inspector::{InspectorContextArgs, InspectorEnvironmentContainer};
|
||||
use fyrox::gui::message::MessageData;
|
||||
use fyrox::gui::utils::make_dropdown_list_option;
|
||||
use fyrox::gui::{Thickness, VerticalAlignment};
|
||||
@@ -216,7 +216,7 @@ impl ScriptPropertyEditorBuilder {
|
||||
open_in_ide_button: Handle<Button>,
|
||||
variant_selector: Handle<UiNode>,
|
||||
script_uuid: Option<Uuid>,
|
||||
environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
environment: Option<InspectorEnvironmentContainer>,
|
||||
layer_index: usize,
|
||||
generate_property_string_values: bool,
|
||||
filter: PropertyFilter,
|
||||
|
||||
@@ -62,6 +62,7 @@ use crate::{
|
||||
utils::window_content,
|
||||
Editor, Message, WidgetMessage, WrapMode,
|
||||
};
|
||||
use fyrox::gui::inspector::InspectorEnvironmentContainer;
|
||||
use std::{any::Any, sync::mpsc::Sender, sync::Arc};
|
||||
|
||||
pub mod editors;
|
||||
@@ -93,7 +94,7 @@ pub struct EditorEnvironment {
|
||||
|
||||
impl EditorEnvironment {
|
||||
pub fn try_get_from(
|
||||
environment: &Option<Arc<dyn InspectorEnvironment>>,
|
||||
environment: &Option<InspectorEnvironmentContainer>,
|
||||
) -> Result<&Self, InspectorError> {
|
||||
let environment = &**environment.as_ref().ok_or(InspectorError::Custom(
|
||||
"Missing InspectorEnvironment".into(),
|
||||
|
||||
@@ -495,7 +495,7 @@ struct ContextMenu {
|
||||
paste_keys: Handle<MenuItem>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
struct DragEntry {
|
||||
key_id: Uuid,
|
||||
initial_position: Vector2<f32>,
|
||||
@@ -533,7 +533,7 @@ impl OperationContext {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,PartialEq, Debug)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
enum Selection {
|
||||
Keys { keys: FxHashSet<Uuid> },
|
||||
LeftTangent { key_id: Uuid },
|
||||
@@ -952,7 +952,7 @@ impl Control for CurveEditor {
|
||||
// but when it works, who cares.
|
||||
self.zoom_to_fit_timer = Some(10);
|
||||
} else {
|
||||
self.zoom_to_fit(&ui.sender);
|
||||
self.zoom_to_fit(&ui.ui_message_channel.sender);
|
||||
}
|
||||
|
||||
self.invalidate_visual();
|
||||
@@ -1088,7 +1088,7 @@ impl Control for CurveEditor {
|
||||
if let Some(timer) = self.zoom_to_fit_timer.as_mut() {
|
||||
*timer = timer.saturating_sub(1);
|
||||
if *timer == 0 {
|
||||
self.zoom_to_fit(&ui.sender);
|
||||
self.zoom_to_fit(&ui.ui_message_channel.sender);
|
||||
self.zoom_to_fit_timer = None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,7 +873,7 @@ impl RenderData {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct DrawingContext {
|
||||
pub render_data: RenderData,
|
||||
pub transform_stack: TransformStack,
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
use crate::{
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
core::{
|
||||
err, log::Log, ok_or_continue, ok_or_return, parking_lot::Mutex, pool::Handle,
|
||||
reflect::prelude::*, some_or_return, visitor::prelude::*, SafeLock,
|
||||
err, log::Log, ok_or_continue, ok_or_return, pool::Handle, reflect::prelude::*,
|
||||
some_or_return, visitor::prelude::*,
|
||||
},
|
||||
file_browser::{
|
||||
fs_tree::{sanitize_path, TreeItemPath},
|
||||
@@ -52,11 +52,12 @@ use fyrox_graph::{
|
||||
SceneGraph,
|
||||
};
|
||||
use notify::{Event, Watcher};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
fmt::{Debug, Formatter},
|
||||
path::{Path, PathBuf},
|
||||
sync::{mpsc::Sender, Arc},
|
||||
sync::mpsc::Sender,
|
||||
};
|
||||
|
||||
mod dialog;
|
||||
@@ -72,6 +73,7 @@ use crate::button::Button;
|
||||
use crate::scroll_viewer::ScrollViewer;
|
||||
use crate::text::Text;
|
||||
use crate::text_box::TextBox;
|
||||
use crate::widget::UserData;
|
||||
pub use field::*;
|
||||
pub use filter::*;
|
||||
pub use selector::*;
|
||||
@@ -100,6 +102,29 @@ enum FsEventMessage {
|
||||
}
|
||||
impl MessageData for FsEventMessage {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FsWatcher(notify::RecommendedWatcher);
|
||||
|
||||
impl PartialEq for FsWatcher {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for FsWatcher {
|
||||
type Target = notify::RecommendedWatcher;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for FsWatcher {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Visit, PartialEq, Reflect)]
|
||||
#[reflect(type_uuid = "b7f4610e-4b0c-4671-9b4a-60bb45268928")]
|
||||
#[reflect(derived_type = "UiNode")]
|
||||
@@ -122,7 +147,7 @@ pub struct FileBrowser {
|
||||
pub item_context_menu: RcUiNodeHandle,
|
||||
#[visit(skip)]
|
||||
#[reflect(hidden)]
|
||||
pub watcher: Option<notify::RecommendedWatcher>,
|
||||
pub watcher: Option<FsWatcher>,
|
||||
}
|
||||
|
||||
impl ConstructorProvider<UiNode, UserInterface> for FileBrowser {
|
||||
@@ -282,7 +307,7 @@ impl FileBrowser {
|
||||
};
|
||||
if let Some(root) = self.root.clone() {
|
||||
self.set_path(&root, ui);
|
||||
let tree_item_path = Arc::new(Mutex::new(TreeItemPath::root(root.clone())));
|
||||
let tree_item_path = UserData::new(TreeItemPath::root(root.clone()));
|
||||
ui[self.tree_root].user_data = Some(tree_item_path.clone());
|
||||
self.user_data = Some(tree_item_path);
|
||||
}
|
||||
@@ -558,7 +583,7 @@ impl Control for FileBrowser {
|
||||
ui.node(widget)
|
||||
.user_data
|
||||
.as_ref()
|
||||
.is_some_and(|data| data.safe_lock().downcast_ref::<TreeItemPath>().is_some())
|
||||
.is_some_and(|data| data.downcast::<TreeItemPath>().is_some())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,7 +844,7 @@ fn setup_file_browser_fs_watcher(
|
||||
sender: Sender<UiMessage>,
|
||||
file_browser_handle: Handle<FileBrowser>,
|
||||
the_path: PathBuf,
|
||||
) -> Option<notify::RecommendedWatcher> {
|
||||
) -> Option<FsWatcher> {
|
||||
let handler = EventReceiver {
|
||||
file_browser_handle,
|
||||
sender,
|
||||
@@ -828,7 +853,7 @@ fn setup_file_browser_fs_watcher(
|
||||
match notify::RecommendedWatcher::new(handler, config) {
|
||||
Ok(mut watcher) => {
|
||||
Log::verify(watcher.watch(&the_path, notify::RecursiveMode::Recursive));
|
||||
Some(watcher)
|
||||
Some(FsWatcher(watcher))
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
|
||||
use crate::file_browser::fs_tree::{sanitize_path, TreeItemPath};
|
||||
use crate::file_browser::{FileType, PathFilter};
|
||||
use crate::widget::UserData;
|
||||
use crate::{
|
||||
core::{algebra::Vector2, parking_lot::Mutex, pool::Handle},
|
||||
core::{algebra::Vector2, pool::Handle},
|
||||
file_browser::{
|
||||
fs_tree::{self, read_dir_entries, DisksProvider},
|
||||
FileBrowserBuilder, FileBrowserMessage,
|
||||
@@ -35,7 +36,6 @@ use fyrox_graph::SceneGraph;
|
||||
use std::{
|
||||
fs::File,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
fn create_dir(path: impl AsRef<Path>) {
|
||||
@@ -124,7 +124,7 @@ fn test_find_tree() {
|
||||
let mut ui = UserInterface::new(Vector2::new(100.0, 100.0));
|
||||
|
||||
let root = TreeRootBuilder::new(
|
||||
WidgetBuilder::new().with_user_data(Arc::new(Mutex::new(PathBuf::from("test")))),
|
||||
WidgetBuilder::new().with_user_data(UserData::new(PathBuf::from("test"))),
|
||||
)
|
||||
.build(&mut ui.build_ctx())
|
||||
.to_base();
|
||||
|
||||
@@ -26,8 +26,7 @@ use crate::{
|
||||
PropertyEditorDefinitionContainer, PropertyEditorInstance,
|
||||
PropertyEditorMessageContext, PropertyEditorTranslationContext,
|
||||
},
|
||||
make_expander_container, CollectionAction, FieldAction, InspectorEnvironment,
|
||||
InspectorError, PropertyChanged,
|
||||
make_expander_container, CollectionAction, FieldAction, InspectorError, PropertyChanged,
|
||||
},
|
||||
inspector::{make_property_margin, PropertyFilter},
|
||||
message::{MessageDirection, UiMessage},
|
||||
@@ -36,6 +35,7 @@ use crate::{
|
||||
BuildContext, Control, Thickness, UiNode, UserInterface,
|
||||
};
|
||||
|
||||
use crate::inspector::InspectorEnvironmentContainer;
|
||||
use crate::message::{DeliveryMode, MessageData};
|
||||
use fyrox_graph::SceneGraph;
|
||||
use std::sync::Arc;
|
||||
@@ -92,7 +92,7 @@ where
|
||||
{
|
||||
widget_builder: WidgetBuilder,
|
||||
collection: Option<I>,
|
||||
environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
environment: Option<InspectorEnvironmentContainer>,
|
||||
definition_container: Option<Arc<PropertyEditorDefinitionContainer>>,
|
||||
layer_index: usize,
|
||||
generate_property_string_values: bool,
|
||||
@@ -111,7 +111,7 @@ fn create_item_views(items: &[Item]) -> Vec<Handle<UiNode>> {
|
||||
|
||||
fn create_items<'a, 'b, T, I>(
|
||||
iter: I,
|
||||
environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
environment: Option<InspectorEnvironmentContainer>,
|
||||
definition_container: Arc<PropertyEditorDefinitionContainer>,
|
||||
property_info: &FieldRef<'a, 'b>,
|
||||
ctx: &mut BuildContext,
|
||||
@@ -209,7 +209,7 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_environment(mut self, environment: Option<Arc<dyn InspectorEnvironment>>) -> Self {
|
||||
pub fn with_environment(mut self, environment: Option<InspectorEnvironmentContainer>) -> Self {
|
||||
self.environment = environment;
|
||||
self
|
||||
}
|
||||
@@ -317,7 +317,7 @@ where
|
||||
|
||||
impl<T, const N: usize> PropertyEditorDefinition for ArrayPropertyEditorDefinition<T, N>
|
||||
where
|
||||
T: Reflect + Clone,
|
||||
T: Reflect + Clone + PartialEq,
|
||||
{
|
||||
fn value_type_id(&self) -> TypeId {
|
||||
TypeId::of::<[T; N]>()
|
||||
|
||||
@@ -66,7 +66,7 @@ where
|
||||
|
||||
impl<T> PropertyEditorDefinition for CellPropertyEditorDefinition<T>
|
||||
where
|
||||
T: Reflect + Copy,
|
||||
T: Reflect + Copy + PartialEq,
|
||||
{
|
||||
fn value_type_id(&self) -> TypeId {
|
||||
TypeId::of::<Cell<T>>()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::inspector::InspectorEnvironmentContainer;
|
||||
use crate::{
|
||||
button::{Button, ButtonMessage},
|
||||
core::{
|
||||
@@ -31,7 +32,7 @@ use crate::{
|
||||
PropertyEditorMessageContext, PropertyEditorTranslationContext,
|
||||
},
|
||||
make_expander_container, make_property_margin, CollectionAction, FieldAction,
|
||||
InspectorEnvironment, InspectorError, ObjectValue, PropertyChanged, PropertyFilter,
|
||||
InspectorError, ObjectValue, PropertyChanged, PropertyFilter,
|
||||
},
|
||||
message::{DeliveryMode, MessageData, MessageDirection, UiMessage},
|
||||
resources,
|
||||
@@ -177,7 +178,7 @@ where
|
||||
{
|
||||
widget_builder: WidgetBuilder,
|
||||
collection: Option<I>,
|
||||
environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
environment: Option<InspectorEnvironmentContainer>,
|
||||
definition_container: Option<Arc<PropertyEditorDefinitionContainer>>,
|
||||
add: Handle<Button>,
|
||||
layer_index: usize,
|
||||
@@ -209,7 +210,7 @@ fn create_item_views(items: &[Item], ctx: &mut BuildContext) -> Vec<Handle<UiNod
|
||||
|
||||
fn create_items<'a, 'b, T, I>(
|
||||
iter: I,
|
||||
environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
environment: Option<InspectorEnvironmentContainer>,
|
||||
definition_container: Arc<PropertyEditorDefinitionContainer>,
|
||||
property_info: &FieldRef<'a, 'b>,
|
||||
ctx: &mut BuildContext,
|
||||
@@ -321,7 +322,7 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_environment(mut self, environment: Option<Arc<dyn InspectorEnvironment>>) -> Self {
|
||||
pub fn with_environment(mut self, environment: Option<InspectorEnvironmentContainer>) -> Self {
|
||||
self.environment = environment;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::inspector::InspectorEnvironmentContainer;
|
||||
use crate::{
|
||||
core::{pool::Handle, reflect::prelude::*, visitor::prelude::*},
|
||||
dropdown_list::{DropdownList, DropdownListBuilder, DropdownListMessage},
|
||||
@@ -28,8 +29,7 @@ use crate::{
|
||||
PropertyEditorMessageContext, PropertyEditorTranslationContext,
|
||||
},
|
||||
make_expander_container, FieldAction, Inspector, InspectorBuilder, InspectorContext,
|
||||
InspectorContextArgs, InspectorEnvironment, InspectorError, InspectorMessage,
|
||||
PropertyChanged, PropertyFilter,
|
||||
InspectorContextArgs, InspectorError, InspectorMessage, PropertyChanged, PropertyFilter,
|
||||
},
|
||||
message::{MessageData, UiMessage},
|
||||
utils::make_dropdown_list_option,
|
||||
@@ -76,7 +76,7 @@ pub struct EnumPropertyEditor<T: InspectableEnum> {
|
||||
pub definition_container: Arc<PropertyEditorDefinitionContainer>,
|
||||
#[visit(skip)]
|
||||
#[reflect(hidden)]
|
||||
pub environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
pub environment: Option<InspectorEnvironmentContainer>,
|
||||
#[visit(skip)]
|
||||
#[reflect(hidden)]
|
||||
pub layer_index: usize,
|
||||
@@ -183,7 +183,7 @@ impl<T: InspectableEnum> Control for EnumPropertyEditor<T> {
|
||||
pub struct EnumPropertyEditorBuilder {
|
||||
widget_builder: WidgetBuilder,
|
||||
definition_container: Option<Arc<PropertyEditorDefinitionContainer>>,
|
||||
environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
environment: Option<InspectorEnvironmentContainer>,
|
||||
variant_selector: Handle<UiNode>,
|
||||
layer_index: usize,
|
||||
generate_property_string_values: bool,
|
||||
@@ -211,7 +211,7 @@ impl EnumPropertyEditorBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_environment(mut self, environment: Option<Arc<dyn InspectorEnvironment>>) -> Self {
|
||||
pub fn with_environment(mut self, environment: Option<InspectorEnvironmentContainer>) -> Self {
|
||||
self.environment = environment;
|
||||
self
|
||||
}
|
||||
@@ -293,6 +293,7 @@ impl EnumPropertyEditorBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct EnumPropertyEditorDefinition<T: InspectableEnum> {
|
||||
pub variant_generator: fn(usize) -> T,
|
||||
pub index_generator: fn(&T) -> usize,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
//! A collection of [PropertyEditorDefinition] objects for a wide variety of types,
|
||||
//! including standard Rust types and Fyrox core types.
|
||||
|
||||
use crate::inspector::InspectorEnvironmentContainer;
|
||||
use crate::style::{StyleProperty, StylePropertyContainer};
|
||||
use crate::{
|
||||
absm::{EventAction, EventKind},
|
||||
@@ -80,7 +81,7 @@ use crate::{
|
||||
Vec4PropertyEditorDefinition,
|
||||
},
|
||||
},
|
||||
InspectorEnvironment, InspectorError, PropertyChanged, PropertyFilter,
|
||||
InspectorError, PropertyChanged, PropertyFilter,
|
||||
},
|
||||
key::{HotKeyEditor, KeyBinding, KeyBindingEditor},
|
||||
list_view::{ListView, ListViewItem},
|
||||
@@ -166,7 +167,7 @@ pub struct PropertyEditorBuildContext<'a, 'b, 'c, 'd> {
|
||||
/// [fyroxed_base::inspector::EditorEnvironment](https://docs.rs/fyroxed_base/latest/fyroxed_base/inspector/struct.EditorEnvironment.html)
|
||||
/// when the Inspector is being used in Fyroxed, but Inspector widgets can be used in other applications,
|
||||
/// and we can access those applications by casting the environment to the appropriate type.
|
||||
pub environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
pub environment: Option<InspectorEnvironmentContainer>,
|
||||
/// The list of the Inspectors property editors.
|
||||
/// This allows one property editor to make use of other property editors.
|
||||
pub definition_container: Arc<PropertyEditorDefinitionContainer>,
|
||||
@@ -215,7 +216,7 @@ pub struct PropertyEditorMessageContext<'a, 'b, 'c> {
|
||||
/// this property is being translated. This allows the created message to
|
||||
/// adapt to the situation if we can successfully cast the given
|
||||
/// [InspectorEnvironment] into a specific type.
|
||||
pub environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
pub environment: Option<InspectorEnvironmentContainer>,
|
||||
/// When true, this indicates that an Inspector should generate strings from `format!("{:?}", field)`, for each field.
|
||||
/// Having this in the property editor build context indicates how any Inspectors that are update due to the created message
|
||||
/// should behave.
|
||||
@@ -251,7 +252,7 @@ pub struct PropertyEditorTranslationContext<'b, 'c> {
|
||||
/// [fyrox::script::Script](https://docs.rs/fyrox/latest/fyrox/script/struct.Script.html)
|
||||
/// when it receives a
|
||||
/// [ScriptPropertyEditorMessage::Value](https://docs.rs/fyroxed_base/latest/fyroxed_base/inspector/editors/script/enum.ScriptPropertyEditorMessage.html#variant.Value).
|
||||
pub environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
pub environment: Option<InspectorEnvironmentContainer>,
|
||||
/// The name of the property being edited.
|
||||
/// This comes from [ContextEntry::property_name](crate::inspector::ContextEntry).
|
||||
pub name: &'b str,
|
||||
@@ -372,6 +373,18 @@ pub struct PropertyEditorDefinitionContainer {
|
||||
definitions: RwLock<FxHashMap<TypeId, PropertyEditorDefinitionContainerEntry>>,
|
||||
}
|
||||
|
||||
impl PartialEq for PropertyEditorDefinitionContainer {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self.context_type_id.safe_lock() == *other.context_type_id.safe_lock()
|
||||
&& self
|
||||
.definitions
|
||||
.read()
|
||||
.keys()
|
||||
.zip(other.definitions.read().keys())
|
||||
.all(|(a, b)| *a == *b)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PropertyEditorDefinitionContainer {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "PropertyEditorDefinitionContainer")
|
||||
|
||||
@@ -69,7 +69,7 @@ where
|
||||
|
||||
impl<T> PropertyEditorDefinition for RefCellPropertyEditorDefinition<T>
|
||||
where
|
||||
T: Reflect + Clone,
|
||||
T: Reflect + Clone + PartialEq,
|
||||
{
|
||||
fn value_type_id(&self) -> TypeId {
|
||||
TypeId::of::<RefCell<T>>()
|
||||
|
||||
@@ -502,7 +502,7 @@ where
|
||||
|
||||
impl<T> PropertyEditorDefinition for StyledPropertyEditorDefinition<T>
|
||||
where
|
||||
T: Reflect + Clone,
|
||||
T: Reflect + Clone + PartialEq,
|
||||
{
|
||||
fn value_type_id(&self) -> TypeId {
|
||||
TypeId::of::<StyledProperty<T>>()
|
||||
|
||||
@@ -54,6 +54,7 @@ use fyrox_graph::{
|
||||
constructor::{ConstructorProvider, GraphNodeConstructor},
|
||||
SceneGraph,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
fmt::{Debug, Display, Formatter},
|
||||
@@ -432,6 +433,23 @@ pub trait InspectorEnvironment: Send + Sync + Reflect {
|
||||
fn name(&self) -> String;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InspectorEnvironmentContainer(pub Arc<dyn InspectorEnvironment>);
|
||||
|
||||
impl PartialEq for InspectorEnvironmentContainer {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.try_compare(&*other.0).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for InspectorEnvironmentContainer {
|
||||
type Target = dyn InspectorEnvironment;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Inspector is a widget, that allows you to generate visual representation for internal fields an arbitrary
|
||||
/// structure or enumeration recursively. It's primary usage is provide unified and simple way of introspection.
|
||||
///
|
||||
@@ -813,7 +831,7 @@ pub struct InspectorContext {
|
||||
pub property_definitions: Arc<PropertyEditorDefinitionContainer>,
|
||||
/// Untyped information from the application that is using the inspector. This can be used by editors that may be
|
||||
/// supplied by that application, if those editors know the actual type of this value to be able to successfully cast it.
|
||||
pub environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
pub environment: Option<InspectorEnvironmentContainer>,
|
||||
/// Type id of the object for which the context was created.
|
||||
pub object_type_id: TypeId,
|
||||
/// A width of the property name column.
|
||||
@@ -1009,6 +1027,16 @@ fn make_simple_property_container(
|
||||
#[derive(Default, Clone)]
|
||||
pub struct PropertyFilter(pub Option<Arc<dyn Fn(&dyn Reflect) -> bool + Send + Sync>>);
|
||||
|
||||
impl PartialEq for PropertyFilter {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if let (Some(a), Some(b)) = (self.0.as_ref(), other.0.as_ref()) {
|
||||
Arc::ptr_eq(a, b)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PropertyFilter {
|
||||
pub fn new<T>(func: T) -> Self
|
||||
where
|
||||
@@ -1046,7 +1074,7 @@ pub struct InspectorContextArgs<'a, 'b, 'c> {
|
||||
pub object: &'a dyn Reflect,
|
||||
pub ctx: &'b mut BuildContext<'c>,
|
||||
pub definition_container: Arc<PropertyEditorDefinitionContainer>,
|
||||
pub environment: Option<Arc<dyn InspectorEnvironment>>,
|
||||
pub environment: Option<InspectorEnvironmentContainer>,
|
||||
pub layer_index: usize,
|
||||
pub generate_property_string_values: bool,
|
||||
pub filter: PropertyFilter,
|
||||
|
||||
+127
-70
@@ -372,6 +372,12 @@ pub(crate) struct RcUiNodeHandleInner {
|
||||
sender: Option<Sender<UiMessage>>,
|
||||
}
|
||||
|
||||
impl PartialEq for RcUiNodeHandleInner {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.handle == other.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for RcUiNodeHandleInner {
|
||||
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
|
||||
self.handle.visit(name, visitor)?;
|
||||
@@ -529,7 +535,7 @@ impl NodeStatistics {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Visit, Reflect, Debug, Clone)]
|
||||
#[derive(Visit, Reflect, PartialEq, Debug, Clone)]
|
||||
#[reflect(type_uuid = "9f9d5633-1568-4611-8709-3eeb615b7c0f")]
|
||||
pub struct DragContext {
|
||||
pub is_dragging: bool,
|
||||
@@ -568,7 +574,7 @@ impl Default for MouseState {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Visit, Reflect, Debug, Default)]
|
||||
#[derive(Copy, Clone, Visit, PartialEq, Reflect, Debug, Default)]
|
||||
#[reflect(type_uuid = "2f1add9c-5019-4922-9045-0bd5ca2fd63a")]
|
||||
pub struct RestrictionEntry {
|
||||
/// Handle to UI node to which picking must be restricted to.
|
||||
@@ -584,7 +590,7 @@ pub struct RestrictionEntry {
|
||||
pub stop: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct TooltipEntry {
|
||||
pub tooltip: RcUiNodeHandle,
|
||||
pub appear_timer: f32,
|
||||
@@ -620,7 +626,7 @@ pub enum LayoutEvent {
|
||||
TransformChanged(Handle<UiNode>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Visit, Reflect, Default)]
|
||||
#[derive(Clone, Debug, Visit, Reflect, PartialEq, Default)]
|
||||
#[reflect(type_uuid = "30bc5bc5-6592-48d8-8647-9bdbbb977ffb")]
|
||||
struct DoubleClickEntry {
|
||||
timer: f32,
|
||||
@@ -629,13 +635,19 @@ struct DoubleClickEntry {
|
||||
|
||||
struct Clipboard(Option<RefCell<ClipboardContext>>);
|
||||
|
||||
impl PartialEq for Clipboard {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Clipboard {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Clipboard")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
#[derive(Default, PartialEq, Debug, Clone)]
|
||||
struct WidgetMethodsRegistry {
|
||||
preview_message: FxHashSet<Handle<UiNode>>,
|
||||
on_update: FxHashSet<Handle<UiNode>>,
|
||||
@@ -681,7 +693,7 @@ pub struct UiUpdateSwitches {
|
||||
|
||||
pub type WidgetPool = Pool<UiNode, WidgetContainer>;
|
||||
|
||||
#[derive(Default, Debug, Clone, Reflect, Visit)]
|
||||
#[derive(Default, Debug, Clone, PartialEq, Reflect, Visit)]
|
||||
#[reflect(type_uuid = "b426e937-4050-4539-8041-ade4222539c8")]
|
||||
pub enum RenderMode {
|
||||
/// The UI will be re-rendered on every frame. This is the default behavior.
|
||||
@@ -693,6 +705,29 @@ pub enum RenderMode {
|
||||
OnChanges,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UiMessageChannel {
|
||||
pub receiver: Receiver<UiMessage>,
|
||||
pub sender: Sender<UiMessage>,
|
||||
}
|
||||
|
||||
impl UiMessageChannel {
|
||||
pub fn new() -> Self {
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
Self { receiver, sender }
|
||||
}
|
||||
|
||||
pub fn send(&self, message: UiMessage) {
|
||||
let _ = self.sender.send(message);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for UiMessageChannel {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Reflect, PartialEq)]
|
||||
#[reflect(type_uuid = "0d065c93-ef9c-4dd2-9fe7-e2b33c1a21b6")]
|
||||
pub struct UserInterface {
|
||||
@@ -709,9 +744,7 @@ pub struct UserInterface {
|
||||
cursor_position: Vector2<f32>,
|
||||
pub style: StyleResource,
|
||||
#[reflect(hidden)]
|
||||
receiver: Receiver<UiMessage>,
|
||||
#[reflect(hidden)]
|
||||
sender: Sender<UiMessage>,
|
||||
ui_message_channel: UiMessageChannel,
|
||||
stack: Vec<Handle<UiNode>>,
|
||||
picking_stack: Vec<RestrictionEntry>,
|
||||
#[reflect(hidden)]
|
||||
@@ -727,9 +760,9 @@ pub struct UserInterface {
|
||||
#[reflect(hidden)]
|
||||
clipboard: Clipboard,
|
||||
#[reflect(hidden)]
|
||||
layout_events_receiver: Receiver<LayoutEvent>,
|
||||
layout_events_receiver: LayoutEventsReceiver,
|
||||
#[reflect(hidden)]
|
||||
layout_events_sender: Sender<LayoutEvent>,
|
||||
layout_events_sender: LayoutEventsSender,
|
||||
#[reflect(hidden)]
|
||||
z_index_update_set: FxHashSet<Handle<UiNode>>,
|
||||
#[reflect(hidden)]
|
||||
@@ -767,8 +800,7 @@ impl Debug for UserInterface {
|
||||
.field("keyboard_focus_node", &self.keyboard_focus_node)
|
||||
.field("cursor_position", &self.cursor_position)
|
||||
.field("style", &self.style)
|
||||
.field("receiver", &self.receiver)
|
||||
.field("sender", &self.sender)
|
||||
.field("ui_message_channel", &self.ui_message_channel)
|
||||
.field("stack", &self.stack)
|
||||
.field("picking_stack", &self.picking_stack)
|
||||
.field("bubble_queue", &self.bubble_queue)
|
||||
@@ -842,10 +874,46 @@ impl Visit for UserInterface {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LayoutEventsSender(pub Sender<LayoutEvent>);
|
||||
|
||||
impl PartialEq for LayoutEventsSender {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for LayoutEventsSender {
|
||||
type Target = Sender<LayoutEvent>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LayoutEventsReceiver(pub Receiver<LayoutEvent>);
|
||||
|
||||
impl PartialEq for LayoutEventsReceiver {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for LayoutEventsReceiver {
|
||||
type Target = Receiver<LayoutEvent>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for UserInterface {
|
||||
fn clone(&self) -> Self {
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
let ui_message_channel = UiMessageChannel::new();
|
||||
let (layout_events_sender, layout_events_receiver) = mpsc::channel();
|
||||
let layout_events_sender = LayoutEventsSender(layout_events_sender);
|
||||
let layout_events_receiver = LayoutEventsReceiver(layout_events_receiver);
|
||||
let mut nodes = Pool::new();
|
||||
for (handle, node) in self.nodes.pair_iter() {
|
||||
let mut clone = node.clone_boxed();
|
||||
@@ -865,8 +933,7 @@ impl Clone for UserInterface {
|
||||
keyboard_focus_node: self.keyboard_focus_node,
|
||||
cursor_position: self.cursor_position,
|
||||
style: DEFAULT_STYLE.resource.clone(),
|
||||
receiver,
|
||||
sender,
|
||||
ui_message_channel,
|
||||
stack: self.stack.clone(),
|
||||
picking_stack: self.picking_stack.clone(),
|
||||
bubble_queue: self.bubble_queue.clone(),
|
||||
@@ -1160,21 +1227,19 @@ pub struct PollResult {
|
||||
|
||||
impl UserInterface {
|
||||
pub fn new(screen_size: Vector2<f32>) -> UserInterface {
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
Self::new_with_channel(sender, receiver, screen_size)
|
||||
let ui_message_channel = UiMessageChannel::new();
|
||||
Self::new_with_channel(ui_message_channel, screen_size)
|
||||
}
|
||||
|
||||
pub fn new_with_channel(
|
||||
sender: Sender<UiMessage>,
|
||||
receiver: Receiver<UiMessage>,
|
||||
ui_message_channel: UiMessageChannel,
|
||||
screen_size: Vector2<f32>,
|
||||
) -> UserInterface {
|
||||
let (layout_events_sender, layout_events_receiver) = mpsc::channel();
|
||||
let style = DEFAULT_STYLE.resource.clone();
|
||||
let mut ui = UserInterface {
|
||||
screen_size,
|
||||
sender,
|
||||
receiver,
|
||||
ui_message_channel,
|
||||
visual_debug: false,
|
||||
captured_node: Handle::NONE,
|
||||
root_canvas: Handle::NONE,
|
||||
@@ -1195,8 +1260,8 @@ impl UserInterface {
|
||||
active_tooltip: Default::default(),
|
||||
methods_registry: Default::default(),
|
||||
clipboard: Clipboard(ClipboardContext::new().ok().map(RefCell::new)),
|
||||
layout_events_receiver,
|
||||
layout_events_sender,
|
||||
layout_events_receiver: LayoutEventsReceiver(layout_events_receiver),
|
||||
layout_events_sender: LayoutEventsSender(layout_events_sender),
|
||||
z_index_update_set: Default::default(),
|
||||
default_font: BUILT_IN_FONT.resource(),
|
||||
double_click_entries: Default::default(),
|
||||
@@ -2025,11 +2090,11 @@ impl UserInterface {
|
||||
/// Returns instance of message sender which can be used to push messages into queue
|
||||
/// from other threads.
|
||||
pub fn sender(&self) -> Sender<UiMessage> {
|
||||
self.sender.clone()
|
||||
self.ui_message_channel.sender.clone()
|
||||
}
|
||||
|
||||
pub fn send_message(&self, message: UiMessage) {
|
||||
self.sender.send(message).unwrap()
|
||||
self.ui_message_channel.send(message)
|
||||
}
|
||||
|
||||
pub fn try_send_response(&self, message: &UiMessage) -> bool {
|
||||
@@ -2048,13 +2113,11 @@ impl UserInterface {
|
||||
}
|
||||
|
||||
pub fn send(&self, handle: Handle<impl ObjectOrVariant<UiNode>>, data: impl MessageData) {
|
||||
self.sender
|
||||
.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::ToWidget),
|
||||
)
|
||||
.unwrap()
|
||||
self.ui_message_channel.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::ToWidget),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn send_handled(
|
||||
@@ -2062,25 +2125,21 @@ impl UserInterface {
|
||||
handle: Handle<impl ObjectOrVariant<UiNode>>,
|
||||
data: impl MessageData,
|
||||
) {
|
||||
self.sender
|
||||
.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::ToWidget)
|
||||
.with_handled(true),
|
||||
)
|
||||
.unwrap()
|
||||
self.ui_message_channel.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::ToWidget)
|
||||
.with_handled(true),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn send_sync(&self, handle: Handle<impl ObjectOrVariant<UiNode>>, data: impl MessageData) {
|
||||
self.sender
|
||||
.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::ToWidget)
|
||||
.with_delivery_mode(DeliveryMode::SyncOnly),
|
||||
)
|
||||
.unwrap()
|
||||
self.ui_message_channel.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::ToWidget)
|
||||
.with_delivery_mode(DeliveryMode::SyncOnly),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn send_with_flags<T: MessageData>(
|
||||
@@ -2089,14 +2148,12 @@ impl UserInterface {
|
||||
flags: u64,
|
||||
data: T,
|
||||
) {
|
||||
self.sender
|
||||
.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::ToWidget)
|
||||
.with_flags(flags),
|
||||
)
|
||||
.unwrap()
|
||||
self.ui_message_channel.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::ToWidget)
|
||||
.with_flags(flags),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn send_many<const N: usize, T: MessageData>(
|
||||
@@ -2120,13 +2177,11 @@ impl UserInterface {
|
||||
}
|
||||
|
||||
pub fn post<T: MessageData>(&self, handle: Handle<impl ObjectOrVariant<UiNode>>, data: T) {
|
||||
self.sender
|
||||
.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::FromWidget),
|
||||
)
|
||||
.unwrap()
|
||||
self.ui_message_channel.send(
|
||||
UiMessage::with_data(data)
|
||||
.with_destination(handle.transmute())
|
||||
.with_direction(MessageDirection::FromWidget),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn post_many<const N: usize, T: MessageData>(
|
||||
@@ -2248,7 +2303,7 @@ impl UserInterface {
|
||||
message: None,
|
||||
};
|
||||
|
||||
while let Ok(message) = self.receiver.try_recv() {
|
||||
while let Ok(message) = self.ui_message_channel.receiver.try_recv() {
|
||||
poll_result.processed_messages += 1;
|
||||
if let Some(message) = self.poll_single_message(message) {
|
||||
poll_result.message = Some(message);
|
||||
@@ -2584,7 +2639,7 @@ impl UserInterface {
|
||||
/// Find any tooltips that are being hovered and activate them.
|
||||
/// As well, update their time.
|
||||
fn update_tooltips(&mut self, dt: f32) {
|
||||
let sender = self.sender.clone();
|
||||
let sender = self.ui_message_channel.sender.clone();
|
||||
if let Some(entry) = self.active_tooltip.as_mut() {
|
||||
if entry.shown {
|
||||
entry.disappear_timer -= dt;
|
||||
@@ -3488,13 +3543,15 @@ impl UserInterface {
|
||||
let (mut ui, data) = {
|
||||
let data = io.load_file(path.as_ref()).await?;
|
||||
let mut visitor = Visitor::load_from_memory(&data)?;
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
let ui_message_channel = UiMessageChannel::new();
|
||||
visitor.blackboard.register(constructors);
|
||||
visitor.blackboard.register(Arc::new(sender.clone()));
|
||||
visitor
|
||||
.blackboard
|
||||
.register(Arc::new(ui_message_channel.sender.clone()));
|
||||
visitor.blackboard.register(Arc::new(resource_manager));
|
||||
visitor.blackboard.register(dyn_type_constructors);
|
||||
let mut ui =
|
||||
UserInterface::new_with_channel(sender, receiver, Vector2::new(100.0, 100.0));
|
||||
UserInterface::new_with_channel(ui_message_channel, Vector2::new(100.0, 100.0));
|
||||
ui.visit("Ui", &mut visitor)?;
|
||||
(ui, data)
|
||||
};
|
||||
@@ -3637,7 +3694,7 @@ impl SceneGraph for UserInterface {
|
||||
let node = node.to_base();
|
||||
self.isolate_node(node);
|
||||
|
||||
let sender = self.sender.clone();
|
||||
let sender = self.ui_message_channel.sender.clone();
|
||||
let mut stack = vec![node];
|
||||
while let Some(handle) = stack.pop() {
|
||||
if self.prev_picked_node == handle {
|
||||
|
||||
@@ -150,7 +150,7 @@ pub static LIGHT_STYLE: LazyLock<BuiltInResource<Style>> = LazyLock::new(|| {
|
||||
/// the style and why do we need to store the value as well? The answer is flexibility. In this
|
||||
/// approach, style becomes not necessary and the value can be hardcoded. Also, the values of such
|
||||
/// properties can be updated individually.
|
||||
#[derive(Clone, Debug, PartialEq, Reflect, Default)]
|
||||
#[derive(Clone, Debug, Reflect, Default)]
|
||||
#[reflect(
|
||||
bounds = "T: Reflect + Clone + PartialEq",
|
||||
type_uuid = "71e84137-2832-42a1-bcb5-f8ee95784997"
|
||||
|
||||
@@ -50,6 +50,7 @@ use crate::{
|
||||
};
|
||||
use copypasta::ClipboardProvider;
|
||||
use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
|
||||
use std::ops::Deref;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fmt::{Debug, Formatter},
|
||||
@@ -195,6 +196,23 @@ impl SelectionRange {
|
||||
/// the filter, and `false` - otherwise.
|
||||
pub type FilterCallback = dyn FnMut(char) -> bool + Send;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TextBoxFilter(pub Arc<Mutex<FilterCallback>>);
|
||||
|
||||
impl PartialEq for TextBoxFilter {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for TextBoxFilter {
|
||||
type Target = Mutex<FilterCallback>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// TextBox is a text widget that allows you to edit text and create specialized input fields. It has various options like
|
||||
/// word wrapping, text alignment, and so on.
|
||||
///
|
||||
@@ -427,7 +445,7 @@ pub struct TextBox {
|
||||
/// Current character filter of the text box.
|
||||
#[visit(skip)]
|
||||
#[reflect(hidden)]
|
||||
pub filter: Option<Arc<Mutex<FilterCallback>>>,
|
||||
pub filter: Option<TextBoxFilter>,
|
||||
/// Current text commit mode of the text box.
|
||||
pub commit_mode: InheritableVariable<TextCommitMode>,
|
||||
/// `true` if the multiline mode is active.
|
||||
@@ -1527,7 +1545,7 @@ pub struct TextBoxBuilder<'a> {
|
||||
text: String,
|
||||
caret_brush: Brush,
|
||||
selection_brush: Brush,
|
||||
filter: Option<Arc<Mutex<FilterCallback>>>,
|
||||
filter: Option<TextBoxFilter>,
|
||||
vertical_alignment: VerticalAlignment,
|
||||
horizontal_alignment: HorizontalAlignment,
|
||||
wrap: WrapMode,
|
||||
@@ -1613,7 +1631,7 @@ impl<'a> TextBoxBuilder<'a> {
|
||||
}
|
||||
|
||||
/// Sets the desired character filter of the text box. See [`FilterCallback`] for more info.
|
||||
pub fn with_filter(mut self, filter: Arc<Mutex<FilterCallback>>) -> Self {
|
||||
pub fn with_filter(mut self, filter: TextBoxFilter) -> Self {
|
||||
self.filter = Some(filter);
|
||||
self
|
||||
}
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::widget::UserData;
|
||||
use crate::{
|
||||
border::BorderBuilder,
|
||||
button::{Button, ButtonBuilder},
|
||||
core::{algebra::Vector2, color::Color, parking_lot::Mutex, pool::Handle},
|
||||
core::{algebra::Vector2, color::Color, pool::Handle},
|
||||
decorator::DecoratorBuilder,
|
||||
formatted_text::WrapMode,
|
||||
grid::{Column, GridBuilder, Row},
|
||||
@@ -37,7 +38,6 @@ use fyrox_texture::{
|
||||
CompressionOptions, TextureImportOptions, TextureMinificationFilter, TextureResource,
|
||||
TextureResourceExtension,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub enum ArrowDirection {
|
||||
@@ -233,7 +233,7 @@ pub fn make_dropdown_list_option_universal<T: Send + 'static>(
|
||||
BorderBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_height(height)
|
||||
.with_user_data(Arc::new(Mutex::new(user_data)))
|
||||
.with_user_data(UserData::new(user_data))
|
||||
.with_child(
|
||||
TextBuilder::new(WidgetBuilder::new().with_margin(text_margin()))
|
||||
.with_vertical_text_alignment(VerticalAlignment::Center)
|
||||
|
||||
+32
-13
@@ -41,9 +41,10 @@ use crate::{
|
||||
resource::{StyleResource, StyleResourceExt},
|
||||
Style, StyledProperty, DEFAULT_STYLE,
|
||||
},
|
||||
BuildContext, HorizontalAlignment, LayoutEvent, MouseButton, MouseState, RcUiNodeHandle,
|
||||
Thickness, UiNode, UserInterface, VerticalAlignment,
|
||||
BuildContext, HorizontalAlignment, LayoutEvent, LayoutEventsSender, MouseButton, MouseState,
|
||||
RcUiNodeHandle, Thickness, UiNode, UserInterface, VerticalAlignment,
|
||||
};
|
||||
use fyrox_core::parking_lot::{MappedMutexGuard, MutexGuard};
|
||||
use fyrox_core::pool::ObjectOrVariant;
|
||||
use fyrox_graph::SceneGraph;
|
||||
use fyrox_material::{Material, MaterialResource};
|
||||
@@ -54,7 +55,7 @@ use std::{
|
||||
cmp::Ordering,
|
||||
fmt::{Debug, Formatter},
|
||||
ops::{Deref, DerefMut},
|
||||
sync::{mpsc::Sender, Arc},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
/// Sorting predicate that is used to sort widgets by some criteria.
|
||||
@@ -536,6 +537,25 @@ impl WidgetRenderDataSet {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UserData(pub Arc<Mutex<dyn Any + Send>>);
|
||||
|
||||
impl UserData {
|
||||
pub fn new<T: Any + Send>(v: T) -> Self {
|
||||
Self(Arc::new(Mutex::new(v)))
|
||||
}
|
||||
|
||||
pub fn downcast<T: Any + Send>(&self) -> Option<MappedMutexGuard<T>> {
|
||||
MutexGuard::try_map(self.0.safe_lock(), |v| v.downcast_mut::<T>()).ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for UserData {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Widget is a base UI element, that is always used to build derived, more complex, widgets. In general, it is a container
|
||||
/// for layout information, basic visual appearance, visibility options, parent-child information. It does almost nothing
|
||||
/// on its own, instead, the user interface modifies its state accordingly.
|
||||
@@ -619,7 +639,7 @@ pub struct Widget {
|
||||
/// Optional, user-defined data.
|
||||
#[reflect(hidden)]
|
||||
#[visit(skip)]
|
||||
pub user_data: Option<Arc<Mutex<dyn Any + Send>>>,
|
||||
pub user_data: Option<UserData>,
|
||||
/// A flag, that defines whether the widget should be drawn in a separate drawing pass after any other widget that draws
|
||||
/// normally.
|
||||
pub draw_on_top: InheritableVariable<bool>,
|
||||
@@ -675,7 +695,7 @@ pub struct Widget {
|
||||
/// Internal sender for layout events.
|
||||
#[reflect(hidden)]
|
||||
#[visit(skip)]
|
||||
pub layout_events_sender: Option<Sender<LayoutEvent>>,
|
||||
pub layout_events_sender: Option<LayoutEventsSender>,
|
||||
/// Unique identifier of the widget.
|
||||
pub id: Uuid,
|
||||
/// A flag, that indicates whether this widget is a root widget of a hierarchy of widgets
|
||||
@@ -1564,11 +1584,10 @@ impl Widget {
|
||||
|
||||
/// Tries to fetch user-defined data of the specified type `T`.
|
||||
#[inline]
|
||||
pub fn user_data_cloned<T: Clone + 'static>(&self) -> Option<T> {
|
||||
self.user_data.as_ref().and_then(|v| {
|
||||
let guard = v.safe_lock();
|
||||
guard.downcast_ref::<T>().cloned()
|
||||
})
|
||||
pub fn user_data_cloned<T: Any + Send + Clone + 'static>(&self) -> Option<T> {
|
||||
self.user_data
|
||||
.as_ref()
|
||||
.and_then(|v| Some(T::clone(&*v.downcast::<T>()?)))
|
||||
}
|
||||
|
||||
/// Returns current clipping bounds of the widget. It is valid only after at least one layout pass.
|
||||
@@ -1701,7 +1720,7 @@ pub struct WidgetBuilder {
|
||||
/// Whether the drop of the widget is allowed or not.
|
||||
pub allow_drop: bool,
|
||||
/// User-defined data.
|
||||
pub user_data: Option<Arc<Mutex<dyn Any + Send>>>,
|
||||
pub user_data: Option<UserData>,
|
||||
/// Whether to draw the widget on top of any other or not.
|
||||
pub draw_on_top: bool,
|
||||
/// Whether the widget is enabled or not.
|
||||
@@ -1981,7 +2000,7 @@ impl WidgetBuilder {
|
||||
/// Sets the desired widget user data.
|
||||
pub fn with_user_data_value_opt<T: Any + Send>(mut self, user_data: Option<T>) -> Self {
|
||||
if let Some(data) = user_data {
|
||||
self.user_data = Some(Arc::new(Mutex::new(data)));
|
||||
self.user_data = Some(UserData::new(data));
|
||||
}
|
||||
self
|
||||
}
|
||||
@@ -1992,7 +2011,7 @@ impl WidgetBuilder {
|
||||
}
|
||||
|
||||
/// Sets the desired widget user data.
|
||||
pub fn with_user_data(mut self, user_data: Arc<Mutex<dyn Any + Send>>) -> Self {
|
||||
pub fn with_user_data(mut self, user_data: UserData) -> Self {
|
||||
self.user_data = Some(user_data);
|
||||
self
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user