wgui: Separate user and wgui assets, topmost widgets (poc)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -6285,6 +6285,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"resvg",
|
"resvg",
|
||||||
"roxmltree 0.20.0",
|
"roxmltree 0.20.0",
|
||||||
|
"rust-embed",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::{cell::RefCell, collections::VecDeque, rc::Rc};
|
|||||||
use chrono::Timelike;
|
use chrono::Timelike;
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use wgui::{
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
components::button::ComponentButton,
|
components::button::ComponentButton,
|
||||||
event::{CallbackDataCommon, EventAlterables, EventListenerCollection},
|
event::{CallbackDataCommon, EventAlterables, EventListenerCollection},
|
||||||
globals::WguiGlobals,
|
globals::WguiGlobals,
|
||||||
@@ -56,7 +57,7 @@ impl Frontend {
|
|||||||
params.listeners,
|
params.listeners,
|
||||||
&ParseDocumentParams {
|
&ParseDocumentParams {
|
||||||
globals: globals.clone(),
|
globals: globals.clone(),
|
||||||
path: "gui/dashboard.xml",
|
path: AssetPath::BuiltIn("gui/dashboard.xml"),
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
},
|
},
|
||||||
&LayoutParams { resize_to_parent: true },
|
&LayoutParams { resize_to_parent: true },
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::{collections::HashMap, rc::Rc};
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use wgui::{
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
components::button::ComponentButton,
|
components::button::ComponentButton,
|
||||||
layout::WidgetPair,
|
layout::WidgetPair,
|
||||||
parser::{Fetchable, ParseDocumentParams, ParserData, ParserState},
|
parser::{Fetchable, ParseDocumentParams, ParserData, ParserState},
|
||||||
@@ -36,7 +37,7 @@ impl TabApps {
|
|||||||
pub fn new(mut tab_params: TabParams) -> anyhow::Result<Self> {
|
pub fn new(mut tab_params: TabParams) -> anyhow::Result<Self> {
|
||||||
let doc_params = &ParseDocumentParams {
|
let doc_params = &ParseDocumentParams {
|
||||||
globals: tab_params.globals.clone(),
|
globals: tab_params.globals.clone(),
|
||||||
path: "gui/tab/apps.xml",
|
path: AssetPath::BuiltIn("gui/tab/apps.xml"),
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use wgui::parser::{ParseDocumentParams, ParserState};
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
|
parser::{ParseDocumentParams, ParserState},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tab::{Tab, TabParams, TabType};
|
use crate::tab::{Tab, TabParams, TabType};
|
||||||
|
|
||||||
@@ -18,7 +21,7 @@ impl TabGames {
|
|||||||
let state = wgui::parser::parse_from_assets(
|
let state = wgui::parser::parse_from_assets(
|
||||||
&ParseDocumentParams {
|
&ParseDocumentParams {
|
||||||
globals: params.globals.clone(),
|
globals: params.globals.clone(),
|
||||||
path: "gui/tab/games.xml",
|
path: AssetPath::BuiltIn("gui/tab/games.xml"),
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
},
|
},
|
||||||
params.layout,
|
params.layout,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use wgui::{
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
components::button::ComponentButton,
|
components::button::ComponentButton,
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||||
@@ -38,7 +39,7 @@ impl TabHome {
|
|||||||
let state = wgui::parser::parse_from_assets(
|
let state = wgui::parser::parse_from_assets(
|
||||||
&ParseDocumentParams {
|
&ParseDocumentParams {
|
||||||
globals: params.globals.clone(),
|
globals: params.globals.clone(),
|
||||||
path: "gui/tab/home.xml",
|
path: AssetPath::BuiltIn("gui/tab/home.xml"),
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
},
|
},
|
||||||
params.layout,
|
params.layout,
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use wgui::parser::{ParseDocumentParams, ParserState};
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
|
parser::{ParseDocumentParams, ParserState},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tab::{Tab, TabParams, TabType};
|
use crate::tab::{Tab, TabParams, TabType};
|
||||||
|
|
||||||
@@ -18,7 +21,7 @@ impl TabMonado {
|
|||||||
let state = wgui::parser::parse_from_assets(
|
let state = wgui::parser::parse_from_assets(
|
||||||
&ParseDocumentParams {
|
&ParseDocumentParams {
|
||||||
globals: params.globals.clone(),
|
globals: params.globals.clone(),
|
||||||
path: "gui/tab/monado.xml",
|
path: AssetPath::BuiltIn("gui/tab/monado.xml"),
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
},
|
},
|
||||||
params.layout,
|
params.layout,
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use wgui::parser::{ParseDocumentParams, ParserState};
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
|
parser::{ParseDocumentParams, ParserState},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tab::{Tab, TabParams, TabType};
|
use crate::tab::{Tab, TabParams, TabType};
|
||||||
|
|
||||||
@@ -18,7 +21,7 @@ impl TabProcesses {
|
|||||||
let state = wgui::parser::parse_from_assets(
|
let state = wgui::parser::parse_from_assets(
|
||||||
&ParseDocumentParams {
|
&ParseDocumentParams {
|
||||||
globals: params.globals.clone(),
|
globals: params.globals.clone(),
|
||||||
path: "gui/tab/processes.xml",
|
path: AssetPath::BuiltIn("gui/tab/processes.xml"),
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
},
|
},
|
||||||
params.layout,
|
params.layout,
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use wgui::parser::{ParseDocumentParams, ParserState};
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
|
parser::{ParseDocumentParams, ParserState},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tab::{Tab, TabParams, TabType};
|
use crate::tab::{Tab, TabParams, TabType};
|
||||||
|
|
||||||
@@ -18,7 +21,7 @@ impl TabSettings {
|
|||||||
let state = wgui::parser::parse_from_assets(
|
let state = wgui::parser::parse_from_assets(
|
||||||
&ParseDocumentParams {
|
&ParseDocumentParams {
|
||||||
globals: params.globals.clone(),
|
globals: params.globals.clone(),
|
||||||
path: "gui/tab/settings.xml",
|
path: AssetPath::BuiltIn("gui/tab/settings.xml"),
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
},
|
},
|
||||||
params.layout,
|
params.layout,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use gio::prelude::{AppInfoExt, IconExt};
|
|||||||
use gtk::traits::IconThemeExt;
|
use gtk::traits::IconThemeExt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[allow(dead_code)] // TODO: remove this
|
||||||
pub struct DesktopEntry {
|
pub struct DesktopEntry {
|
||||||
pub exec_path: String,
|
pub exec_path: String,
|
||||||
pub exec_args: Vec<String>,
|
pub exec_args: Vec<String>,
|
||||||
@@ -10,6 +11,7 @@ pub struct DesktopEntry {
|
|||||||
pub categories: Vec<String>,
|
pub categories: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // TODO: remove this
|
||||||
pub struct EntrySearchCell {
|
pub struct EntrySearchCell {
|
||||||
pub exec_path: String,
|
pub exec_path: String,
|
||||||
pub exec_args: Vec<String>,
|
pub exec_args: Vec<String>,
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
<layout>
|
<layout>
|
||||||
<elements>
|
<elements>
|
||||||
<rectangle
|
<rectangle
|
||||||
color="#888888"
|
width="1000" height="1000" min_width="1000" min_height="500"
|
||||||
width="1000" height="500" min_width="1000" min_height="500"
|
|
||||||
gap="4" flex_direction="column"
|
gap="4" flex_direction="column"
|
||||||
|
color="#444444ee"
|
||||||
overflow_y="scroll">
|
overflow_y="scroll">
|
||||||
<label text="Raw text" color="#FFFFFF" />
|
<label text="Raw text" color="#FFFFFF" />
|
||||||
<label translation="TESTBED.HELLO_WORLD" color="#FFFFFF" />
|
<label translation="TESTBED.HELLO_WORLD" color="#FFFFFF" />
|
||||||
|
|
||||||
<div margin_left="16" gap="8" flex_direction="column">
|
<div margin_left="16" gap="8" flex_direction="column">
|
||||||
<label id="label_current_option" text="Click any of these buttons" size="20" weight="bold" />
|
<label id="label_current_option" text="Click any of these buttons" size="20" weight="bold" />
|
||||||
|
<Button id="button_popup" text="Show pop-up" width="200" height="32" color="#777777" />
|
||||||
<div gap="4">
|
<div gap="4">
|
||||||
<Button id="button_red" text="Red button" width="150" height="32" color="#FF0000" />
|
<Button id="button_red" text="Red button" width="150" height="32" color="#FF0000" />
|
||||||
<Button id="button_aqua" text="Aqua button" width="150" height="32" color="#00FFFF" />
|
<Button id="button_aqua" text="Aqua button" width="150" height="32" color="#00FFFF" />
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
log::trace!("drawing frame {frame_index}");
|
log::trace!("drawing frame {frame_index}");
|
||||||
frame_index += 1;
|
frame_index += 1;
|
||||||
|
|
||||||
limiter.start(120); // max 120 fps
|
limiter.start(0); // max 120 fps
|
||||||
profiler.start();
|
profiler.start();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use wgui::{
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
event::EventListenerCollection,
|
event::EventListenerCollection,
|
||||||
globals::WguiGlobals,
|
globals::WguiGlobals,
|
||||||
layout::{LayoutParams, RcLayout},
|
layout::{LayoutParams, RcLayout},
|
||||||
@@ -19,7 +20,7 @@ pub struct TestbedAny {
|
|||||||
|
|
||||||
impl TestbedAny {
|
impl TestbedAny {
|
||||||
pub fn new(name: &str, listeners: &mut EventListenerCollection<(), ()>) -> anyhow::Result<Self> {
|
pub fn new(name: &str, listeners: &mut EventListenerCollection<(), ()>) -> anyhow::Result<Self> {
|
||||||
let path = format!("gui/{name}.xml");
|
let path = AssetPath::BuiltIn(&format!("gui/{name}.xml"));
|
||||||
|
|
||||||
let globals = WguiGlobals::new(
|
let globals = WguiGlobals::new(
|
||||||
Box::new(assets::Asset {}),
|
Box::new(assets::Asset {}),
|
||||||
@@ -30,7 +31,7 @@ impl TestbedAny {
|
|||||||
listeners,
|
listeners,
|
||||||
&ParseDocumentParams {
|
&ParseDocumentParams {
|
||||||
globals,
|
globals,
|
||||||
path: &path,
|
path,
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
},
|
},
|
||||||
&LayoutParams::default(),
|
&LayoutParams::default(),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::rc::Rc;
|
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assets,
|
assets,
|
||||||
@@ -6,25 +6,37 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use wgui::{
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
components::{
|
components::{
|
||||||
|
Component,
|
||||||
button::{ButtonClickCallback, ComponentButton},
|
button::{ButtonClickCallback, ComponentButton},
|
||||||
checkbox::ComponentCheckbox,
|
checkbox::ComponentCheckbox,
|
||||||
Component,
|
|
||||||
},
|
},
|
||||||
drawing::Color,
|
drawing::Color,
|
||||||
event::EventListenerCollection,
|
event::EventListenerCollection,
|
||||||
globals::WguiGlobals,
|
globals::WguiGlobals,
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::{LayoutParams, RcLayout, Widget},
|
layout::{Layout, LayoutParams, RcLayout, Widget},
|
||||||
parser::{Fetchable, ParseDocumentExtra, ParseDocumentParams, ParserState},
|
parser::{Fetchable, ParseDocumentExtra, ParseDocumentParams, ParserState},
|
||||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle},
|
taffy::{self, prelude::length},
|
||||||
|
widget::{div::WidgetDiv, label::WidgetLabel, rectangle::WidgetRectangle},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub enum TestbedTask {
|
||||||
|
ShowPopup,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Data {
|
||||||
|
tasks: VecDeque<TestbedTask>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
state: ParserState,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct TestbedGeneric {
|
pub struct TestbedGeneric {
|
||||||
pub layout: RcLayout,
|
pub layout: RcLayout,
|
||||||
|
|
||||||
#[allow(dead_code)]
|
data: Rc<RefCell<Data>>,
|
||||||
state: ParserState,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button_click_callback(
|
fn button_click_callback(
|
||||||
@@ -57,7 +69,7 @@ fn handle_button_click(button: Rc<ComponentButton>, label: Widget, text: &'stati
|
|||||||
|
|
||||||
impl TestbedGeneric {
|
impl TestbedGeneric {
|
||||||
pub fn new(listeners: &mut EventListenerCollection<(), ()>) -> anyhow::Result<Self> {
|
pub fn new(listeners: &mut EventListenerCollection<(), ()>) -> anyhow::Result<Self> {
|
||||||
const XML_PATH: &str = "gui/various_widgets.xml";
|
const XML_PATH: AssetPath = AssetPath::BuiltIn("gui/various_widgets.xml");
|
||||||
|
|
||||||
let globals = WguiGlobals::new(
|
let globals = WguiGlobals::new(
|
||||||
Box::new(assets::Asset {}),
|
Box::new(assets::Asset {}),
|
||||||
@@ -112,6 +124,7 @@ impl TestbedGeneric {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
let button_popup = state.fetch_component_as::<ComponentButton>("button_popup")?;
|
||||||
let button_red = state.fetch_component_as::<ComponentButton>("button_red")?;
|
let button_red = state.fetch_component_as::<ComponentButton>("button_red")?;
|
||||||
let button_aqua = state.fetch_component_as::<ComponentButton>("button_aqua")?;
|
let button_aqua = state.fetch_component_as::<ComponentButton>("button_aqua")?;
|
||||||
let button_yellow = state.fetch_component_as::<ComponentButton>("button_yellow")?;
|
let button_yellow = state.fetch_component_as::<ComponentButton>("button_yellow")?;
|
||||||
@@ -133,19 +146,102 @@ impl TestbedGeneric {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Ok(Self {
|
let testbed = Self {
|
||||||
layout: layout.as_rc(),
|
layout: layout.as_rc(),
|
||||||
state,
|
data: Rc::new(RefCell::new(Data {
|
||||||
})
|
state,
|
||||||
|
tasks: Default::default(),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
button_popup.on_click({
|
||||||
|
let testbed = testbed.clone();
|
||||||
|
Box::new(move |_, _| {
|
||||||
|
testbed.push_task(TestbedTask::ShowPopup);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(testbed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_task(&self, task: TestbedTask) {
|
||||||
|
self.data.borrow_mut().tasks.push_back(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_task(
|
||||||
|
&mut self,
|
||||||
|
task: &TestbedTask,
|
||||||
|
params: &mut TestbedUpdateParams,
|
||||||
|
layout: &mut Layout,
|
||||||
|
data: &mut Data,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
match task {
|
||||||
|
TestbedTask::ShowPopup => self.show_popup(params, layout, data)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_popup(
|
||||||
|
&mut self,
|
||||||
|
params: &mut TestbedUpdateParams,
|
||||||
|
layout: &mut Layout,
|
||||||
|
_data: &mut Data,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
const XML_PATH: AssetPath = AssetPath::WguiInternal("wgui/window_frame.xml");
|
||||||
|
|
||||||
|
let globals = WguiGlobals::new(
|
||||||
|
Box::new(assets::Asset {}),
|
||||||
|
wgui::globals::Defaults::default(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let (widget, _) = layout.add_topmost_child(
|
||||||
|
WidgetDiv::create(),
|
||||||
|
taffy::Style {
|
||||||
|
position: taffy::Position::Absolute,
|
||||||
|
margin: taffy::Rect {
|
||||||
|
left: length(64.0),
|
||||||
|
right: length(0.0),
|
||||||
|
top: length(64.0),
|
||||||
|
bottom: length(0.0),
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let _state = wgui::parser::parse_from_assets(
|
||||||
|
&ParseDocumentParams {
|
||||||
|
globals,
|
||||||
|
path: XML_PATH,
|
||||||
|
extra: Default::default(),
|
||||||
|
},
|
||||||
|
layout,
|
||||||
|
params.listeners,
|
||||||
|
widget.id,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Testbed for TestbedGeneric {
|
impl Testbed for TestbedGeneric {
|
||||||
fn update(&mut self, params: TestbedUpdateParams) -> anyhow::Result<()> {
|
fn update(&mut self, mut params: TestbedUpdateParams) -> anyhow::Result<()> {
|
||||||
self.layout.borrow_mut().update(
|
let layout = self.layout.clone();
|
||||||
|
let data = self.data.clone();
|
||||||
|
|
||||||
|
let mut layout = layout.borrow_mut();
|
||||||
|
let mut data = data.borrow_mut();
|
||||||
|
|
||||||
|
layout.update(
|
||||||
Vec2::new(params.width, params.height),
|
Vec2::new(params.width, params.height),
|
||||||
params.timestep_alpha,
|
params.timestep_alpha,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
while let Some(task) = data.tasks.pop_front() {
|
||||||
|
self.process_task(&task, &mut params, &mut layout, &mut data)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,3 +29,4 @@ smallvec = "1.15.1"
|
|||||||
taffy = "0.9.1"
|
taffy = "0.9.1"
|
||||||
vulkano = { workspace = true }
|
vulkano = { workspace = true }
|
||||||
vulkano-shaders = { workspace = true }
|
vulkano-shaders = { workspace = true }
|
||||||
|
rust-embed = { workspace = true }
|
||||||
|
|||||||
3
wgui/assets/wgui/close.svg
Normal file
3
wgui/assets/wgui/close.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
|
||||||
|
<path fill="white" d="M8.4 17L7 15.6l3.6-3.6L7 8.425l1.4-1.4l3.6 3.6l3.575-3.6l1.4 1.4l-3.6 3.575l3.6 3.6l-1.4 1.4L12 13.4z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 220 B |
25
wgui/assets/wgui/window_frame.xml
Normal file
25
wgui/assets/wgui/window_frame.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<layout>
|
||||||
|
<elements>
|
||||||
|
<rectangle
|
||||||
|
flex_direction="column"
|
||||||
|
round="8"
|
||||||
|
border="2"
|
||||||
|
border_color="#778899"
|
||||||
|
color="#001122ee"
|
||||||
|
padding="2">
|
||||||
|
|
||||||
|
<!-- window title -->
|
||||||
|
<rectangle width="100%" height="100%" round="4" align_items="center" justify_content="space_between"
|
||||||
|
gradient="vertical" color="#224466" color2="#113355">
|
||||||
|
<label margin_left="8" text="Window title" weight="bold" />
|
||||||
|
<sprite src_internal="wgui/close.svg" width="24" height="24" />
|
||||||
|
</rectangle>
|
||||||
|
|
||||||
|
<!-- content itself -->
|
||||||
|
<div width="100%" height="100%" padding="8" gap="4" flex_direction="column">
|
||||||
|
<label text="Window content" />
|
||||||
|
<Button color="#9911AA" text="I'm clickable." width="128" height="24" />
|
||||||
|
</div>
|
||||||
|
</rectangle>
|
||||||
|
</elements>
|
||||||
|
</layout>
|
||||||
@@ -152,7 +152,11 @@ _Internal (assets) image path_
|
|||||||
|
|
||||||
`src_ext`: **string**
|
`src_ext`: **string**
|
||||||
|
|
||||||
_External image path_
|
_External (filesystem) image path_
|
||||||
|
|
||||||
|
`src_internal`: **string**
|
||||||
|
|
||||||
|
_wgui internal image path. Do not use directly unless it's related to the core wgui assets._
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,77 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum AssetPath<'a> {
|
||||||
|
WguiInternal(&'a str), // tied to internal wgui AssetProvider. Used internally
|
||||||
|
BuiltIn(&'a str), // tied to user AssetProvider
|
||||||
|
Filesystem(&'a str), // tied to filesystem path
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum AssetPathOwned {
|
||||||
|
WguiInternal(PathBuf),
|
||||||
|
BuiltIn(PathBuf),
|
||||||
|
Filesystem(PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssetPath<'_> {
|
||||||
|
pub const fn get_str(&self) -> &str {
|
||||||
|
match &self {
|
||||||
|
AssetPath::WguiInternal(path) => path,
|
||||||
|
AssetPath::BuiltIn(path) => path,
|
||||||
|
AssetPath::Filesystem(path) => path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_owned(&self) -> AssetPathOwned {
|
||||||
|
match self {
|
||||||
|
AssetPath::WguiInternal(path) => AssetPathOwned::WguiInternal(PathBuf::from(path)),
|
||||||
|
AssetPath::BuiltIn(path) => AssetPathOwned::BuiltIn(PathBuf::from(path)),
|
||||||
|
AssetPath::Filesystem(path) => AssetPathOwned::Filesystem(PathBuf::from(path)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssetPathOwned {
|
||||||
|
pub fn as_ref(&'_ self) -> AssetPath<'_> {
|
||||||
|
match self {
|
||||||
|
AssetPathOwned::WguiInternal(buf) => AssetPath::WguiInternal(buf.to_str().unwrap()),
|
||||||
|
AssetPathOwned::BuiltIn(buf) => AssetPath::BuiltIn(buf.to_str().unwrap()),
|
||||||
|
AssetPathOwned::Filesystem(buf) => AssetPath::Filesystem(buf.to_str().unwrap()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn get_path_buf(&self) -> &PathBuf {
|
||||||
|
match self {
|
||||||
|
AssetPathOwned::WguiInternal(buf) => buf,
|
||||||
|
AssetPathOwned::BuiltIn(buf) => buf,
|
||||||
|
AssetPathOwned::Filesystem(buf) => buf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssetPathOwned {
|
||||||
|
#[must_use]
|
||||||
|
pub fn push_include(&self, include: &str) -> AssetPathOwned {
|
||||||
|
let buf = self.get_path_buf();
|
||||||
|
let mut new_path = buf.parent().unwrap_or_else(|| Path::new("/")).to_path_buf();
|
||||||
|
new_path.push(include);
|
||||||
|
let new_path = normalize_path(&new_path);
|
||||||
|
|
||||||
|
match self {
|
||||||
|
AssetPathOwned::WguiInternal(_) => AssetPathOwned::WguiInternal(new_path),
|
||||||
|
AssetPathOwned::BuiltIn(_) => AssetPathOwned::BuiltIn(new_path),
|
||||||
|
AssetPathOwned::Filesystem(_) => AssetPathOwned::Filesystem(new_path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AssetPathOwned {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::WguiInternal(PathBuf::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait AssetProvider {
|
pub trait AssetProvider {
|
||||||
fn load_from_path(&mut self, path: &str) -> anyhow::Result<Vec<u8>>;
|
fn load_from_path(&mut self, path: &str) -> anyhow::Result<Vec<u8>>;
|
||||||
}
|
}
|
||||||
|
|||||||
12
wgui/src/assets_internal.rs
Normal file
12
wgui/src/assets_internal.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#[derive(rust_embed::Embed)]
|
||||||
|
#[folder = "assets/"]
|
||||||
|
pub struct AssetInternal;
|
||||||
|
|
||||||
|
impl crate::assets::AssetProvider for AssetInternal {
|
||||||
|
fn load_from_path(&mut self, path: &str) -> anyhow::Result<Vec<u8>> {
|
||||||
|
match AssetInternal::get(path) {
|
||||||
|
Some(data) => Ok(data.data.to_vec()),
|
||||||
|
None => anyhow::bail!("internal file {path} not found"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -146,6 +146,7 @@ pub struct PrimitiveExtent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum RenderPrimitive {
|
pub enum RenderPrimitive {
|
||||||
|
NewPass,
|
||||||
Rectangle(PrimitiveExtent, Rectangle),
|
Rectangle(PrimitiveExtent, Rectangle),
|
||||||
Text(PrimitiveExtent, Rc<RefCell<Buffer>>, Option<TextShadow>),
|
Text(PrimitiveExtent, Rc<RefCell<Buffer>>, Option<TextShadow>),
|
||||||
Sprite(PrimitiveExtent, Option<CustomGlyph>), //option because we want as_slice
|
Sprite(PrimitiveExtent, Option<CustomGlyph>), //option because we want as_slice
|
||||||
@@ -276,7 +277,7 @@ fn draw_widget(
|
|||||||
|
|
||||||
widget_state.draw_all(state, &draw_params);
|
widget_state.draw_all(state, &draw_params);
|
||||||
|
|
||||||
draw_children(params, state, node_id);
|
draw_children(params, state, node_id, false);
|
||||||
|
|
||||||
if scissor_pushed {
|
if scissor_pushed {
|
||||||
state.scissor_stack.pop();
|
state.scissor_stack.pop();
|
||||||
@@ -296,7 +297,7 @@ fn draw_widget(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_children(params: &DrawParams, state: &mut DrawState, parent_node_id: taffy::NodeId) {
|
fn draw_children(params: &DrawParams, state: &mut DrawState, parent_node_id: taffy::NodeId, is_topmost: bool) {
|
||||||
let layout = ¶ms.layout;
|
let layout = ¶ms.layout;
|
||||||
|
|
||||||
for node_id in layout.state.tree.child_ids(parent_node_id) {
|
for node_id in layout.state.tree.child_ids(parent_node_id) {
|
||||||
@@ -316,6 +317,10 @@ fn draw_children(params: &DrawParams, state: &mut DrawState, parent_node_id: taf
|
|||||||
};
|
};
|
||||||
|
|
||||||
draw_widget(params, state, node_id, style, widget);
|
draw_widget(params, state, node_id, style, widget);
|
||||||
|
|
||||||
|
if is_topmost {
|
||||||
|
state.primitives.push(RenderPrimitive::NewPass);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,14 +329,6 @@ pub fn draw(params: &mut DrawParams) -> anyhow::Result<Vec<RenderPrimitive>> {
|
|||||||
let mut transform_stack = TransformStack::new();
|
let mut transform_stack = TransformStack::new();
|
||||||
let mut scissor_stack = ScissorStack::new();
|
let mut scissor_stack = ScissorStack::new();
|
||||||
|
|
||||||
let Some(root_widget) = params.layout.state.widgets.get(params.layout.root_widget) else {
|
|
||||||
panic!();
|
|
||||||
};
|
|
||||||
|
|
||||||
let Ok(style) = params.layout.state.tree.style(params.layout.root_node) else {
|
|
||||||
panic!();
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut alterables = EventAlterables::default();
|
let mut alterables = EventAlterables::default();
|
||||||
|
|
||||||
let mut state = DrawState {
|
let mut state = DrawState {
|
||||||
@@ -342,7 +339,8 @@ pub fn draw(params: &mut DrawParams) -> anyhow::Result<Vec<RenderPrimitive>> {
|
|||||||
alterables: &mut alterables,
|
alterables: &mut alterables,
|
||||||
};
|
};
|
||||||
|
|
||||||
draw_widget(params, &mut state, params.layout.root_node, style, root_widget);
|
draw_children(params, &mut state, params.layout.tree_root_node, true);
|
||||||
|
|
||||||
params.layout.process_alterables(alterables)?;
|
params.layout.process_alterables(alterables)?;
|
||||||
|
|
||||||
Ok(primitives)
|
Ok(primitives)
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use std::{marker::PhantomData, ops::Range, sync::Arc};
|
use std::{marker::PhantomData, ops::Range, sync::Arc};
|
||||||
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{
|
buffer::{
|
||||||
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
|
|
||||||
BufferContents, BufferUsage, Subbuffer,
|
BufferContents, BufferUsage, Subbuffer,
|
||||||
|
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
|
||||||
},
|
},
|
||||||
descriptor_set::{
|
descriptor_set::{
|
||||||
layout::{DescriptorBindingFlags, DescriptorSetLayoutCreateFlags},
|
|
||||||
DescriptorSet, WriteDescriptorSet,
|
DescriptorSet, WriteDescriptorSet,
|
||||||
|
layout::{DescriptorBindingFlags, DescriptorSetLayoutCreateFlags},
|
||||||
},
|
},
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{
|
image::{
|
||||||
@@ -17,8 +17,9 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
memory::allocator::MemoryTypeFilter,
|
memory::allocator::MemoryTypeFilter,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
|
DynamicState, GraphicsPipeline, Pipeline, PipelineLayout,
|
||||||
graphics::{
|
graphics::{
|
||||||
self,
|
self, GraphicsPipelineCreateInfo,
|
||||||
color_blend::{AttachmentBlend, ColorBlendAttachmentState, ColorBlendState},
|
color_blend::{AttachmentBlend, ColorBlendAttachmentState, ColorBlendState},
|
||||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||||
multisample::MultisampleState,
|
multisample::MultisampleState,
|
||||||
@@ -26,15 +27,13 @@ use vulkano::{
|
|||||||
subpass::PipelineRenderingCreateInfo,
|
subpass::PipelineRenderingCreateInfo,
|
||||||
vertex_input::{Vertex, VertexDefinition, VertexInputState},
|
vertex_input::{Vertex, VertexDefinition, VertexInputState},
|
||||||
viewport::ViewportState,
|
viewport::ViewportState,
|
||||||
GraphicsPipelineCreateInfo,
|
|
||||||
},
|
},
|
||||||
layout::PipelineDescriptorSetLayoutCreateInfo,
|
layout::PipelineDescriptorSetLayoutCreateInfo,
|
||||||
DynamicState, GraphicsPipeline, Pipeline, PipelineLayout,
|
|
||||||
},
|
},
|
||||||
shader::{EntryPoint, ShaderModule},
|
shader::{EntryPoint, ShaderModule},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{pass::WGfxPass, WGfx};
|
use super::{WGfx, pass::WGfxPass};
|
||||||
|
|
||||||
pub struct WGfxPipeline<V> {
|
pub struct WGfxPipeline<V> {
|
||||||
pub graphics: Arc<WGfx>,
|
pub graphics: Arc<WGfx>,
|
||||||
@@ -47,6 +46,7 @@ impl<V> WGfxPipeline<V>
|
|||||||
where
|
where
|
||||||
V: Sized,
|
V: Sized,
|
||||||
{
|
{
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn new_from_stages(
|
fn new_from_stages(
|
||||||
graphics: Arc<WGfx>,
|
graphics: Arc<WGfx>,
|
||||||
format: Format,
|
format: Format,
|
||||||
@@ -207,21 +207,25 @@ impl WPipelineCreateInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_blend(mut self, blend: AttachmentBlend) -> Self {
|
#[must_use]
|
||||||
|
pub const fn use_blend(mut self, blend: AttachmentBlend) -> Self {
|
||||||
self.blend = Some(blend);
|
self.blend = Some(blend);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_topology(mut self, topology: PrimitiveTopology) -> Self {
|
#[must_use]
|
||||||
|
pub const fn use_topology(mut self, topology: PrimitiveTopology) -> Self {
|
||||||
self.topology = topology;
|
self.topology = topology;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_instanced(mut self) -> Self {
|
#[must_use]
|
||||||
|
pub const fn use_instanced(mut self) -> Self {
|
||||||
self.instanced = true;
|
self.instanced = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn use_updatable_descriptors(mut self, updatable_sets: SmallVec<[usize; 8]>) -> Self {
|
pub fn use_updatable_descriptors(mut self, updatable_sets: SmallVec<[usize; 8]>) -> Self {
|
||||||
self.updatable_sets = updatable_sets;
|
self.updatable_sets = updatable_sets;
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cell::{RefCell, RefMut},
|
cell::{RefCell, RefMut},
|
||||||
|
io::Read,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{assets::AssetProvider, drawing, i18n::I18n};
|
use crate::{
|
||||||
|
assets::{AssetPath, AssetProvider},
|
||||||
|
assets_internal, drawing,
|
||||||
|
i18n::I18n,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Defaults {
|
pub struct Defaults {
|
||||||
pub dark_mode: bool,
|
pub dark_mode: bool,
|
||||||
@@ -22,8 +27,9 @@ impl Default for Defaults {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Globals {
|
pub struct Globals {
|
||||||
pub assets: Box<dyn AssetProvider>,
|
pub assets_internal: Box<dyn AssetProvider>,
|
||||||
pub i18n: I18n,
|
pub assets_builtin: Box<dyn AssetProvider>,
|
||||||
|
pub i18n_builtin: I18n,
|
||||||
pub defaults: Defaults,
|
pub defaults: Defaults,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,10 +37,33 @@ pub struct Globals {
|
|||||||
pub struct WguiGlobals(Rc<RefCell<Globals>>);
|
pub struct WguiGlobals(Rc<RefCell<Globals>>);
|
||||||
|
|
||||||
impl WguiGlobals {
|
impl WguiGlobals {
|
||||||
pub fn new(mut assets: Box<dyn AssetProvider>, defaults: Defaults) -> anyhow::Result<Self> {
|
pub fn new(mut assets_builtin: Box<dyn AssetProvider>, defaults: Defaults) -> anyhow::Result<Self> {
|
||||||
let i18n = I18n::new(&mut assets)?;
|
let i18n_builtin = I18n::new(&mut assets_builtin)?;
|
||||||
|
let assets_internal = Box::new(assets_internal::AssetInternal {});
|
||||||
|
|
||||||
Ok(Self(Rc::new(RefCell::new(Globals { assets, i18n, defaults }))))
|
Ok(Self(Rc::new(RefCell::new(Globals {
|
||||||
|
assets_internal,
|
||||||
|
assets_builtin,
|
||||||
|
i18n_builtin,
|
||||||
|
defaults,
|
||||||
|
}))))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_asset(&self, asset_path: AssetPath) -> anyhow::Result<Vec<u8>> {
|
||||||
|
match asset_path {
|
||||||
|
AssetPath::WguiInternal(path) => self.assets_internal().load_from_path(path),
|
||||||
|
AssetPath::BuiltIn(path) => self.assets_builtin().load_from_path(path),
|
||||||
|
AssetPath::Filesystem(path) => {
|
||||||
|
let mut file = std::fs::File::open(path)?;
|
||||||
|
/* 16 MiB safeguard */
|
||||||
|
if file.metadata()?.len() > 16 * 1024 * 1024 {
|
||||||
|
anyhow::bail!("Too large file size");
|
||||||
|
}
|
||||||
|
let mut data = Vec::new();
|
||||||
|
file.read_to_end(&mut data)?;
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> RefMut<'_, Globals> {
|
pub fn get(&self) -> RefMut<'_, Globals> {
|
||||||
@@ -42,10 +71,14 @@ impl WguiGlobals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn i18n(&self) -> RefMut<'_, I18n> {
|
pub fn i18n(&self) -> RefMut<'_, I18n> {
|
||||||
RefMut::map(self.0.borrow_mut(), |x| &mut x.i18n)
|
RefMut::map(self.0.borrow_mut(), |x| &mut x.i18n_builtin)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assets(&self) -> RefMut<'_, Box<dyn AssetProvider>> {
|
pub fn assets_internal(&self) -> RefMut<'_, Box<dyn AssetProvider>> {
|
||||||
RefMut::map(self.0.borrow_mut(), |x| &mut x.assets)
|
RefMut::map(self.0.borrow_mut(), |x| &mut x.assets_internal)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assets_builtin(&self) -> RefMut<'_, Box<dyn AssetProvider>> {
|
||||||
|
RefMut::map(self.0.borrow_mut(), |x| &mut x.assets_builtin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ use std::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
animation::Animations,
|
animation::Animations,
|
||||||
components::{Component, InitData},
|
components::{Component, InitData},
|
||||||
drawing::{push_scissor_stack, push_transform_stack, Boundary},
|
drawing::{Boundary, push_scissor_stack, push_transform_stack},
|
||||||
event::{self, CallbackDataCommon, EventAlterables, EventListenerCollection},
|
event::{self, CallbackDataCommon, EventAlterables, EventListenerCollection},
|
||||||
globals::WguiGlobals,
|
globals::WguiGlobals,
|
||||||
widget::{self, div::WidgetDiv, EventParams, WidgetObj, WidgetState},
|
widget::{self, EventParams, WidgetObj, WidgetState, div::WidgetDiv},
|
||||||
};
|
};
|
||||||
|
|
||||||
use glam::{vec2, Vec2};
|
use glam::{Vec2, vec2};
|
||||||
use slotmap::{new_key_type, HopSlotMap, SecondaryMap};
|
use slotmap::{HopSlotMap, SecondaryMap, new_key_type};
|
||||||
use taffy::{NodeId, TaffyTree, TraversePartialTree};
|
use taffy::{NodeId, TaffyTree, TraversePartialTree};
|
||||||
|
|
||||||
new_key_type! {
|
new_key_type! {
|
||||||
@@ -113,8 +113,15 @@ pub struct Layout {
|
|||||||
pub components_to_init: Vec<Component>,
|
pub components_to_init: Vec<Component>,
|
||||||
pub widgets_to_tick: Vec<WidgetID>,
|
pub widgets_to_tick: Vec<WidgetID>,
|
||||||
|
|
||||||
pub root_widget: WidgetID,
|
// *Main root*
|
||||||
pub root_node: taffy::NodeId,
|
// contains content_root_widget and topmost widgets
|
||||||
|
pub tree_root_widget: WidgetID,
|
||||||
|
pub tree_root_node: taffy::NodeId,
|
||||||
|
|
||||||
|
// *Main topmost widget*
|
||||||
|
// main topmost widget, always present, parent of `tree_root_widget`
|
||||||
|
pub content_root_widget: WidgetID,
|
||||||
|
pub content_root_node: taffy::NodeId,
|
||||||
|
|
||||||
pub prev_size: Vec2,
|
pub prev_size: Vec2,
|
||||||
pub content_size: Vec2,
|
pub content_size: Vec2,
|
||||||
@@ -165,6 +172,22 @@ impl Layout {
|
|||||||
Rc::new(RefCell::new(self))
|
Rc::new(RefCell::new(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_topmost_child(
|
||||||
|
&mut self,
|
||||||
|
widget: WidgetState,
|
||||||
|
style: taffy::Style,
|
||||||
|
) -> anyhow::Result<(WidgetPair, taffy::NodeId)> {
|
||||||
|
self.mark_redraw();
|
||||||
|
add_child_internal(
|
||||||
|
&mut self.state.tree,
|
||||||
|
&mut self.state.widgets,
|
||||||
|
&mut self.state.nodes,
|
||||||
|
Some(self.tree_root_node),
|
||||||
|
widget,
|
||||||
|
style,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_child(
|
pub fn add_child(
|
||||||
&mut self,
|
&mut self,
|
||||||
parent_widget_id: WidgetID,
|
parent_widget_id: WidgetID,
|
||||||
@@ -217,7 +240,7 @@ impl Layout {
|
|||||||
self.needs_redraw = true;
|
self.needs_redraw = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_pending_components(&mut self, alterables: &mut EventAlterables) -> anyhow::Result<()> {
|
fn process_pending_components(&mut self, alterables: &mut EventAlterables) {
|
||||||
for comp in &self.components_to_init {
|
for comp in &self.components_to_init {
|
||||||
let mut common = CallbackDataCommon {
|
let mut common = CallbackDataCommon {
|
||||||
state: &self.state,
|
state: &self.state,
|
||||||
@@ -227,7 +250,6 @@ impl Layout {
|
|||||||
comp.0.init(&mut InitData { common: &mut common });
|
comp.0.init(&mut InitData { common: &mut common });
|
||||||
}
|
}
|
||||||
self.components_to_init.clear();
|
self.components_to_init.clear();
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_pending_widget_ticks(&mut self, alterables: &mut EventAlterables) {
|
fn process_pending_widget_ticks(&mut self, alterables: &mut EventAlterables) {
|
||||||
@@ -358,9 +380,7 @@ impl Layout {
|
|||||||
mut user_data: (&mut U1, &mut U2),
|
mut user_data: (&mut U1, &mut U2),
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut alterables = EventAlterables::default();
|
let mut alterables = EventAlterables::default();
|
||||||
|
self.push_event_widget(listeners, self.tree_root_node, event, &mut alterables, &mut user_data)?;
|
||||||
self.push_event_widget(listeners, self.root_node, event, &mut alterables, &mut user_data)?;
|
|
||||||
|
|
||||||
self.process_alterables(alterables)?;
|
self.process_alterables(alterables)?;
|
||||||
|
|
||||||
listeners.gc();
|
listeners.gc();
|
||||||
@@ -376,7 +396,7 @@ impl Layout {
|
|||||||
globals,
|
globals,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (root_widget, root_node) = add_child_internal(
|
let (tree_root_widget, tree_root_node) = add_child_internal(
|
||||||
&mut state.tree,
|
&mut state.tree,
|
||||||
&mut state.widgets,
|
&mut state.widgets,
|
||||||
&mut state.nodes,
|
&mut state.nodes,
|
||||||
@@ -392,12 +412,23 @@ impl Layout {
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let (content_root_widget, content_root_node) = add_child_internal(
|
||||||
|
&mut state.tree,
|
||||||
|
&mut state.widgets,
|
||||||
|
&mut state.nodes,
|
||||||
|
Some(tree_root_node),
|
||||||
|
WidgetDiv::create(),
|
||||||
|
taffy::Style::default(),
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
state,
|
state,
|
||||||
prev_size: Vec2::default(),
|
prev_size: Vec2::default(),
|
||||||
content_size: Vec2::default(),
|
content_size: Vec2::default(),
|
||||||
root_node,
|
tree_root_node,
|
||||||
root_widget: root_widget.id,
|
tree_root_widget: tree_root_widget.id,
|
||||||
|
content_root_node,
|
||||||
|
content_root_widget: content_root_widget.id,
|
||||||
needs_redraw: true,
|
needs_redraw: true,
|
||||||
haptics_triggered: false,
|
haptics_triggered: false,
|
||||||
animations: Animations::default(),
|
animations: Animations::default(),
|
||||||
@@ -407,7 +438,7 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_recompute_layout(&mut self, size: Vec2) -> anyhow::Result<()> {
|
fn try_recompute_layout(&mut self, size: Vec2) -> anyhow::Result<()> {
|
||||||
if !self.state.tree.dirty(self.root_node)? && self.prev_size == size {
|
if !self.state.tree.dirty(self.tree_root_node)? && self.prev_size == size {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -417,7 +448,7 @@ impl Layout {
|
|||||||
self.prev_size = size;
|
self.prev_size = size;
|
||||||
|
|
||||||
self.state.tree.compute_layout_with_measure(
|
self.state.tree.compute_layout_with_measure(
|
||||||
self.root_node,
|
self.tree_root_node,
|
||||||
taffy::Size {
|
taffy::Size {
|
||||||
width: taffy::AvailableSpace::Definite(size.x),
|
width: taffy::AvailableSpace::Definite(size.x),
|
||||||
height: taffy::AvailableSpace::Definite(size.y),
|
height: taffy::AvailableSpace::Definite(size.y),
|
||||||
@@ -443,7 +474,7 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
let root_size = self.state.tree.layout(self.root_node).unwrap().size;
|
let root_size = self.state.tree.layout(self.tree_root_node).unwrap().size;
|
||||||
if self.content_size.x != root_size.width || self.content_size.y != root_size.height {
|
if self.content_size.x != root_size.width || self.content_size.y != root_size.height {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"content size changed: {:.0}x{:.0} → {:.0}x{:.0}",
|
"content size changed: {:.0}x{:.0} → {:.0}x{:.0}",
|
||||||
@@ -470,7 +501,7 @@ impl Layout {
|
|||||||
pub fn tick(&mut self) -> anyhow::Result<()> {
|
pub fn tick(&mut self) -> anyhow::Result<()> {
|
||||||
let mut alterables = EventAlterables::default();
|
let mut alterables = EventAlterables::default();
|
||||||
self.animations.tick(&self.state, &mut alterables);
|
self.animations.tick(&self.state, &mut alterables);
|
||||||
self.process_pending_components(&mut alterables)?;
|
self.process_pending_components(&mut alterables);
|
||||||
self.process_pending_widget_ticks(&mut alterables);
|
self.process_pending_widget_ticks(&mut alterables);
|
||||||
self.process_alterables(alterables)?;
|
self.process_alterables(alterables)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
pub mod animation;
|
pub mod animation;
|
||||||
pub mod any;
|
pub mod any;
|
||||||
pub mod assets;
|
pub mod assets;
|
||||||
|
mod assets_internal;
|
||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod drawing;
|
pub mod drawing;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ mod widget_rectangle;
|
|||||||
mod widget_sprite;
|
mod widget_sprite;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::{self, AssetProvider},
|
assets::{AssetPath, AssetPathOwned, normalize_path},
|
||||||
components::{Component, ComponentWeak},
|
components::{Component, ComponentWeak},
|
||||||
drawing::{self},
|
drawing::{self},
|
||||||
event::EventListenerCollection,
|
event::EventListenerCollection,
|
||||||
@@ -22,12 +22,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use ouroboros::self_referencing;
|
use ouroboros::self_referencing;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{cell::RefMut, collections::HashMap, path::Path, rc::Rc};
|
||||||
cell::RefMut,
|
|
||||||
collections::HashMap,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[self_referencing]
|
#[self_referencing]
|
||||||
struct XmlDocument {
|
struct XmlDocument {
|
||||||
@@ -44,7 +39,7 @@ pub struct Template {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ParserFile {
|
struct ParserFile {
|
||||||
path: PathBuf,
|
path: AssetPathOwned,
|
||||||
document: Rc<XmlDocument>,
|
document: Rc<XmlDocument>,
|
||||||
template_parameters: HashMap<Rc<str>, Rc<str>>,
|
template_parameters: HashMap<Rc<str>, Rc<str>>,
|
||||||
}
|
}
|
||||||
@@ -201,7 +196,7 @@ impl Fetchable for ParserData {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ParserState {
|
pub struct ParserState {
|
||||||
pub data: ParserData,
|
pub data: ParserData,
|
||||||
pub path: PathBuf,
|
pub path: AssetPathOwned,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParserState {
|
impl ParserState {
|
||||||
@@ -558,11 +553,22 @@ fn parse_tag_include<U1, U2>(
|
|||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
match pair.attrib.as_ref() {
|
match pair.attrib.as_ref() {
|
||||||
"src" => {
|
"src" => {
|
||||||
let mut new_path = file.path.parent().unwrap_or_else(|| Path::new("/")).to_path_buf();
|
let new_path = {
|
||||||
new_path.push(pair.value.as_ref());
|
let this = &file.path.clone();
|
||||||
let new_path = assets::normalize_path(&new_path);
|
let include: &str = &pair.value;
|
||||||
|
let buf = this.get_path_buf();
|
||||||
|
let mut new_path = buf.parent().unwrap_or_else(|| Path::new("/")).to_path_buf();
|
||||||
|
new_path.push(include);
|
||||||
|
let new_path = normalize_path(&new_path);
|
||||||
|
|
||||||
let (new_file, node_layout) = get_doc_from_path(ctx, &new_path)?;
|
match this {
|
||||||
|
AssetPathOwned::WguiInternal(_) => AssetPathOwned::WguiInternal(new_path),
|
||||||
|
AssetPathOwned::BuiltIn(_) => AssetPathOwned::BuiltIn(new_path),
|
||||||
|
AssetPathOwned::Filesystem(_) => AssetPathOwned::Filesystem(new_path),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let new_path_ref = new_path.as_ref();
|
||||||
|
let (new_file, node_layout) = get_doc_from_asset_path(ctx, new_path_ref)?;
|
||||||
parse_document_root(&new_file, ctx, parent_id, node_layout)?;
|
parse_document_root(&new_file, ctx, parent_id, node_layout)?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -992,7 +998,7 @@ pub struct ParseDocumentExtra {
|
|||||||
// filled-in by you in `new_layout_from_assets` function
|
// filled-in by you in `new_layout_from_assets` function
|
||||||
pub struct ParseDocumentParams<'a> {
|
pub struct ParseDocumentParams<'a> {
|
||||||
pub globals: WguiGlobals, // mandatory field
|
pub globals: WguiGlobals, // mandatory field
|
||||||
pub path: &'a str, // mandatory field
|
pub path: AssetPath<'a>, // mandatory field
|
||||||
pub extra: ParseDocumentExtra, // optional field, can be Default-ed
|
pub extra: ParseDocumentExtra, // optional field, can be Default-ed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1002,18 +1008,15 @@ pub fn parse_from_assets<U1, U2>(
|
|||||||
listeners: &mut EventListenerCollection<U1, U2>,
|
listeners: &mut EventListenerCollection<U1, U2>,
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
) -> anyhow::Result<ParserState> {
|
) -> anyhow::Result<ParserState> {
|
||||||
let path = PathBuf::from(doc_params.path);
|
|
||||||
|
|
||||||
let parser_data = ParserData::default();
|
let parser_data = ParserData::default();
|
||||||
let mut ctx = create_default_context(doc_params, layout, listeners, &parser_data);
|
let mut ctx = create_default_context(doc_params, layout, listeners, &parser_data);
|
||||||
|
let (file, node_layout) = get_doc_from_asset_path(&ctx, doc_params.path)?;
|
||||||
let (file, node_layout) = get_doc_from_path(&ctx, &path)?;
|
|
||||||
parse_document_root(&file, &mut ctx, parent_id, node_layout)?;
|
parse_document_root(&file, &mut ctx, parent_id, node_layout)?;
|
||||||
|
|
||||||
// move everything essential to the result
|
// move everything essential to the result
|
||||||
let result = ParserState {
|
let result = ParserState {
|
||||||
data: std::mem::take(&mut ctx.data_local),
|
data: std::mem::take(&mut ctx.data_local),
|
||||||
path,
|
path: doc_params.path.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
drop(ctx);
|
drop(ctx);
|
||||||
@@ -1027,21 +1030,18 @@ pub fn new_layout_from_assets<U1, U2>(
|
|||||||
layout_params: &LayoutParams,
|
layout_params: &LayoutParams,
|
||||||
) -> anyhow::Result<(Layout, ParserState)> {
|
) -> anyhow::Result<(Layout, ParserState)> {
|
||||||
let mut layout = Layout::new(doc_params.globals.clone(), layout_params)?;
|
let mut layout = Layout::new(doc_params.globals.clone(), layout_params)?;
|
||||||
let widget = layout.root_widget;
|
let widget = layout.content_root_widget;
|
||||||
let state = parse_from_assets(doc_params, &mut layout, listeners, widget)?;
|
let state = parse_from_assets(doc_params, &mut layout, listeners, widget)?;
|
||||||
Ok((layout, state))
|
Ok((layout, state))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assets_path_to_xml(assets: &mut Box<dyn AssetProvider>, path: &Path) -> anyhow::Result<String> {
|
fn get_doc_from_asset_path<U1, U2>(
|
||||||
let data = assets.load_from_path(&path.to_string_lossy())?;
|
|
||||||
Ok(String::from_utf8(data)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_doc_from_path<U1, U2>(
|
|
||||||
ctx: &ParserContext<U1, U2>,
|
ctx: &ParserContext<U1, U2>,
|
||||||
path: &Path,
|
asset_path: AssetPath,
|
||||||
) -> anyhow::Result<(ParserFile, roxmltree::NodeId)> {
|
) -> anyhow::Result<(ParserFile, roxmltree::NodeId)> {
|
||||||
let xml = assets_path_to_xml(&mut ctx.layout.state.globals.assets(), path)?;
|
let data = ctx.layout.state.globals.get_asset(asset_path)?;
|
||||||
|
let xml = String::from_utf8(data)?;
|
||||||
|
|
||||||
let document = Rc::new(XmlDocument::new(xml, |xml| {
|
let document = Rc::new(XmlDocument::new(xml, |xml| {
|
||||||
let opt = roxmltree::ParsingOptions {
|
let opt = roxmltree::ParsingOptions {
|
||||||
allow_dtd: true,
|
allow_dtd: true,
|
||||||
@@ -1054,7 +1054,7 @@ fn get_doc_from_path<U1, U2>(
|
|||||||
let tag_layout = require_tag_by_name(&root, "layout")?;
|
let tag_layout = require_tag_by_name(&root, "layout")?;
|
||||||
|
|
||||||
let file = ParserFile {
|
let file = ParserFile {
|
||||||
path: PathBuf::from(path),
|
path: asset_path.to_owned(),
|
||||||
document: document.clone(),
|
document: document.clone(),
|
||||||
template_parameters: Default::default(),
|
template_parameters: Default::default(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
assets::AssetPath,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, style::parse_style},
|
parser::{AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, style::parse_style},
|
||||||
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
|
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
|
||||||
@@ -21,9 +22,16 @@ pub fn parse_widget_sprite<'a, U1, U2>(
|
|||||||
for pair in attribs {
|
for pair in attribs {
|
||||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
match key {
|
match key {
|
||||||
"src" => {
|
"src" | "src_ext" | "src_internal" => {
|
||||||
|
let asset_path = match key {
|
||||||
|
"src" => AssetPath::BuiltIn(value),
|
||||||
|
"src_ext" => AssetPath::Filesystem(value),
|
||||||
|
"src_internal" => AssetPath::WguiInternal(value),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
if !value.is_empty() {
|
if !value.is_empty() {
|
||||||
glyph = match CustomGlyphContent::from_assets(&mut ctx.layout.state.globals.assets(), value) {
|
glyph = match CustomGlyphContent::from_assets(&mut ctx.layout.state.globals, asset_path) {
|
||||||
Ok(glyph) => Some(glyph),
|
Ok(glyph) => Some(glyph),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("failed to load {value}: {e}");
|
log::warn!("failed to load {value}: {e}");
|
||||||
@@ -32,11 +40,6 @@ pub fn parse_widget_sprite<'a, U1, U2>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"src_ext" => {
|
|
||||||
if !value.is_empty() && std::fs::exists(value).unwrap_or(false) {
|
|
||||||
glyph = CustomGlyphContent::from_file(value).ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"color" => {
|
"color" => {
|
||||||
if let Some(color) = parse_color_hex(value) {
|
if let Some(color) = parse_color_hex(value) {
|
||||||
params.color = Some(color);
|
params.color = Some(color);
|
||||||
|
|||||||
@@ -243,6 +243,9 @@ impl Context {
|
|||||||
let pass = passes.last_mut().unwrap(); // always safe
|
let pass = passes.last_mut().unwrap(); // always safe
|
||||||
|
|
||||||
match &primitive {
|
match &primitive {
|
||||||
|
drawing::RenderPrimitive::NewPass => {
|
||||||
|
needs_new_pass = true;
|
||||||
|
}
|
||||||
drawing::RenderPrimitive::Rectangle(extent, rectangle) => {
|
drawing::RenderPrimitive::Rectangle(extent, rectangle) => {
|
||||||
pass
|
pass
|
||||||
.rect_renderer
|
.rect_renderer
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use cosmic_text::SubpixelBin;
|
|||||||
use image::RgbaImage;
|
use image::RgbaImage;
|
||||||
use resvg::usvg::{Options, Tree};
|
use resvg::usvg::{Options, Tree};
|
||||||
|
|
||||||
use crate::assets::AssetProvider;
|
use crate::{assets::AssetPath, globals::WguiGlobals};
|
||||||
|
|
||||||
static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
|
static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
@@ -32,19 +32,10 @@ impl CustomGlyphContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::case_sensitive_file_extension_comparisons)]
|
#[allow(clippy::case_sensitive_file_extension_comparisons)]
|
||||||
pub fn from_assets(provider: &mut Box<dyn AssetProvider>, path: &str) -> anyhow::Result<Self> {
|
pub fn from_assets(globals: &mut WguiGlobals, path: AssetPath) -> anyhow::Result<Self> {
|
||||||
let data = provider.load_from_path(path)?;
|
let path_str = path.get_str();
|
||||||
if path.ends_with(".svg") || path.ends_with(".svgz") {
|
let data = globals.get_asset(path)?;
|
||||||
Ok(Self::from_bin_svg(&data)?)
|
if path_str.ends_with(".svg") || path_str.ends_with(".svgz") {
|
||||||
} else {
|
|
||||||
Ok(Self::from_bin_raster(&data)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::case_sensitive_file_extension_comparisons)]
|
|
||||||
pub fn from_file(path: &str) -> anyhow::Result<Self> {
|
|
||||||
let data = std::fs::read(path)?;
|
|
||||||
if path.ends_with(".svg") || path.ends_with(".svgz") {
|
|
||||||
Ok(Self::from_bin_svg(&data)?)
|
Ok(Self::from_bin_svg(&data)?)
|
||||||
} else {
|
} else {
|
||||||
Ok(Self::from_bin_raster(&data)?)
|
Ok(Self::from_bin_raster(&data)?)
|
||||||
@@ -165,11 +156,7 @@ impl RasterizedCustomGlyph {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn validate(
|
pub(super) fn validate(&self, input: &RasterizeCustomGlyphRequest, expected_type: Option<ContentType>) {
|
||||||
&self,
|
|
||||||
input: &RasterizeCustomGlyphRequest,
|
|
||||||
expected_type: Option<ContentType>,
|
|
||||||
) {
|
|
||||||
if let Some(expected_type) = expected_type {
|
if let Some(expected_type) = expected_type {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
self.content_type, expected_type,
|
self.content_type, expected_type,
|
||||||
@@ -222,10 +209,7 @@ impl ContentType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rasterize_svg(
|
fn rasterize_svg(tree: &Tree, input: &RasterizeCustomGlyphRequest) -> Option<RasterizedCustomGlyph> {
|
||||||
tree: &Tree,
|
|
||||||
input: &RasterizeCustomGlyphRequest,
|
|
||||||
) -> Option<RasterizedCustomGlyph> {
|
|
||||||
// Calculate the scale based on the "glyph size".
|
// Calculate the scale based on the "glyph size".
|
||||||
let svg_size = tree.size();
|
let svg_size = tree.size();
|
||||||
let scale_x = f32::from(input.width) / svg_size.width();
|
let scale_x = f32::from(input.width) / svg_size.width();
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ impl WidgetLabel {
|
|||||||
buffer.set_wrap(wrap);
|
buffer.set_wrap(wrap);
|
||||||
|
|
||||||
buffer.set_rich_text(
|
buffer.set_rich_text(
|
||||||
[(params.content.generate(&mut globals.i18n).as_ref(), attrs)],
|
[(params.content.generate(&mut globals.i18n_builtin).as_ref(), attrs)],
|
||||||
&Attrs::new(),
|
&Attrs::new(),
|
||||||
Shaping::Advanced,
|
Shaping::Advanced,
|
||||||
params.style.align.map(Into::into),
|
params.style.align.map(Into::into),
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
use button::setup_custom_button;
|
use button::setup_custom_button;
|
||||||
use glam::{vec2, Affine2, Vec2};
|
use glam::{Affine2, Vec2, vec2};
|
||||||
use label::setup_custom_label;
|
use label::setup_custom_label;
|
||||||
use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView};
|
use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView};
|
||||||
use wgui::{
|
use wgui::{
|
||||||
|
assets::AssetPath,
|
||||||
drawing,
|
drawing,
|
||||||
event::{
|
event::{
|
||||||
Event as WguiEvent, EventListenerCollection, InternalStateChangeEvent, ListenerHandleVec,
|
Event as WguiEvent, EventListenerCollection, InternalStateChangeEvent, ListenerHandleVec,
|
||||||
@@ -21,7 +22,7 @@ use crate::{
|
|||||||
backend::input::{Haptics, PointerHit, PointerMode},
|
backend::input::{Haptics, PointerHit, PointerMode},
|
||||||
graphics::{CommandBuffers, ExtentExt},
|
graphics::{CommandBuffers, ExtentExt},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
windowing::backend::{ui_transform, FrameMeta, OverlayBackend, ShouldRender},
|
windowing::backend::{FrameMeta, OverlayBackend, ShouldRender, ui_transform},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{timer::GuiTimer, timestep::Timestep};
|
use super::{timer::GuiTimer, timestep::Timestep};
|
||||||
@@ -72,7 +73,7 @@ impl<S> GuiPanel<S> {
|
|||||||
|
|
||||||
let doc_params = wgui::parser::ParseDocumentParams {
|
let doc_params = wgui::parser::ParseDocumentParams {
|
||||||
globals: app.wgui_globals.clone(),
|
globals: app.wgui_globals.clone(),
|
||||||
path,
|
path: AssetPath::BuiltIn(path),
|
||||||
extra: wgui::parser::ParseDocumentExtra {
|
extra: wgui::parser::ParseDocumentExtra {
|
||||||
on_custom_attribs: Some(Box::new({
|
on_custom_attribs: Some(Box::new({
|
||||||
let custom_elems = custom_elems.clone();
|
let custom_elems = custom_elems.clone();
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use std::{collections::HashMap, rc::Rc};
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use glam::{vec2, vec3, Affine3A, Mat4, Quat, Vec2, Vec3};
|
use glam::{Affine3A, Mat4, Quat, Vec2, Vec3, vec2, vec3};
|
||||||
use wgui::{
|
use wgui::{
|
||||||
animation::{Animation, AnimationEasing},
|
animation::{Animation, AnimationEasing},
|
||||||
|
assets::AssetPath,
|
||||||
drawing::Color,
|
drawing::Color,
|
||||||
event::{self, CallbackMetadata, EventListenerKind},
|
event::{self, CallbackMetadata, EventListenerKind},
|
||||||
layout::LayoutParams,
|
layout::LayoutParams,
|
||||||
@@ -19,14 +20,14 @@ use wgui::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
gui::panel::GuiPanel,
|
gui::panel::GuiPanel,
|
||||||
state::AppState,
|
state::AppState,
|
||||||
subsystem::hid::{XkbKeymap, ALT, CTRL, META, SHIFT, SUPER},
|
subsystem::hid::{ALT, CTRL, META, SHIFT, SUPER, XkbKeymap},
|
||||||
windowing::window::{OverlayWindowConfig, OverlayWindowState, Positioning},
|
windowing::window::{OverlayWindowConfig, OverlayWindowState, Positioning},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
handle_press, handle_release,
|
KEYBOARD_NAME, KeyButtonData, KeyState, KeyboardBackend, KeyboardState, handle_press,
|
||||||
|
handle_release,
|
||||||
layout::{self, AltModifier, KeyCapType},
|
layout::{self, AltModifier, KeyCapType},
|
||||||
KeyButtonData, KeyState, KeyboardBackend, KeyboardState, KEYBOARD_NAME,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const BACKGROUND_PADDING: f32 = 4.;
|
const BACKGROUND_PADDING: f32 = 4.;
|
||||||
@@ -54,7 +55,7 @@ pub fn create_keyboard(
|
|||||||
let mut panel = GuiPanel::new_blank(app, state)?;
|
let mut panel = GuiPanel::new_blank(app, state)?;
|
||||||
|
|
||||||
let (background, _) = panel.layout.add_child(
|
let (background, _) = panel.layout.add_child(
|
||||||
panel.layout.root_widget,
|
panel.layout.content_root_widget,
|
||||||
WidgetRectangle::create(WidgetRectangleParams {
|
WidgetRectangle::create(WidgetRectangleParams {
|
||||||
color: wgui::drawing::Color::new(0., 0., 0., 0.6),
|
color: wgui::drawing::Color::new(0., 0., 0., 0.6),
|
||||||
round: WLength::Units(4.0),
|
round: WLength::Units(4.0),
|
||||||
@@ -75,7 +76,7 @@ pub fn create_keyboard(
|
|||||||
|
|
||||||
let parse_doc_params = wgui::parser::ParseDocumentParams {
|
let parse_doc_params = wgui::parser::ParseDocumentParams {
|
||||||
globals: app.wgui_globals.clone(),
|
globals: app.wgui_globals.clone(),
|
||||||
path: "gui/keyboard.xml",
|
path: AssetPath::BuiltIn("gui/keyboard.xml"),
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{
|
|||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
use glam::{vec3, Affine3A, Quat, Vec3};
|
use glam::{Affine3A, Quat, Vec3, vec3};
|
||||||
use idmap_derive::IntegerId;
|
use idmap_derive::IntegerId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use wgui::{
|
use wgui::{
|
||||||
@@ -28,8 +28,8 @@ use crate::{
|
|||||||
gui::panel::GuiPanel,
|
gui::panel::GuiPanel,
|
||||||
state::{AppState, LeftRight},
|
state::{AppState, LeftRight},
|
||||||
windowing::{
|
windowing::{
|
||||||
window::{OverlayWindowConfig, OverlayWindowState, Positioning},
|
|
||||||
OverlaySelector, Z_ORDER_TOAST,
|
OverlaySelector, Z_ORDER_TOAST,
|
||||||
|
window::{OverlayWindowConfig, OverlayWindowState, Positioning},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -144,8 +144,7 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<OverlayWindowConfig> {
|
|||||||
Positioning::FollowHead { lerp: 0.1 },
|
Positioning::FollowHead { lerp: 0.1 },
|
||||||
),
|
),
|
||||||
DisplayMethod::Watch => {
|
DisplayMethod::Watch => {
|
||||||
let mut watch_pos =
|
let mut watch_pos = app.session.config.watch_pos + vec3(-0.005, -0.05, 0.02);
|
||||||
Vec3::from(app.session.config.watch_pos) + vec3(-0.005, -0.05, 0.02);
|
|
||||||
let mut watch_rot = app.session.config.watch_rot;
|
let mut watch_rot = app.session.config.watch_rot;
|
||||||
let relative_to = match app.session.config.watch_hand {
|
let relative_to = match app.session.config.watch_hand {
|
||||||
LeftRight::Left => Positioning::FollowHand { hand: 0, lerp: 1.0 },
|
LeftRight::Left => Positioning::FollowHand { hand: 0, lerp: 1.0 },
|
||||||
@@ -172,7 +171,7 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<OverlayWindowConfig> {
|
|||||||
let (rect, _) = panel
|
let (rect, _) = panel
|
||||||
.layout
|
.layout
|
||||||
.add_child(
|
.add_child(
|
||||||
panel.layout.root_widget,
|
panel.layout.content_root_widget,
|
||||||
WidgetRectangle::create(WidgetRectangleParams {
|
WidgetRectangle::create(WidgetRectangleParams {
|
||||||
color: parse_color_hex("#1e2030").unwrap(),
|
color: parse_color_hex("#1e2030").unwrap(),
|
||||||
border_color: parse_color_hex("#5e7090").unwrap(),
|
border_color: parse_color_hex("#5e7090").unwrap(),
|
||||||
|
|||||||
Reference in New Issue
Block a user