diff --git a/.gitignore b/.gitignore index 005ebea..1dcc6d1 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ examples/*/*.exe *.lib *.a /Makefile +/build compile_flags.txt diff --git a/examples/basic/sevensegment.c b/examples/basic/sevensegment.c new file mode 100644 index 0000000..7479da9 --- /dev/null +++ b/examples/basic/sevensegment.c @@ -0,0 +1,22 @@ +#include + +int main() { + MwWidget wnd, label; + int W = 480, H = 40; + + MwLibraryInit(); + + wnd = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, W, H, + MwNtitle, "seven segment", + NULL); + + label = MwVaCreateWidget(MwLabelClass, "label", wnd, 0, 0, W, H, + MwNtext, " 123456:78.90 abcdef", + MwNsevenSegment, 1, + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + + MwLabelSetSevenSegment(label, 0, (1 << 0) | (1 << 3) | (1 << 6)); + + MwLoop(wnd); +} diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index deac295..f5b723a 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -36,6 +36,7 @@ #define MwNfixedSize "IfixedSize" #define MwNmargin "Imargin" #define MwNbitmapFont "IbitmapFont" +#define MwNsevenSegment "IsevenSegment" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 0d2eeca..2a6efc7 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -20,6 +20,9 @@ typedef struct _MwViewport* MwViewport; typedef struct _MwListBox* MwListBox; typedef struct _MwComboBox* MwComboBox; typedef struct _MwTreeView* MwTreeView; +typedef struct _MwScrollBar* MwScrollBar; +typedef struct _MwLabel* MwLabel; +typedef struct _MwLabelSegment MwLabelSegment; typedef struct _MwListBoxEntry MwListBoxEntry; typedef struct _MwTreeViewEntry MwTreeViewEntry; typedef struct _MwDirectoryEntry MwDirectoryEntry; @@ -164,6 +167,21 @@ struct _MwTreeView { MwPoint pressed; }; +struct _MwScrollBar { + MwPoint point; + int drag; + int pos; +}; + +struct _MwLabel { + MwLabelSegment* segment; +}; + +struct _MwLabelSegment { + int key; + unsigned char value; +}; + struct _MwDirectoryEntry { char* name; int type; diff --git a/include/Mw/Widget/Label.h b/include/Mw/Widget/Label.h index f11c06b..4c75133 100644 --- a/include/Mw/Widget/Label.h +++ b/include/Mw/Widget/Label.h @@ -17,6 +17,17 @@ extern "C" { */ MWDECL MwClass MwLabelClass; +/*! + * @brief Sets the custom data for seven segment + * @param handle Widget + * @param index Index + * @param data Data, `GFEDCBA` as 7-bit value + * @note See https://en.wikipedia.org/wiki/File:7_Segment_Display_with_Labeled_Segments.svg for what alphabets mean here + * */ +MwInline void MwLabelSetSevenSegment(MwWidget handle, int index, int data) { + MwVaWidgetExecute(handle, "mwLabelSetSevenSegment", NULL, index, data); +} + #ifdef __cplusplus } #endif diff --git a/milsko.xml b/milsko.xml index d46e0d3..9448e30 100644 --- a/milsko.xml +++ b/milsko.xml @@ -89,6 +89,7 @@ + @@ -536,7 +537,16 @@ + + + + + + + + + diff --git a/pl/ostype/NetBSD.pl b/pl/ostype/NetBSD.pl index de93b14..0eec106 100644 --- a/pl/ostype/NetBSD.pl +++ b/pl/ostype/NetBSD.pl @@ -2,6 +2,6 @@ add_incdir("-I/usr/X11R7/include -I/usr/pkg/include"); add_libdir( "-L/usr/X11R7/lib -Wl,-R/usr/X11R7/lib -L/usr/pkg/lib -Wl,-R/usr/pkg/lib"); use_backend("x11"); -add_libs("pthread"); +add_libs("-lpthread"); 1; diff --git a/pl/rules.pl b/pl/rules.pl index 71f38c0..1ad3ff3 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -115,6 +115,7 @@ new_example("examples/basic/combobox"); new_example("examples/basic/treeview"); new_example("examples/basic/box"); new_example("examples/basic/clipboard"); +new_example("examples/basic/sevensegment"); if (param_get("opengl")) { new_example("examples/gldemos/boing", $gl_libs); diff --git a/src/widget/button.c b/src/widget/button.c index dfff6d5..7e5b36c 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -1,5 +1,7 @@ #include +#include "../../external/stb_ds.h" + static int create(MwWidget handle) { MwSetDefault(handle); diff --git a/src/widget/label.c b/src/widget/label.c index 2cf6a8d..a2ae407 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -1,13 +1,119 @@ #include +#include "../../external/stb_ds.h" + +#define ShortOne 5 +#define LongOne 10 +#define Spacing 2 + static int create(MwWidget handle) { + MwLabel lab = malloc(sizeof(*lab)); + + lab->segment = NULL; + handle->internal = lab; + MwSetDefault(handle); MwSetInteger(handle, MwNalignment, MwALIGNMENT_CENTER); MwSetInteger(handle, MwNbold, 0); + MwSetInteger(handle, MwNsevenSegment, 0); return 0; } +static void destroy(MwWidget handle) { + MwLabel lab = handle->internal; + + hmfree(lab->segment); + + free(handle->internal); +} + +static void draw_v(unsigned char* raw, int x, int y, int stride, MwLLColor text) { + int cy, cx, b; + for(cy = y; cy < y + LongOne; cy++) { + for(cx = x; cx < x + ShortOne; cx++) { + unsigned char* px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = y - (ShortOne - 1) / 2; + for(cy = b; cy < b + (ShortOne - 1) / 2; cy++) { + int w = (cy - b) * 2 + 1; + int b2 = x + (ShortOne - w) / 2; + for(cx = b2; cx < b2 + w; cx++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = y + LongOne; + for(cy = b; cy < b + (ShortOne - 1) / 2; cy++) { + int w = ((ShortOne - 1) / 2 - 1 - (cy - b)) * 2 + 1; + int b2 = x + (ShortOne - w) / 2; + for(cx = b2; cx < b2 + w; cx++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } +} + +static void draw_h(unsigned char* raw, int x, int y, int stride, MwLLColor text) { + int cy, cx, b; + for(cx = x; cx < x + LongOne; cx++) { + for(cy = y; cy < y + ShortOne; cy++) { + unsigned char* px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = x - (ShortOne - 1) / 2; + for(cx = b; cx < b + (ShortOne - 1) / 2; cx++) { + int w = (cx - b) * 2 + 1; + int b2 = y + (ShortOne - w) / 2; + for(cy = b2; cy < b2 + w; cy++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = x + LongOne; + for(cx = b; cx < b + (ShortOne - 1) / 2; cx++) { + int w = ((ShortOne - 1) / 2 - 1 - (cx - b)) * 2 + 1; + int b2 = y + (ShortOne - w) / 2; + for(cy = b2; cy < b2 + w; cy++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } +} + static void draw(MwWidget handle) { MwRect r; MwPoint p; @@ -16,6 +122,7 @@ static void draw(MwWidget handle) { int align; const char* str = MwGetText(handle, MwNtext); MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + MwLabel lab = handle->internal; if(str == NULL) str = ""; @@ -28,40 +135,206 @@ static void draw(MwWidget handle) { if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); align = MwGetInteger(handle, MwNalignment); - if(align == MwALIGNMENT_CENTER) { - p.x = r.width / 2; - } else if(align == MwALIGNMENT_BEGINNING) { - p.x = MwTextWidth(handle, str) / 2; - } else if(align == MwALIGNMENT_END) { - p.x = r.width - MwTextWidth(handle, str) / 2; + if(MwGetInteger(handle, MwNsevenSegment)) { + MwLLPixmap px; + unsigned char* raw; + int w = 0, h = ShortOne * 3 + LongOne * 2, i; + int x = 0; + + /* so - this mode cannot do unicode. + * but you wouldn't show unicode on 7 segment anyways + */ + + /* L + * S <---> + * + * S + * ^ + * | + * L | + * | + * v + */ + + for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { + if(i > 0 && ((hmgeti(lab->segment, i) != -1) || str[i] != '.')) w += Spacing; + if(hmgeti(lab->segment, i) != -1 || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { + w += LongOne + ShortOne * 2; + } else if(str[i] == ':' || str[i] == ' ') { + w += ShortOne; + } + } + + raw = malloc(w * h * 4); + memset(raw, 0, w * h * 4); + + for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { + if((hmgeti(lab->segment, i) != -1) || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { + int la = 0, lb = 0, lc = 0, ld = 0, le = 0, lf = 0, lg = 0; + + /* https://en.wikipedia.org/wiki/File:7_Segment_Display_with_Labeled_Segments.svg */ + + if(hmgeti(lab->segment, i) != -1) { + unsigned char c = hmget(lab->segment, i); + + if(c & (1 << 0)) la = 1; + if(c & (1 << 1)) lb = 1; + if(c & (1 << 2)) lc = 1; + if(c & (1 << 3)) ld = 1; + if(c & (1 << 4)) le = 1; + if(c & (1 << 5)) lf = 1; + if(c & (1 << 6)) lg = 1; + } else { + if(str[i] == '0') { + la = lb = lc = ld = le = lf = 1; + } else if(str[i] == '1') { + lb = lc = 1; + } else if(str[i] == '2') { + la = lb = ld = le = lg = 1; + } else if(str[i] == '3') { + la = lb = lc = ld = lg = 1; + } else if(str[i] == '4') { + lb = lc = lf = lg = 1; + } else if(str[i] == '5') { + la = lc = ld = lf = lg = 1; + } else if(str[i] == '6') { + la = lc = ld = le = lf = lg = 1; + } else if(str[i] == '7') { + la = lb = lc = 1; + } else if(str[i] == '8') { + la = lb = lc = ld = le = lf = lg = 1; + } else if(str[i] == '9') { + la = lb = lc = ld = lf = lg = 1; + } else if(str[i] == 'A' || str[i] == 'a') { + la = lb = lc = le = lf = lg = 1; + } else if(str[i] == 'B' || str[i] == 'b') { + lc = ld = le = lf = lg = 1; + } else if(str[i] == 'C' || str[i] == 'c') { + ld = le = lg = 1; + } else if(str[i] == 'D' || str[i] == 'd') { + lb = lc = ld = le = lg = 1; + } else if(str[i] == 'E' || str[i] == 'e') { + la = ld = le = lf = lg = 1; + } else if(str[i] == 'F' || str[i] == 'f') { + la = le = lf = lg = 1; + } + } + + if(la) draw_h(raw, x + ShortOne, 0, w, text); + if(lb) draw_v(raw, x + ShortOne + LongOne, ShortOne, w, text); + if(lc) draw_v(raw, x + ShortOne + LongOne, ShortOne * 2 + LongOne, w, text); + if(ld) draw_h(raw, x + ShortOne, ShortOne * 2 + LongOne * 2, w, text); + if(le) draw_v(raw, x, ShortOne * 2 + LongOne, w, text); + if(lf) draw_v(raw, x, ShortOne, w, text); + if(lg) draw_h(raw, x + ShortOne, ShortOne + LongOne, w, text); + + x += LongOne + ShortOne * 2; + } else if(str[i] == ':') { + int cy, cx; + for(cy = 1; cy < h - 1; cy++) { + int c = (LongOne - ShortOne) / 2 + ShortOne; + + int c1 = (c <= cy && cy <= (c + ShortOne)) ? 1 : 0; + int c2 = ((ShortOne + LongOne + c) <= cy && cy <= (ShortOne + LongOne + c + ShortOne)) ? 1 : 0; + + if(c1 || c2) { + for(cx = x; cx < x + ShortOne; cx++) { + unsigned char* px = &raw[(cy * w + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + } + x += ShortOne; + } else if(str[i] == ' ') { + x += ShortOne; + } else if(str[i] == '.') { + int cy, cx; + for(cy = h - (ShortOne - 1) / 2 - 1; cy < h; cy++) { + for(cx = x - Spacing - (ShortOne - 1) / 2 - 1; cx < (x - Spacing); cx++) { + unsigned char* px = &raw[(cy * w + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + continue; + } + + x += Spacing; + } + + px = MwLoadRaw(handle, raw, w, h); + + r.y = 0; + r.height = h; + if(align == MwALIGNMENT_CENTER) { + r.x = (r.width - w) / 2; + } else if(align == MwALIGNMENT_BEGINNING) { + r.x = 0; + } else if(align == MwALIGNMENT_END) { + r.x = r.width - w; + } + r.width = w; + MwLLDrawPixmap(handle->lowlevel, &r, px); + + MwLLDestroyPixmap(px); + } else { + if(align == MwALIGNMENT_CENTER) { + p.x = r.width / 2; + } else if(align == MwALIGNMENT_BEGINNING) { + p.x = MwTextWidth(handle, str) / 2; + } else if(align == MwALIGNMENT_END) { + p.x = r.width - MwTextWidth(handle, str) / 2; + } + p.y = r.height / 2; + MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, text); } - p.y = r.height / 2; - MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, text); MwLLFreeColor(text); MwLLFreeColor(base); } static void prop_change(MwWidget handle, const char* key) { - if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0) MwForceRender(handle); + if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0 || strcmp(key, MwNsevenSegment) == 0) MwForceRender(handle); +} + +static void mwLabelSetSevenSegmentImpl(MwWidget handle, int index, unsigned char data) { + MwLabel lab = handle->internal; + + hmput(lab->segment, index, data); +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + (void)out; + + if(strcmp(name, "mwLabelSetSevenSegment") == 0) { + int index = va_arg(va, int); + int data = va_arg(va, int); + + mwLabelSetSevenSegmentImpl(handle, index, data); + } } MwClassRec MwLabelClassRec = { - create, /* create */ - NULL, /* destroy */ - draw, /* draw */ - NULL, /* click */ - NULL, /* parent_resize */ - prop_change, /* prop_change */ - NULL, /* mouse_move */ - NULL, /* mouse_up */ - NULL, /* mouse_down */ - NULL, /* key */ - NULL, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ + create, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ NULL, NULL, NULL, diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index 254e05b..ff42d3a 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -1,13 +1,7 @@ #include -typedef struct scrollbar { - MwPoint point; - int drag; - int pos; -} scrollbar_t; - static int create(MwWidget handle) { - scrollbar_t* scr = malloc(sizeof(*scr)); + MwScrollBar scr = malloc(sizeof(*scr)); handle->internal = scr; @@ -60,10 +54,10 @@ static void add_value(MwWidget handle, int mul) { } static void draw(MwWidget handle) { - MwRect r, rt, rbar; - MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwLLColor dark = MwLightenColor(handle, base, -64, -64, -64); - scrollbar_t* scr = handle->internal; + MwRect r, rt, rbar; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor dark = MwLightenColor(handle, base, -64, -64, -64); + MwScrollBar scr = handle->internal; int or ; int uy, dy, ux, dx; MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); @@ -144,8 +138,8 @@ static void draw(MwWidget handle) { } static void mouse_move(MwWidget handle) { - int or = MwGetInteger(handle, MwNorientation); - scrollbar_t* scr = handle->internal; + int or = MwGetInteger(handle, MwNorientation); + MwScrollBar scr = handle->internal; if(!handle->pressed) return; @@ -172,11 +166,11 @@ static void mouse_move(MwWidget handle) { } static void mouse_down(MwWidget handle, void* ptr) { - int ww = MwGetInteger(handle, MwNwidth); - int wh = MwGetInteger(handle, MwNheight); - int or = MwGetInteger(handle, MwNorientation); - scrollbar_t* scr = handle->internal; - MwLLMouse* m = ptr; + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight); + int or = MwGetInteger(handle, MwNorientation); + MwScrollBar scr = handle->internal; + MwLLMouse* m = ptr; if(m->button == MwLLMouseWheelUp) { int min = MwGetInteger(handle, MwNminValue);