bar chart

This commit is contained in:
Nishi 2026-09-14 01:09:57 +09:00
commit 120eb5baaf
14 changed files with 405 additions and 44 deletions

View file

@ -270,6 +270,11 @@ int main() {
f = frame("Chart", -PaddingContent, -PaddingContent, MwChartClass,
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);
f = frame("ComboBox", -PaddingContent, 24, MwComboBoxClass, NULL);
w = child(f);

View file

@ -113,6 +113,10 @@ enum MwCLIPBOARD {
MwCLIPBOARD_PRIMARY,
};
enum MwCHART {
MwCHART_BAR = 0
};
enum MwMOUSE {
MwMOUSE_LEFT = 1,
MwMOUSE_MIDDLE,

View file

@ -60,6 +60,14 @@ MWDECL MwLLColor MWAPI MwLightenColor(MwWidget handle, MwLLColor color, int r, i
*/
MWDECL void MWAPI MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color);
/*!
* @brief Draws a rectangle
* @param handle Widget
* @param rect Rectangle area
* @param color Color
*/
MWDECL void MWAPI MwDrawRectLine(MwWidget handle, MwRect* rect, MwLLColor color);
/*!
* @brief Draws a filled rectangle that fades to a darker color
* @param handle Widget

View file

@ -57,6 +57,7 @@
#define MwNhour "Ihour"
#define MwNminute "Iminute"
#define MwNsecond "Isecond"
#define MwNtype "Itype"
#define MwNtitle "Stitle"
#define MwNtext "Stext"

View file

@ -30,6 +30,8 @@ typedef struct _MwBox* MwBox;
typedef struct _MwSubWindow* MwSubWindow;
typedef struct _MwTab* MwTab;
typedef struct _MwTable* MwTable;
typedef struct _MwChartEntry MwChartEntry;
typedef struct _MwChart* MwChart;
typedef struct _MwMouse MwMouse;
typedef struct _MwTTFInfo* MwTTFInfo;
#ifdef _MILSKO
@ -247,6 +249,16 @@ struct _MwTab {
char** names;
};
struct _MwChartEntry {
char* name;
char* color;
double value;
};
struct _MwChart {
MwChartEntry* entries;
};
struct _MwMouse {
MwPoint point;
int button;

View file

@ -17,6 +17,39 @@ extern "C" {
*/
MWDECL MwClass MwChartClass;
/*!
* @brief Adds the entry to the chart
* @param handle Widget
* @param index Index
* @param text Text
* @param value Value
* @return Index
*/
MwInline int MwChartAdd(MwWidget handle, int index, const char* text, double value, const char* color) {
int out;
MwVaWidgetExecute(handle, "mwChartAdd", (void*)&out, index, text, value, color);
return out;
}
/*!
* @brief Deletes item from the chart
* @param handle Widget
* @param index Index
*/
MwInline void MwChartDelete(MwWidget handle, int index) {
MwVaWidgetExecute(handle, "mwChartDelete", NULL, index);
}
/*!
* @brief Resets the chart
* @param handle Widget
*/
MwInline void MwChartReset(MwWidget handle) {
MwVaWidgetExecute(handle, "mwChartReset", NULL);
}
#ifdef __cplusplus
}
#endif

View file

@ -41,6 +41,23 @@ MwInline const char* MwComboBoxGet(MwWidget handle, int index) {
return text;
}
/*!
* @brief Deletes the entry from combobox
* @param handle Widget
* @param index Index
*/
MwInline void MwComboBoxDelete(MwWidget handle, int index) {
MwVaWidgetExecute(handle, "mwComboBoxDelete", NULL, index);
}
/*!
* @brief Resets the combobox
* @param handle Widget
*/
MwInline void MwComboBoxReset(MwWidget handle) {
MwVaWidgetExecute(handle, "mwComboBoxReset", NULL);
}
#ifdef __cplusplus
}
#endif

View file

@ -1,10 +1,11 @@
<?xml version="1.0" ?>
<!--
Basically, you have to implement 10+n types:
Basically, you have to implement 11+n types:
- Integer (int)
- Unsigned integer (unsigned int)
- Short integer (short)
- Unsigned short integer (unsigned short)
- Double (double)
- String (char*)
- Pointer (void*)
- Struct and pointer to it
@ -109,6 +110,7 @@
<integer name="hour" />
<integer name="minute" />
<integer name="second" />
<integer name="type" />
<!-- waitMS is a special property, only applies to toplevel widget -->
<integer name="waitMS" common="yes" />
@ -228,6 +230,9 @@
<integer name="MwCLIPBOARD_MAIN">0</integer>
<integer name="MwCLIPBOARD_PRIMARY" />
</enumeration>
<enumeration name="MwCHART">
<integer name="MwCHART_BAR">0</integer>
</enumeration>
<enumeration name="MwMOUSE">
<integer name="MwMOUSE_LEFT">1</integer>
<integer name="MwMOUSE_MIDDLE" />
@ -649,6 +654,29 @@
<property name="scale" />
</properties>
</widget>
<widget name="Chart">
<properties>
<property name="type" />
</properties>
<functions>
<function name="Set">
<return>
<integer />
</return>
<arguments>
<integer name="index" />
<string name="text" />
<double name="value" />
<string name="color" />
</arguments>
</function>
<function name="Delete">
<arguments>
<integer name="index" />
</arguments>
</function>
</functions>
</widget>
<widget name="CheckBox">
<properties>
<property name="checked" />
@ -879,9 +907,26 @@
</handlers>
<functions>
<function name="Add">
<integer name="index" />
<string name="text" />
<arguments>
<integer name="index" />
<string name="text" />
</arguments>
</function>
<function name="Get">
<return>
<string />
</return>
<arguments>
<integer name="index" />
<string name="text" />
</arguments>
</function>
<function name="Delete">
<arguments>
<integer name="index" />
</arguments>
</function>
<function name="Reset" />
</functions>
</widget>
<widget name="TreeView">

View file

@ -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) \

View file

@ -101,22 +101,67 @@ MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b)
void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) {
MwPoint p[4];
MwRect r = *rect;
p[0].x = rect->x;
p[0].y = rect->y;
if(r.width < 0) {
r.width *= -1;
r.x -= r.width;
}
p[1].x = rect->x + rect->width;
p[1].y = rect->y;
if(r.height < 0) {
r.height *= -1;
r.y -= r.height;
}
p[2].x = rect->x + rect->width;
p[2].y = rect->y + rect->height;
p[0].x = r.x;
p[0].y = r.y;
p[3].x = rect->x;
p[3].y = rect->y + rect->height;
p[1].x = r.x + r.width;
p[1].y = r.y;
p[2].x = r.x + r.width;
p[2].y = r.y + r.height;
p[3].x = r.x;
p[3].y = r.y + r.height;
MwLLPolygon(handle->lowlevel, p, 4, color);
}
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;
}
p[0].x = r.x;
p[0].y = r.y;
p[1].x = r.x + r.width;
p[1].y = r.y;
p[2].x = r.x + r.width;
p[2].y = r.y + r.height;
p[3].x = r.x;
p[3].y = r.y + r.height;
p[4] = p[0];
MwLLLine(handle->lowlevel, &p[0], color);
MwLLLine(handle->lowlevel, &p[1], color);
MwLLLine(handle->lowlevel, &p[2], color);
MwLLLine(handle->lowlevel, &p[3], color);
}
void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) {
MwLLPixmap pixmap;
int y;

View file

@ -1,12 +1,62 @@
#include <Mw/Milsko.h>
#include "../../external/stb_ds.h"
static const char* palette0[] = {
"#800",
"#080",
"#880",
"#008",
"#808",
"#088",
"#888",
"#f00",
"#0f0",
"#ff0",
"#00f",
"#f0f",
"#0ff",
"#fff",
NULL};
static int wcreate(MwWidget handle) {
MwChart c = malloc(sizeof(*c));
memset(c, 0, sizeof(*c));
handle->internal = c;
MwSetDefault(handle);
return 0;
}
static void destroy(MwWidget handle) {
MwChartReset(handle);
free(handle->internal);
}
static void draw(MwWidget handle) {
MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground));
MwRect r;
MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground));
MwLLColor border = MwParseColor(handle, MwGetText(handle, MwNforeground));
MwRect r;
MwChart c = handle->internal;
int i;
const char** colors = palette0;
int n;
int gap;
int width;
MwRect node;
double min = 0xffffffff;
double max = -0xffffffff;
int space = MwTextHeight(handle, NULL, "M");
MwPoint p[2];
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;
}
r.x = 0;
r.y = 0;
@ -14,31 +64,144 @@ static void draw(MwWidget handle) {
r.height = MwGetInteger(handle, MwNheight);
MwDrawRect(handle, &r, base);
if(min > 0) {
min = 0;
} else if(min < 0) {
min -= r.height / 10;
}
node.x = 16;
node.y = 0;
width = (r.width - node.x) * 2 / (arrlen(c->entries) * 3 + 1);
gap = width / 2;
p[0].x = node.x;
p[0].y = r.height - space;
p[1].x = node.x + (width + gap) * arrlen(c->entries) + gap;
p[1].y = p[0].y;
MwLLLine(handle->lowlevel, &p[0], border);
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);
p[0].x = node.x;
p[0].y = 0;
p[1].x = node.x;
p[1].y = r.height - space;
MwLLLine(handle->lowlevel, &p[0], 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);
node.x += gap;
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));
MwDrawRect(handle, &node, color);
MwDrawRectLine(handle, &node, 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(color);
}
MwLLFreeColor(border);
MwLLFreeColor(base);
}
static void prop_change(MwWidget handle, const char* key) {
if(strcmp(key, MwNhour) == 0 || strcmp(key, MwNminute) == 0 || strcmp(key, MwNsecond) == 0) MwForceRender(handle);
if(strcmp(key, MwNtype) == 0) MwForceRender(handle);
}
static int mwChartAddImpl(MwWidget handle, int index, const char* text, double value, const char* color) {
MwChart c = handle->internal;
MwChartEntry e;
if(index == -1) index = arrlen(c->entries);
e.name = MwStringDuplicate(text);
e.color = color == NULL ? NULL : MwStringDuplicate(color);
e.value = value;
arrins(c->entries, index, e);
MwForceRender(handle);
return index;
}
static void mwChartDeleteImpl(MwWidget handle, int index) {
MwChart c = handle->internal;
if(index == -1) index = arrlen(c->entries) - 1;
free(c->entries[index].name);
if(c->entries[index].color != NULL) free(c->entries[index].color);
arrdel(c->entries, index);
MwForceRender(handle);
}
static void mwChartResetImpl(MwWidget handle) {
MwChart c = handle->internal;
int i;
for(i = 0; i < arrlen(c->entries); i++) {
free(c->entries[i].name);
if(c->entries[i].color != NULL) free(c->entries[i].color);
}
arrfree(c->entries);
MwForceRender(handle);
}
static void func_handler(MwWidget handle, const char* name, void* out, va_list va) {
if(strcmp(name, "mwChartAdd") == 0) {
int index = va_arg(va, int);
const char* text = va_arg(va, const char*);
double value = va_arg(va, double);
const char* color = va_arg(va, const char*);
*(int*)out = mwChartAddImpl(handle, index, text, value, color);
}
if(strcmp(name, "mwChartDelete") == 0) {
int index = va_arg(va, int);
mwChartDeleteImpl(handle, index);
}
if(strcmp(name, "mwChartReset") == 0) {
mwChartResetImpl(handle);
}
}
MwClassRec MwChartClassRec = {
wcreate, /* 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 */
NULL, /* clipboard */
NULL, /* props_change */
wcreate, /* 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 */
MwForceRender, /* resize */
NULL, /* children_update */
NULL, /* children_prop_change */
NULL, /* clipboard */
NULL, /* props_change */
NULL,
NULL,
NULL};

View file

@ -20,12 +20,8 @@ static int wcreate(MwWidget handle) {
static void destroy(MwWidget handle) {
MwComboBox cb = handle->internal;
int i;
for(i = 0; i < arrlen(cb->list); i++) {
free(cb->list[i]);
}
arrfree(cb->list);
MwComboBoxReset(handle);
free(handle->internal);
}
@ -145,6 +141,13 @@ static void prop_change(MwWidget handle, const char* prop) {
}
}
static void parent_resize(MwWidget handle) {
MwComboBox cb = handle->internal;
if(cb->opened) {
click(handle);
}
}
static void mwComboBoxAddImpl(MwWidget handle, int index, const char* text) {
MwComboBox cb = handle->internal;
char* t = MwStringDuplicate(text);
@ -153,7 +156,7 @@ static void mwComboBoxAddImpl(MwWidget handle, int index, const char* text) {
arrins(cb->list, index, t);
if(index <= MwGetInteger(handle, MwNvalue)) MwForceRender(handle);
MwForceRender(handle);
}
static const char* mwComboBoxGetImpl(MwWidget handle, int index) {
@ -162,6 +165,29 @@ static const char* mwComboBoxGetImpl(MwWidget handle, int index) {
return cb->list[index];
}
static void mwComboBoxDeleteImpl(MwWidget handle, int index) {
MwComboBox cb = handle->internal;
int n = MwGetInteger(handle, MwNvalue);
free(cb->list[index]);
arrdel(cb->list, index);
if(index < n && n > 0) {
MwSetInteger(handle, MwNvalue, n - 1);
}
MwForceRender(handle);
}
static void mwComboBoxResetImpl(MwWidget handle) {
MwComboBox cb = handle->internal;
arrfree(cb->list);
MwSetInteger(handle, MwNvalue, 0);
MwForceRender(handle);
}
static void func_handler(MwWidget handle, const char* name, void* out, va_list va) {
if(strcmp(name, "mwComboBoxAdd") == 0) {
int index = va_arg(va, int);
@ -172,12 +198,12 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v
int index = va_arg(va, int);
*(const char**)out = mwComboBoxGetImpl(handle, index);
}
}
static void parent_resize(MwWidget handle) {
MwComboBox cb = handle->internal;
if(cb->opened) {
click(handle);
if(strcmp(name, "mwComboBoxDelete") == 0) {
int index = va_arg(va, int);
mwComboBoxDeleteImpl(handle, index);
}
if(strcmp(name, "mwComboBoxReset") == 0) {
mwComboBoxResetImpl(handle);
}
}

View file

@ -317,6 +317,7 @@ static int wcreate(MwWidget handle) {
}
static void destroy(MwWidget handle) {
MwTreeViewReset(handle);
free(handle->internal);
}

View file

@ -51,6 +51,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v
mwWindowShouldCloseImpl(handle, out);
}
}
MwClassRec MwWindowClassRec = {
wcreate, /* create */
NULL, /* destroy */