i: i32,
#[bind("list")]
list: UiList<i32>,
- #[bind]
- sublists: UiList<SubList<String>>
+ #[bind("source")]
+ sublists: UiSourceList<String>
}
#[ui_actions]
list.push(11);
list.push(12);
+ let mut sl = SubList::new();
+ sl.set_header("Header");
+ sl.data().push(String::from("Elm 1"));
+ sl.data().push(String::from("Elm 2"));
+
+ data.sublists.push(sl);
+
+
obj.button_builder().label("Hello").onclick(|e| {
println!("Button clicked: {}", e.data.i);
e.data.i += 1;
//obj.tableview_builder::<i32>().fill(true).varname("list").model(&model).getvalue(|elm, _row, _col| {
// ListValue::String(elm.to_string())
//}).create();
- obj.sourcelist_builder::<String>().fill(true).value(&data.sublists).create();
+ obj.sourcelist_builder::<String>().fill(true).value(&data.sublists).getvalue(|elm, index, item| {
+ item.label = Some(elm.to_string());
+ item.badge = Some(index.to_string());
+ }).create();
+
+ println!("test");
});
window.show();
}
pub struct SubList<T> {
- handle: *mut ffi::UiSubList,
+ pub handle: *mut ffi::UiSubList,
list: toolkit::UiList<T>
}
+#[derive(Default)]
+pub struct SourceListItem {
+ pub icon: Option<String>,
+ pub label: Option<String>,
+ pub button_icon: Option<String>,
+ pub button_label: Option<String>,
+ pub badge: Option<String>,
+ // TODO: button_menu
+}
+
pub enum ColumnType {
String = 0,
// skip UI_STRING_FREE
impl<'a, T, E> SourceListBuilder<'a, T, E> {
pub fn create(&mut self) {
unsafe {
+ ui_sourcelist_args_set_getvalue_func(self.args, sourcelist_getvalue_wrapper::<E>);
ui_sourcelist_create(self.obj.ptr, self.args);
}
}
}
self
}
- pub fn value(&mut self, value: &toolkit::UiList<SubList<E>>) -> &mut Self {
+ pub fn value(&mut self, value: &toolkit::UiSourceList<E>) -> &mut Self {
unsafe {
ui_sourcelist_args_set_dynamic_sublists(self.args, value.ptr);
}
}
pub fn getvalue<F>(&mut self, f: F) -> &mut Self
- where F: Fn(&E, i32, i32) -> ListValue<'a> + 'static {
+ where F: Fn(&E, i32, &mut SourceListItem) + 'static {
unsafe {
- let wrapper = Box::new(GetValueWrapper { callback: Box::new(f), is_table: false });
+ let wrapper = Box::new(SLGetValueWrapper { callback: Box::new(f)});
let ptr = self.obj.ctx.reg_box(wrapper);
- ui_sourcelist_args_set_getvalue_func(self.args, sourcelist_getvalue_wrapper::<E>);
ui_sourcelist_args_set_getvalue_userdata(self.args, ptr as *mut c_void);
}
self
impl<E> SubList<E> {
pub fn new() -> Self {
unsafe {
- SubList {
+ let s = SubList {
handle: ui_sublist_new(),
list: toolkit::UiList::new()
- }
+ };
+ ui_sublist_set_value(s.handle, s.list.ptr);
+ s
}
}
ui_sublist_set_header(self.handle, cstr.as_ptr());
}
}
+
+ pub fn list(&mut self) -> &mut toolkit::UiList<E> {
+ &mut self.list
+ }
+
+ pub fn data(&mut self) -> &mut Vec<E> {
+ self.list.data()
+ }
}
impl<E> Drop for SubList<E> {
is_table: bool
}
+struct SLGetValueWrapper<T> {
+ callback: Box<dyn Fn(&T, i32, &mut SourceListItem)>
+}
+
fn str_dup(str: &str) -> *mut c_void {
let cstr = CString::new(str).unwrap();
pub extern "C" fn sourcelist_getvalue_wrapper<T>(
_list: *const ffi::UiList,
_sublist_userdata: *mut c_void,
- _row_data: *mut c_void,
- _index: c_int,
- _item: *mut ffi::UiSubListItem,
- _userdata: *mut c_void)
+ row_data: *mut c_void,
+ index: c_int,
+ item: *mut ffi::UiSubListItem,
+ userdata: *mut c_void)
{
- // TODO
+ if userdata.is_null() {
+ return;
+ }
+
+ let wrapper = unsafe { &*(userdata as *const SLGetValueWrapper<T> ) };
+ let elm = unsafe { &*(row_data as *const T) };
+
+ let mut it: SourceListItem = Default::default();
+ (wrapper.callback)(elm, index, &mut it);
+
+ if let Some(icon) = it.icon {
+ let cstr = CString::new(icon).unwrap();
+ unsafe {
+ ui_sublist_item_set_icon(item, cstr.as_ptr());
+ }
+ }
+ if let Some(label) = it.label {
+ let cstr = CString::new(label).unwrap();
+ unsafe {
+ ui_sublist_item_set_label(item, cstr.as_ptr());
+ }
+ }
+ if let Some(icon) = it.button_icon {
+ let cstr = CString::new(icon).unwrap();
+ unsafe {
+ ui_sublist_item_set_button_icon(item, cstr.as_ptr());
+ }
+ }
+ if let Some(label) = it.button_label {
+ let cstr = CString::new(label).unwrap();
+ unsafe {
+ ui_sublist_item_set_button_label(item, cstr.as_ptr());
+ }
+ }
+ if let Some(badge) = it.badge {
+ let cstr = CString::new(badge).unwrap();
+ unsafe {
+ ui_sublist_item_set_badge(item, cstr.as_ptr());
+ }
+ }
}
type SLGetValueFunc = extern "C" fn(
fn ui_sublist_set_value(list: *mut ffi::UiSubList, value: *mut ffi::UiList);
fn ui_sublist_set_header(list: *mut ffi::UiSubList, header: *const c_char);
fn ui_sublist_free(list: *mut ffi::UiSubList);
+
+ fn ui_sublist_item_set_icon(item: *mut ffi::UiSubListItem, icon: *const c_char);
+ fn ui_sublist_item_set_label(item: *mut ffi::UiSubListItem, label: *const c_char);
+ fn ui_sublist_item_set_button_icon(item: *mut ffi::UiSubListItem, icon: *const c_char);
+ fn ui_sublist_item_set_button_label(item: *mut ffi::UiSubListItem, label: *const c_char);
+ fn ui_sublist_item_set_badge(item: *mut ffi::UiSubListItem, badge: *const c_char);
}
\ No newline at end of file
#![allow(dead_code)]
use std::ffi::{c_char, c_int, c_void, CStr, CString};
-use crate::ui::{action_event_wrapper, event, ffi, ui_object_get_context, ui_object_get_windowdata, ui_reg_destructor, ActionEventWrapper, EventWrapper};
+use crate::ui::{action_event_wrapper, event, ffi, ui_object_get_context, ui_object_get_windowdata, ui_reg_destructor, ActionEventWrapper, EventWrapper, SubList};
use std::marker::PhantomData;
use std::mem;
data: Box<Vec<T>>
}
+pub struct UiSourceList<T> {
+ pub ptr: *mut ffi::UiList,
+ sublists: Vec<SubList<T>>
+}
+
/* -------------------------------- Default implementation -------------------------------- */
macro_rules! value_default_impl {
}
}
+impl<T> Default for UiSourceList<T> {
+ fn default() -> Self {
+ Self {
+ ptr: std::ptr::null_mut(),
+ sublists: Default::default()
+ }
+ }
+
+
+}
+
pub fn app_init(appname: &str) {
let s;
let c_str = if appname.len() > 0 {
}
+/* -------------------------------- SourceList -------------------------------- */
+
+impl<T> UiSourceList<T> {
+ pub fn init(&mut self, ctx: &UiContext, name: Option<&str>) {
+ let c_string = name.map(|n| CString::new(n).unwrap());
+ let c_str = c_string.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
+ unsafe {
+ self.ptr = ui_list_new(ctx.ptr, c_str);
+ }
+ }
+
+ pub fn push(&mut self, sublist: SubList<T>) {
+ unsafe {
+ ui_list_append(self.ptr, sublist.handle as *mut c_void);
+ }
+ self.sublists.push(sublist);
+ }
+
+ pub fn insert(&mut self, index: usize, sublist: SubList<T>) {
+ unsafe {
+ ui_list_insert(self.ptr, index as c_int, sublist.handle as *mut c_void);
+ }
+ self.sublists.insert(index, sublist);
+ }
+
+ pub fn remove(&mut self, index: usize) {
+ // TODO
+ self.sublists.remove(index);
+ }
+
+ pub fn clear(&mut self) {
+ // TODO
+ self.sublists.clear();
+ }
+
+ pub fn update(&mut self) {
+
+ }
+}
+
+
/* -------------------------------- List -------------------------------- */
/*
type UiListCountFunc = extern "C" fn(*const ffi::UiList) -> c_int;
extern "C" {
+ fn ui_list_new(ctx: *mut ffi::UiContext, name: *const c_char) -> *mut ffi::UiList;
fn ui_list_new2(ctx: *mut ffi::UiContext, name: *const c_char, init: UiListInitFunc, userdata: *mut c_void) -> *mut ffi::UiList;
fn ui_list_class_set_first(list: *mut ffi::UiList, func: UiListFirstFunc);
fn ui_list_class_set_next(list: *mut ffi::UiList, func: UiListNextFunc);
fn ui_list_selection_get_rows(list: *mut ffi::UiListSelection) -> *const c_int;
fn ui_list_selection_free(list: *mut ffi::UiListSelection);
+ pub fn ui_list_append(list: *mut ffi::UiList, data: *mut c_void);
+ pub fn ui_list_insert(list: *mut ffi::UiList, index: c_int, data: *mut c_void);
+
fn ui_list_free(ctx: *mut ffi::UiContext, list: *mut ffi::UiList);
}
#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;
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);
button.image = ui_cocoa_named_icon(args->icon);;
}
- if(args->onclick) {
+ if(args->onclick || args->action) {
EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata action:args->action];
event.obj = obj;
button.target = event;
button.action = @selector(handleEvent:);
objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
+
+ ui_cocoa_view_bind_action(obj->ctx, button, args->action);
}
UiLayout layout = UI_INIT_LAYOUT(args);
}
-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;
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;
@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;
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
#import "text.h"
#import "EventData.h"
#import "container.h"
+#import "action.h"
#import <objc/runtime.h>
UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
/* -------------------------- 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) {
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;
}
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
/* --------------------------- UiList --------------------------- */
void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused) {
+ const CxAllocator *a = ctx ? ctx->allocator : cxDefaultAllocator;
list->destroy = uic_ucx_list_destroy;
- list->data = cxArrayListCreate(ctx->mp->allocator, CX_STORE_POINTERS, 32);
+ list->data = cxArrayListCreate(a, CX_STORE_POINTERS, 32);
list->first = ui_list_first;
list->next = ui_list_next;
list->get = ui_list_get;
cxListInsert(list->data, 0, data);
}
+void ui_list_insert(UiList *list, int index, void *data) {
+ cxListInsert(list->data, (size_t)index, data);
+}
+
void ui_list_remove(UiList *list, int i) {
if(i >= 0) {
cxListRemove(list->data, i);
UiInteger* ui_int_new(UiContext *ctx, const char *name) {
UiInteger *i = ui_malloc(ctx, sizeof(UiInteger));
memset(i, 0, sizeof(UiInteger));
- if(name) {
+ if(name && ctx) {
uic_reg_var(ctx, name, UI_VAR_INTEGER, i);
}
return i;
UiDouble* ui_double_new(UiContext *ctx, const char *name) {
UiDouble *d = ui_malloc(ctx, sizeof(UiDouble));
memset(d, 0, sizeof(UiDouble));
- if(name) {
+ if(name && ctx) {
uic_reg_var(ctx, name, UI_VAR_DOUBLE, d);
}
return d;
UiString *s = ui_malloc(ctx, sizeof(UiString));
memset(s, 0, sizeof(UiString));
ui_set_destructor(s, (ui_destructor_func)string_destroy);
- if(name) {
+ if(name && ctx) {
uic_reg_var(ctx, name, UI_VAR_STRING, s);
}
return s;
UiText *t = ui_malloc(ctx, sizeof(UiText));
memset(t, 0, sizeof(UiText));
ui_set_destructor(t, (ui_destructor_func)text_destroy);
- if(name) {
+ if(name && ctx) {
uic_reg_var(ctx, name, UI_VAR_TEXT, t);
}
return t;
UiRange* ui_range_new(UiContext *ctx, const char *name) {
UiRange *r = ui_malloc(ctx, sizeof(UiRange));
memset(r, 0, sizeof(UiRange));
- if(name) {
+ if(name && ctx) {
uic_reg_var(ctx, name, UI_VAR_RANGE, r);
}
return r;
UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
UiGeneric *g = ui_malloc(ctx, sizeof(UiGeneric));
memset(g, 0, sizeof(UiGeneric));
- ui_set_destructor(g, (ui_destructor_func)generic_destroy);
- if(name) {
+ if(ctx) {
+ ui_set_destructor(g, (ui_destructor_func)generic_destroy);
+ }
+ if(name && ctx) {
uic_reg_var(ctx, name, UI_VAR_GENERIC, g);
}
return g;
uitext->last_selection_state = 0;
uitext->onchange = args->onchange;
uitext->onchangedata = args->onchangedata;
+ uitext->action = args->action ? strdup(args->action) : NULL;
g_object_set_data(G_OBJECT(text_area), "ui_textarea", uitext);
g_object_set_data(G_OBJECT(text_area), "ui_textarea_widget", text_area);
if(textarea->var) {
ui_destroy_boundvar(textarea->ctx, textarea->var);
}
+ free(textarea->action);
free(textarea);
}
if(value->observers) {
ui_notify_evt(value->observers, &e);
}
+
+ if(textarea->action) {
+ uic_action_callback(&e, textarea->action);
+ }
}
// undo manager functions
uitext->onchangedata = args->onchangedata;
uitext->onactivate = args->onactivate;
uitext->onactivatedata = args->onactivatedata;
+ uitext->onactivate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL;
+ uitext->onchange_action = args->onchange_action ? strdup(args->onchange_action) : NULL;
g_signal_connect(
textfield,
value->obj = GTK_ENTRY(textfield);
}
- if(args->onchange || var) {
+ if(args->onchange || args->onchange_action || var) {
g_signal_connect(
textfield,
"changed",
uitext);
}
- if(args->onactivate) {
+ if(args->onactivate || args->onactivate_action) {
g_signal_connect(
textfield,
"activate",
}
void ui_textfield_destroy(GtkWidget *object, UiTextField *textfield) {
+ free(textfield->onactivate_action);
+ free(textfield->onchange_action);
free(textfield);
}
e.window = e.obj->window;
e.document = textfield->obj->ctx->document;
e.eventdata = value;
- e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
+ e.eventdatatype = value ? UI_EVENT_DATA_STRING_VALUE : 0;
e.intval = 0;
e.set = ui_get_setop();
if(textfield->var) {
ui_notify_evt(value->observers, &e);
}
+
+ if(textfield->onchange_action) {
+ uic_action_callback(&e, textfield->onchange_action);
+ }
}
void ui_textfield_activate(GtkEntry* self, UiTextField *textfield) {
- if(textfield->onactivate) {
- UiString *value = textfield->var ? textfield->var->value : NULL;
+ UiString *value = textfield->var ? textfield->var->value : NULL;
- UiEvent e;
- e.obj = textfield->obj;
- e.window = e.obj->window;
- e.document = textfield->obj->ctx->document;
- e.eventdata = value;
- e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
- e.intval = 0;
- e.set = ui_get_setop();
+ UiEvent e;
+ e.obj = textfield->obj;
+ e.window = e.obj->window;
+ e.document = textfield->obj->ctx->document;
+ e.eventdata = value;
+ e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
+ e.intval = 0;
+ e.set = ui_get_setop();
+
+ if(textfield->onactivate) {
textfield->onactivate(&e, textfield->onactivatedata);
}
+
+ if(textfield->onactivate_action) {
+ uic_action_callback(&e, textfield->onactivate_action);
+ }
}
char* ui_textfield_get(UiString *str) {
int last_selection_state;
ui_callback onchange;
void *onchangedata;
+ char *action;
} UiTextArea;
typedef struct UiTextField {
void *onchangedata;
ui_callback onactivate;
void *onactivatedata;
+ char *onactivate_action;
+ char *onchange_action;
} UiTextField;
typedef struct UiPathTextField {
UIEXPORT int ui_list_count(UiList *list);
UIEXPORT void ui_list_append(UiList *list, void *data);
UIEXPORT void ui_list_prepend(UiList *list, void *data);
+UIEXPORT void ui_list_insert(UiList *list, int index, void *data);
UIEXPORT void ui_list_remove(UiList *list, int i);
UIEXPORT void ui_list_clear(UiList *list);
UIEXPORT void ui_list_update(UiList *list);