From 67ea3dec3792e54a44b095ce7f2cf1a5e2bf955b Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Tue, 28 Apr 2026 16:52:39 +0200 Subject: [PATCH] add TextArea/TextField widget struct, that is returned by the builder create methods --- ui-rs/src/ui/text.rs | 165 ++++++++++++++++++++++++++++++++++++++----- ui/gtk/text.c | 76 ++++++++++++++++++++ ui/ui/text.h | 7 ++ 3 files changed, 232 insertions(+), 16 deletions(-) diff --git a/ui-rs/src/ui/text.rs b/ui-rs/src/ui/text.rs index 63d1b58..30491f9 100644 --- a/ui-rs/src/ui/text.rs +++ b/ui-rs/src/ui/text.rs @@ -32,11 +32,65 @@ use std::ffi::{c_char, c_int, c_void}; use std::ffi::CString; use crate::ui::{event, toolkit, EventWrapper}; use crate::ui::ffi::*; -use crate::ui::widget::widget_fn; +use crate::ui::widget::{widget_fn, Widget}; /* -------------------------------- TextArea -------------------------------- */ +pub struct TextArea { + ptr: *mut c_void +} + +impl Widget for TextArea { + fn get_widget(&self) -> *mut c_void { + self.ptr + } +} + +impl TextArea { + pub fn focus(&mut self) { + unsafe { + ui_textarea_focus(self.ptr); + } + } + + pub fn set_selection(&mut self, begin: usize, end: usize) { + unsafe { + ui_textarea_set_selection(self.ptr, begin as c_int, end as c_int); + } + } + + pub fn select_all(&mut self) { + unsafe { + ui_textarea_select_all(self.ptr); + } + } + + pub fn set_editable(&mut self, editable: bool) { + unsafe { + ui_textarea_set_editable(self.ptr, editable as c_int); + } + } + + pub fn is_editable(&self) -> bool { + unsafe { + ui_textarea_is_editable(self.ptr) != 0 + } + } + + pub fn set_position(&mut self, pos: usize) { + unsafe { + ui_textarea_set_position(self.ptr, pos as c_int); + } + } + + pub fn get_position(&self) -> usize { + unsafe { + ui_textarea_get_position(self.ptr) as usize + } + } +} + pub struct TextAreaBuilder<'a, T> { args: *mut UiTextAreaArgs, obj: &'a mut toolkit::UiObject @@ -62,9 +116,9 @@ impl<'a, T> Drop for TextAreaBuilder<'a, T> { } impl<'a, T> TextAreaBuilder<'a, T> { - pub fn create(&mut self) { + pub fn create(&mut self) -> TextArea { unsafe { - ui_textarea_create(self.obj.ptr, self.args); + TextArea { ptr: ui_textarea_create(self.obj.ptr, self.args) } } } @@ -218,7 +272,68 @@ impl<'a, T> TextAreaBuilder<'a, T> { /* -------------------------------- TextField -------------------------------- */ -pub type TextFieldCreate = fn(*const UiObject, *const UiTextFieldArgs); +pub struct TextField { + ptr: *mut c_void +} + +impl Widget for TextField { + fn get_widget(&self) -> *mut c_void { + self.ptr + } +} + +impl TextField { + pub fn focus(&mut self) { + unsafe { + ui_textfield_focus(self.ptr); + } + } + + pub fn focus_without_selecting(&mut self) { + unsafe { + ui_textfield_focus_without_selecting(self.ptr); + } + } + + pub fn set_selection(&mut self, begin: usize, end: usize) { + unsafe { + ui_textfield_set_selection(self.ptr, begin as c_int, end as c_int); + } + } + + pub fn select_all(&mut self) { + unsafe { + ui_textfield_select_all(self.ptr); + } + } + + pub fn set_editable(&mut self, editable: bool) { + unsafe { + ui_textfield_set_editable(self.ptr, editable as c_int); + } + } + + pub fn is_editable(&self) -> bool { + unsafe { + ui_textfield_is_editable(self.ptr) != 0 + } + } + + pub fn set_position(&mut self, pos: usize) { + unsafe { + ui_textfield_set_position(self.ptr, pos as c_int); + } + } + + pub fn get_position(&self) -> usize { + unsafe { + ui_textfield_get_position(self.ptr) as usize + } + } +} + + +pub type TextFieldCreate = fn(*const UiObject, *const UiTextFieldArgs) -> *mut c_void; pub struct TextFieldBuilder<'a, T> { args: *mut UiTextFieldArgs, @@ -226,21 +341,21 @@ pub struct TextFieldBuilder<'a, T> { create: TextFieldCreate } -pub fn textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) { +pub fn textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) -> *mut c_void { unsafe { - ui_textfield_create(obj, args); + ui_textfield_create(obj, args) } } -pub fn passwordfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) { +pub fn passwordfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) -> *mut c_void { unsafe { - ui_passwordfield_create(obj, args); + ui_passwordfield_create(obj, args) } } -pub fn frameless_textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) { +pub fn frameless_textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) -> *mut c_void { unsafe { - ui_frameless_textfield_create(obj, args); + ui_frameless_textfield_create(obj, args) } } @@ -280,9 +395,9 @@ impl<'a, T> Drop for TextFieldBuilder<'a, T> { } impl<'a, T> TextFieldBuilder<'a, T> { - pub fn create(&mut self) { + pub fn create(&mut self) -> TextField { unsafe { - ui_textfield_create(self.obj.ptr, self.args); + TextField { ptr: ui_textfield_create(self.obj.ptr, self.args) } } } @@ -464,10 +579,10 @@ impl<'a, T> TextFieldBuilder<'a, T> { /* -------------------------------- C functions -------------------------------- */ extern "C" { - fn ui_textarea_create(obj: *const UiObject, args: *const UiTextAreaArgs); - fn ui_textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs); - fn ui_frameless_textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs); - fn ui_passwordfield_create(obj: *const UiObject, args: *const UiTextFieldArgs); + fn ui_textarea_create(obj: *const UiObject, args: *const UiTextAreaArgs) -> *mut c_void; + fn ui_textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) -> *mut c_void; + fn ui_frameless_textfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) -> *mut c_void; + fn ui_passwordfield_create(obj: *const UiObject, args: *const UiTextFieldArgs) -> *mut c_void; fn ui_textfield_args_new() -> *mut UiTextFieldArgs; fn ui_textfield_args_set_fill(args: *mut UiTextFieldArgs, fill: c_int); @@ -520,4 +635,22 @@ extern "C" { fn ui_textarea_args_set_states(args: *mut UiTextAreaArgs, states: *const c_int, numstates: c_int); fn ui_textarea_args_set_visibility_states(args: *mut UiTextAreaArgs, states: *const c_int, numstates: c_int); fn ui_textarea_args_free(args: *mut UiTextAreaArgs); + + fn ui_textarea_focus(textarea: *mut c_void); + fn ui_textarea_set_selection(textarea: *mut c_void, begin: c_int, end: c_int); + fn ui_textarea_select_all(textarea: *mut c_void); + fn ui_textarea_set_editable(textarea: *mut c_void, editable: c_int); + fn ui_textarea_is_editable(textarea: *mut c_void) -> c_int; + fn ui_textarea_set_position(textarea: *mut c_void, pos: c_int); + fn ui_textarea_get_position(textarea: *mut c_void) -> c_int; + fn ui_textarea_scroll_to(textarea: *mut c_void, pos: c_int); + + fn ui_textfield_focus(textfield: *mut c_void); + fn ui_textfield_focus_without_selecting(textfield: *mut c_void); + fn ui_textfield_set_position(textfield: *mut c_void, pos: c_int); + fn ui_textfield_get_position(textfield: *mut c_void) -> c_int; + fn ui_textfield_set_selection(textfield: *mut c_void, begin: c_int, end: c_int); + fn ui_textfield_select_all(textfield: *mut c_void); + fn ui_textfield_set_editable(textfield: *mut c_void, editable: c_int); + fn ui_textfield_is_editable(textfield: *mut c_void) -> c_int; } \ No newline at end of file diff --git a/ui/gtk/text.c b/ui/gtk/text.c index e3929da..3ae5318 100644 --- a/ui/gtk/text.c +++ b/ui/gtk/text.c @@ -221,6 +221,7 @@ 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"); + return; } GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); @@ -230,6 +231,81 @@ void ui_textarea_scroll_to(UIWIDGET textarea, int pos) { gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(widget), &offset, 0.2, FALSE, 0, 0); } +void ui_textarea_focus(UIWIDGET textarea) { + gtk_widget_grab_focus(textarea); +} + +void ui_textarea_set_selection(UIWIDGET textarea, int begin, int end) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_set_selection: widget is not a textarea\n"); + return; + } + + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + GtkTextIter ib; + GtkTextIter ie; + gtk_text_buffer_get_iter_at_offset(buf, &ib, begin); + gtk_text_buffer_get_iter_at_offset(buf, &ie, end); + gtk_text_buffer_select_range(buf, &ib, &ie); +} + +void ui_textarea_select_all(UIWIDGET textarea) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_select_all: widget is not a textarea\n"); + return; + } + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + GtkTextIter start; + GtkTextIter end; + gtk_text_buffer_get_bounds(buf, &start, &end); + gtk_text_buffer_select_range(buf, &start, &end); +} + +void ui_textarea_set_editable(UIWIDGET textarea, UiBool editable) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_set_editable: widget is not a textarea\n"); + return; + } + gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), editable); +} + +UiBool ui_textarea_is_editable(UIWIDGET textarea) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_is_editable: widget is not a textarea\n"); + return 0; + } + return gtk_text_view_get_editable(GTK_TEXT_VIEW(widget)); +} + +void ui_textarea_set_position(UIWIDGET textarea, int pos) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_set_position: widget is not a textarea\n"); + return; + } + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + GtkTextIter iter; + gtk_text_buffer_get_iter_at_offset(buf, &iter, pos); + gtk_text_buffer_place_cursor(buf, &iter); +} + +int ui_textarea_get_position(UIWIDGET textarea) { + GtkWidget *widget = ui_textarea_gettextwidget(textarea); + if(!widget) { + fprintf(stderr, "Error: ui_textarea_get_position: widget is not a textarea\n"); + return 0; + } + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + GtkTextIter begin; + GtkTextIter end; + gtk_text_buffer_get_selection_bounds(buf, &begin, &end); + return gtk_text_iter_get_offset(&begin); +} + UIWIDGET ui_textarea_gettextwidget(UIWIDGET textarea) { return g_object_get_data(G_OBJECT(textarea), "ui_textarea_widget"); } diff --git a/ui/ui/text.h b/ui/ui/text.h index 15f7ced..8a6368b 100644 --- a/ui/ui/text.h +++ b/ui/ui/text.h @@ -153,6 +153,13 @@ 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_focus(UIWIDGET textarea); +UIEXPORT void ui_textarea_set_selection(UIWIDGET textarea, int begin, int end); +UIEXPORT void ui_textarea_select_all(UIWIDGET textarea); +UIEXPORT void ui_textarea_set_editable(UIWIDGET textarea, UiBool editable); +UIEXPORT UiBool ui_textarea_is_editable(UIWIDGET textarea); +UIEXPORT void ui_textarea_set_position(UIWIDGET textarea, int pos); +UIEXPORT int ui_textarea_get_position(UIWIDGET textarea); UIEXPORT void ui_textarea_scroll_to(UIWIDGET textarea, int pos); #define ui_textfield(obj, ...) ui_textfield_create(obj, &(UiTextFieldArgs) { __VA_ARGS__ }) -- 2.47.3