#include #include "../../external/stb_ds.h" #define Spacing 1 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); MwSetInteger(handle, MwNlength, 4); return 0; } static void destroy(MwWidget handle) { MwLabel lab = handle->internal; hmfree(lab->segment); free(handle->internal); } static void draw_v(MwWidget handle, unsigned char* raw, int x, int y, int stride, MwLLColor text) { int cy, cx, b; int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; for(cy = y; cy < y + l_one; cy++) { for(cx = x; cx < x + s_one; 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 - (s_one - 1) / 2; for(cy = b; cy < b + (s_one - 1) / 2; cy++) { int w = (cy - b) * 2 + 1; int b2 = x + (s_one - 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 + l_one; for(cy = b; cy < b + (s_one - 1) / 2; cy++) { int w = ((s_one - 1) / 2 - 1 - (cy - b)) * 2 + 1; int b2 = x + (s_one - 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(MwWidget handle, unsigned char* raw, int x, int y, int stride, MwLLColor text) { int cy, cx, b; int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; for(cx = x; cx < x + l_one; cx++) { for(cy = y; cy < y + s_one; 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 - (s_one - 1) / 2; for(cx = b; cx < b + (s_one - 1) / 2; cx++) { int w = (cx - b) * 2 + 1; int b2 = y + (s_one - 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 + l_one; for(cx = b; cx < b + (s_one - 1) / 2; cx++) { int w = ((s_one - 1) / 2 - 1 - (cx - b)) * 2 + 1; int b2 = y + (s_one - 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; MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); MwLLColor shadow = MwLightenColor(handle, base, MwDefaultShadow, MwDefaultShadow, MwDefaultShadow); int align; const char* str = MwGetText(handle, MwNtext); MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); MwLabel lab = handle->internal; int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; if(str == NULL) str = ""; r.x = 0; r.y = 0; r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); MwDrawRect(handle, &r, base); if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); align = MwGetInteger(handle, MwNalignment); if(MwGetInteger(handle, MwNsevenSegment)) { MwLLPixmap px; unsigned char* raw; int w = 0, h = s_one * 3 + l_one * 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 += l_one + s_one * 2; } else if(str[i] == ':' || str[i] == ' ') { w += s_one; } } w++; h++; 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; int j; /* 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; } } for(j = 1; j >= 0; j--) { MwLLColor cl = j == 1 ? shadow : text; if(la) draw_h(handle, raw, x + s_one + j, j, w, cl); if(lb) draw_v(handle, raw, x + s_one + l_one + j, s_one + j, w, cl); if(lc) draw_v(handle, raw, x + s_one + l_one + j, s_one * 2 + l_one + j, w, cl); if(ld) draw_h(handle, raw, x + s_one + j, s_one * 2 + l_one * 2 + j, w, cl); if(le) draw_v(handle, raw, x + j, s_one * 2 + l_one + j, w, cl); if(lf) draw_v(handle, raw, x + j, s_one + j, w, cl); if(lg) draw_h(handle, raw, x + s_one + j, s_one + l_one + j, w, cl); } x += l_one + s_one * 2; } else if(str[i] == ':') { int cy, cx; int j; for(j = 1; j >= 0; j--) { MwLLColor cl = j == 1 ? shadow : text; for(cy = 1; cy < h - 1; cy++) { int c = (l_one - s_one) / 2 + s_one; int c1 = (c <= cy && cy <= (c + s_one)) ? 1 : 0; int c2 = ((s_one + l_one + c) <= cy && cy <= (s_one + l_one + c + s_one)) ? 1 : 0; if(c1 || c2) { for(cx = x; cx < x + s_one; cx++) { unsigned char* px = &raw[((cy + j) * w + (cx + j)) * 4]; px[0] = cl->common.red; px[1] = cl->common.green; px[2] = cl->common.blue; px[3] = 255; } } } } x += s_one; } else if(str[i] == ' ') { x += s_one; } else if(str[i] == '.') { int cy, cx; int j; for(j = 1; j >= 0; j--) { MwLLColor cl = j == 1 ? shadow : text; for(cy = h - (s_one - 1) / 2 - 1; cy < h; cy++) { for(cx = x - Spacing - (s_one - 1) / 2 - 1; cx < (x - Spacing); cx++) { unsigned char* px = &raw[((cy + j) * w + (cx + j)) * 4]; px[0] = cl->common.red; px[1] = cl->common.green; px[2] = cl->common.blue; px[3] = 255; } } } continue; } x += Spacing; } px = MwLoadRaw(handle, raw, w, h); r.y = (r.height - h) / 2; 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; p.x += 1; p.y += 1; MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, shadow); p.x -= 1; p.y -= 1; MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, text); } MwLLFreeColor(shadow); MwLLFreeColor(text); MwLLFreeColor(base); } static void prop_change(MwWidget handle, const char* key) { 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 */ 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, NULL, NULL}; MwClass MwLabelClass = &MwLabelClassRec;