GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
Support default draggable Window objects via ui_context provider
src/backend/window_runner.rs | 13 +++++++++++++
src/context.rs | 21 +++++++++++++++++++++
src/layout.rs | 4 ++++
src/widget/container/window.rs | 15 +++++++++++++++
src/widget/mod.rs | 1 +
5 files changed, 54 insertions(+)
diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 097422f..d877d7e 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -900,6 +900,10 @@ pub trait Application: Sized + 'static {
fn text_items(&self) -> &[TextItem];
fn render_popovers(&self, _pc: &mut dyn crate::layout::RenderTarget) {}
+ fn ui_context(&self) -> Option<&crate::context::UiContext> {
+ None
+ }
+
fn text_areas(&self, scale_f32: f32, bounds: TextBounds) -> Vec<TextArea<'_>> {
let overlay_rects: Vec<(f32, f32, f32, f32)> = Vec::new();
@@ -1687,7 +1691,16 @@ impl<A: Application> PointerHandler for EngineState<A> {
}
// Titlebar drag check: y is in [8.0, 32.0], and x is not in the top-right button area
+ let mut should_move = false;
if ly >= border && ly < 32.0 && lx < self.logical_width - 70.0 {
+ should_move = true;
+ } else if let Some(ctx) = self.inner.ui_context() {
+ if ctx.is_movable_window_at(lx, ly) {
+ should_move = true;
+ }
+ }
+
+ if should_move {
if let Some(ref window) = self.window {
if let Some(seat) = self.seats.first() {
window.move_(seat, *serial);
diff --git a/src/context.rs b/src/context.rs
index e8d5d3b..0465fe1 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -477,4 +477,25 @@ impl UiContext {
pub fn context_menu_labels(&self) -> Vec<crate::widget::display::TextLabel> {
crate::widget::context_menu::text_labels()
}
+
+ pub fn is_movable_window_at(&self, px: f32, py: f32) -> bool {
+ let mut hit_window = false;
+ for &ptr in self.widget_registry.values() {
+ unsafe {
+ if !ptr.is_null() {
+ let w = &*ptr;
+ if w.hit_test(px, py, self) {
+ if w.is_window() {
+ if w.is_movable_window() {
+ hit_window = true;
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ hit_window
+ }
}
diff --git a/src/layout.rs b/src/layout.rs
index 81fcce2..228d7d8 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -1744,6 +1744,10 @@ fn get_keybinds_control_sub_widget_info(
}
pub fn render_widget<T: Element + 'static>(pc: &mut dyn RenderTarget, w: &mut T, x: f32, y: f32, ww: f32, wh: f32, ctx: &mut UiContext) {
+ let id = w.base().map(|b| b.id());
+ if let Some(w_id) = id {
+ ctx.register_widget(w_id, w.as_ptr_mut());
+ }
w.layout(crate::widget::Point { x, y }, crate::widget::LayoutConstraints::new(ww, ww, wh, wh), ctx);
let corners = w.rounded_corners();
let r = if corners != (false, false, false, false) {
diff --git a/src/widget/container/window.rs b/src/widget/container/window.rs
index 0d66fc7..4ee5bfe 100644
--- a/src/widget/container/window.rs
+++ b/src/widget/container/window.rs
@@ -12,6 +12,7 @@ pub struct Window {
pub radius: f32,
pub background_color: Option<[f32; 4]>,
pub visible: bool,
+ pub movable: bool,
}
impl Window {
@@ -25,9 +26,15 @@ impl Window {
radius: crate::color::window_corner_radius(),
background_color: None,
visible: true,
+ movable: true,
}
}
+ pub fn with_movable(mut self, movable: bool) -> Self {
+ self.movable = movable;
+ self
+ }
+
pub fn with_border(mut self, color: [f32; 4], thickness: f32) -> Self {
self.border_color = Some(color);
self.border_thickness = thickness;
@@ -299,6 +306,10 @@ impl Element for Window {
fn is_window(&self) -> bool {
true
}
+
+ fn is_movable_window(&self) -> bool {
+ self.movable
+ }
}
impl Drop for Window {
@@ -323,6 +334,10 @@ mod tests {
assert_eq!(win.solid_border(), Some(([1.0, 0.0, 0.0, 1.0], 2.5)));
assert_eq!(win.corner_radius(), 8.0);
assert_eq!(win.rounded_corners(), (true, true, true, true));
+ assert!(win.is_movable_window());
+
+ let non_movable_win = win.with_movable(false);
+ assert!(!non_movable_win.is_movable_window());
}
#[test]
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index 02482ab..3770534 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -517,6 +517,7 @@ pub trait Element {
fn is_page(&self) -> bool { false }
fn is_layer(&self) -> bool { false }
fn is_window(&self) -> bool { false }
+ fn is_movable_window(&self) -> bool { false }
fn rounded_corners(&self) -> (bool, bool, bool, bool) { (false, false, false, false) }
fn corner_radius(&self) -> f32 { 12.0 }