building a graph now basically works!
This commit is contained in:
@@ -353,8 +353,9 @@ int AQDG_DrawableWidget_DrawChildren(AQDG_OBJECT *object)
|
|||||||
|
|
||||||
child=AQDG_Object_Tree2_GetFirstChild(object);
|
child=AQDG_Object_Tree2_GetFirstChild(object);
|
||||||
if (child) {
|
if (child) {
|
||||||
while (child) {
|
while (child) {
|
||||||
AQDG_DrawableWidget_Draw(child);
|
if (!(AQDG_Object_GetFlags(child) & AQDG_OBJECT_FLAGS_HIDDEN))
|
||||||
|
AQDG_DrawableWidget_Draw(child);
|
||||||
child=AQDG_Object_Tree2_GetNext(child);
|
child=AQDG_Object_Tree2_GetNext(child);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
|
|
||||||
<headers dist="true" install="$(pkgincludedir)">
|
<headers dist="true" install="$(pkgincludedir)">
|
||||||
graph.h
|
graph.h
|
||||||
|
timegraph.h
|
||||||
w_graph.h
|
w_graph.h
|
||||||
w_axis.h
|
w_axis.h
|
||||||
w_xaxis.h
|
w_xaxis.h
|
||||||
@@ -97,6 +98,7 @@
|
|||||||
<sources>
|
<sources>
|
||||||
$(local/typefiles)
|
$(local/typefiles)
|
||||||
graph.c
|
graph.c
|
||||||
|
timegraph.c
|
||||||
w_graph.c
|
w_graph.c
|
||||||
w_axis.c
|
w_axis.c
|
||||||
w_xaxis.c
|
w_xaxis.c
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
<header type="sys" loc="pre">aqdiagram/aqdg_api.h</header>
|
<header type="sys" loc="pre">aqdiagram/aqdg_api.h</header>
|
||||||
<header type="sys" loc="pre">aqdiagram/graph/tick.h</header>
|
<header type="sys" loc="pre">aqdiagram/graph/tick.h</header>
|
||||||
<header type="sys" loc="pre">gwenhywfar/buffer.h</header>
|
<header type="sys" loc="pre">gwenhywfar/buffer.h</header>
|
||||||
|
<header type="sys" loc="pre">gwenhywfar/timestamp.h</header>
|
||||||
|
<header type="sys" loc="pre">gwenhywfar/gwendate.h</header>
|
||||||
<header type="sys" loc="pre">math.h</header>
|
<header type="sys" loc="pre">math.h</header>
|
||||||
</headers>
|
</headers>
|
||||||
|
|
||||||
@@ -90,7 +92,7 @@
|
|||||||
} \n
|
} \n
|
||||||
\n
|
\n
|
||||||
vRun=startValue; \n
|
vRun=startValue; \n
|
||||||
v/=10.0; \n
|
v/=2.0; \n
|
||||||
while(vRun<=(st->maxValue)) { \n
|
while(vRun<=(st->maxValue)) { \n
|
||||||
if (vRun>=(st->minValue)) { \n
|
if (vRun>=(st->minValue)) { \n
|
||||||
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n
|
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n
|
||||||
@@ -130,6 +132,214 @@
|
|||||||
</content>
|
</content>
|
||||||
</inline>
|
</inline>
|
||||||
|
|
||||||
|
|
||||||
|
<inline loc="end" access="public">
|
||||||
|
<content>
|
||||||
|
$(api) void $(struct_prefix)_GenHourTicks($(struct_type) *st, int lvl);
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
<inline loc="code">
|
||||||
|
<content>
|
||||||
|
void $(struct_prefix)_GenHourTicks($(struct_type) *st, int lvl) \n
|
||||||
|
{ \n
|
||||||
|
double minValue; \n
|
||||||
|
double maxValue; \n
|
||||||
|
double endTime; \n
|
||||||
|
GWEN_BUFFER *dbuf; \n
|
||||||
|
GWEN_TIMESTAMP *ts; \n
|
||||||
|
\n
|
||||||
|
maxValue=st->maxValue; \n
|
||||||
|
ts=GWEN_Timestamp_fromLocalTime(maxValue); \n
|
||||||
|
GWEN_Timestamp_SetTime(ts, GWEN_Timestamp_GetHour(ts), 0, 0); \n
|
||||||
|
GWEN_Timestamp_AddSeconds(ts, 60*60); \n
|
||||||
|
endTime=GWEN_Timestamp_toTimeT(ts); \n
|
||||||
|
GWEN_Timestamp_free(ts); \n
|
||||||
|
\n
|
||||||
|
minValue=st->minValue; \n
|
||||||
|
ts=GWEN_Timestamp_fromLocalTime(minValue); \n
|
||||||
|
GWEN_Timestamp_SetTime(ts, GWEN_Timestamp_GetHour(ts), 0, 0); \n
|
||||||
|
\n
|
||||||
|
dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n
|
||||||
|
while(1) { \n
|
||||||
|
double v; \n
|
||||||
|
\n
|
||||||
|
v=GWEN_Timestamp_toTimeT(ts); \n
|
||||||
|
if (v>=minValue && v<endTime) { \n
|
||||||
|
GWEN_Buffer_AppendArgs(dbuf, \n
|
||||||
|
"%02d:%02d", \n
|
||||||
|
GWEN_Timestamp_GetHour(ts), \n
|
||||||
|
GWEN_Timestamp_GetMinute(ts)); \n
|
||||||
|
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), v, lvl, 0); \n
|
||||||
|
GWEN_Buffer_Reset(dbuf); \n
|
||||||
|
} \n
|
||||||
|
GWEN_Timestamp_AddSeconds(ts, 60*60); \n
|
||||||
|
if (v>=endTime) \n
|
||||||
|
break; \n
|
||||||
|
} \n
|
||||||
|
GWEN_Buffer_free(dbuf); \n
|
||||||
|
GWEN_Timestamp_free(ts); \n
|
||||||
|
} \n
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
|
||||||
|
<inline loc="end" access="public">
|
||||||
|
<content>
|
||||||
|
$(api) void $(struct_prefix)_GenDayTicks($(struct_type) *st, int lvl);
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
<inline loc="code">
|
||||||
|
<content>
|
||||||
|
void $(struct_prefix)_GenDayTicks($(struct_type) *st, int lvl) \n
|
||||||
|
{ \n
|
||||||
|
double minValue; \n
|
||||||
|
double maxValue; \n
|
||||||
|
double endTime; \n
|
||||||
|
GWEN_BUFFER *dbuf; \n
|
||||||
|
GWEN_TIMESTAMP *ts; \n
|
||||||
|
\n
|
||||||
|
maxValue=st->maxValue; \n
|
||||||
|
ts=GWEN_Timestamp_fromLocalTime(maxValue); \n
|
||||||
|
GWEN_Timestamp_SetTime(ts, 0, 0, 0); \n
|
||||||
|
GWEN_Timestamp_AddSeconds(ts, 24*60*60); \n
|
||||||
|
endTime=GWEN_Timestamp_toTimeT(ts); \n
|
||||||
|
GWEN_Timestamp_free(ts); \n
|
||||||
|
\n
|
||||||
|
minValue=st->minValue; \n
|
||||||
|
ts=GWEN_Timestamp_fromLocalTime(minValue); \n
|
||||||
|
GWEN_Timestamp_SetTime(ts, 0, 0, 0); \n
|
||||||
|
\n
|
||||||
|
dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n
|
||||||
|
while(1) { \n
|
||||||
|
double v; \n
|
||||||
|
\n
|
||||||
|
v=GWEN_Timestamp_toTimeT(ts); \n
|
||||||
|
if (v>=minValue && v<endTime) { \n
|
||||||
|
GWEN_Buffer_AppendArgs(dbuf, \n
|
||||||
|
"%04d/%02d/%02d", \n
|
||||||
|
GWEN_Timestamp_GetYear(ts), \n
|
||||||
|
GWEN_Timestamp_GetMonth(ts), \n
|
||||||
|
GWEN_Timestamp_GetDay(ts)); \n
|
||||||
|
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), v, lvl, 0); \n
|
||||||
|
GWEN_Buffer_Reset(dbuf); \n
|
||||||
|
} \n
|
||||||
|
GWEN_Timestamp_AddSeconds(ts, 24*60*60); \n
|
||||||
|
if (v>=endTime) \n
|
||||||
|
break; \n
|
||||||
|
} \n
|
||||||
|
GWEN_Buffer_free(dbuf); \n
|
||||||
|
GWEN_Timestamp_free(ts); \n
|
||||||
|
} \n
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<inline loc="end" access="public">
|
||||||
|
<content>
|
||||||
|
$(api) void $(struct_prefix)_GenWeekTicks($(struct_type) *st, int lvl);
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
<inline loc="code">
|
||||||
|
<content>
|
||||||
|
void $(struct_prefix)_GenWeekTicks($(struct_type) *st, int lvl) \n
|
||||||
|
{ \n
|
||||||
|
double minValue; \n
|
||||||
|
double maxValue; \n
|
||||||
|
double endTime; \n
|
||||||
|
GWEN_BUFFER *dbuf; \n
|
||||||
|
GWEN_TIMESTAMP *ts; \n
|
||||||
|
\n
|
||||||
|
maxValue=st->maxValue; \n
|
||||||
|
ts=GWEN_Timestamp_fromLocalTime(maxValue); \n
|
||||||
|
GWEN_Timestamp_SetTime(ts, 0, 0, 0); \n
|
||||||
|
GWEN_Timestamp_AddSeconds(ts, 24*60*60); \n
|
||||||
|
endTime=GWEN_Timestamp_toTimeT(ts); \n
|
||||||
|
GWEN_Timestamp_free(ts); \n
|
||||||
|
\n
|
||||||
|
minValue=st->minValue; \n
|
||||||
|
ts=GWEN_Timestamp_fromLocalTime(minValue); \n
|
||||||
|
GWEN_Timestamp_SetTime(ts, 0, 0, 0); \n
|
||||||
|
GWEN_Timestamp_AddSeconds(ts, -GWEN_Timestamp_GetWeekDay(ts)*24*60*60); \n
|
||||||
|
\n
|
||||||
|
dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n
|
||||||
|
while(1) { \n
|
||||||
|
double v; \n
|
||||||
|
\n
|
||||||
|
v=GWEN_Timestamp_toTimeT(ts); \n
|
||||||
|
if (v>=minValue && v<endTime) { \n
|
||||||
|
GWEN_Buffer_AppendArgs(dbuf, \n
|
||||||
|
"%04d/%02d/%02d", \n
|
||||||
|
GWEN_Timestamp_GetYear(ts), \n
|
||||||
|
GWEN_Timestamp_GetMonth(ts), \n
|
||||||
|
GWEN_Timestamp_GetDay(ts)); \n
|
||||||
|
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), v, lvl, 0); \n
|
||||||
|
GWEN_Buffer_Reset(dbuf); \n
|
||||||
|
} \n
|
||||||
|
GWEN_Timestamp_AddSeconds(ts, 7*24*60*60); \n
|
||||||
|
if (v>=endTime) \n
|
||||||
|
break; \n
|
||||||
|
} \n
|
||||||
|
GWEN_Buffer_free(dbuf); \n
|
||||||
|
GWEN_Timestamp_free(ts); \n
|
||||||
|
} \n
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
|
||||||
|
<inline loc="end" access="public">
|
||||||
|
<content>
|
||||||
|
$(api) void $(struct_prefix)_GenMonthTicks($(struct_type) *st, int lvl);
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
<inline loc="code">
|
||||||
|
<content>
|
||||||
|
void $(struct_prefix)_GenMonthTicks($(struct_type) *st, int lvl) \n
|
||||||
|
{ \n
|
||||||
|
double minValue; \n
|
||||||
|
double maxValue; \n
|
||||||
|
double endTime; \n
|
||||||
|
GWEN_BUFFER *dbuf; \n
|
||||||
|
GWEN_DATE *dt; \n
|
||||||
|
\n
|
||||||
|
maxValue=st->maxValue; \n
|
||||||
|
dt=GWEN_Date_fromLocalTime(maxValue); \n
|
||||||
|
endTime=GWEN_Date_toLocalTime(dt); \n
|
||||||
|
GWEN_Date_free(dt); \n
|
||||||
|
\n
|
||||||
|
minValue=st->minValue; \n
|
||||||
|
dt=GWEN_Date_fromLocalTime(minValue); \n
|
||||||
|
\n
|
||||||
|
dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n
|
||||||
|
while(1) { \n
|
||||||
|
double v; \n
|
||||||
|
GWEN_DATE *dtCurrent; \n
|
||||||
|
\n
|
||||||
|
dtCurrent=GWEN_Date_GetThisMonthStart(dt); \n
|
||||||
|
v=GWEN_Date_toLocalTime(dt); \n
|
||||||
|
if (v>=minValue && v<endTime) { \n
|
||||||
|
GWEN_Buffer_AppendArgs(dbuf, \n
|
||||||
|
"%04d/%02d", \n
|
||||||
|
GWEN_Date_GetYear(dt), \n
|
||||||
|
GWEN_Date_GetMonth(dt)); \n
|
||||||
|
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), v, lvl, 0); \n
|
||||||
|
GWEN_Date_free(dtCurrent); \n
|
||||||
|
GWEN_Buffer_Reset(dbuf); \n
|
||||||
|
} \n
|
||||||
|
GWEN_Date_AddDays(dt, 32); \n
|
||||||
|
if (v>=endTime) \n
|
||||||
|
break; \n
|
||||||
|
} \n
|
||||||
|
GWEN_Buffer_free(dbuf); \n
|
||||||
|
GWEN_Date_free(dt); \n
|
||||||
|
} \n
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
</inlines>
|
</inlines>
|
||||||
|
|
||||||
</lang>
|
</lang>
|
||||||
@@ -141,6 +351,11 @@
|
|||||||
<item name="VERTICAL" value="1" />
|
<item name="VERTICAL" value="1" />
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define id="AQDG_GRAPH_AXIS_FLAGS" prefix="AQDG_GRAPH_AXIS_FLAGS_">
|
||||||
|
<item name="HASMINVALUE" value="0x0001" />
|
||||||
|
<item name="HASMAXVALUE" value="0x0002" />
|
||||||
|
</define>
|
||||||
|
|
||||||
</defines>
|
</defines>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,21 @@
|
|||||||
#include <gwenhywfar/debug.h>
|
#include <gwenhywfar/debug.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* forward declarations
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static void _updateAxisMinMaxValues(AQDG_GRAPH_AXIS *axis, double minValue, double maxValue);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* code
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
AQDG_GRAPH *AQDG_Graph_new(void)
|
AQDG_GRAPH *AQDG_Graph_new(void)
|
||||||
{
|
{
|
||||||
@@ -135,3 +150,73 @@ void AQDG_Graph_AddSubGraph(AQDG_GRAPH *g, AQDG_GRAPH_SUBGRAPH *sg)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQDG_GRAPH_SUBGRAPH *AQDG_Graph_GetFirstSubGraph(const AQDG_GRAPH *g)
|
||||||
|
{
|
||||||
|
return (g && g->subGraphList)?AQDG_Graph_SubGraph_List_First(g->subGraphList):NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AQDG_Graph_CalcMinMaxValues(AQDG_GRAPH *g)
|
||||||
|
{
|
||||||
|
if (g) {
|
||||||
|
AQDG_GRAPH_SUBGRAPH *sg;
|
||||||
|
|
||||||
|
sg=AQDG_Graph_SubGraph_List_First(g->subGraphList);
|
||||||
|
while(sg) {
|
||||||
|
AQDG_GRAPH_AXIS *axis;
|
||||||
|
|
||||||
|
AQDG_Graph_SubGraph_CalcMinMaxValues(sg);
|
||||||
|
DBG_ERROR(NULL, "SubGraph: minX=%f, maxX=%f", AQDG_Graph_SubGraph_GetMinValueX(sg), AQDG_Graph_SubGraph_GetMaxValueX(sg));
|
||||||
|
axis=AQDG_Graph_GetAxisByIndex(g, AQDG_Graph_SubGraph_GetIndexAxisX(sg));
|
||||||
|
if (axis)
|
||||||
|
_updateAxisMinMaxValues(axis, AQDG_Graph_SubGraph_GetMinValueX(sg), AQDG_Graph_SubGraph_GetMaxValueX(sg));
|
||||||
|
axis=AQDG_Graph_GetAxisByIndex(g, AQDG_Graph_SubGraph_GetIndexAxisY(sg));
|
||||||
|
if (axis)
|
||||||
|
_updateAxisMinMaxValues(axis, AQDG_Graph_SubGraph_GetMinValueY(sg), AQDG_Graph_SubGraph_GetMaxValueY(sg));
|
||||||
|
|
||||||
|
sg=AQDG_Graph_SubGraph_List_Next(sg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _updateAxisMinMaxValues(AQDG_GRAPH_AXIS *axis, double minValue, double maxValue)
|
||||||
|
{
|
||||||
|
if (axis) {
|
||||||
|
uint32_t flags;
|
||||||
|
|
||||||
|
flags=AQDG_Graph_Axis_GetFlags(axis);
|
||||||
|
|
||||||
|
if (flags & AQDG_GRAPH_AXIS_FLAGS_HASMINVALUE) {
|
||||||
|
double value;
|
||||||
|
|
||||||
|
value=AQDG_Graph_Axis_GetMinValue(axis);
|
||||||
|
if (minValue<value)
|
||||||
|
AQDG_Graph_Axis_SetMinValue(axis, minValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AQDG_Graph_Axis_SetMinValue(axis, minValue);
|
||||||
|
AQDG_Graph_Axis_AddFlags(axis, AQDG_GRAPH_AXIS_FLAGS_HASMINVALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & AQDG_GRAPH_AXIS_FLAGS_HASMAXVALUE) {
|
||||||
|
double value;
|
||||||
|
|
||||||
|
value=AQDG_Graph_Axis_GetMaxValue(axis);
|
||||||
|
if (maxValue>value)
|
||||||
|
AQDG_Graph_Axis_SetMaxValue(axis, maxValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AQDG_Graph_Axis_SetMaxValue(axis, maxValue);
|
||||||
|
AQDG_Graph_Axis_AddFlags(axis, AQDG_GRAPH_AXIS_FLAGS_HASMAXVALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -63,10 +63,13 @@ AQDG_API int AQDG_Graph_SetAxis(AQDG_GRAPH *g, int idx, AQDG_GRAPH_AXIS *ax);
|
|||||||
|
|
||||||
AQDG_API AQDG_GRAPH_SUBGRAPH_LIST *AQDG_Graph_GetSubGraphList(const AQDG_GRAPH *g);
|
AQDG_API AQDG_GRAPH_SUBGRAPH_LIST *AQDG_Graph_GetSubGraphList(const AQDG_GRAPH *g);
|
||||||
AQDG_API void AQDG_Graph_AddSubGraph(AQDG_GRAPH *g, AQDG_GRAPH_SUBGRAPH *sg);
|
AQDG_API void AQDG_Graph_AddSubGraph(AQDG_GRAPH *g, AQDG_GRAPH_SUBGRAPH *sg);
|
||||||
|
AQDG_API AQDG_GRAPH_SUBGRAPH *AQDG_Graph_GetFirstSubGraph(const AQDG_GRAPH *g);
|
||||||
|
|
||||||
AQDG_API AQDG_DRAW_CONTEXT *AQDG_Graph_GetDrawContext(const AQDG_GRAPH *g);
|
AQDG_API AQDG_DRAW_CONTEXT *AQDG_Graph_GetDrawContext(const AQDG_GRAPH *g);
|
||||||
AQDG_API void AQDG_Graph_SetDrawContext(AQDG_GRAPH *g, AQDG_DRAW_CONTEXT *dc);
|
AQDG_API void AQDG_Graph_SetDrawContext(AQDG_GRAPH *g, AQDG_DRAW_CONTEXT *dc);
|
||||||
|
|
||||||
|
AQDG_API void AQDG_Graph_CalcMinMaxValues(AQDG_GRAPH *g);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,10 @@
|
|||||||
void $(struct_prefix)_CalcMinMaxValues($(struct_type) *st) \n
|
void $(struct_prefix)_CalcMinMaxValues($(struct_type) *st) \n
|
||||||
{ \n
|
{ \n
|
||||||
if (st && st->curves) { \n
|
if (st && st->curves) { \n
|
||||||
|
int hasMinX=0; \n
|
||||||
|
int hasMaxX=0; \n
|
||||||
|
int hasMinY=0; \n
|
||||||
|
int hasMaxY=0; \n
|
||||||
double minX; \n
|
double minX; \n
|
||||||
double maxX; \n
|
double maxX; \n
|
||||||
double maxY; \n
|
double maxY; \n
|
||||||
@@ -49,14 +53,35 @@
|
|||||||
\n
|
\n
|
||||||
AQDG_Graph_Curve_CalcMinMaxValues(curve); \n
|
AQDG_Graph_Curve_CalcMinMaxValues(curve); \n
|
||||||
d=AQDG_Graph_Curve_GetMinValueX(curve); \n
|
d=AQDG_Graph_Curve_GetMinValueX(curve); \n
|
||||||
minX=(d<minX)?d:minX; \n
|
if (hasMinX) \n
|
||||||
|
minX=(d<minX)?d:minX; \n
|
||||||
|
else { \n
|
||||||
|
minX=d; \n
|
||||||
|
hasMinX=1; \n
|
||||||
|
} \n
|
||||||
|
\n
|
||||||
d=AQDG_Graph_Curve_GetMinValueY(curve); \n
|
d=AQDG_Graph_Curve_GetMinValueY(curve); \n
|
||||||
minY=(d<minY)?d:minY; \n
|
if (hasMinY) \n
|
||||||
|
minY=(d<minY)?d:minY; \n
|
||||||
|
else { \n
|
||||||
|
minY=d; \n
|
||||||
|
hasMinY=1; \n
|
||||||
|
} \n
|
||||||
\n
|
\n
|
||||||
d=AQDG_Graph_Curve_GetMaxValueX(curve); \n
|
d=AQDG_Graph_Curve_GetMaxValueX(curve); \n
|
||||||
maxX=(d>maxX)?d:maxX; \n
|
if (hasMaxX) \n
|
||||||
|
maxX=(d>maxX)?d:maxX; \n
|
||||||
|
else { \n
|
||||||
|
maxX=d; \n
|
||||||
|
hasMaxX=1; \n
|
||||||
|
} \n
|
||||||
d=AQDG_Graph_Curve_GetMaxValueY(curve); \n
|
d=AQDG_Graph_Curve_GetMaxValueY(curve); \n
|
||||||
maxY=(d>maxY)?d:maxY; \n
|
if (hasMaxY) \n
|
||||||
|
maxY=(d>maxY)?d:maxY; \n
|
||||||
|
else { \n
|
||||||
|
maxY=d; \n
|
||||||
|
hasMaxY=1; \n
|
||||||
|
} \n
|
||||||
\n
|
\n
|
||||||
curve=AQDG_Graph_Curve_List_Next(curve); \n
|
curve=AQDG_Graph_Curve_List_Next(curve); \n
|
||||||
} \n
|
} \n
|
||||||
@@ -71,6 +96,26 @@
|
|||||||
</inline>
|
</inline>
|
||||||
|
|
||||||
|
|
||||||
|
<inline loc="end" access="public">
|
||||||
|
<content>
|
||||||
|
$(api) void $(struct_prefix)_AddCurve($(struct_type) *st, AQDG_GRAPH_CURVE *curve);
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
<inline loc="code">
|
||||||
|
<content>
|
||||||
|
void $(struct_prefix)_AddCurve($(struct_type) *st, AQDG_GRAPH_CURVE *curve) \n
|
||||||
|
{ \n
|
||||||
|
if (st && curve) { \n
|
||||||
|
if (st->curves==NULL) \n
|
||||||
|
st->curves=AQDG_Graph_Curve_List_new(); \n
|
||||||
|
AQDG_Graph_Curve_List_Add(curve, st->curves); \n
|
||||||
|
} \n
|
||||||
|
} \n
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
|
||||||
</inlines>
|
</inlines>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -373,6 +373,3 @@ int _hideEverySecondLabel(AQDG_OBJECT *o)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -480,30 +480,31 @@ void AQDG_GraphWidget_SetupDefaultPens(AQDG_OBJECT *o)
|
|||||||
AQDG_DRAW_CONTEXT *dc;
|
AQDG_DRAW_CONTEXT *dc;
|
||||||
|
|
||||||
dc=AQDG_DrawableWidget_GetDrawContext(o);
|
dc=AQDG_DrawableWidget_GetDrawContext(o);
|
||||||
#define MKSOLIDPEN(penArrayIdx, penColour, penSize) \
|
#define MKPEN(penArrayIdx, penColour, penSize, penDash) \
|
||||||
xo->penArray[penArrayIdx]=AQDG_Draw_Context_PenCreate(dc, penColour, penSize, AQDG_Dash_None);
|
xo->penArray[penArrayIdx]=AQDG_Draw_Context_PenCreate(dc, penColour, penSize, penDash);
|
||||||
|
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_TITLE, AQDG_GRAPHWIDGET_COL_BLACK, 2);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_TITLE, AQDG_GRAPHWIDGET_COL_BLACK, 2, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_SUBTITLE, AQDG_GRAPHWIDGET_COL_BLACK, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_SUBTITLE, AQDG_GRAPHWIDGET_COL_BLACK, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_AXISLINE, AQDG_GRAPHWIDGET_COL_BLACK, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_AXISLINE, AQDG_GRAPHWIDGET_COL_BLACK, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_AXISLABEL, AQDG_GRAPHWIDGET_COL_BLACK, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_AXISLABEL, AQDG_GRAPHWIDGET_COL_BLACK, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_TICKLABELMAINLEVEL, AQDG_GRAPHWIDGET_COL_BLACK, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_TICKLABELMAINLEVEL, AQDG_GRAPHWIDGET_COL_BLACK, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_TICKLABELSUBLEVEL, AQDG_GRAPHWIDGET_COL_BLACK, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_TICKLABELSUBLEVEL, AQDG_GRAPHWIDGET_COL_BLACK, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_TICKMAINLEVEL, AQDG_GRAPHWIDGET_COL_BLACK, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_TICKMAINLEVEL, AQDG_GRAPHWIDGET_COL_BLACK, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_TICKSUBLEVEL, AQDG_GRAPHWIDGET_COL_BLACK, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_TICKSUBLEVEL, AQDG_GRAPHWIDGET_COL_BLACK, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_GRAPHBACKGROUND, AQDG_GRAPHWIDGET_COL_WHITESMOKE, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_GRAPHBACKGROUND, AQDG_GRAPHWIDGET_COL_WHITESMOKE, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_GRID, AQDG_GRAPHWIDGET_COL_BLACK, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_GRID1, AQDG_GRAPHWIDGET_COL_BLACK, 1, AQDG_Dash_Format1);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_BACKGROUND, AQDG_GRAPHWIDGET_COL_GAINSBORO, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_GRID2, AQDG_GRAPHWIDGET_COL_BLACK, 1, AQDG_Dash_Format2);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE0, AQDG_GRAPHWIDGET_COL_LIME, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_BACKGROUND, AQDG_GRAPHWIDGET_COL_GAINSBORO, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE1, AQDG_GRAPHWIDGET_COL_BLUE, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE0, AQDG_GRAPHWIDGET_COL_GREEN, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE2, AQDG_GRAPHWIDGET_COL_CYAN, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE1, AQDG_GRAPHWIDGET_COL_BLUE, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE3, AQDG_GRAPHWIDGET_COL_MAGENTA, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE2, AQDG_GRAPHWIDGET_COL_RED, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE4, AQDG_GRAPHWIDGET_COL_GREEN, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE3, AQDG_GRAPHWIDGET_COL_MAGENTA, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE5, AQDG_GRAPHWIDGET_COL_TURQUOISE, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE4, AQDG_GRAPHWIDGET_COL_ORANGE, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE6, AQDG_GRAPHWIDGET_COL_DEEPPINK, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE5, AQDG_GRAPHWIDGET_COL_TURQUOISE, 1, AQDG_Dash_None);
|
||||||
MKSOLIDPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE7, AQDG_GRAPHWIDGET_COL_NAVY, 1);
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE6, AQDG_GRAPHWIDGET_COL_DEEPPINK, 1, AQDG_Dash_None);
|
||||||
|
MKPEN(AQDG_GRAPHWIDGET_PEN_IDX_CURVE7, AQDG_GRAPHWIDGET_COL_NAVY, 1, AQDG_Dash_None);
|
||||||
|
|
||||||
#undef MKSOLIDPEN
|
#undef MKPEN
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -534,11 +535,3 @@ void AQDG_GraphWidget_SetupDefaultFonts(AQDG_OBJECT *o)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ enum {
|
|||||||
AQDG_GRAPHWIDGET_PEN_IDX_TICKMAINLEVEL,
|
AQDG_GRAPHWIDGET_PEN_IDX_TICKMAINLEVEL,
|
||||||
AQDG_GRAPHWIDGET_PEN_IDX_TICKSUBLEVEL,
|
AQDG_GRAPHWIDGET_PEN_IDX_TICKSUBLEVEL,
|
||||||
AQDG_GRAPHWIDGET_PEN_IDX_GRAPHBACKGROUND,
|
AQDG_GRAPHWIDGET_PEN_IDX_GRAPHBACKGROUND,
|
||||||
AQDG_GRAPHWIDGET_PEN_IDX_GRID,
|
AQDG_GRAPHWIDGET_PEN_IDX_GRID1,
|
||||||
|
AQDG_GRAPHWIDGET_PEN_IDX_GRID2,
|
||||||
AQDG_GRAPHWIDGET_PEN_IDX_BACKGROUND,
|
AQDG_GRAPHWIDGET_PEN_IDX_BACKGROUND,
|
||||||
AQDG_GRAPHWIDGET_PEN_IDX_CURVE0,
|
AQDG_GRAPHWIDGET_PEN_IDX_CURVE0,
|
||||||
AQDG_GRAPHWIDGET_PEN_IDX_CURVE1,
|
AQDG_GRAPHWIDGET_PEN_IDX_CURVE1,
|
||||||
@@ -102,6 +103,15 @@ AQDG_API void AQDG_GraphWidget_SetupDefaultPens(AQDG_OBJECT *o);
|
|||||||
AQDG_API void AQDG_GraphWidget_SetupDefaultFonts(AQDG_OBJECT *o);
|
AQDG_API void AQDG_GraphWidget_SetupDefaultFonts(AQDG_OBJECT *o);
|
||||||
|
|
||||||
|
|
||||||
|
AQDG_API AQDG_OBJECT *AQDG_GraphWidget_GenerateTimeGraph(const char *sTitle,
|
||||||
|
const char *sSubTitle,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
const char *sYLabel,
|
||||||
|
const char *sYUnits,
|
||||||
|
int yPrecision);
|
||||||
|
AQDG_API void AQDG_GraphWidget_AddCurve(AQDG_OBJECT *o);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "./w_viewport_p.h"
|
#include "./w_viewport_p.h"
|
||||||
|
#include "./w_axis.h"
|
||||||
#include "aqdiagram/draw/w_drawable.h"
|
#include "aqdiagram/draw/w_drawable.h"
|
||||||
|
|
||||||
#include <gwenhywfar/debug.h>
|
#include <gwenhywfar/debug.h>
|
||||||
@@ -23,6 +24,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static GWENHYWFAR_CB void _freeData(void *bp, void *p);
|
static GWENHYWFAR_CB void _freeData(void *bp, void *p);
|
||||||
|
static int _draw(AQDG_OBJECT *object);
|
||||||
|
static void _drawCurves(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc);
|
||||||
|
static void _drawCurve(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
|
||||||
|
double minValueX, double maxValueX, double minValueY, double maxValueY,
|
||||||
|
int pen);
|
||||||
|
static void _drawCurveLines(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
|
||||||
|
double minValueX, double maxValueX, double minValueY, double maxValueY,
|
||||||
|
int pen);
|
||||||
|
static void _drawCurvePoints(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
|
||||||
|
double minValueX, double maxValueX, double minValueY, double maxValueY,
|
||||||
|
int pen);
|
||||||
|
static void _drawVerticalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc);
|
||||||
|
static void _drawHorizontalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -45,6 +59,8 @@ AQDG_OBJECT *AQDG_ViewportWidget_new(AQDG_OBJECT *parent, uint32_t options, AQDG
|
|||||||
GWEN_NEW_OBJECT(AQDG_WIDGET_VIEWPORT, xo);
|
GWEN_NEW_OBJECT(AQDG_WIDGET_VIEWPORT, xo);
|
||||||
GWEN_INHERIT_SETDATA(AQDG_OBJECT, AQDG_WIDGET_VIEWPORT, o, xo, _freeData);
|
GWEN_INHERIT_SETDATA(AQDG_OBJECT, AQDG_WIDGET_VIEWPORT, o, xo, _freeData);
|
||||||
|
|
||||||
|
AQDG_DrawableWidget_SetDrawFn(o, _draw);
|
||||||
|
|
||||||
xo->graphObject=graphObject;
|
xo->graphObject=graphObject;
|
||||||
|
|
||||||
AQDG_DrawableWidget_SetBackgroundPenId(o, AQDG_GraphWidget_GetPen(graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRAPHBACKGROUND));
|
AQDG_DrawableWidget_SetBackgroundPenId(o, AQDG_GraphWidget_GetPen(graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRAPHBACKGROUND));
|
||||||
@@ -70,6 +86,21 @@ GWENHYWFAR_CB void _freeData(void *bp, void *p)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _draw(AQDG_OBJECT *object)
|
||||||
|
{
|
||||||
|
AQDG_DRAW_CONTEXT *dc;
|
||||||
|
|
||||||
|
AQDG_DrawableWidget_DefaultDraw(object);
|
||||||
|
|
||||||
|
dc=AQDG_DrawableWidget_GetDrawContext(object);
|
||||||
|
_drawVerticalGrid(object, dc);
|
||||||
|
_drawHorizontalGrid(object, dc);
|
||||||
|
_drawCurves(object, dc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _calcHorizontalPos(double value, int contentSize, double minValue, double maxValue)
|
int _calcHorizontalPos(double value, int contentSize, double minValue, double maxValue)
|
||||||
{
|
{
|
||||||
return ((value-minValue)*(contentSize/(maxValue-minValue)));
|
return ((value-minValue)*(contentSize/(maxValue-minValue)));
|
||||||
@@ -84,3 +115,257 @@ int _calcVerticalPos(double value, int contentSize, double minValue, double maxV
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _drawCurves(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc)
|
||||||
|
{
|
||||||
|
AQDG_WIDGET_VIEWPORT *xo;
|
||||||
|
AQDG_GRAPH *graph;
|
||||||
|
const AQDG_GRAPH_SUBGRAPH_LIST *subGraphList;
|
||||||
|
const AQDG_GRAPH_SUBGRAPH *subGraph;
|
||||||
|
|
||||||
|
xo=GWEN_INHERIT_GETDATA(AQDG_OBJECT, AQDG_WIDGET_VIEWPORT, o);
|
||||||
|
graph=AQDG_GraphWidget_GetGraph(xo->graphObject);
|
||||||
|
|
||||||
|
subGraphList=AQDG_Graph_GetSubGraphList(graph);
|
||||||
|
subGraph=subGraphList?AQDG_Graph_SubGraph_List_First(subGraphList):NULL;
|
||||||
|
while (subGraph) {
|
||||||
|
double minValueX;
|
||||||
|
double maxValueX;
|
||||||
|
double minValueY;
|
||||||
|
double maxValueY;
|
||||||
|
int penIdx=AQDG_GRAPHWIDGET_PEN_IDX_CURVE0;
|
||||||
|
const AQDG_GRAPH_CURVE_LIST *curveList;
|
||||||
|
const AQDG_GRAPH_CURVE *curve;
|
||||||
|
|
||||||
|
minValueX=AQDG_Graph_SubGraph_GetMinValueX(subGraph);
|
||||||
|
maxValueX=AQDG_Graph_SubGraph_GetMaxValueX(subGraph);
|
||||||
|
minValueY=AQDG_Graph_SubGraph_GetMinValueY(subGraph);
|
||||||
|
maxValueY=AQDG_Graph_SubGraph_GetMaxValueY(subGraph);
|
||||||
|
|
||||||
|
curveList=AQDG_Graph_SubGraph_GetCurves(subGraph);
|
||||||
|
curve=curveList?AQDG_Graph_Curve_List_First(curveList):NULL;
|
||||||
|
while(curve) {
|
||||||
|
int pen;
|
||||||
|
|
||||||
|
pen=AQDG_GraphWidget_GetPen(xo->graphObject, penIdx);
|
||||||
|
_drawCurve(o, dc, curve, minValueX, maxValueX, minValueY, maxValueY, pen);
|
||||||
|
|
||||||
|
penIdx++;
|
||||||
|
curve=AQDG_Graph_Curve_List_Next(curve);
|
||||||
|
}
|
||||||
|
|
||||||
|
subGraph=AQDG_Graph_SubGraph_List_Next(subGraph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _drawCurve(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
|
||||||
|
double minValueX, double maxValueX, double minValueY, double maxValueY,
|
||||||
|
int pen)
|
||||||
|
{
|
||||||
|
switch(AQDG_Graph_Curve_GetGraphType(curve)) {
|
||||||
|
case AQDG_GRAPH_TYPE_LINE:
|
||||||
|
_drawCurveLines(o, dc, curve, minValueX, maxValueX, minValueY, maxValueY, pen);
|
||||||
|
break;
|
||||||
|
case AQDG_GRAPH_TYPE_POINTS:
|
||||||
|
_drawCurvePoints(o, dc, curve, minValueX, maxValueX, minValueY, maxValueY, pen);
|
||||||
|
break;
|
||||||
|
case AQDG_GRAPH_TYPE_BARS:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _drawCurveLines(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
|
||||||
|
double minValueX, double maxValueX, double minValueY, double maxValueY,
|
||||||
|
int pen)
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
const AQDG_GRAPH_DATAPAIR_LIST *dpList;
|
||||||
|
const AQDG_GRAPH_DATAPAIR *dp;
|
||||||
|
int absX;
|
||||||
|
int absY;
|
||||||
|
int lastX=-1;
|
||||||
|
int lastY=-1;
|
||||||
|
|
||||||
|
absX=AQDG_Object_GetAbsoluteX(o);
|
||||||
|
absY=AQDG_Object_GetAbsoluteY(o);
|
||||||
|
width=AQDG_Object_GetWidth(o);
|
||||||
|
height=AQDG_Object_GetHeight(o);
|
||||||
|
dpList=AQDG_Graph_Curve_GetDataPairs(curve);
|
||||||
|
dp=dpList?AQDG_Graph_DataPair_List_First(dpList):NULL;
|
||||||
|
while(dp) {
|
||||||
|
int xPos;
|
||||||
|
int yPos;
|
||||||
|
double xValue;
|
||||||
|
double yValue;
|
||||||
|
|
||||||
|
xValue=AQDG_Graph_DataPair_GetValueX(dp);
|
||||||
|
yValue=AQDG_Graph_DataPair_GetValueY(dp);
|
||||||
|
|
||||||
|
xPos=_calcHorizontalPos(xValue, width, minValueX, maxValueX);
|
||||||
|
yPos=_calcVerticalPos(yValue, height, minValueY, maxValueY);
|
||||||
|
if (lastX>=0 && lastY>=0)
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen, absX+lastX, absY+lastY, absX+xPos, absY+yPos);
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen, absX+xPos-2, absY+yPos-2, absX+xPos+2, absY+yPos+2);
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen, absX+xPos-2, absY+yPos+2, absX+xPos+2, absY+yPos-2);
|
||||||
|
lastX=xPos;
|
||||||
|
lastY=yPos;
|
||||||
|
dp=AQDG_Graph_DataPair_List_Next(dp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _drawCurvePoints(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, const AQDG_GRAPH_CURVE *curve,
|
||||||
|
double minValueX, double maxValueX, double minValueY, double maxValueY,
|
||||||
|
int pen)
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
const AQDG_GRAPH_DATAPAIR_LIST *dpList;
|
||||||
|
const AQDG_GRAPH_DATAPAIR *dp;
|
||||||
|
int absX;
|
||||||
|
int absY;
|
||||||
|
|
||||||
|
absX=AQDG_Object_GetAbsoluteX(o);
|
||||||
|
absY=AQDG_Object_GetAbsoluteY(o);
|
||||||
|
width=AQDG_Object_GetWidth(o);
|
||||||
|
height=AQDG_Object_GetHeight(o);
|
||||||
|
dpList=AQDG_Graph_Curve_GetDataPairs(curve);
|
||||||
|
dp=dpList?AQDG_Graph_DataPair_List_First(dpList):NULL;
|
||||||
|
while(dp) {
|
||||||
|
int xPos;
|
||||||
|
int yPos;
|
||||||
|
double xValue;
|
||||||
|
double yValue;
|
||||||
|
|
||||||
|
xValue=AQDG_Graph_DataPair_GetValueX(dp);
|
||||||
|
yValue=AQDG_Graph_DataPair_GetValueY(dp);
|
||||||
|
|
||||||
|
xPos=_calcHorizontalPos(xValue, width, minValueX, maxValueX);
|
||||||
|
yPos=_calcVerticalPos(yValue, height, minValueY, maxValueY);
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen, absX+xPos-4, absY+yPos-4, absX+xPos+4, absY+yPos+4);
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen, absX+xPos-4, absY+yPos+4, absX+xPos+4, absY+yPos-4);
|
||||||
|
dp=AQDG_Graph_DataPair_List_Next(dp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _drawVerticalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc)
|
||||||
|
{
|
||||||
|
AQDG_WIDGET_VIEWPORT *xo;
|
||||||
|
AQDG_GRAPH *graph;
|
||||||
|
AQDG_GRAPH_AXIS *axis;
|
||||||
|
|
||||||
|
xo=GWEN_INHERIT_GETDATA(AQDG_OBJECT, AQDG_WIDGET_VIEWPORT, o);
|
||||||
|
graph=AQDG_GraphWidget_GetGraph(xo->graphObject);
|
||||||
|
axis=AQDG_Graph_GetAxisByIndex(graph, AQDG_GRAPH_AXISPOS_BOTTOM);
|
||||||
|
if (axis==NULL)
|
||||||
|
axis=AQDG_Graph_GetAxisByIndex(graph, AQDG_GRAPH_AXISPOS_TOP);
|
||||||
|
if (axis) {
|
||||||
|
const AQDG_GRAPH_TICK_LIST *tickList;
|
||||||
|
|
||||||
|
tickList=AQDG_Graph_Axis_GetTickList(axis);
|
||||||
|
if (tickList) {
|
||||||
|
const AQDG_GRAPH_TICK *tick;
|
||||||
|
int contentSize;
|
||||||
|
double minValue;
|
||||||
|
double maxValue;
|
||||||
|
int absX;
|
||||||
|
int pen1;
|
||||||
|
int pen2;
|
||||||
|
int y1;
|
||||||
|
int y2;
|
||||||
|
|
||||||
|
y1=AQDG_Object_GetAbsoluteY(o)+AQDG_Object_GetBorderTop(o);
|
||||||
|
y2=AQDG_Object_GetAbsoluteY(o)+AQDG_Object_GetHeight(o)-AQDG_Object_GetBorderBottom(o);
|
||||||
|
contentSize=AQDG_Object_GetWidth(o)-AQDG_Object_GetBorderLeft(o)-AQDG_Object_GetBorderRight(o);
|
||||||
|
absX=AQDG_Object_GetAbsoluteX(o);
|
||||||
|
minValue=AQDG_Graph_Axis_GetMinValue(axis);
|
||||||
|
maxValue=AQDG_Graph_Axis_GetMaxValue(axis);
|
||||||
|
pen1=AQDG_GraphWidget_GetPen(xo->graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRID1);
|
||||||
|
pen2=AQDG_GraphWidget_GetPen(xo->graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRID2);
|
||||||
|
|
||||||
|
tick=AQDG_Graph_Tick_List_First(tickList);
|
||||||
|
while(tick) {
|
||||||
|
double value;
|
||||||
|
int xpos;
|
||||||
|
|
||||||
|
value=AQDG_Graph_Tick_GetValue(tick);
|
||||||
|
xpos=_calcHorizontalPos(value, contentSize, minValue, maxValue);
|
||||||
|
xpos+=AQDG_Object_GetBorderLeft(o);
|
||||||
|
if (AQDG_Graph_Tick_GetLevel(tick)==0)
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen1, absX+xpos, y1, absX+xpos, y2);
|
||||||
|
else if (AQDG_Graph_Tick_GetLevel(tick)==1)
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen2, absX+xpos, y1, absX+xpos, y2);
|
||||||
|
tick=AQDG_Graph_Tick_List_Next(tick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _drawHorizontalGrid(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc)
|
||||||
|
{
|
||||||
|
AQDG_WIDGET_VIEWPORT *xo;
|
||||||
|
AQDG_GRAPH *graph;
|
||||||
|
AQDG_GRAPH_AXIS *axis;
|
||||||
|
|
||||||
|
xo=GWEN_INHERIT_GETDATA(AQDG_OBJECT, AQDG_WIDGET_VIEWPORT, o);
|
||||||
|
graph=AQDG_GraphWidget_GetGraph(xo->graphObject);
|
||||||
|
axis=AQDG_Graph_GetAxisByIndex(graph, AQDG_GRAPH_AXISPOS_LEFT);
|
||||||
|
if (axis==NULL)
|
||||||
|
axis=AQDG_Graph_GetAxisByIndex(graph, AQDG_GRAPH_AXISPOS_RIGHT);
|
||||||
|
if (axis) {
|
||||||
|
const AQDG_GRAPH_TICK_LIST *tickList;
|
||||||
|
|
||||||
|
tickList=AQDG_Graph_Axis_GetTickList(axis);
|
||||||
|
if (tickList) {
|
||||||
|
const AQDG_GRAPH_TICK *tick;
|
||||||
|
int contentSize;
|
||||||
|
double minValue;
|
||||||
|
double maxValue;
|
||||||
|
int absY;
|
||||||
|
int pen1;
|
||||||
|
int pen2;
|
||||||
|
int x1;
|
||||||
|
int x2;
|
||||||
|
|
||||||
|
x1=AQDG_Object_GetAbsoluteX(o)+AQDG_Object_GetBorderLeft(o);
|
||||||
|
x2=AQDG_Object_GetAbsoluteX(o)+AQDG_Object_GetWidth(o)-AQDG_Object_GetBorderLeft(o)-AQDG_Object_GetBorderRight(o);
|
||||||
|
contentSize=AQDG_Object_GetHeight(o)-AQDG_Object_GetBorderTop(o)-AQDG_Object_GetBorderBottom(o);
|
||||||
|
absY=AQDG_Object_GetAbsoluteY(o);
|
||||||
|
minValue=AQDG_Graph_Axis_GetMinValue(axis);
|
||||||
|
maxValue=AQDG_Graph_Axis_GetMaxValue(axis);
|
||||||
|
pen1=AQDG_GraphWidget_GetPen(xo->graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRID1);
|
||||||
|
pen2=AQDG_GraphWidget_GetPen(xo->graphObject, AQDG_GRAPHWIDGET_PEN_IDX_GRID2);
|
||||||
|
|
||||||
|
tick=AQDG_Graph_Tick_List_First(tickList);
|
||||||
|
while(tick) {
|
||||||
|
double value;
|
||||||
|
int ypos;
|
||||||
|
|
||||||
|
value=AQDG_Graph_Tick_GetValue(tick);
|
||||||
|
ypos=_calcVerticalPos(value, contentSize, minValue, maxValue);
|
||||||
|
ypos+=AQDG_Object_GetBorderTop(o);
|
||||||
|
if (AQDG_Graph_Tick_GetLevel(tick)==0)
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen1, x1, absY+ypos, x2, absY+ypos);
|
||||||
|
else
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen2, x1, absY+ypos, x2, absY+ypos);
|
||||||
|
tick=AQDG_Graph_Tick_List_Next(tick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -131,15 +131,16 @@ void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int absY)
|
|||||||
|
|
||||||
tick=AQDG_Graph_Tick_List_First(tickList);
|
tick=AQDG_Graph_Tick_List_First(tickList);
|
||||||
while(tick) {
|
while(tick) {
|
||||||
if (AQDG_Graph_Tick_GetLevel(tick)==0) {
|
double value;
|
||||||
double value;
|
int xpos;
|
||||||
int xpos;
|
|
||||||
|
|
||||||
value=AQDG_Graph_Tick_GetValue(tick);
|
value=AQDG_Graph_Tick_GetValue(tick);
|
||||||
xpos=_calcHorizontalPos(value, contentSize, minValue, maxValue);
|
xpos=_calcHorizontalPos(value, contentSize, minValue, maxValue);
|
||||||
xpos+=AQDG_Object_GetBorderLeft(o);
|
xpos+=AQDG_Object_GetBorderLeft(o);
|
||||||
|
if (AQDG_Graph_Tick_GetLevel(tick)==0)
|
||||||
AQDG_Draw_Context_DrawLine(dc, pen, absX+xpos, absY-(scaleSize/2), absX+xpos, absY+(scaleSize/2));
|
AQDG_Draw_Context_DrawLine(dc, pen, absX+xpos, absY-(scaleSize/2), absX+xpos, absY+(scaleSize/2));
|
||||||
}
|
else if (AQDG_Graph_Tick_GetLevel(tick)==1)
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen, absX+xpos, absY-(scaleSize/4), absX+xpos, absY+(scaleSize/4));
|
||||||
tick=AQDG_Graph_Tick_List_Next(tick);
|
tick=AQDG_Graph_Tick_List_Next(tick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,15 +158,16 @@ void _drawTicks(AQDG_OBJECT *o, AQDG_DRAW_CONTEXT *dc, int absX)
|
|||||||
|
|
||||||
tick=AQDG_Graph_Tick_List_First(tickList);
|
tick=AQDG_Graph_Tick_List_First(tickList);
|
||||||
while(tick) {
|
while(tick) {
|
||||||
if (AQDG_Graph_Tick_GetLevel(tick)==0) {
|
double value;
|
||||||
double value;
|
int ypos;
|
||||||
int ypos;
|
|
||||||
|
|
||||||
value=AQDG_Graph_Tick_GetValue(tick);
|
value=AQDG_Graph_Tick_GetValue(tick);
|
||||||
ypos=_calcVerticalPos(value, contentSize, minValue, maxValue);
|
ypos=_calcVerticalPos(value, contentSize, minValue, maxValue);
|
||||||
ypos+=AQDG_Object_GetBorderTop(o);
|
ypos+=AQDG_Object_GetBorderTop(o);
|
||||||
|
if (AQDG_Graph_Tick_GetLevel(tick)==0)
|
||||||
AQDG_Draw_Context_DrawLine(dc, pen, absX-(scaleSize/2), absY+ypos, absX+(scaleSize/2), absY+ypos);
|
AQDG_Draw_Context_DrawLine(dc, pen, absX-(scaleSize/2), absY+ypos, absX+(scaleSize/2), absY+ypos);
|
||||||
}
|
else
|
||||||
|
AQDG_Draw_Context_DrawLine(dc, pen, absX-(scaleSize/4), absY+ypos, absX+(scaleSize/4), absY+ypos);
|
||||||
tick=AQDG_Graph_Tick_List_Next(tick);
|
tick=AQDG_Graph_Tick_List_Next(tick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <aqdiagram/graph/axis.h>
|
#include <aqdiagram/graph/axis.h>
|
||||||
#include <aqdiagram/graph/subgraph.h>
|
#include <aqdiagram/graph/subgraph.h>
|
||||||
#include <aqdiagram/graph/w_graph.h>
|
#include <aqdiagram/graph/w_graph.h>
|
||||||
|
#include <aqdiagram/graph/timegraph.h>
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
#include <gwenhywfar/gwenhywfar.h>
|
||||||
#include <gwenhywfar/cgui.h>
|
#include <gwenhywfar/cgui.h>
|
||||||
@@ -38,6 +39,8 @@
|
|||||||
|
|
||||||
|
|
||||||
static AQDG_GRAPH *_mkTestGraph();
|
static AQDG_GRAPH *_mkTestGraph();
|
||||||
|
static AQDG_GRAPH_DATAPAIR_LIST *_mkTestData1();
|
||||||
|
static AQDG_GRAPH_DATAPAIR_LIST *_mkTestData2();
|
||||||
static void _dumpTicks(const AQDG_GRAPH_TICK_LIST *tickList);
|
static void _dumpTicks(const AQDG_GRAPH_TICK_LIST *tickList);
|
||||||
|
|
||||||
|
|
||||||
@@ -165,6 +168,46 @@ int test3()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int test4()
|
||||||
|
{
|
||||||
|
AQDG_GRAPH *g;
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *dpList;
|
||||||
|
AQDG_DRAW_CONTEXT *dc;
|
||||||
|
AQDG_OBJECT *graphObject;
|
||||||
|
|
||||||
|
g=AQDG_TimeGraph_new("Title", "Subtitle", "Value", "mm", 0);
|
||||||
|
dpList=_mkTestData1();
|
||||||
|
AQDG_TimeGraph_AddCurve(g, "Testdata", AQDG_GRAPH_TYPE_LINE, dpList);
|
||||||
|
|
||||||
|
dpList=_mkTestData2();
|
||||||
|
AQDG_TimeGraph_AddCurve(g, "Testdata", AQDG_GRAPH_TYPE_POINTS, dpList);
|
||||||
|
|
||||||
|
AQDG_TimeGraph_SetupTicks(g);
|
||||||
|
|
||||||
|
dc=AQDG_Draw_ContextCairo_Png_new("/tmp/testgraph.png", 800, 600);
|
||||||
|
graphObject=AQDG_GraphWidget_new(NULL, AQDG_OBJECT_OPTIONS_STRETCHX | AQDG_OBJECT_OPTIONS_STRETCHY, dc);
|
||||||
|
AQDG_Object_SetWidth(graphObject, 800);
|
||||||
|
AQDG_Object_SetHeight(graphObject, 600);
|
||||||
|
|
||||||
|
AQDG_GraphWidget_SetupDefaultPens(graphObject);
|
||||||
|
AQDG_GraphWidget_SetupDefaultFonts(graphObject);
|
||||||
|
|
||||||
|
AQDG_GraphWidget_SetupForGraph(graphObject, g);
|
||||||
|
|
||||||
|
AQDG_Object_ModifyBranchFlagsDown(graphObject, AQDG_OBJECT_FLAGS_RECALC, AQDG_OBJECT_FLAGS_RECALC);
|
||||||
|
AQDG_Object_ModifyBranchFlagsDown(graphObject, AQDG_OBJECT_FLAGS_LAYOUT, AQDG_OBJECT_FLAGS_LAYOUT);
|
||||||
|
AQDG_Object_Layout(graphObject);
|
||||||
|
AQDG_Object_Tree2_CalculateAbsPositions(graphObject);
|
||||||
|
AQDG_Object_Dump(graphObject, 2);
|
||||||
|
|
||||||
|
AQDG_DrawableWidget_Draw(graphObject);
|
||||||
|
AQDG_Draw_Context_Finish(dc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQDG_GRAPH *_mkTestGraph()
|
AQDG_GRAPH *_mkTestGraph()
|
||||||
{
|
{
|
||||||
AQDG_GRAPH *g;
|
AQDG_GRAPH *g;
|
||||||
@@ -177,12 +220,13 @@ AQDG_GRAPH *_mkTestGraph()
|
|||||||
|
|
||||||
xAxis=AQDG_Graph_Axis_new();
|
xAxis=AQDG_Graph_Axis_new();
|
||||||
AQDG_Graph_Axis_SetLabel(xAxis, "Label X");
|
AQDG_Graph_Axis_SetLabel(xAxis, "Label X");
|
||||||
AQDG_Graph_Axis_SetMinValue(xAxis, -23.0);
|
AQDG_Graph_Axis_SetMinValue(xAxis, time(NULL)-(4*7*24*60*60));
|
||||||
AQDG_Graph_Axis_SetMaxValue(xAxis, 117.0);
|
AQDG_Graph_Axis_SetMaxValue(xAxis, time(NULL));
|
||||||
AQDG_Graph_Axis_SetPrecision(xAxis, 0);
|
AQDG_Graph_Axis_SetPrecision(xAxis, 0);
|
||||||
AQDG_Graph_SetAxis(g, AQDG_GRAPH_AXISPOS_BOTTOM, xAxis);
|
AQDG_Graph_SetAxis(g, AQDG_GRAPH_AXISPOS_BOTTOM, xAxis);
|
||||||
fprintf(stderr, "Generating ticks for X-axis\n");
|
fprintf(stderr, "Generating ticks for X-axis\n");
|
||||||
AQDG_Graph_Axis_GenLog10Ticks(xAxis);
|
AQDG_Graph_Axis_GenWeekTicks(xAxis, 0);
|
||||||
|
AQDG_Graph_Axis_GenDayTicks(xAxis, 1);
|
||||||
fprintf(stderr, "Ticks for X-Axis (%f - %f)\n",
|
fprintf(stderr, "Ticks for X-Axis (%f - %f)\n",
|
||||||
AQDG_Graph_Axis_GetMinValue(xAxis),
|
AQDG_Graph_Axis_GetMinValue(xAxis),
|
||||||
AQDG_Graph_Axis_GetMaxValue(xAxis));
|
AQDG_Graph_Axis_GetMaxValue(xAxis));
|
||||||
@@ -206,6 +250,58 @@ AQDG_GRAPH *_mkTestGraph()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *_mkTestData1()
|
||||||
|
{
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *dpList;
|
||||||
|
GWEN_TIMESTAMP *ts;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dpList=AQDG_Graph_DataPair_List_new();
|
||||||
|
ts=GWEN_Timestamp_new(2025, 1, 1, 0, 0, 0);
|
||||||
|
for(i=0; i<60; i++) {
|
||||||
|
AQDG_GRAPH_DATAPAIR *dp;
|
||||||
|
double v;
|
||||||
|
|
||||||
|
v=i*2;
|
||||||
|
dp=AQDG_Graph_DataPair_new();
|
||||||
|
AQDG_Graph_DataPair_SetValueX(dp, GWEN_Timestamp_toTimeT(ts));
|
||||||
|
AQDG_Graph_DataPair_SetValueY(dp, v);
|
||||||
|
AQDG_Graph_DataPair_List_Add(dp, dpList);
|
||||||
|
|
||||||
|
GWEN_Timestamp_AddSeconds(ts, 24*60*60); /* add a day */
|
||||||
|
}
|
||||||
|
|
||||||
|
return dpList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *_mkTestData2()
|
||||||
|
{
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *dpList;
|
||||||
|
GWEN_TIMESTAMP *ts;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dpList=AQDG_Graph_DataPair_List_new();
|
||||||
|
ts=GWEN_Timestamp_new(2025, 1, 1, 0, 0, 0);
|
||||||
|
for(i=0; i<60; i++) {
|
||||||
|
AQDG_GRAPH_DATAPAIR *dp;
|
||||||
|
double v;
|
||||||
|
|
||||||
|
v=random() % 200;
|
||||||
|
dp=AQDG_Graph_DataPair_new();
|
||||||
|
AQDG_Graph_DataPair_SetValueX(dp, GWEN_Timestamp_toTimeT(ts));
|
||||||
|
AQDG_Graph_DataPair_SetValueY(dp, v);
|
||||||
|
AQDG_Graph_DataPair_List_Add(dp, dpList);
|
||||||
|
|
||||||
|
GWEN_Timestamp_AddSeconds(ts, 24*60*60); /* add a day */
|
||||||
|
}
|
||||||
|
|
||||||
|
return dpList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _dumpTicks(const AQDG_GRAPH_TICK_LIST *tickList)
|
void _dumpTicks(const AQDG_GRAPH_TICK_LIST *tickList)
|
||||||
{
|
{
|
||||||
const AQDG_GRAPH_TICK *tick;
|
const AQDG_GRAPH_TICK *tick;
|
||||||
@@ -270,7 +366,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
// rv=test1(argc, argv);
|
// rv=test1(argc, argv);
|
||||||
// rv=test2(argc, argv);
|
// rv=test2(argc, argv);
|
||||||
rv=test3();
|
rv=test4();
|
||||||
|
|
||||||
if (rv!=0){
|
if (rv!=0){
|
||||||
DBG_ERROR(NULL, "here (%d)", rv);
|
DBG_ERROR(NULL, "here (%d)", rv);
|
||||||
|
|||||||
Reference in New Issue
Block a user