mirror of https://github.com/wayvr-org/wayvr.git
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
fb4e4d59ff
|
|
@ -1033,6 +1033,7 @@ dependencies = [
|
|||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"pure-rust-locales",
|
||||
"wasm-bindgen",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
|
@ -4878,6 +4879,12 @@ dependencies = [
|
|||
"syn 2.0.113",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pure-rust-locales"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "869675ad2d7541aea90c6d88c81f46a7f4ea9af8cd0395d38f11a95126998a0d"
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.27"
|
||||
|
|
@ -7378,6 +7385,7 @@ dependencies = [
|
|||
"mint",
|
||||
"openxr",
|
||||
"ovr_overlay",
|
||||
"pure-rust-locales",
|
||||
"regex",
|
||||
"rosc",
|
||||
"rust-embed",
|
||||
|
|
|
|||
21
README.md
21
README.md
|
|
@ -131,7 +131,10 @@ Typing
|
|||
- While using the ORANGE laser, all keystrokes will have SHIFT applied.
|
||||
- Purple laser is customizable via the settings, no modifier by default.
|
||||
|
||||
**Modifier Keys** are sticky. They will remain pressed until a non-modifier key is pressed, the modifier gets toggled off, or the keyboard gets hidden.
|
||||
**Modifier Keys are sticky**. They will remain pressed until eiter:
|
||||
- a non-modifier key is pressed
|
||||
- the modifier is toggled off by clicking again
|
||||
- the keyboard is hidden (including via show-hide)
|
||||
|
||||
### Default Bindings
|
||||
|
||||
|
|
@ -139,11 +142,23 @@ Typing
|
|||
|
||||

|
||||
|
||||
To customize bindings on OpenXR, refer to the [OpenXR Bindings wiki page](https://github.com/wlx-team/wayvr/wiki/OpenXR-Bindings).
|
||||
|
||||
If your bindings are not supported, please reach out. \
|
||||
### Changing Bindings
|
||||
|
||||
SteamVR: Simply change the bindings from the SteamVR bindings section. If WayVR doesn't show up on the list, select any other title and then press back on the top left. (SteamVR is weird like that sometimes)
|
||||
|
||||
OpenXR (Monado/WiVRn): See [Wiki: OpenXR Bindings](https://github.com/wlx-team/wayvr/wiki/OpenXR-Bindings)
|
||||
|
||||
If your controllers are not supported, please reach out. \
|
||||
We would like to work with you and include additional bindings.
|
||||
|
||||
## Customization
|
||||
|
||||
See these relevant wiki pages:
|
||||
- For all available config options, check [Wiki: Configuration](https://github.com/wlx-team/wayvr/wiki/Configuration)
|
||||
- Looking to customize look & feel, or add functionality? See [Wiki: Customization](https://github.com/wlx-team/wayvr/wiki/Customization)
|
||||
- Looking to change the OpenXR background? See [Wiki: OpenXR Skybox](https://github.com/wlx-team/wayvr/wiki/OpenXR-Skybox)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
When an error is detected, we often print tips for fixing it into the log file.
|
||||
|
|
|
|||
|
|
@ -90,7 +90,9 @@
|
|||
"BLOCK_POSES_ON_KBD_INTERACTION": "Posen beim Interagieren mit der Tastatur blockieren",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Verhindert, dass das Spiel Posen empfängt, wenn die Tastatur angefahren wird und „Spieleingabe blockieren“ aktiviert ist",
|
||||
"LANGUAGE": "Sprache",
|
||||
"REQUIRES_RESTART": "Erfordert Neustart"
|
||||
"REQUIRES_RESTART": "Erfordert Neustart",
|
||||
"GRID_OPACITY": "Bodenraster-Undurchsichtigkeit",
|
||||
"GRID_OPACITY_HELP": "Undurchsichtigkeit des Bodenrasters, wenn der Skybox aktiviert ist"
|
||||
},
|
||||
"HELLO": "Hallo!",
|
||||
"AUDIO": {
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@
|
|||
"USE_PASSTHROUGH_HELP": "Allow passthrough if the XR runtime supports it",
|
||||
"USE_SKYBOX": "Enable skybox",
|
||||
"USE_SKYBOX_HELP": "Show a skybox if there's no scene app or passthrough",
|
||||
"GRID_OPACITY": "Floor grid opacity",
|
||||
"GRID_OPACITY_HELP": "Opacity of the floor grid when the skybox is enabled",
|
||||
"XR_CLICK_SENSITIVITY": "XR click sensitivity",
|
||||
"XR_CLICK_SENSITIVITY_HELP": "Analog trigger sensitivity",
|
||||
"XR_CLICK_SENSITIVITY_RELEASE": "XR release sensitivity",
|
||||
|
|
|
|||
|
|
@ -90,7 +90,9 @@
|
|||
"BLOCK_POSES_ON_KBD_INTERACTION": "Bloquear poses al interactuar con el teclado",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Bloquea que el juego reciba poses cuando el teclado está sobre él y 'Bloquear entrada del juego' está habilitado",
|
||||
"LANGUAGE": "Idioma",
|
||||
"REQUIRES_RESTART": "Requiere reinicio"
|
||||
"REQUIRES_RESTART": "Requiere reinicio",
|
||||
"GRID_OPACITY": "Opacidad de la cuadrícula del suelo",
|
||||
"GRID_OPACITY_HELP": "Opacidad de la cuadrícula del suelo cuando el skybox está habilitado"
|
||||
},
|
||||
"HELLO": "¡Hola!",
|
||||
"AUDIO": {
|
||||
|
|
|
|||
|
|
@ -111,7 +111,9 @@
|
|||
"BLOCK_POSES_ON_KBD_INTERACTION": "Blocca le pose durante l'interazione con la tastiera",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Impedisce al gioco di ricevere pose quando la tastiera è evidenziata e 'Blocca input di gioco' è abilitato",
|
||||
"LANGUAGE": "Lingua",
|
||||
"REQUIRES_RESTART": "Richiede riavvio"
|
||||
"REQUIRES_RESTART": "Richiede riavvio",
|
||||
"GRID_OPACITY": "Opacità della griglia del pavimento",
|
||||
"GRID_OPACITY_HELP": "Opacità della griglia del pavimento quando lo skybox è abilitato"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "Lanciatore applicazioni",
|
||||
"APPLICATION_STARTED": "Applicazione avviata",
|
||||
|
|
|
|||
|
|
@ -90,7 +90,9 @@
|
|||
"BLOCK_POSES_ON_KBD_INTERACTION": "キーボード操作時のポーズをブロック",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "キーボードがホバーされ、「ゲーム入力をブロック」が有効になっている場合、ゲームがポーズを受信することをブロックします",
|
||||
"LANGUAGE": "言語",
|
||||
"REQUIRES_RESTART": "再起動が必要です"
|
||||
"REQUIRES_RESTART": "再起動が必要です",
|
||||
"GRID_OPACITY": "フロアグリッドの不透明度",
|
||||
"GRID_OPACITY_HELP": "スカイボックスが有効なときの床グリッドの不透明度"
|
||||
},
|
||||
"HELLO": "こんにちは!",
|
||||
"AUDIO": {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,9 @@
|
|||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Blokuje odbieranie póz przez grę, gdy kursor myszy znajduje się nad klawiaturą i włączona jest opcja 'Blokuj dane wejściowe z gry'",
|
||||
"LANGUAGE": "Język",
|
||||
"REQUIRES_RESTART": "Wymaga restartu",
|
||||
"MISC": "Różne"
|
||||
"MISC": "Różne",
|
||||
"GRID_OPACITY": "Przezroczystość siatki podłogowej",
|
||||
"GRID_OPACITY_HELP": "Przezroczystość siatki podłogowej, gdy włączony jest skybox"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "Uruchamiacz aplikacji",
|
||||
"APPLICATIONS": "Aplikacje",
|
||||
|
|
|
|||
|
|
@ -111,7 +111,9 @@
|
|||
"BLOCK_POSES_ON_KBD_INTERACTION": "与键盘交互时阻止姿势",
|
||||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "当键盘悬停且启用“阻止游戏输入”时,阻止游戏接收姿势",
|
||||
"LANGUAGE": "语言",
|
||||
"REQUIRES_RESTART": "需要重启"
|
||||
"REQUIRES_RESTART": "需要重启",
|
||||
"GRID_OPACITY": "地面网格不透明度",
|
||||
"GRID_OPACITY_HELP": "启用天空盒时地板网格的不透明度"
|
||||
},
|
||||
"APPLICATION_LAUNCHER": "应用启动器",
|
||||
"APPLICATION_STARTED": "应用已启动",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use wgui::{
|
|||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||
renderer_vk::text::custom_glyph::CustomGlyphData,
|
||||
task::Tasks,
|
||||
theme::WguiTheme,
|
||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle, sprite::WidgetSprite},
|
||||
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
|
||||
};
|
||||
|
|
@ -86,6 +87,7 @@ pub struct InitParams<'a, T> {
|
|||
pub interface: BoxDashInterface<T>,
|
||||
pub lang_provider: &'a WayVRLangProvider,
|
||||
pub has_monado: bool,
|
||||
pub theme: Rc<WguiTheme>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -106,12 +108,11 @@ pub enum FrontendTask {
|
|||
RecenterPlayspace,
|
||||
PushToast(Translation),
|
||||
PlaySound(SoundType),
|
||||
UpdateWguiDefaultsFromConfig,
|
||||
HideDashboard,
|
||||
}
|
||||
|
||||
impl<T: 'static> Frontend<T> {
|
||||
pub fn new(mut params: InitParams<T>, data: &mut T) -> anyhow::Result<Frontend<T>> {
|
||||
pub fn new(params: InitParams<T>) -> anyhow::Result<Frontend<T>> {
|
||||
let mut assets = Box::new(assets::Asset {});
|
||||
|
||||
let font_binary_bold = assets.load_from_path_gzip("Quicksand-Bold.ttf.gz")?;
|
||||
|
|
@ -121,7 +122,6 @@ impl<T: 'static> Frontend<T> {
|
|||
let globals = WguiGlobals::new(
|
||||
assets,
|
||||
params.lang_provider,
|
||||
wgui::globals::Defaults::default(),
|
||||
&WguiFontConfig {
|
||||
binaries: vec![&font_binary_regular, &font_binary_bold, &font_binary_light],
|
||||
family_name_sans_serif: "Quicksand",
|
||||
|
|
@ -131,15 +131,16 @@ impl<T: 'static> Frontend<T> {
|
|||
PathBuf::new(), //FIXME: pass from somewhere else
|
||||
)?;
|
||||
|
||||
Frontend::update_defaults_from_config(&globals, &mut params.interface, data);
|
||||
|
||||
let (layout, state) = wgui::parser::new_layout_from_assets(
|
||||
&ParseDocumentParams {
|
||||
globals: globals.clone(),
|
||||
path: AssetPath::BuiltIn("gui/dashboard.xml"),
|
||||
extra: Default::default(),
|
||||
},
|
||||
&LayoutParams { resize_to_parent: true },
|
||||
LayoutParams {
|
||||
resize_to_parent: true,
|
||||
theme: params.theme,
|
||||
},
|
||||
)?;
|
||||
|
||||
let id_popup_manager = state.get_widget_id("popup_manager")?;
|
||||
|
|
@ -185,7 +186,6 @@ impl<T: 'static> Frontend<T> {
|
|||
// init some things first
|
||||
frontend.tasks.push(FrontendTask::RefreshBackground);
|
||||
frontend.tasks.push(FrontendTask::RefreshClock);
|
||||
frontend.tasks.push(FrontendTask::UpdateWguiDefaultsFromConfig);
|
||||
|
||||
Frontend::register_widgets(&mut frontend)?;
|
||||
|
||||
|
|
@ -196,16 +196,6 @@ impl<T: 'static> Frontend<T> {
|
|||
self.sounds_to_play.push(sound_type);
|
||||
}
|
||||
|
||||
fn update_defaults_from_config(globals: &WguiGlobals, interface: &mut BoxDashInterface<T>, data: &mut T) {
|
||||
let config = interface.general_config(data);
|
||||
|
||||
let mut globals = globals.get();
|
||||
let defaults = &mut globals.defaults;
|
||||
|
||||
defaults.animation_mult = 1.0 / config.ui_animation_speed;
|
||||
defaults.gradient_intensity = config.ui_gradient_intensity;
|
||||
}
|
||||
|
||||
fn play_sound(&mut self, audio_system: &mut audio::AudioSystem, sound_type: SoundType) -> anyhow::Result<()> {
|
||||
let mut assets = self.globals.assets_builtin();
|
||||
|
||||
|
|
@ -273,7 +263,7 @@ impl<T: 'static> Frontend<T> {
|
|||
{
|
||||
// always 30 times per second
|
||||
while self.timestep.on_tick() {
|
||||
self.toast_manager.tick(&self.globals, &mut self.layout)?;
|
||||
self.toast_manager.tick(&mut self.layout)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -374,9 +364,6 @@ impl<T: 'static> Frontend<T> {
|
|||
FrontendTask::PushToast(content) => self.toast_manager.push(content),
|
||||
FrontendTask::PlaySound(sound_type) => self.queue_play_sound(sound_type),
|
||||
FrontendTask::HideDashboard => self.action_hide_dashboard(params.data),
|
||||
FrontendTask::UpdateWguiDefaultsFromConfig => {
|
||||
Frontend::update_defaults_from_config(&self.globals, &mut self.interface, params.data)
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ impl<T> Tab<T> for TabSettings<T> {
|
|||
}
|
||||
Task::SettingUpdated(setting) => match setting {
|
||||
SettingType::UiAnimationSpeed | SettingType::UiGradientIntensity | SettingType::UiRoundMultiplier => {
|
||||
frontend.tasks.push(FrontendTask::UpdateWguiDefaultsFromConfig);
|
||||
// todo: currently, wayvr restart is required to apply these changes (WguiTheme is Rc)
|
||||
}
|
||||
_ => { /* do nothing */ }
|
||||
},
|
||||
|
|
@ -247,6 +247,7 @@ enum SettingType {
|
|||
UprightScreenFix,
|
||||
UsePassthrough,
|
||||
UseSkybox,
|
||||
GridOpacity,
|
||||
XrClickSensitivity,
|
||||
XrClickSensitivityRelease,
|
||||
XwaylandByDefault,
|
||||
|
|
@ -294,6 +295,7 @@ impl SettingType {
|
|||
Self::XrClickSensitivityRelease => &mut config.xr_click_sensitivity_release,
|
||||
Self::SpaceDragMultiplier => &mut config.space_drag_multiplier,
|
||||
Self::PointerLerpFactor => &mut config.pointer_lerp_factor,
|
||||
Self::GridOpacity => &mut config.grid_opacity,
|
||||
_ => panic!("Requested f32 for non-f32 SettingType"),
|
||||
}
|
||||
}
|
||||
|
|
@ -368,6 +370,7 @@ impl SettingType {
|
|||
Self::Clock12h => Ok("APP_SETTINGS.CLOCK_12H"),
|
||||
Self::DoubleCursorFix => Ok("APP_SETTINGS.DOUBLE_CURSOR_FIX"),
|
||||
Self::FocusFollowsMouseMode => Ok("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE"),
|
||||
Self::GridOpacity => Ok("APP_SETTINGS.GRID_OPACITY"),
|
||||
Self::HandsfreePointer => Ok("APP_SETTINGS.HANDSFREE_POINTER"),
|
||||
Self::HideGrabHelp => Ok("APP_SETTINGS.HIDE_GRAB_HELP"),
|
||||
Self::HideUsername => Ok("APP_SETTINGS.HIDE_USERNAME"),
|
||||
|
|
@ -408,6 +411,7 @@ impl SettingType {
|
|||
Self::BlockPosesOnKbdInteraction => Some("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION_HELP"),
|
||||
Self::CaptureMethod => Some("APP_SETTINGS.CAPTURE_METHOD_HELP"),
|
||||
Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"),
|
||||
Self::GridOpacity => Some("APP_SETTINGS.GRID_OPACITY_HELP"),
|
||||
Self::HandsfreePointer => Some("APP_SETTINGS.HANDSFREE_POINTER_HELP"),
|
||||
Self::KeyboardMiddleClick => Some("APP_SETTINGS.KEYBOARD_MIDDLE_CLICK_HELP"),
|
||||
Self::LeftHandedMouse => Some("APP_SETTINGS.LEFT_HANDED_MOUSE_HELP"),
|
||||
|
|
@ -422,16 +426,17 @@ impl SettingType {
|
|||
}
|
||||
|
||||
fn requires_restart(self) -> bool {
|
||||
match self {
|
||||
matches!(
|
||||
self,
|
||||
Self::UiAnimationSpeed
|
||||
| Self::UiRoundMultiplier
|
||||
| Self::UprightScreenFix
|
||||
| Self::DoubleCursorFix
|
||||
| Self::ScreenRenderDown
|
||||
| Self::Language
|
||||
| Self::CaptureMethod => true,
|
||||
_ => false,
|
||||
}
|
||||
| Self::UiRoundMultiplier
|
||||
| Self::UiGradientIntensity
|
||||
| Self::UprightScreenFix
|
||||
| Self::DoubleCursorFix
|
||||
| Self::ScreenRenderDown
|
||||
| Self::Language
|
||||
| Self::CaptureMethod
|
||||
)
|
||||
}
|
||||
|
||||
fn get_frontend_task(self) -> Option<FrontendTask> {
|
||||
|
|
@ -462,7 +467,7 @@ fn horiz_cell(layout: &mut Layout, parent: WidgetID) -> anyhow::Result<WidgetID>
|
|||
fn mount_requires_restart(layout: &mut Layout, parent: WidgetID) -> anyhow::Result<()> {
|
||||
let content = Translation::from_translation_key("APP_SETTINGS.REQUIRES_RESTART");
|
||||
let label = WidgetLabel::create(
|
||||
&mut layout.state.globals.get(),
|
||||
&mut layout.state,
|
||||
WidgetLabelParams {
|
||||
content,
|
||||
style: TextStyle {
|
||||
|
|
@ -795,6 +800,7 @@ impl<T> TabSettings<T> {
|
|||
slider_f32!(mp, c, SettingType::UiRoundMultiplier, 0.5, 5.0, 0.1);
|
||||
checkbox!(mp, c, SettingType::SetsOnWatch);
|
||||
checkbox!(mp, c, SettingType::UseSkybox);
|
||||
slider_f32!(mp, c, SettingType::GridOpacity, 0.0, 1.0, 0.05); // min, max, step
|
||||
checkbox!(mp, c, SettingType::UsePassthrough);
|
||||
checkbox!(mp, c, SettingType::Clock12h);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use wgui::{
|
|||
animation::{Animation, AnimationEasing},
|
||||
components::tooltip::{TOOLTIP_BORDER_COLOR, TOOLTIP_COLOR},
|
||||
drawing::Color,
|
||||
globals::WguiGlobals,
|
||||
i18n::Translation,
|
||||
layout::{Layout, LayoutTask, LayoutTasks, WidgetID},
|
||||
renderer_vk::{
|
||||
|
|
@ -61,15 +60,7 @@ impl ToastManager {
|
|||
}
|
||||
}
|
||||
|
||||
fn mount_toast(
|
||||
&self,
|
||||
globals: &WguiGlobals,
|
||||
layout: &mut Layout,
|
||||
state: &mut State,
|
||||
content: Translation,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut globals = globals.get();
|
||||
|
||||
fn mount_toast(&self, layout: &mut Layout, state: &mut State, content: Translation) -> anyhow::Result<()> {
|
||||
let (root, _) = layout.add_topmost_child(
|
||||
WidgetDiv::create(),
|
||||
taffy::Style {
|
||||
|
|
@ -110,27 +101,24 @@ impl ToastManager {
|
|||
},
|
||||
)?;
|
||||
|
||||
let (label, _) = layout.add_child(
|
||||
rect.id,
|
||||
WidgetLabel::create(
|
||||
&mut globals,
|
||||
WidgetLabelParams {
|
||||
content,
|
||||
style: TextStyle {
|
||||
weight: Some(FontWeight::Bold),
|
||||
align: Some(HorizontalAlign::Center),
|
||||
wrap: true,
|
||||
..Default::default()
|
||||
},
|
||||
let label = WidgetLabel::create(
|
||||
&mut layout.state,
|
||||
WidgetLabelParams {
|
||||
content,
|
||||
style: TextStyle {
|
||||
weight: Some(FontWeight::Bold),
|
||||
align: Some(HorizontalAlign::Center),
|
||||
wrap: true,
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
taffy::Style { ..Default::default() },
|
||||
)?;
|
||||
},
|
||||
);
|
||||
let (label, _) = layout.add_child(rect.id, label, taffy::Style { ..Default::default() })?;
|
||||
|
||||
// show-up animation
|
||||
layout.animations.add(Animation::new(
|
||||
rect.id,
|
||||
(TOAST_DURATION_TICKS as f32 * globals.defaults.animation_mult) as u32,
|
||||
(TOAST_DURATION_TICKS as f32 * layout.state.theme.animation_mult) as u32,
|
||||
AnimationEasing::Linear,
|
||||
Box::new(move |common, data| {
|
||||
let pos_showup = AnimationEasing::OutQuint.interpolate((data.pos * 4.0).min(1.0));
|
||||
|
|
@ -161,7 +149,7 @@ impl ToastManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, globals: &WguiGlobals, layout: &mut Layout) -> anyhow::Result<()> {
|
||||
pub fn tick(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
|
||||
let mut state = self.state.borrow_mut();
|
||||
if state.timeout > 0 {
|
||||
state.timeout -= 1;
|
||||
|
|
@ -176,7 +164,7 @@ impl ToastManager {
|
|||
state.timeout = TOAST_DURATION_TICKS;
|
||||
// mount next
|
||||
if let Some(content) = state.queue.pop_front() {
|
||||
self.mount_toast(globals, layout, &mut state, content)?;
|
||||
self.mount_toast(layout, &mut state, content)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use wgui::{
|
|||
#[allow(dead_code)]
|
||||
pub fn create_label(layout: &mut Layout, parent: WidgetID, content: Translation) -> anyhow::Result<()> {
|
||||
let label = WidgetLabel::create(
|
||||
&mut layout.state.globals.get(),
|
||||
&mut layout.state,
|
||||
WidgetLabelParams {
|
||||
content,
|
||||
style: TextStyle {
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ struct MultiSelectorParams<'a> {
|
|||
}
|
||||
|
||||
fn mount_multi_selector(params: MultiSelectorParams) -> anyhow::Result<()> {
|
||||
let globals = params.ess.layout.state.globals.clone();
|
||||
let accent_color = globals.defaults().accent_color;
|
||||
let accent_color = params.ess.layout.state.theme.accent_color;
|
||||
|
||||
for cell in params.cells {
|
||||
let highlighted = cell.key == params.def_cell;
|
||||
|
|
@ -654,8 +653,6 @@ impl View {
|
|||
}
|
||||
|
||||
fn update_button_highlights(&self, layout: &mut Layout) -> anyhow::Result<()> {
|
||||
let defaults = self.globals.defaults();
|
||||
|
||||
let mut c = layout.start_common();
|
||||
let mut common = c.common();
|
||||
|
||||
|
|
@ -667,14 +664,12 @@ impl View {
|
|||
};
|
||||
|
||||
let mut perform = |btn_num: u8, btn: &Rc<ComponentButton>| {
|
||||
btn.set_color(
|
||||
&mut common,
|
||||
if num == btn_num {
|
||||
defaults.accent_color
|
||||
} else {
|
||||
defaults.button_color
|
||||
},
|
||||
);
|
||||
let color = if num == btn_num {
|
||||
common.state.theme.accent_color
|
||||
} else {
|
||||
common.state.theme.button_color
|
||||
};
|
||||
btn.set_color(&mut common, color);
|
||||
};
|
||||
|
||||
perform(0, &self.btn_sinks);
|
||||
|
|
|
|||
|
|
@ -98,15 +98,9 @@ impl View {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn mount_placeholder_text(
|
||||
&self,
|
||||
globals: &WguiGlobals,
|
||||
layout: &mut Layout,
|
||||
parent: WidgetID,
|
||||
text: &str,
|
||||
) -> anyhow::Result<()> {
|
||||
fn mount_placeholder_text(&self, layout: &mut Layout, parent: WidgetID, text: &str) -> anyhow::Result<()> {
|
||||
let label = WidgetLabel::create(
|
||||
&mut globals.get(),
|
||||
&mut layout.state,
|
||||
WidgetLabelParams {
|
||||
content: Translation::from_raw_text(text),
|
||||
style: TextStyle {
|
||||
|
|
@ -153,7 +147,7 @@ impl View {
|
|||
// mount placeholder
|
||||
let img = view_common.get_placeholder_image()?.clone();
|
||||
self.mount_image(layout, &img)?;
|
||||
self.mount_placeholder_text(&view_common.globals, layout, self.id_image_parent, &self.app_name)?;
|
||||
self.mount_placeholder_text(layout, self.id_image_parent, &self.app_name)?;
|
||||
} else {
|
||||
// mount image
|
||||
let path = format!("app:{:?}", self.app_id);
|
||||
|
|
|
|||
|
|
@ -256,17 +256,14 @@ impl View {
|
|||
)?;
|
||||
|
||||
if let Some(text) = text.take() {
|
||||
layout.add_child(
|
||||
self.id_list_parent,
|
||||
WidgetLabel::create(
|
||||
&mut self.globals.get(),
|
||||
WidgetLabelParams {
|
||||
content: text,
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
Default::default(),
|
||||
)?;
|
||||
let label = WidgetLabel::create(
|
||||
&mut layout.state,
|
||||
WidgetLabelParams {
|
||||
content: text,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
layout.add_child(self.id_list_parent, label, Default::default())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ impl TestbedAny {
|
|||
let globals = WguiGlobals::new(
|
||||
assets,
|
||||
&lang_provider,
|
||||
wgui::globals::Defaults::default(),
|
||||
&WguiFontConfig::default(),
|
||||
PathBuf::new(), // cwd
|
||||
)?;
|
||||
|
|
@ -45,7 +44,7 @@ impl TestbedAny {
|
|||
path,
|
||||
extra: Default::default(),
|
||||
},
|
||||
&LayoutParams::default(),
|
||||
LayoutParams::default(),
|
||||
)?;
|
||||
Ok(Self { layout, state })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::testbed::{Testbed, TestbedUpdateParams};
|
||||
use dash_frontend::frontend::{self, FrontendUpdateParams};
|
||||
use wgui::layout::Layout;
|
||||
use wgui::{layout::Layout, theme::WguiTheme};
|
||||
use wlx_common::{dash_interface_emulated::DashInterfaceEmulated, locale::WayVRLangProvider};
|
||||
|
||||
pub struct TestbedDashboard {
|
||||
|
|
@ -12,14 +14,12 @@ impl TestbedDashboard {
|
|||
let interface = DashInterfaceEmulated::new();
|
||||
let lang_provider = WayVRLangProvider::default();
|
||||
|
||||
let frontend = frontend::Frontend::new(
|
||||
frontend::InitParams {
|
||||
interface: Box::new(interface),
|
||||
has_monado: true,
|
||||
lang_provider: &lang_provider,
|
||||
},
|
||||
&mut (),
|
||||
)?;
|
||||
let frontend = frontend::Frontend::new(frontend::InitParams {
|
||||
interface: Box::new(interface),
|
||||
has_monado: true,
|
||||
lang_provider: &lang_provider,
|
||||
theme: Rc::new(WguiTheme::default()),
|
||||
})?;
|
||||
Ok(Self { frontend })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use wgui::{
|
|||
parser::{Fetchable, ParseDocumentExtra, ParseDocumentParams, ParserState},
|
||||
taffy::{self, prelude::length},
|
||||
task::Tasks,
|
||||
theme::WguiTheme,
|
||||
widget::{div::WidgetDiv, label::WidgetLabel, rectangle::WidgetRectangle},
|
||||
windowing::{
|
||||
context_menu::{self, TickResult},
|
||||
|
|
@ -91,7 +92,6 @@ impl TestbedGeneric {
|
|||
let globals = WguiGlobals::new(
|
||||
assets,
|
||||
&lang_provider,
|
||||
wgui::globals::Defaults::default(),
|
||||
&WguiFontConfig::default(),
|
||||
PathBuf::new(), // cwd
|
||||
)?;
|
||||
|
|
@ -125,8 +125,9 @@ impl TestbedGeneric {
|
|||
|
||||
let (layout, parser_state) = wgui::parser::new_layout_from_assets(
|
||||
&TestbedGeneric::doc_params(&globals, extra),
|
||||
&LayoutParams {
|
||||
LayoutParams {
|
||||
resize_to_parent: true,
|
||||
theme: Rc::new(WguiTheme::default()),
|
||||
},
|
||||
)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
This repository contains the IPC specification and client implementation for the WayVR protocol. The primary purpose is to enable communication between applications and the WayVR server, offering a range of API functions.
|
||||
|
||||
[WayVR Server README](https://github.com/galister/wlx-overlay-s/tree/main/contrib/wayvr)
|
||||
[WayVR Server README](https://github.com/wlx-team/wayvr/tree/main/wayvr/contrib/wayvr)
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ xdg.workspace = true
|
|||
|
||||
ash = "^0.38.0" # must match vulkano
|
||||
bytes = { version = "1.11.1" }
|
||||
chrono = "0.4.42"
|
||||
chrono = { version = "0.4.42", features = [ "unstable-locales"]}
|
||||
pure-rust-locales = "0.8.2"
|
||||
chrono-tz = "0.10.4"
|
||||
config = "0.15.19"
|
||||
dbus = { version = "0.9.9" }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,18 @@ use glam::{Affine3A, Quat, Vec3, Vec3A};
|
|||
use openxr::{self as xr, SessionCreateFlags, Version, sys::Handle};
|
||||
use xr::OverlaySessionCreateFlagsEXTX;
|
||||
|
||||
macro_rules! next_chain_insert {
|
||||
($layer:expr, $payload:expr) => {{
|
||||
let payload_ptr = $payload.as_mut() as *mut _ as *mut xr::sys::BaseInStructure;
|
||||
let new_elem = payload_ptr.as_mut().unwrap();
|
||||
let mut raw = $layer.into_raw();
|
||||
new_elem.next = raw.next as _;
|
||||
raw.next = payload_ptr as *const _;
|
||||
raw
|
||||
}};
|
||||
}
|
||||
pub(crate) use next_chain_insert;
|
||||
|
||||
pub(super) fn init_xr() -> Result<(xr::Instance, xr::SystemId), anyhow::Error> {
|
||||
let entry = xr::Entry::linked();
|
||||
|
||||
|
|
|
|||
|
|
@ -214,8 +214,11 @@
|
|||
left: "/user/hand/left/input/trackpad/x",
|
||||
right: "/user/hand/right/input/trackpad/x"
|
||||
},
|
||||
toggle_dashboard: {
|
||||
right: "/user/hand/right/input/system/click",
|
||||
},
|
||||
show_hide: {
|
||||
left: "/user/hand/left/input/menu/click",
|
||||
left: "/user/hand/left/input/system/click",
|
||||
},
|
||||
space_drag: {
|
||||
right: "/user/hand/right/input/menu/click",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ use xr::EyeVisibility;
|
|||
|
||||
use super::{CompositionLayer, XrState, helpers, swapchain::WlxSwapchain};
|
||||
use crate::{
|
||||
backend::openxr::swapchain::{SwapchainOpts, WlxSwapchainImage, create_swapchain},
|
||||
backend::openxr::{
|
||||
helpers::next_chain_insert,
|
||||
swapchain::{SwapchainOpts, WlxSwapchainImage, create_swapchain},
|
||||
},
|
||||
state::AppState,
|
||||
windowing::window::OverlayWindowData,
|
||||
};
|
||||
|
|
@ -20,17 +23,6 @@ pub struct OpenXrOverlayData {
|
|||
color_bias_khr: Option<Box<xr::sys::CompositionLayerColorScaleBiasKHR>>,
|
||||
}
|
||||
|
||||
macro_rules! next_chain_insert {
|
||||
($layer:expr, $payload:expr) => {{
|
||||
let payload_ptr = $payload.as_mut() as *mut _ as *mut xr::sys::BaseInStructure;
|
||||
let new_elem = payload_ptr.as_mut().unwrap();
|
||||
let mut raw = $layer.into_raw();
|
||||
new_elem.next = raw.next as _;
|
||||
raw.next = payload_ptr as *const _;
|
||||
raw
|
||||
}};
|
||||
}
|
||||
|
||||
impl OverlayWindowData<OpenXrOverlayData> {
|
||||
pub(super) fn ensure_swapchain_acquire<'a>(
|
||||
&'a mut self,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
use std::{
|
||||
f32::consts::PI,
|
||||
fs::File,
|
||||
sync::{Arc, LazyLock},
|
||||
};
|
||||
use std::{f32::consts::PI, fs::File, sync::Arc};
|
||||
|
||||
use glam::{Quat, Vec3A};
|
||||
use openxr as xr;
|
||||
|
|
@ -14,7 +10,10 @@ use wgui::gfx::{cmd::WGfxClearMode, pipeline::WPipelineCreateInfo};
|
|||
use wlx_common::config_io;
|
||||
|
||||
use crate::{
|
||||
backend::openxr::{helpers::translation_rotation_to_posef, swapchain::SwapchainOpts},
|
||||
backend::openxr::{
|
||||
helpers::{next_chain_insert, translation_rotation_to_posef},
|
||||
swapchain::SwapchainOpts,
|
||||
},
|
||||
graphics::{ExtentExt, GpuFutures, dds::WlxCommandBufferDds},
|
||||
state::AppState,
|
||||
};
|
||||
|
|
@ -28,10 +27,12 @@ pub(super) struct Skybox {
|
|||
view: Arc<ImageView>,
|
||||
sky: Option<WlxSwapchain>,
|
||||
grid: Option<WlxSwapchain>,
|
||||
grid_pose: xr::Posef,
|
||||
grid_color_scale_bias_khr: Option<Box<xr::sys::CompositionLayerColorScaleBiasKHR>>,
|
||||
}
|
||||
|
||||
impl Skybox {
|
||||
pub fn new(app: &AppState) -> anyhow::Result<Self> {
|
||||
pub fn new(xr: &XrState, app: &AppState) -> anyhow::Result<Self> {
|
||||
let mut command_buffer = app
|
||||
.gfx
|
||||
.create_xfer_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
|
||||
|
|
@ -74,10 +75,30 @@ impl Skybox {
|
|||
|
||||
let view = ImageView::new_default(maybe_image.unwrap())?; // safe unwrap
|
||||
|
||||
let grid_color_scale_bias_khr = xr
|
||||
.instance
|
||||
.exts()
|
||||
.khr_composition_layer_color_scale_bias
|
||||
.map(|_| {
|
||||
Box::new(xr::sys::CompositionLayerColorScaleBiasKHR {
|
||||
ty: xr::StructureType::COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR,
|
||||
next: std::ptr::null(),
|
||||
color_bias: Default::default(),
|
||||
color_scale: xr::Color4f {
|
||||
r: 1.0,
|
||||
g: 1.0,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
view,
|
||||
sky: None,
|
||||
grid: None,
|
||||
grid_pose: translation_rotation_to_posef(Vec3A::ZERO, Quat::from_rotation_x(PI * -0.5)),
|
||||
grid_color_scale_bias_khr: grid_color_scale_bias_khr,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -205,10 +226,6 @@ impl Skybox {
|
|||
const HI_VERT_ANGLE: f32 = 0.5 * PI;
|
||||
const LO_VERT_ANGLE: f32 = -0.5 * PI;
|
||||
|
||||
static GRID_POSE: LazyLock<xr::Posef> = LazyLock::new(|| {
|
||||
translation_rotation_to_posef(Vec3A::ZERO, Quat::from_rotation_x(PI * -0.5))
|
||||
});
|
||||
|
||||
let pose = xr::Posef {
|
||||
orientation: xr::Quaternionf::IDENTITY,
|
||||
position: xr::Vector3f {
|
||||
|
|
@ -232,9 +249,12 @@ impl Skybox {
|
|||
.lower_vertical_angle(LO_VERT_ANGLE);
|
||||
|
||||
self.grid.as_mut().unwrap().ensure_image_released()?;
|
||||
let grid = xr::CompositionLayerQuad::new()
|
||||
.layer_flags(xr::CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA)
|
||||
.pose(*GRID_POSE)
|
||||
|
||||
let flags = xr::CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA
|
||||
| xr::CompositionLayerFlags::UNPREMULTIPLIED_ALPHA;
|
||||
let mut grid = xr::CompositionLayerQuad::new()
|
||||
.layer_flags(flags)
|
||||
.pose(self.grid_pose)
|
||||
.size(xr::Extent2Df {
|
||||
width: 10.0,
|
||||
height: 10.0,
|
||||
|
|
@ -243,6 +263,15 @@ impl Skybox {
|
|||
.eye_visibility(xr::EyeVisibility::BOTH)
|
||||
.space(&xr.stage);
|
||||
|
||||
if let Some(grid_color_scale_bias_khr) = self.grid_color_scale_bias_khr.as_mut() {
|
||||
let grid_opacity = app.session.config.grid_opacity;
|
||||
grid_color_scale_bias_khr.color_scale.a = (grid_opacity * grid_opacity).clamp(0.0, 1.0);
|
||||
unsafe {
|
||||
let raw = next_chain_insert!(grid, grid_color_scale_bias_khr);
|
||||
grid = xr::CompositionLayerQuad::from_raw(raw);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(vec![
|
||||
CompositionLayer::Equirect2(sky),
|
||||
CompositionLayer::Quad(grid),
|
||||
|
|
@ -254,5 +283,5 @@ pub(super) fn create_skybox(xr: &XrState, app: &AppState) -> Option<Skybox> {
|
|||
xr.instance
|
||||
.exts()
|
||||
.khr_composition_layer_equirect2
|
||||
.and_then(|_| Skybox::new(app).ok())
|
||||
.and_then(|_| Skybox::new(xr, app).ok())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ pub struct AutoSettings {
|
|||
pub block_poses_on_kbd_interaction: bool,
|
||||
pub space_drag_multiplier: f32,
|
||||
pub use_skybox: bool,
|
||||
pub grid_opacity: f32,
|
||||
pub use_passthrough: bool,
|
||||
pub screen_render_down: bool,
|
||||
pub pointer_lerp_factor: f32,
|
||||
|
|
@ -180,6 +181,7 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
|
|||
block_poses_on_kbd_interaction: config.block_poses_on_kbd_interaction,
|
||||
space_drag_multiplier: config.space_drag_multiplier,
|
||||
use_skybox: config.use_skybox,
|
||||
grid_opacity: config.grid_opacity,
|
||||
use_passthrough: config.use_passthrough,
|
||||
screen_render_down: config.screen_render_down,
|
||||
pointer_lerp_factor: config.pointer_lerp_factor,
|
||||
|
|
|
|||
|
|
@ -130,6 +130,14 @@ pub(super) fn setup_custom_label<S: 'static>(
|
|||
.ok()
|
||||
}),
|
||||
format: format.into(),
|
||||
locale: {
|
||||
let i18n = app.wgui_globals.i18n();
|
||||
let locale = i18n.get_locale();
|
||||
match pure_rust_locales::Locale::try_from(locale.to_string().as_str()) {
|
||||
Ok(loc) => loc,
|
||||
Err(_) => pure_rust_locales::Locale::en_US,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Box::new(move |common, data, _, _| {
|
||||
|
|
@ -213,6 +221,7 @@ fn battery_on_tick(
|
|||
struct ClockLabelState {
|
||||
timezone: Option<Tz>,
|
||||
format: Rc<str>,
|
||||
locale: chrono::Locale,
|
||||
}
|
||||
|
||||
fn clock_on_tick(
|
||||
|
|
@ -221,8 +230,20 @@ fn clock_on_tick(
|
|||
data: &mut event::CallbackData,
|
||||
) {
|
||||
let date_time = state.timezone.as_ref().map_or_else(
|
||||
|| format!("{}", Local::now().format(&state.format)),
|
||||
|tz| format!("{}", Local::now().with_timezone(tz).format(&state.format)),
|
||||
|| {
|
||||
format!(
|
||||
"{}",
|
||||
Local::now().format_localized(&state.format, state.locale)
|
||||
)
|
||||
},
|
||||
|tz| {
|
||||
format!(
|
||||
"{}",
|
||||
Local::now()
|
||||
.with_timezone(tz)
|
||||
.format_localized(&state.format, state.locale)
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let label = data.obj.get_as_mut::<WidgetLabel>().unwrap();
|
||||
|
|
|
|||
|
|
@ -147,8 +147,9 @@ impl<S: 'static> GuiPanel<S> {
|
|||
|
||||
let (mut layout, mut parser_state) = wgui::parser::new_layout_from_assets(
|
||||
&doc_params,
|
||||
&LayoutParams {
|
||||
LayoutParams {
|
||||
resize_to_parent: params.resize_to_parent,
|
||||
theme: app.wgui_theme.clone(),
|
||||
},
|
||||
)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -77,14 +77,12 @@ impl DashFrontend {
|
|||
let _ = interface.process_launch(app, false, p)?;
|
||||
}
|
||||
|
||||
let frontend = frontend::Frontend::new(
|
||||
frontend::InitParams {
|
||||
interface: Box::new(interface),
|
||||
lang_provider: &WayVRLangProvider::from_config(&app.session.config),
|
||||
has_monado: matches!(app.xr_backend, XrBackend::OpenXR),
|
||||
},
|
||||
app,
|
||||
)?;
|
||||
let frontend = frontend::Frontend::new(frontend::InitParams {
|
||||
interface: Box::new(interface),
|
||||
lang_provider: &WayVRLangProvider::from_config(&app.session.config),
|
||||
has_monado: matches!(app.xr_backend, XrBackend::OpenXR),
|
||||
theme: app.wgui_theme.clone(),
|
||||
})?;
|
||||
|
||||
frontend
|
||||
.tasks
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use wgui::{
|
|||
widget::rectangle::WidgetRectangle,
|
||||
};
|
||||
|
||||
use crate::{backend::task::ModifyOverlayTask, overlays::edit::EditModeWrapPanel, state::AppState};
|
||||
use crate::{backend::task::ModifyOverlayTask, overlays::edit::EditModeWrapPanel};
|
||||
|
||||
#[derive(Default)]
|
||||
pub(super) struct InteractLockHandler {
|
||||
|
|
@ -53,21 +53,18 @@ impl InteractLockHandler {
|
|||
button.set_sticky_state(common, !interactable);
|
||||
}
|
||||
|
||||
let globals = common.state.globals.get();
|
||||
if interactable {
|
||||
set_anim_color(&mut rect, 0.0, self.color, globals.defaults.danger_color);
|
||||
set_anim_color(&mut rect, 0.0, self.color, common.state.theme.danger_color);
|
||||
} else {
|
||||
set_anim_color(&mut rect, 0.2, self.color, globals.defaults.danger_color);
|
||||
set_anim_color(&mut rect, 0.2, self.color, common.state.theme.danger_color);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle(
|
||||
&mut self,
|
||||
common: &mut CallbackDataCommon,
|
||||
app: &mut AppState,
|
||||
anim_mult: f32,
|
||||
) -> Box<ModifyOverlayTask> {
|
||||
let defaults = app.wgui_globals.defaults().clone();
|
||||
let rect_color = self.color;
|
||||
|
||||
self.interactable = !self.interactable;
|
||||
|
|
@ -86,7 +83,7 @@ impl InteractLockHandler {
|
|||
rect,
|
||||
0.2 - (data.pos * 0.2),
|
||||
rect_color,
|
||||
defaults.danger_color,
|
||||
common.state.theme.danger_color,
|
||||
);
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
|
|
@ -98,7 +95,12 @@ impl InteractLockHandler {
|
|||
AnimationEasing::OutBack,
|
||||
Box::new(move |common, data| {
|
||||
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
|
||||
set_anim_color(rect, data.pos * 0.2, rect_color, defaults.danger_color);
|
||||
set_anim_color(
|
||||
rect,
|
||||
data.pos * 0.2,
|
||||
rect_color,
|
||||
common.state.theme.danger_color,
|
||||
);
|
||||
common.alterables.mark_redraw();
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
|||
mouse: SpriteTabHandler::default(),
|
||||
};
|
||||
|
||||
let anim_mult = app.wgui_globals.defaults().animation_mult;
|
||||
let anim_mult = app.wgui_theme.animation_mult;
|
||||
|
||||
let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, parser, attribs, _app| {
|
||||
let Ok(button) =
|
||||
|
|
@ -302,7 +302,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
|||
}
|
||||
|
||||
let sel = OverlaySelector::Id(*state.id.borrow());
|
||||
let task = state.lock.toggle(common, app, anim_mult);
|
||||
let task = state.lock.toggle(common, anim_mult);
|
||||
app.tasks
|
||||
.enqueue(TaskType::Overlay(OverlayTask::Modify(sel, task)));
|
||||
Ok(EventResult::Consumed)
|
||||
|
|
|
|||
|
|
@ -51,11 +51,9 @@ pub(super) fn create_keyboard_panel(
|
|||
|
||||
let doc_params = new_doc_params(&mut panel);
|
||||
|
||||
let globals = app.wgui_globals.clone();
|
||||
|
||||
let (accent_color, anim_mult) = {
|
||||
let def = globals.defaults();
|
||||
(def.accent_color, def.animation_mult)
|
||||
let theme = &app.wgui_theme;
|
||||
(theme.accent_color, theme.animation_mult)
|
||||
};
|
||||
|
||||
let root = panel
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@
|
|||
## If disabled, there will be no background rendered (solid black).
|
||||
#use_skybox: true
|
||||
|
||||
## Monado/WiVRn only. Opacity of the floor grid if use_skybox is enabled.
|
||||
#grid_opacity: true
|
||||
|
||||
## Hide the help popup that appears on your hand while grabbing an overlay
|
||||
#hide_grab_help: false
|
||||
|
||||
|
|
|
|||
|
|
@ -16,4 +16,3 @@ void main()
|
|||
}
|
||||
out_color = vec4(1.0, 1.0, 1.0, grid * fade);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use glam::Affine3A;
|
||||
use idmap::IdMap;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use wgui::log::LogErr;
|
||||
use wgui::theme::WguiTheme;
|
||||
use wgui::{
|
||||
drawing, font_config::WguiFontConfig, gfx::WGfx, globals::WguiGlobals, parser::parse_color_hex,
|
||||
renderer_vk::context::SharedContext as WSharedContext,
|
||||
|
|
@ -48,6 +50,7 @@ pub struct AppState {
|
|||
pub anchor_grabbed: bool,
|
||||
|
||||
pub wgui_globals: WguiGlobals,
|
||||
pub wgui_theme: Rc<WguiTheme>,
|
||||
|
||||
pub dbus: DbusConnector,
|
||||
|
||||
|
|
@ -90,7 +93,7 @@ impl AppState {
|
|||
let osc_sender = crate::subsystem::osc::OscSender::new(session.config.osc_out_port).ok();
|
||||
|
||||
let wgui_shared = WSharedContext::new(gfx.clone())?;
|
||||
let theme = session.config.theme_path.clone();
|
||||
let theme_path = session.config.theme_path.clone();
|
||||
|
||||
let mut audio_sample_player = audio::SamplePlayer::new();
|
||||
audio_sample_player.register_sample(
|
||||
|
|
@ -112,7 +115,7 @@ impl AppState {
|
|||
let mut assets = Box::new(gui::asset::GuiAsset {});
|
||||
audio_sample_player.register_wgui_samples(assets.as_mut())?;
|
||||
|
||||
let mut defaults = wgui::globals::Defaults::default();
|
||||
let mut theme = WguiTheme::default();
|
||||
|
||||
{
|
||||
#[allow(clippy::ref_option)]
|
||||
|
|
@ -122,15 +125,15 @@ impl AppState {
|
|||
}
|
||||
}
|
||||
|
||||
apply_color(&mut defaults.text_color, &session.config.color_text);
|
||||
apply_color(&mut defaults.accent_color, &session.config.color_accent);
|
||||
apply_color(&mut defaults.danger_color, &session.config.color_danger);
|
||||
apply_color(&mut defaults.faded_color, &session.config.color_faded);
|
||||
apply_color(&mut defaults.bg_color, &session.config.color_background);
|
||||
apply_color(&mut theme.text_color, &session.config.color_text);
|
||||
apply_color(&mut theme.accent_color, &session.config.color_accent);
|
||||
apply_color(&mut theme.danger_color, &session.config.color_danger);
|
||||
apply_color(&mut theme.faded_color, &session.config.color_faded);
|
||||
apply_color(&mut theme.bg_color, &session.config.color_background);
|
||||
}
|
||||
|
||||
defaults.animation_mult = 1. / session.config.ui_animation_speed;
|
||||
defaults.rounding_mult = session.config.ui_round_multiplier;
|
||||
theme.animation_mult = 1. / session.config.ui_animation_speed;
|
||||
theme.rounding_mult = session.config.ui_round_multiplier;
|
||||
|
||||
let dbus = DbusConnector::default();
|
||||
|
||||
|
|
@ -157,10 +160,10 @@ impl AppState {
|
|||
wgui_globals: WguiGlobals::new(
|
||||
assets,
|
||||
&lang_provider,
|
||||
defaults,
|
||||
&WguiFontConfig::default(),
|
||||
get_config_file_path(&theme),
|
||||
get_config_file_path(&theme_path),
|
||||
)?,
|
||||
wgui_theme: Rc::new(theme),
|
||||
dbus,
|
||||
xr_backend,
|
||||
ipc_server,
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ _They can be used in any widget/component._
|
|||
|
||||
`width`, `height`: **float** | **percent**
|
||||
|
||||
### Advanced attributes
|
||||
## Advanced attributes
|
||||
|
||||
`interactable`: "1" | "0"
|
||||
|
||||
|
|
@ -74,6 +74,32 @@ _Used in case of overlapping pop-ups or windows, most notably applied to various
|
|||
|
||||
_Set to 1 if you want to render overlapping pop-ups to properly render your widgets in order. Wgui renders with as few Vulkan drawcalls as possible, so this is your responsibility._
|
||||
|
||||
## Default Colors
|
||||
|
||||
_These colors can be defined by the user to control the color scheme. They always exists and can be used in any place a normal color could be used._
|
||||
|
||||
`~color_text`: default: white(#FFFFFF)
|
||||
`~color_accent`: default: light blue(#21ADFF)
|
||||
`~color_danger`: default: red(#E60000)
|
||||
`~color_faded`: default: grey(#ABBDCC)
|
||||
`~color_bg`: default: black(#00121ABF) (color_background in config)
|
||||
|
||||
_Only the default colors can be changed with the following suffixes._
|
||||
|
||||
`_translucent`
|
||||
|
||||
_Halves the alpha of the color._
|
||||
|
||||
`_10`
|
||||
`_20`
|
||||
`_30`
|
||||
`_40`
|
||||
`_50`
|
||||
|
||||
_Darkens the color by multiplying it with a percentage. `~color_accent_50` Would be half of the normal brightness but the same alpha. You can't combine the suffixes_
|
||||
|
||||
### Color
|
||||
|
||||
# Widgets
|
||||
|
||||
## div widget
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ impl ComponentButton {
|
|||
}
|
||||
|
||||
pub fn set_color(&self, common: &mut CallbackDataCommon, color: Color) {
|
||||
let gradient_intensity = common.defaults().gradient_intensity;
|
||||
let gradient_intensity = common.state.theme.gradient_intensity;
|
||||
|
||||
let Some(mut rect) = common.state.widgets.get_as::<WidgetRectangle>(self.data.id_rect) else {
|
||||
return;
|
||||
|
|
@ -194,8 +194,8 @@ impl ComponentButton {
|
|||
}
|
||||
|
||||
let (anim_mult, gradient_intensity) = {
|
||||
let defaults = common.state.globals.defaults();
|
||||
(defaults.animation_mult, defaults.gradient_intensity)
|
||||
let theme = &common.state.theme;
|
||||
(theme.animation_mult, theme.gradient_intensity)
|
||||
};
|
||||
|
||||
let anim_ticks = if sticky_down { 5. } else { 10. };
|
||||
|
|
@ -247,7 +247,7 @@ fn anim_hover(
|
|||
|
||||
let bgcolor = init_color.lerp(&colors.hover_color, mult);
|
||||
|
||||
let gradient_intensity = common.globals().defaults.gradient_intensity;
|
||||
let gradient_intensity = common.state.theme.gradient_intensity;
|
||||
|
||||
//let t = Mat4::from_scale(Vec3::splat(1.0 + pos * 0.5)) * Mat4::from_rotation_z(pos * 1.0);
|
||||
|
||||
|
|
@ -416,8 +416,8 @@ fn register_event_mouse_release(
|
|||
}
|
||||
|
||||
pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Result<(WidgetPair, Rc<ComponentButton>)> {
|
||||
let globals = ess.layout.state.globals.clone();
|
||||
let mut style = params.style;
|
||||
let theme = &ess.layout.state.theme;
|
||||
|
||||
// force-override style
|
||||
style.align_items = Some(AlignItems::Center);
|
||||
|
|
@ -431,7 +431,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
let color = if let Some(color) = params.color {
|
||||
color
|
||||
} else {
|
||||
globals.defaults().button_color
|
||||
theme.button_color
|
||||
};
|
||||
|
||||
let border_color = if let Some(border_color) = params.border_color {
|
||||
|
|
@ -452,7 +452,12 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
Color::new(color.r + 0.5, color.g + 0.5, color.g + 0.5, color.a + 0.5)
|
||||
};
|
||||
|
||||
let gradient_intensity = ess.layout.state.globals.defaults().gradient_intensity;
|
||||
let gradient_intensity = theme.gradient_intensity;
|
||||
|
||||
let light_text = {
|
||||
let mult = if theme.dark_mode { color.a } else { 1.0 - color.a };
|
||||
(color.r + color.g + color.b) * mult < 1.5
|
||||
};
|
||||
|
||||
let (root, _) = ess.layout.add_child(
|
||||
ess.parent,
|
||||
|
|
@ -469,15 +474,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
|
||||
let id_rect = root.id;
|
||||
|
||||
let light_text = {
|
||||
let mult = if globals.defaults().dark_mode {
|
||||
color.a
|
||||
} else {
|
||||
1.0 - color.a
|
||||
};
|
||||
(color.r + color.g + color.b) * mult < 1.5
|
||||
};
|
||||
|
||||
let default_margin = taffy::Rect {
|
||||
top: length(4.0),
|
||||
bottom: length(4.0),
|
||||
|
|
@ -487,7 +483,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
|
||||
if let Some(sprite_path) = params.sprite_src {
|
||||
let sprite = WidgetSprite::create(WidgetSpriteParams {
|
||||
glyph_data: Some(CustomGlyphData::from_assets(&globals, sprite_path)?),
|
||||
glyph_data: Some(CustomGlyphData::from_assets(&ess.layout.state.globals, sprite_path)?),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
|
|
@ -506,23 +502,25 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
}
|
||||
|
||||
let id_label = if let Some(content) = params.text {
|
||||
let widget_label = WidgetLabel::create(
|
||||
&mut ess.layout.state,
|
||||
WidgetLabelParams {
|
||||
content,
|
||||
style: TextStyle {
|
||||
weight: Some(FontWeight::Bold),
|
||||
color: Some(if light_text {
|
||||
Color::new(1.0, 1.0, 1.0, 1.0)
|
||||
} else {
|
||||
Color::new(0.0, 0.0, 0.0, 1.0)
|
||||
}),
|
||||
..params.text_style
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
let (label, _node_label) = ess.layout.add_child(
|
||||
id_rect,
|
||||
WidgetLabel::create(
|
||||
&mut globals.get(),
|
||||
WidgetLabelParams {
|
||||
content,
|
||||
style: TextStyle {
|
||||
weight: Some(FontWeight::Bold),
|
||||
color: Some(if light_text {
|
||||
Color::new(1.0, 1.0, 1.0, 1.0)
|
||||
} else {
|
||||
Color::new(0.0, 0.0, 0.0, 1.0)
|
||||
}),
|
||||
..params.text_style
|
||||
},
|
||||
},
|
||||
),
|
||||
widget_label,
|
||||
taffy::Style {
|
||||
margin: default_margin,
|
||||
..Default::default()
|
||||
|
|
@ -558,7 +556,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
id: root.id,
|
||||
lhandles: {
|
||||
let listeners = &mut root.widget.state().event_listeners;
|
||||
let anim_mult = ess.layout.state.globals.defaults().animation_mult;
|
||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||
vec![
|
||||
register_event_mouse_enter(data.clone(), state.clone(), listeners, params.tooltip, anim_mult),
|
||||
register_event_mouse_leave(state.clone(), listeners, anim_mult),
|
||||
|
|
|
|||
|
|
@ -343,8 +343,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
(WLength::Units(5.0), WLength::Units(8.0))
|
||||
};
|
||||
|
||||
let globals = ess.layout.state.globals.clone();
|
||||
|
||||
let (root, _) = ess.layout.add_child(
|
||||
ess.parent,
|
||||
WidgetRectangle::create(WidgetRectangleParams {
|
||||
|
|
@ -397,20 +395,17 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
},
|
||||
)?;
|
||||
|
||||
let (label, _node_label) = ess.layout.add_child(
|
||||
id_container,
|
||||
WidgetLabel::create(
|
||||
&mut globals.get(),
|
||||
WidgetLabelParams {
|
||||
content: params.text,
|
||||
style: TextStyle {
|
||||
weight: Some(FontWeight::Bold),
|
||||
..Default::default()
|
||||
},
|
||||
let widget_label = WidgetLabel::create(
|
||||
&mut ess.layout.state,
|
||||
WidgetLabelParams {
|
||||
content: params.text,
|
||||
style: TextStyle {
|
||||
weight: Some(FontWeight::Bold),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
Default::default(),
|
||||
)?;
|
||||
},
|
||||
);
|
||||
let (label, _node_label) = ess.layout.add_child(id_container, widget_label, Default::default())?;
|
||||
|
||||
let data = Rc::new(Data {
|
||||
id_container,
|
||||
|
|
@ -433,7 +428,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
id: root.id,
|
||||
lhandles: {
|
||||
let listeners = &mut root.widget.state().event_listeners;
|
||||
let anim_mult = ess.layout.state.globals.defaults().animation_mult;
|
||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||
vec![
|
||||
register_event_mouse_enter(state.clone(), listeners, params.tooltip, anim_mult),
|
||||
register_event_mouse_leave(state.clone(), listeners, anim_mult),
|
||||
|
|
|
|||
|
|
@ -99,11 +99,10 @@ fn anim_bottom_rect(
|
|||
}
|
||||
|
||||
fn refresh_all(common: &mut CallbackDataCommon, data: &Data, state: &mut State) -> Option<()> {
|
||||
let defaults = common.defaults();
|
||||
let editbox_color = defaults.editbox_color;
|
||||
let anim_mult = defaults.animation_mult;
|
||||
let accent_color = defaults.accent_color;
|
||||
drop(defaults);
|
||||
let theme = &common.state.theme;
|
||||
let editbox_color = theme.editbox_color;
|
||||
let anim_mult = theme.animation_mult;
|
||||
let accent_color = theme.accent_color;
|
||||
|
||||
let (rect_color, border_color) = if state.focused {
|
||||
(editbox_color.add_rgb(0.15), editbox_color.add_rgb(0.15 + 0.25))
|
||||
|
|
@ -279,10 +278,7 @@ pub fn construct(
|
|||
ess: &mut ConstructEssentials,
|
||||
mut params: Params,
|
||||
) -> anyhow::Result<(WidgetPair, Rc<ComponentEditBox>)> {
|
||||
let globals = ess.layout.state.globals.clone();
|
||||
let defaults = globals.defaults();
|
||||
let text_color = defaults.text_color;
|
||||
drop(defaults);
|
||||
let text_color = ess.layout.state.theme.text_color;
|
||||
|
||||
if params.style.size.width.is_auto() {
|
||||
params.style.size.width = length(128.0);
|
||||
|
|
@ -345,22 +341,23 @@ pub fn construct(
|
|||
},
|
||||
)?;
|
||||
|
||||
let widget_label = WidgetLabel::create(
|
||||
&mut ess.layout.state,
|
||||
WidgetLabelParams {
|
||||
content: Translation::from_raw_text(¶ms.initial_text),
|
||||
style: TextStyle {
|
||||
shadow: Some(TextShadow {
|
||||
x: 1.0,
|
||||
y: 1.0,
|
||||
color: Color::new(0.0, 0.0, 0.0, 1.0),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
);
|
||||
let (label, _node_label) = ess.layout.add_child(
|
||||
label_parent.id,
|
||||
WidgetLabel::create(
|
||||
&mut globals.get(),
|
||||
WidgetLabelParams {
|
||||
content: Translation::from_raw_text(¶ms.initial_text),
|
||||
style: TextStyle {
|
||||
shadow: Some(TextShadow {
|
||||
x: 1.0,
|
||||
y: 1.0,
|
||||
color: Color::new(0.0, 0.0, 0.0, 1.0),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
),
|
||||
widget_label,
|
||||
taffy::Style {
|
||||
position: taffy::Position::Relative,
|
||||
..Default::default()
|
||||
|
|
|
|||
|
|
@ -498,26 +498,20 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
active_tooltip: None,
|
||||
};
|
||||
|
||||
let globals = ess.layout.state.globals.clone();
|
||||
|
||||
let slider_text: Option<(WidgetPair, taffy::NodeId)> = if params.show_value {
|
||||
let pair = ess.layout.add_child(
|
||||
slider_handle.id,
|
||||
WidgetLabel::create(
|
||||
&mut globals.get(),
|
||||
WidgetLabelParams {
|
||||
content: Translation::default(),
|
||||
style: TextStyle {
|
||||
color: Some(drawing::Color::new(0.0, 0.0, 0.0, 1.0)), // always black
|
||||
weight: Some(FontWeight::Bold),
|
||||
align: Some(HorizontalAlign::Center),
|
||||
..Default::default()
|
||||
},
|
||||
let label = WidgetLabel::create(
|
||||
&mut ess.layout.state,
|
||||
WidgetLabelParams {
|
||||
content: Translation::default(),
|
||||
style: TextStyle {
|
||||
color: Some(drawing::Color::new(0.0, 0.0, 0.0, 1.0)), // always black
|
||||
weight: Some(FontWeight::Bold),
|
||||
align: Some(HorizontalAlign::Center),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
Default::default(),
|
||||
)?;
|
||||
Some(pair)
|
||||
},
|
||||
);
|
||||
Some(ess.layout.add_child(slider_handle.id, label, Default::default())?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -535,7 +529,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
id: root.id,
|
||||
lhandles: {
|
||||
let listeners = &mut root.widget.state().event_listeners;
|
||||
let anim_mult = ess.layout.state.globals.defaults().animation_mult;
|
||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||
vec![
|
||||
register_event_mouse_enter(data.clone(), state.clone(), listeners, params.tooltip, anim_mult),
|
||||
register_event_mouse_leave(data.clone(), state.clone(), listeners, anim_mult),
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ impl ComponentTrait for ComponentTabs {
|
|||
impl State {
|
||||
fn select_entry(&mut self, common: &mut CallbackDataCommon, name: &Rc<str>) {
|
||||
let (color_accent, color_button) = {
|
||||
let def = common.state.globals.defaults();
|
||||
(def.accent_color, def.button_color)
|
||||
let theme = &common.state.theme;
|
||||
(theme.accent_color, theme.button_color)
|
||||
};
|
||||
|
||||
for entry in &self.mounted_entries {
|
||||
|
|
|
|||
|
|
@ -163,8 +163,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
),
|
||||
};
|
||||
|
||||
let globals = ess.layout.state.globals.clone();
|
||||
|
||||
let (div, _) = ess.layout.add_child(
|
||||
ess.parent,
|
||||
WidgetDiv::create(),
|
||||
|
|
@ -211,20 +209,17 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
},
|
||||
)?;
|
||||
|
||||
let (label, _) = ess.layout.add_child(
|
||||
rect.id,
|
||||
WidgetLabel::create(
|
||||
&mut globals.get(),
|
||||
WidgetLabelParams {
|
||||
content: params.info.text,
|
||||
style: TextStyle {
|
||||
weight: Some(FontWeight::Bold),
|
||||
..Default::default()
|
||||
},
|
||||
let label = WidgetLabel::create(
|
||||
&mut ess.layout.state,
|
||||
WidgetLabelParams {
|
||||
content: params.info.text,
|
||||
style: TextStyle {
|
||||
weight: Some(FontWeight::Bold),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
Default::default(),
|
||||
)?;
|
||||
},
|
||||
);
|
||||
let (label, _) = ess.layout.add_child(rect.id, label, Default::default())?;
|
||||
|
||||
let data = Rc::new(Data { id_root: div.id });
|
||||
|
||||
|
|
@ -246,7 +241,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
|||
TooltipSide::Bottom => Vec2::new(0.0, 1.0),
|
||||
};
|
||||
|
||||
let anim_mult = ess.layout.state.globals.defaults().animation_mult;
|
||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||
ess.layout.animations.add(Animation::new(
|
||||
rect.id,
|
||||
(10.0 * anim_mult) as u32,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{
|
||||
any::{Any, TypeId},
|
||||
cell::{Ref, RefMut},
|
||||
cell::RefMut,
|
||||
collections::HashSet,
|
||||
rc::{Rc, Weak},
|
||||
};
|
||||
|
|
@ -181,10 +181,6 @@ impl CallbackDataCommon<'_> {
|
|||
pub fn globals(&self) -> RefMut<'_, globals::Globals> {
|
||||
self.state.globals.get()
|
||||
}
|
||||
|
||||
pub fn defaults(&self) -> Ref<'_, globals::Defaults> {
|
||||
self.state.globals.defaults()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CallbackData<'a> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use std::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
cell::{RefCell, RefMut},
|
||||
io::Read,
|
||||
path::PathBuf,
|
||||
rc::Rc,
|
||||
|
|
@ -11,53 +11,17 @@ use regex::Regex;
|
|||
|
||||
use crate::{
|
||||
assets::{AssetPath, AssetProvider, LangProvider},
|
||||
assets_internal, drawing,
|
||||
assets_internal,
|
||||
font_config::{WguiFontConfig, WguiFontSystem},
|
||||
i18n::I18n,
|
||||
renderer_vk::text::custom_glyph::CustomGlyphCache,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Defaults {
|
||||
pub dark_mode: bool,
|
||||
pub text_color: drawing::Color,
|
||||
pub button_color: drawing::Color,
|
||||
pub accent_color: drawing::Color,
|
||||
pub danger_color: drawing::Color,
|
||||
pub faded_color: drawing::Color,
|
||||
pub bg_color: drawing::Color,
|
||||
pub editbox_color: drawing::Color,
|
||||
pub translucent_alpha: f32,
|
||||
pub animation_mult: f32,
|
||||
pub rounding_mult: f32,
|
||||
pub gradient_intensity: f32, // currently used for buttons
|
||||
}
|
||||
|
||||
impl Default for Defaults {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dark_mode: true,
|
||||
text_color: drawing::Color::new(1.0, 1.0, 1.0, 1.0),
|
||||
button_color: drawing::Color::new(1.0, 1.0, 1.0, 0.02),
|
||||
accent_color: drawing::Color::new(0.13, 0.68, 1.0, 1.0),
|
||||
danger_color: drawing::Color::new(0.9, 0.0, 0.0, 1.0),
|
||||
faded_color: drawing::Color::new(0.67, 0.74, 0.80, 1.0),
|
||||
bg_color: drawing::Color::new(0.0, 0.07, 0.1, 0.75),
|
||||
editbox_color: drawing::Color::new(0.15, 0.25, 0.35, 0.95),
|
||||
translucent_alpha: 0.5,
|
||||
animation_mult: 1.0,
|
||||
rounding_mult: 1.0,
|
||||
gradient_intensity: 0.3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Globals {
|
||||
pub assets_internal: Box<dyn AssetProvider>,
|
||||
pub assets_builtin: Box<dyn AssetProvider>,
|
||||
pub asset_folder: PathBuf,
|
||||
pub i18n_builtin: I18n,
|
||||
pub defaults: Defaults,
|
||||
pub font_system: WguiFontSystem,
|
||||
pub custom_glyph_cache: CustomGlyphCache,
|
||||
}
|
||||
|
|
@ -69,7 +33,6 @@ impl WguiGlobals {
|
|||
pub fn new(
|
||||
mut assets_builtin: Box<dyn AssetProvider>,
|
||||
lang_provider: &dyn LangProvider,
|
||||
defaults: Defaults,
|
||||
font_config: &WguiFontConfig,
|
||||
asset_folder: PathBuf,
|
||||
) -> anyhow::Result<Self> {
|
||||
|
|
@ -79,7 +42,6 @@ impl WguiGlobals {
|
|||
Ok(Self(Rc::new(RefCell::new(Globals {
|
||||
assets_internal,
|
||||
assets_builtin,
|
||||
defaults,
|
||||
asset_folder,
|
||||
font_system: WguiFontSystem::new(font_config, i18n_builtin.get_locale()),
|
||||
i18n_builtin,
|
||||
|
|
@ -128,10 +90,6 @@ impl WguiGlobals {
|
|||
RefMut::map(self.0.borrow_mut(), |x| &mut x.i18n_builtin)
|
||||
}
|
||||
|
||||
pub fn defaults(&self) -> Ref<'_, Defaults> {
|
||||
Ref::map(self.0.borrow(), |x| &x.defaults)
|
||||
}
|
||||
|
||||
pub fn assets_internal(&self) -> RefMut<'_, Box<dyn AssetProvider>> {
|
||||
RefMut::map(self.0.borrow_mut(), |x| &mut x.assets_internal)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,13 +123,7 @@ impl Locale {
|
|||
|
||||
// check if forced language is set
|
||||
if let Some(forced_lang) = lang_provider.forced_lang() {
|
||||
let matched =
|
||||
Self::match_locale(default_lang, forced_lang, None, lang_provider.langs_list().all_locale()).to_string();
|
||||
return Self {
|
||||
lang: forced_lang.to_string(),
|
||||
region: None,
|
||||
matched,
|
||||
};
|
||||
return Self::parse_str(lang_provider.langs_list(), forced_lang);
|
||||
}
|
||||
|
||||
// fallback to environment variables
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use crate::{
|
|||
globals::WguiGlobals,
|
||||
sound::WguiSoundType,
|
||||
task::Tasks,
|
||||
theme::WguiTheme,
|
||||
widget::{self, EventParams, EventResult, WidgetObj, WidgetState, WidgetStateFlags, div::WidgetDiv},
|
||||
};
|
||||
|
||||
|
|
@ -118,6 +119,7 @@ impl WidgetMap {
|
|||
|
||||
pub struct LayoutState {
|
||||
pub globals: WguiGlobals,
|
||||
pub theme: Rc<WguiTheme>,
|
||||
pub widgets: WidgetMap,
|
||||
pub nodes: WidgetNodeMap,
|
||||
pub tree: taffy::tree::TaffyTree<WidgetID>,
|
||||
|
|
@ -185,6 +187,7 @@ pub struct Layout {
|
|||
#[derive(Default)]
|
||||
pub struct LayoutParams {
|
||||
pub resize_to_parent: bool,
|
||||
pub theme: Rc<WguiTheme>,
|
||||
}
|
||||
|
||||
fn add_child_internal(
|
||||
|
|
@ -526,12 +529,13 @@ impl Layout {
|
|||
Ok(event_result)
|
||||
}
|
||||
|
||||
pub fn new(globals: WguiGlobals, params: &LayoutParams) -> anyhow::Result<Self> {
|
||||
pub fn new(globals: WguiGlobals, params: LayoutParams) -> anyhow::Result<Self> {
|
||||
let mut state = LayoutState {
|
||||
tree: TaffyTree::new(),
|
||||
widgets: WidgetMap::new(),
|
||||
nodes: WidgetNodeMap::default(),
|
||||
globals,
|
||||
theme: params.theme,
|
||||
};
|
||||
|
||||
let size = if params.resize_to_parent {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ pub mod renderer_vk;
|
|||
pub mod sound;
|
||||
pub mod stack;
|
||||
pub mod task;
|
||||
pub mod theme;
|
||||
pub mod widget;
|
||||
pub mod windowing;
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ pub fn parse_component_button<'a>(
|
|||
key,
|
||||
value,
|
||||
&mut round,
|
||||
ctx.doc_params.globals.defaults().rounding_mult,
|
||||
ctx.layout.state.theme.rounding_mult,
|
||||
);
|
||||
}
|
||||
"color" => {
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@ impl ParserContext<'_> {
|
|||
}
|
||||
|
||||
fn populate_theme_variables(&mut self) {
|
||||
let def = self.doc_params.globals.defaults();
|
||||
let theme = self.layout.state.theme.clone();
|
||||
|
||||
macro_rules! insert_color_vars {
|
||||
($self:expr, $name:literal, $field:expr, $alpha:expr) => {
|
||||
|
|
@ -479,11 +479,11 @@ impl ParserContext<'_> {
|
|||
};
|
||||
}
|
||||
|
||||
insert_color_vars!(self, "text", def.text_color, def.translucent_alpha);
|
||||
insert_color_vars!(self, "accent", def.accent_color, def.translucent_alpha);
|
||||
insert_color_vars!(self, "danger", def.danger_color, def.translucent_alpha);
|
||||
insert_color_vars!(self, "faded", def.faded_color, def.translucent_alpha);
|
||||
insert_color_vars!(self, "bg", def.bg_color, def.translucent_alpha);
|
||||
insert_color_vars!(self, "text", theme.text_color, theme.translucent_alpha);
|
||||
insert_color_vars!(self, "accent", theme.accent_color, theme.translucent_alpha);
|
||||
insert_color_vars!(self, "danger", theme.danger_color, theme.translucent_alpha);
|
||||
insert_color_vars!(self, "faded", theme.faded_color, theme.translucent_alpha);
|
||||
insert_color_vars!(self, "bg", theme.bg_color, theme.translucent_alpha);
|
||||
}
|
||||
|
||||
fn print_invalid_attrib(&self, tag_name: &str, key: &str, value: &str) {
|
||||
|
|
@ -1232,7 +1232,7 @@ pub fn parse_from_assets(
|
|||
|
||||
pub fn new_layout_from_assets(
|
||||
doc_params: &ParseDocumentParams,
|
||||
layout_params: &LayoutParams,
|
||||
layout_params: LayoutParams,
|
||||
) -> anyhow::Result<(Layout, ParserState)> {
|
||||
let mut layout = Layout::new(doc_params.globals.clone(), layout_params)?;
|
||||
let widget = layout.content_root_widget;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pub fn parse_widget_image<'a>(
|
|||
key,
|
||||
value,
|
||||
&mut params.round,
|
||||
ctx.doc_params.globals.defaults().rounding_mult,
|
||||
ctx.layout.state.theme.rounding_mult,
|
||||
);
|
||||
}
|
||||
"border" => {
|
||||
|
|
|
|||
|
|
@ -45,11 +45,8 @@ pub fn parse_widget_label<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let globals = ctx.layout.state.globals.clone();
|
||||
|
||||
let (widget, _) = ctx
|
||||
.layout
|
||||
.add_child(parent_id, WidgetLabel::create(&mut globals.get(), params), style)?;
|
||||
let label = WidgetLabel::create(&mut ctx.layout.state, params);
|
||||
let (widget, _) = ctx.layout.add_child(parent_id, label, style)?;
|
||||
|
||||
parse_widget_universal(ctx, &widget, attribs, tag_name);
|
||||
parse_children(file, ctx, node, widget.id)?;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ pub fn parse_widget_rectangle<'a>(
|
|||
key,
|
||||
value,
|
||||
&mut params.round,
|
||||
ctx.doc_params.globals.defaults().rounding_mult,
|
||||
ctx.layout.state.theme.rounding_mult,
|
||||
);
|
||||
}
|
||||
"border" => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
use crate::drawing;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WguiTheme {
|
||||
pub dark_mode: bool,
|
||||
pub text_color: drawing::Color,
|
||||
pub button_color: drawing::Color,
|
||||
pub accent_color: drawing::Color,
|
||||
pub danger_color: drawing::Color,
|
||||
pub faded_color: drawing::Color,
|
||||
pub bg_color: drawing::Color,
|
||||
pub editbox_color: drawing::Color,
|
||||
pub translucent_alpha: f32,
|
||||
pub animation_mult: f32,
|
||||
pub rounding_mult: f32,
|
||||
pub gradient_intensity: f32, // currently used for buttons
|
||||
}
|
||||
|
||||
impl Default for WguiTheme {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dark_mode: true,
|
||||
text_color: drawing::Color::new(1.0, 1.0, 1.0, 1.0),
|
||||
button_color: drawing::Color::new(1.0, 1.0, 1.0, 0.02),
|
||||
accent_color: drawing::Color::new(0.13, 0.68, 1.0, 1.0),
|
||||
danger_color: drawing::Color::new(0.9, 0.0, 0.0, 1.0),
|
||||
faded_color: drawing::Color::new(0.67, 0.74, 0.80, 1.0),
|
||||
bg_color: drawing::Color::new(0.0, 0.07, 0.1, 0.75),
|
||||
editbox_color: drawing::Color::new(0.15, 0.25, 0.35, 0.95),
|
||||
translucent_alpha: 0.5,
|
||||
animation_mult: 1.0,
|
||||
rounding_mult: 1.0,
|
||||
gradient_intensity: 0.3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,8 +9,9 @@ use crate::{
|
|||
event::CallbackDataCommon,
|
||||
globals::Globals,
|
||||
i18n::Translation,
|
||||
layout::WidgetID,
|
||||
layout::{LayoutState, WidgetID},
|
||||
renderer_vk::text::TextStyle,
|
||||
theme::WguiTheme,
|
||||
widget::WidgetStateFlags,
|
||||
};
|
||||
|
||||
|
|
@ -31,9 +32,13 @@ pub struct WidgetLabel {
|
|||
}
|
||||
|
||||
impl WidgetLabel {
|
||||
pub fn create(globals: &mut Globals, mut params: WidgetLabelParams) -> WidgetState {
|
||||
pub fn create(state: &mut LayoutState, params: WidgetLabelParams) -> WidgetState {
|
||||
WidgetLabel::create_ex(&mut state.globals.get(), &state.theme, params)
|
||||
}
|
||||
|
||||
pub fn create_ex(globals: &mut Globals, theme: &WguiTheme, mut params: WidgetLabelParams) -> WidgetState {
|
||||
if params.style.color.is_none() {
|
||||
params.style.color = Some(globals.defaults.text_color);
|
||||
params.style.color = Some(theme.text_color);
|
||||
}
|
||||
|
||||
let metrics = Metrics::from(¶ms.style);
|
||||
|
|
|
|||
|
|
@ -324,4 +324,7 @@ pub struct GeneralConfig {
|
|||
|
||||
#[serde(default)]
|
||||
pub handsfree_pointer: HandsfreePointer,
|
||||
|
||||
#[serde(default = "def_one")]
|
||||
pub grid_opacity: f32,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ use crate::config::GeneralConfig;
|
|||
pub enum Language {
|
||||
#[strum(props(Text = "English"))]
|
||||
English,
|
||||
#[strum(props(Text = "English(UK)"))]
|
||||
British,
|
||||
#[strum(props(Text = "Polski"))]
|
||||
Polish,
|
||||
#[strum(props(Text = "日本語"))]
|
||||
|
|
@ -26,13 +28,14 @@ pub enum Language {
|
|||
impl Language {
|
||||
pub const fn code(&self) -> &'static str {
|
||||
match self {
|
||||
Language::English => "en",
|
||||
Language::Polish => "pl",
|
||||
Language::Japanese => "ja",
|
||||
Language::German => "de",
|
||||
Language::Italian => "it",
|
||||
Language::English => "en_US",
|
||||
Language::British => "en_GB",
|
||||
Language::Polish => "pl_PL",
|
||||
Language::Japanese => "ja_JP",
|
||||
Language::German => "de_DE",
|
||||
Language::Italian => "it_IT",
|
||||
Language::ChineseSimplified => "zh_CN",
|
||||
Language::Spanish => "es",
|
||||
Language::Spanish => "es_ES",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue