Skip to content
Snippets Groups Projects
Commit 5c3b7af1 authored by Deucе's avatar Deucе :ok_hand_tone4:
Browse files

Focus, hidden, handlers work, etc.

Getting design to completion... just need to figure out how to do
pre-defined trees of controls, and I should be able to start work
on the actual rendering bits.
parent 704eba93
No related branches found
No related tags found
No related merge requests found
Pipeline #5446 passed
...@@ -45,6 +45,7 @@ enum attribute_impl { ...@@ -45,6 +45,7 @@ enum attribute_impl {
attr_impl_global, attr_impl_global,
attr_impl_object, attr_impl_object,
attr_impl_root, attr_impl_root,
attr_impl_global_custom_setter,
}; };
struct attribute_info { struct attribute_info {
...@@ -62,7 +63,9 @@ attributes[] = { ...@@ -62,7 +63,9 @@ attributes[] = {
{"child_xpos", NI_attr_type_uint16_t, attr_impl_global, 1}, {"child_xpos", NI_attr_type_uint16_t, attr_impl_global, 1},
{"child_ypos", NI_attr_type_uint16_t, attr_impl_global, 1}, {"child_ypos", NI_attr_type_uint16_t, attr_impl_global, 1},
{"dirty", NI_attr_type_bool, attr_impl_root, 1}, {"dirty", NI_attr_type_bool, attr_impl_root, 1},
{"focus", NI_attr_type_bool, attr_impl_global_custom_setter, 0},
{"height", NI_attr_type_uint16_t, attr_impl_global, 0}, {"height", NI_attr_type_uint16_t, attr_impl_global, 0},
{"hidden", NI_attr_type_bool, attr_impl_global, 1},
{"higherpeer", NI_attr_type_NewIfcObj, attr_impl_global, 1}, {"higherpeer", NI_attr_type_NewIfcObj, attr_impl_global, 1},
{"last_error", NI_attr_type_NI_err, attr_impl_global, 1}, {"last_error", NI_attr_type_NI_err, attr_impl_global, 1},
{"locked", NI_attr_type_bool, attr_impl_root, 0}, {"locked", NI_attr_type_bool, attr_impl_root, 0},
...@@ -98,6 +101,7 @@ error_inf[] = { ...@@ -98,6 +101,7 @@ error_inf[] = {
{"error_out_of_range", -1}, {"error_out_of_range", -1},
{"error_wont_fit", -1}, {"error_wont_fit", -1},
{"error_cancelled", -1}, {"error_cancelled", -1},
{"error_skip_subtree", -1},
}; };
struct handler_info { struct handler_info {
...@@ -157,12 +161,14 @@ main(int argc, char **argv) ...@@ -157,12 +161,14 @@ main(int argc, char **argv)
fputs("NI_err NI_copy(NewIfcObj obj, NewIfcObj *newobj);\n", header); fputs("NI_err NI_copy(NewIfcObj obj, NewIfcObj *newobj);\n", header);
fputs("NI_err NI_create(enum NewIfc_object obj, NewIfcObj parent, NewIfcObj *newobj);\n", header); fputs("NI_err NI_create(enum NewIfc_object obj, NewIfcObj parent, NewIfcObj *newobj);\n", header);
fputs("NI_err NI_error(NewIfcObj obj);\n", header); fputs("NI_err NI_error(NewIfcObj obj);\n", header);
fputs("NI_err NI_walk_children(NewIfcObj obj, NI_err (*cb)(NewIfcObj obj, void *cb_data), void *cbdata);\n\n", header); fputs("NI_err NI_walk_children(NewIfcObj obj, bool top_down, NI_err (*cb)(NewIfcObj obj, void *cb_data), void *cbdata);\n\n", header);
nitems = sizeof(attributes) / sizeof(attributes[0]); nitems = sizeof(attributes) / sizeof(attributes[0]);
for (i = 0; i < nitems; i++) { for (i = 0; i < nitems; i++) {
if (!attributes[i].read_only) if (!attributes[i].read_only) {
fprintf(header, "NI_err NI_add_%s_handler(NewIfcObj obj, NI_err (*handler)(NewIfcObj obj, %s newval, void *cbdata), void *cbdata);\n", attributes[i].name, type_str[attributes[i].type].type);
fprintf(header, "NI_err NI_set_%s(NewIfcObj obj, %s value);\n", attributes[i].name, type_str[attributes[i].type].type); fprintf(header, "NI_err NI_set_%s(NewIfcObj obj, %s value);\n", attributes[i].name, type_str[attributes[i].type].type);
}
fprintf(header, "NI_err NI_get_%s(NewIfcObj obj, %s* value);\n", attributes[i].name, type_str[attributes[i].type].type); fprintf(header, "NI_err NI_get_%s(NewIfcObj obj, %s* value);\n", attributes[i].name, type_str[attributes[i].type].type);
} }
fputs("\n#endif\n", header); fputs("\n#endif\n", header);
...@@ -212,7 +218,7 @@ main(int argc, char **argv) ...@@ -212,7 +218,7 @@ main(int argc, char **argv)
" NI_err (*set)(NewIfcObj niobj, const int attr, ...);\n" " NI_err (*set)(NewIfcObj niobj, const int attr, ...);\n"
" NI_err (*get)(NewIfcObj niobj, const int attr, ...);\n" " NI_err (*get)(NewIfcObj niobj, const int attr, ...);\n"
" NI_err (*copy)(NewIfcObj obj, NewIfcObj *newobj);\n" " NI_err (*copy)(NewIfcObj obj, NewIfcObj *newobj);\n"
" struct NewIfc_handler *handlers;\n" " struct NewIfc_handler **handlers;\n"
" size_t handlers_sz;\n" " size_t handlers_sz;\n"
" NewIfcObj root;\n" " NewIfcObj root;\n"
" NewIfcObj parent;\n" " NewIfcObj parent;\n"
...@@ -232,6 +238,8 @@ main(int argc, char **argv) ...@@ -232,6 +238,8 @@ main(int argc, char **argv)
" uint16_t child_width;\n" " uint16_t child_width;\n"
" uint16_t child_xpos;\n" " uint16_t child_xpos;\n"
" uint16_t child_ypos;\n" " uint16_t child_ypos;\n"
" unsigned focus:1;\n"
" unsigned hidden:1;\n"
"};\n\n", internal_header); "};\n\n", internal_header);
fputs("enum NewIfc_attribute {\n", internal_header); fputs("enum NewIfc_attribute {\n", internal_header);
...@@ -325,9 +333,10 @@ main(int argc, char **argv) ...@@ -325,9 +333,10 @@ main(int argc, char **argv)
"{\n" "{\n"
" if (obj->handlers == NULL)\n" " if (obj->handlers == NULL)\n"
" return NewIfc_error_none;\n" " return NewIfc_error_none;\n"
" struct NewIfc_handler *h = bsearch(&type, obj->handlers, obj->handlers_sz, sizeof(obj->handlers[0]), handler_compar);\n" " struct NewIfc_handler **head = bsearch(&type, obj->handlers, obj->handlers_sz, sizeof(obj->handlers[0]), handler_bsearch_compar);\n"
" if (h == NULL)\n" " if (head == NULL)\n"
" return NewIfc_error_none;\n" " return NewIfc_error_none;\n"
" struct NewIfc_handler *h = *head;\n"
" while (h != NULL) {\n" " while (h != NULL) {\n"
" NI_err ret = h->on_%s_change(obj, newval, h->cbdata);\n" " NI_err ret = h->on_%s_change(obj, newval, h->cbdata);\n"
" if (ret != NewIfc_error_none)\n" " if (ret != NewIfc_error_none)\n"
...@@ -398,6 +407,8 @@ main(int argc, char **argv) ...@@ -398,6 +407,8 @@ main(int argc, char **argv)
"}\n\n", attributes[i].name, type_str[attributes[i].type].type, attributes[i].name, attributes[i].name); "}\n\n", attributes[i].name, type_str[attributes[i].type].type, attributes[i].name, attributes[i].name);
} }
// Fall-through
case attr_impl_global_custom_setter:
fprintf(c_code, "NI_err\n" fprintf(c_code, "NI_err\n"
"NI_get_%s(NewIfcObj obj, %s* value) {\n" "NI_get_%s(NewIfcObj obj, %s* value) {\n"
" NI_err ret;\n" " NI_err ret;\n"
...@@ -442,6 +453,30 @@ main(int argc, char **argv) ...@@ -442,6 +453,30 @@ main(int argc, char **argv)
"}\n\n", attributes[i].name, type_str[attributes[i].type].type, attributes[i].name); "}\n\n", attributes[i].name, type_str[attributes[i].type].type, attributes[i].name);
break; break;
} }
fprintf(c_code, "NI_err\n"
"NI_add_%s_handler(NewIfcObj obj, NI_err (*handler)(NewIfcObj obj, %s newval, void *cbdata), void *cbdata)\n"
"{\n"
" NI_err ret;\n"
" if (obj == NULL || handler == NULL)\n"
" return NewIfc_error_invalid_arg;\n"
" if (NI_set_locked(obj, true)) {\n"
" struct NewIfc_handler *h = malloc(sizeof(struct NewIfc_handler));\n"
" if (h == NULL)\n"
" return NewIfc_error_allocation_failure;\n"
" h->on_%s_change = handler;\n"
" h->cbdata = cbdata;\n"
" h->event = NewIfc_on_%s_change;\n"
" h->next = NULL;\n"
" ret = NI_install_handler(obj, h);\n"
" NI_set_locked(obj, false);\n"
" }\n"
" else\n"
" ret = NewIfc_error_lock_failed;\n"
" return ret;\n"
"}\n\n", attributes[i].name, type_str[attributes[i].type].type, type_str[attributes[i].type].var_name, attributes[i].name);
} }
fputs("#include \"newifc_nongen_after.c\"\n\n", c_code);
fclose(c_code); fclose(c_code);
} }
...@@ -28,27 +28,41 @@ NI_copy(NewIfcObj obj, NewIfcObj *newobj) { ...@@ -28,27 +28,41 @@ NI_copy(NewIfcObj obj, NewIfcObj *newobj) {
} }
static NI_err static NI_err
NI_walk_children_recurse(NewIfcObj obj, NI_err (*cb)(NewIfcObj obj, void *cb_data), void *cbdata) NI_walk_children_recurse(NewIfcObj obj, bool top_down, NI_err (*cb)(NewIfcObj obj, void *cb_data), void *cbdata)
{ {
NI_err err; NI_err err;
NewIfcObj nobj;
if (!obj) if (!obj)
return NewIfc_error_none; return NewIfc_error_none;
err = cb(obj, cbdata); err = cb(obj, cbdata);
if (err != NewIfc_error_none) if (err != NewIfc_error_none)
return err; return err;
if (obj->bottomchild != NULL) { if (top_down)
err = NI_walk_children_recurse(obj->bottomchild, cb, cbdata); nobj = obj->topchild;
if (err != NewIfc_error_none) else
nobj = obj->bottomchild;
if (nobj != NULL) {
err = NI_walk_children_recurse(nobj, top_down, cb, cbdata);
if (err != NewIfc_error_none && err != NewIfc_error_skip_subtree)
return err; return err;
} }
if (!obj->higherpeer) if (top_down)
nobj = obj->lowerpeer;
else
nobj = obj->higherpeer;
if (!nobj)
return NewIfc_error_none; return NewIfc_error_none;
return NI_walk_children_recurse(obj->higherpeer, cb, cbdata); err = NI_walk_children_recurse(nobj, top_down, cb, cbdata);
if (err != NewIfc_error_none && err != NewIfc_error_skip_subtree)
return err;
return NewIfc_error_none;
} }
NI_err NI_err
NI_walk_children(NewIfcObj obj, NI_err (*cb)(NewIfcObj obj, void *cb_data), void *cbdata) NI_walk_children(NewIfcObj obj, bool top_down, NI_err (*cb)(NewIfcObj obj, void *cb_data), void *cbdata)
{ {
NI_err ret; NI_err ret;
...@@ -58,7 +72,7 @@ NI_walk_children(NewIfcObj obj, NI_err (*cb)(NewIfcObj obj, void *cb_data), void ...@@ -58,7 +72,7 @@ NI_walk_children(NewIfcObj obj, NI_err (*cb)(NewIfcObj obj, void *cb_data), void
return NewIfc_error_invalid_arg; return NewIfc_error_invalid_arg;
ret = NI_set_locked(obj, true); ret = NI_set_locked(obj, true);
if (ret == NewIfc_error_none) { if (ret == NewIfc_error_none) {
ret = NI_walk_children_recurse(obj->bottomchild, cb, cbdata); ret = NI_walk_children_recurse(obj->bottomchild, top_down, cb, cbdata);
NI_set_locked(obj, false); NI_set_locked(obj, false);
} }
else else
...@@ -66,15 +80,59 @@ NI_walk_children(NewIfcObj obj, NI_err (*cb)(NewIfcObj obj, void *cb_data), void ...@@ -66,15 +80,59 @@ NI_walk_children(NewIfcObj obj, NI_err (*cb)(NewIfcObj obj, void *cb_data), void
return ret; return ret;
} }
int static int
handler_compar(const void *a, const void *b) handler_bsearch_compar(const void *a, const void *b)
{ {
const enum NewIfc_event_handlers *key = a; const enum NewIfc_event_handlers *key = a;
const struct NewIfc_handler *tst = b; const struct NewIfc_handler **tst = (const struct NewIfc_handler **)b;
if (*key < tst->event) if (*key < (*tst)->event)
return -1; return -1;
if (*key > tst->event) if (*key > (*tst)->event)
return 1; return 1;
return 0; return 0;
} }
static int
handler_qsort_compar(const void *a, const void *b)
{
const struct NewIfc_handler **ap = (const struct NewIfc_handler **)a;
const struct NewIfc_handler **bp = (const struct NewIfc_handler **)b;
return ((*ap)->event - (*bp)->event);
}
static NI_err
NI_install_handler(NewIfcObj obj, struct NewIfc_handler *handler)
{
struct NewIfc_handler **head = bsearch(&handler->event, obj->handlers,
obj->handlers_sz, sizeof(obj->handlers[0]), handler_bsearch_compar);
if (head != NULL) {
handler->next = *head;
*head = handler;
return NewIfc_error_none;
}
// Increase the size of handlers...
// TODO: this is pretty inefficient, a bsearch() for insert point
// would be best, but even a linear search for it would likely be
// better.
size_t new_sz = obj->handlers_sz;
struct NewIfc_handler ***na = realloc(obj->handlers, new_sz * sizeof(obj->handlers[0]));
if (na == NULL)
return NewIfc_error_allocation_failure;
obj->handlers[obj->handlers_sz] = handler;
obj->handlers_sz = new_sz;
qsort(obj->handlers, obj->handlers_sz, sizeof(obj->handlers[0]), handler_qsort_compar);
return NewIfc_error_none;
}
static NI_err
remove_focus_cb(NewIfcObj obj, void *cbdata)
{
(void)cbdata;
if (obj->focus == false)
return NewIfc_error_skip_subtree;
obj->set(obj, NewIfc_focus, false);
return NewIfc_error_none;
}
...@@ -63,7 +63,7 @@ rw_recalc_child(struct root_window *rw, uint16_t height, uint16_t width) ...@@ -63,7 +63,7 @@ rw_recalc_child(struct root_window *rw, uint16_t height, uint16_t width)
rw->api.last_error = NewIfc_error_wont_fit; rw->api.last_error = NewIfc_error_wont_fit;
return; return;
} }
if (NI_walk_children((NewIfcObj)rw, rw_recalc_child_cb, &nsz) != NewIfc_error_none) { if (NI_walk_children((NewIfcObj)rw, false, rw_recalc_child_cb, &nsz) != NewIfc_error_none) {
rw->api.last_error = NewIfc_error_wont_fit; rw->api.last_error = NewIfc_error_wont_fit;
return; return;
} }
...@@ -242,6 +242,7 @@ NewIFC_root_window(NewIfcObj *newobj) ...@@ -242,6 +242,7 @@ NewIFC_root_window(NewIfcObj *newobj)
(*newrw)->api.min_width = 40; (*newrw)->api.min_width = 40;
// TODO: This is only needed by the unit tests... // TODO: This is only needed by the unit tests...
(*newrw)->api.root = *newobj; (*newrw)->api.root = *newobj;
(*newrw)->api.focus = true;
(*newrw)->show_title = true; (*newrw)->show_title = true;
(*newrw)->help = true; (*newrw)->help = true;
(*newrw)->title_sz = 0; (*newrw)->title_sz = 0;
...@@ -276,6 +277,7 @@ void test_root_window(CuTest *ct) ...@@ -276,6 +277,7 @@ void test_root_window(CuTest *ct)
CuAssertTrue(ct, obj->min_width == 40); CuAssertTrue(ct, obj->min_width == 40);
CuAssertTrue(ct, obj->min_height == 2); CuAssertTrue(ct, obj->min_height == 2);
CuAssertTrue(ct, obj->last_error == NewIfc_error_none); CuAssertTrue(ct, obj->last_error == NewIfc_error_none);
CuAssertTrue(ct, obj->focus == true);
CuAssertTrue(ct, obj->get(obj, NewIfc_show_title, &b) == NewIfc_error_none && b); CuAssertTrue(ct, obj->get(obj, NewIfc_show_title, &b) == NewIfc_error_none && b);
CuAssertTrue(ct, obj->last_error == NewIfc_error_none); CuAssertTrue(ct, obj->last_error == NewIfc_error_none);
CuAssertTrue(ct, obj->get(obj, NewIfc_show_help, &b) == NewIfc_error_none && b); CuAssertTrue(ct, obj->get(obj, NewIfc_show_help, &b) == NewIfc_error_none && b);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment