diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index db833c67c..e40994d90 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -269,12 +269,17 @@ int main() { wclock = child(f); f = frame("Chart", -PaddingContent, -PaddingContent, MwChartClass, + MwNtype, MwCHART_3D_BAR, + MwNcolumnSpan, 2, NULL); w = child(f); - MwChartAdd(w, -1, "A", -100, NULL); - MwChartAdd(w, -1, "B", 100, NULL); - MwChartAdd(w, -1, "C", 200, NULL); - MwChartAdd(w, -1, "D", 300, NULL); + MwChartAdd(w, -1, "A", -400, NULL); + MwChartAdd(w, -1, "B", -200, NULL); + MwChartAdd(w, -1, "C", -100, NULL); + MwChartAdd(w, -1, "D", 100, NULL); + MwChartAdd(w, -1, "E", 200, NULL); + MwChartAdd(w, -1, "F", 400, NULL); + MwChartAdd(w, -1, "G", 800, NULL); f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL); w = child(f); @@ -288,6 +293,7 @@ int main() { f = frame("Label", -PaddingContent, -PaddingContent, MwLabelClass, MwNtext, "Epic text\nNewline can be used too!", + MwNcolumnSpan, 2, NULL); f = frame("ListBox", -PaddingContent, -PaddingContent, MwListBoxClass, @@ -321,9 +327,7 @@ int main() { MwNtitle, "Sub window 2", NULL); - f = frame("Tab", -PaddingContent, -PaddingContent, MwTabClass, - MwNcolumnSpan, 2, - NULL); + f = frame("Tab", -PaddingContent, -PaddingContent, MwTabClass, NULL); w = child(f); MwSetText(MwTabAdd(w, "ABC"), MwNbackground, "#f00"); MwSetText(MwTabAdd(w, "DEF"), MwNbackground, "#0f0"); diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index ad29792ef..6df447d43 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -114,7 +114,8 @@ enum MwCLIPBOARD { }; enum MwCHART { - MwCHART_BAR = 0 + MwCHART_BAR = 0, + MwCHART_3D_BAR, }; enum MwMOUSE { diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index e3c6991f1..ad13c6032 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -52,6 +52,13 @@ MWDECL void MWAPI MwColorTableInit(void); */ MWDECL MwLLColor MWAPI MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b); +/*! + * @brief Fix a rectangle + * @param handle Widget + * @param rect Rectangle area + */ +MWDECL void MWAPI MwFixRect(MwRect* rect); + /*! * @brief Draws a filled rectangle * @param handle Widget diff --git a/milsko.xml b/milsko.xml index 30efce111..6bf802b01 100644 --- a/milsko.xml +++ b/milsko.xml @@ -232,6 +232,7 @@ 0 + 1 @@ -657,6 +658,8 @@ + + diff --git a/src/core.c b/src/core.c index 2982c1ed9..481fa340f 100644 --- a/src/core.c +++ b/src/core.c @@ -5,7 +5,7 @@ #ifdef USE_COCOA #define PERIODIC #endif -#define USE_CLASSIC_THEME +// #define USE_CLASSIC_THEME #define RESIZE_ON_TICK #define DRAW(handle) \ diff --git a/src/draw.c b/src/draw.c index 5cbfd22b0..eb15c76ba 100644 --- a/src/draw.c +++ b/src/draw.c @@ -99,19 +99,23 @@ MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b) return MwLLAllocColor(handle->lowlevel, cr, cg, cb); } +void MwFixRect(MwRect* rect) { + if(rect->width < 0) { + rect->width *= -1; + rect->x -= rect->width; + } + + if(rect->height < 0) { + rect->height *= -1; + rect->y -= rect->height; + } +} + void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { MwPoint p[4]; MwRect r = *rect; - if(r.width < 0) { - r.width *= -1; - r.x -= r.width; - } - - if(r.height < 0) { - r.height *= -1; - r.y -= r.height; - } + MwFixRect(&r); p[0].x = r.x; p[0].y = r.y; @@ -132,15 +136,7 @@ void MwDrawRectLine(MwWidget handle, MwRect* rect, MwLLColor color) { MwPoint p[5]; MwRect r = *rect; - if(r.width < 0) { - r.width *= -1; - r.x -= r.width; - } - - if(r.height < 0) { - r.height *= -1; - r.y -= r.height; - } + MwFixRect(&r); p[0].x = r.x; p[0].y = r.y; diff --git a/src/widget/chart.c b/src/widget/chart.c index b01451383..34d8f4e28 100644 --- a/src/widget/chart.c +++ b/src/widget/chart.c @@ -27,6 +27,8 @@ static int wcreate(MwWidget handle) { MwSetDefault(handle); + MwSetInteger(handle, MwNtype, MwCHART_BAR); + return 0; } @@ -35,6 +37,35 @@ static void destroy(MwWidget handle) { free(handle->internal); } +static void draw_line(MwWidget handle, const char* text, double x, double y, double width, double height, MwLLColor color) { + MwPoint p[2]; + int type = MwGetInteger(handle, MwNtype); + + p[0].x = x; + p[0].y = y; + + p[1].x = x + width; + p[1].y = p[0].y; + MwDrawText(handle, NULL, p, text, MwALIGNMENT_END, color); + + if(type == MwCHART_3D_BAR) { + MwPoint p2[2]; + + p2[0] = p[0]; + p2[1] = p[0]; + + p2[1].x += height; + p2[1].y -= height; + + MwLLLine(handle->lowlevel, &p2[0], color); + + p[0].x += height; + p[0].y -= height; + p[1].y -= height; + } + MwLLLine(handle->lowlevel, &p[0], color); +} + static void draw(MwWidget handle) { MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); MwLLColor border = MwParseColor(handle, MwGetText(handle, MwNforeground)); @@ -46,75 +77,162 @@ static void draw(MwWidget handle) { int gap; int width; MwRect node; - double min = 0xffffffff; - double max = -0xffffffff; + double vmin = 0xffffffff; + double vmax = -0xffffffff; int space = MwTextHeight(handle, NULL, "M"); MwPoint p[2]; + int type = MwGetInteger(handle, MwNtype); for(n = 0; colors[n] != NULL; n++); for(i = 0; i < arrlen(c->entries); i++) { - if(min > c->entries[i].value) min = c->entries[i].value; - if(max < c->entries[i].value) max = c->entries[i].value; + if(vmin > c->entries[i].value) vmin = c->entries[i].value; + if(vmax < c->entries[i].value) vmax = c->entries[i].value; } + if(MwGetInteger(handle, MwNminValue) != MwDEFAULT) vmin = MwGetInteger(handle, MwNminValue); + if(MwGetInteger(handle, MwNmaxValue) != MwDEFAULT) vmax = MwGetInteger(handle, MwNmaxValue); + r.x = 0; r.y = 0; r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); MwDrawRect(handle, &r, base); - if(min > 0) { - min = 0; - } else if(min < 0) { - min -= r.height / 10; - } + if(type == MwCHART_BAR || type == MwCHART_3D_BAR) { + double s = 1.5; + double ovmin = vmin; + double ovmax = vmax; + double twidth; + char buf[128]; - node.x = 16; - node.y = 0; + node.x = 128; + node.y = 0; - width = (r.width - node.x) * 2 / (arrlen(c->entries) * 3 + 1); - gap = width / 2; + width = (r.width - node.x) * s / (arrlen(c->entries) * (1 + s) + 1); + gap = width / s; - p[0].x = node.x; - p[0].y = r.height - space; + twidth = (width + gap) * arrlen(c->entries) + gap; - p[1].x = node.x + (width + gap) * arrlen(c->entries) + gap; - p[1].y = p[0].y; - MwLLLine(handle->lowlevel, &p[0], border); + if(vmin > 0) { + vmin = 0; + } else if(vmin < 0) { + vmin -= (double)width / r.height * (vmax - vmin); + } - p[0].y = r.height - space - abs(min / (max - min) * (r.height - space)); - p[1].y = p[0].y; - MwLLLine(handle->lowlevel, &p[0], border); - MwDrawText(handle, NULL, p, "0", MwALIGNMENT_END, border); + if(vmax < 0) { + vmax = 0; + } else if(vmax > 0) { + vmax += (double)width / r.height * (vmax - vmin); + } - p[0].x = node.x; - p[0].y = 0; + sprintf(buf, "%.2f", ovmax); + draw_line(handle, buf, node.x, (r.height - space) - (ovmax - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - p[1].x = node.x; - p[1].y = r.height - space; - MwLLLine(handle->lowlevel, &p[0], border); + draw_line(handle, "0", node.x, (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - node.width = width; - for(i = 0; i < arrlen(c->entries); i++) { - MwLLColor color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + sprintf(buf, "%.2f", ovmin); + draw_line(handle, buf, node.x, (r.height - space) - (ovmin - vmin) / (vmax - vmin) * (r.height - space), twidth, width / 2, border); - node.x += gap; + p[0].x = node.x; + p[0].y = 0; - node.height = c->entries[i].value / (max - min) * (r.height - space); - node.y = r.height - space - node.height - abs(min / (max - min) * (r.height - space)); + p[1].x = node.x; + p[1].y = r.height - space; + MwLLLine(handle->lowlevel, &p[0], border); - MwDrawRect(handle, &node, color); - MwDrawRectLine(handle, &node, border); + p[0].x = node.x; + p[0].y = r.height - space; - p[0].x = node.x + node.width / 2; - p[0].y = r.height - space / 2; + p[1].x = node.x + twidth; + p[1].y = p[0].y; + MwLLLine(handle->lowlevel, &p[0], border); - MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); + node.width = width; + for(i = 0; i < arrlen(c->entries); i++) { + int ColorDiff = MwGetColorDifference(handle); + MwLLColor color = MwParseColor(handle, c->entries[i].color == NULL ? colors[i % n] : c->entries[i].color); + MwLLColor colorl = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); + MwLLColor colord = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); + MwPoint persp_top[5]; + MwPoint persp_right[5]; - node.x += node.width; + node.x += gap; - MwLLFreeColor(color); + node.height = -c->entries[i].value / (vmax - vmin) * (r.height - space); + node.y = (r.height - space) - (0 - vmin) / (vmax - vmin) * (r.height - space); + + MwDrawRect(handle, &node, color); + + if(type == MwCHART_3D_BAR) { + MwRect node2 = node; + + MwFixRect(&node2); + + persp_top[0] = *(MwPoint*)&node2; + persp_top[1] = *(MwPoint*)&node2; + persp_top[1].x += node2.width; + + persp_top[2] = persp_top[1]; + persp_top[3] = persp_top[0]; + + persp_top[2].x += node2.width / 2; + persp_top[2].y -= node2.width / 2; + + persp_top[3].x += node2.width / 2; + persp_top[3].y -= node2.width / 2; + + persp_top[4] = persp_top[0]; + + MwLLPolygon(handle->lowlevel, persp_top, 4, colorl); + + persp_right[0] = *(MwPoint*)&node2; + persp_right[1] = *(MwPoint*)&node2; + persp_right[0].x += node2.width; + persp_right[1].x += node2.width; + persp_right[1].y += node2.height; + + persp_right[2] = persp_right[1]; + persp_right[3] = persp_right[0]; + + persp_right[2].x += node2.width / 2; + persp_right[2].y -= node2.width / 2; + + persp_right[3].x += node2.width / 2; + persp_right[3].y -= node2.width / 2; + + persp_right[4] = persp_right[0]; + + MwLLPolygon(handle->lowlevel, persp_right, 4, colord); + } + + if(!MwGetInteger(handle, MwNmodernLook)) { + MwDrawRectLine(handle, &node, border); + + if(type == MwCHART_3D_BAR) { + MwLLLine(handle->lowlevel, &persp_top[0], border); + MwLLLine(handle->lowlevel, &persp_top[1], border); + MwLLLine(handle->lowlevel, &persp_top[2], border); + MwLLLine(handle->lowlevel, &persp_top[3], border); + + MwLLLine(handle->lowlevel, &persp_right[0], border); + MwLLLine(handle->lowlevel, &persp_right[1], border); + MwLLLine(handle->lowlevel, &persp_right[2], border); + MwLLLine(handle->lowlevel, &persp_right[3], border); + } + } + + p[0].x = node.x + node.width / 2; + p[0].y = r.height - space / 2; + + MwDrawText(handle, NULL, p, c->entries[i].name, MwALIGNMENT_CENTER, border); + + node.x += node.width; + + MwLLFreeColor(colord); + MwLLFreeColor(colorl); + MwLLFreeColor(color); + } } MwLLFreeColor(border);