From 17ee3c8307689fdcc4dfddac4e8344181f41aab6 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Sat, 16 May 2026 16:09:13 +0200 Subject: [PATCH] add dialogwindow --- application/src/window.rs | 15 ++++ ui-rs/src/ui/ffi.rs | 5 ++ ui-rs/src/ui/toolkit.rs | 2 +- ui-rs/src/ui/window.rs | 181 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 193 insertions(+), 10 deletions(-) diff --git a/application/src/window.rs b/application/src/window.rs index e32fee9..3e3fe14 100644 --- a/application/src/window.rs +++ b/application/src/window.rs @@ -41,6 +41,21 @@ pub struct MainWindow { impl MainWindow { #[action] pub fn new_notebook(&mut self, _event: &ActionEvent) { + println!("new notebook"); + } + + #[action] + pub fn new_note(&mut self, _event: &ActionEvent) { + + } + + #[action] + pub fn go_back(&mut self, _event: &ActionEvent) { + + } + + #[action] + pub fn go_forward(&mut self, _event: &ActionEvent) { } } diff --git a/ui-rs/src/ui/ffi.rs b/ui-rs/src/ui/ffi.rs index baae610..bac96bc 100644 --- a/ui-rs/src/ui/ffi.rs +++ b/ui-rs/src/ui/ffi.rs @@ -177,6 +177,11 @@ pub struct UiDialogArgs { _private: [u8; 0], } +#[repr(C)] +pub struct UiDialogWindowArgs { + _private: [u8; 0], +} + #[repr(C)] pub struct UiModel { _private: [u8; 0], diff --git a/ui-rs/src/ui/toolkit.rs b/ui-rs/src/ui/toolkit.rs index 1923f29..3edc5ff 100644 --- a/ui-rs/src/ui/toolkit.rs +++ b/ui-rs/src/ui/toolkit.rs @@ -109,7 +109,7 @@ impl UiContext { } } -extern "C" fn destroy_boxed(data: *mut c_void) { +pub extern "C" fn destroy_boxed(data: *mut c_void) { if data.is_null() { return; } diff --git a/ui-rs/src/ui/window.rs b/ui-rs/src/ui/window.rs index fe933e3..f84d381 100644 --- a/ui-rs/src/ui/window.rs +++ b/ui-rs/src/ui/window.rs @@ -32,8 +32,8 @@ use std::ffi::{c_char, c_int, c_void}; use std::ffi::{c_uint, CString}; use std::marker::PhantomData; -use crate::ui::{event, event_wrapper_oneshot, ffi, toolkit, ui_object_ref, ui_update_action_bindings, AppContext, EventWrapper, NoAppData, UiActions, UiModel}; -use crate::ui::ffi::{UiButtonArgs, UiCallback, UiContext, UiDestructor, UiDialogArgs, UiObject}; +use crate::ui::{destroy_boxed, event, event_wrapper_oneshot, ffi, toolkit, ui_object_ref, ui_update_action_bindings, AppContext, EventWrapper, NoAppData, UiActions, UiModel}; +use crate::ui::ffi::{UiButtonArgs, UiCallback, UiContext, UiDestructor, UiDialogArgs, UiDialogWindowArgs, UiObject}; use crate::ui::widget::widget_fn; impl toolkit::UiObject { @@ -68,10 +68,11 @@ enum WindowType { Standard, SplitView(bool), Sidebar, - Simple + Simple, + DialogWindow } -fn window_create(title: &str, kind: WindowType, data: T, create_ui: F) -> toolkit::UiObject +fn window_create(parent: *mut ffi::UiObject, title: &str, kind: WindowType, args: *mut UiDialogWindowArgs, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { // create the window let objptr = unsafe { @@ -80,7 +81,8 @@ where F: FnOnce(&mut toolkit::UiObject, &mut T) { WindowType::SplitView(val) => ui_splitview_window(str.as_ptr(), val as c_int), WindowType::Sidebar => ui_sidebar_window(str.as_ptr()), WindowType::Standard => ui_window(str.as_ptr()), - WindowType::Simple => ui_simple_window(str.as_ptr()) + WindowType::Simple => ui_simple_window(str.as_ptr()), + WindowType::DialogWindow => ui_dialog_window_create(parent, args) } }; // because we use additional reference counting in the Rust UiObject wrapper, @@ -127,26 +129,26 @@ impl AppContext { pub fn window(&self, title: &str, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { - window_create(title, WindowType::Standard, data, create_ui) + window_create(std::ptr::null_mut(), title, WindowType::Standard, std::ptr::null_mut(), data, create_ui) } pub fn sidebar_window(&self, title: &str, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { - window_create(title, WindowType::Sidebar, data, create_ui) + window_create(std::ptr::null_mut(), title, WindowType::Sidebar, std::ptr::null_mut(), data, create_ui) } pub fn splitview_window(&self, title: &str, sidebar: bool, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { - window_create(title, WindowType::SplitView(sidebar), data, create_ui) + window_create(std::ptr::null_mut(), title, WindowType::SplitView(sidebar), std::ptr::null_mut(), data, create_ui) } } pub fn simple_window(title: &str, data: T, create_ui: F) -> toolkit::UiObject where F: FnOnce(&mut toolkit::UiObject, &mut T) { - window_create(title, WindowType::Simple, data, create_ui) + window_create(std::ptr::null_mut(), title, WindowType::Simple, std::ptr::null_mut(), data, create_ui) } /* ---------------------------------- dialogs ---------------------------------- */ @@ -246,6 +248,135 @@ impl DialogBuilder { } } + +pub struct DialogWindowBuilder { + args: *mut UiDialogWindowArgs, + parent: *mut ffi::UiObject, + onclick: Option>>, + _marker: PhantomData +} + +impl Drop for DialogWindowBuilder { + fn drop(&mut self) { + unsafe { + ui_dialogwindow_args_free(self.args); + } + } +} + +impl DialogWindowBuilder { + pub fn create(&mut self, data: T, create_ui: F) -> toolkit::UiObject + where F: FnOnce(&mut toolkit::UiObject, &mut T) { + let ptr = if let Some(onclick) = self.onclick.take() { + let ptr = Box::into_raw(onclick); + unsafe { + ui_dialogwindow_args_set_onclick(self.args, Some(event::event_wrapper::)); + ui_dialogwindow_args_set_onclickdata(self.args, ptr as *mut c_void); + } + ptr + } else { + std::ptr::null_mut() + }; + let obj = window_create(self.parent, "", WindowType::DialogWindow, self.args, data, create_ui); + if !ptr.is_null() { + unsafe { + ui_reg_destructor(obj.ctx.ptr, ptr as *mut c_void, destroy_boxed::>); + } + } + self.onclick = None; + obj + } + + pub fn modal(&mut self, val: bool) -> &mut Self { + unsafe { + ui_dialogwindow_args_set_modal(self.args, if val { 1 } else { 2 }); + } + self + } + + pub fn titlebar_buttons(&mut self, val: bool) -> &mut Self { + unsafe { + ui_dialogwindow_args_set_titlebar_buttons(self.args, if val { 1 } else { 2 }); + } + self + } + + pub fn show_closebutton(&mut self, val: bool) -> &mut Self { + unsafe { + ui_dialogwindow_args_set_show_closebutton(self.args, if val { 1 } else { 2 }); + } + self + } + + pub fn title(&mut self, val: &str) -> &mut Self { + let cstr = CString::new(val).unwrap(); + unsafe { + ui_dialogwindow_args_set_title(self.args, cstr.as_ptr()); + } + self + } + + pub fn lbutton1(&mut self, val: &str) -> &mut Self { + let cstr = CString::new(val).unwrap(); + unsafe { + ui_dialogwindow_args_set_lbutton1(self.args, cstr.as_ptr()); + } + self + } + + pub fn lbutton2(&mut self, val: &str) -> &mut Self { + let cstr = CString::new(val).unwrap(); + unsafe { + ui_dialogwindow_args_set_lbutton2(self.args, cstr.as_ptr()); + } + self + } + + pub fn rbutton3(&mut self, val: &str) -> &mut Self { + let cstr = CString::new(val).unwrap(); + unsafe { + ui_dialogwindow_args_set_rbutton3(self.args, cstr.as_ptr()); + } + self + } + + pub fn rbutton4(&mut self, val: &str) -> &mut Self { + let cstr = CString::new(val).unwrap(); + unsafe { + ui_dialogwindow_args_set_rbutton4(self.args, cstr.as_ptr()); + } + self + } + + pub fn default_button(&mut self, button: i32) -> &mut Self { + unsafe { + ui_dialogwindow_args_set_default_button(self.args, button); + } + self + } + + pub fn width(&mut self, val: i32) -> &mut Self { + unsafe { + ui_dialogwindow_args_set_width(self.args, val); + } + self + } + + pub fn height(&mut self, val: i32) -> &mut Self { + unsafe { + ui_dialogwindow_args_set_height(self.args, val); + } + self + } + + pub fn onclick(&mut self, f: F) -> &mut Self + where F: FnMut(&mut event::Event) + 'static { + self.onclick = Some(Box::new(EventWrapper { callback: Box::new(f) })); + self + } +} + + impl toolkit::UiObject { pub fn dialog_builder(&self) -> DialogBuilder { DialogBuilder { @@ -264,6 +395,17 @@ impl toolkit::UiObject { builder.create(); } + pub fn dialogwindow_builder(&self) -> DialogWindowBuilder { + unsafe { + DialogWindowBuilder { + args: ui_dialogwindow_args_new(), + parent: self.ptr, + onclick: None, + _marker: PhantomData, + } + } + } + pub fn openfile_dialog(&mut self, multiselect: bool, callback: F) where F: FnMut(&mut event::Event) + 'static { openfile_dialog(self, multiselect as c_uint, callback); @@ -326,6 +468,7 @@ extern "C" { fn ui_simple_window(title: *const c_char) -> *mut UiObject; fn ui_dialog_create(parent: *mut UiObject, args: *mut UiDialogArgs); + fn ui_dialog_window_create(parent: *mut UiObject, args: *mut UiDialogWindowArgs) -> *mut UiObject; fn ui_window_size(obj: *mut UiObject, width: c_int, height: c_int); fn ui_window_menubar_set_visible(obj: *mut UiObject, visible: c_int) -> c_int; @@ -353,6 +496,26 @@ extern "C" { fn ui_dialog_args_set_resultdata(args: *mut UiDialogArgs, data: *mut c_void); fn ui_dialog_args_free(args: *mut UiDialogArgs); + fn ui_dialogwindow_args_new() -> *mut UiDialogWindowArgs; + fn ui_dialogwindow_args_set_modal(args: *mut ffi::UiDialogWindowArgs, value: c_int); + fn ui_dialogwindow_args_set_titlebar_buttons(args: *mut ffi::UiDialogWindowArgs, value: c_int); + fn ui_dialogwindow_args_set_show_closebutton(args: *mut ffi::UiDialogWindowArgs, value: c_int); + fn ui_dialogwindow_args_set_title(args: *mut ffi::UiDialogWindowArgs, title: *const c_char); + fn ui_dialogwindow_args_set_lbutton1(args: *mut ffi::UiDialogWindowArgs, label: *const c_char); + fn ui_dialogwindow_args_set_lbutton2(args: *mut ffi::UiDialogWindowArgs, label: *const c_char); + fn ui_dialogwindow_args_set_rbutton3(args: *mut ffi::UiDialogWindowArgs, label: *const c_char); + fn ui_dialogwindow_args_set_rbutton4(args: *mut ffi::UiDialogWindowArgs, label: *const c_char); + fn ui_dialogwindow_args_set_lbutton1_states(args: *mut ffi::UiDialogWindowArgs, states: *const c_int, numstates: c_int); + fn ui_dialogwindow_args_set_lbutton2_states(args: *mut ffi::UiDialogWindowArgs, states: *const c_int, numstates: c_int); + fn ui_dialogwindow_args_set_rbutton3_states(args: *mut ffi::UiDialogWindowArgs, states: *const c_int, numstates: c_int); + fn ui_dialogwindow_args_set_rbutton4_states(args: *mut ffi::UiDialogWindowArgs, states: *const c_int, numstates: c_int); + fn ui_dialogwindow_args_set_default_button(args: *mut ffi::UiDialogWindowArgs, button: c_int); + fn ui_dialogwindow_args_set_width(args: *mut ffi::UiDialogWindowArgs, width: c_int); + fn ui_dialogwindow_args_set_height(args: *mut ffi::UiDialogWindowArgs, height: c_int); + fn ui_dialogwindow_args_set_onclick(args: *mut ffi::UiDialogWindowArgs, cb: UiCallback); + fn ui_dialogwindow_args_set_onclickdata(args: *mut ffi::UiDialogWindowArgs, data: *mut c_void); + fn ui_dialogwindow_args_free(args: *mut ffi::UiDialogWindowArgs); + fn ui_openfiledialog(obj: *mut ffi::UiObject, mode: c_uint, callback: UiCallback, data: *mut c_void); fn ui_savefiledialog(obj: *mut ffi::UiObject, name: *const c_char, callback: UiCallback, data: *mut c_void); } -- 2.47.3