poc window decorations
This commit is contained in:
23
wlx-overlay-s/src/assets/gui/decor.xml
Normal file
23
wlx-overlay-s/src/assets/gui/decor.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<layout>
|
||||
<elements>
|
||||
<rectangle
|
||||
width="100%" height="100%"
|
||||
margin="4" box_sizing="border_box"
|
||||
border_color="~color_faded" border="2"
|
||||
round="50%" color="~color_faded"
|
||||
justify_content="space_between">
|
||||
|
||||
<label id="label_title" color="~color_text" size="18" text="Test" weight="bold" />
|
||||
|
||||
|
||||
<Button macro="button_style" tooltip="WATCH.EDIT_MODE" _press="" border_color="~color_faded_translucent" color="~color_faded_50" color2="~color_faded_10">
|
||||
<sprite width="24" height="24" src="watch/edit.svg" />
|
||||
</Button>
|
||||
|
||||
<Button macro="button_style" tooltip="DECOR.CLOSE_WINDOW" _long_release="" border_color="~color_danger_translucent" color="~color_danger_50" color2="~color_danger_10">
|
||||
<sprite width="24" height="24" src="edit/close.svg" />
|
||||
</Button>
|
||||
|
||||
</rectangle>
|
||||
</elements>
|
||||
</layout>
|
||||
@@ -75,6 +75,7 @@ impl LinePool {
|
||||
|
||||
let pass = self.pipeline.create_pass(
|
||||
[1.0, 1.0],
|
||||
[0.0, 0.0],
|
||||
app.gfx_extras.quad_verts.clone(),
|
||||
0..4,
|
||||
0..1,
|
||||
|
||||
@@ -110,6 +110,7 @@ impl Skybox {
|
||||
let set1 = pipeline.uniform_buffer_upload(1, vec![1f32])?;
|
||||
let pass = pipeline.create_pass(
|
||||
tgt.extent_f32(),
|
||||
[0.0, 0.0],
|
||||
app.gfx_extras.quad_verts.clone(),
|
||||
0..4,
|
||||
0..1,
|
||||
@@ -161,6 +162,7 @@ impl Skybox {
|
||||
.unwrap();
|
||||
let pass = pipeline.create_pass(
|
||||
tgt.extent_f32(),
|
||||
[0.0, 0.0],
|
||||
app.gfx_extras.quad_verts.clone(),
|
||||
0..4,
|
||||
0..1,
|
||||
|
||||
@@ -192,12 +192,20 @@ impl OverlayBackend for ScreenBackend {
|
||||
.meta
|
||||
.is_some_and(|old| old.extent[..2] != meta.extent[..2])
|
||||
{
|
||||
pipeline.set_extent(app, [meta.extent[0] as _, meta.extent[1] as _])?;
|
||||
pipeline.set_extent(
|
||||
app,
|
||||
[meta.extent[0] as _, meta.extent[1] as _],
|
||||
[0., 0.],
|
||||
)?;
|
||||
self.interaction_transform = Some(ui_transform(meta.extent.extent_u32arr()));
|
||||
}
|
||||
} else {
|
||||
let pipeline =
|
||||
ScreenPipeline::new(&meta, app, self.stereo.unwrap_or(StereoMode::None))?;
|
||||
let pipeline = ScreenPipeline::new(
|
||||
&meta,
|
||||
app,
|
||||
self.stereo.unwrap_or(StereoMode::None),
|
||||
[0., 0.],
|
||||
)?;
|
||||
meta.extent[2] = pipeline.get_depth();
|
||||
self.pipeline = Some(pipeline);
|
||||
self.interaction_transform = Some(ui_transform(meta.extent.extent_u32arr()));
|
||||
|
||||
@@ -46,11 +46,17 @@ pub struct ScreenPipeline {
|
||||
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
buf_alpha: Subbuffer<[f32]>,
|
||||
extentf: [f32; 2],
|
||||
offsetf: [f32; 2],
|
||||
stereo: StereoMode,
|
||||
}
|
||||
|
||||
impl ScreenPipeline {
|
||||
pub fn new(meta: &FrameMeta, app: &mut AppState, stereo: StereoMode) -> anyhow::Result<Self> {
|
||||
pub fn new(
|
||||
meta: &FrameMeta,
|
||||
app: &mut AppState,
|
||||
stereo: StereoMode,
|
||||
offsetf: [f32; 2],
|
||||
) -> anyhow::Result<Self> {
|
||||
let extentf = [meta.extent[0] as f32, meta.extent[1] as f32];
|
||||
|
||||
let pipeline = app.gfx.create_pipeline(
|
||||
@@ -70,11 +76,19 @@ impl ScreenPipeline {
|
||||
app,
|
||||
pipeline.clone(),
|
||||
extentf,
|
||||
offsetf,
|
||||
buf_alpha.clone()
|
||||
)?],
|
||||
mouse: Self::create_mouse_pass(app, pipeline.clone(), extentf, buf_alpha.clone())?,
|
||||
mouse: Self::create_mouse_pass(
|
||||
app,
|
||||
pipeline.clone(),
|
||||
extentf,
|
||||
offsetf,
|
||||
buf_alpha.clone(),
|
||||
)?,
|
||||
pipeline,
|
||||
extentf,
|
||||
offsetf,
|
||||
buf_alpha,
|
||||
stereo,
|
||||
};
|
||||
@@ -94,6 +108,7 @@ impl ScreenPipeline {
|
||||
app,
|
||||
self.pipeline.clone(),
|
||||
self.extentf,
|
||||
self.offsetf,
|
||||
self.buf_alpha.clone(),
|
||||
)?);
|
||||
}
|
||||
@@ -113,15 +128,34 @@ impl ScreenPipeline {
|
||||
self.pass.len() as _
|
||||
}
|
||||
|
||||
pub fn set_extent(&mut self, app: &mut AppState, extentf: [f32; 2]) -> anyhow::Result<()> {
|
||||
pub fn set_extent(
|
||||
&mut self,
|
||||
app: &mut AppState,
|
||||
extentf: [f32; 2],
|
||||
offsetf: [f32; 2],
|
||||
) -> anyhow::Result<()> {
|
||||
self.extentf = extentf;
|
||||
self.offsetf = offsetf;
|
||||
|
||||
for (eye, pass) in self.pass.iter_mut().enumerate() {
|
||||
*pass = Self::create_pass(app, self.pipeline.clone(), extentf, self.buf_alpha.clone())?;
|
||||
*pass = Self::create_pass(
|
||||
app,
|
||||
self.pipeline.clone(),
|
||||
extentf,
|
||||
offsetf,
|
||||
self.buf_alpha.clone(),
|
||||
)?;
|
||||
let verts = stereo_mode_to_verts(self.stereo, eye);
|
||||
pass.buf_vert.write()?.copy_from_slice(&verts);
|
||||
}
|
||||
|
||||
self.mouse =
|
||||
Self::create_mouse_pass(app, self.pipeline.clone(), extentf, self.buf_alpha.clone())?;
|
||||
self.mouse = Self::create_mouse_pass(
|
||||
app,
|
||||
self.pipeline.clone(),
|
||||
extentf,
|
||||
offsetf,
|
||||
self.buf_alpha.clone(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -129,6 +163,7 @@ impl ScreenPipeline {
|
||||
app: &mut AppState,
|
||||
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
extentf: [f32; 2],
|
||||
offsetf: [f32; 2],
|
||||
buf_alpha: Subbuffer<[f32]>,
|
||||
) -> anyhow::Result<BufPass> {
|
||||
let set0 = pipeline.uniform_sampler(
|
||||
@@ -143,6 +178,7 @@ impl ScreenPipeline {
|
||||
|
||||
let pass = pipeline.create_pass(
|
||||
extentf,
|
||||
offsetf,
|
||||
buf_vert.clone(),
|
||||
0..4,
|
||||
0..1,
|
||||
@@ -157,6 +193,7 @@ impl ScreenPipeline {
|
||||
app: &mut AppState,
|
||||
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
extentf: [f32; 2],
|
||||
offsetf: [f32; 2],
|
||||
buf_alpha: Subbuffer<[f32]>,
|
||||
) -> anyhow::Result<BufPass> {
|
||||
#[rustfmt::skip]
|
||||
@@ -184,6 +221,7 @@ impl ScreenPipeline {
|
||||
let set1 = pipeline.buffer(1, buf_alpha)?;
|
||||
let pass = pipeline.create_pass(
|
||||
extentf,
|
||||
offsetf,
|
||||
buf_vert.clone(),
|
||||
0..4,
|
||||
0..1,
|
||||
|
||||
@@ -7,7 +7,15 @@ use std::sync::Arc;
|
||||
use vulkano::{
|
||||
buffer::BufferUsage, image::view::ImageView, pipeline::graphics::color_blend::AttachmentBlend,
|
||||
};
|
||||
use wgui::gfx::pipeline::{WGfxPipeline, WPipelineCreateInfo};
|
||||
use wgui::{
|
||||
gfx::{
|
||||
cmd::WGfxClearMode,
|
||||
pipeline::{WGfxPipeline, WPipelineCreateInfo},
|
||||
},
|
||||
i18n::Translation,
|
||||
parser::Fetchable,
|
||||
widget::label::WidgetLabel,
|
||||
};
|
||||
use wlx_capture::frame::MouseMeta;
|
||||
use wlx_common::{
|
||||
overlays::{BackendAttrib, BackendAttribValue, StereoMode},
|
||||
@@ -21,6 +29,7 @@ use crate::{
|
||||
wayvr::{self, SurfaceBufWithImage},
|
||||
},
|
||||
graphics::{ExtentExt, Vert2Uv, upload_quad_vertices},
|
||||
gui::panel::{GuiPanel, NewGuiPanelParams},
|
||||
overlays::screen::capture::ScreenPipeline,
|
||||
state::{self, AppState},
|
||||
subsystem::{hid::WheelDelta, input::KeyboardFocus},
|
||||
@@ -33,9 +42,12 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
const BORDER_SIZE: u32 = 5;
|
||||
const BAR_SIZE: u32 = 24;
|
||||
|
||||
pub fn create_wl_window_overlay(
|
||||
name: Arc<str>,
|
||||
app: &AppState,
|
||||
app: &mut AppState,
|
||||
window: wayvr::window::WindowHandle,
|
||||
) -> anyhow::Result<OverlayWindowConfig> {
|
||||
Ok(OverlayWindowConfig {
|
||||
@@ -71,12 +83,14 @@ pub struct WvrWindowBackend {
|
||||
mouse: Option<MouseMeta>,
|
||||
stereo: Option<StereoMode>,
|
||||
cur_image: Option<Arc<ImageView>>,
|
||||
panel: GuiPanel<()>,
|
||||
mouse_transform: Affine2,
|
||||
}
|
||||
|
||||
impl WvrWindowBackend {
|
||||
fn new(
|
||||
name: Arc<str>,
|
||||
app: &AppState,
|
||||
app: &mut AppState,
|
||||
window: wayvr::window::WindowHandle,
|
||||
) -> anyhow::Result<Self> {
|
||||
let popups_pipeline = app.gfx.create_pipeline(
|
||||
@@ -85,6 +99,28 @@ impl WvrWindowBackend {
|
||||
WPipelineCreateInfo::new(app.gfx.surface_format).use_blend(AttachmentBlend::default()),
|
||||
)?;
|
||||
|
||||
let mut panel = GuiPanel::new_from_template(
|
||||
app,
|
||||
"gui/decor.xml",
|
||||
(),
|
||||
NewGuiPanelParams {
|
||||
resize_to_parent: true,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
{
|
||||
let mut title = panel
|
||||
.parser_state
|
||||
.fetch_widget_as::<WidgetLabel>(&panel.layout.state, "label_title")?;
|
||||
title.set_text_simple(
|
||||
&mut app.wgui_globals.get(),
|
||||
Translation::from_raw_text(&*name),
|
||||
);
|
||||
}
|
||||
|
||||
panel.update_layout()?;
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
pipeline: None,
|
||||
@@ -101,25 +137,29 @@ impl WvrWindowBackend {
|
||||
None
|
||||
},
|
||||
cur_image: None,
|
||||
panel,
|
||||
mouse_transform: Affine2::ZERO,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl OverlayBackend for WvrWindowBackend {
|
||||
fn init(&mut self, _app: &mut state::AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
fn init(&mut self, app: &mut state::AppState) -> anyhow::Result<()> {
|
||||
self.panel.init(app)
|
||||
}
|
||||
|
||||
fn pause(&mut self, _app: &mut state::AppState) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
fn pause(&mut self, app: &mut state::AppState) -> anyhow::Result<()> {
|
||||
self.panel.pause(app)
|
||||
}
|
||||
|
||||
fn resume(&mut self, _app: &mut state::AppState) -> anyhow::Result<()> {
|
||||
fn resume(&mut self, app: &mut state::AppState) -> anyhow::Result<()> {
|
||||
self.just_resumed = true;
|
||||
Ok(())
|
||||
self.panel.resume(app)
|
||||
}
|
||||
|
||||
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||
let should_render_panel = self.panel.should_render(app)?;
|
||||
|
||||
let Some(toplevel) = app
|
||||
.wvr_server
|
||||
.as_ref()
|
||||
@@ -162,22 +202,37 @@ impl OverlayBackend for WvrWindowBackend {
|
||||
let mut meta = FrameMeta {
|
||||
extent: surf.image.image().extent(),
|
||||
format: surf.image.format(),
|
||||
clear: WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.0]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Some(pipeline) = self.pipeline.as_mut() {
|
||||
let inner_extent = meta.extent;
|
||||
|
||||
meta.extent[0] += BORDER_SIZE * 2;
|
||||
meta.extent[1] += BORDER_SIZE * 2 + BAR_SIZE;
|
||||
meta.extent[2] = pipeline.get_depth();
|
||||
if self
|
||||
.meta
|
||||
.is_some_and(|old| old.extent[..2] != meta.extent[..2])
|
||||
{
|
||||
pipeline.set_extent(app, [meta.extent[0] as _, meta.extent[1] as _])?;
|
||||
pipeline.set_extent(
|
||||
app,
|
||||
[inner_extent[0] as _, inner_extent[1] as _],
|
||||
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
|
||||
)?;
|
||||
self.interaction_transform =
|
||||
Some(ui_transform(meta.extent.extent_u32arr()));
|
||||
}
|
||||
} else {
|
||||
let pipeline =
|
||||
ScreenPipeline::new(&meta, app, self.stereo.unwrap_or(StereoMode::None))?;
|
||||
let pipeline = ScreenPipeline::new(
|
||||
&meta,
|
||||
app,
|
||||
self.stereo.unwrap_or(StereoMode::None),
|
||||
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
|
||||
)?;
|
||||
meta.extent[0] += BORDER_SIZE * 2;
|
||||
meta.extent[1] += BORDER_SIZE * 2 + BAR_SIZE;
|
||||
meta.extent[2] = pipeline.get_depth();
|
||||
self.pipeline = Some(pipeline);
|
||||
self.interaction_transform = Some(ui_transform(meta.extent.extent_u32arr()));
|
||||
@@ -215,7 +270,7 @@ impl OverlayBackend for WvrWindowBackend {
|
||||
} else if dirty {
|
||||
Ok(ShouldRender::Should)
|
||||
} else {
|
||||
Ok(ShouldRender::Can)
|
||||
Ok(should_render_panel)
|
||||
}
|
||||
} else {
|
||||
log::trace!("{}: no buffer for wl_surface", self.name);
|
||||
@@ -229,6 +284,8 @@ impl OverlayBackend for WvrWindowBackend {
|
||||
app: &mut state::AppState,
|
||||
rdr: &mut RenderResources,
|
||||
) -> anyhow::Result<()> {
|
||||
self.panel.render(app, rdr)?;
|
||||
|
||||
let image = self.cur_image.as_ref().unwrap().clone();
|
||||
|
||||
self.pipeline
|
||||
@@ -264,6 +321,7 @@ impl OverlayBackend for WvrWindowBackend {
|
||||
|
||||
let pass = self.popups_pipeline.create_pass(
|
||||
extentf,
|
||||
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
|
||||
buf_vert,
|
||||
0..4,
|
||||
0..1,
|
||||
@@ -308,8 +366,8 @@ impl OverlayBackend for WvrWindowBackend {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_left(&mut self, _app: &mut state::AppState, _pointer: usize) {
|
||||
// Ignore event
|
||||
fn on_left(&mut self, app: &mut state::AppState, pointer: usize) {
|
||||
self.panel.on_left(app, pointer);
|
||||
}
|
||||
|
||||
fn on_pointer(&mut self, app: &mut state::AppState, hit: &input::PointerHit, pressed: bool) {
|
||||
|
||||
Reference in New Issue
Block a user