From: Olaf Wintermann Date: Sun, 1 Feb 2026 17:36:32 +0000 (+0100) Subject: note_search scrolls to the found text X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=HEAD;p=note.git note_search scrolls to the found text --- diff --git a/application/note.c b/application/note.c index b64fe85..e23d53f 100644 --- a/application/note.c +++ b/application/note.c @@ -408,6 +408,7 @@ static void note_search(NoteModel *note, bool backwards) { if(text_search(text, searchstr, pos, backwards, regex, cs, &begin, &end)) { note->text->setposition(note->text, end); note->text->setselection(note->text, begin, end); + note->text->showposition(note->text, begin); } } diff --git a/ui/common/action.c b/ui/common/action.c new file mode 100644 index 0000000..9c53b5d --- /dev/null +++ b/ui/common/action.c @@ -0,0 +1,73 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "action.h" +#include "context.h" + +#include + +void uic_add_action( + UiContext *ctx, + const char *name, + ui_callback callback, + void *userdata, + const char *accelerator, + const char *accelerator_text) +{ + if(!name) { + return; + } + + UiAction action; + action.name = ui_strdup(ctx, name); + action.callback = callback; + action.userdata = userdata; + action.accelerator = accelerator ? ui_strdup(ctx, accelerator) : NULL; + action.accelerator_text = accelerator_text ? ui_strdup(ctx, accelerator_text) : NULL; + cxMapPut(ctx->actions, name, &action); + cxMapRehash(ctx->actions); +} + +void uic_bind_action( + UiContext *ctx, + const char *action, + void *bind_obj, + ui_action_binding_set_enabled_func set_enabled, + ui_action_binding_set_accelerator_text_func set_accelerator_text) +{ + if(!action) { + return; + } + + UiActionBinding binding; + binding.action = ui_strdup(ctx, action); + binding.userdata = bind_obj; + binding.set_enabled = set_enabled; + binding.set_accelerator_text = set_accelerator_text; + cxListAdd(ctx->action_bindings, &binding); +} diff --git a/ui/common/action.h b/ui/common/action.h new file mode 100644 index 0000000..a363827 --- /dev/null +++ b/ui/common/action.h @@ -0,0 +1,78 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UIC_ACTION_H +#define UIC_ACTION_H + +#include "../ui/toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UiAction UiAction; +typedef struct UiActionBinding UiActionBinding; + +struct UiAction { + char *name; + char *accelerator; + char *accelerator_text; + ui_callback callback; + void *userdata; +}; + +typedef void (*ui_action_binding_set_enabled_func)(void *bind_obj, UiBool enabled); +typedef void (*ui_action_binding_set_accelerator_text_func)(void *bind_obj, const char *text); +struct UiActionBinding { + const char *action; + ui_action_binding_set_enabled_func set_enabled; + ui_action_binding_set_accelerator_text_func set_accelerator_text; + void *userdata; +}; + +void uic_add_action( + UiContext *ctx, + const char *name, + ui_callback callback, + void *userdata, + const char *accelerator, + const char *accelerator_text); + +void uic_bind_action( + UiContext *ctx, + const char *action, + void *bind_obj, + ui_action_binding_set_enabled_func set_enabled, + ui_action_binding_set_accelerator_text_func set_accelerator_text); + +#ifdef __cplusplus +} +#endif + +#endif /* UIC_ACTION_H */ + diff --git a/ui/common/context.c b/ui/common/context.c index 4909d93..3e7abfc 100644 --- a/ui/common/context.c +++ b/ui/common/context.c @@ -68,6 +68,9 @@ UiContext* uic_context(UiObject *toplevel, CxMempool *mp) { ctx->states = cxArrayListCreate(mp->allocator, sizeof(int), 32); cxSetCompareFunc(ctx->states, cx_cmp_int); + ctx->actions = cxHashMapCreate(ctx->allocator, sizeof(UiAction), 8); + ctx->action_bindings = cxArrayListCreate(ctx->allocator, sizeof(UiActionBinding), 0); + ctx->attach_document = uic_context_attach_document; ctx->detach_document2 = uic_context_detach_document; diff --git a/ui/common/context.h b/ui/common/context.h index 9a73efa..de80481 100644 --- a/ui/common/context.h +++ b/ui/common/context.h @@ -36,6 +36,8 @@ #include #include +#include "action.h" + #ifdef __cplusplus extern "C" { #endif @@ -72,6 +74,9 @@ struct UiContext { CxList *states; // int list CxList *state_widgets; // UiGroupWidget list + CxMap *actions; // key: action name (string), value: UiAction + CxList *action_bindings; // UiActionBinding list + void (*attach_document)(UiContext *ctx, void *document); void (*detach_document2)(UiContext *ctx, void *document); diff --git a/ui/common/objs.mk b/ui/common/objs.mk index e69125c..2ce73a5 100644 --- a/ui/common/objs.mk +++ b/ui/common/objs.mk @@ -32,6 +32,7 @@ COMMON_OBJPRE = $(OBJ_DIR)$(COMMON_SRC_DIR) COMMON_OBJ = context$(OBJ_EXT) COMMON_OBJ += document$(OBJ_EXT) COMMON_OBJ += object$(OBJ_EXT) +COMMON_OBJ += action$(OBJ_EXT) COMMON_OBJ += container$(OBJ_EXT) COMMON_OBJ += types$(OBJ_EXT) COMMON_OBJ += app$(OBJ_EXT) diff --git a/ui/common/types.c b/ui/common/types.c index 67e1225..38e6b6c 100644 --- a/ui/common/types.c +++ b/ui/common/types.c @@ -678,6 +678,7 @@ void uic_text_copy(UiText *from, UiText *to) { to->insert = from->insert; to->setposition = from->setposition; to->position = from->position; + to->showposition = from->showposition; to->setselection = from->setselection; to->selection = from->selection; to->length = from->length; diff --git a/ui/gtk/text.c b/ui/gtk/text.c index 36f25b9..fd355ee 100644 --- a/ui/gtk/text.c +++ b/ui/gtk/text.c @@ -131,6 +131,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { uitext->onchangedata = args->onchangedata; g_object_set_data(G_OBJECT(text_area), "ui_textarea", uitext); + g_object_set_data(G_OBJECT(text_area), "ui_textarea_widget", text_area); g_signal_connect( text_area, @@ -144,6 +145,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS SCROLLEDWINDOW_SET_CHILD(scroll_area, text_area); + g_object_set_data(G_OBJECT(scroll_area), "ui_textarea_widget", text_area); ui_widget_size_request(scroll_area, args->width, args->height); @@ -186,6 +188,7 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) { value->insert = ui_textarea_insert; value->setposition = ui_textarea_setposition; value->position = ui_textarea_position; + value->showposition = ui_textarea_showposition; value->setselection = ui_textarea_setselection; value->selection = ui_textarea_selection; value->length = ui_textarea_length; @@ -211,8 +214,21 @@ void ui_textarea_destroy(GtkWidget *object, UiTextArea *textarea) { free(textarea); } +void ui_textarea_scroll_to(UIWIDGET textarea, int pos) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_scroll_to: widget is not a textarea\n"); + } + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + + GtkTextIter offset; + gtk_text_buffer_get_iter_at_offset(buf, &offset, pos); + + gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(widget), &offset, 0.2, FALSE, 0, 0); +} + UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea) { - return SCROLLEDWINDOW_GET_CHILD(textarea); + return g_object_get_data(G_OBJECT(textarea), "ui_textarea_widget"); } void ui_textarea_save(UiText *text) { @@ -296,6 +312,10 @@ int ui_textarea_position(UiText *text) { return text->pos; } +void ui_textarea_showposition(UiText *text, int pos) { + ui_textarea_scroll_to(text->obj, pos); +} + void ui_textarea_setselection(UiText *text, int begin, int end) { GtkTextBuffer *buf = text->data1; GtkTextIter ib; diff --git a/ui/gtk/text.h b/ui/gtk/text.h index 701ed7f..a976cbc 100644 --- a/ui/gtk/text.h +++ b/ui/gtk/text.h @@ -120,6 +120,7 @@ char* ui_textarea_getsubstr(UiText *text, int begin, int end); void ui_textarea_insert(UiText *text, int pos, char *str); void ui_textarea_setposition(UiText *text, int pos); int ui_textarea_position(UiText *text); +void ui_textarea_showposition(UiText *text, int pos); void ui_textarea_setselection(UiText *text, int begin, int end); void ui_textarea_selection(UiText *text, int *begin, int *end); int ui_textarea_length(UiText *text); diff --git a/ui/ui/menu.h b/ui/ui/menu.h index 43cca7e..bd5b96b 100644 --- a/ui/ui/menu.h +++ b/ui/ui/menu.h @@ -37,31 +37,38 @@ extern "C" { typedef struct UiMenuItemArgs { - const char* label; - const char* icon; + const char *label; + const char *icon; ui_callback onclick; - void* onclickdata; + void *onclickdata; + const char *action; + const char *accelerator; + const char *accelerator_text; - const int* states; + const int *states; } UiMenuItemArgs; typedef struct UiMenuToggleItemArgs { - const char* label; - const char* icon; + const char *label; + const char *icon; - const char* varname; + const char *varname; ui_callback onchange; - void* onchangedata; + void *onchangedata; + const char *action; + const char *accelerator; + const char *accelerator_text; - const int* nstates; + const int *nstates; } UiMenuToggleItemArgs; typedef struct UiMenuItemListArgs { - const char* varname; + const char *varname; ui_getvaluefunc getvalue; ui_callback onselect; - void* onselectdata; + void *onselectdata; + const char *action; UiBool addseparator; } UiMenuItemListArgs; diff --git a/ui/ui/text.h b/ui/ui/text.h index 9fed6b8..ebea880 100644 --- a/ui/ui/text.h +++ b/ui/ui/text.h @@ -149,6 +149,8 @@ UIEXPORT UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea); UIEXPORT void ui_text_undo(UiText *value); UIEXPORT void ui_text_redo(UiText *value); +UIEXPORT void ui_textarea_scroll_to(UIWIDGET textarea, int pos); + #define ui_textfield(obj, ...) ui_textfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ }) #define ui_frameless_textfield(obj, ...) ui_frameless_field_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ }) #define ui_passwordfield(obj, ...) ui_passwordfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ }) diff --git a/ui/ui/toolbar.h b/ui/ui/toolbar.h index 2e230df..29319ec 100644 --- a/ui/ui/toolbar.h +++ b/ui/ui/toolbar.h @@ -42,7 +42,10 @@ typedef struct UiToolbarItemArgs { const char *tooltip; ui_callback onclick; - void* onclickdata; + void *onclickdata; + const char *action; + const char *accelerator; + const char *accelerator_text; const int *states; const int *visibility_states; @@ -56,6 +59,9 @@ typedef struct UiToolbarToggleItemArgs { const char *varname; ui_callback onchange; void *onchangedata; + const char *action; + const char *accelerator; + const char *accelerator_text; const int *states; const int *visibility_states; diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h index 9d23073..9fbc658 100644 --- a/ui/ui/toolkit.h +++ b/ui/ui/toolkit.h @@ -395,6 +395,7 @@ struct UiText { void (*insert)(UiText*, int, char*); void (*setposition)(UiText*,int); int (*position)(UiText*); + void (*showposition)(UiText*, int); void (*setselection)(UiText*, int, int); /* text, begin, end */ void (*selection)(UiText*, int*, int*); /* text, begin, end */ int (*length)(UiText*);