2023-01-16 09:53:52 +00:00
|
|
|
use crate::prelude::*;
|
2025-02-28 05:48:19 +00:00
|
|
|
use anyhow::{Result, anyhow};
|
2023-01-16 09:53:52 +00:00
|
|
|
use assetpath::AssetPath;
|
2025-03-04 08:11:05 +00:00
|
|
|
|
2023-01-17 06:08:29 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2023-02-01 13:42:25 +00:00
|
|
|
use utilities::{impl_reprc, prelude::*};
|
2023-01-22 15:02:46 +00:00
|
|
|
use vulkan_rs::{prelude::*, render_target::sub_pass::InputAttachmentInfo};
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
use super::{
|
|
|
|
elements::Elements,
|
2023-01-27 12:46:54 +00:00
|
|
|
gui::{
|
|
|
|
colorable::ColorableVertex, iconizable::IconBuilderType, texturedvertex::TexturedVertex,
|
|
|
|
},
|
2023-01-16 09:53:52 +00:00
|
|
|
};
|
|
|
|
|
2024-05-13 13:03:54 +00:00
|
|
|
use cgmath::{ortho, vec2};
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
use std::sync::{Arc, Mutex};
|
2023-01-16 09:53:52 +00:00
|
|
|
use std::{collections::HashMap, ptr};
|
2024-08-29 09:09:17 +00:00
|
|
|
use std::{mem, sync::Weak};
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
use paste::paste;
|
|
|
|
|
2023-01-17 06:24:20 +00:00
|
|
|
#[derive(Deserialize, Serialize, Clone, Debug)]
|
2023-01-18 11:24:56 +00:00
|
|
|
pub enum Font<'a> {
|
|
|
|
Path(AssetPath),
|
|
|
|
Bytes(&'a [u8]),
|
|
|
|
}
|
|
|
|
|
2023-01-21 13:40:58 +00:00
|
|
|
impl Default for Font<'_> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::Path(AssetPath::default())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-28 05:42:24 +00:00
|
|
|
#[derive(Deserialize, Serialize, Clone, Debug)]
|
2023-01-18 11:24:56 +00:00
|
|
|
pub struct GuiHandlerCreateInfo<'a> {
|
2023-01-16 09:53:52 +00:00
|
|
|
// path to the alphabet image
|
2023-01-18 11:24:56 +00:00
|
|
|
#[serde(borrow)]
|
2023-01-18 11:27:08 +00:00
|
|
|
pub font: Font<'a>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
// sound info
|
2023-01-17 06:07:19 +00:00
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
pub click_sound: Option<AssetPath>,
|
2023-01-17 06:07:19 +00:00
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
pub hover_sound: Option<AssetPath>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
// resource base directory
|
2025-02-28 05:26:57 +00:00
|
|
|
pub resource_directory: Option<AssetPath>,
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-18 11:24:56 +00:00
|
|
|
impl<'a> GuiHandlerCreateInfo<'a> {
|
2023-01-21 13:40:58 +00:00
|
|
|
pub const fn new() -> Self {
|
2023-01-17 06:24:20 +00:00
|
|
|
GuiHandlerCreateInfo {
|
|
|
|
// path to the alphabet image
|
2025-02-28 05:26:57 +00:00
|
|
|
font: Font::Bytes(include_bytes!("default_font.png")),
|
2023-01-17 06:24:20 +00:00
|
|
|
|
|
|
|
// sound info
|
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
click_sound: None,
|
2023-01-17 06:24:20 +00:00
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
hover_sound: None,
|
2023-01-17 06:24:20 +00:00
|
|
|
|
|
|
|
// resource base directory
|
2025-02-28 05:26:57 +00:00
|
|
|
resource_directory: None,
|
2023-01-17 06:24:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 09:53:52 +00:00
|
|
|
struct GuiSeparator {
|
|
|
|
_descriptor_layout: Arc<DescriptorSetLayout>,
|
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
pipeline: Arc<Pipeline>,
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2023-02-01 13:42:25 +00:00
|
|
|
impl_reprc!(
|
|
|
|
struct ColorBuffer {
|
|
|
|
#[assume_reprc]
|
|
|
|
color: f32,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2023-01-16 09:53:52 +00:00
|
|
|
struct TextableColor {
|
|
|
|
_descriptor_pool: Arc<DescriptorPool>,
|
|
|
|
_descriptor_set: Arc<DescriptorSet>,
|
|
|
|
|
2023-02-01 13:42:25 +00:00
|
|
|
_buffer: Arc<Buffer<ColorBuffer>>,
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct CommandBufferState {
|
2025-03-04 08:11:05 +00:00
|
|
|
text_buffers: Vec<Arc<Buffer<TexturedVertex>>>,
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
struct TextToScreen {
|
|
|
|
pipeline: TargetMode<GuiSeparator>,
|
|
|
|
descriptor: TargetMode<Arc<DescriptorSet>>,
|
|
|
|
buffer: Arc<Buffer<TexturedVertex>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TextToScreen {
|
|
|
|
fn new(
|
|
|
|
device: &Arc<Device>,
|
|
|
|
pipeline: TargetMode<GuiSeparator>,
|
2025-03-04 08:11:05 +00:00
|
|
|
render_target: &TargetMode<RenderTarget>,
|
2023-01-22 15:02:46 +00:00
|
|
|
) -> Result<Self> {
|
|
|
|
let descriptor = pipeline
|
|
|
|
.chain(render_target)
|
|
|
|
.execute(|(separator, render_target)| {
|
|
|
|
let descriptor = DescriptorPool::builder()
|
|
|
|
.set_layout(separator._descriptor_layout.clone())
|
|
|
|
.build(device.clone())?
|
|
|
|
.prepare_set()
|
|
|
|
.allocate()?;
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
Self::update_descriptor(&descriptor, render_target)?;
|
2023-01-22 15:02:46 +00:00
|
|
|
|
|
|
|
Ok(descriptor)
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let edges = [
|
|
|
|
TexturedVertex {
|
2024-05-13 13:03:54 +00:00
|
|
|
position: vec2(-1.0, -1.0),
|
2023-01-22 15:02:46 +00:00
|
|
|
texture_coordinates: vec2(0.0, 0.0),
|
|
|
|
},
|
|
|
|
TexturedVertex {
|
2024-05-13 13:03:54 +00:00
|
|
|
position: vec2(-1.0, 1.0),
|
2023-01-22 15:02:46 +00:00
|
|
|
texture_coordinates: vec2(0.0, 1.0),
|
|
|
|
},
|
|
|
|
TexturedVertex {
|
2024-05-13 13:03:54 +00:00
|
|
|
position: vec2(1.0, 1.0),
|
2023-01-22 15:02:46 +00:00
|
|
|
texture_coordinates: vec2(1.0, 1.0),
|
|
|
|
},
|
|
|
|
TexturedVertex {
|
2024-05-13 13:03:54 +00:00
|
|
|
position: vec2(1.0, 1.0),
|
2023-01-22 15:02:46 +00:00
|
|
|
texture_coordinates: vec2(1.0, 1.0),
|
|
|
|
},
|
|
|
|
TexturedVertex {
|
2024-05-13 13:03:54 +00:00
|
|
|
position: vec2(1.0, -1.0),
|
2023-01-22 15:02:46 +00:00
|
|
|
texture_coordinates: vec2(1.0, 0.0),
|
|
|
|
},
|
|
|
|
TexturedVertex {
|
2024-05-13 13:03:54 +00:00
|
|
|
position: vec2(-1.0, -1.0),
|
2023-01-22 15:02:46 +00:00
|
|
|
texture_coordinates: vec2(0.0, 0.0),
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
let buffer = Buffer::builder()
|
|
|
|
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
|
|
|
|
.set_memory_usage(MemoryUsage::CpuOnly)
|
|
|
|
.set_data(&edges)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
pipeline,
|
|
|
|
descriptor,
|
|
|
|
buffer,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update_descriptor(
|
|
|
|
descriptor: &Arc<DescriptorSet>,
|
|
|
|
render_target: &RenderTarget,
|
|
|
|
) -> Result<()> {
|
|
|
|
// take resolve target of second sub pass as image sampler
|
|
|
|
descriptor.update(&[DescriptorWrite::input_attachments(
|
|
|
|
0,
|
|
|
|
&[&render_target.sub_pass(1).attachments()[1].image(0)],
|
|
|
|
)
|
|
|
|
.change_image_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)])
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
fn update_on_resize(&self, render_target: &TargetMode<RenderTarget>) -> Result<()> {
|
2023-01-22 15:02:46 +00:00
|
|
|
self.descriptor
|
|
|
|
.chain(render_target)
|
|
|
|
.execute(|(descriptor, render_target)| {
|
2025-03-04 08:11:05 +00:00
|
|
|
Self::update_descriptor(descriptor, render_target)
|
2023-01-22 15:02:46 +00:00
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-03 19:01:17 +00:00
|
|
|
pub struct GuiHandler<'a> {
|
2023-01-16 09:53:52 +00:00
|
|
|
device: Arc<Device>,
|
|
|
|
queue: Arc<Mutex<Queue>>,
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
width: u32,
|
|
|
|
height: u32,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-02-28 05:48:19 +00:00
|
|
|
resource_base_path: Option<AssetPath>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
top_ui: Option<Arc<dyn TopGui>>,
|
|
|
|
tooltip_ui: Option<Arc<dyn TopGui>>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
render_targets: TargetMode<RenderTarget>,
|
2023-01-16 09:53:52 +00:00
|
|
|
command_buffers: TargetMode<Vec<CommandBufferState>>,
|
|
|
|
|
2023-01-21 13:14:43 +00:00
|
|
|
text_objects: TargetMode<GuiSeparator>,
|
|
|
|
rectangle_objects: TargetMode<GuiSeparator>,
|
|
|
|
single_color_objects: TargetMode<GuiSeparator>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
text_to_screen: TextToScreen,
|
|
|
|
|
2023-01-16 09:53:52 +00:00
|
|
|
_bitmap_font: Arc<Image>,
|
|
|
|
_bitmap_desc_pool: Arc<DescriptorPool>,
|
|
|
|
bitmap_desc_set: Arc<DescriptorSet>,
|
|
|
|
|
|
|
|
text_color_layout: Arc<DescriptorSetLayout>,
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
internal_icons: HashMap<AssetPath, Weak<Image>>,
|
|
|
|
internal_textures: HashMap<AssetPath, Arc<Image>>,
|
|
|
|
internal_colors: HashMap<Color, TextableColor>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2024-03-25 11:33:56 +00:00
|
|
|
element_creator: Mutex<ElementCreator>,
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
ortho: cgmath::Matrix4<f32>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
icon_descriptor_layout: Arc<DescriptorSetLayout>,
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
needs_update: bool,
|
|
|
|
text_change_queue: Vec<Box<dyn Fn() -> Result<()> + Send + Sync>>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
on_selected: Option<Box<dyn Fn() -> Result<()> + Send + Sync>>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-17 06:07:19 +00:00
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
click_sound: Option<AssetPath>,
|
2023-01-17 06:07:19 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
hover_sound: Option<AssetPath>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
// ----- gui handling -----
|
2025-03-04 08:11:05 +00:00
|
|
|
layers: Vec<(i32, Elements)>,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
mouse_x: u32,
|
|
|
|
mouse_y: u32,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
last_direction: GuiDirection,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
current_writeable: Option<Arc<Writeable>>,
|
|
|
|
current_hoverable: Option<Arc<Hoverable>>,
|
|
|
|
current_clickable: Option<Arc<Clickable>>,
|
|
|
|
current_selectable: Option<Arc<Selectable<'a>>>,
|
2023-01-21 21:09:07 +00:00
|
|
|
|
|
|
|
text_sample_count: VkSampleCountFlags,
|
2024-08-29 09:09:17 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
callback_list: Vec<Box<dyn FnOnce() -> Result<()> + Send + Sync>>,
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-03 19:01:17 +00:00
|
|
|
impl<'a> GuiHandler<'a> {
|
2023-01-16 09:53:52 +00:00
|
|
|
pub fn new(
|
2023-01-18 11:24:56 +00:00
|
|
|
gui_handler_create_info: GuiHandlerCreateInfo<'_>,
|
2025-02-27 09:43:07 +00:00
|
|
|
context: &impl ContextInterface,
|
2025-03-04 08:11:05 +00:00
|
|
|
) -> Result<Self> {
|
2023-01-16 09:53:52 +00:00
|
|
|
let device = context.device();
|
|
|
|
let queue = context.queue();
|
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
let command_buffers = context
|
|
|
|
.images()
|
|
|
|
.execute(|_| Self::create_command_buffers(context.image_count()))?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 21:09:07 +00:00
|
|
|
let text_sample_count = device.max_supported_sample_count(VK_SAMPLE_COUNT_4_BIT);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 21:09:07 +00:00
|
|
|
let render_targets =
|
|
|
|
Self::create_render_targets(device, &context.images(), queue, text_sample_count)?;
|
2023-01-21 13:14:43 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
let (text_objs, color_layout) =
|
|
|
|
Self::init_text_objects(device, &render_targets, text_sample_count)?;
|
2023-01-21 13:14:43 +00:00
|
|
|
let rect_objs = Self::init_rectangle_objects(device, &render_targets)?;
|
|
|
|
let single_color_objects = Self::init_single_color_objects(device, &render_targets)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
let text_to_screen = TextToScreen::new(
|
|
|
|
device,
|
|
|
|
Self::init_text_screen_objects(device, &render_targets)?,
|
|
|
|
&render_targets,
|
|
|
|
)?;
|
|
|
|
|
2023-01-16 09:53:52 +00:00
|
|
|
let (bitmap_texture, bitmap_desc_pool, bitmap_desc_set) = Self::init_bitmap_font(
|
|
|
|
device,
|
|
|
|
queue,
|
2023-01-21 13:14:43 +00:00
|
|
|
match &text_objs {
|
|
|
|
TargetMode::Mono(l) => l,
|
|
|
|
TargetMode::Stereo(l, _) => l,
|
|
|
|
}
|
|
|
|
._descriptor_layout
|
|
|
|
.clone(),
|
2025-02-28 05:38:41 +00:00
|
|
|
gui_handler_create_info.font,
|
2023-01-16 09:53:52 +00:00
|
|
|
)?;
|
|
|
|
|
|
|
|
let icon_descriptor_layout = DescriptorSetLayout::builder()
|
|
|
|
.add_layout_binding(
|
|
|
|
0,
|
|
|
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
|
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
Ok(GuiHandler {
|
2023-01-16 09:53:52 +00:00
|
|
|
device: device.clone(),
|
|
|
|
queue: queue.clone(),
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
width: context.width(),
|
|
|
|
height: context.height(),
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-17 06:07:19 +00:00
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
click_sound: gui_handler_create_info.click_sound.map(|mut click_sound| {
|
|
|
|
click_sound.set_prefix(
|
|
|
|
&gui_handler_create_info
|
|
|
|
.resource_directory
|
|
|
|
.as_ref()
|
|
|
|
.expect("missing resource directory")
|
|
|
|
.full_path(),
|
|
|
|
);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
click_sound
|
2025-02-28 05:26:57 +00:00
|
|
|
}),
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-17 06:07:19 +00:00
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
hover_sound: gui_handler_create_info.hover_sound.map(|mut hover_sound| {
|
|
|
|
hover_sound.set_prefix(
|
|
|
|
&gui_handler_create_info
|
|
|
|
.resource_directory
|
|
|
|
.as_ref()
|
|
|
|
.expect("missing resource directory")
|
|
|
|
.full_path(),
|
|
|
|
);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
hover_sound
|
2025-02-28 05:26:57 +00:00
|
|
|
}),
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-02-28 05:48:19 +00:00
|
|
|
resource_base_path: gui_handler_create_info.resource_directory,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
top_ui: None,
|
|
|
|
tooltip_ui: None,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 13:14:43 +00:00
|
|
|
render_targets,
|
2023-01-16 09:53:52 +00:00
|
|
|
command_buffers,
|
|
|
|
|
|
|
|
text_objects: text_objs,
|
|
|
|
rectangle_objects: rect_objs,
|
|
|
|
single_color_objects,
|
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
text_to_screen,
|
|
|
|
|
2023-01-16 09:53:52 +00:00
|
|
|
_bitmap_font: bitmap_texture,
|
|
|
|
_bitmap_desc_pool: bitmap_desc_pool,
|
|
|
|
bitmap_desc_set,
|
|
|
|
|
|
|
|
text_color_layout: color_layout,
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
internal_icons: HashMap::new(),
|
|
|
|
internal_textures: HashMap::new(),
|
|
|
|
internal_colors: HashMap::new(),
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2024-03-25 11:33:56 +00:00
|
|
|
element_creator: Mutex::new(ElementCreator::new(device.clone(), queue.clone())?),
|
|
|
|
|
2023-01-16 09:53:52 +00:00
|
|
|
icon_descriptor_layout,
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
needs_update: true,
|
|
|
|
text_change_queue: Vec::new(),
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
on_selected: None,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
layers: Vec::new(),
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
ortho: ortho(
|
2023-01-16 09:53:52 +00:00
|
|
|
0.0,
|
2023-01-16 11:58:59 +00:00
|
|
|
context.width() as f32,
|
2023-01-16 09:53:52 +00:00
|
|
|
0.0,
|
2023-01-16 11:58:59 +00:00
|
|
|
context.height() as f32,
|
2023-01-16 09:53:52 +00:00
|
|
|
-1.0,
|
|
|
|
1.0,
|
2025-03-04 08:11:05 +00:00
|
|
|
),
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
mouse_x: 0,
|
|
|
|
mouse_y: 0,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
last_direction: GuiDirection::None,
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
current_clickable: None,
|
|
|
|
current_hoverable: None,
|
|
|
|
current_selectable: None,
|
|
|
|
current_writeable: None,
|
2023-01-21 21:09:07 +00:00
|
|
|
|
|
|
|
text_sample_count,
|
2024-08-29 09:09:17 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
callback_list: Vec::new(),
|
|
|
|
})
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn device(&self) -> &Arc<Device> {
|
|
|
|
&self.device
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn queue(&self) -> &Arc<Mutex<Queue>> {
|
|
|
|
&self.queue
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn width(&self) -> u32 {
|
2025-03-04 08:11:05 +00:00
|
|
|
self.width
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn height(&self) -> u32 {
|
2025-03-04 08:11:05 +00:00
|
|
|
self.height
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn icon_descriptor_layout(&self) -> &Arc<DescriptorSetLayout> {
|
|
|
|
&self.icon_descriptor_layout
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn request_icon(
|
2025-03-04 08:11:05 +00:00
|
|
|
&mut self,
|
2023-01-16 09:53:52 +00:00
|
|
|
icon_builder: impl Into<IconBuilderType>,
|
|
|
|
) -> Result<Arc<Image>> {
|
|
|
|
let icon_builder = icon_builder.into();
|
|
|
|
|
|
|
|
match icon_builder {
|
|
|
|
IconBuilderType::Image(image) => {
|
|
|
|
if let Some(path) = image.file_name() {
|
|
|
|
self.internal_icons
|
|
|
|
.insert(path.clone(), Arc::downgrade(&image));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(image)
|
|
|
|
}
|
2025-03-04 08:11:05 +00:00
|
|
|
IconBuilderType::Path(mut path) => match self.internal_icons.get_mut(&path) {
|
|
|
|
Some(weak_image) => match weak_image.upgrade() {
|
|
|
|
Some(image) => Ok(image),
|
2023-01-16 09:53:52 +00:00
|
|
|
None => {
|
|
|
|
if !path.has_prefix() {
|
2025-02-28 05:48:19 +00:00
|
|
|
path.set_prefix(
|
|
|
|
&self
|
|
|
|
.resource_base_path
|
|
|
|
.as_ref()
|
|
|
|
.ok_or(anyhow!("resource base path not set!"))?
|
|
|
|
.full_path(),
|
|
|
|
);
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
let image = Image::from_file(path)?
|
2023-01-16 09:53:52 +00:00
|
|
|
.max_mip_map_levels()
|
2025-02-28 14:10:04 +00:00
|
|
|
.attach_pretty_sampler(self.device())?
|
2023-01-16 09:53:52 +00:00
|
|
|
.build(self.device(), self.queue())?;
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
*weak_image = Arc::downgrade(&image);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
Ok(image)
|
|
|
|
}
|
2025-03-04 08:11:05 +00:00
|
|
|
},
|
|
|
|
None => {
|
|
|
|
if !path.has_prefix() {
|
|
|
|
path.set_prefix(
|
|
|
|
&self
|
|
|
|
.resource_base_path
|
|
|
|
.as_ref()
|
|
|
|
.ok_or(anyhow!("resource base path not set!"))?
|
|
|
|
.full_path(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let image = Image::from_file(path.clone())?
|
|
|
|
.max_mip_map_levels()
|
|
|
|
.attach_pretty_sampler(self.device())?
|
|
|
|
.build(self.device(), self.queue())?;
|
|
|
|
|
|
|
|
self.internal_icons.insert(path, Arc::downgrade(&image));
|
|
|
|
|
|
|
|
Ok(image)
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
2025-03-04 08:11:05 +00:00
|
|
|
},
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-21 13:14:43 +00:00
|
|
|
fn text_desc_layout(&self) -> &Arc<DescriptorSetLayout> {
|
|
|
|
&match &self.text_objects {
|
|
|
|
TargetMode::Mono(l) => l,
|
|
|
|
TargetMode::Stereo(l, _) => l,
|
|
|
|
}
|
|
|
|
._descriptor_layout
|
|
|
|
}
|
|
|
|
|
2024-03-25 11:33:56 +00:00
|
|
|
pub(crate) fn displayable_image_from_descriptor(
|
2025-03-04 08:11:05 +00:00
|
|
|
&mut self,
|
2024-03-25 11:33:56 +00:00
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
descriptor: ElementDescriptor,
|
|
|
|
) -> Result<Arc<Image>> {
|
|
|
|
self.element_creator
|
|
|
|
.lock()
|
|
|
|
.unwrap()
|
|
|
|
.get(width, height, descriptor)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn image_descriptor_set(&self) -> Result<Arc<DescriptorSet>> {
|
|
|
|
let desc_pool = DescriptorPool::builder()
|
|
|
|
.set_layout(self.text_desc_layout().clone())
|
|
|
|
.build(self.device.clone())?;
|
|
|
|
|
|
|
|
DescriptorPool::prepare_set(&desc_pool).allocate()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn displayable_image_from_path(&self, mut path: AssetPath) -> Result<Arc<Image>> {
|
2023-01-16 09:53:52 +00:00
|
|
|
if !path.has_prefix() {
|
2025-02-28 05:48:19 +00:00
|
|
|
path.set_prefix(
|
|
|
|
&self
|
|
|
|
.resource_base_path
|
|
|
|
.as_ref()
|
|
|
|
.ok_or(anyhow!("resource base path not set!"))?
|
|
|
|
.full_path(),
|
|
|
|
);
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
if self.internal_textures.contains_key(&path) {
|
|
|
|
Ok(self.internal_textures[&path].clone())
|
2023-01-16 09:53:52 +00:00
|
|
|
} else {
|
|
|
|
let texture = Image::from_file(path.clone())?
|
|
|
|
.format(VK_FORMAT_R8G8B8A8_UNORM)
|
|
|
|
.attach_sampler(Sampler::nearest_sampler().build(&self.device)?)
|
|
|
|
.build(&self.device, &self.queue)?;
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.internal_textures.insert(path.clone(), texture.clone());
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2024-03-25 11:33:56 +00:00
|
|
|
Ok(texture.clone())
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn color_descriptor(&mut self, color: Color) -> Result<Arc<DescriptorSet>> {
|
|
|
|
if self.internal_colors.contains_key(&color) {
|
|
|
|
Ok(self.internal_colors[&color]._descriptor_set.clone())
|
2023-01-16 09:53:52 +00:00
|
|
|
} else {
|
|
|
|
let desc_pool = DescriptorPool::builder()
|
|
|
|
.set_layout(self.text_color_layout.clone())
|
|
|
|
.build(self.device.clone())?;
|
|
|
|
|
|
|
|
let desc_set = DescriptorPool::prepare_set(&desc_pool).allocate()?;
|
|
|
|
|
|
|
|
let color_array: [f32; 3] = color.into();
|
2023-02-01 13:42:25 +00:00
|
|
|
let color_buffer_array: [ColorBuffer; 3] = color_array
|
|
|
|
.into_iter()
|
|
|
|
.map(|f| ColorBuffer { color: f })
|
|
|
|
.collect::<Vec<ColorBuffer>>()
|
|
|
|
.try_into()
|
|
|
|
.unwrap_or_else(|_: Vec<ColorBuffer>| {
|
|
|
|
unreachable!("create array from vec from an array")
|
|
|
|
});
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
let buffer = Buffer::builder()
|
|
|
|
.set_usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
|
|
|
|
.set_memory_usage(MemoryUsage::CpuOnly)
|
2023-02-01 13:42:25 +00:00
|
|
|
.set_data(&color_buffer_array)
|
2023-01-16 09:53:52 +00:00
|
|
|
.build(self.device.clone())?;
|
|
|
|
|
|
|
|
desc_set.update(&[DescriptorWrite::uniform_buffers(0, &[&buffer])])?;
|
|
|
|
|
|
|
|
let textable_color = TextableColor {
|
|
|
|
_descriptor_pool: desc_pool,
|
|
|
|
_descriptor_set: desc_set,
|
|
|
|
|
|
|
|
_buffer: buffer,
|
|
|
|
};
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.internal_colors.insert(color, textable_color);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
Ok(self.internal_colors[&color]._descriptor_set.clone())
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn ortho(&self) -> cgmath::Matrix4<f32> {
|
2025-03-04 08:11:05 +00:00
|
|
|
self.ortho
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-02-28 05:48:19 +00:00
|
|
|
pub(crate) fn resource_base_path(&self) -> Option<&AssetPath> {
|
|
|
|
self.resource_base_path.as_ref()
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-17 06:07:19 +00:00
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
pub fn click_sound(&self) -> Option<&AssetPath> {
|
|
|
|
self.click_sound.as_ref()
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-17 06:07:19 +00:00
|
|
|
#[cfg(feature = "audio")]
|
2025-02-28 05:26:57 +00:00
|
|
|
pub fn hover_sound(&self) -> Option<&AssetPath> {
|
|
|
|
self.hover_sound.as_ref()
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn set_on_selected_event<F>(&self, f: F)
|
2023-01-16 09:53:52 +00:00
|
|
|
where
|
|
|
|
F: Fn() -> Result<()> + Send + Sync + 'static,
|
|
|
|
{
|
2025-03-04 08:11:05 +00:00
|
|
|
self.on_selected = Some(Box::new(f));
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
// ------------------------- event handling --------------------------
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn set_mouse_pos(&mut self, x: u32, y: u32) -> Result<()> {
|
|
|
|
self.mouse_x = x;
|
|
|
|
self.mouse_y = y;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
let mut hovered = None;
|
|
|
|
|
|
|
|
{
|
2025-03-04 08:11:05 +00:00
|
|
|
for (_, elements) in self.layers.iter() {
|
2023-01-16 09:53:52 +00:00
|
|
|
for hoverable in elements.iter_hoverables() {
|
|
|
|
if hoverable.is_hovered(x as i32, y as i32) {
|
|
|
|
hovered = Some(hoverable.clone());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match hovered {
|
|
|
|
Some(hovered) => {
|
2025-03-04 08:11:05 +00:00
|
|
|
if let Some(current) = &self.current_hoverable {
|
2023-01-16 09:53:52 +00:00
|
|
|
if Arc::ptr_eq(current, &hovered) {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
current.set_hovered(self, false)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
hovered.set_hovered(self, true)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.current_hoverable = Some(hovered);
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
None => {
|
2025-03-04 08:11:05 +00:00
|
|
|
if self.current_hoverable.is_some() {
|
2023-01-16 09:53:52 +00:00
|
|
|
// unwrap is safe, just tested for `is_some`
|
2025-03-04 08:11:05 +00:00
|
|
|
if !self
|
|
|
|
.current_hoverable
|
2023-01-16 09:53:52 +00:00
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.is_hovered(x as i32, y as i32)
|
|
|
|
{
|
2025-03-04 08:11:05 +00:00
|
|
|
self.current_hoverable
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.set_hovered(self, false)?;
|
|
|
|
self.current_hoverable = None;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn mouse_position(&self) -> (u32, u32) {
|
2025-03-04 08:11:05 +00:00
|
|
|
(self.mouse_x, self.mouse_y)
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
fn find_clickable(&mut self) -> Result<Option<Arc<Clickable>>> {
|
|
|
|
for (_, elements) in self.layers.iter() {
|
2023-01-16 09:53:52 +00:00
|
|
|
for clickable in elements.iter_clickables() {
|
2025-03-04 08:11:05 +00:00
|
|
|
if clickable.is_pressed(self.mouse_x as i32, self.mouse_y as i32) {
|
|
|
|
self.current_clickable = Some(clickable.clone());
|
2023-01-16 09:53:52 +00:00
|
|
|
return Ok(Some(clickable.clone()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn mouse_down(&mut self, mouse_button: MouseButton) -> Result<bool> {
|
2023-01-16 09:53:52 +00:00
|
|
|
if mouse_button == MouseButton::Left {
|
|
|
|
if let Some(tmp_clickable) = self.find_clickable()? {
|
2025-03-04 08:11:05 +00:00
|
|
|
tmp_clickable.set_clicked(self, true)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn mouse_up(&mut self, mouse_button: MouseButton) -> Result<bool> {
|
2023-01-16 09:53:52 +00:00
|
|
|
if mouse_button == MouseButton::Left {
|
2025-03-04 08:11:05 +00:00
|
|
|
if self.current_clickable.is_some() {
|
|
|
|
self.current_clickable
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.set_clicked(self, false)?;
|
|
|
|
|
|
|
|
if self
|
|
|
|
.current_clickable
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.is_pressed(self.mouse_x as i32, self.mouse_y as i32)
|
|
|
|
{
|
|
|
|
if let Some(hoverable) = self.current_hoverable.as_ref() {
|
|
|
|
hoverable.set_hovered(self, true)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.current_clickable = None;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn current_selectable(&self) -> Option<Arc<Selectable<'a>>> {
|
|
|
|
self.current_selectable.clone()
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn accept_selection(&mut self) -> Result<bool> {
|
|
|
|
if let Some(current_selectable) = &self.current_selectable {
|
|
|
|
current_selectable.click_event(self)?;
|
|
|
|
|
2023-01-16 09:53:52 +00:00
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn accept_custom_selection(&self, button: ControllerButton) -> Result<bool> {
|
2025-03-04 08:11:05 +00:00
|
|
|
if let Some(current_selectable) = &self.current_selectable {
|
2023-01-16 09:53:52 +00:00
|
|
|
if current_selectable.custom_click_event(button)? {
|
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn decline_topgui(&self) -> Result<bool> {
|
|
|
|
// workaround for unwanted borrowing behaviour inside decline function
|
2025-03-04 08:11:05 +00:00
|
|
|
let opt_topgui = self.top_ui.as_ref().cloned();
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
if let Some(topgui) = opt_topgui {
|
|
|
|
topgui.decline()?;
|
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn next_tab_topgui(&self, second_level: bool) -> Result<bool> {
|
|
|
|
// workaround for unwanted borrowing behaviour inside decline function
|
2025-03-04 08:11:05 +00:00
|
|
|
let opt_topgui = self.top_ui.as_ref().cloned();
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
if let Some(topgui) = opt_topgui {
|
|
|
|
topgui.next_tab(second_level)?;
|
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn previous_tab_topgui(&self, second_level: bool) -> Result<bool> {
|
|
|
|
// workaround for unwanted borrowing behaviour inside decline function
|
2025-03-04 08:11:05 +00:00
|
|
|
let opt_topgui = self.top_ui.as_ref().cloned();
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
if let Some(topgui) = opt_topgui {
|
|
|
|
topgui.previous_tab(second_level)?;
|
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn writeable(&self) -> Option<Arc<Writeable>> {
|
|
|
|
self.current_writeable.clone()
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove_char(&self) -> Result<bool> {
|
2025-03-04 08:11:05 +00:00
|
|
|
match &self.current_writeable {
|
2023-01-16 09:53:52 +00:00
|
|
|
Some(current_writable) => {
|
|
|
|
current_writable.remove_last()?;
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
None => Ok(false),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn check_navigatable(&self) -> bool {
|
|
|
|
self.current_selectable.is_some()
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn update_selection(&mut self, direction: GuiDirection) -> Result<bool> {
|
|
|
|
if direction != self.last_direction {
|
|
|
|
self.last_direction = direction;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
match self.current_selectable.write().unwrap().as_mut() {
|
|
|
|
Some(current_selectable) => match direction {
|
|
|
|
GuiDirection::Left => {
|
|
|
|
if let Some(neighbour) = current_selectable.west_neighbour() {
|
2025-03-04 08:11:05 +00:00
|
|
|
current_selectable.set_selected(self, false)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
*current_selectable = neighbour;
|
2025-03-04 08:11:05 +00:00
|
|
|
current_selectable.set_selected(self, true)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
GuiDirection::Right => {
|
|
|
|
if let Some(neighbour) = current_selectable.east_neighbour() {
|
2025-03-04 08:11:05 +00:00
|
|
|
current_selectable.set_selected(self, false)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
*current_selectable = neighbour;
|
2025-03-04 08:11:05 +00:00
|
|
|
current_selectable.set_selected(self, true)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
GuiDirection::Up => {
|
|
|
|
if let Some(neighbour) = current_selectable.north_neighbour() {
|
2025-03-04 08:11:05 +00:00
|
|
|
current_selectable.set_selected(self, false)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
*current_selectable = neighbour;
|
2025-03-04 08:11:05 +00:00
|
|
|
current_selectable.set_selected(self, true)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
GuiDirection::Down => {
|
|
|
|
if let Some(neighbour) = current_selectable.south_neighbour() {
|
2025-03-04 08:11:05 +00:00
|
|
|
current_selectable.set_selected(self, false)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
*current_selectable = neighbour;
|
2025-03-04 08:11:05 +00:00
|
|
|
current_selectable.set_selected(self, true)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
GuiDirection::None => Ok(false),
|
|
|
|
},
|
|
|
|
None => Ok(false),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn enqueue_text_update(
|
|
|
|
&mut self,
|
|
|
|
function: Box<dyn Fn() -> Result<()> + Send + Sync>,
|
|
|
|
) {
|
|
|
|
self.text_change_queue.push(function);
|
|
|
|
self.needs_update = true;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn set_top_gui(&mut self, top_gui: impl Into<Option<Arc<dyn TopGui>>>) {
|
|
|
|
self.top_ui = top_gui.into();
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn set_tooltip(&mut self, tooltip: impl Into<Option<Arc<dyn TopGui>>>) {
|
|
|
|
self.tooltip_ui = tooltip.into();
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_callback<F: FnOnce() -> Result<()> + Send + Sync + 'static>(&mut self, f: F) {
|
|
|
|
self.callback_list.push(Box::new(f));
|
2024-08-29 09:09:17 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub fn process_callbacks(&mut self) -> Result<()> {
|
|
|
|
let callbacks = mem::take(&mut self.callback_list);
|
2024-08-29 09:13:28 +00:00
|
|
|
|
|
|
|
callbacks.into_iter().try_for_each(|callback| callback())
|
2024-08-29 09:09:17 +00:00
|
|
|
}
|
|
|
|
|
2023-01-16 09:53:52 +00:00
|
|
|
fn render(
|
|
|
|
&self,
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder: &mut CommandBufferRecorder<'_>,
|
2023-01-16 09:53:52 +00:00
|
|
|
command_buffer_state: &CommandBufferState,
|
2023-01-21 13:14:43 +00:00
|
|
|
render_target: &RenderTarget,
|
|
|
|
single_color_objects: &GuiSeparator,
|
|
|
|
rectangle_objects: &GuiSeparator,
|
|
|
|
text_objects: &GuiSeparator,
|
2023-01-22 15:02:46 +00:00
|
|
|
text_to_screen: &GuiSeparator,
|
|
|
|
text_to_screen_desc: &Arc<DescriptorSet>,
|
2023-01-21 21:09:07 +00:00
|
|
|
index: usize,
|
2023-01-16 09:53:52 +00:00
|
|
|
) -> Result<()> {
|
2023-01-21 22:34:01 +00:00
|
|
|
let viewport = [VkViewport {
|
|
|
|
x: 0.0,
|
|
|
|
y: 0.0,
|
2025-03-04 08:11:05 +00:00
|
|
|
width: self.width as f32,
|
|
|
|
height: self.height as f32,
|
2023-01-21 22:34:01 +00:00
|
|
|
minDepth: 0.0,
|
|
|
|
maxDepth: 1.0,
|
|
|
|
}];
|
|
|
|
|
|
|
|
let scissor = [VkRect2D {
|
|
|
|
offset: VkOffset2D { x: 0, y: 0 },
|
|
|
|
extent: VkExtent2D {
|
2025-03-04 08:11:05 +00:00
|
|
|
width: self.width,
|
|
|
|
height: self.height,
|
2023-01-21 22:34:01 +00:00
|
|
|
},
|
|
|
|
}];
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
for (_, elements) in self.layers.iter() {
|
2023-01-21 22:34:01 +00:00
|
|
|
render_target.begin(buffer_recorder, VK_SUBPASS_CONTENTS_INLINE, index);
|
2023-01-21 21:09:07 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
if !elements.is_colorables_empty() {
|
2023-01-22 15:02:46 +00:00
|
|
|
buffer_recorder.bind_pipeline(&single_color_objects.pipeline)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.set_scissor(&scissor);
|
|
|
|
buffer_recorder.set_viewport(&viewport);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
// ---------- render colorables ----------
|
|
|
|
for colorable in elements.iter_colorables() {
|
|
|
|
buffer_recorder.bind_vertex_buffer(colorable.buffer());
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.bind_descriptor_sets_minimal(&[&colorable.descriptor_set()]);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.draw_complete_single_instance(6);
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
2023-01-21 22:34:01 +00:00
|
|
|
}
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
if !elements.is_displayables_empty() || !elements.is_iconizables_empty() {
|
2023-01-22 15:02:46 +00:00
|
|
|
buffer_recorder.bind_pipeline(&rectangle_objects.pipeline)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.set_scissor(&scissor);
|
|
|
|
buffer_recorder.set_viewport(&viewport);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
// ---------- render displayables ----------
|
|
|
|
for displayable in elements.iter_displayables() {
|
|
|
|
buffer_recorder.bind_vertex_buffer(displayable.buffer());
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.bind_descriptor_sets_minimal(&[&displayable.descriptor_set()]);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.draw_complete_single_instance(6);
|
|
|
|
}
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
// ---------- render iconizables ----------
|
|
|
|
for iconizable in elements.iter_iconizables() {
|
|
|
|
buffer_recorder.bind_vertex_buffer(iconizable.buffer());
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.bind_descriptor_sets_minimal(&[iconizable.descriptor_set()]);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.draw_complete_single_instance(6);
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
2023-01-21 22:34:01 +00:00
|
|
|
}
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
// render text, render to offscreen (multisampled) and merge resolved target with actual image
|
2023-01-21 22:34:01 +00:00
|
|
|
if !elements.is_textables_empty() {
|
2023-01-22 15:02:46 +00:00
|
|
|
render_target.next_subpass(buffer_recorder, VK_SUBPASS_CONTENTS_INLINE);
|
|
|
|
|
|
|
|
buffer_recorder.bind_pipeline(&text_objects.pipeline)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.set_scissor(&scissor);
|
|
|
|
buffer_recorder.set_viewport(&viewport);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
let mut text_buffers = command_buffer_state.text_buffers.write().unwrap();
|
|
|
|
text_buffers.clear();
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
// ---------- render textables ----------
|
|
|
|
for textable in elements.iter_textables() {
|
|
|
|
if let Some(text_buffer) = textable.buffer() {
|
|
|
|
buffer_recorder.bind_vertex_buffer(&text_buffer);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
text_buffers.push(text_buffer);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.bind_descriptor_sets_minimal(&[
|
|
|
|
&self.bitmap_desc_set,
|
|
|
|
&textable.descriptor_set(),
|
|
|
|
]);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
buffer_recorder.draw_complete_single_instance(textable.vertex_count());
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-22 15:02:46 +00:00
|
|
|
|
|
|
|
// after text is written und resolved, we read image as input and draw it over the current image
|
|
|
|
render_target.next_subpass(buffer_recorder, VK_SUBPASS_CONTENTS_INLINE);
|
|
|
|
|
|
|
|
buffer_recorder.bind_pipeline(&text_to_screen.pipeline)?;
|
|
|
|
|
|
|
|
buffer_recorder.set_scissor(&scissor);
|
|
|
|
buffer_recorder.set_viewport(&viewport);
|
|
|
|
|
|
|
|
buffer_recorder.bind_descriptor_sets_minimal(&[text_to_screen_desc]);
|
|
|
|
buffer_recorder.bind_vertex_buffer(&self.text_to_screen.buffer);
|
|
|
|
buffer_recorder
|
|
|
|
.draw_complete_single_instance(self.text_to_screen.buffer.size() as u32);
|
2023-01-26 08:24:53 +00:00
|
|
|
} else {
|
|
|
|
// dummy advance sub passes
|
|
|
|
// since ending render pass and not being in the last sub pass seems to be an error
|
|
|
|
render_target.next_subpass(buffer_recorder, VK_SUBPASS_CONTENTS_INLINE);
|
|
|
|
render_target.next_subpass(buffer_recorder, VK_SUBPASS_CONTENTS_INLINE);
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-21 22:34:01 +00:00
|
|
|
render_target.end(buffer_recorder);
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! add_element {
|
|
|
|
($layers: expr, $layer_id: ident, $element: ident) => {
|
|
|
|
let mut layers = $layers.lock().unwrap();
|
|
|
|
|
|
|
|
paste! {
|
|
|
|
match layers.iter_mut().find(|(id, _)| *id == $layer_id) {
|
|
|
|
Some((_, layer)) => {
|
|
|
|
layer.[<add_ $element>]($element);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let mut elements = Elements::default();
|
|
|
|
elements.[<add_ $element>]($element);
|
|
|
|
|
|
|
|
layers.push(($layer_id, elements));
|
|
|
|
layers.sort_by(|(left_id, _), (right_id, _)| left_id.cmp(right_id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! remove_element {
|
|
|
|
($layers: expr, $layer_id: ident, $element: ident) => {
|
|
|
|
paste! {
|
2025-03-04 08:11:05 +00:00
|
|
|
match $layers.iter_mut().find(|(id, _)| *id == $layer_id) {
|
2023-01-16 09:53:52 +00:00
|
|
|
Some((_, layer)) => {
|
|
|
|
layer.[<delete_ $element>]($element);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
panic!("layer not present from which {} is to remove", stringify!($element));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
($layers: expr, $layer_id: ident, $element: ident, $update: expr) => {
|
|
|
|
paste! {
|
2025-03-04 08:11:05 +00:00
|
|
|
match $layers.iter_mut().find(|(id, _)| *id == $layer_id) {
|
2023-01-16 09:53:52 +00:00
|
|
|
Some((_, layer)) => {
|
|
|
|
if layer.[<delete_ $element>]($element) {
|
2025-03-04 08:11:05 +00:00
|
|
|
$update = true;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
panic!("layer not present from which {} is to remove", stringify!($element));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// object handling
|
2025-03-03 19:01:17 +00:00
|
|
|
impl<'a> GuiHandler<'a> {
|
2023-01-16 09:53:52 +00:00
|
|
|
// framable
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_framable(&mut self, layer: i32, framable: Arc<Framable>) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
add_element!(self.layers, layer, framable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn delete_framable(&mut self, layer: i32, framable: &Arc<Framable>) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
remove_element!(self.layers, layer, framable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// hoverable
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_hoverable(&mut self, layer: i32, hoverable: Arc<Hoverable>) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
add_element!(self.layers, layer, hoverable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn delete_hoverable(
|
|
|
|
&mut self,
|
|
|
|
layer: i32,
|
|
|
|
hoverable: &Arc<Hoverable>,
|
|
|
|
) -> Result<()> {
|
|
|
|
if self.current_hoverable.is_some() {
|
2023-01-16 09:53:52 +00:00
|
|
|
// unwrap is safe, just tested for `is_some`
|
2025-03-04 08:11:05 +00:00
|
|
|
if Arc::ptr_eq(hoverable, self.current_hoverable.as_ref().unwrap()) {
|
|
|
|
self.current_hoverable = None;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
remove_element!(self.layers, layer, hoverable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// selectable
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_selectable(
|
|
|
|
&mut self,
|
|
|
|
layer: i32,
|
|
|
|
selectable: Arc<Selectable<'_>>,
|
|
|
|
) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
add_element!(self.layers, layer, selectable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-03 19:01:17 +00:00
|
|
|
pub(crate) fn delete_selectable(
|
2025-03-04 08:11:05 +00:00
|
|
|
&mut self,
|
2025-03-03 19:01:17 +00:00
|
|
|
layer: i32,
|
|
|
|
selectable: &Arc<Selectable<'a>>,
|
|
|
|
) -> Result<()> {
|
2025-03-04 08:11:05 +00:00
|
|
|
if self.current_selectable.is_some() {
|
2023-01-16 09:53:52 +00:00
|
|
|
// unwrap is safe, just tested for `is_some`
|
2025-03-04 08:11:05 +00:00
|
|
|
if Arc::ptr_eq(selectable, self.current_selectable.as_ref().unwrap()) {
|
|
|
|
self.current_selectable = None;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
remove_element!(self.layers, layer, selectable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// displayable
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_displayable(
|
|
|
|
&mut self,
|
|
|
|
layer: i32,
|
|
|
|
displayable: Arc<Displayable>,
|
|
|
|
) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
add_element!(self.layers, layer, displayable);
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.needs_update = true;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn delete_displayable(
|
2025-03-04 08:11:05 +00:00
|
|
|
&mut self,
|
2023-01-16 09:53:52 +00:00
|
|
|
layer: i32,
|
|
|
|
displayable: &Arc<Displayable>,
|
|
|
|
) -> Result<()> {
|
|
|
|
remove_element!(self.layers, layer, displayable, self.needs_update);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// clickable
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_clickable(&mut self, layer: i32, clickable: Arc<Clickable>) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
add_element!(self.layers, layer, clickable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn delete_clickable(
|
|
|
|
&mut self,
|
|
|
|
layer: i32,
|
|
|
|
clickable: &Arc<Clickable>,
|
|
|
|
) -> Result<()> {
|
|
|
|
if self.current_clickable.is_some() {
|
2023-01-16 09:53:52 +00:00
|
|
|
// unwrap is safe, just tested for `is_some`
|
2025-03-04 08:11:05 +00:00
|
|
|
if ptr::eq(clickable, self.current_clickable.as_ref().unwrap()) {
|
|
|
|
self.current_clickable = None;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
remove_element!(self.layers, layer, clickable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// textable
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_textable(&mut self, layer: i32, textable: Arc<Textable>) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
add_element!(self.layers, layer, textable);
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.needs_update = true;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn delete_textable(&mut self, layer: i32, textable: &Arc<Textable>) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
remove_element!(self.layers, layer, textable, self.needs_update);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// writable
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_writeable(&mut self, layer: i32, writeable: Arc<Writeable>) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
add_element!(self.layers, layer, writeable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn set_active_writeable(&mut self, writeable: Arc<Writeable>) -> Result<bool> {
|
|
|
|
if let Some(current) = self.current_writeable.as_ref() {
|
2023-01-16 09:53:52 +00:00
|
|
|
// change nothing if both are the same
|
|
|
|
if Arc::ptr_eq(current, &writeable) {
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
current.inactivation_event()?;
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.current_writeable = Some(writeable);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn delete_writeable(
|
|
|
|
&mut self,
|
|
|
|
layer: i32,
|
|
|
|
writeable: &Arc<Writeable>,
|
|
|
|
) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
{
|
2025-03-04 08:11:05 +00:00
|
|
|
if let Some(w) = &self.current_writeable {
|
2023-01-16 09:53:52 +00:00
|
|
|
if Arc::ptr_eq(w, writeable) {
|
|
|
|
w.inactivation_event()?;
|
2025-03-04 08:11:05 +00:00
|
|
|
self.current_writeable = None;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
remove_element!(self.layers, layer, writeable);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// iconizable
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_iconizable(&mut self, layer: i32, iconizable: Arc<Iconizable>) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
add_element!(self.layers, layer, iconizable);
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.needs_update = true;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn delete_iconizable(
|
|
|
|
&mut self,
|
|
|
|
layer: i32,
|
|
|
|
iconizable: &Arc<Iconizable>,
|
|
|
|
) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
remove_element!(self.layers, layer, iconizable, self.needs_update);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn set_selectable(&mut self, selectable: Option<Arc<Selectable<'a>>>) -> Result<()> {
|
|
|
|
if let Some(selectable) = &self.current_selectable {
|
|
|
|
selectable.set_selected(self, false)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
if let Some(selectable) = &selectable {
|
|
|
|
selectable.set_selected(self, true)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
if let Some(on_selected) = &self.on_selected {
|
2023-01-16 09:53:52 +00:00
|
|
|
on_selected()?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.current_selectable = selectable;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn add_colorable(&mut self, layer: i32, colorable: Arc<Colorable>) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
add_element!(self.layers, layer, colorable);
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.needs_update = true;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
pub(crate) fn delete_colorable(
|
|
|
|
&mut self,
|
|
|
|
layer: i32,
|
|
|
|
colorable: &Arc<Colorable>,
|
|
|
|
) -> Result<()> {
|
2023-01-16 09:53:52 +00:00
|
|
|
remove_element!(self.layers, layer, colorable, self.needs_update);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-18 07:39:15 +00:00
|
|
|
// private - create rendering stuff
|
2025-03-03 19:01:17 +00:00
|
|
|
impl<'a> GuiHandler<'a> {
|
2023-01-21 13:14:43 +00:00
|
|
|
fn create_render_targets(
|
2023-01-16 09:53:52 +00:00
|
|
|
device: &Arc<Device>,
|
|
|
|
target_images: &TargetMode<Vec<Arc<Image>>>,
|
2023-01-21 21:09:07 +00:00
|
|
|
queue: &Arc<Mutex<Queue>>,
|
|
|
|
sample_count: VkSampleCountFlags,
|
2025-03-04 08:11:05 +00:00
|
|
|
) -> Result<TargetMode<RenderTarget>> {
|
2023-01-21 13:14:43 +00:00
|
|
|
Ok(match target_images {
|
2025-03-04 08:11:05 +00:00
|
|
|
TargetMode::Mono(images) => TargetMode::Mono(Self::create_render_target(
|
2023-01-21 21:09:07 +00:00
|
|
|
device,
|
|
|
|
images,
|
|
|
|
None,
|
|
|
|
queue,
|
|
|
|
sample_count,
|
2025-03-04 08:11:05 +00:00
|
|
|
)?),
|
2023-01-21 13:14:43 +00:00
|
|
|
TargetMode::Stereo(left_images, right_images) => TargetMode::Stereo(
|
2025-03-04 08:11:05 +00:00
|
|
|
Self::create_render_target(device, left_images, None, queue, sample_count)?,
|
|
|
|
Self::create_render_target(device, right_images, None, queue, sample_count)?,
|
2023-01-21 13:14:43 +00:00
|
|
|
),
|
|
|
|
})
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-21 16:03:54 +00:00
|
|
|
fn create_render_target(
|
|
|
|
device: &Arc<Device>,
|
|
|
|
target_images: &Vec<Arc<Image>>,
|
|
|
|
old_render_target: Option<&RenderTarget>,
|
2023-01-21 21:09:07 +00:00
|
|
|
queue: &Arc<Mutex<Queue>>,
|
|
|
|
sample_count: VkSampleCountFlags,
|
2023-01-21 16:03:54 +00:00
|
|
|
) -> Result<RenderTarget> {
|
2023-01-21 21:09:07 +00:00
|
|
|
let mut builder = RenderTarget::builder()
|
|
|
|
.add_sub_pass(
|
|
|
|
SubPass::builder(target_images[0].width(), target_images[0].height())
|
2025-03-01 13:12:58 +00:00
|
|
|
.set_prepared_targets(target_images, 0, None)
|
2023-01-21 21:09:07 +00:00
|
|
|
.build(device)?,
|
|
|
|
)
|
|
|
|
.add_sub_pass(
|
|
|
|
SubPass::builder(target_images[0].width(), target_images[0].height())
|
|
|
|
.add_target_info(CustomTarget {
|
|
|
|
usage: VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT.into(),
|
2023-01-21 22:34:01 +00:00
|
|
|
format: VK_FORMAT_R8G8B8A8_UNORM,
|
2023-01-22 17:18:24 +00:00
|
|
|
clear_on_load: true,
|
2023-01-21 21:09:07 +00:00
|
|
|
store_on_save: true,
|
|
|
|
attach_sampler: false,
|
|
|
|
use_as_input: false,
|
|
|
|
clear_value: ClearValue::Color([0.0, 0.0, 0.0, 0.0]),
|
|
|
|
})
|
|
|
|
.set_sample_count(sample_count)
|
2023-01-22 17:18:24 +00:00
|
|
|
.add_resolve_targets(CustomTarget::resolve(
|
|
|
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
|
|
VK_FORMAT_R8G8B8A8_UNORM,
|
|
|
|
None,
|
|
|
|
false,
|
|
|
|
true,
|
|
|
|
))
|
2023-01-21 21:09:07 +00:00
|
|
|
.use_queue(queue.clone())
|
|
|
|
.build(device)?,
|
2023-01-22 15:02:46 +00:00
|
|
|
)
|
|
|
|
.add_sub_pass(
|
|
|
|
SubPass::builder(target_images[0].width(), target_images[0].height())
|
|
|
|
.set_input_attachment_info(InputAttachmentInfo {
|
|
|
|
sub_pass_index: 1,
|
|
|
|
input_indices: vec![1],
|
|
|
|
})
|
2025-03-01 13:12:58 +00:00
|
|
|
.set_prepared_targets(target_images, 0, None)
|
2023-01-22 15:02:46 +00:00
|
|
|
.build(device)?,
|
2023-01-21 21:09:07 +00:00
|
|
|
);
|
2023-01-21 16:03:54 +00:00
|
|
|
|
|
|
|
if let Some(render_target) = old_render_target {
|
|
|
|
builder = builder.preserve_old_render_pass(render_target);
|
|
|
|
}
|
|
|
|
|
|
|
|
builder.build(device)
|
|
|
|
}
|
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
fn create_command_buffers(image_count: usize) -> Result<Vec<CommandBufferState>> {
|
|
|
|
let mut command_buffers = Vec::with_capacity(image_count);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
for _ in 0..image_count {
|
2023-01-16 09:53:52 +00:00
|
|
|
command_buffers.push(CommandBufferState {
|
2025-03-04 08:11:05 +00:00
|
|
|
text_buffers: Vec::new(),
|
2023-01-16 09:53:52 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(command_buffers)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init_bitmap_font(
|
|
|
|
device: &Arc<Device>,
|
|
|
|
queue: &Arc<Mutex<Queue>>,
|
|
|
|
descriptor_layout: Arc<DescriptorSetLayout>,
|
2023-01-18 11:24:56 +00:00
|
|
|
font: Font<'_>,
|
2023-01-16 09:53:52 +00:00
|
|
|
) -> Result<(Arc<Image>, Arc<DescriptorPool>, Arc<DescriptorSet>)> {
|
2023-01-18 11:24:56 +00:00
|
|
|
let texture = match font {
|
|
|
|
Font::Path(path) => Image::from_file(path)?,
|
|
|
|
Font::Bytes(bytes) => Image::from_slice(bytes)?,
|
|
|
|
}
|
|
|
|
.format(VK_FORMAT_R8G8B8A8_UNORM)
|
|
|
|
.max_mip_map_levels()
|
2025-02-28 14:10:04 +00:00
|
|
|
.attach_pretty_sampler(device)?
|
2023-01-18 11:24:56 +00:00
|
|
|
.build(device, queue)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
let descriptor_pool = DescriptorPool::builder()
|
|
|
|
.set_layout(descriptor_layout)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
let descriptor_set = DescriptorPool::prepare_set(&descriptor_pool).allocate()?;
|
|
|
|
|
|
|
|
descriptor_set.update(&[DescriptorWrite::combined_samplers(0, &[&texture])])?;
|
|
|
|
|
|
|
|
Ok((texture, descriptor_pool, descriptor_set))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init_text_objects(
|
|
|
|
device: &Arc<Device>,
|
2025-03-04 08:11:05 +00:00
|
|
|
render_targets: &TargetMode<RenderTarget>,
|
2023-01-21 22:34:01 +00:00
|
|
|
sample_count: VkSampleCountFlags,
|
2023-01-21 13:14:43 +00:00
|
|
|
) -> Result<(TargetMode<GuiSeparator>, Arc<DescriptorSetLayout>)> {
|
2023-01-16 09:53:52 +00:00
|
|
|
// --- layout creation ---
|
|
|
|
let descriptor_layout = DescriptorSetLayout::builder()
|
|
|
|
.add_layout_binding(
|
|
|
|
0,
|
|
|
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
|
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
let color_layout = DescriptorSetLayout::builder()
|
|
|
|
.add_layout_binding(
|
|
|
|
0,
|
|
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
let pipeline_layout = PipelineLayout::builder()
|
|
|
|
.add_descriptor_set_layout(&descriptor_layout)
|
|
|
|
.add_descriptor_set_layout(&color_layout)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
// --- pipeline creation ---
|
2025-02-27 09:43:07 +00:00
|
|
|
let vertex_shader_text = include_bytes!("gui_shader/text.vert.spv");
|
|
|
|
let fragment_shader_text = include_bytes!("gui_shader/text.frag.spv");
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-27 12:46:54 +00:00
|
|
|
let vertex_shader = ShaderModule::from_slice(device.clone(), vertex_shader_text)?;
|
|
|
|
let fragment_shader = ShaderModule::from_slice(device.clone(), fragment_shader_text)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
Ok((
|
2023-01-21 13:14:43 +00:00
|
|
|
render_targets.execute(|render_target| {
|
|
|
|
Ok(GuiSeparator {
|
|
|
|
_descriptor_layout: descriptor_layout.clone(),
|
|
|
|
|
2023-01-27 12:46:54 +00:00
|
|
|
pipeline: GuiHandler::init_gui_pipeline::<TexturedVertex>(
|
2023-01-21 13:14:43 +00:00
|
|
|
device,
|
2025-03-04 08:11:05 +00:00
|
|
|
render_target.render_pass(),
|
2023-01-21 13:14:43 +00:00
|
|
|
&pipeline_layout,
|
|
|
|
vertex_shader.clone(),
|
|
|
|
fragment_shader.clone(),
|
2023-01-21 22:34:01 +00:00
|
|
|
sample_count,
|
2023-01-21 21:09:07 +00:00
|
|
|
1,
|
2023-01-21 13:14:43 +00:00
|
|
|
)?,
|
|
|
|
})
|
|
|
|
})?,
|
2023-01-16 09:53:52 +00:00
|
|
|
color_layout,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init_rectangle_objects(
|
|
|
|
device: &Arc<Device>,
|
2025-03-04 08:11:05 +00:00
|
|
|
render_targets: &TargetMode<RenderTarget>,
|
2023-01-21 13:14:43 +00:00
|
|
|
) -> Result<TargetMode<GuiSeparator>> {
|
2023-01-16 09:53:52 +00:00
|
|
|
let descriptor_layout = DescriptorSetLayout::builder()
|
|
|
|
.add_layout_binding(
|
|
|
|
0,
|
|
|
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
|
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
let pipeline_layout = PipelineLayout::builder()
|
|
|
|
.add_descriptor_set_layout(&descriptor_layout)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
// pipeline creation
|
2023-01-27 12:46:54 +00:00
|
|
|
let vertex_shader =
|
2025-02-27 09:43:07 +00:00
|
|
|
ShaderModule::from_slice(device.clone(), include_bytes!("gui_shader/rect.vert.spv"))?;
|
2023-01-27 12:46:54 +00:00
|
|
|
let fragment_shader =
|
2025-02-27 09:43:07 +00:00
|
|
|
ShaderModule::from_slice(device.clone(), include_bytes!("gui_shader/rect.frag.spv"))?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2023-01-21 13:14:43 +00:00
|
|
|
render_targets.execute(|render_target| {
|
|
|
|
Ok(GuiSeparator {
|
|
|
|
_descriptor_layout: descriptor_layout.clone(),
|
|
|
|
|
2023-01-27 12:46:54 +00:00
|
|
|
pipeline: GuiHandler::init_gui_pipeline::<TexturedVertex>(
|
2023-01-21 13:14:43 +00:00
|
|
|
device,
|
2025-03-04 08:11:05 +00:00
|
|
|
render_target.render_pass(),
|
2023-01-21 13:14:43 +00:00
|
|
|
&pipeline_layout,
|
|
|
|
vertex_shader.clone(),
|
|
|
|
fragment_shader.clone(),
|
2023-01-21 22:34:01 +00:00
|
|
|
VK_SAMPLE_COUNT_1_BIT,
|
2023-01-21 21:09:07 +00:00
|
|
|
0,
|
2023-01-21 13:14:43 +00:00
|
|
|
)?,
|
|
|
|
})
|
2023-01-16 09:53:52 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
fn init_text_screen_objects(
|
|
|
|
device: &Arc<Device>,
|
2025-03-04 08:11:05 +00:00
|
|
|
render_targets: &TargetMode<RenderTarget>,
|
2023-01-22 15:02:46 +00:00
|
|
|
) -> Result<TargetMode<GuiSeparator>> {
|
|
|
|
let descriptor_layout = DescriptorSetLayout::builder()
|
|
|
|
.add_layout_binding(
|
|
|
|
0,
|
|
|
|
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
|
|
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
let pipeline_layout = PipelineLayout::builder()
|
|
|
|
.add_descriptor_set_layout(&descriptor_layout)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
// pipeline creation
|
2023-01-27 12:46:54 +00:00
|
|
|
let vertex_shader =
|
2025-02-27 09:43:07 +00:00
|
|
|
ShaderModule::from_slice(device.clone(), include_bytes!("gui_shader/rect.vert.spv"))?;
|
2023-01-22 15:02:46 +00:00
|
|
|
let fragment_shader = ShaderModule::from_slice(
|
|
|
|
device.clone(),
|
2025-02-27 09:43:07 +00:00
|
|
|
include_bytes!("gui_shader/input_rect.frag.spv"),
|
2023-01-22 15:02:46 +00:00
|
|
|
)?;
|
|
|
|
|
|
|
|
render_targets.execute(|render_target| {
|
|
|
|
Ok(GuiSeparator {
|
|
|
|
_descriptor_layout: descriptor_layout.clone(),
|
|
|
|
|
2023-01-27 12:46:54 +00:00
|
|
|
pipeline: GuiHandler::init_gui_pipeline::<TexturedVertex>(
|
2023-01-22 15:02:46 +00:00
|
|
|
device,
|
2025-03-04 08:11:05 +00:00
|
|
|
render_target.render_pass(),
|
2023-01-22 15:02:46 +00:00
|
|
|
&pipeline_layout,
|
|
|
|
vertex_shader.clone(),
|
|
|
|
fragment_shader.clone(),
|
|
|
|
VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
2,
|
|
|
|
)?,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-01-16 09:53:52 +00:00
|
|
|
fn init_single_color_objects(
|
|
|
|
device: &Arc<Device>,
|
2025-03-04 08:11:05 +00:00
|
|
|
render_targets: &TargetMode<RenderTarget>,
|
2023-01-21 13:14:43 +00:00
|
|
|
) -> Result<TargetMode<GuiSeparator>> {
|
2023-01-16 09:53:52 +00:00
|
|
|
let color_layout = DescriptorSetLayout::builder()
|
|
|
|
.add_layout_binding(
|
|
|
|
0,
|
|
|
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
let pipeline_layout = PipelineLayout::builder()
|
|
|
|
.add_descriptor_set_layout(&color_layout)
|
|
|
|
.build(device.clone())?;
|
|
|
|
|
|
|
|
// pipeline creation
|
|
|
|
let vertex_shader = ShaderModule::from_slice(
|
|
|
|
device.clone(),
|
2025-02-27 09:43:07 +00:00
|
|
|
include_bytes!("gui_shader/single_color.vert.spv"),
|
2023-01-16 09:53:52 +00:00
|
|
|
)?;
|
|
|
|
let fragment_shader = ShaderModule::from_slice(
|
|
|
|
device.clone(),
|
2025-02-27 09:43:07 +00:00
|
|
|
include_bytes!("gui_shader/single_color.frag.spv"),
|
2023-01-16 09:53:52 +00:00
|
|
|
)?;
|
|
|
|
|
2023-01-21 13:14:43 +00:00
|
|
|
render_targets.execute(|render_target| {
|
|
|
|
Ok(GuiSeparator {
|
|
|
|
_descriptor_layout: color_layout.clone(),
|
|
|
|
|
2023-01-27 12:46:54 +00:00
|
|
|
pipeline: GuiHandler::init_gui_pipeline::<ColorableVertex>(
|
2023-01-21 13:14:43 +00:00
|
|
|
device,
|
2025-03-04 08:11:05 +00:00
|
|
|
render_target.render_pass(),
|
2023-01-21 13:14:43 +00:00
|
|
|
&pipeline_layout,
|
|
|
|
vertex_shader.clone(),
|
|
|
|
fragment_shader.clone(),
|
2023-01-21 22:34:01 +00:00
|
|
|
VK_SAMPLE_COUNT_1_BIT,
|
2023-01-21 21:09:07 +00:00
|
|
|
0,
|
2023-01-21 13:14:43 +00:00
|
|
|
)?,
|
|
|
|
})
|
2023-01-16 09:53:52 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-01-27 12:46:54 +00:00
|
|
|
fn init_gui_pipeline<T: VertexInputDescription>(
|
2023-01-16 09:53:52 +00:00
|
|
|
device: &Arc<Device>,
|
|
|
|
render_pass: &Arc<RenderPass>,
|
|
|
|
pipeline_layout: &Arc<PipelineLayout>,
|
2024-03-24 20:40:35 +00:00
|
|
|
vertex_shader: Arc<ShaderModule<shader_type::Vertex>>,
|
|
|
|
fragment_shader: Arc<ShaderModule<shader_type::Fragment>>,
|
2023-01-21 22:34:01 +00:00
|
|
|
sample_count: VkSampleCountFlags,
|
2023-01-21 21:09:07 +00:00
|
|
|
sub_pass: u32,
|
2023-01-16 09:53:52 +00:00
|
|
|
) -> Result<Arc<Pipeline>> {
|
|
|
|
Pipeline::new_graphics()
|
2023-01-27 12:46:54 +00:00
|
|
|
.set_vertex_shader::<T>(vertex_shader)
|
2023-01-16 09:53:52 +00:00
|
|
|
.set_fragment_shader(fragment_shader)
|
|
|
|
.input_assembly(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, false)
|
2023-01-21 22:34:01 +00:00
|
|
|
.default_multisample(sample_count)
|
2023-01-16 09:53:52 +00:00
|
|
|
.default_color_blend(vec![VkPipelineColorBlendAttachmentState::default()])
|
|
|
|
.default_rasterization(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE)
|
2023-01-21 21:09:07 +00:00
|
|
|
.build(device.clone(), pipeline_layout, render_pass, sub_pass)
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-03 19:01:17 +00:00
|
|
|
impl<'a> GuiHandler<'a> {
|
2023-01-16 11:58:59 +00:00
|
|
|
pub fn process(
|
2023-01-16 09:53:52 +00:00
|
|
|
&self,
|
|
|
|
buffer_recorder: &mut CommandBufferRecorder<'_>,
|
|
|
|
indices: &TargetMode<usize>,
|
|
|
|
) -> Result<()> {
|
2025-03-04 08:11:05 +00:00
|
|
|
if self.needs_update {
|
|
|
|
if !self.text_change_queue.is_empty() {
|
|
|
|
for text_change in self.text_change_queue.iter() {
|
2023-01-16 09:53:52 +00:00
|
|
|
(text_change)()?;
|
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.text_change_queue.clear();
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.needs_update = false;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
self.command_buffers
|
|
|
|
.chain(&self.render_targets)
|
|
|
|
.chain(&self.text_objects)
|
|
|
|
.unfold()
|
|
|
|
.chain(&self.rectangle_objects)
|
|
|
|
.unfold()
|
|
|
|
.chain(&self.single_color_objects)
|
|
|
|
.unfold()
|
|
|
|
.chain(indices)
|
|
|
|
.unfold()
|
|
|
|
.chain(&self.text_to_screen.pipeline)
|
|
|
|
.unfold()
|
|
|
|
.chain(&self.text_to_screen.descriptor)
|
|
|
|
.unfold()
|
|
|
|
.execute(
|
|
|
|
|(
|
2023-01-21 13:14:43 +00:00
|
|
|
command_buffers,
|
2023-01-22 15:02:46 +00:00
|
|
|
render_target,
|
2023-01-21 13:14:43 +00:00
|
|
|
text_objects,
|
2023-01-22 15:02:46 +00:00
|
|
|
rectangle_objects,
|
|
|
|
single_color_object,
|
2025-02-27 09:43:07 +00:00
|
|
|
index,
|
2023-01-22 15:02:46 +00:00
|
|
|
text_pipeline,
|
|
|
|
text_descriptor,
|
|
|
|
)| {
|
|
|
|
self.render(
|
|
|
|
buffer_recorder,
|
2025-02-27 09:43:07 +00:00
|
|
|
&command_buffers[****index],
|
2025-03-04 08:11:05 +00:00
|
|
|
render_target,
|
2023-01-22 15:02:46 +00:00
|
|
|
single_color_object,
|
|
|
|
rectangle_objects,
|
|
|
|
text_objects,
|
|
|
|
text_pipeline,
|
|
|
|
text_descriptor,
|
2025-02-27 09:43:07 +00:00
|
|
|
****index,
|
2023-01-22 15:02:46 +00:00
|
|
|
)
|
|
|
|
},
|
|
|
|
)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-08-27 09:24:44 +00:00
|
|
|
pub fn resize(
|
2025-03-04 08:11:05 +00:00
|
|
|
&mut self,
|
2024-08-27 09:24:44 +00:00
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
images: &TargetMode<Vec<Arc<Image>>>,
|
|
|
|
) -> Result<()> {
|
|
|
|
images
|
2023-01-22 15:02:46 +00:00
|
|
|
.chain(&self.render_targets)
|
2025-03-04 08:11:05 +00:00
|
|
|
.execute(|(images, old_render_target)| {
|
|
|
|
let new_render_target = Self::create_render_target(
|
2023-01-21 21:09:07 +00:00
|
|
|
&self.device,
|
|
|
|
&images,
|
2025-03-04 08:11:05 +00:00
|
|
|
Some(old_render_target),
|
2023-01-21 21:09:07 +00:00
|
|
|
&self.queue,
|
|
|
|
self.text_sample_count,
|
|
|
|
)?;
|
2023-01-21 16:03:54 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
**old_render_target = new_render_target;
|
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
Ok(())
|
|
|
|
})?;
|
2023-01-21 16:03:54 +00:00
|
|
|
|
2023-01-22 15:02:46 +00:00
|
|
|
self.text_to_screen.update_on_resize(&self.render_targets)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.needs_update = true;
|
|
|
|
self.ortho = ortho(0.0, width as f32, 0.0, height as f32, -1.0, 1.0);
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
self.width = width;
|
|
|
|
self.height = height;
|
2023-01-16 09:53:52 +00:00
|
|
|
|
2025-03-04 08:11:05 +00:00
|
|
|
for (_, elements) in self.layers.iter() {
|
2023-01-16 09:53:52 +00:00
|
|
|
for framable in elements.iter_framables() {
|
2025-03-04 08:11:05 +00:00
|
|
|
framable.resize(self)?;
|
2023-01-16 09:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2025-03-04 08:11:05 +00:00
|
|
|
|
|
|
|
impl<'a> From<&'a ecs::World> for &'a GuiHandler<'_> {
|
|
|
|
fn from(world: &'a ecs::World) -> Self {
|
|
|
|
world.resources.get::<GuiHandler<'_>>()
|
|
|
|
}
|
|
|
|
}
|