implement textfield onchange events (Cocoa) default tip

Wed, 22 Apr 2026 19:29:26 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 22 Apr 2026 19:29:26 +0200
changeset 1102
c4883a63929b
parent 1101
789b476ff7e3

implement textfield onchange events (Cocoa)

make/xcode/toolkit/toolkit/main.m file | annotate | diff | comparison | revisions
ui/cocoa/EventData.h file | annotate | diff | comparison | revisions
ui/cocoa/EventData.m file | annotate | diff | comparison | revisions
ui/cocoa/button.m file | annotate | diff | comparison | revisions
ui/cocoa/text.h file | annotate | diff | comparison | revisions
ui/cocoa/text.m file | annotate | diff | comparison | revisions
--- a/make/xcode/toolkit/toolkit/main.m	Wed Apr 22 10:07:54 2026 +0200
+++ b/make/xcode/toolkit/toolkit/main.m	Wed Apr 22 19:29:26 2026 +0200
@@ -141,6 +141,10 @@
     printf("action test\n");
 }
 
+void textfield_changed(UiEvent *event, void *userdata) {
+    printf("textfield changed\n");
+}
+
 void application_startup(UiEvent *event, void *data) {
     UiObject *obj = ui_splitview_window("My Window", TRUE);
     //WindowData *wdata = ui_malloc(obj->ctx, sizeof(WindowData));
@@ -180,6 +184,7 @@
                 ui_button(obj, .label = "Test Button", .action = "test");
                 ui_button(obj, .label = "Test Button", .action = "test");
                 ui_button(obj, .label = "Test Button", .action = "test");
+                ui_textfield(obj, .onchange = textfield_changed);
             }
         }
     }
--- a/ui/cocoa/EventData.h	Wed Apr 22 10:07:54 2026 +0200
+++ b/ui/cocoa/EventData.h	Wed Apr 22 19:29:26 2026 +0200
@@ -29,7 +29,7 @@
 #import "../ui/toolkit.h"
 #import "../common/context.h"
 
-typedef void(*get_eventdata_func)(id sender, UiVar *var, void **eventdata, int *value);
+typedef void(*get_eventdata_func)(id sender, UiVar *var, void **eventdata, int *eventdatatype, int *value);
 
 @interface EventData : NSObject
 @property UiObject           *obj;
--- a/ui/cocoa/EventData.m	Wed Apr 22 10:07:54 2026 +0200
+++ b/ui/cocoa/EventData.m	Wed Apr 22 19:29:26 2026 +0200
@@ -70,7 +70,7 @@
     event.intval = 0;
     event.set = ui_get_setop();
     if(_get_eventdata) {
-        _get_eventdata(sender, _var, &event.eventdata, &event.intval);
+        _get_eventdata(sender, _var, &event.eventdata, &event.eventdatatype, &event.intval);
     }
     if(self.callback) {
         self.callback(&event, self.userdata);
--- a/ui/cocoa/button.m	Wed Apr 22 10:07:54 2026 +0200
+++ b/ui/cocoa/button.m	Wed Apr 22 19:29:26 2026 +0200
@@ -64,7 +64,7 @@
 }
 
 
-static void togglebutton_eventdata(id button, UiVar *var, void **eventdata, int *value) {
+static void togglebutton_eventdata(id button, UiVar *var, void **eventdata, int *eventdatatype, int *value) {
     NSButton *btn = (NSButton*)button;
     NSControlStateValue state = btn.state;
     *value = (int)state;
@@ -137,7 +137,7 @@
     return togglebutton_create(obj, args, NSButtonTypeSwitch);
 }
 
-static void switch_eventdata(id button, UiVar *var, void **eventdata, int *value) {
+static void switch_eventdata(id button, UiVar *var, void **eventdata, int *eventdatatype, int *value) {
     NSSwitch *btn = (NSSwitch*)button;
     NSControlStateValue state = btn.state;
     *value = (int)state;
@@ -207,10 +207,10 @@
 
 @end
 
-static void radiobutton_eventdata(id button, UiVar *var, void **eventdata, int *value) {
+static void radiobutton_eventdata(id button, UiVar *var, void **eventdata, int *eventdatatype, int *value) {
     if(var) {
-        UiInteger *value = var->value;
-        NSMutableArray *buttons = (__bridge NSMutableArray*)value->obj;
+        UiInteger *i = var->value;
+        NSMutableArray *buttons = (__bridge NSMutableArray*)i->obj;
         for(UiRadioButton *b in buttons) {
             if(b != button) {
                 b.direct_state = YES;
--- a/ui/cocoa/text.h	Wed Apr 22 10:07:54 2026 +0200
+++ b/ui/cocoa/text.h	Wed Apr 22 19:29:26 2026 +0200
@@ -47,3 +47,15 @@
 
 char* ui_textfield_get(UiString *s);
 void ui_textfield_set(UiString *s, const char *value);
+
+@interface TextFieldDelegate : NSObject<NSTextFieldDelegate>
+
+@property UiObject *obj;
+@property UiVar *var;
+@property ui_callback onchange;
+@property void *onchangedata;
+@property NSString *onchange_action;
+
+- (id)init:(UiObject*)obj var:(UiVar*)var;
+
+@end
--- a/ui/cocoa/text.m	Wed Apr 22 10:07:54 2026 +0200
+++ b/ui/cocoa/text.m	Wed Apr 22 19:29:26 2026 +0200
@@ -29,6 +29,7 @@
 #import "text.h"
 #import "EventData.h"
 #import "container.h"
+#import "action.h"
 #import <objc/runtime.h>
 
 UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
@@ -186,6 +187,10 @@
 
 /* -------------------------- TextField -------------------------- */
 
+static void textfield_geteventdata(id sender, UiVar *var, void **eventdata, int *eventdatatype, int *value) {
+    
+}
+
 static UIWIDGET textfield_create(UiObject *obj, UiTextFieldArgs *args, BOOL password, BOOL frameless) {
     NSTextField *textfield;
     if(password) {
@@ -222,6 +227,27 @@
         s->set = ui_textfield_set;
     }
     
+    if(args->onactivate || args->onactivate_action) {
+        EventData *event = [[EventData alloc] init:args->onactivate userdata:args->onactivatedata action:args->onactivate_action];
+        event.get_eventdata = textfield_geteventdata;
+        event.obj = obj;
+        textfield.target = event;
+        textfield.action = @selector(handleEventWithEventData:);
+        objc_setAssociatedObject(textfield, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
+        ui_cocoa_view_bind_action(obj->ctx, textfield, args->onactivate_action);
+    }
+    
+    if(args->onchange || args->onchange_action) {
+        TextFieldDelegate *tfd = [[TextFieldDelegate alloc]init:obj var:var];
+        tfd.onchange = args->onchange;
+        tfd.onchangedata = args->onchangedata;
+        if(args->onchange_action) {
+            tfd.onchange_action = [[NSString alloc]initWithUTF8String:args->onchange_action];
+        }
+        objc_setAssociatedObject(textfield, "delegate", tfd, OBJC_ASSOCIATION_RETAIN);
+        textfield.delegate = tfd;
+    }
+    
     return (__bridge void*)textfield;
 }
 
@@ -306,3 +332,41 @@
     NSRange selectedRange = [editor selectedRange];
     return (int)selectedRange.location;
 }
+
+
+/* -------------------- textfield delegate -------------------- */
+
+@implementation TextFieldDelegate
+
+- (id)init:(UiObject*)obj var:(UiVar*)var {
+    self.obj = obj;
+    self.var = var;
+    return self;
+}
+
+- (void)controlTextDidChange:(NSNotification *)obj {
+    UiString *value = _var ? _var->value : NULL;
+    
+    UiEvent e;
+    e.obj = _obj;
+    e.window = e.obj->window;
+    e.document = e.obj->ctx->document;
+    e.eventdata = value;
+    e.eventdatatype = value ? UI_EVENT_DATA_STRING_VALUE : 0;
+    e.intval = 0;
+    e.set = ui_get_setop();
+    
+    if(_onchange) {
+        _onchange(&e, _onchangedata);
+    }
+    
+    if(_var) {
+        ui_notify_evt(value->observers, &e);
+    }
+    
+    if(_onchange_action) {
+        uic_action_callback(&e, _onchange_action.UTF8String);
+    }
+}
+
+@end

mercurial