move add_display::View -> add_window::View & display_options::View -> window_options::VIew, remove displays logic and replace it with window ones

[skip ci]
This commit is contained in:
Aleksander
2025-12-25 14:57:10 +01:00
parent 7cde2f8c42
commit ccf72b16c5
27 changed files with 293 additions and 770 deletions

View File

@@ -236,6 +236,7 @@ impl Frontend {
self.globals.clone(),
self.settings.as_ref(),
&mut layout,
&mut self.interface,
self.tasks.clone(),
params,
)?;

View File

@@ -5,14 +5,14 @@ use wgui::{
use crate::{
tab::{Tab, TabParams, TabType, TabUpdateParams},
views::{display_list, process_list},
views::{process_list, window_list},
};
pub struct TabProcesses {
#[allow(dead_code)]
pub state: ParserState,
view_display_list: display_list::View,
view_window_list: window_list::View,
view_process_list: process_list::View,
}
@@ -22,7 +22,7 @@ impl Tab for TabProcesses {
}
fn update(&mut self, params: TabUpdateParams) -> anyhow::Result<()> {
self.view_display_list.update(params.layout, params.interface)?;
self.view_window_list.update(params.layout, params.interface)?;
self.view_process_list.update(params.layout, params.interface)?;
Ok(())
}
@@ -41,9 +41,9 @@ impl TabProcesses {
)?;
Ok(Self {
view_display_list: display_list::View::new(display_list::Params {
view_window_list: window_list::View::new(window_list::Params {
layout: params.layout,
parent_id: state.get_widget_id("display_list_parent")?,
parent_id: state.get_widget_id("window_list_parent")?,
globals: params.globals,
frontend_tasks: params.frontend_tasks.clone(),
on_click: None,

View File

@@ -14,6 +14,7 @@ use wgui::{
taffy::Display,
widget::label::WidgetLabel,
};
use wlx_common::dash_interface::BoxDashInterface;
use crate::{
frontend::{FrontendTask, FrontendTasks},
@@ -60,6 +61,7 @@ pub struct PopupContentFuncData<'a> {
pub layout: &'a mut Layout,
pub settings: &'a dyn SettingsIO,
pub handle: PopupHandle,
pub interface: &'a mut BoxDashInterface,
pub id_content: WidgetID,
}
@@ -125,6 +127,7 @@ impl PopupManager {
globals: WguiGlobals,
settings: &dyn SettingsIO,
layout: &mut Layout,
interface: &mut BoxDashInterface,
frontend_tasks: FrontendTasks,
params: MountPopupParams,
) -> anyhow::Result<()> {
@@ -181,6 +184,7 @@ impl PopupManager {
handle: popup_handle.clone(),
id_content,
settings,
interface,
})?;
Ok(())

View File

@@ -1,6 +1,4 @@
use std::{path::PathBuf, str::FromStr};
use wayvr_ipc::packet_server;
use wgui::{
assets::{AssetPath, AssetPathOwned},
globals::WguiGlobals,
@@ -13,7 +11,6 @@ use wgui::{
sprite::{WidgetSprite, WidgetSpriteParams},
},
};
use wlx_common::dash_interface::BoxDashInterface;
use crate::util::desktop_finder;
@@ -33,22 +30,6 @@ pub fn get_desktop_file_icon_path(desktop_file: &desktop_finder::DesktopFile) ->
AssetPathOwned::BuiltIn(PathBuf::from_str("dashboard/terminal.svg").unwrap())
}
pub fn get_all_windows(interface: &mut BoxDashInterface) -> anyhow::Result<Vec<packet_server::WvrWindow>> {
let mut windows = Vec::<packet_server::WvrWindow>::new();
for display in interface.display_list()? {
let Ok(window_list) = interface.display_window_list(display.handle) else {
continue;
};
for window in window_list {
windows.push(window)
}
}
Ok(windows)
}
pub fn mount_simple_label(
globals: &WguiGlobals,
layout: &mut Layout,

View File

@@ -1,247 +0,0 @@
use std::rc::Rc;
use anyhow::Context;
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::label::WidgetLabel,
};
use crate::task::Tasks;
#[derive(Clone)]
enum Task {
Confirm,
SetWidth(u16),
SetHeight(u16),
SetPortrait(bool),
}
pub struct View {
#[allow(dead_code)]
pub state: ParserState,
tasks: Tasks<Task>,
on_submit: Rc<dyn Fn(Result)>,
cur_raw_width: u16,
cur_raw_height: u16,
cur_display_name: String,
cur_portrait: bool,
id_label_width: WidgetID,
id_label_height: WidgetID,
id_label_display_name: WidgetID,
id_rect_display: WidgetID,
id_label_display: WidgetID,
}
#[derive(Clone)]
pub struct Result {
pub width: u16,
pub height: u16,
pub display_name: String,
}
pub struct Params<'a> {
pub globals: WguiGlobals,
pub layout: &'a mut Layout,
pub parent_id: WidgetID,
pub on_submit: Rc<dyn Fn(Result)>,
}
const RES_COUNT: usize = 7;
const RES_WIDTHS: [u16; RES_COUNT] = [512, 854, 1280, 1600, 1920, 2560, 3840];
const RES_HEIGHTS: [u16; 7] = [256, 480, 720, 900, 1080, 1440, 2160];
impl View {
pub fn new(params: Params) -> anyhow::Result<Self> {
let doc_params = &ParseDocumentParams {
globals: params.globals.clone(),
path: AssetPath::BuiltIn("gui/view/add_display.xml"),
extra: Default::default(),
};
let state = wgui::parser::parse_from_assets(doc_params, params.layout, params.parent_id)?;
let tasks = Tasks::new();
let slider_width = state.fetch_component_as::<ComponentSlider>("slider_width")?;
let slider_height = state.fetch_component_as::<ComponentSlider>("slider_height")?;
let id_label_width = state.get_widget_id("label_width")?;
let id_label_height = state.get_widget_id("label_height")?;
let id_label_display_name = state.get_widget_id("label_display_name")?;
let id_rect_display = state.get_widget_id("rect_display")?;
let id_label_display = state.get_widget_id("label_display")?;
let btn_confirm = state.fetch_component_as::<ComponentButton>("btn_confirm")?;
let cb_portrait = state.fetch_component_as::<ComponentCheckbox>("cb_portrait")?;
tasks.handle_button(btn_confirm, Task::Confirm);
// width
slider_width.on_value_changed({
let tasks = tasks.clone();
Box::new(move |_c, e| {
tasks.push(Task::SetWidth(RES_WIDTHS[e.value as usize]));
Ok(())
})
});
// height
slider_height.on_value_changed({
let tasks = tasks.clone();
Box::new(move |_c, e| {
tasks.push(Task::SetHeight(RES_HEIGHTS[e.value as usize]));
Ok(())
})
});
cb_portrait.on_toggle({
let tasks = tasks.clone();
Box::new(move |_c, e| {
tasks.push(Task::SetPortrait(e.checked));
Ok(())
})
});
let mut res = Self {
state,
tasks,
on_submit: params.on_submit,
cur_raw_width: RES_WIDTHS[2],
cur_raw_height: RES_HEIGHTS[2],
cur_display_name: String::new(),
cur_portrait: false,
id_label_width,
id_label_height,
id_label_display_name,
id_rect_display,
id_label_display,
};
res.update_ui(params.layout);
Ok(res)
}
pub fn update(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
for task in self.tasks.drain() {
match task {
Task::Confirm => self.confirm(),
Task::SetWidth(w) => {
self.cur_raw_width = w;
self.update_ui_res(layout)?;
}
Task::SetHeight(h) => {
self.cur_raw_height = h;
self.update_ui_res(layout)?;
}
Task::SetPortrait(p) => {
self.cur_portrait = p;
self.update_ui_res(layout)?;
}
}
}
Ok(())
}
}
// greatest common divisor
fn gcd(a: u16, b: u16) -> u16 {
let (mut a, mut b) = (a, b);
while b != 0 {
let temp = b;
b = a % b;
a = temp;
}
a
}
// aspect ratio calculation
// e.g. returns (16, 9) for input values [1280, 720]
fn aspect_ratio(width: u16, height: u16) -> (u16, u16) {
let gcd = gcd(width, height);
(width / gcd, height / gcd)
}
impl View {
fn confirm(&mut self) {
let (width, height) = self.get_wh();
(*self.on_submit)(Result {
width,
height,
display_name: self.cur_display_name.clone(),
});
}
fn update_ui(&mut self, layout: &mut Layout) -> Option<()> {
let mut c = layout.start_common();
let (cur_width, cur_height) = self.get_wh();
{
let mut common = c.common();
let mut label_width = common.state.widgets.get_as::<WidgetLabel>(self.id_label_width)?;
let mut label_height = common.state.widgets.get_as::<WidgetLabel>(self.id_label_height)?;
let mut label_display_name = common.state.widgets.get_as::<WidgetLabel>(self.id_label_display_name)?;
let mut label_display = common.state.widgets.get_as::<WidgetLabel>(self.id_label_display)?;
// todo?
self.cur_display_name = format!("wvr-{}x{}", cur_width, cur_height);
label_width.set_text(
&mut common,
Translation::from_raw_text_string(format!("{}px", self.cur_raw_width)),
);
label_height.set_text(
&mut common,
Translation::from_raw_text_string(format!("{}px", self.cur_raw_height)),
);
let aspect = aspect_ratio(cur_width, cur_height);
label_display.set_text(
&mut common,
Translation::from_raw_text_string(format!("{}x{}\n{}:{}", cur_width, cur_height, aspect.0, aspect.1)),
);
label_display_name.set_text(&mut common, Translation::from_raw_text(&self.cur_display_name));
let mult = 0.1;
common.alterables.set_style(
self.id_rect_display,
StyleSetRequest::Width(length(cur_width as f32 * mult)),
);
common.alterables.set_style(
self.id_rect_display,
StyleSetRequest::Height(length(cur_height as f32 * mult)),
);
}
c.finish().ok()?;
Some(())
}
fn update_ui_res(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
self.update_ui(layout).context("failed to update ui")?;
Ok(())
}
fn get_wh(&self) -> (u16, u16) {
if self.cur_portrait {
(self.cur_raw_height, self.cur_raw_width)
} else {
(self.cur_raw_width, self.cur_raw_height)
}
}
}

View File

@@ -1,10 +1,9 @@
use std::{collections::HashMap, rc::Rc};
use anyhow::Context;
use wayvr_ipc::{packet_client::WvrProcessLaunchParams, packet_server::WvrDisplayHandle};
use wgui::{
assets::AssetPath,
components::checkbox::ComponentCheckbox,
components::{button::ComponentButton, checkbox::ComponentCheckbox},
globals::WguiGlobals,
i18n::Translation,
layout::{Layout, WidgetID},
@@ -18,7 +17,6 @@ use crate::{
settings::SettingsIO,
task::Tasks,
util::desktop_finder::DesktopEntry,
views::display_list,
};
#[derive(Clone, Eq, PartialEq)]
@@ -27,13 +25,13 @@ enum RunMode {
Wayland,
}
#[derive(Clone)]
enum Task {
SetRunMode(RunMode),
DisplayClick(WvrDisplayHandle),
Launch,
}
struct LaunchParams<'a> {
display_handle: WvrDisplayHandle,
application: &'a DesktopEntry,
run_mode: RunMode,
globals: &'a WguiGlobals,
@@ -46,7 +44,6 @@ pub struct View {
#[allow(dead_code)]
state: ParserState,
entry: DesktopEntry,
view_display_list: display_list::View,
tasks: Tasks<Task>,
frontend_tasks: FrontendTasks,
globals: WguiGlobals,
@@ -80,6 +77,7 @@ impl View {
let cb_cage_mode = state.fetch_component_as::<ComponentCheckbox>("cb_cage_mode")?;
let cb_wayland_mode = state.fetch_component_as::<ComponentCheckbox>("cb_wayland_mode")?;
let btn_launch = state.fetch_component_as::<ComponentButton>("btn_launch")?;
{
let mut label_exec = state.fetch_widget_as::<WidgetLabel>(&params.layout.state, "label_exec")?;
@@ -96,24 +94,9 @@ impl View {
);
}
let display_list_parent = state.fetch_widget(&params.layout.state, "display_list_parent")?.id;
let tasks = Tasks::new();
let on_display_click = {
let tasks = tasks.clone();
Box::new(move |disp_handle: WvrDisplayHandle| {
tasks.push(Task::DisplayClick(disp_handle));
})
};
let view_display_list = display_list::View::new(display_list::Params {
frontend_tasks: params.frontend_tasks.clone(),
globals: params.globals,
layout: params.layout,
parent_id: display_list_parent,
on_click: Some(on_display_click),
})?;
tasks.handle_button(btn_launch, Task::Launch);
let id_icon_parent = state.get_widget_id("icon_parent")?;
@@ -163,7 +146,6 @@ impl View {
Ok(Self {
state,
view_display_list,
tasks,
cb_cage_mode,
cb_wayland_mode,
@@ -184,13 +166,11 @@ impl View {
for task in tasks {
match task {
Task::SetRunMode(run_mode) => self.action_set_run_mode(layout, run_mode)?,
Task::DisplayClick(disp_handle) => self.action_display_click(disp_handle, interface),
Task::Launch => self.action_launch(interface),
}
}
}
self.view_display_list.update(layout, interface)?;
Ok(())
}
@@ -208,10 +188,9 @@ impl View {
Ok(())
}
fn action_display_click(&mut self, handle: WvrDisplayHandle, interface: &mut BoxDashInterface) {
fn action_launch(&mut self, interface: &mut BoxDashInterface) {
View::try_launch(LaunchParams {
application: &self.entry,
display_handle: handle,
frontend_tasks: &self.frontend_tasks,
globals: &self.globals,
run_mode: self.run_mode.clone(),
@@ -253,10 +232,6 @@ impl View {
let exec_args_str = desktop_file.exec_args.join(" ");
params
.interface
.display_set_visible(params.display_handle.clone(), true)?;
let args = match params.run_mode {
RunMode::Cage => format!("-- {} {}", desktop_file.exec_path, exec_args_str),
RunMode::Wayland => exec_args_str,
@@ -267,29 +242,22 @@ impl View {
RunMode::Wayland => &desktop_file.name,
};
let display = params
.interface
.display_get(params.display_handle.clone())
.context("Display not found")?;
params.interface.process_launch(WvrProcessLaunchParams {
env,
exec: String::from(exec),
name: desktop_file.name,
target_display: params.display_handle,
target_display: WvrDisplayHandle {
generation: 12345, // stub
idx: 12345,
},
args,
userdata,
})?;
let str_launched_on = params
.globals
.i18n()
.translate_and_replace("APPLICATION_LAUNCHED_ON", ("{DISPLAY_NAME}", &display.name));
params
.frontend_tasks
.push(FrontendTask::PushToast(Translation::from_raw_text_string(
str_launched_on,
.push(FrontendTask::PushToast(Translation::from_translation_key(
"APPLICATION_STARTED",
)));
(*params.on_launched)();

View File

@@ -1,6 +1,5 @@
pub mod add_display;
pub mod app_launcher;
pub mod audio_settings;
pub mod display_list;
pub mod display_options;
pub mod process_list;
pub mod window_list;
pub mod window_options;

View File

@@ -91,29 +91,18 @@ impl View {
}
}
fn get_desktop_file_from_process(
windows: &Vec<packet_server::WvrWindow>,
process: &packet_server::WvrProcess,
) -> Option<desktop_finder::DesktopFile> {
for window in windows {
if window.process_handle != process.handle {
continue;
}
fn get_desktop_file_from_process(process: &packet_server::WvrProcess) -> Option<desktop_finder::DesktopFile> {
// TODO: refactor this after we ditch old wayvr-dashboard completely
let Some(dfile_str) = process.userdata.get("desktop_file") else {
return None;
};
// TODO: refactor this after we ditch old wayvr-dashboard completely
let Some(dfile_str) = process.userdata.get("desktop_file") else {
continue;
};
let Ok(desktop_file) = serde_json::from_str::<desktop_finder::DesktopFile>(dfile_str) else {
debug_assert!(false); // invalid json???
return None;
};
let Ok(desktop_file) = serde_json::from_str::<desktop_finder::DesktopFile>(dfile_str) else {
debug_assert!(false); // invalid json???
continue;
};
return Some(desktop_file);
}
None
Some(desktop_file)
}
struct ProcessEntryResult {
@@ -124,8 +113,6 @@ fn construct_process_entry(
ess: &mut ConstructEssentials,
globals: &WguiGlobals,
process: &packet_server::WvrProcess,
display: Option<&packet_server::WvrDisplay>,
all_windows: &Vec<packet_server::WvrWindow>,
) -> anyhow::Result<ProcessEntryResult> {
let (cell, _) = ess.layout.add_child(
ess.parent,
@@ -159,7 +146,7 @@ fn construct_process_entry(
},
)?;
if let Some(desktop_file) = get_desktop_file_from_process(all_windows, process) {
if let Some(desktop_file) = get_desktop_file_from_process(process) {
// desktop file icon and process name
util::various::mount_simple_sprite_square(
globals,
@@ -185,35 +172,6 @@ fn construct_process_entry(
)?;
}
if let Some(display) = display {
// show display icon if available
// "on" text
util::various::mount_simple_label(
globals,
ess.layout,
cell.id,
Translation::from_translation_key("PROCESS_LIST.LOCATED_ON"),
)?;
// "display" icon
util::various::mount_simple_sprite_square(
globals,
ess.layout,
cell.id,
24.0,
AssetPath::BuiltIn("dashboard/display.svg"),
)?;
// display name itself
util::various::mount_simple_label(
globals,
ess.layout,
cell.id,
Translation::from_raw_text_string(display.name.clone()),
)?;
}
Ok(ProcessEntryResult { btn_terminate })
}
@@ -222,18 +180,9 @@ fn fill_process_list(
ess: &mut ConstructEssentials,
tasks: &Tasks<Task>,
list: &Vec<packet_server::WvrProcess>,
displays: &Vec<packet_server::WvrDisplay>,
all_windows: &Vec<packet_server::WvrWindow>,
) -> anyhow::Result<()> {
for process_entry in list {
let mut matching_display = None;
for display in displays {
if process_entry.display_handle == display.handle {
matching_display = Some(display);
}
}
let entry_res = construct_process_entry(ess, globals, process_entry, matching_display, all_windows)?;
let entry_res = construct_process_entry(ess, globals, process_entry)?;
entry_res.btn_terminate.on_click({
let tasks = tasks.clone();
@@ -252,9 +201,6 @@ impl View {
fn refresh(&mut self, layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> {
layout.remove_children(self.id_list_parent);
let displays = interface.display_list()?;
let all_windows = util::various::get_all_windows(interface)?;
let mut text: Option<Translation> = None;
match interface.process_list() {
Ok(list) => {
@@ -269,8 +215,6 @@ impl View {
},
&self.tasks,
&list,
&displays,
&all_windows,
)?;
}
}

View File

@@ -1,9 +1,6 @@
use std::{cell::RefCell, rc::Rc};
use wayvr_ipc::{
packet_client::{self},
packet_server::{self, WvrDisplayHandle},
};
use wayvr_ipc::packet_server::{self, WvrWindowHandle};
use wgui::{
assets::AssetPath,
components::{self, button::ComponentButton},
@@ -24,15 +21,13 @@ use crate::{
frontend::{FrontendTask, FrontendTasks},
task::Tasks,
util::popup_manager::{MountPopupParams, PopupHandle},
views::{add_display, display_options},
views::window_options,
};
#[derive(Clone)]
enum Task {
AddDisplay,
AddDisplayFinish(add_display::Result),
DisplayClicked(packet_server::WvrDisplay),
DisplayOptionsFinish,
WindowClicked(packet_server::WvrWindow),
WindowOptionsFinish,
Refresh,
}
@@ -41,12 +36,11 @@ pub struct Params<'a> {
pub frontend_tasks: FrontendTasks,
pub layout: &'a mut Layout,
pub parent_id: WidgetID,
pub on_click: Option<Box<dyn Fn(WvrDisplayHandle)>>,
pub on_click: Option<Box<dyn Fn(WvrWindowHandle)>>,
}
struct State {
view_add_display: Option<(PopupHandle, add_display::View)>,
view_display_options: Option<(PopupHandle, display_options::View)>,
view_window_options: Option<(PopupHandle, window_options::View)>,
}
pub struct View {
@@ -57,14 +51,14 @@ pub struct View {
globals: WguiGlobals,
state: Rc<RefCell<State>>,
id_list_parent: WidgetID,
on_click: Option<Box<dyn Fn(WvrDisplayHandle)>>,
on_click: Option<Box<dyn Fn(WvrWindowHandle)>>,
}
impl View {
pub fn new(params: Params) -> anyhow::Result<Self> {
let doc_params = &ParseDocumentParams {
globals: params.globals.clone(),
path: AssetPath::BuiltIn("gui/view/display_list.xml"),
path: AssetPath::BuiltIn("gui/view/window_list.xml"),
extra: Default::default(),
};
@@ -73,13 +67,10 @@ impl View {
let tasks = Tasks::new();
let btn_add = parser_state.fetch_component_as::<ComponentButton>("btn_add")?;
tasks.handle_button(btn_add, Task::AddDisplay);
tasks.push(Task::Refresh);
let state = Rc::new(RefCell::new(State {
view_add_display: None,
view_display_options: None,
view_window_options: None,
}));
Ok(Self {
@@ -101,21 +92,15 @@ impl View {
}
for task in tasks {
match task {
Task::AddDisplay => self.action_add_display(),
Task::AddDisplayFinish(result) => self.action_add_display_finish(interface, result)?,
Task::DisplayOptionsFinish => self.action_display_options_finish(),
Task::WindowClicked(display) => self.action_window_clicked(display)?,
Task::WindowOptionsFinish => self.action_window_options_finish(),
Task::Refresh => self.refresh(layout, interface)?,
Task::DisplayClicked(display) => self.action_display_clicked(display)?,
}
}
}
let mut state = self.state.borrow_mut();
if let Some((_, view)) = &mut state.view_add_display {
view.update(layout)?;
}
if let Some((_, view)) = &mut state.view_display_options {
if let Some((_, view)) = &mut state.view_window_options {
view.update(layout, interface)?;
}
@@ -123,12 +108,13 @@ impl View {
}
}
pub fn construct_display_button(
pub fn construct_window_button(
ess: &mut ConstructEssentials,
interface: &mut BoxDashInterface,
globals: &WguiGlobals,
display: &packet_server::WvrDisplay,
window: &packet_server::WvrWindow,
) -> anyhow::Result<(WidgetPair, Rc<ComponentButton>)> {
let aspect = display.width as f32 / display.height as f32;
let aspect = window.size_x as f32 / window.size_y as f32;
let height = 96.0;
let width = height * aspect;
let accent_color = globals.defaults().accent_color;
@@ -151,10 +137,15 @@ pub fn construct_display_button(
},
)?;
let process_name = match interface.process_get(window.process_handle.clone()) {
Some(process) => process.name.clone(),
None => String::from("Unknown"),
};
let label_name = WidgetLabel::create(
&mut globals.get(),
WidgetLabelParams {
content: Translation::from_raw_text(&display.name),
content: Translation::from_raw_text(&process_name),
style: TextStyle {
weight: Some(FontWeight::Bold),
wrap: true,
@@ -180,19 +171,20 @@ pub fn construct_display_button(
Ok((widget_button, button))
}
fn fill_display_list(
fn fill_window_list(
globals: &WguiGlobals,
ess: &mut ConstructEssentials,
list: Vec<packet_server::WvrDisplay>,
interface: &mut BoxDashInterface,
list: Vec<packet_server::WvrWindow>,
tasks: &Tasks<Task>,
) -> anyhow::Result<()> {
for entry in list {
let (_, button) = construct_display_button(ess, globals, &entry)?;
let (_, button) = construct_window_button(ess, interface, globals, &entry)?;
button.on_click({
let tasks = tasks.clone();
Box::new(move |_, _| {
tasks.push(Task::DisplayClicked(entry.clone()));
tasks.push(Task::WindowClicked(entry.clone()));
Ok(())
})
});
@@ -202,55 +194,8 @@ fn fill_display_list(
}
impl View {
fn action_add_display(&mut self) {
self.frontend_tasks.push(FrontendTask::MountPopup(MountPopupParams {
title: Translation::from_translation_key("ADD_DISPLAY"),
on_content: {
let globals = self.globals.clone();
let state = self.state.clone();
let on_submit = {
let tasks = self.tasks.clone();
Rc::new(move |result| {
tasks.push(Task::AddDisplayFinish(result));
tasks.push(Task::Refresh);
})
};
Rc::new(move |data| {
state.borrow_mut().view_add_display = Some((
data.handle,
add_display::View::new(add_display::Params {
globals: globals.clone(),
layout: data.layout,
parent_id: data.id_content,
on_submit: on_submit.clone(),
})?,
));
Ok(())
})
},
}));
}
fn action_add_display_finish(
&mut self,
interface: &mut BoxDashInterface,
result: add_display::Result,
) -> anyhow::Result<()> {
interface.display_create(packet_client::WvrDisplayCreateParams {
width: result.width,
height: result.height,
name: result.display_name,
attach_to: packet_client::AttachTo::None,
scale: None,
})?;
self.state.borrow_mut().view_add_display = None;
Ok(())
}
fn action_display_options_finish(&mut self) {
self.state.borrow_mut().view_display_options = None;
fn action_window_options_finish(&mut self) {
self.state.borrow_mut().view_window_options = None;
self.tasks.push(Task::Refresh);
}
@@ -258,17 +203,18 @@ impl View {
layout.remove_children(self.id_list_parent);
let mut text: Option<Translation> = None;
match interface.display_list() {
match interface.window_list() {
Ok(list) => {
if list.is_empty() {
text = Some(Translation::from_translation_key("NO_DISPLAYS_FOUND"))
text = Some(Translation::from_translation_key("NO_WINDOWS_FOUND"))
} else {
fill_display_list(
fill_window_list(
&self.globals,
&mut ConstructEssentials {
layout,
parent: self.id_list_parent,
},
interface,
list,
&self.tasks,
)?
@@ -294,12 +240,12 @@ impl View {
Ok(())
}
fn action_display_clicked(&mut self, display: packet_server::WvrDisplay) -> anyhow::Result<()> {
fn action_window_clicked(&mut self, window: packet_server::WvrWindow) -> anyhow::Result<()> {
if let Some(on_click) = &mut self.on_click {
(*on_click)(display.handle);
(*on_click)(window.handle);
} else {
self.frontend_tasks.push(FrontendTask::MountPopup(MountPopupParams {
title: Translation::from_translation_key("DISPLAY_OPTIONS"),
title: Translation::from_translation_key("WINDOW_OPTIONS"),
on_content: {
let frontend_tasks = self.frontend_tasks.clone();
let globals = self.globals.clone();
@@ -307,15 +253,16 @@ impl View {
let tasks = self.tasks.clone();
Rc::new(move |data| {
state.borrow_mut().view_display_options = Some((
state.borrow_mut().view_window_options = Some((
data.handle,
display_options::View::new(display_options::Params {
window_options::View::new(window_options::Params {
globals: globals.clone(),
layout: data.layout,
parent_id: data.id_content,
on_submit: tasks.make_callback(Task::DisplayOptionsFinish),
display: display.clone(),
on_submit: tasks.make_callback(Task::WindowOptionsFinish),
window: window.clone(),
frontend_tasks: frontend_tasks.clone(),
interface: data.interface,
})?,
));
Ok(())

View File

@@ -1,3 +1,4 @@
use anyhow::Context;
use std::rc::Rc;
use wayvr_ipc::packet_server;
use wgui::{
@@ -14,13 +15,14 @@ use wlx_common::dash_interface::BoxDashInterface;
use crate::{
frontend::{FrontendTask, FrontendTasks},
task::Tasks,
views::display_list::construct_display_button,
views::window_list::construct_window_button,
};
#[derive(Clone)]
enum Task {
SetVisible(bool),
Remove,
Kill,
Close,
}
pub struct View {
@@ -28,7 +30,7 @@ pub struct View {
pub state: ParserState,
tasks: Tasks<Task>,
frontend_tasks: FrontendTasks,
display: packet_server::WvrDisplay,
window: packet_server::WvrWindow,
on_submit: Rc<dyn Fn()>,
}
@@ -38,14 +40,15 @@ pub struct Params<'a> {
pub layout: &'a mut Layout,
pub parent_id: WidgetID,
pub on_submit: Rc<dyn Fn()>,
pub display: packet_server::WvrDisplay,
pub window: packet_server::WvrWindow,
pub interface: &'a mut BoxDashInterface,
}
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"),
path: AssetPath::BuiltIn("gui/view/window_options.xml"),
extra: Default::default(),
};
@@ -53,35 +56,38 @@ impl View {
let tasks = Tasks::new();
let display_parent = state.get_widget_id("display_parent")?;
let btn_remove = state.fetch_component_as::<ComponentButton>("btn_remove")?;
let window_parent = state.get_widget_id("window_parent")?;
let btn_close = state.fetch_component_as::<ComponentButton>("btn_close")?;
let btn_kill = state.fetch_component_as::<ComponentButton>("btn_kill")?;
let btn_show_hide = state.fetch_component_as::<ComponentButton>("btn_show_hide")?;
construct_display_button(
construct_window_button(
&mut ConstructEssentials {
layout: params.layout,
parent: display_parent,
parent: window_parent,
},
params.interface,
&params.globals,
&params.display,
&params.window,
)?;
{
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" }),
Translation::from_translation_key(if params.window.visible { "HIDE" } else { "SHOW" }),
);
c.finish()?;
}
tasks.handle_button(btn_remove, Task::Remove);
tasks.handle_button(btn_show_hide, Task::SetVisible(!params.display.visible));
tasks.handle_button(btn_close, Task::Close);
tasks.handle_button(btn_kill, Task::Kill);
tasks.handle_button(btn_show_hide, Task::SetVisible(!params.window.visible));
Ok(Self {
state,
tasks,
display: params.display,
window: params.window,
frontend_tasks: params.frontend_tasks,
on_submit: params.on_submit,
})
@@ -91,7 +97,8 @@ impl View {
for task in self.tasks.drain() {
match task {
Task::SetVisible(v) => self.action_set_visible(interface, v),
Task::Remove => self.action_remove(interface),
Task::Close => self.action_close(interface),
Task::Kill => self.action_kill(interface),
}
}
Ok(())
@@ -100,11 +107,11 @@ impl View {
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) {
if let Err(e) = interface.window_set_visible(self.window.handle.clone(), visible) {
self
.frontend_tasks
.push(FrontendTask::PushToast(Translation::from_raw_text_string(format!(
"Failed to remove display: {:?}",
"Failed to set window visibility: {:?}",
e
))));
};
@@ -112,12 +119,33 @@ impl View {
(*self.on_submit)();
}
fn action_remove(&mut self, interface: &mut BoxDashInterface) {
if let Err(e) = interface.display_remove(self.display.handle.clone()) {
fn action_close(&mut self, interface: &mut BoxDashInterface) {
if let Err(e) = interface.window_request_close(self.window.handle.clone()) {
self
.frontend_tasks
.push(FrontendTask::PushToast(Translation::from_raw_text_string(format!(
"Failed to remove display: {:?}",
"Failed to close window: {:?}",
e
))));
};
(*self.on_submit)();
}
fn action_kill_process(&mut self, interface: &mut BoxDashInterface) -> anyhow::Result<()> {
let process = interface
.process_get(self.window.process_handle.clone())
.context("Process not found")?;
interface.process_terminate(process.handle)?;
Ok(())
}
fn action_kill(&mut self, interface: &mut BoxDashInterface) {
if let Err(e) = self.action_kill_process(interface) {
self
.frontend_tasks
.push(FrontendTask::PushToast(Translation::from_raw_text_string(format!(
"Failed to kill process: {:?}",
e
))));
};