From d7f8e7303d537b725eee9ebf7af98804995bcfe9 Mon Sep 17 00:00:00 2001 From: Timerix22 Date: Sat, 27 May 2023 22:40:28 +0600 Subject: [PATCH] ScalingSize, onBuild, toString --- kerep | 2 +- src/TUI/Dtsod/tui_dtsod.c | 42 +++++---- src/TUI/Dtsod/tui_dtsod.h | 52 ++++++----- src/TUI/Dtsod/tui_dtsod_internal.h | 4 - src/TUI/Grid.c | 140 +++++++++++++++++++++++------ src/TUI/TextBlock.c | 11 ++- src/TUI/UIElement.c | 41 ++++++--- src/TUI/UIError.h | 4 +- src/TUI/tui.c | 50 ++++++++++- src/TUI/tui.h | 46 ++++++---- src/TUI/tui_internal.h | 18 ++++ src/main.c | 18 +++- view/example.tui.dtsod | 9 +- view/main.tui.dtsod | 23 +++-- 14 files changed, 345 insertions(+), 115 deletions(-) diff --git a/kerep b/kerep index 70807ed..aba6771 160000 --- a/kerep +++ b/kerep @@ -1 +1 @@ -Subproject commit 70807ed22b4c34db247fd8fc1ca1c776dd27ab4c +Subproject commit aba67710c70c779fcf04af2bd01fb348ce75135d diff --git a/src/TUI/Dtsod/tui_dtsod.c b/src/TUI/Dtsod/tui_dtsod.c index 1f0f20e..fe5ebbf 100644 --- a/src/TUI/Dtsod/tui_dtsod.c +++ b/src/TUI/Dtsod/tui_dtsod.c @@ -66,8 +66,23 @@ UI_Maybe UIDtsodParser_parseText(UIDtsodParser* parser, char* file_name_placehol return MaybeNull; } +UI_Maybe UIElement_deserialize(Dtsod* dtsod){ + char* type_name; + Dtsod_tryGet_cptr(dtsod, "type", type_name, true); + UITDescriptor* type=UITDescriptor_getByName(type_name); + if(type==NULL) + UI_safethrow_msg(cptr_concat("invalid type '", type_name, "'"), ;); + if(type->deserialize==NULL) + UI_safethrow(UIError_NullPtr, ;); + UI_try(type->deserialize(dtsod), _m_ui, ;); + return _m_ui; +} +////////////////////////////////////// +// UIContext // +////////////////////////////////////// + void _UIContext_freeMembers(void* _u){ UIContext* u=_u; Hashtable_free(u->ui_elements); @@ -80,17 +95,6 @@ void UIContext_destroy(UIContext* u){ kt_define(UIContext, _UIContext_freeMembers, NULL); - -UI_Maybe UIElement_deserialize(Dtsod* dtsod){ - char* type_name; - Dtsod_tryGet_cptr(dtsod, "type", type_name, true); - UITDescriptor* ui_type=UITDescriptor_getByName(type_name); - if(ui_type==NULL) - UI_safethrow_msg(cptr_concat("invalid type '", type_name, "'"), ;); - UI_try(ui_type->deserialize(dtsod), _m_ui, ;); - return _m_ui; -} - UI_Maybe UIDtsodParser_constructUIContext(UIDtsodParser* parser){ if(parser->context == NULL){ parser->context=malloc(sizeof(UIContext)); @@ -107,14 +111,16 @@ UI_Maybe UIDtsodParser_constructUIContext(UIDtsodParser* parser){ char* file_namespace; Dtsod_tryGet_cptr(fm.dtsod, "namespace", file_namespace, true); Hashtable_foreach(fm.dtsod, dtsod_elem, - if(cptr_compare(dtsod_elem.key, "ui")) { + if(cptr_equals(dtsod_elem.key, "ui")) { + if(!UniCheckTypePtr(dtsod_elem.value, Autoarr(Unitype))) + UI_safethrow(UIError_InvalidFormat, ;); Autoarr_Unitype* ui_ar=dtsod_elem.value.VoidPtr; Autoarr_foreach(ui_ar, ui_el_dtsod, UI_try(UIElement_deserialize(ui_el_dtsod.VoidPtr),_m_ui,;); UIElement_Ptr new_el=_m_ui.value.VoidPtr; - // kprintf("[UIDtsodParser_constructUIContext] %s : %s\n", new_el->name, new_el->ui_type->type->name); - if(new_el->ui_type->type->id==ktid_ptrName(Grid)){ - UI_try(_Grid_bindContent((Grid*)new_el, parser->context),_15151,;); + // kprintf("[UIDtsodParser_constructUIContext] %s : %s\n", new_el->name, new_el->type->kt->name); + if(new_el->type->onBuild){ + UI_try(new_el->type->onBuild(new_el, parser->context),_15151,;); } UI_try( UIContext_add(parser->context, file_namespace, new_el), _a76515, ;); ); @@ -140,16 +146,16 @@ UI_Maybe UIContext_getAny(UIContext* context, char* name){ UI_Maybe _UIContext_get(UIContext* context, char* name, ktid type_id){ UI_try(UIContext_getAny(context, name), _m_ui, ;); UIElement* ptr=_m_ui.value.VoidPtr; - if(ptr->ui_type->type->id != type_id) + if(ptr->type->kt->id != type_id) UI_safethrow_msg(cptr_concat( - "tried to get ",ktDescriptor_get(type_id)->name, " <",name,"> but it is of type ", ptr->ui_type->type->name + "tried to get ",ktDescriptor_get(type_id)->name, " <",name,"> but it is of type ", ptr->type->kt->name ), ;); return _m_ui; } UI_Maybe UIContext_add(UIContext* context, char* namespace, _UIElement_Ptr _new_el){ UIElement_Ptr new_el=_new_el; - Unitype u=UniPtr(new_el->ui_type->type->id, new_el, true); + Unitype u=UniPtr(new_el->type->kt->id, new_el, true); char* namespace_and_name=cptr_concat(namespace, "_", new_el->name); if(!Hashtable_tryAdd(context->ui_elements, namespace_and_name, u)) UI_safethrow_msg(cptr_concat("element with name <", new_el->name, "> already exists in context"), diff --git a/src/TUI/Dtsod/tui_dtsod.h b/src/TUI/Dtsod/tui_dtsod.h index 0c7f8c9..3b4522a 100644 --- a/src/TUI/Dtsod/tui_dtsod.h +++ b/src/TUI/Dtsod/tui_dtsod.h @@ -44,7 +44,9 @@ UI_THROWING_FUNC_DECL(UIDtsodParser_constructUIContext(UIDtsodParser* parser)); ////////////////////////////////////// // UIContext // ////////////////////////////////////// -typedef struct UIContext UIContext; +STRUCT(UIContext, + Hashtable* ui_elements; +) void UIContext_destroy(UIContext* u); @@ -61,7 +63,7 @@ UI_THROWING_FUNC_DECL(_UIContext_get(UIContext* context, char* name, ktid type_i TYPE* NAMESPACE##_##NAME=_m_##NAMESPACE##_##NAME.value.VoidPtr; ///@return Maybe -UI_THROWING_FUNC_DECL(UIContext_add(UIContext* context, char* namespace, _UIElement_Ptr new_el)); +UI_THROWING_FUNC_DECL(UIContext_add(UIContext* context, char* _namespace, _UIElement_Ptr new_el)); ////////////////////////////////////// @@ -73,7 +75,7 @@ UI_THROWING_FUNC_DECL(UIContext_add(UIContext* context, char* namespace, _UIElem UI_THROWING_FUNC_DECL( UIElement_deserialize(Dtsod* dtsod) ); -#define __def_Dtsod_tryGet(dtsod, key, var_name, is_neccecary, TYPE, TYPE_ID, UNI_FIELD, code...) { \ +#define _Dtsod_tryGet(dtsod, key, var_name, is_necessary, TYPE, TYPE_ID, UNI_FIELD, code...) { \ Unitype uni; \ if(Hashtable_tryGet(dtsod, key, &uni)) { \ if(!UniCheckTypeId(uni, TYPE_ID)) \ @@ -82,35 +84,43 @@ UI_THROWING_FUNC_DECL( UIElement_deserialize(Dtsod* dtsod) ); var_name=uni.UNI_FIELD; \ { code; } \ } \ - else if(is_neccecary) \ + else if(is_necessary) \ UI_safethrow_msg(cptr_concat("can't find key '", key, "'"), ;); \ } -#define Dtsod_tryGet_i64(dtsod, key, var_name, is_neccecary, code...) \ - __def_Dtsod_tryGet(dtsod, key, var_name, is_neccecary, i64, ktid_name(i64), Int64, code) +#define Dtsod_tryGet_i64(dtsod, key, var_name, is_necessary, code...) \ + _Dtsod_tryGet(dtsod, key, var_name, is_necessary, i64, ktid_name(i64), Int64, code) -#define Dtsod_tryGet_u64(dtsod, key, var_name, is_neccecary, code...) \ - __def_Dtsod_tryGet(dtsod, key, var_name, is_neccecary, u64, ktid_name(u64), UInt64, code) +#define Dtsod_tryGet_u64(dtsod, key, var_name, is_necessary, code...) \ + _Dtsod_tryGet(dtsod, key, var_name, is_necessary, u64, ktid_name(u64), UInt64, code) -#define Dtsod_tryGet_f64(dtsod, key, var_name, is_neccecary, code...) \ - __def_Dtsod_tryGet(dtsod, key, var_name, is_neccecary, f64, ktid_name(f64), Float64, code) +#define Dtsod_tryGet_f64(dtsod, key, var_name, is_necessary, code...) \ + _Dtsod_tryGet(dtsod, key, var_name, is_necessary, f64, ktid_name(f64), Float64, code) -#define Dtsod_tryGet_bool(dtsod, key, var_name, is_neccecary, code...) \ - __def_Dtsod_tryGet(dtsod, key, var_name, is_neccecary, bool, ktid_name(bool), Bool, code) +#define Dtsod_tryGet_bool(dtsod, key, var_name, is_necessary, code...) \ + _Dtsod_tryGet(dtsod, key, var_name, is_necessary, bool, ktid_name(bool), Bool, code) -#define Dtsod_tryGet_ptr(dtsod, key, type, var_name, is_neccecary, code...) \ - __def_Dtsod_tryGet(dtsod, key, var_name, is_neccecary, type*, ktid_ptrName(type), VoidPtr, code) +#define Dtsod_tryGet_ptr(dtsod, key, type, var_name, is_necessary, code...) \ + _Dtsod_tryGet(dtsod, key, var_name, is_necessary, type*, ktid_ptrName(type), VoidPtr, code) -#define Dtsod_tryGet_cptr(dtsod, key, var_name, is_neccecary, code...) \ - Dtsod_tryGet_ptr(dtsod, key, char, var_name, is_neccecary, code) +#define Dtsod_tryGet_cptr(dtsod, key, var_name, is_necessary, code...) \ + Dtsod_tryGet_ptr(dtsod, key, char, var_name, is_necessary, code) -#define Dtsod_tryGet_Hashtable(dtsod, key, var_name, is_neccecary, code...) \ - Dtsod_tryGet_ptr(dtsod, key, Hashtable, var_name, is_neccecary, code) - -#define Dtsod_tryGet_Autoarr(dtsod, key, var_name, is_neccecary, code...) \ - Dtsod_tryGet_ptr(dtsod, key, Autoarr(Unitype), var_name, is_neccecary, code) +#define Dtsod_tryGet_Hashtable(dtsod, key, var_name, is_necessary, code...) \ + Dtsod_tryGet_ptr(dtsod, key, Hashtable, var_name, is_necessary, code) +#define Dtsod_tryGet_Autoarr(dtsod, key, var_name, is_necessary, code...) \ + Dtsod_tryGet_ptr(dtsod, key, Autoarr(Unitype), var_name, is_necessary, code) +#define Dtsod_tryGet_ScalingSize(dtsod, key, var_name, is_necessary, code...) { \ + Unitype uni; \ + if(Hashtable_tryGet(dtsod, key, &uni)) { \ + UI_try(ScalingSize_fromUnitype(uni, &(var_name)), _195, ;); \ + { code; } \ + } \ + else if(is_necessary) \ + UI_safethrow_msg(cptr_concat("can't find key '", key, "'"), ;); \ +} #if __cplusplus } diff --git a/src/TUI/Dtsod/tui_dtsod_internal.h b/src/TUI/Dtsod/tui_dtsod_internal.h index 7d8cbe4..928bd0f 100644 --- a/src/TUI/Dtsod/tui_dtsod_internal.h +++ b/src/TUI/Dtsod/tui_dtsod_internal.h @@ -15,7 +15,3 @@ STRUCT(UIDtsodParser, UIContext* context; bool returned_context; ) - -STRUCT(UIContext, - Hashtable* ui_elements; -) \ No newline at end of file diff --git a/src/TUI/Grid.c b/src/TUI/Grid.c index a1128ae..00b97f3 100644 --- a/src/TUI/Grid.c +++ b/src/TUI/Grid.c @@ -23,7 +23,8 @@ UI_Maybe _Grid_getName(Grid* grid, u16 column, u16 row) { return SUCCESS(UniHeapPtr(char, *str_ptr)); } -UI_Maybe _Grid_bindContent(Grid* grid, UIContext* context) { +UI_Maybe Grid_onBuildUIContext(UIElement* _grid, UIContext* context) { + Grid* grid=(Grid*)_grid; Autoarr(UIElement_Ptr)* content=Autoarr_create(UIElement_Ptr, 64, 16); Grid_foreachName(grid, name, UI_try(UIContext_getAny(context, name), m_uie, Autoarr_freeWithoutMembers(content,true)); @@ -39,7 +40,9 @@ UI_Maybe _Grid_bindContent(Grid* grid, UIContext* context) { void Grid_freeMembers(void* _self){ Grid* self=(Grid*)_self; - if(self->is_bound){ + free(self->column_widths); + free(self->row_heights); + if(self->content_names){ for(u16 r = 0; r < self->rows; r++){ for(u16 c = 0; c < self->columns; c++){ tryLast(Grid_get(self, c, r), m_el, @@ -47,12 +50,11 @@ void Grid_freeMembers(void* _self){ free(self->content_names)); UIElement_Ptr el=m_el.value.VoidPtr; UIElement_destroy(el); - } + } } - } - free(self->content); - if(self->content_names) free(self->content_names); + } + else free(self->content); } UI_Maybe Grid_draw(Renderer* renderer, UIElement_Ptr _self, const DrawingArea area){ @@ -67,33 +69,78 @@ UI_Maybe Grid_draw(Renderer* renderer, UIElement_Ptr _self, const DrawingArea ar UI_Maybe Grid_deserialize(Dtsod* dtsod){ Grid gr; - Autoarr(Pointer)* content_names=Autoarr_create(Pointer, 64, 16); u16 columns=0, rows=0; + Autoarr(i16)* column_widths=Autoarr_create(i16, 16, 64); + Autoarr(i16)* row_heights=Autoarr_create(i16, 16, 64); + Autoarr(Pointer)* content_names=Autoarr_create(Pointer, 64, 16); UI_try(UIElement_deserializeBase(dtsod, &gr.base), _91875, ;); + + Autoarr(Unitype)* _column_widths; + Dtsod_tryGet_Autoarr(dtsod, "column_widths", _column_widths, true, + Autoarr_foreach(_column_widths, _cw, + ScalingSize cw; + UI_try(ScalingSize_fromUnitype(_cw, &cw), _18751, + Autoarr_freeWithoutMembers(content_names, true); + Autoarr_freeWithoutMembers(column_widths, true); + Autoarr_freeWithoutMembers(row_heights, true); + ); + Autoarr_add(column_widths, cw); + ); + ); + columns=Autoarr_length(column_widths); + + Autoarr(Unitype)* _row_heights; + Dtsod_tryGet_Autoarr(dtsod, "row_heights", _row_heights, true, + Autoarr_foreach(_row_heights, _rh, + ScalingSize rh; + UI_try(ScalingSize_fromUnitype(_rh, &rh), _18751, + Autoarr_freeWithoutMembers(content_names, true); + Autoarr_freeWithoutMembers(row_heights, true); + Autoarr_freeWithoutMembers(row_heights, true); + ); + Autoarr_add(row_heights, rh); + ); + ); + rows=Autoarr_length(row_heights); + Autoarr(Unitype)* _content; Dtsod_tryGet_Autoarr(dtsod, "content", _content, true); - rows=Autoarr_length(_content); + if(rows != Autoarr_length(_content)) + UI_safethrow(UIError_InvalidGrid, + Autoarr_freeWithoutMembers(content_names, true); + Autoarr_freeWithoutMembers(column_widths, true); + Autoarr_freeWithoutMembers(row_heights, true); + ); + Autoarr_foreach(_content, _row, - if(!UniCheckTypePtr(_row, Autoarr(Unitype))){ + if(!UniCheckTypePtr(_row, Autoarr(Unitype))) UI_safethrow_msg( - cptr_concat("expected Autoarr, but has got type id '", + cptr_concat("expected type Autoarr(Unitype), but has got type id '", toString_i64(_row.typeId), "'"), - Autoarr_freeWithoutMembers(content_names, true)); - } + Autoarr_freeWithoutMembers(content_names, true); + Autoarr_freeWithoutMembers(column_widths, true); + Autoarr_freeWithoutMembers(row_heights, true); + ); + Autoarr(Unitype)* row=_row.VoidPtr; - u16 row_len=Autoarr_length(row); - if(columns==0) - columns=row_len; - else if(row_len != columns) - UI_safethrow_msg("wrong grid row size",;); + if(columns != Autoarr_length(row)) + UI_safethrow(UIError_InvalidGrid, + Autoarr_freeWithoutMembers(content_names, true); + Autoarr_freeWithoutMembers(column_widths, true); + Autoarr_freeWithoutMembers(row_heights, true); + ); + Autoarr_foreach(row, _elem_d, - if(!UniCheckTypePtr(_elem_d, char)){ + if(!UniCheckTypePtr(_elem_d, char)) UI_safethrow_msg( - cptr_concat("expected char*, but has got type id '", + cptr_concat("expected type char*, but has got type id '", toString_i64(_elem_d.typeId),"'"), - Autoarr_freeWithoutMembers(content_names, true)); - } + Autoarr_freeWithoutMembers(content_names, true); + Autoarr_freeWithoutMembers(column_widths, true); + Autoarr_freeWithoutMembers(row_heights, true); + ); + char* elem_name=_elem_d.VoidPtr; Autoarr_add(content_names, elem_name); ) @@ -103,7 +150,10 @@ UI_Maybe Grid_deserialize(Dtsod* dtsod){ Autoarr_freeWithoutMembers(content_names, true); gr.columns=columns; gr.rows=rows; - gr.is_bound=false; + gr.column_widths=Autoarr_toArray(column_widths); + Autoarr_freeWithoutMembers(column_widths, true); + gr.row_heights=Autoarr_toArray(row_heights); + Autoarr_freeWithoutMembers(row_heights, true); gr.content=NULL; Grid* ptr=malloc(sizeof(*ptr)); @@ -111,18 +161,56 @@ UI_Maybe Grid_deserialize(Dtsod* dtsod){ return SUCCESS(UniHeapPtr(Grid, ptr)); } +char* Grid_toString(void* _gr, kp_fmt fmt){ + Grid* gr=_gr; + StringBuilder* sb=StringBuilder_create(); + adds("Grid {") + UIElement_appendToStringBuilder(sb, &gr->base); + adduf(gr,rows) + adduf(gr,columns) + adds(" row_heights: [ ") + for(u16 r=0; r < gr->rows; r++){ + addi(gr->row_heights[r]) addc(' ') + } + adds("]" + " column_widths: [ ") + for(u16 c=0; c < gr->rows; c++){ + addi(gr->row_heights[c]) addc(' ') + } + u32 count=gr->rows*gr->columns; + adds("]" + " content: [") + if(gr->content) + for(u32 i=0; icontent[i]; + addc(' ')adds(child->name)addc(':')adds(child->type->kt->name) + } + else if(gr->content_names) + for(u32 i=0; icontent_names[i]; + addc(' ')adds(child_name) + } + adds(" ]" + " }") + return StringBuilder_build(sb).ptr; +} -uit_define(Grid, Grid_freeMembers, NULL, Grid_draw, Grid_deserialize); +uit_define(Grid, Grid_freeMembers, Grid_toString, Grid_draw, Grid_deserialize, Grid_onBuildUIContext); -Grid* Grid_create(char* name, u16 columns, u16 rows, UIElement_Ptr* content){ +Grid* Grid_create(char* name, + u16 columns, u16 rows, + ScalingSize* column_widths, ScalingSize* row_heights, + UIElement_Ptr* content) +{ Grid* grid=malloc(sizeof(Grid)); *grid=(Grid){ .base=_UIElement_initBaseDefault(name, &UITDescriptor_Grid), .columns=columns, .rows=rows, + .column_widths=column_widths, + .row_heights=row_heights, .content=content, - .content_names=NULL, - .is_bound=true + .content_names=NULL }; return grid; } diff --git a/src/TUI/TextBlock.c b/src/TUI/TextBlock.c index 084d1c3..3c5a4e3 100644 --- a/src/TUI/TextBlock.c +++ b/src/TUI/TextBlock.c @@ -31,8 +31,17 @@ UI_Maybe TextBlock_deserialize(Dtsod* dtsod){ return SUCCESS(UniHeapPtr(TextBlock, ptr)); } +char* TextBlock_toString(void* _tb, kp_fmt fmt){ + TextBlock* tb=_tb; + StringBuilder* sb=StringBuilder_create(); + adds("TextBlock {") + UIElement_appendToStringBuilder(sb, &tb->base); + addstrf(tb,text) + adds(" }") + return StringBuilder_build(sb).ptr; +} -uit_define(TextBlock, TextBlock_freeMembers, NULL,TextBlock_draw, TextBlock_deserialize); +uit_define(TextBlock, TextBlock_freeMembers, TextBlock_toString, TextBlock_draw, TextBlock_deserialize, NULL); TextBlock* TextBlock_create(char* name, string text){ TextBlock* textBlock=malloc(sizeof(TextBlock)); diff --git a/src/TUI/UIElement.c b/src/TUI/UIElement.c index 09e9a97..7f3d5d6 100644 --- a/src/TUI/UIElement.c +++ b/src/TUI/UIElement.c @@ -1,5 +1,26 @@ #include "tui_internal.h" +void UIElement_appendToStringBuilder(StringBuilder* sb, UIElement_Ptr u){ + char *s0; + addsf(u,name) addc(' ') + adds((s0=UITDescriptor_toString(u->type))); + adduf(u,min_width) + adduf(u,min_height) + addif(u,width) + addif(u,height) + adds(" color:") adds(kp_bgColor_toString(u->color)) + addc('|') adds(kp_fgColor_toString(u->color)) + adds(" border { t:") addu(u->border.top) + adds(" b:") addu(u->border.bottom) + adds(" l:") addu(u->border.left) + adds(" r:") addu(u->border.right) + adds(" color:") adds(kp_bgColor_toString(u->color)) + addc('|') adds(kp_fgColor_toString(u->color)) + adds(" }") + free(s0); +} + + kt_define(UIElement, NULL, NULL); Autoarr_define(UIElement_Ptr, true); Array_define(UIElement); @@ -8,11 +29,11 @@ Array_define(UIElement); inline UIElement _UIElement_initBaseDefault(char* name, UITDescriptor* uit){ return (UIElement){ .name=name, - .ui_type=uit, + .type=uit, .min_width=2, .min_height=2, - .width_scaling=UIElement_no_scaling, - .height_scaling=UIElement_no_scaling, + .width=size_enable_scaling(1), + .height=size_enable_scaling(1), .color=kp_bgBlack|kp_fgGray, .border={ .left=UIBorder_Thin, .right=UIBorder_Thin, @@ -23,8 +44,8 @@ inline UIElement _UIElement_initBaseDefault(char* name, UITDescriptor* uit){ } void UIElement_destroy(UIElement_Ptr self){ - if(self->ui_type->type->freeMembers) - self->ui_type->type->freeMembers(self); + if(self->type->kt->freeMembers) + self->type->kt->freeMembers(self); free(self); } @@ -50,16 +71,16 @@ UI_Maybe UIElement_deserializeBase(Dtsod* dtsod, UIElement* base){ char* type_name; Dtsod_tryGet_cptr(dtsod, "type", type_name, true); - UITDescriptor* ui_type=UITDescriptor_getByName(type_name); - if(ui_type==NULL) + UITDescriptor* type=UITDescriptor_getByName(type_name); + if(type==NULL) UI_safethrow_msg(cptr_concat("invalid type '", type_name, "'"), ;); - *base=_UIElement_initBaseDefault(name, ui_type); + *base=_UIElement_initBaseDefault(cptr_copy(name), type); Dtsod_tryGet_i64(dtsod, "min_width", base->min_width, false); Dtsod_tryGet_i64(dtsod, "min_height", base->min_height, false); - Dtsod_tryGet_i64(dtsod, "width_scaling", base->width_scaling, false); - Dtsod_tryGet_i64(dtsod, "height_scaling", base->height_scaling, false); + Dtsod_tryGet_ScalingSize(dtsod, "width", base->width, false); + Dtsod_tryGet_ScalingSize(dtsod, "height", base->height, false); char *bg_color_name, *fg_color_name; Dtsod_tryGet_cptr(dtsod, "bg_color", bg_color_name, false, set_color(bg_color_name, base->color); diff --git a/src/TUI/UIError.h b/src/TUI/UIError.h index ee362ef..9267b03 100644 --- a/src/TUI/UIError.h +++ b/src/TUI/UIError.h @@ -13,7 +13,9 @@ PACKED_ENUM(UIError, UIError_InvalidHeight, UIError_InvalidWidth, UIError_InvalidX, UIError_InvalidY, UIError_PrintError, - UIError_InvalidVersion + UIError_InvalidVersion, + UIError_InvalidGrid, + UIError_InvalidFormat ) // this macros can be changed later to improve debugging diff --git a/src/TUI/tui.c b/src/TUI/tui.c index b440c6c..7cbab27 100644 --- a/src/TUI/tui.c +++ b/src/TUI/tui.c @@ -3,7 +3,53 @@ kt_define(DrawingArea, NULL, NULL); kt_define(UIBorder, NULL, NULL); -kt_define(UITDescriptor, NULL, NULL); + +UI_Maybe ScalingSize_fromUnitype(Unitype UNI, ScalingSize* SZ_VAR){ + if(UniCheckType(UNI, i64)){ + *SZ_VAR=UNI.Int64; + } else if(UniCheckTypePtr(UNI, char)){ + char* _sz_str=UNI.VoidPtr; + u32 len=cptr_length(_sz_str); + bool has_asterisk=_sz_str[len-1]=='0'; + if(has_asterisk) + _sz_str[len-1]=0; + int _sz=0; + if(sscanf(_sz_str, "%i", &_sz)!=1) + UI_safethrow(UIError_InvalidFormat, ;); + if(has_asterisk) + _sz=size_enable_scaling(_sz); + *SZ_VAR=_sz; + } else UI_safethrow_msg( + cptr_concat("expected type i64 or char*, but has got type id '", + toString_i64(UNI.typeId), "'"),;); + return MaybeNull; +} + +////////////////////////////////////// +// TUI type system // +////////////////////////////////////// +char* UITDescriptor_toString(UITDescriptor* d){ + const char* n="NULL"; + char *s0=ktDescriptor_toString(d->kt); + char *s1= d->draw ? toString_hex(d->draw, sizeof(void*), 0,1,0) : n; + char *s2= d->deserialize ? toString_hex(d->deserialize, sizeof(void*), 0,1,0) : n; + char *s3= d->onBuild ? toString_hex(d->onBuild, sizeof(void*), 0,1,0) : n; + char* rez=cptr_concat("UITDescriptor { ", + s0, + " draw:",s1, + " deserialize:",s2, + " onBuild:",s3, + " }"); + if(s0!=n) free(s0); + if(s1!=n) free(s1); + if(s2!=n) free(s2); + if(s3!=n) free(s3); + return rez; +} + +char* _UITDescriptor_toString(void* _d, u32 fmt){ return UITDescriptor_toString(_d); } + +kt_define(UITDescriptor, NULL, _UITDescriptor_toString); Hashtable* _uit_hashtable=NULL; u32 __kt_id_first=-1; @@ -29,7 +75,7 @@ void kt_freeTUI(){ } void __uit_register(ktDescriptor* kt, UITDescriptor* uit){ - uit->type=kt; + uit->kt=kt; Hashtable_add(_uit_hashtable, cptr_copy(kt->name), UniStackPtr(UITDescriptor, uit)); } diff --git a/src/TUI/tui.h b/src/TUI/tui.h index ce686b2..824ebd2 100644 --- a/src/TUI/tui.h +++ b/src/TUI/tui.h @@ -20,11 +20,12 @@ typedef UIElement* UIElement_Ptr; typedef struct Renderer Renderer; typedef struct DrawingArea DrawingArea; -///@return Maybe +///@return Maybe typedef UI_THROWING_FUNC_DECL( (*UIElement_draw_t)(Renderer* renderer, UIElement_Ptr self, const DrawingArea area) ); - ///@return Maybe typedef UI_THROWING_FUNC_DECL( (*UIElement_deserialize_t)(Dtsod* dtsod) ); +///@return Maybe +typedef UI_THROWING_FUNC_DECL( (*UIElement_onBuildUIContext_t)(UIElement* self, UIContext* context) ); ////////////////////////////////////// @@ -32,17 +33,19 @@ typedef UI_THROWING_FUNC_DECL( (*UIElement_deserialize_t)(Dtsod* dtsod) ); ////////////////////////////////////// STRUCT(UITDescriptor, - ktDescriptor* type; + ktDescriptor* kt; UIElement_draw_t draw; UIElement_deserialize_t deserialize; + UIElement_onBuildUIContext_t onBuild; ) #define uit_declare(TYPE) extern UITDescriptor UITDescriptor_##TYPE; -#define uit_define(TYPE, FREE_F, TOSTRING_F, DRAW_F, DESERIALIZE_F) kt_define(TYPE, FREE_F, TOSTRING_F) \ +#define uit_define(TYPE, FREE_F, TOSTRING_F, DRAW_F, DESERIALIZE_F, ON_BUILD_F) kt_define(TYPE, FREE_F, TOSTRING_F) \ UITDescriptor UITDescriptor_##TYPE={ \ .draw=DRAW_F, \ - .deserialize=DESERIALIZE_F \ + .deserialize=DESERIALIZE_F, \ + .onBuild=ON_BUILD_F \ }; /// call this between kt_beginInit() and kt_endInit() @@ -74,6 +77,14 @@ PACKED_ENUM(UIBorderThickness, // Small structs // ////////////////////////////////////// +typedef i16 ScalingSize; + +#define is_size_scaling(SZ) (SZ<0) +#define size_enable_scaling(SZ) (SZ < 0 ? SZ : (-1*SZ)) +#define size_disable_scaling(SZ) (SZ >= 0 ? SZ : (-1*SZ)) +///@return Maybe +UI_THROWING_FUNC_DECL( ScalingSize_fromUnitype(Unitype UNI, ScalingSize* SZ_VAR) ); + STRUCT(DrawingArea, /* right-top corner */ u16 x; u16 y; @@ -123,25 +134,23 @@ UI_THROWING_FUNC_DECL(Renderer_drawBorder(Renderer* renderer, UIBorder border, c ////////////////////////////////////// STRUCT(UIElement, - UITDescriptor* ui_type; + UITDescriptor* type; char* name; u16 min_width; u16 min_height; - u16 width_scaling; - u16 height_scaling; + ScalingSize width; + ScalingSize height; termcolor color; UIBorder border; ) Autoarr_declare(UIElement_Ptr) Array_declare(UIElement) -#define UIElement_no_scaling (u16)0 - /// proper way to free UIElement and all its members void UIElement_destroy(UIElement_Ptr self); #define UIElement_draw(RENDERER, UIE_PTR, PLACE_RECT) \ - (UIE_PTR)->ui_type->draw(RENDERER, UIE_PTR, PLACE_RECT) + (UIE_PTR)->type->draw(RENDERER, UIE_PTR, PLACE_RECT) ////////////////////////////////////// @@ -154,25 +163,24 @@ STRUCT(Grid, UIElement base; u16 columns; u16 rows; - bool is_bound; + ScalingSize* row_heights; + ScalingSize* column_widths; char** content_names; UIElement_Ptr* content; /* UIElement[rows][columns] */ ) uit_declare(Grid); -Grid* Grid_create(char* name, u16 columns, u16 rows, UIElement_Ptr* content); +Grid* Grid_create(char* name, u16 columns, u16 rows, ScalingSize* column_widths, ScalingSize* row_heights, UIElement_Ptr* content); ///@return Maybe UI_THROWING_FUNC_DECL( Grid_get(Grid* grid, u16 column, u16 row) ); ///@return maybe UI_THROWING_FUNC_DECL( Grid_set(Grid* grid, u16 column, u16 row, UIElement_Ptr value)); ///@return Maybe UI_THROWING_FUNC_DECL( _Grid_getName(Grid* grid, u16 column, u16 row) ); -///@return maybe -UI_THROWING_FUNC_DECL( _Grid_bindContent(Grid* grid, UIContext* context) ); #define Grid_foreach(GRID, ELEM_VAR_NAME, CODE...) { \ - if(!GRID->is_bound) \ - UI_safethrow_msg(cptr_concat("grid '", GRID->base.ui_type->type->name, \ + if(!GRID->content) \ + UI_safethrow_msg(cptr_concat("grid '", GRID->base.type->kt->name, \ "' content has not been bound"),;); \ for(u16 _g_r = 0; _g_r < GRID->rows; _g_r++){ \ for(u16 _g_c = 0; _g_c < GRID->columns; _g_c++){ \ @@ -184,8 +192,8 @@ UI_THROWING_FUNC_DECL( _Grid_bindContent(Grid* grid, UIContext* context) ); } #define Grid_foreachName(GRID, ELEM_VAR_NAME, CODE...) { \ - if(GRID->is_bound) \ - UI_safethrow_msg(cptr_concat("grid '", GRID->base.ui_type->type->name, \ + if(!GRID->content_names) \ + UI_safethrow_msg(cptr_concat("grid '", GRID->base.type->kt->name, \ "' content has been already bound"),;); \ for(u16 _g_r = 0; _g_r < GRID->rows; _g_r++){ \ for(u16 _g_c = 0; _g_c < GRID->columns; _g_c++){ \ diff --git a/src/TUI/tui_internal.h b/src/TUI/tui_internal.h index 1f8880c..4b2f0a3 100644 --- a/src/TUI/tui_internal.h +++ b/src/TUI/tui_internal.h @@ -5,6 +5,7 @@ extern "C" { #endif #include "tui.h" +#include "../../kerep/src/String/StringBuilder.h" extern UIElement _UIElement_initBaseDefault(char* name, UITDescriptor* type); @@ -45,6 +46,23 @@ int UIBorderThickness_getByName(char* name); var=(UIBorderThickness)th; \ } + +#define addstr(V) StringBuilder_append_string(sb, V); +#define addstrf(O,F) adds(" "#F":'") addstr(O->F) addc('\'') +#define adds(V) StringBuilder_append_cptr(sb, V); +#define addsf(O,F) adds(" "#F":'") adds(O->F) addc('\'') +#define addc(V) StringBuilder_append_char(sb, V); +#define addcf(O,F) adds(" "#F":") addc(O->F) +#define addi(V) StringBuilder_append_i64(sb, V); +#define addif(O,F) adds(" "#F":") addi(O->F) +#define addu(V) StringBuilder_append_u64(sb, V); +#define adduf(O,F) adds(" "#F":") addu(O->F) +#define addf(V) StringBuilder_append_f64(sb, V); +#define addff(O,F) adds(" "#F":") addf(O->F) + +char* UITDescriptor_toString(UITDescriptor* d); +void UIElement_appendToStringBuilder(StringBuilder* sb, UIElement_Ptr u); + #if __cplusplus } #endif diff --git a/src/main.c b/src/main.c index bf82778..f2f783c 100644 --- a/src/main.c +++ b/src/main.c @@ -43,6 +43,20 @@ UI_Maybe test_example_ui_build() { UIDtsodParser_destroy(p); UIContext_get(ui_context, example, textblock, TextBlock, UIContext_destroy(ui_context)); example_textblock->text=string_fromCptr("text replaced"); + u32 n=0; + Hashtable_foreach(ui_context->ui_elements, el_pair, + UIElement* el=el_pair.value.VoidPtr; + toString_t elToString=el->type->kt->toString; + if(elToString){ + char* str_tmp=elToString(el,0); + char* str=cptr_replace(str_tmp, " ", "\n"); + kprintf("[%u] %s\n", n, str); + free(str_tmp); + free(str); + } + else kprintf("[%u] %s\n", n, el->name); + n++; + ); UIContext_destroy(ui_context); return MaybeNull; } @@ -97,7 +111,9 @@ i32 main(const i32 argc, const char* const* argv){ // TODO signal( SIGWINCH, redraw ); - tryLast(test_example_ui_build(), _6981751, on_exit()); + for(u32 n=0; n<1; n++){ + tryLast(test_example_ui_build(), _6981751, on_exit()); + } on_exit(); return 0; diff --git a/view/example.tui.dtsod b/view/example.tui.dtsod index c3c1b9a..ae933c3 100644 --- a/view/example.tui.dtsod +++ b/view/example.tui.dtsod @@ -6,8 +6,8 @@ $ui: { type: "TextBlock", min_width: 4, max_width: 4, - width_scaling: 0, - height_scaling: 0, + width: 20, + height: "3", bg_color: "black", fg_color: "white", border: { @@ -24,6 +24,11 @@ $ui: { $ui: { name: "Grid", type: "Grid", + row_heights: [ + "1*", + -1, + ], + column_widths: [ "-8*" ], content: [ # column [ "example_textblock" ], # row diff --git a/view/main.tui.dtsod b/view/main.tui.dtsod index 13fb061..62b081e 100644 --- a/view/main.tui.dtsod +++ b/view/main.tui.dtsod @@ -1,12 +1,17 @@ parser_version: 1; namespace: "main"; -$ui: { - name: "main_grid", - type: "Grid", - content: [ - # column -# [ "namespace.element0" ], # row -# [ "namespace.element1" ], # row - ]; -}; +# $ui: { +# name: "main_grid", +# type: "Grid", +# row_heights: [ +# "1*", +# # -1, +# # ], +# # column_widths: [ "-8*" ], +# content: [ +# # column +# # [ "namespace.element0" ], # row +# # [ "namespace.element1" ], # row +# ]; +# };