diff --git a/src/graphics/renderers/deferred/mod.rs b/src/graphics/renderers/deferred/mod.rs index cbe7b9a67..dcc46f312 100644 --- a/src/graphics/renderers/deferred/mod.rs +++ b/src/graphics/renderers/deferred/mod.rs @@ -243,7 +243,7 @@ impl DeferredRenderer { } } - #[profile("recreate deferred pipeline")] + #[profile("re-create deferred pipeline")] pub fn recreate_pipeline(&mut self, viewport: Viewport, dimensions: [u32; 2], #[cfg(feature = "debug")] wireframe: bool) { let device = self.memory_allocator.device().clone(); let geometry_subpass = Subpass::from(self.render_pass.clone(), 0).unwrap(); diff --git a/src/graphics/renderers/interface/mod.rs b/src/graphics/renderers/interface/mod.rs index cb1e28d06..b75f0d369 100644 --- a/src/graphics/renderers/interface/mod.rs +++ b/src/graphics/renderers/interface/mod.rs @@ -106,7 +106,7 @@ impl InterfaceRenderer { self.font_loader.borrow().get_text_dimensions(text, font_size, available_width) } - #[profile("recreate interface pipeline")] + #[profile("re-create interface pipeline")] pub fn recreate_pipeline(&mut self, viewport: Viewport, dimensions: [u32; 2]) { let device = self.memory_allocator.device().clone(); let subpass = self.render_pass.clone().first_subpass(); diff --git a/src/graphics/renderers/interface/rectangle/fragment_shader.glsl b/src/graphics/renderers/interface/rectangle/fragment_shader.glsl index 5eba5480c..aca8fdc9d 100644 --- a/src/graphics/renderers/interface/rectangle/fragment_shader.glsl +++ b/src/graphics/renderers/interface/rectangle/fragment_shader.glsl @@ -10,11 +10,16 @@ layout(push_constant) uniform Constants { vec4 clip_size; vec4 corner_radius; vec4 color; + float aspect_ratio; } constants; void main() { vec2 coords = fragment_position * constants.screen_size; + vec2 screen_size = constants.screen_size; + + coords.x /= constants.aspect_ratio; + screen_size.x /= constants.aspect_ratio; // top-left if (length(coords - constants.corner_radius.x) > constants.corner_radius.x && coords.x < constants.corner_radius.x && @@ -23,20 +28,20 @@ void main() { } // top-right - if (length(coords - vec2(constants.screen_size.x - constants.corner_radius.y, constants.corner_radius.y)) > constants.corner_radius.y && - constants.screen_size.x - coords.x < constants.corner_radius.y && coords.y < constants.corner_radius.y) { + if (length(coords - vec2(screen_size.x - constants.corner_radius.y, constants.corner_radius.y)) > constants.corner_radius.y && + screen_size.x - coords.x < constants.corner_radius.y && coords.y < constants.corner_radius.y) { discard; } // bottom-right - if (length(coords - constants.screen_size + constants.corner_radius.z) > constants.corner_radius.z && - constants.screen_size.x - coords.x < constants.corner_radius.z && constants.screen_size.y - coords.y < constants.corner_radius.z) { + if (length(coords - screen_size + constants.corner_radius.z) > constants.corner_radius.z && + screen_size.x - coords.x < constants.corner_radius.z && screen_size.y - coords.y < constants.corner_radius.z) { discard; } // bottom_left - if (length(coords - vec2(constants.corner_radius.w, constants.screen_size.y - constants.corner_radius.w)) > constants.corner_radius.w && - coords.x < constants.corner_radius.w && constants.screen_size.y - coords.y < constants.corner_radius.w) { + if (length(coords - vec2(constants.corner_radius.w, screen_size.y - constants.corner_radius.w)) > constants.corner_radius.w && + coords.x < constants.corner_radius.w && screen_size.y - coords.y < constants.corner_radius.w) { discard; } diff --git a/src/graphics/renderers/interface/rectangle/mod.rs b/src/graphics/renderers/interface/rectangle/mod.rs index 8263ef250..8309e616e 100644 --- a/src/graphics/renderers/interface/rectangle/mod.rs +++ b/src/graphics/renderers/interface/rectangle/mod.rs @@ -100,6 +100,7 @@ impl RectangleRenderer { clip_size: clip_size.into(), corner_radius: corner_radius.into(), color: [color.red_f32(), color.green_f32(), color.blue_f32(), color.alpha_f32()], + aspect_ratio: window_size.y as f32 / window_size.x as f32, }; render_target diff --git a/src/graphics/renderers/interface/rectangle/vertex_shader.glsl b/src/graphics/renderers/interface/rectangle/vertex_shader.glsl index f02249803..3ab6e46c0 100644 --- a/src/graphics/renderers/interface/rectangle/vertex_shader.glsl +++ b/src/graphics/renderers/interface/rectangle/vertex_shader.glsl @@ -8,6 +8,7 @@ layout(push_constant) uniform Constants { vec4 clip_size; vec4 corner_radius; vec4 color; + float aspect_ratio; } constants; const vec2 data[6] = vec2[] diff --git a/src/graphics/renderers/mod.rs b/src/graphics/renderers/mod.rs index 203c669cc..4e79d99da 100644 --- a/src/graphics/renderers/mod.rs +++ b/src/graphics/renderers/mod.rs @@ -70,7 +70,7 @@ use self::picker::PickerSubrenderer; pub use self::picker::{PickerRenderer, PickerTarget}; #[cfg(feature = "debug")] pub use self::settings::RenderSettings; -pub use self::shadow::ShadowRenderer; +pub use self::shadow::{ShadowDetail, ShadowRenderer}; pub use self::swapchain::{PresentModeInfo, SwapchainHolder}; use super::{Color, MemoryAllocator, ModelVertex}; #[cfg(feature = "debug")] diff --git a/src/graphics/renderers/shadow/mod.rs b/src/graphics/renderers/shadow/mod.rs index 62eccdae5..fad2e4613 100644 --- a/src/graphics/renderers/shadow/mod.rs +++ b/src/graphics/renderers/shadow/mod.rs @@ -5,6 +5,7 @@ mod indicator; use std::sync::Arc; use cgmath::{Matrix4, Vector2, Vector3}; +use serde::{Deserialize, Serialize}; use vulkano::device::{DeviceOwned, Queue}; use vulkano::format::{ClearValue, Format}; use vulkano::image::{ImageUsage, SampleCount}; @@ -20,6 +21,25 @@ use crate::graphics::{ use crate::loaders::{GameFileLoader, TextureLoader}; use crate::network::EntityId; +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +pub enum ShadowDetail { + Low, + Medium, + High, + Ultra, +} + +impl ShadowDetail { + pub fn into_resolution(self) -> u32 { + match self { + ShadowDetail::Low => 512, + ShadowDetail::Medium => 1024, + ShadowDetail::High => 2048, + ShadowDetail::Ultra => 8192, + } + } +} + #[derive(PartialEq, Eq)] pub enum ShadowSubrenderer { Geometry, diff --git a/src/graphics/settings.rs b/src/graphics/settings.rs index ce78fa734..ed82d6e34 100644 --- a/src/graphics/settings.rs +++ b/src/graphics/settings.rs @@ -1,12 +1,60 @@ -use derive_new::new; use procedural::toggle; +use ron::ser::PrettyConfig; +use serde::{Deserialize, Serialize}; -#[derive(toggle, new)] +use super::ShadowDetail; +#[cfg(feature = "debug")] +use crate::debug::*; + +#[derive(Serialize, Deserialize, toggle)] pub struct GraphicsSettings { #[toggle] - #[new(value = "true")] pub frame_limit: bool, #[toggle] - #[new(value = "true")] pub show_interface: bool, + pub shadow_detail: ShadowDetail, +} + +impl Default for GraphicsSettings { + fn default() -> Self { + Self { + frame_limit: true, + show_interface: true, + shadow_detail: ShadowDetail::Medium, + } + } +} + +impl GraphicsSettings { + pub fn new() -> Self { + Self::load().unwrap_or_else(|| { + #[cfg(feature = "debug")] + print_debug!("failed to load graphics settings from {}filename{}", MAGENTA, NONE); + + Default::default() + }) + } + + pub fn load() -> Option { + #[cfg(feature = "debug")] + print_debug!("loading graphics settings from {}filename{}", MAGENTA, NONE); + + std::fs::read_to_string("client/graphics_settings.ron") + .ok() + .and_then(|data| ron::from_str(&data).ok()) + } + + pub fn save(&self) { + #[cfg(feature = "debug")] + print_debug!("saving graphics settings to {}filename{}", MAGENTA, NONE); + + let data = ron::ser::to_string_pretty(self, PrettyConfig::new()).unwrap(); + std::fs::write("client/graphics_settings.ron", data).expect("unable to write file"); + } +} + +impl Drop for GraphicsSettings { + fn drop(&mut self) { + self.save(); + } } diff --git a/src/input/event.rs b/src/input/event.rs index e6799b6d9..7bedf2056 100644 --- a/src/input/event.rs +++ b/src/input/event.rs @@ -1,21 +1,23 @@ use cgmath::Vector2; use super::HotbarSlot; -use crate::interface::{ItemMove, SkillMove}; -use crate::loaders::Service; +use crate::interface::{ItemMove, SkillMove, ThemeKind}; +use crate::loaders::ServiceId; use crate::network::{AccountId, CharacterId, CharacterServerInformation, EntityId}; #[cfg(feature = "debug")] use crate::world::MarkerIdentifier; #[derive(Clone, Debug)] +// TODO: A lot of these are not user events, just a element events pub enum UserEvent { - SelectService(Service), - LogIn(Service, String, String), + LogIn { + service_id: ServiceId, + username: String, + password: String, + }, SelectServer(CharacterServerInformation), LogOut, Exit, - ToggleRemeberUsername, - ToggleRemeberPassword, CameraZoom(f32), CameraRotate(f32), ToggleFrameLimit, @@ -27,9 +29,16 @@ pub enum UserEvent { OpenGraphicsSettingsWindow, OpenAudioSettingsWindow, OpenFriendsWindow, - SetThemeFile(String), - SaveTheme, - ReloadTheme, + SetThemeFile { + theme_file: String, + theme_kind: ThemeKind, + }, + SaveTheme { + theme_kind: ThemeKind, + }, + ReloadTheme { + theme_kind: ThemeKind, + }, SelectCharacter(usize), OpenCharacterCreationWindow(usize), CreateCharacter(usize, String), diff --git a/src/input/mod.rs b/src/input/mod.rs index 397ff9316..cf0e9699c 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -256,12 +256,12 @@ impl InputSystem { self.mouse_input_mode = MouseInputMode::ClickInterface; if let Some(hovered_element) = &hovered_element { - let action = match self.left_mouse_button.pressed() { + let actions = match self.left_mouse_button.pressed() { true => interface.left_click_element(hovered_element, *window_index), false => interface.right_click_element(hovered_element, *window_index), }; - if let Some(action) = action { + for action in actions { match action { ClickAction::ChangeEvent(..) => {} @@ -302,6 +302,14 @@ impl InputSystem { ClickAction::OpenWindow(prototype_window) => interface.open_window(focus_state, prototype_window.as_ref()), ClickAction::CloseWindow => interface.close_window(focus_state, *window_index), + + ClickAction::OpenPopup { + element, + position_tracker, + size_tracker, + } => interface.open_popup(element, position_tracker, size_tracker, *window_index), + + ClickAction::ClosePopup => interface.close_popup(*window_index), } } } @@ -414,9 +422,9 @@ impl InputSystem { } if self.get_key(VirtualKeyCode::Return).pressed() { - let action = interface.left_click_element(focused_element, *focused_window); + let actions = interface.left_click_element(focused_element, *focused_window); - if let Some(action) = action { + for action in actions { // TODO: remove and replace with proper event match action { ClickAction::Event(event) => events.push(event), @@ -442,7 +450,9 @@ impl InputSystem { '\t' => {} '\x1b' => {} valid => { - if let Some(action) = interface.input_character_element(focused_element, *focused_window, valid) { + let actions = interface.input_character_element(focused_element, *focused_window, valid); + + for action in actions { match action { // is handled in the interface ClickAction::ChangeEvent(..) => {} @@ -469,6 +479,12 @@ impl InputSystem { ClickAction::MoveSkill(..) => {} ClickAction::OpenWindow(prototype_window) => interface.open_window(focus_state, prototype_window.as_ref()), ClickAction::CloseWindow => interface.close_window(focus_state, *focused_window), + ClickAction::OpenPopup { + element, + position_tracker, + size_tracker, + } => interface.open_popup(element, position_tracker, size_tracker, *focused_window), + ClickAction::ClosePopup => interface.close_popup(*focused_window), } } } diff --git a/src/interface/elements/base.rs b/src/interface/elements/base.rs index edb5a1fd3..6a1610c89 100644 --- a/src/interface/elements/base.rs +++ b/src/interface/elements/base.rs @@ -36,6 +36,10 @@ pub struct ElementRenderer<'a> { } impl<'a> ElementRenderer<'a> { + pub fn get_position(&self) -> Position { + self.position + } + pub fn get_text_dimensions(&self, text: &str, font_size: f32, available_width: f32) -> Vector2 { self.renderer .get_text_dimensions(text, font_size * *self.interface_settings.scaling, available_width) @@ -117,7 +121,7 @@ impl<'a> ElementRenderer<'a> { element: &dyn Element, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, hovered_element: Option<&dyn Element>, focused_element: Option<&dyn Element>, mouse_mode: &MouseInputMode, @@ -142,7 +146,8 @@ impl<'a> ElementRenderer<'a> { pub struct ElementState { pub cached_size: Size, pub cached_position: Position, - pub parent_element: Option>>, + pub self_element: Option, + pub parent_element: Option, pub mouse_position: Cell, } @@ -151,6 +156,7 @@ impl Default for ElementState { Self { cached_size: Size::zero(), cached_position: Position::zero(), + self_element: None, parent_element: None, mouse_position: Cell::new(Position::zero()), } @@ -158,7 +164,8 @@ impl Default for ElementState { } impl ElementState { - pub fn link_back(&mut self, weak_parent: Option>>) { + pub fn link_back(&mut self, weak_self: WeakElementCell, weak_parent: Option) { + self.self_element = Some(weak_self); self.parent_element = weak_parent; } @@ -255,8 +262,8 @@ pub trait Element { fn get_state_mut(&mut self) -> &mut ElementState; - fn link_back(&mut self, _weak_self: Weak>, weak_parent: Option>>) { - self.get_state_mut().link_back(weak_parent); + fn link_back(&mut self, weak_self: WeakElementCell, weak_parent: Option) { + self.get_state_mut().link_back(weak_self, weak_parent); } fn is_focusable(&self) -> bool { @@ -284,7 +291,7 @@ pub trait Element { self.is_focusable().then_some(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme); + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme); fn update(&mut self) -> Option { None @@ -298,20 +305,20 @@ pub trait Element { HoverInformation::Missed } - fn left_click(&mut self, _update: &mut bool) -> Option { - None + fn left_click(&mut self, _update: &mut bool) -> Vec { + Vec::new() } - fn right_click(&mut self, _update: &mut bool) -> Option { - None + fn right_click(&mut self, _update: &mut bool) -> Vec { + Vec::new() } fn drag(&mut self, _mouse_delta: Position) -> Option { None } - fn input_character(&mut self, _character: char) -> Option { - None + fn input_character(&mut self, _character: char) -> Vec { + Vec::new() } fn drop_item(&mut self, _item_source: ItemSource, _item: Item) -> Option { @@ -338,7 +345,7 @@ pub trait Element { render: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/buttons/close.rs b/src/interface/elements/buttons/close.rs index b73425fa9..7f2180e76 100644 --- a/src/interface/elements/buttons/close.rs +++ b/src/interface/elements/buttons/close.rs @@ -16,7 +16,7 @@ impl Element for CloseButton { &mut self.state } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let (size, position) = placement_resolver.allocate_right(&theme.close_button.size_constraint); self.state.cached_size = size.finalize(); self.state.cached_position = position; @@ -33,8 +33,8 @@ impl Element for CloseButton { } } - fn left_click(&mut self, _force_update: &mut bool) -> Option { - Some(ClickAction::CloseWindow) + fn left_click(&mut self, _force_update: &mut bool) -> Vec { + vec![ClickAction::CloseWindow] } fn render( @@ -43,7 +43,7 @@ impl Element for CloseButton { renderer: &InterfaceRenderer, _state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/buttons/default.rs b/src/interface/elements/buttons/default.rs index f9741bcb2..3272ed174 100644 --- a/src/interface/elements/buttons/default.rs +++ b/src/interface/elements/buttons/default.rs @@ -58,12 +58,12 @@ where self } - pub fn with_foreground_color(mut self, foreground_color: impl Fn(&Theme) -> Color + 'static) -> Self { + pub fn with_foreground_color(mut self, foreground_color: impl Fn(&InterfaceTheme) -> Color + 'static) -> Self { self.foreground_color = Some(Box::new(foreground_color)); self } - pub fn with_background_color(mut self, background_color: impl Fn(&Theme) -> Color + 'static) -> Self { + pub fn with_background_color(mut self, background_color: impl Fn(&InterfaceTheme) -> Color + 'static) -> Self { self.background_color = Some(Box::new(background_color)); self } @@ -91,7 +91,7 @@ impl + 'static, E: ElementEvent> Element for Button { !self.is_disabled() } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = self .width_constraint .as_ref() @@ -108,12 +108,12 @@ impl + 'static, E: ElementEvent> Element for Button { } } - fn left_click(&mut self, _force_update: &mut bool) -> Option { + fn left_click(&mut self, _force_update: &mut bool) -> Vec { if self.is_disabled() { - return None; + return Vec::new(); } - self.event.as_mut().and_then(ElementEvent::trigger) + self.event.as_mut().map(|event| event.trigger()).unwrap_or_default() } fn render( @@ -122,7 +122,7 @@ impl + 'static, E: ElementEvent> Element for Button { renderer: &InterfaceRenderer, _state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/buttons/drag.rs b/src/interface/elements/buttons/drag.rs index 1d7fbf34f..6ac02aba7 100644 --- a/src/interface/elements/buttons/drag.rs +++ b/src/interface/elements/buttons/drag.rs @@ -21,7 +21,7 @@ impl Element for DragButton { &mut self.state } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = self.width_constraint.add_height(theme.window.title_height); self.state.resolve(placement_resolver, &size_constraint); @@ -39,8 +39,8 @@ impl Element for DragButton { } } - fn left_click(&mut self, _force_update: &mut bool) -> Option { - Some(ClickAction::MoveInterface) + fn left_click(&mut self, _force_update: &mut bool) -> Vec { + vec![ClickAction::MoveInterface] } fn render( @@ -49,7 +49,7 @@ impl Element for DragButton { renderer: &InterfaceRenderer, _state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/buttons/state.rs b/src/interface/elements/buttons/state.rs index e878a68e6..3509f9e73 100644 --- a/src/interface/elements/buttons/state.rs +++ b/src/interface/elements/buttons/state.rs @@ -4,6 +4,7 @@ use crate::graphics::{InterfaceRenderer, Renderer}; use crate::input::MouseInputMode; use crate::interface::{Element, *}; +// FIX: State button won't redraw just because the state changes pub struct StateButton where T: AsRef + 'static, @@ -80,7 +81,7 @@ where &mut self.state } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = self .width_constraint .as_ref() @@ -97,8 +98,8 @@ where } } - fn left_click(&mut self, _force_update: &mut bool) -> Option { - self.event.as_mut().and_then(ElementEvent::trigger) + fn left_click(&mut self, _force_update: &mut bool) -> Vec { + self.event.as_mut().map(|event| event.trigger()).unwrap_or_default() } fn render( @@ -107,7 +108,7 @@ where renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/character.rs b/src/interface/elements/containers/character.rs index 428046716..c181e7397 100644 --- a/src/interface/elements/containers/character.rs +++ b/src/interface/elements/containers/character.rs @@ -105,7 +105,7 @@ impl Element for CharacterPreview { self.state.focus_next::(self_cell, caller_cell, focus) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = &constraint!(20%, 150); self.state.resolve( placement_resolver, @@ -121,11 +121,8 @@ impl Element for CharacterPreview { let move_request_changed = self.move_request.consume_changed(); if characters_changed || move_request_changed { + let weak_self = self.state.state.self_element.take().unwrap(); let weak_parent = self.state.state.parent_element.clone(); - // Since the character container will always have at least one linked child - // element, we can get a reference to self there instead of storing - // it in self. - let weak_self = self.state.elements[0].borrow().get_state().parent_element.clone().unwrap(); *self = Self::new(self.characters.clone(), self.move_request.clone(), self.slot); @@ -139,14 +136,14 @@ impl Element for CharacterPreview { None } - fn left_click(&mut self, _update: &mut bool) -> Option { + fn left_click(&mut self, _update: &mut bool) -> Vec { if let Some(origin_slot) = *self.move_request.borrow() { let event = match origin_slot == self.slot { true => UserEvent::CancelSwitchCharacterSlot, false => UserEvent::SwitchCharacterSlot(self.slot), }; - return Some(ClickAction::Event(event)); + return vec![ClickAction::Event(event)]; } let event = match self.has_character() { @@ -154,7 +151,7 @@ impl Element for CharacterPreview { false => UserEvent::OpenCharacterCreationWindow(self.slot), }; - Some(ClickAction::Event(event)) + vec![ClickAction::Event(event)] } fn hovered_element(&self, mouse_position: Position, mouse_mode: &MouseInputMode) -> HoverInformation { @@ -170,7 +167,7 @@ impl Element for CharacterPreview { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/default.rs b/src/interface/elements/containers/default.rs index 91c8f5c78..9aafe5955 100644 --- a/src/interface/elements/containers/default.rs +++ b/src/interface/elements/containers/default.rs @@ -54,7 +54,7 @@ impl Element for Container { self.state.restore_focus(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = self.size_constraint.as_ref().unwrap_or(&constraint!(100%, ?)); let border = self.border_size.unwrap_or_else(Vector2::zero); @@ -76,7 +76,7 @@ impl Element for Container { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/dialog.rs b/src/interface/elements/containers/dialog.rs index 75c4df1e6..19b82ed93 100644 --- a/src/interface/elements/containers/dialog.rs +++ b/src/interface/elements/containers/dialog.rs @@ -70,7 +70,7 @@ impl Element for DialogContainer { // TODO: focus related things - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = &constraint!(100%, ?); self.state.resolve( placement_resolver, @@ -103,7 +103,7 @@ impl Element for DialogContainer { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/equipment.rs b/src/interface/elements/containers/equipment.rs index 4576dbbdd..2be6c88e2 100644 --- a/src/interface/elements/containers/equipment.rs +++ b/src/interface/elements/containers/equipment.rs @@ -86,7 +86,7 @@ impl Element for EquipmentContainer { self.state.restore_focus(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = &constraint!(100%, ?); self.state.resolve( placement_resolver, @@ -126,7 +126,7 @@ impl Element for EquipmentContainer { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/expandable.rs b/src/interface/elements/containers/expandable.rs index 712690516..804dbd6da 100644 --- a/src/interface/elements/containers/expandable.rs +++ b/src/interface/elements/containers/expandable.rs @@ -57,7 +57,7 @@ impl Element for Expandable { self.state.restore_focus(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let closed_size = self .closed_size_constraint .resolve_partial( @@ -141,10 +141,10 @@ impl Element for Expandable { HoverInformation::Missed } - fn left_click(&mut self, force_update: &mut bool) -> Option { + fn left_click(&mut self, force_update: &mut bool) -> Vec { self.expanded = !self.expanded; *force_update = true; - None + Vec::new() } fn render( @@ -153,7 +153,7 @@ impl Element for Expandable { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/friends.rs b/src/interface/elements/containers/friends.rs index b4010ddd8..377068536 100644 --- a/src/interface/elements/containers/friends.rs +++ b/src/interface/elements/containers/friends.rs @@ -11,13 +11,11 @@ use crate::network::Friend; pub struct FriendView { friends: Remote>)>>, - weak_self: Option, state: ContainerState, } impl FriendView { pub fn new(friends: Remote>)>>) -> Self { - let weak_self = None; let elements = { let friends = friends.borrow(); @@ -33,7 +31,6 @@ impl FriendView { Self { friends, - weak_self, state: ContainerState::new(elements), } } @@ -63,7 +60,6 @@ impl Element for FriendView { } fn link_back(&mut self, weak_self: Weak>, weak_parent: Option>>) { - self.weak_self = Some(weak_self.clone()); self.state.link_back(weak_self, weak_parent); } @@ -79,7 +75,7 @@ impl Element for FriendView { self.state.restore_focus(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { self.state.resolve( placement_resolver, interface_settings, @@ -107,7 +103,9 @@ impl Element for FriendView { } else { let element = Self::friend_to_element(friend); unsafe { *linked_element.get() = Some(Rc::downgrade(&element)) }; - element.borrow_mut().link_back(Rc::downgrade(&element), self.weak_self.clone()); + let weak_self = self.state.state.self_element.clone(); + + element.borrow_mut().link_back(Rc::downgrade(&element), weak_self); self.state.elements.insert(index, element); resolve = true; @@ -141,7 +139,7 @@ impl Element for FriendView { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/hotbar.rs b/src/interface/elements/containers/hotbar.rs index b6d0d99a8..8515e84a7 100644 --- a/src/interface/elements/containers/hotbar.rs +++ b/src/interface/elements/containers/hotbar.rs @@ -8,7 +8,6 @@ use crate::inventory::Skill; pub struct HotbarContainer { skills: Remote<[Option; 10]>, - weak_self: Option, state: ContainerState, } @@ -34,10 +33,9 @@ impl HotbarContainer { .collect() }; - let weak_self = None; let state = ContainerState::new(elements); - Self { skills, weak_self, state } + Self { skills, state } } } @@ -51,7 +49,6 @@ impl Element for HotbarContainer { } fn link_back(&mut self, weak_self: WeakElementCell, weak_parent: Option) { - self.weak_self = Some(weak_self.clone()); self.state.link_back(weak_self, weak_parent); } @@ -67,7 +64,7 @@ impl Element for HotbarContainer { self.state.restore_focus(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = &constraint!(100%, ?); self.state.resolve( placement_resolver, @@ -80,8 +77,8 @@ impl Element for HotbarContainer { fn update(&mut self) -> Option { if self.skills.consume_changed() { + let weak_self = self.state.state.self_element.take().unwrap(); let weak_parent = self.state.state.parent_element.take(); - let weak_self = self.weak_self.take().unwrap(); *self = Self::new(self.skills.clone()); // important: link back after creating elements, otherwise focus navigation and @@ -107,7 +104,7 @@ impl Element for HotbarContainer { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/inventory.rs b/src/interface/elements/containers/inventory.rs index 613103127..4f4670eb5 100644 --- a/src/interface/elements/containers/inventory.rs +++ b/src/interface/elements/containers/inventory.rs @@ -57,7 +57,7 @@ impl Element for InventoryContainer { self.state.restore_focus(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = &constraint!(100%, ?); self.state.resolve( placement_resolver, @@ -106,7 +106,7 @@ impl Element for InventoryContainer { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/mod.rs b/src/interface/elements/containers/mod.rs index 40b25ce29..1de3035b9 100644 --- a/src/interface/elements/containers/mod.rs +++ b/src/interface/elements/containers/mod.rs @@ -44,18 +44,18 @@ pub struct ContainerState { impl ContainerState { pub fn link_back(&mut self, weak_self: Weak>, weak_parent: Option>>) { - self.state.link_back(weak_parent); self.elements.iter().for_each(|element| { let weak_element = Rc::downgrade(element); element.borrow_mut().link_back(weak_element, Some(weak_self.clone())); }); + self.state.link_back(weak_self, weak_parent); } pub fn resolve( &mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, size_constraint: &SizeConstraint, border: Vector2, ) { @@ -299,7 +299,7 @@ impl ContainerState { renderer: &mut ElementRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, hovered_element: Option<&dyn Element>, focused_element: Option<&dyn Element>, mouse_mode: &MouseInputMode, diff --git a/src/interface/elements/containers/packet.rs b/src/interface/elements/containers/packet.rs index eeceebf71..728046ad9 100644 --- a/src/interface/elements/containers/packet.rs +++ b/src/interface/elements/containers/packet.rs @@ -20,7 +20,7 @@ impl Element for HiddenElement { unimplemented!() } - fn resolve(&mut self, _placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, _theme: &Theme) { + fn resolve(&mut self, _placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, _theme: &InterfaceTheme) { unimplemented!() } @@ -30,7 +30,7 @@ impl Element for HiddenElement { _render: &InterfaceRenderer, _state_provider: &StateProvider, _interface_settings: &InterfaceSettings, - _theme: &Theme, + _theme: &InterfaceTheme, _parent_position: Position, _clip_size: ClipSize, _hovered_element: Option<&dyn Element>, @@ -94,14 +94,12 @@ impl PacketEntry { pub struct PacketView { packets: Remote>), N>>, show_pings: Remote, - weak_self: Option, hidden_element: ElementCell, state: ContainerState, } impl PacketView { pub fn new(packets: Remote>), N>>, show_pings: Remote) -> Self { - let weak_self = None; let hidden_element = HiddenElement.wrap(); let elements = { let packets = packets.borrow(); @@ -130,7 +128,6 @@ impl PacketView { Self { packets, show_pings, - weak_self, hidden_element, state: ContainerState::new(elements), } @@ -147,7 +144,6 @@ impl Element for PacketView { } fn link_back(&mut self, weak_self: Weak>, weak_parent: Option>>) { - self.weak_self = Some(weak_self.clone()); self.state.link_back(weak_self, weak_parent); } @@ -163,7 +159,7 @@ impl Element for PacketView { self.state.restore_focus(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { self.state.resolve( placement_resolver, interface_settings, @@ -223,7 +219,9 @@ impl Element for PacketView { if show_packet && was_hidden { let element = PacketEntry::to_element(packet); *linked_element = Rc::downgrade(&element); - element.borrow_mut().link_back(Rc::downgrade(&element), self.weak_self.clone()); + element + .borrow_mut() + .link_back(Rc::downgrade(&element), self.state.state.self_element.clone()); self.state.elements.insert(index, element); resolve = true; @@ -242,7 +240,9 @@ impl Element for PacketView { true => { let element = PacketEntry::to_element(packet); unsafe { *linked_element.get() = Some(Rc::downgrade(&element)) }; - element.borrow_mut().link_back(Rc::downgrade(&element), self.weak_self.clone()); + element + .borrow_mut() + .link_back(Rc::downgrade(&element), self.state.state.self_element.clone()); self.state.elements.push(element); resolve = true; @@ -278,7 +278,7 @@ impl Element for PacketView { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/containers/scroll.rs b/src/interface/elements/containers/scroll.rs index 354ee46cc..e894c3cec 100644 --- a/src/interface/elements/containers/scroll.rs +++ b/src/interface/elements/containers/scroll.rs @@ -12,19 +12,27 @@ pub struct ScrollView { scroll: f32, state: ContainerState, size_constraint: SizeConstraint, + background_color: Option, } impl ScrollView { pub fn new(elements: Vec, size_constraint: SizeConstraint) -> Self { let scroll = 0.0; let state = ContainerState::new(elements); + let background_color = None; Self { scroll, state, size_constraint, + background_color, } } + + pub fn with_background_color(mut self, background_color: impl Fn(&InterfaceTheme) -> Color + 'static) -> Self { + self.background_color = Some(Box::new(background_color)); + self + } } impl Element for ScrollView { @@ -52,7 +60,7 @@ impl Element for ScrollView { self.state.restore_focus(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { self.state.resolve( placement_resolver, interface_settings, @@ -86,7 +94,7 @@ impl Element for ScrollView { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, @@ -99,6 +107,10 @@ impl Element for ScrollView { .state .element_renderer(render_target, renderer, interface_settings, parent_position, clip_size); + if let Some(color_selector) = &self.background_color { + renderer.render_background((*theme.button.corner_radius).into(), color_selector(theme)); + } + renderer.set_scroll(self.scroll); self.state.render( diff --git a/src/interface/elements/containers/skill_tree.rs b/src/interface/elements/containers/skill_tree.rs index 4a670d8ca..d0f451b2a 100644 --- a/src/interface/elements/containers/skill_tree.rs +++ b/src/interface/elements/containers/skill_tree.rs @@ -57,7 +57,7 @@ impl Element for SkillTreeContainer { self.state.restore_focus(self_cell) } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let size_constraint = &constraint!(100%, ?); self.state.resolve( placement_resolver, @@ -106,7 +106,7 @@ impl Element for SkillTreeContainer { renderer: &InterfaceRenderer, state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/miscellanious/chat.rs b/src/interface/elements/miscellanious/chat.rs index 2fae6e2ce..7cec8850c 100644 --- a/src/interface/elements/miscellanious/chat.rs +++ b/src/interface/elements/miscellanious/chat.rs @@ -44,7 +44,7 @@ impl Element for Chat { false } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, interface_settings: &InterfaceSettings, theme: &InterfaceTheme) { let mut size_constraint = constraint!(100%, 0); // Not sure why but 0.0 cuts off the lower part of the text, so add some // padding. @@ -83,7 +83,7 @@ impl Element for Chat { renderer: &InterfaceRenderer, _state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, _hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/miscellanious/headline.rs b/src/interface/elements/miscellanious/headline.rs index bd93cec24..617235750 100644 --- a/src/interface/elements/miscellanious/headline.rs +++ b/src/interface/elements/miscellanious/headline.rs @@ -29,7 +29,7 @@ impl Element for Headline { false } - fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, _theme: &Theme) { + fn resolve(&mut self, placement_resolver: &mut PlacementResolver, _interface_settings: &InterfaceSettings, _theme: &InterfaceTheme) { self.state.resolve(placement_resolver, &self.size_constraint); } @@ -39,7 +39,7 @@ impl Element for Headline { renderer: &InterfaceRenderer, _state_provider: &StateProvider, interface_settings: &InterfaceSettings, - theme: &Theme, + theme: &InterfaceTheme, parent_position: Position, clip_size: ClipSize, _hovered_element: Option<&dyn Element>, diff --git a/src/interface/elements/miscellanious/input.rs b/src/interface/elements/miscellanious/input.rs index 97739d56c..2599217c8 100644 --- a/src/interface/elements/miscellanious/input.rs +++ b/src/interface/elements/miscellanious/input.rs @@ -12,33 +12,33 @@ use crate::interface::{Element, *}; pub struct InputField { display: Rc>, ghost_text: &'static str, - action: Box Option>, + action: Box Vec>, width_constraint: DimensionConstraint, #[new(default)] state: ElementState, } impl InputField