starting preparing the graph class for a slight rework.
[AROS.git] / workbench / classes / zune / graph / graph.c
blob6023ba1f2a5a233ca685f2261ce130a32fd0d9ff
1 /*
2 Copyright © 2017, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
7 #include <aros/debug.h>
9 #define MUIMASTER_YES_INLINE_STDARG
11 #include <exec/types.h>
12 #include <utility/date.h>
14 #include <aros/asmcall.h>
16 #include <proto/alib.h>
17 #include <proto/muimaster.h>
18 #include <proto/graphics.h>
19 #include <proto/intuition.h>
20 #include <proto/utility.h>
21 #include <proto/timer.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <math.h>
27 #include "graph.h"
28 #include "graph_intern.h"
30 IPTR Graph__UpdateSourceArray(struct Graph_DATA *data, IPTR count)
32 struct Graph_SourceDATA *newSourceArray = data->graph_Sources;
34 D(bug("[Graph] %s(%d)\n", __func__, count);)
36 if (data->graph_SourceCount != count)
38 IPTR copycnt;
40 if (count > data->graph_SourceCount)
41 copycnt = data->graph_SourceCount;
42 else
43 copycnt = count;
45 newSourceArray = AllocMem(sizeof(struct Graph_SourceDATA) * count, MEMF_ANY);
46 if (newSourceArray)
49 if (data->graph_Sources)
51 CopyMem(data->graph_Sources, newSourceArray, sizeof(struct Graph_SourceDATA) * copycnt);
52 FreeMem(data->graph_Sources, sizeof(struct Graph_SourceDATA) * data->graph_SourceCount);
55 if (count > data->graph_SourceCount)
57 D(bug("[Graph] %s: initializing new source\n", __func__);)
58 memset(&newSourceArray[count - 1], 0, sizeof(struct Graph_SourceDATA));
59 newSourceArray[count - 1].gs_PlotPen = -1;
60 newSourceArray[count - 1].gs_PlotFillPen = -1;
61 if (data->graph_EntryCount > 0)
62 newSourceArray[count - 1].gs_Entries = AllocMem(sizeof(IPTR) * data->graph_EntryCount, MEMF_CLEAR|MEMF_ANY);
65 data->graph_Sources = newSourceArray;
66 data->graph_SourceCount = count;
70 return (IPTR)newSourceArray;
73 IPTR Graph__UpdateSourceEntries(struct Graph_DATA *data, IPTR sourceNo, IPTR count)
75 struct Graph_SourceDATA *dataSource = NULL;
77 D(bug("[Graph] %s(%d:%d)\n", __func__, sourceNo, count);)
79 if (count > data->graph_EntryCount)
81 IPTR *newEntries;
83 dataSource = &data->graph_Sources[sourceNo];
85 newEntries = AllocMem(sizeof(IPTR) * count, MEMF_ANY);
86 if (newEntries)
88 if (dataSource->gs_Entries)
90 CopyMem(dataSource->gs_Entries, newEntries, sizeof(IPTR) * data->graph_EntryCount);
91 FreeMem(dataSource->gs_Entries, sizeof(IPTR) * data->graph_EntryCount);
93 dataSource->gs_Entries = newEntries;
97 return (IPTR)dataSource;
100 void Graph__FreeInfoText(Class *cl, Object *obj)
102 struct Graph_DATA *data = INST_DATA(cl, obj);
103 struct Node *infoLine, *tmp;
105 D(bug("[Graph] %s()\n", __func__);)
107 ForeachNodeSafe(&data->graph_InfoText, infoLine, tmp)
109 D(bug("[Graph] %s: Deleting old infotext line @ 0x%p - '%s'\n", __func__, infoLine, infoLine->ln_Name);)
110 Remove(infoLine);
111 FreeVec(infoLine);
113 data->graph_ITHeight = 0;
116 IPTR Graph__ParseInfoText(Class *cl, Object *obj, char *infoTxt)
118 struct Graph_DATA *data = INST_DATA(cl, obj);
120 int i, srcLen, start = 0;
121 struct Node *infoLine;
123 D(bug("[Graph] %s(0x%p)\n", __func__, infoTxt);)
125 Graph__FreeInfoText(cl, obj);
127 if (infoTxt)
129 srcLen = strlen(infoTxt);
131 for (i = 0; i < (srcLen + 1); i ++)
133 if (((i - start) > 0) && (infoTxt[i] == '\n') || (infoTxt[i] == '\0'))
135 infoLine = (struct Node *)AllocVec(sizeof(struct Node) + 1 + (i - start), MEMF_ANY|MEMF_CLEAR);
136 infoLine->ln_Name = (char *)&infoLine[1];
138 CopyMem(&infoTxt[start], infoLine->ln_Name, (i - start));
140 D(bug("[Graph] %s: New infotext line @ 0x%p - '%s'\n", __func__, infoLine, infoLine->ln_Name);)
141 AddTail(&data->graph_InfoText, infoLine);
143 data->graph_ITHeight += 1;
144 start = i + 1;
148 D(bug("[Graph] %s: InfoText> %d lines\n", __func__, data->graph_ITHeight);)
149 return data->graph_ITHeight;
152 /*** Methods ****************************************************************/
153 IPTR Graph__OM_NEW(Class *cl, Object *obj, struct opSet *msg)
155 struct Graph_DATA *data;
157 D(bug("[Graph] %s()\n", __func__);)
159 obj = (Object *) DoSuperNewTags
161 cl, obj, NULL,
163 MUIA_InnerLeft, 4,
164 MUIA_InnerTop, 4,
165 MUIA_InnerRight, 4,
166 MUIA_InnerBottom, 4,
168 TAG_MORE, (IPTR) msg->ops_AttrList
171 if (obj)
173 data = INST_DATA(cl, obj);
175 NEWLIST(&data->graph_InfoText);
176 data->graph_ITHeight = 0;
178 data->graph_RastPort = NULL;
180 data->graph_Flags = 0;
181 data->graph_BackPen = -1;
182 data->graph_AxisPen = -1;
183 data->graph_SegmentPen = -1;
185 /* default segment size ... */
186 data->graph_SegmentSize = 10;
188 /* We always have atleast one source .. */
189 Graph__UpdateSourceArray(data, 1);
191 data->ihn.ihn_Flags = MUIIHNF_TIMER;
192 data->ihn.ihn_Method = MUIM_Graph_Timer;
193 data->ihn.ihn_Object = obj;
194 data->ihn.ihn_Millis = 1000;
196 SetAttrsA(obj, msg->ops_AttrList);
199 return (IPTR)obj;
202 IPTR Graph__OM_DISPOSE(Class *cl, Object *obj, Msg msg)
204 struct Graph_DATA *data = INST_DATA(cl, obj);
205 int i;
207 D(bug("[Graph] %s()\n", __func__);)
209 if (data->graph_SourceCount > 0)
211 if (data->graph_EntryCount > 0)
213 for (i = 0; i < data->graph_SourceCount; i ++)
215 FreeMem(data->graph_Sources[i].gs_Entries, sizeof(IPTR) * data->graph_EntryCount);
218 FreeMem(data->graph_Sources, sizeof(struct Graph_SourceDATA) * data->graph_SourceCount);
221 Graph__FreeInfoText(cl, obj);
223 return DoSuperMethodA(cl, obj, msg);
227 IPTR Graph__OM_SET(Class *cl, Object *obj, struct opSet *msg)
229 struct Graph_DATA *data = INST_DATA(cl, obj);
230 struct TagItem *tags = msg->ops_AttrList;
231 struct TagItem *tag;
232 BOOL redraw = FALSE;
234 D(bug("[Graph] %s()\n", __func__);)
236 while ((tag = NextTagItem(&tags)) != NULL)
238 switch(tag->ti_Tag)
240 /* Aggreagte mode plots the sum of source entries/no of sources */
241 case MUIA_Graph_Aggregate:
242 data->graph_Flags &= ~GRAPHF_AGGR;
243 if (tag->ti_Data)
244 data->graph_Flags |= GRAPHF_AGGR;
245 break;
247 /* Set the info text to display */
248 case MUIA_Graph_InfoText:
249 Graph__ParseInfoText(cl, obj, (char *)tag->ti_Data);
250 redraw = TRUE;
251 break;
253 /* Set the input value ceiling and stepping */
254 case MUIA_Graph_ValueCeiling:
255 data->graph_ValCeiling = tag->ti_Data;
256 break;
258 case MUIA_Graph_ValueStep:
259 data->graph_ValStepping = tag->ti_Data;
260 break;
262 /* Set the period ceiling and stepping */
263 case MUIA_Graph_PeriodCeiling:
264 data->graph_PeriodCeiling = tag->ti_Data;
265 break;
267 case MUIA_Graph_PeriodStep:
268 data->graph_PeriodStepping = tag->ti_Data;
269 break;
271 /* Set or turn off periodic update mode */
272 case MUIA_Graph_PeriodInterval:
273 if (tag->ti_Data)
275 data->graph_Flags |= GRAPHF_PERIODIC;
276 data->ihn.ihn_Millis = tag->ti_Data;
277 if ((data->graph_Flags & GRAPHF_SETUP) && !(data->graph_Flags & GRAPHF_HANDLER))
279 data->graph_Flags |= GRAPHF_HANDLER;
280 DoMethod(_app(obj), MUIM_Application_AddInputHandler, (IPTR) &data->ihn);
283 else
285 data->graph_Flags &= ~GRAPHF_PERIODIC;
286 if ((data->graph_Flags & GRAPHF_SETUP) && (data->graph_Flags & GRAPHF_HANDLER))
288 DoMethod(_app(obj), MUIM_Application_RemInputHandler, (IPTR) &data->ihn);
289 data->graph_Flags &= ~GRAPHF_HANDLER;
292 break;
294 /* Set or turn off Fixed entry count mode */
295 case MUIA_Graph_EntryCount:
296 if (tag->ti_Data)
298 int i;
299 for (i = 0; i < data->graph_SourceCount; i ++)
301 Graph__UpdateSourceEntries(data, i, tag->ti_Data);
303 data->graph_EntryCount = tag->ti_Data;
304 data->graph_Flags |= GRAPHF_FIXEDLEN;
306 else
308 data->graph_Flags &= ~GRAPHF_FIXEDLEN;
310 break;
314 if (redraw)
315 MUI_Redraw(obj, MADF_DRAWUPDATE);
317 return DoSuperMethodA(cl, obj, (Msg)msg);
321 IPTR Graph__OM_GET(Class *cl, Object *obj, struct opGet *msg)
323 struct Graph_DATA *data = INST_DATA(cl, obj);
324 IPTR retval = TRUE;
326 D(bug("[Graph] %s()\n", __func__);)
328 switch(msg->opg_AttrID)
330 case MUIA_Graph_ValueCeiling:
331 *(msg->opg_Storage) = data->graph_ValCeiling;
332 break;
334 case MUIA_Graph_EntryCount:
335 *(msg->opg_Storage) = data->graph_EntryCount;
336 break;
338 case MUIA_Graph_PeriodInterval:
339 *(msg->opg_Storage) = data->ihn.ihn_Millis;
340 break;
342 default:
343 retval = DoSuperMethodA(cl, obj, (Msg)msg);
344 break;
347 return retval;
350 IPTR Graph__MUIM_Setup(Class *cl, Object *obj, struct MUIP_Setup *msg)
352 struct Graph_DATA *data = INST_DATA(cl, obj);
354 D(bug("[Graph] %s()\n", __func__);)
356 if (!DoSuperMethodA(cl, obj, (Msg)msg)) return FALSE;
358 if ((data->graph_Flags & GRAPHF_PERIODIC) && !(data->graph_Flags & GRAPHF_HANDLER))
360 data->graph_Flags |= GRAPHF_HANDLER;
361 DoMethod(_app(obj), MUIM_Application_AddInputHandler, (IPTR) &data->ihn);
364 data->graph_BackPen = ObtainBestPen(_screen(obj)->ViewPort.ColorMap,
365 0xF2F2F2F2,
366 0xF8F8F8F8,
367 0xFAFAFAFA,
368 OBP_Precision, PRECISION_GUI,
369 OBP_FailIfBad, FALSE,
370 TAG_DONE);
372 data->graph_AxisPen = ObtainBestPen(_screen(obj)->ViewPort.ColorMap,
373 0x7A7A7A7A,
374 0xC5C5C5C5,
375 0xDEDEDEDE,
376 OBP_Precision, PRECISION_GUI,
377 OBP_FailIfBad, FALSE,
378 TAG_DONE);
380 data->graph_SegmentPen = ObtainBestPen(_screen(obj)->ViewPort.ColorMap,
381 0x85858585,
382 0xD3D3D3D3,
383 0xEDEDEDED,
384 OBP_Precision, PRECISION_GUI,
385 OBP_FailIfBad, FALSE,
386 TAG_DONE);
388 data->graph_Flags |= GRAPHF_SETUP;
390 return TRUE;
394 IPTR Graph__MUIM_Cleanup(Class *cl, Object *obj, struct MUIP_Cleanup *msg)
396 struct Graph_DATA *data = INST_DATA(cl, obj);
398 D(bug("[Graph] %s()\n", __func__);)
400 data->graph_Flags &= ~GRAPHF_SETUP;
402 if (data->graph_SegmentPen != -1)
404 ReleasePen(_screen(obj)->ViewPort.ColorMap, data->graph_SegmentPen);
405 data->graph_SegmentPen = -1;
408 if (data->graph_AxisPen != -1)
410 ReleasePen(_screen(obj)->ViewPort.ColorMap, data->graph_AxisPen);
411 data->graph_AxisPen = -1;
414 if (data->graph_BackPen != -1)
416 ReleasePen(_screen(obj)->ViewPort.ColorMap, data->graph_BackPen);
417 data->graph_BackPen = -1;
420 if ((data->graph_Flags & GRAPHF_PERIODIC) && (data->graph_Flags & GRAPHF_HANDLER))
422 DoMethod(_app(obj), MUIM_Application_RemInputHandler, (IPTR) &data->ihn);
423 data->graph_Flags &= ~GRAPHF_HANDLER;
426 return DoSuperMethodA(cl, obj, (Msg)msg);
430 IPTR Graph__MUIM_AskMinMax(Class *cl, Object *obj, struct MUIP_AskMinMax *msg)
432 struct Graph_DATA *data = INST_DATA(cl, obj);
433 UWORD nominalsize = (data->graph_SegmentSize * 10);
435 bug("[Graph] %s()\n", __func__);
437 DoSuperMethodA(cl, obj, (Msg)msg);
439 msg->MinMaxInfo->MinWidth += nominalsize;
440 msg->MinMaxInfo->MinHeight += nominalsize;
441 msg->MinMaxInfo->DefWidth += nominalsize;
442 msg->MinMaxInfo->DefHeight += nominalsize;
443 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
444 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
446 return TRUE;
449 IPTR Graph__MUIM_Draw(Class *cl, Object *obj, struct MUIP_Draw *msg)
451 struct Graph_DATA *data = INST_DATA(cl, obj);
452 struct Graph_SourceDATA *sourceData;
453 struct Region *region;
454 struct Node *infoLine;
455 struct RastPort *renderPort;
456 struct Rectangle rect;
457 APTR clip = NULL;
458 UWORD pos, offset = 0, src, objHeight;
460 D(bug("[Graph] %s()\n", __func__);)
462 if (data->graph_Flags & GRAPHF_FIXEDLEN)
463 data->graph_SegmentSize = (_right(obj) - _left(obj) )/ data->graph_EntryCount;
465 rect.MinX = _left(obj);
466 rect.MinY = _top(obj);
467 rect.MaxX = _right(obj);
468 rect.MaxY = _bottom(obj);
470 region = NewRegion();
471 if (region)
473 OrRectRegion(region, &rect);
475 clip = MUI_AddClipRegion(muiRenderInfo(obj), region);
478 DoSuperMethodA(cl, obj, (Msg)msg);
480 /* Render our graph.. */
481 if ((msg->flags & (MADF_DRAWOBJECT | MADF_DRAWUPDATE)))
483 if (data->graph_RastPort)
485 renderPort = data->graph_RastPort;
486 rect.MinX = 0;
487 rect.MinY = 0;
488 rect.MaxX = _right(obj) - _left(obj);
489 rect.MaxY = _bottom(obj) - _top(obj);
491 else
492 renderPort = _rp(obj);
494 objHeight = rect.MaxY - rect.MinY;
496 if ((data->graph_Flags & GRAPHF_PERIODIC) && (data->graph_Flags & GRAPHF_FIXEDLEN))
497 offset = data->graph_Tick;
500 bug("[Graph] %s: height %d, segemnt size %d\n", __func__, objHeight, data->graph_SegmentSize);
501 bug("[Graph] %s: offset %d\n", __func__, offset);
504 // First fill the background ..
505 SetAPen(renderPort, data->graph_BackPen);
506 RectFill(renderPort, rect.MinX, rect.MinY, rect.MaxX, rect.MaxY);
508 // Draw the segment divisions..
509 SetAPen(renderPort, data->graph_SegmentPen);
510 for (pos = rect.MinX; pos <= (rect.MaxX + data->graph_SegmentSize); pos += data->graph_SegmentSize)
512 Move(renderPort, pos - offset, rect.MinY);
513 Draw(renderPort, pos - offset, rect.MaxY);
515 for (pos = rect.MaxY; pos >= rect.MinY; pos -= data->graph_SegmentSize)
517 Move(renderPort, rect.MinX, pos);
518 Draw(renderPort, rect.MaxX, pos);
521 // Draw the Axis..
522 SetAPen(renderPort, data->graph_AxisPen);
523 Move(renderPort, rect.MinX, rect.MinY);
524 Draw(renderPort, rect.MaxX, rect.MinY);
525 Draw(renderPort, rect.MaxX, rect.MaxY);
526 Draw(renderPort, rect.MinX, rect.MaxY);
527 Draw(renderPort, rect.MinX, rect.MinY);
529 // Plot the entries..
530 if (data->graph_Sources)
532 for (src = 0; src < data->graph_SourceCount; src ++)
534 sourceData = &data->graph_Sources[src];
536 SetAPen(renderPort, data->graph_Sources[src].gs_PlotPen);
537 Move(renderPort, rect.MinX - offset, rect.MaxY);
539 for (pos = 1; pos < data->graph_EntryPtr; pos++)
541 UWORD ypos = (objHeight * sourceData->gs_Entries[pos])/ data->graph_ValCeiling;
542 D(bug("[Graph] %s: YPos = %d\n", __func__, ypos);)
543 Draw(renderPort,
544 rect.MinX + (pos * data->graph_SegmentSize) - offset,
545 rect.MaxY - ypos);
550 // Add the InfoText
551 pos = ((rect.MinY + rect.MaxY) /2) - ((_font(obj)->tf_YSize * data->graph_ITHeight) /2) + _font(obj)->tf_Baseline;
553 ForeachNode(&data->graph_InfoText, infoLine)
555 UWORD txtLen = strlen(infoLine->ln_Name);
556 UWORD textWidth = TextLength(renderPort, infoLine->ln_Name, txtLen);
558 D(bug("[Graph] %s: pos = %d, strlen = %d, wid = %d\n", __func__, pos, txtLen, textWidth);)
560 if (textWidth > 0)
562 SetAPen(renderPort, _pens(obj)[MPEN_TEXT]);
563 Move(renderPort, ((rect.MinX + rect.MaxX) /2) - (textWidth / 2), pos);
564 Text(renderPort, (CONST_STRPTR)infoLine->ln_Name, txtLen);
565 pos += _font(obj)->tf_YSize;
568 if (renderPort != _rp(obj))
570 BltBitMapRastPort(
571 renderPort->BitMap,
574 _rp(obj),
575 _left(obj),
576 _top(obj),
577 _right(obj) - _left(obj) + 1,
578 _bottom(obj) - _top(obj) + 1,
579 0x0C0 );
582 if (region)
584 MUI_RemoveClipRegion(muiRenderInfo(obj), clip);
587 D(bug("[Graph] %s: done\n", __func__);)
589 return 0;
592 IPTR Graph__MUIM_Graph_GetSourceHandle(Class *cl, Object *obj, struct MUIP_Graph_GetSourceHandle *msg)
594 struct Graph_DATA *data;
595 IPTR retVal = 0;
597 D(bug("[Graph] %s(%d)\n", __func__, msg->SourceNo);)
599 data = INST_DATA(cl, obj);
600 if (msg->SourceNo >= data->graph_SourceCount)
601 Graph__UpdateSourceArray(data, (msg->SourceNo + 1));
603 retVal = (IPTR)&data->graph_Sources[msg->SourceNo];
605 return retVal;
608 IPTR Graph__MUIM_Graph_SetSourceAttrib(Class *cl, Object *obj, struct MUIP_Graph_SetSourceAttrib *msg)
610 struct Graph_SourceDATA *dataSource = (struct Graph_SourceDATA *)msg->SourceHandle;
612 D(bug("[Graph] %s()\n", __func__);)
614 switch (msg->Attrib)
616 case MUIV_Graph_Source_ReadHook:
617 dataSource->gs_ReadHook = (struct Hook *)msg->AttribVal;
618 break;
619 case MUIV_Graph_Source_Pen:
620 dataSource->gs_PlotPen = (WORD)msg->AttribVal;
621 break;
622 case MUIV_Graph_Source_FillPen:
623 dataSource->gs_PlotFillPen = (WORD)msg->AttribVal;
624 break;
627 return 0;
630 IPTR Graph__MUIM_Graph_Reset(Class *cl, Object *obj, Msg msg)
632 D(bug("[Graph] %s()\n", __func__);)
634 return 0;
637 IPTR Graph__MUIM_Graph_Timer(Class *cl, Object *obj, Msg msg)
639 struct Graph_DATA *data;
640 int i;
642 D(bug("[Graph] %s()\n", __func__);)
644 data = INST_DATA(cl, obj);
646 if (data->graph_Tick++ == data->graph_SegmentSize)
647 data->graph_Tick = 0;
649 if (data->graph_Flags & GRAPHF_PERIODIC)
651 if (data->graph_SourceCount > 0)
653 BOOL updateEntries = FALSE, updated = FALSE, move = FALSE;
655 if (data->graph_Flags & GRAPHF_FIXEDLEN)
657 if (data->graph_EntryPtr >= data->graph_EntryCount)
659 data->graph_EntryPtr = data->graph_EntryCount - 1;
660 move = TRUE;
663 else
665 if (!(data->graph_EntryCount) || (data->graph_EntryPtr >= data->graph_EntryCount))
666 updateEntries = TRUE;
669 D(bug("[Graph] %s: reading entry %d\n", __func__, data->graph_EntryPtr);)
671 for (i = 0; i < data->graph_SourceCount; i ++)
673 if (data->graph_Sources[i].gs_ReadHook)
675 if (updateEntries)
677 Graph__UpdateSourceEntries(data, i, (data->graph_EntryPtr + 1));
678 updated = TRUE;
681 if (move)
683 CopyMem(&data->graph_Sources[i].gs_Entries[1], &data->graph_Sources[i].gs_Entries[0], sizeof(IPTR) * (data->graph_EntryCount - 1));
686 D(bug("[Graph] %s: source %d entries @ 0x%p\n", __func__, i, data->graph_Sources[i].gs_Entries);)
687 CALLHOOKPKT(data->graph_Sources[i].gs_ReadHook,
688 (APTR)&data->graph_Sources[i].gs_Entries[data->graph_EntryPtr],
689 data->graph_Sources[i].gs_ReadHook->h_Data);
692 if (updated)
693 data->graph_EntryCount++;
694 data->graph_EntryPtr++;
697 SET(obj, MUIA_Graph_PeriodicTick, TRUE);
700 return 0;