#include "uiclient.h"
#include "args.h"
#include <stdio.h>
#include <stdlib.h>
#include <cx/hash_map.h>
#include "../ui/common/args.h"
#ifndef _WIN32
static UiMessageHandler *io;
static CxMap *msg_types;
static CxMap *objects;
void client_init(UiMessageHandler *handler) {
io = handler;
msg_types = cxHashMapCreateSimple(
CX_STORE_POINTERS);
cxMapPut(msg_types,
"window", msg_window);
cxMapPut(msg_types,
"sidebar_window", msg_window);
cxMapPut(msg_types,
"splitview_window", msg_window);
cxMapPut(msg_types,
"simple_window", msg_window);
cxMapPut(msg_types,
"show", msg_show);
cxMapPut(msg_types,
"vbox", msg_vbox);
cxMapPut(msg_types,
"hbox", msg_vbox);
cxMapPut(msg_types,
"grid", msg_vbox);
cxMapPut(msg_types,
"end", msg_end);
cxMapPut(msg_types,
"button", msg_button);
cxMapPut(msg_types,
"toggle", msg_togglebutton);
objects = cxHashMapCreateSimple(
CX_STORE_POINTERS);
}
static cxmutstr jsonobj_getstring(
const CxJsonValue *obj,
const char *name) {
CxJsonValue *value = cxJsonObjGet(obj, name);
if(value->type ==
CX_JSON_STRING) {
return value->value.string;
}
else {
return (cxmutstr){
NULL,
0 };
}
}
static UiBool jsonobj_getbool(
const CxJsonValue *obj,
const char *name,
int *error) {
CxJsonValue *value = cxJsonObjGet(obj, name);
if(value->type ==
CX_JSON_LITERAL) {
if(*error) {
*error =
0;
}
return value->value.literal ==
CX_JSON_TRUE ?
1 :
0;
}
else {
if(error) {
*error =
1;
}
return FALSE;
}
}
static int msg_received(
void *data) {
CxJsonValue *value = data;
if(client_handle_json(
NULL, value)) {
fprintf(stderr,
"Error: invalid json message\n");
}
cxJsonValueFree(value);
return 0;
}
void client_msg_received(cxstring msg) {
CxJson json;
cxJsonInit(&json,
NULL);
cxJsonFilln(&json, msg.ptr, msg.length);
CxJsonValue *value;
if(cxJsonNext(&json, &value) ==
CX_JSON_NO_ERROR && value) {
ui_call_mainthread(msg_received, value);
}
else {
fprintf(stderr,
"Error: invalid json message\n");
}
cxJsonDestroy(&json);
}
int client_handle_json(UiObject *obj,
const CxJsonValue *value) {
if(value->type !=
CX_JSON_OBJECT) {
return 1;
}
CxJsonValue *type = cxJsonObjGet(value,
"type");
if(!type || type->type !=
CX_JSON_STRING) {
return 1;
}
json_msg_handler handler = cxMapGet(msg_types, type->value.string);
if(!handler) {
return 1;
}
return handler(obj, value, type->value.string);
}
int client_handle_children(UiObject *parent,
const CxJsonValue *value) {
CxJsonValue *children = cxJsonObjGet(value,
"children");
if(children && children->type ==
CX_JSON_ARRAY) {
for(
int i=
0;i<children->value.array.array_size;i++) {
CxJsonValue *child = children->value.array.array[i];
if(client_handle_json(parent, child)) {
fprintf(stderr,
"Error: invalid child\n");
return 1;
}
}
}
return 0;
}
void client_add_obj_mapping(UiObject *obj, cxmutstr id) {
cxMapPut(objects, id, obj);
CxAllocator *a = ui_allocator(obj->ctx);
WindowData *wdata = cxMalloc(a,
sizeof(WindowData));
wdata->widgets = cxHashMapCreate(a,
CX_STORE_POINTERS,
128);
obj->window = wdata;
}
UiObject* client_get_mapped_obj(cxmutstr id) {
return cxMapGet(objects, id);
}
void client_reg_widget(UiObject *obj, cxmutstr id,
UIWIDGET w) {
WindowData *wdata = obj->window;
if(!wdata) {
fprintf(stderr,
"Error: missing obj window data\n");
return;
}
cxMapPut(wdata->widgets, id, w);
}
UIWIDGET client_get_widget(UiObject *obj, cxmutstr id) {
WindowData *wdata = obj->window;
if(!wdata) {
fprintf(stderr,
"Error: missing obj window data\n");
return NULL;
}
return cxMapGet(wdata->widgets, id);
}
static UiObject* get_msg_obj(UiObject *obj,
const CxJsonValue *value) {
if(obj) {
return obj;
}
CxJsonValue *obj_id = cxJsonObjGet(value,
"obj");
if(!obj_id || obj_id->type !=
CX_JSON_STRING) {
return NULL;
}
return client_get_mapped_obj(obj_id->value.string);
}
int msg_window(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
cxmutstr obj_id = jsonobj_getstring(value,
"obj");
cxmutstr id = jsonobj_getstring(value,
"id");
cxmutstr title = jsonobj_getstring(value,
"title");
if(!obj_id.ptr) {
return 1;
}
if(!id.ptr) {
return 1;
}
UiObject *obj;
if(!cx_strcmp(type,
"window")) {
obj = ui_window(title.ptr);
}
else if(!cx_strcmp(type,
"sidebar_window")) {
obj = ui_sidebar_window(title.ptr);
}
else if(!cx_strcmp(type,
"splitview_window")) {
int err;
bool sidebar = jsonobj_getbool(value,
"sidebar", &err);
if(err) {
return 1;
}
obj = ui_splitview_window(title.ptr, sidebar);
}
else if(!cx_strcmp(type,
"simple_window")) {
obj = ui_simple_window(title.ptr);
}
client_add_obj_mapping(obj, obj_id);
if(obj->widget) {
client_reg_widget(obj, id, obj->widget);
}
return client_handle_children(obj, value);
}
int msg_show(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
UiObject *obj = client_get_mapped_obj(jsonobj_getstring(value,
"obj"));
if(!obj) {
return 1;
}
ui_show(obj);
return 0;
}
typedef UIWIDGET(*ctcreate_func)(UiObject *obj, UiContainerArgs *args);
static int msg_container(UiObject *parent,
const CxJsonValue *value, ctcreate_func create) {
CxJsonValue *args_value = cxJsonObjGet(value,
"args");
cxmutstr id = jsonobj_getstring(value,
"id");
if(!id.ptr) {
return 1;
}
UiObject *obj = get_msg_obj(parent, value);
if(!obj) {
return 1;
}
UiContainerArgs *args = json2container_args(args_value);
UIWIDGET w = create(obj, args);
ui_container_args_free(args);
client_reg_widget(obj, id, w);
return 0;
}
int msg_vbox(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
return msg_container(parent, value, ui_vbox_create);
}
int msg_hbox(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
return msg_container(parent, value, ui_hbox_create);
}
int msg_grid(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
return msg_container(parent, value, ui_grid_create);
}
int msg_end(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
UiObject *obj = get_msg_obj(parent, value);
if(!obj) {
return 1;
}
ui_end_new(obj);
return 0;
}
int msg_button(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
CxJsonValue *args_value = cxJsonObjGet(value,
"args");
cxmutstr id = jsonobj_getstring(value,
"id");
if(!id.ptr) {
return 1;
}
UiObject *obj = get_msg_obj(parent, value);
if(!obj) {
return 1;
}
UiButtonArgs *args = json2button_args(args_value);
UIWIDGET w = ui_button_create(obj, args);
ui_button_args_free(args);
client_reg_widget(obj, id, w);
return 0;
}
int msg_togglebutton(UiObject *parent,
const CxJsonValue *value, cxmutstr type) {
CxJsonValue *args_value = cxJsonObjGet(value,
"args");
cxmutstr id = jsonobj_getstring(value,
"id");
if(!id.ptr) {
return 1;
}
UiObject *obj = get_msg_obj(parent, value);
if(!obj) {
return 1;
}
CxJsonValue *button_type = cxJsonObjGet(value,
"button_type");
if(!button_type || button_type->type !=
CX_JSON_INTEGER) {
return 1;
}
CxJsonValue *val = cxJsonObjGet(value,
"value");
UiInteger *i =
NULL;
if(val && val->type ==
CX_JSON_STRING) {
i = ui_get_int_var(obj->ctx, val->value.string.ptr);
if(!i) {
i = ui_int_new(obj->ctx, val->value.string.ptr);
}
}
UiToggleArgs *args = json2toggle_args(args_value);
UIWIDGET w;
switch(button_type->value.integer) {
default: {
w = ui_togglebutton_create(obj, args);
break;
}
case 1: {
w = ui_checkbox_create(obj, args);
break;
}
case 2: {
w = ui_switch_create(obj, args);
break;
}
case 3: {
w = ui_radiobutton_create(obj, args);
break;
}
}
ui_toggle_args_free(args);
client_reg_widget(obj, id, w);
return 0;
}
#endif