display_options::View done

This commit is contained in:
Aleksander
2025-12-20 13:54:09 +01:00
parent e81c3945e6
commit 5462e84995
15 changed files with 370 additions and 151 deletions

View File

@@ -0,0 +1,15 @@
<layout>
<include src="../t_group_box.xml" />
<elements>
<div gap="16" flex_direction="column" width="100%" justify_self="center" align_items="center" justify_content="center">
<rectangle macro="group_box" align_items="center">
<div id="display_parent" />
<div gap="8">
<Button id="btn_remove" translation="REMOVE" sprite_src_builtin="dashboard/remove_circle.svg" />
<Button id="btn_show_hide" text="showhide" sprite_src_builtin="dashboard/eye.svg" />
</div>
</rectangle>
</div>
</elements>
</layout>

View File

@@ -55,5 +55,9 @@
}, },
"WIDTH": "Breite", "WIDTH": "Breite",
"HEIGHT": "Höhe", "HEIGHT": "Höhe",
"DISPLAY_PORTRAIT_MODE": "Porträtmodus" "DISPLAY_PORTRAIT_MODE": "Porträtmodus",
"HIDE": "Verbergen",
"REMOVE": "Entfernen",
"SHOW": "Anzeigen",
"DISPLAY_OPTIONS": "Anzeigeeinstellungen"
} }

View File

@@ -3,7 +3,6 @@
"RECENTER_PLAYSPACE": "Re-center playspace" "RECENTER_PLAYSPACE": "Re-center playspace"
}, },
"ADD_DISPLAY": "Add display", "ADD_DISPLAY": "Add display",
"DISPLAY_PORTRAIT_MODE": "Portrait mode",
"APP_SETTINGS": { "APP_SETTINGS": {
"BRIGHTNESS": "Brightness", "BRIGHTNESS": "Brightness",
"HEADSET_SETTINGS": "Headset settings", "HEADSET_SETTINGS": "Headset settings",
@@ -40,11 +39,14 @@
"SPEAKERS_SET_SUCCESSFULLY": "Speakers set successfully", "SPEAKERS_SET_SUCCESSFULLY": "Speakers set successfully",
"VOLUME": "Volume" "VOLUME": "Volume"
}, },
"DISPLAY_OPTIONS": "Display options",
"DISPLAY_PORTRAIT_MODE": "Portrait mode",
"GAMES": "Games", "GAMES": "Games",
"GENERAL_SETTINGS": "General settings", "GENERAL_SETTINGS": "General settings",
"HEIGHT": "Height", "HEIGHT": "Height",
"HELLO": "Hello!", "HELLO": "Hello!",
"HELLO_USER": "Hello, {USER}!", "HELLO_USER": "Hello, {USER}!",
"HIDE": "Hide",
"HOME_SCREEN": "Home", "HOME_SCREEN": "Home",
"LIST_OF_DISPLAYS": "Display list", "LIST_OF_DISPLAYS": "Display list",
"LIST_OF_PROCESSES": "Process list", "LIST_OF_PROCESSES": "Process list",
@@ -54,6 +56,8 @@
"RESOLUTION": "Resolution" "RESOLUTION": "Resolution"
}, },
"PROCESSES": "Processes", "PROCESSES": "Processes",
"REMOVE": "Remove",
"SETTINGS": "Settings", "SETTINGS": "Settings",
"SHOW": "Show",
"WIDTH": "Width" "WIDTH": "Width"
} }

View File

@@ -55,5 +55,9 @@
}, },
"WIDTH": "Ancho", "WIDTH": "Ancho",
"HEIGHT": "Altura", "HEIGHT": "Altura",
"DISPLAY_PORTRAIT_MODE": "Modo retrato" "DISPLAY_PORTRAIT_MODE": "Modo retrato",
"HIDE": "Ocultar",
"REMOVE": "Eliminar",
"SHOW": "Mostrar",
"DISPLAY_OPTIONS": "Opciones de pantalla"
} }

View File

@@ -55,5 +55,9 @@
}, },
"WIDTH": "幅", "WIDTH": "幅",
"HEIGHT": "高さ", "HEIGHT": "高さ",
"DISPLAY_PORTRAIT_MODE": "縦向きモード" "DISPLAY_PORTRAIT_MODE": "縦向きモード",
"HIDE": "隠す",
"REMOVE": "削除",
"SHOW": "表示",
"DISPLAY_OPTIONS": "表示オプション"
} }

View File

@@ -1,59 +1,63 @@
{ {
"HOME_SCREEN": "Ekran główny",
"MONADO_RUNTIME": "Środowisko Monado",
"APPLICATIONS": "Aplikacje",
"GAMES": "Gry",
"SETTINGS": "Ustawienia",
"PROCESSES": "Procesy",
"HELLO_USER": "Witaj, {USER}!",
"GENERAL_SETTINGS": "Ustawienia ogólne",
"APPLICATION_LAUNCHER": "Uruchamiacz aplikacji",
"APP_SETTINGS": {
"HIDE_USERNAME": "Ukryj nazwę użytkownika",
"OPAQUE_BACKGROUND": "Nieprzezroczyste tło",
"RUN_IN_XWAYLAND_MODE_BY_DEFAULT": "Uruchom domyślnie w trybie XWayland",
"WLX_OVERLAY_S_SETTINGS": "Ustawienia wlx-overlay-s",
"HEADSET_SETTINGS": "Ustawienia HMD",
"BRIGHTNESS": "Jasność",
"WLX": {
"NOTIFICATIONS_ENABLED": "Powiadomienia",
"NOTIFICATIONS_SOUND_ENABLED": "Dźwięk powiadomień",
"KEYBOARD_SOUND_ENABLED": "Dźwięki klawiatury",
"BLOCK_GAME_INPUT": "Zablokuj sterowanie grą podczas używania Wlx",
"SPACE_DRAG_MULTIPLIER": "Mnożnik space-drag",
"SPACE_DRAG_ROTATION_ENABLED": "Włącz rotację w space-drag",
"SHOW_SKYBOX": "Pokaż skybox",
"ENABLE_PASSTHROUGH": "Włącz passthrough"
},
"RESTART_SOFTWARE": "Uruchom ponownie oprogramowanie"
},
"HELLO": "Witaj!",
"AUDIO": {
"VOLUME": "Głośność",
"SETTINGS": "Ustawienia dźwięku",
"AUTO_SWITCH_TO_VR_AUDIO": "Automatyczne przełączanie na dźwięk VR",
"SPEAKERS": "Głośniki",
"MICROPHONES": "Mikrofony",
"CARDS": "Karty",
"SELECT_AUDIO_CARD_PROFILE": "Wybierz profil karty dźwiękowej",
"NO_VR_SPEAKERS_FOUND_SWITCH_MANUALLY": "Brak głośników VR. Włącz je ręcznie.",
"NO_VR_MICROPHONE_SWITCH_MANUALLY": "Brak mikrofonu VR. Włącz go ręcznie.",
"FAILED_TO_SWITCH_MICROPHONE": "Nie udało się przełączyć mikrofon",
"MICROPHONE_SET_SUCCESSFULLY": "Mikrofon ustawiono pomyślnie",
"SPEAKERS_SET_SUCCESSFULLY": "Głośniki ustawiono pomyślnie",
"DEVICE_FOUND_AND_INITIALIZED_BUT_NOT_SWITCHED": "Urządzenie znalezione i zainicjalizowane, ale nie przełączone"
},
"ACTIONS": { "ACTIONS": {
"RECENTER_PLAYSPACE": "Wycentruj przestrzeń" "RECENTER_PLAYSPACE": "Wycentruj przestrzeń"
}, },
"ADD_DISPLAY": "Dodaj monitor",
"APP_SETTINGS": {
"BRIGHTNESS": "Jasność",
"HEADSET_SETTINGS": "Ustawienia HMD",
"HIDE_USERNAME": "Ukryj nazwę użytkownika",
"OPAQUE_BACKGROUND": "Nieprzezroczyste tło",
"RESTART_SOFTWARE": "Uruchom ponownie oprogramowanie",
"RUN_IN_XWAYLAND_MODE_BY_DEFAULT": "Uruchom domyślnie w trybie XWayland",
"WLX": {
"BLOCK_GAME_INPUT": "Zablokuj sterowanie grą podczas używania Wlx",
"ENABLE_PASSTHROUGH": "Włącz passthrough",
"KEYBOARD_SOUND_ENABLED": "Dźwięki klawiatury",
"NOTIFICATIONS_ENABLED": "Powiadomienia",
"NOTIFICATIONS_SOUND_ENABLED": "Dźwięk powiadomień",
"SHOW_SKYBOX": "Pokaż skybox",
"SPACE_DRAG_MULTIPLIER": "Mnożnik space-drag",
"SPACE_DRAG_ROTATION_ENABLED": "Włącz rotację w space-drag"
},
"WLX_OVERLAY_S_SETTINGS": "Ustawienia wlx-overlay-s"
},
"APPLICATION_LAUNCHER": "Uruchamiacz aplikacji",
"APPLICATIONS": "Aplikacje",
"AUDIO": {
"AUTO_SWITCH_TO_VR_AUDIO": "Automatyczne przełączanie na dźwięk VR",
"CARDS": "Karty",
"DEVICE_FOUND_AND_INITIALIZED_BUT_NOT_SWITCHED": "Urządzenie znalezione i zainicjalizowane, ale nie przełączone",
"FAILED_TO_SWITCH_MICROPHONE": "Nie udało się przełączyć mikrofon",
"MICROPHONE_SET_SUCCESSFULLY": "Mikrofon ustawiono pomyślnie",
"MICROPHONES": "Mikrofony",
"NO_VR_MICROPHONE_SWITCH_MANUALLY": "Brak mikrofonu VR. Włącz go ręcznie.",
"NO_VR_SPEAKERS_FOUND_SWITCH_MANUALLY": "Brak głośników VR. Włącz je ręcznie.",
"SELECT_AUDIO_CARD_PROFILE": "Wybierz profil karty dźwiękowej",
"SETTINGS": "Ustawienia dźwięku",
"SPEAKERS": "Głośniki",
"SPEAKERS_SET_SUCCESSFULLY": "Głośniki ustawiono pomyślnie",
"VOLUME": "Głośność"
},
"DISPLAY_OPTIONS": "Opcje monitora",
"DISPLAY_PORTRAIT_MODE": "Tryb pionowy",
"GAMES": "Gry",
"GENERAL_SETTINGS": "Ustawienia ogólne",
"HEIGHT": "Wysokość",
"HELLO": "Witaj!",
"HELLO_USER": "Witaj, {USER}!",
"HIDE": "Ukryj",
"HOME_SCREEN": "Ekran główny",
"LIST_OF_DISPLAYS": "Lista monitorów", "LIST_OF_DISPLAYS": "Lista monitorów",
"LIST_OF_PROCESSES": "Lista procesów", "LIST_OF_PROCESSES": "Lista procesów",
"MONADO_RUNTIME": "Środowisko Monado",
"NO_DISPLAYS_FOUND": "Brak monitorów", "NO_DISPLAYS_FOUND": "Brak monitorów",
"ADD_DISPLAY": "Dodaj monitor",
"POPUP_ADD_DISPLAY": { "POPUP_ADD_DISPLAY": {
"RESOLUTION": "Rozdzielczość" "RESOLUTION": "Rozdzielczość"
}, },
"REMOVE": "Usuń",
"SETTINGS": "Ustawienia",
"SHOW": "Pokaż",
"WIDTH": "Szerokość", "WIDTH": "Szerokość",
"HEIGHT": "Wysokość", "PROCESSES": "Procesy"
"DISPLAY_PORTRAIT_MODE": "Tryb pionowy"
} }

View File

@@ -13,7 +13,10 @@ use wgui::{
widget::{label::WidgetLabel, rectangle::WidgetRectangle}, widget::{label::WidgetLabel, rectangle::WidgetRectangle},
windowing::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement}, windowing::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
}; };
use wlx_common::{dash_interface, timestep::Timestep}; use wlx_common::{
dash_interface::{self, BoxDashInterface},
timestep::Timestep,
};
use crate::{ use crate::{
assets, settings, assets, settings,
@@ -41,7 +44,7 @@ pub struct Frontend {
globals: WguiGlobals, globals: WguiGlobals,
pub settings: Box<dyn settings::SettingsIO>, pub settings: Box<dyn settings::SettingsIO>,
pub interface: Box<dyn dash_interface::DashInterface>, pub interface: BoxDashInterface,
#[allow(dead_code)] #[allow(dead_code)]
state: ParserState, state: ParserState,
@@ -63,7 +66,7 @@ pub struct Frontend {
pub struct InitParams { pub struct InitParams {
pub settings: Box<dyn settings::SettingsIO>, pub settings: Box<dyn settings::SettingsIO>,
pub interface: Box<dyn dash_interface::DashInterface>, pub interface: BoxDashInterface,
} }
pub type RcFrontend = Rc<RefCell<Frontend>>; pub type RcFrontend = Rc<RefCell<Frontend>>;

View File

@@ -2,7 +2,7 @@ use wgui::{
globals::WguiGlobals, globals::WguiGlobals,
layout::{Layout, WidgetID}, layout::{Layout, WidgetID},
}; };
use wlx_common::dash_interface; use wlx_common::dash_interface::BoxDashInterface;
use crate::frontend::{FrontendTasks, RcFrontend}; use crate::frontend::{FrontendTasks, RcFrontend};
@@ -36,7 +36,7 @@ pub struct TabUpdateParams<'a> {
pub globals: &'a WguiGlobals, pub globals: &'a WguiGlobals,
pub frontend_tasks: &'a FrontendTasks, pub frontend_tasks: &'a FrontendTasks,
pub layout: &'a mut Layout, pub layout: &'a mut Layout,
pub interface: &'a mut Box<dyn dash_interface::DashInterface>, pub interface: &'a mut BoxDashInterface,
} }
pub trait Tab { pub trait Tab {

View File

@@ -10,10 +10,10 @@ use wgui::{
layout::{Layout, WidgetID}, layout::{Layout, WidgetID},
parser::{Fetchable, ParseDocumentParams, ParserState}, parser::{Fetchable, ParseDocumentParams, ParserState},
taffy::prelude::length, taffy::prelude::length,
widget::{label::WidgetLabel, rectangle::WidgetRectangle}, widget::label::WidgetLabel,
}; };
use crate::{frontend::FrontendTasks, task::Tasks}; use crate::task::Tasks;
#[derive(Clone)] #[derive(Clone)]
enum Task { enum Task {
@@ -27,7 +27,6 @@ pub struct View {
#[allow(dead_code)] #[allow(dead_code)]
pub state: ParserState, pub state: ParserState,
tasks: Tasks<Task>, tasks: Tasks<Task>,
frontend_tasks: FrontendTasks,
on_submit: Rc<dyn Fn(Result)>, on_submit: Rc<dyn Fn(Result)>,
cur_raw_width: u16, cur_raw_width: u16,
@@ -51,7 +50,6 @@ pub struct Result {
pub struct Params<'a> { pub struct Params<'a> {
pub globals: WguiGlobals, pub globals: WguiGlobals,
pub frontend_tasks: FrontendTasks,
pub layout: &'a mut Layout, pub layout: &'a mut Layout,
pub parent_id: WidgetID, pub parent_id: WidgetID,
pub on_submit: Rc<dyn Fn(Result)>, pub on_submit: Rc<dyn Fn(Result)>,
@@ -114,7 +112,6 @@ impl View {
let mut res = Self { let mut res = Self {
state, state,
tasks, tasks,
frontend_tasks: params.frontend_tasks,
on_submit: params.on_submit, on_submit: params.on_submit,
cur_raw_width: RES_WIDTHS[2], cur_raw_width: RES_WIDTHS[2],
cur_raw_height: RES_HEIGHTS[2], cur_raw_height: RES_HEIGHTS[2],

View File

@@ -1,40 +1,38 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use wayvr_ipc::{ use wayvr_ipc::{
packet_client::{AttachTo, WvrDisplayCreateParams}, packet_client::{self},
packet_server::WvrDisplay, packet_server::{self},
}; };
use wgui::{ use wgui::{
assets::AssetPath, assets::AssetPath,
components::{self, button::ComponentButton}, components::{self, button::ComponentButton},
drawing::Color,
globals::WguiGlobals, globals::WguiGlobals,
i18n::Translation, i18n::Translation,
layout::{Layout, WidgetID}, layout::{Layout, WidgetID, WidgetPair},
parser::{Fetchable, ParseDocumentParams, ParserState}, parser::{Fetchable, ParseDocumentParams, ParserState},
renderer_vk::text::{FontWeight, HorizontalAlign, TextStyle}, renderer_vk::text::{FontWeight, HorizontalAlign, TextStyle},
taffy::{self, prelude::length}, taffy::{self, prelude::length},
widget::{ widget::{
ConstructEssentials, ConstructEssentials,
label::{WidgetLabel, WidgetLabelParams}, label::{WidgetLabel, WidgetLabelParams},
rectangle::{WidgetRectangle, WidgetRectangleParams},
util::WLength,
}, },
}; };
use wlx_common::dash_interface; use wlx_common::dash_interface::BoxDashInterface;
use crate::{ use crate::{
frontend::{FrontendTask, FrontendTasks}, frontend::{FrontendTask, FrontendTasks},
tab::TabUpdateParams,
task::Tasks, task::Tasks,
util::popup_manager::{MountPopupParams, PopupHandle}, util::popup_manager::{MountPopupParams, PopupHandle},
views::add_display, views::{add_display, display_options},
}; };
#[derive(Clone)] #[derive(Clone)]
enum Task { enum Task {
AddDisplay, AddDisplay,
AddDisplayFinish(add_display::Result), AddDisplayFinish(add_display::Result),
DisplayOptions(packet_server::WvrDisplay),
DisplayOptionsFinish,
Refresh, Refresh,
} }
@@ -47,6 +45,7 @@ pub struct Params<'a> {
struct State { struct State {
view_add_display: Option<(PopupHandle, add_display::View)>, view_add_display: Option<(PopupHandle, add_display::View)>,
view_display_options: Option<(PopupHandle, display_options::View)>,
} }
pub struct View { pub struct View {
@@ -76,7 +75,10 @@ impl View {
tasks.handle_button(btn_add, Task::AddDisplay); tasks.handle_button(btn_add, Task::AddDisplay);
tasks.push(Task::Refresh); tasks.push(Task::Refresh);
let state = Rc::new(RefCell::new(State { view_add_display: None })); let state = Rc::new(RefCell::new(State {
view_add_display: None,
view_display_options: None,
}));
Ok(Self { Ok(Self {
parser_state, parser_state,
@@ -88,11 +90,7 @@ impl View {
}) })
} }
pub fn update( pub fn update(&mut self, layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> {
&mut self,
layout: &mut Layout,
interface: &mut Box<dyn dash_interface::DashInterface>,
) -> anyhow::Result<()> {
loop { loop {
let tasks = self.tasks.drain(); let tasks = self.tasks.drain();
if tasks.is_empty() { if tasks.is_empty() {
@@ -102,7 +100,9 @@ impl View {
match task { match task {
Task::AddDisplay => self.add_display(), Task::AddDisplay => self.add_display(),
Task::AddDisplayFinish(result) => self.add_display_finish(interface, result)?, Task::AddDisplayFinish(result) => self.add_display_finish(interface, result)?,
Task::DisplayOptionsFinish => self.display_options_finish(),
Task::Refresh => self.refresh(layout, interface)?, Task::Refresh => self.refresh(layout, interface)?,
Task::DisplayOptions(display) => self.display_options(display)?,
} }
} }
} }
@@ -112,22 +112,23 @@ impl View {
view.update(layout)?; view.update(layout)?;
} }
if let Some((_, view)) = &mut state.view_display_options {
view.update(layout, interface)?;
}
Ok(()) Ok(())
} }
} }
fn fill_display_list( pub fn construct_display_button(
globals: &WguiGlobals,
ess: &mut ConstructEssentials, ess: &mut ConstructEssentials,
list: Vec<WvrDisplay>, globals: &WguiGlobals,
) -> anyhow::Result<()> { display: &packet_server::WvrDisplay,
let accent_color = globals.defaults().accent_color; ) -> anyhow::Result<(WidgetPair, Rc<ComponentButton>)> {
let aspect = display.width as f32 / display.height as f32;
for entry in list {
let aspect = entry.width as f32 / entry.height as f32;
let height = 96.0; let height = 96.0;
let width = height * aspect; let width = height * aspect;
let accent_color = globals.defaults().accent_color;
let (widget_button, button) = components::button::construct( let (widget_button, button) = components::button::construct(
ess, ess,
@@ -147,15 +148,10 @@ fn fill_display_list(
}, },
)?; )?;
button.on_click(Box::new(move |_, _| {
log::error!("display options todo");
Ok(())
}));
let label_name = WidgetLabel::create( let label_name = WidgetLabel::create(
&mut globals.get(), &mut globals.get(),
WidgetLabelParams { WidgetLabelParams {
content: Translation::from_raw_text(&entry.name), content: Translation::from_raw_text(&display.name),
style: TextStyle { style: TextStyle {
weight: Some(FontWeight::Bold), weight: Some(FontWeight::Bold),
wrap: true, wrap: true,
@@ -177,6 +173,26 @@ fn fill_display_list(
ess ess
.layout .layout
.add_child(widget_button.id, label_resolution, Default::default())?; .add_child(widget_button.id, label_resolution, Default::default())?;
Ok((widget_button, button))
}
fn fill_display_list(
globals: &WguiGlobals,
ess: &mut ConstructEssentials,
list: Vec<packet_server::WvrDisplay>,
tasks: &Tasks<Task>,
) -> anyhow::Result<()> {
for entry in list {
let (_, button) = construct_display_button(ess, globals, &entry)?;
button.on_click({
let tasks = tasks.clone();
Box::new(move |_, _| {
tasks.push(Task::DisplayOptions(entry.clone()));
Ok(())
})
});
} }
Ok(()) Ok(())
@@ -187,7 +203,6 @@ impl View {
self.frontend_tasks.push(FrontendTask::MountPopup(MountPopupParams { self.frontend_tasks.push(FrontendTask::MountPopup(MountPopupParams {
title: Translation::from_translation_key("ADD_DISPLAY"), title: Translation::from_translation_key("ADD_DISPLAY"),
on_content: { on_content: {
let frontend_tasks = self.frontend_tasks.clone();
let globals = self.globals.clone(); let globals = self.globals.clone();
let state = self.state.clone(); let state = self.state.clone();
@@ -203,7 +218,6 @@ impl View {
state.borrow_mut().view_add_display = Some(( state.borrow_mut().view_add_display = Some((
data.handle, data.handle,
add_display::View::new(add_display::Params { add_display::View::new(add_display::Params {
frontend_tasks: frontend_tasks.clone(),
globals: globals.clone(), globals: globals.clone(),
layout: data.layout, layout: data.layout,
parent_id: data.id_content, parent_id: data.id_content,
@@ -218,25 +232,26 @@ impl View {
fn add_display_finish( fn add_display_finish(
&mut self, &mut self,
interface: &mut Box<dyn dash_interface::DashInterface>, interface: &mut BoxDashInterface,
result: add_display::Result, result: add_display::Result,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
interface.display_create(WvrDisplayCreateParams { interface.display_create(packet_client::WvrDisplayCreateParams {
width: result.width, width: result.width,
height: result.height, height: result.height,
name: result.display_name, name: result.display_name,
attach_to: AttachTo::None, attach_to: packet_client::AttachTo::None,
scale: None, scale: None,
})?; })?;
self.state.borrow_mut().view_add_display = None; self.state.borrow_mut().view_add_display = None;
Ok(()) Ok(())
} }
fn refresh( fn display_options_finish(&mut self) {
&mut self, self.state.borrow_mut().view_display_options = None;
layout: &mut Layout, self.tasks.push(Task::Refresh);
interface: &mut Box<dyn dash_interface::DashInterface>, }
) -> anyhow::Result<()> {
fn refresh(&mut self, layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> {
layout.remove_children(self.id_list_parent); layout.remove_children(self.id_list_parent);
let mut text: Option<Translation> = None; let mut text: Option<Translation> = None;
@@ -252,6 +267,7 @@ impl View {
parent: self.id_list_parent, parent: self.id_list_parent,
}, },
list, list,
&self.tasks,
)? )?
} }
} }
@@ -274,4 +290,33 @@ impl View {
Ok(()) Ok(())
} }
fn display_options(&mut self, display: packet_server::WvrDisplay) -> anyhow::Result<()> {
self.frontend_tasks.push(FrontendTask::MountPopup(MountPopupParams {
title: Translation::from_translation_key("DISPLAY_OPTIONS"),
on_content: {
let frontend_tasks = self.frontend_tasks.clone();
let globals = self.globals.clone();
let state = self.state.clone();
let tasks = self.tasks.clone();
Rc::new(move |data| {
state.borrow_mut().view_display_options = Some((
data.handle,
display_options::View::new(display_options::Params {
globals: globals.clone(),
layout: data.layout,
parent_id: data.id_content,
on_submit: tasks.make_callback(Task::DisplayOptionsFinish),
display: display.clone(),
frontend_tasks: frontend_tasks.clone(),
})?,
));
Ok(())
})
},
}));
Ok(())
}
} }

View File

@@ -0,0 +1,131 @@
use std::rc::Rc;
use anyhow::Context;
use wayvr_ipc::packet_server;
use wgui::{
assets::AssetPath,
components::{button::ComponentButton, checkbox::ComponentCheckbox, slider::ComponentSlider},
event::StyleSetRequest,
globals::WguiGlobals,
i18n::Translation,
layout::{Layout, WidgetID},
parser::{Fetchable, ParseDocumentParams, ParserState},
taffy::prelude::length,
widget::{ConstructEssentials, label::WidgetLabel, rectangle::WidgetRectangle},
};
use wlx_common::dash_interface::{self, BoxDashInterface};
use crate::{
frontend::{FrontendTask, FrontendTasks},
task::Tasks,
views::display_list::construct_display_button,
};
#[derive(Clone)]
enum Task {
SetVisible(bool),
Remove,
}
pub struct View {
#[allow(dead_code)]
pub state: ParserState,
tasks: Tasks<Task>,
frontend_tasks: FrontendTasks,
display: packet_server::WvrDisplay,
on_submit: Rc<dyn Fn()>,
}
pub struct Params<'a> {
pub globals: WguiGlobals,
pub frontend_tasks: FrontendTasks,
pub layout: &'a mut Layout,
pub parent_id: WidgetID,
pub on_submit: Rc<dyn Fn()>,
pub display: packet_server::WvrDisplay,
}
impl View {
pub fn new(params: Params) -> anyhow::Result<Self> {
let doc_params = &ParseDocumentParams {
globals: params.globals.clone(),
path: AssetPath::BuiltIn("gui/view/display_options.xml"),
extra: Default::default(),
};
let state = wgui::parser::parse_from_assets(doc_params, params.layout, params.parent_id)?;
let tasks = Tasks::new();
let display_parent = state.get_widget_id("display_parent")?;
let btn_remove = state.fetch_component_as::<ComponentButton>("btn_remove")?;
let btn_show_hide = state.fetch_component_as::<ComponentButton>("btn_show_hide")?;
construct_display_button(
&mut ConstructEssentials {
layout: params.layout,
parent: display_parent,
},
&params.globals,
&params.display,
)?;
{
let mut c = params.layout.start_common();
btn_show_hide.set_text(
&mut c.common(),
Translation::from_translation_key(if params.display.visible { "HIDE" } else { "SHOW" }),
);
c.finish()?;
}
tasks.handle_button(btn_remove, Task::Remove);
tasks.handle_button(btn_show_hide, Task::SetVisible(!params.display.visible));
Ok(Self {
state,
tasks,
display: params.display,
frontend_tasks: params.frontend_tasks,
on_submit: params.on_submit,
})
}
pub fn update(&mut self, layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> {
for task in self.tasks.drain() {
match task {
Task::SetVisible(v) => self.action_set_visible(interface, v),
Task::Remove => self.action_remove(interface),
}
}
Ok(())
}
}
impl View {
fn action_set_visible(&mut self, interface: &mut BoxDashInterface, visible: bool) {
if let Err(e) = interface.display_set_visible(self.display.handle.clone(), visible) {
self
.frontend_tasks
.push(FrontendTask::PushToast(Translation::from_raw_text_string(format!(
"Failed to remove display: {:?}",
e
))));
};
(*self.on_submit)();
}
fn action_remove(&mut self, interface: &mut BoxDashInterface) {
if let Err(e) = interface.display_remove(self.display.handle.clone()) {
self
.frontend_tasks
.push(FrontendTask::PushToast(Translation::from_raw_text_string(format!(
"Failed to remove display: {:?}",
e
))));
};
(*self.on_submit)();
}
}

View File

@@ -2,3 +2,4 @@ pub mod add_display;
pub mod app_launcher; pub mod app_launcher;
pub mod audio_settings; pub mod audio_settings;
pub mod display_list; pub mod display_list;
pub mod display_options;

View File

@@ -11,6 +11,7 @@ Glossary:
- Playspace: A designated real area where users can interact with the virtual environment - Playspace: A designated real area where users can interact with the virtual environment
- Space-drag: A feature which allows the user to move their HMD origin position via a controller - Space-drag: A feature which allows the user to move their HMD origin position via a controller
- Passthrough: Some headsets have built-in cameras for displaying image on the HMD screen - Passthrough: Some headsets have built-in cameras for displaying image on the HMD screen
End of glossary; - Display: A virtual monitor located in WayVR environment. It has a specific resolution and it contains virtual windows.
End of glossary.
You will be given the input in the code blocks which needs to be translated to {TARGET_LANG} language. Write only the result in codeblocks, do not explain. Keep any newlines and other important formatting-required identifiers as-is. You will be given the input in the code blocks which needs to be translated to {TARGET_LANG} language. Write only the result in codeblocks, do not explain. Keep any newlines and other important formatting-required identifiers as-is.

View File

@@ -383,7 +383,6 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
style.justify_content = Some(JustifyContent::Center); style.justify_content = Some(JustifyContent::Center);
style.overflow.x = taffy::Overflow::Hidden; style.overflow.x = taffy::Overflow::Hidden;
style.overflow.y = taffy::Overflow::Hidden; style.overflow.y = taffy::Overflow::Hidden;
style.gap = length(8.0);
// update colors to default ones if they are not specified // update colors to default ones if they are not specified
let color = if let Some(color) = params.color { let color = if let Some(color) = params.color {
@@ -434,6 +433,13 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
(color.r + color.g + color.b) * mult < 1.5 (color.r + color.g + color.b) * mult < 1.5
}; };
let default_margin = taffy::Rect {
top: length(4.0),
bottom: length(4.0),
left: length(4.0),
right: length(4.0),
};
if let Some(sprite_path) = params.sprite_src { if let Some(sprite_path) = params.sprite_src {
let sprite = WidgetSprite::create(WidgetSpriteParams { let sprite = WidgetSprite::create(WidgetSpriteParams {
glyph_data: Some(CustomGlyphData::new(CustomGlyphContent::from_assets( glyph_data: Some(CustomGlyphData::new(CustomGlyphContent::from_assets(
@@ -451,12 +457,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
width: length(20.0), width: length(20.0),
height: length(20.0), height: length(20.0),
}, },
margin: taffy::Rect { margin: default_margin.clone(),
top: length(4.0),
bottom: length(4.0),
left: length(0.0),
right: length(0.0),
},
..Default::default() ..Default::default()
}, },
)?; )?;
@@ -480,7 +481,10 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
}, },
}, },
), ),
Default::default(), taffy::Style {
margin: default_margin,
..Default::default()
},
)?; )?;
label.id label.id
} else { } else {

View File

@@ -23,3 +23,5 @@ pub trait DashInterface {
fn process_terminate(&mut self, handle: WvrProcessHandle) -> anyhow::Result<()>; fn process_terminate(&mut self, handle: WvrProcessHandle) -> anyhow::Result<()>;
fn window_set_visible(&mut self, handle: WvrWindowHandle, visible: bool) -> anyhow::Result<()>; fn window_set_visible(&mut self, handle: WvrWindowHandle, visible: bool) -> anyhow::Result<()>;
} }
pub type BoxDashInterface = Box<dyn DashInterface>;