]> uap-core.de Git - note.git/commitdiff
disable the new note button when the current note is new and empty main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Tue, 16 Jun 2026 15:40:36 +0000 (17:40 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Tue, 16 Jun 2026 15:40:36 +0000 (17:40 +0200)
application/src/note.rs
application/src/window.rs
ui-rs/src/ui/toolkit.rs
ui/common/context.c
ui/common/context.h
ui/ui/toolkit.h

index 28352f0404924607c31275cdeb191a99c0ac7bbb..51aa015d5b4310579aa396765edfbca30be4855e 100644 (file)
@@ -101,6 +101,7 @@ impl Note {
             n.doc = d.doc_ref();
             if n.id.is_new() {
                 n.init_new();
+                d.ctx.suppress_state(AppStates::NoteEnableNew as i32);
             } else {
                 n.init_from_model(model);
                 n.load_content(d);
@@ -264,7 +265,7 @@ impl Note {
 
         let proxy = doc.doc_proxy();
         self.backend.save_note(self.id.clone(), note, Some(notecontent), |result|{
-            proxy.call_mainthread(move |_doc, note|{
+            proxy.call_mainthread(move |doc, note|{
                 match result {
                     SaveNoteResult::Ok((notemodel, content_id)) => {
                         note.id = NoteId::Id(notemodel.note_id);
@@ -273,6 +274,8 @@ impl Note {
                         println!("Note saved: note_id: {}, content_id: {}, version: {}", notemodel.note_id, content_id, note.version);
 
                         note.backend.backend.lockmgr.update_note_version(notemodel.note_id, note.version);
+                        // make sure the "new note" button is always enabled within this note
+                        doc.ctx.unsuppress_state(AppStates::NoteEnableNew as i32);
                     },
                     SaveNoteResult::VersionConflict => {
                         println!("Failed to save note: version conflict");
@@ -316,11 +319,25 @@ impl Note {
 
     #[action]
     pub fn note_text_changed(&mut self, event: &ActionEvent) {
+        let Some(doc) = self.doc.get_doc() else {
+            return;
+        };
+
         if event.set {
             // this event was triggered by UiText.set
             return;
         }
         self.modified = true;
+
+        let text = self.text.get();
+        if self.id.is_new() {
+            if text.is_empty() {
+                doc.ctx.suppress_state(AppStates::NoteEnableNew as i32);
+            } else {
+                doc.ctx.unsuppress_state(AppStates::NoteEnableNew as i32);
+            }
+        }
+
         if !event.set && self.extract_title {
             self.update_title(self.text.get().as_str(), true);
         }
index 8d898922dd3fa4c62cb294e8e6f128410f28c054..7206615523b85b5ac179f15e5e9e925deefc5270 100644 (file)
@@ -190,6 +190,8 @@ pub fn create_window(app: &App, ctx: &AppContext<MainWindow>) -> UiObject<MainWi
         init_window_data(data, app);
         data.obj = obj.obj_ref();
         
+        // this state is basically always set, however there are some situations, where
+        // it is suppressed
         obj.ctx.set_state(AppStates::NoteEnableNew as i32);
 
         obj.sidebar_builder().create(|obj|{
index 298c084cadd53093f178acea7ed103693c780eca..b5c3b53e0fd8c990f33d009f545a6878ea685f76 100644 (file)
@@ -218,6 +218,18 @@ impl UiContext {
             ui_unset_state(self.ptr, state);
         }
     }
+
+    pub fn suppress_state(&self, state: i32) {
+        unsafe {
+            ui_suppress_state(self.ptr, state);
+        }
+    }
+
+    pub fn unsuppress_state(&self, state: i32) {
+        unsafe {
+            ui_unsuppress_state(self.ptr, state);
+        }
+    }
 }
 
 
@@ -1375,6 +1387,8 @@ unsafe extern "C" {
 
     pub fn ui_set_state(ctx: *mut ffi::UiContext, state: c_int);
     pub fn ui_unset_state(ctx: *mut ffi::UiContext, state: c_int);
+    pub fn ui_suppress_state(ctx: *mut ffi::UiContext, state: c_int);
+    pub fn ui_unsuppress_state(ctx: *mut ffi::UiContext, state: c_int);
 
     fn ui_mainthread_object_unref(obj: *mut ffi::UiObject);
     fn ui_mainthread_document_unref(doc: *mut c_void);
index 1fd4c1f510fe390f210f8098ec5334d0fda705ac..78434fa31dd124adc9d9742f4e46fc5ae177f205 100644 (file)
@@ -67,6 +67,8 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) {
     ctx->state_widgets = cxLinkedListCreate(mp->allocator, sizeof(UiStateWidget));
     ctx->states = cxArrayListCreate(mp->allocator, sizeof(int), 32);
     cxSetCompareFunc(ctx->states, cx_cmp_int);
+    ctx->suppressed_states = cxArrayListCreate(mp->allocator, sizeof(int), 16);
+    cxSetCompareFunc(ctx->suppressed_states, cx_cmp_int);
     
     ctx->actions = cxHashMapCreate(ctx->allocator, sizeof(UiAction), 8);
     ctx->action_bindings = cxArrayListCreate(ctx->allocator, sizeof(UiActionBinding), 0);
@@ -682,15 +684,39 @@ void ui_unset_state(UiContext *ctx, int state) {
     uic_check_state_widgets(ui_context_toplevel_parent(ctx));
 }
 
+void ui_suppress_state(UiContext *ctx, int state) {
+    if(!cxListIndexValid(ctx->suppressed_states, cxListFind(ctx->suppressed_states, &state))) {
+        cxListAdd(ctx->suppressed_states, &state);
+    }
+    
+    // enable/disable group widgets
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
+}
+
+void ui_unsuppress_state(UiContext *ctx, int state) {
+    int i = cxListFind(ctx->suppressed_states, &state);
+    if(i != -1) {
+        cxListRemove(ctx->suppressed_states, i);
+    }
+    
+    // enable/disable group widgets
+    uic_check_state_widgets(ui_context_toplevel_parent(ctx));
+}
+
 typedef struct StatesList {
     CX_ARRAY(int, states);
+    CX_ARRAY(int, suppressed);
 } StatesList;
 
 static void add_ctx_states(UiContext *ctx, StatesList *states) {
     size_t nstates = cxListSize(ctx->states);
-    int *ctx_states = cxListAt(ctx->states, 0);;
+    int *ctx_states = cxListAt(ctx->states, 0);
+    
+    size_t nsuppressed = cxListSize(ctx->suppressed_states);
+    int *ctx_suppressed_states = cxListAt(ctx->suppressed_states, 0);
     
     cx_array_add_array(states->states, ctx_states, nstates);
+    cx_array_add_array(states->suppressed, ctx_suppressed_states, nsuppressed);
     
     CxIterator i = cxListIterator(ctx->documents);
     cx_foreach(void *, doc, i) {
@@ -702,7 +728,28 @@ static void add_ctx_states(UiContext *ctx, StatesList *states) {
 int* ui_active_states(UiContext *ctx, int *nstates) {
     StatesList states;
     cx_array_init(states.states, 32);
+    cx_array_init(states.suppressed, 8);
     add_ctx_states(ctx, &states);
+    
+    // remove suppressed states
+    for(size_t i=0;i<states.suppressed.size;i++) {
+        int suppressed = states.suppressed.data[i];
+        // important to use ssize_t for the index here
+        for(ssize_t s=0;s<states.states.size;s++) {
+            if(states.states.data[s] == suppressed) {
+                // this state is suppressed
+                if(s+1 < states.states.size) {
+                    // copy last element to the current position
+                    states.states.data[s] = states.states.data[states.states.size-1];
+                    // we need to check the current index again
+                    s--;
+                }
+                states.states.size--;
+            }
+        }
+    }
+    
+    free(states.suppressed.data);
     *nstates = (int)states.states.size;
     return states.states.data;
 }
@@ -712,16 +759,16 @@ void uic_check_state_widgets(UiContext *ctx) {
         return;
     }
     
-    int ngroups = 0;
-    int *groups = ui_active_states(ctx, &ngroups);
+    int nstates = 0;
+    int *states = ui_active_states(ctx, &nstates);
     
     CxIterator i = cxListIterator(ctx->state_widgets);
     cx_foreach(UiStateWidget *, gw, i) {
         char *check = calloc(1, gw->numstates);
         
-        for(int i=0;i<ngroups;i++) {
+        for(int i=0;i<nstates;i++) {
             for(int k=0;k<gw->numstates;k++) {
-                if(groups[i] == gw->states[k]) {
+                if(states[i] == gw->states[k]) {
                     check[k] = 1;
                 }
             }
@@ -738,7 +785,7 @@ void uic_check_state_widgets(UiContext *ctx) {
         gw->enable(gw->widget, enable);
     }
     
-    free(groups);
+    free(states);
 }
 
 void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {
index 45a9dda9893f6feb2b2d9a76733ec497626daf2f..f742d38fd66c320392801defd372205743f1f454 100644 (file)
@@ -75,6 +75,7 @@ struct UiContext {
     CxMap         *vars;
     
     CxList        *states; // int list
+    CxList        *suppressed_states; // int list
     CxList        *state_widgets; // UiGroupWidget list
     
     CxMap         *actions; // key: action name (string), value: UiAction
index 848f4fe278f6ebddf931653f6b3fe356c49c9012..0537d58f073ec029fe8ad69f73d2d28025bab62a 100644 (file)
@@ -624,6 +624,8 @@ UIEXPORT void ui_call_action_on(UiContext *ctx, const char *action);
 
 UIEXPORT void ui_set_state(UiContext *ctx, int state);
 UIEXPORT void ui_unset_state(UiContext *ctx, int state);
+UIEXPORT void ui_suppress_state(UiContext *ctx, int state);
+UIEXPORT void ui_unsuppress_state(UiContext *ctx, int state);
 UIEXPORT int* ui_active_states(UiContext *ctx, int *nstates);
     
 UIEXPORT void* ui_allocator(UiContext *ctx);