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);
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);
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");
#[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);
}
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);
+ }
+ }
}
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);
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);
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) {
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;
}
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;
}
}
gw->enable(gw->widget, enable);
}
- free(groups);
+ free(states);
}
void ui_widget_set_states(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {