use crate::{
asset::item::AssetItem,
fyrox::{
core::{
algebra::Vector2, color::Color, pool::Handle, reflect::prelude::*,
type_traits::prelude::*, uuid_provider, visitor::prelude::*,
},
graph::SceneGraph,
gui::{
brush::Brush,
draw::{CommandTexture, Draw, DrawingContext},
font::{Font, FontResource, BUILT_IN_FONT},
formatted_text::WrapMode,
inspector::{
editors::{
PropertyEditorBuildContext, PropertyEditorDefinition, PropertyEditorInstance,
PropertyEditorMessageContext, PropertyEditorTranslationContext,
},
FieldKind, InspectorError, PropertyChanged,
},
message::{MessageDirection, UiMessage},
text::{TextBuilder, TextMessage},
widget::{Widget, WidgetBuilder, WidgetMessage},
BuildContext, Control, UiNode, UserInterface,
},
},
};
use fyrox::asset::manager::ResourceManager;
use fyrox::gui::message::MessageData;
use fyrox::gui::text::Text;
use std::{
any::TypeId,
fmt::{Debug, Formatter},
ops::{Deref, DerefMut},
};
#[derive(Clone, Visit, Reflect, ComponentProvider)]
#[reflect(derived_type = "UiNode")]
pub struct FontField {
widget: Widget,
text_preview: Handle<Text>,
font: FontResource,
#[reflect(hidden)]
#[visit(skip)]
resource_manager: ResourceManager,
}
impl Debug for FontField {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "TextureEditor")
}
}
impl Deref for FontField {
type Target = Widget;
fn deref(&self) -> &Self::Target {
&self.widget
}
}
impl DerefMut for FontField {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.widget
}
}
#[derive(Debug, PartialEq, Clone, Eq)]
pub enum FontFieldMessage {
Font(FontResource),
}
impl MessageData for FontFieldMessage {}
uuid_provider!(FontField = "5db49479-ff89-49b8-a038-0766253d6493");
impl Control for FontField {
fn draw(&self, drawing_context: &mut DrawingContext) {
drawing_context.push_rect_filled(&self.bounding_rect(), None);
drawing_context.commit(
self.clip_bounds(),
Brush::Solid(Color::TRANSPARENT),
CommandTexture::None,
&self.material,
None,
);
}
fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
self.widget.handle_routed_message(ui, message);
if let Some(WidgetMessage::Drop(dropped)) = message.data::<WidgetMessage>() {
if message.destination() == self.handle {
if let Some(item) = ui.node(*dropped).cast::<AssetItem>() {
if let Some(font) = item.resource::<Font>() {
ui.send(self.handle(), FontFieldMessage::Font(font));
}
}
}
} else if let Some(FontFieldMessage::Font(font)) = message.data_for(self.handle) {
if &self.font != font {
self.font = font.clone();
ui.send(self.text_preview, TextMessage::Font(font.clone()));
ui.send(
self.text_preview,
TextMessage::Text(make_name(&self.resource_manager, &self.font)),
);
ui.send_message(message.reverse());
}
}
}
}
pub struct FontFieldBuilder {
widget_builder: WidgetBuilder,
font: FontResource,
}
fn make_name(resource_manager: &ResourceManager, font: &FontResource) -> String {
match resource_manager.resource_path(font.as_ref()) {
Some(path) => {
if font == &BUILT_IN_FONT.resource.clone() {
"BuiltIn - AaBbCcDd1234567890".to_string()
} else {
format!("{} - AaBbCcDd1234567890", path.display())
}
}
None => "Embedded - AaBbCcDd1234567890".to_string(),
}
}
impl FontFieldBuilder {
pub fn new(widget_builder: WidgetBuilder) -> Self {
Self {
widget_builder,
font: BUILT_IN_FONT.resource(),
}
}
pub fn with_font(mut self, font: FontResource) -> Self {
self.font = font;
self
}
pub fn build(
self,
resource_manager: ResourceManager,
ctx: &mut BuildContext,
) -> Handle<FontField> {
let text_preview;
let widget = self
.widget_builder
.with_allow_drop(true)
.with_child({
text_preview = TextBuilder::new(WidgetBuilder::new())
.with_wrap(WrapMode::Word)
.with_text(make_name(&resource_manager, &self.font))
.with_font(self.font.clone())
.build(ctx);
text_preview
})
.build(ctx);
let editor = FontField {
widget,
text_preview,
font: self.font,
resource_manager,
};
ctx.add(editor)
}
}
#[derive(Debug)]
pub struct FontPropertyEditorDefinition {
pub resource_manager: ResourceManager,
}
impl PropertyEditorDefinition for FontPropertyEditorDefinition {
fn value_type_id(&self) -> TypeId {
TypeId::of::<FontResource>()
}
fn create_instance(
&self,
ctx: PropertyEditorBuildContext,
) -> Result<PropertyEditorInstance, InspectorError> {
let value = ctx.property_info.cast_value::<FontResource>()?;
Ok(PropertyEditorInstance::simple(
FontFieldBuilder::new(WidgetBuilder::new().with_min_size(Vector2::new(0.0, 17.0)))
.with_font(value.clone())
.build(self.resource_manager.clone(), ctx.build_context),
))
}
fn create_message(
&self,
ctx: PropertyEditorMessageContext,
) -> Result<Option<UiMessage>, InspectorError> {
let value = ctx.property_info.cast_value::<FontResource>()?;
Ok(Some(UiMessage::for_widget(
ctx.instance,
FontFieldMessage::Font(value.clone()),
)))
}
fn translate_message(&self, ctx: PropertyEditorTranslationContext) -> Option<PropertyChanged> {
if ctx.message.direction() == MessageDirection::FromWidget {
if let Some(FontFieldMessage::Font(value)) = ctx.message.data() {
return Some(PropertyChanged {
name: ctx.name.to_string(),
value: FieldKind::object(value.clone()),
});
}
}
None
}
}
#[cfg(test)]
mod test {
use crate::plugins::inspector::editors::font::FontFieldBuilder;
use fyrox::asset::io::FsResourceIo;
use fyrox::asset::manager::ResourceManager;
use fyrox::core::task::TaskPool;
use fyrox::{gui::test::test_widget_deletion, gui::widget::WidgetBuilder};
use std::sync::Arc;
#[test]
fn test_deletion() {
let resource_manager =
ResourceManager::new(Arc::new(FsResourceIo), Arc::new(TaskPool::new()));
test_widget_deletion(|ctx| {
FontFieldBuilder::new(WidgetBuilder::new()).build(resource_manager, ctx)
});
}
}