make sure to draw all segments
[AROS.git] / workbench / classes / zune / graph / graph.c
blob5f8ec2e87b28de6e89bc610b4233337620e80056
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 IPTR Graph__SumValues(IPTR *start, int count)
154 IPTR retVal = 0;
155 int i;
156 for (i = 0; i < count; i++)
158 retVal += start[i];
160 if (retVal > 0)
161 retVal /= count;
162 return retVal;
165 /*** Methods ****************************************************************/
166 IPTR Graph__OM_NEW(Class *cl, Object *obj, struct opSet *msg)
168 struct Graph_DATA *data;
170 D(bug("[Graph] %s()\n", __func__);)
172 obj = (Object *) DoSuperNewTags
174 cl, obj, NULL,
176 MUIA_InnerLeft, 4,
177 MUIA_InnerTop, 4,
178 MUIA_InnerRight, 4,
179 MUIA_InnerBottom, 4,
181 TAG_MORE, (IPTR) msg->ops_AttrList
184 if (obj)
186 data = INST_DATA(cl, obj);
188 NEWLIST(&data->graph_InfoText);
189 data->graph_ITHeight = 0;
191 data->graph_RastPort = NULL;
193 data->graph_Flags = (GRAPHF_DRAWAXIS|GRAPHF_DRAWSEGS);
194 data->graph_BackPen = -1;
195 data->graph_AxisPen = -1;
196 data->graph_SegmentPen = -1;
198 /* We always have atleast one source .. */
199 Graph__UpdateSourceArray(data, 1);
201 data->ihn.ihn_Flags = MUIIHNF_TIMER;
202 data->ihn.ihn_Method = MUIM_Graph_Timer;
203 data->ihn.ihn_Object = obj;
204 data->ihn.ihn_Millis = 1000;
206 data->graph_PeriodCeiling = data->ihn.ihn_Millis * 10;
207 data->graph_PeriodStepping = data->ihn.ihn_Millis;
209 data->graph_ValCeiling = 100;
210 data->graph_ValStepping = 10;
212 SetAttrsA(obj, msg->ops_AttrList);
215 return (IPTR)obj;
218 IPTR Graph__OM_DISPOSE(Class *cl, Object *obj, Msg msg)
220 struct Graph_DATA *data = INST_DATA(cl, obj);
221 int i;
223 D(bug("[Graph] %s()\n", __func__);)
225 if (data->graph_SourceCount > 0)
227 if (data->graph_EntryCount > 0)
229 for (i = 0; i < data->graph_SourceCount; i ++)
231 FreeMem(data->graph_Sources[i].gs_Entries, sizeof(IPTR) * data->graph_EntryCount);
234 FreeMem(data->graph_Sources, sizeof(struct Graph_SourceDATA) * data->graph_SourceCount);
237 Graph__FreeInfoText(cl, obj);
239 return DoSuperMethodA(cl, obj, msg);
243 IPTR Graph__OM_SET(Class *cl, Object *obj, struct opSet *msg)
245 struct Graph_DATA *data = INST_DATA(cl, obj);
246 struct TagItem *tags = msg->ops_AttrList;
247 struct TagItem *tag;
248 BOOL redraw = FALSE;
250 D(bug("[Graph] %s()\n", __func__);)
252 while ((tag = NextTagItem(&tags)) != NULL)
254 switch(tag->ti_Tag)
256 /* Aggreagte mode plots the sum of source entries/no of sources */
257 case MUIA_Graph_Aggregate:
258 data->graph_Flags &= ~GRAPHF_AGGR;
259 if (tag->ti_Data)
260 data->graph_Flags |= GRAPHF_AGGR;
261 break;
263 /* Set the info text to display */
264 case MUIA_Graph_InfoText:
265 Graph__ParseInfoText(cl, obj, (char *)tag->ti_Data);
266 redraw = TRUE;
267 break;
269 /* Set the input value ceiling and stepping */
270 case MUIA_Graph_ValueCeiling:
271 data->graph_ValCeiling = tag->ti_Data;
272 break;
274 case MUIA_Graph_ValueStep:
275 data->graph_ValStepping = tag->ti_Data;
276 break;
278 /* Set the period ceiling and stepping */
279 case MUIA_Graph_PeriodCeiling:
280 data->graph_PeriodCeiling = tag->ti_Data;
281 break;
283 case MUIA_Graph_PeriodStep:
284 data->graph_PeriodStepping = tag->ti_Data;
285 break;
287 /* Set or turn off periodic update mode */
288 case MUIA_Graph_PeriodInterval:
289 if (tag->ti_Data)
291 data->graph_Flags |= GRAPHF_PERIODIC;
292 data->ihn.ihn_Millis = tag->ti_Data;
293 SET(obj, MUIA_Graph_EntryCount, (data->graph_PeriodCeiling/ data->ihn.ihn_Millis));
294 if ((data->graph_Flags & GRAPHF_SETUP) && !(data->graph_Flags & GRAPHF_HANDLER))
296 data->graph_Flags |= GRAPHF_HANDLER;
297 DoMethod(_app(obj), MUIM_Application_AddInputHandler, (IPTR) &data->ihn);
300 else
302 data->graph_Flags &= ~GRAPHF_PERIODIC;
303 if ((data->graph_Flags & GRAPHF_SETUP) && (data->graph_Flags & GRAPHF_HANDLER))
305 DoMethod(_app(obj), MUIM_Application_RemInputHandler, (IPTR) &data->ihn);
306 data->graph_Flags &= ~GRAPHF_HANDLER;
309 break;
311 /* Set or turn off Fixed entry count mode */
312 case MUIA_Graph_EntryCount:
313 if (tag->ti_Data)
315 int i;
316 for (i = 0; i < data->graph_SourceCount; i ++)
318 Graph__UpdateSourceEntries(data, i, tag->ti_Data);
320 data->graph_EntryCount = tag->ti_Data;
321 data->graph_Flags |= GRAPHF_FIXEDLEN;
323 else
325 data->graph_Flags &= ~GRAPHF_FIXEDLEN;
327 break;
331 if (redraw)
332 MUI_Redraw(obj, MADF_DRAWUPDATE);
334 return DoSuperMethodA(cl, obj, (Msg)msg);
338 IPTR Graph__OM_GET(Class *cl, Object *obj, struct opGet *msg)
340 struct Graph_DATA *data = INST_DATA(cl, obj);
341 IPTR retval = TRUE;
343 D(bug("[Graph] %s()\n", __func__);)
345 switch(msg->opg_AttrID)
347 case MUIA_Graph_ValueCeiling:
348 *(msg->opg_Storage) = data->graph_ValCeiling;
349 break;
351 case MUIA_Graph_EntryCount:
352 *(msg->opg_Storage) = data->graph_EntryCount;
353 break;
355 case MUIA_Graph_PeriodInterval:
356 *(msg->opg_Storage) = data->ihn.ihn_Millis;
357 break;
359 default:
360 retval = DoSuperMethodA(cl, obj, (Msg)msg);
361 break;
364 return retval;
367 IPTR Graph__MUIM_Setup(Class *cl, Object *obj, struct MUIP_Setup *msg)
369 struct Graph_DATA *data = INST_DATA(cl, obj);
370 int i;
372 D(bug("[Graph] %s()\n", __func__);)
374 if (!DoSuperMethodA(cl, obj, (Msg)msg)) return FALSE;
376 if ((data->graph_Flags & GRAPHF_PERIODIC) && !(data->graph_Flags & GRAPHF_HANDLER))
378 data->graph_Flags |= GRAPHF_HANDLER;
379 DoMethod(_app(obj), MUIM_Application_AddInputHandler, (IPTR) &data->ihn);
382 data->graph_BackPen = ObtainBestPen(_screen(obj)->ViewPort.ColorMap,
383 0xF2F2F2F2,
384 0xF8F8F8F8,
385 0xFAFAFAFA,
386 OBP_Precision, PRECISION_GUI,
387 OBP_FailIfBad, FALSE,
388 TAG_DONE);
390 data->graph_AxisPen = ObtainBestPen(_screen(obj)->ViewPort.ColorMap,
391 0x7A7A7A7A,
392 0xC5C5C5C5,
393 0xDEDEDEDE,
394 OBP_Precision, PRECISION_GUI,
395 OBP_FailIfBad, FALSE,
396 TAG_DONE);
398 data->graph_SegmentPen = ObtainBestPen(_screen(obj)->ViewPort.ColorMap,
399 0x85858585,
400 0xD3D3D3D3,
401 0xEDEDEDED,
402 OBP_Precision, PRECISION_GUI,
403 OBP_FailIfBad, FALSE,
404 TAG_DONE);
406 for (i = 0; i < data->graph_SourceCount; i ++)
408 ULONG *penSrc;
409 if (((penSrc = (ULONG *)data->graph_Sources[i].gs_PlotFillPenSrc) != NULL) &&
410 (data->graph_Sources[i].gs_PlotFillPenSrc != data->graph_Sources[i].gs_PlotPenSrc))
411 data->graph_Sources[i].gs_PlotFillPen = ObtainBestPen(_screen(obj)->ViewPort.ColorMap,
412 penSrc[0],
413 penSrc[1],
414 penSrc[2],
415 OBP_Precision, PRECISION_GUI,
416 OBP_FailIfBad, FALSE,
417 TAG_DONE);
419 if ((penSrc = (ULONG *)data->graph_Sources[i].gs_PlotPenSrc) != NULL)
420 data->graph_Sources[i].gs_PlotPen = ObtainBestPen(_screen(obj)->ViewPort.ColorMap,
421 penSrc[0],
422 penSrc[1],
423 penSrc[2],
424 OBP_Precision, PRECISION_GUI,
425 OBP_FailIfBad, FALSE,
426 TAG_DONE);
429 data->graph_Flags |= GRAPHF_SETUP;
431 return TRUE;
435 IPTR Graph__MUIM_Cleanup(Class *cl, Object *obj, struct MUIP_Cleanup *msg)
437 struct Graph_DATA *data = INST_DATA(cl, obj);
438 int i;
440 D(bug("[Graph] %s()\n", __func__);)
442 data->graph_Flags &= ~GRAPHF_SETUP;
444 if (data->graph_SegmentPen != -1)
446 ReleasePen(_screen(obj)->ViewPort.ColorMap, data->graph_SegmentPen);
447 data->graph_SegmentPen = -1;
450 if (data->graph_AxisPen != -1)
452 ReleasePen(_screen(obj)->ViewPort.ColorMap, data->graph_AxisPen);
453 data->graph_AxisPen = -1;
456 if (data->graph_BackPen != -1)
458 ReleasePen(_screen(obj)->ViewPort.ColorMap, data->graph_BackPen);
459 data->graph_BackPen = -1;
462 for (i = 0; i < data->graph_SourceCount; i ++)
464 if ((data->graph_Sources[i].gs_PlotFillPen != -1) &&
465 (data->graph_Sources[i].gs_PlotFillPen != data->graph_Sources[i].gs_PlotPen))
466 ReleasePen(_screen(obj)->ViewPort.ColorMap, data->graph_Sources[i].gs_PlotFillPen);
467 if (data->graph_Sources[i].gs_PlotPen != -1)
468 ReleasePen(_screen(obj)->ViewPort.ColorMap, data->graph_Sources[i].gs_PlotPen);
471 if ((data->graph_Flags & GRAPHF_PERIODIC) && (data->graph_Flags & GRAPHF_HANDLER))
473 DoMethod(_app(obj), MUIM_Application_RemInputHandler, (IPTR) &data->ihn);
474 data->graph_Flags &= ~GRAPHF_HANDLER;
477 return DoSuperMethodA(cl, obj, (Msg)msg);
481 IPTR Graph__MUIM_AskMinMax(Class *cl, Object *obj, struct MUIP_AskMinMax *msg)
483 struct Graph_DATA *data = INST_DATA(cl, obj);
485 D(bug("[Graph] %s()\n", __func__);)
487 DoSuperMethodA(cl, obj, (Msg)msg);
489 msg->MinMaxInfo->MinWidth += (data->graph_PeriodCeiling / data->graph_PeriodStepping) * 2;
490 msg->MinMaxInfo->MinHeight += (data->graph_ValCeiling / data->graph_ValStepping) * 2;
491 msg->MinMaxInfo->DefWidth += (data->graph_PeriodCeiling / data->graph_PeriodStepping) * 10;
492 msg->MinMaxInfo->DefHeight += (data->graph_ValCeiling / data->graph_ValStepping) * 10;
493 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
494 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
496 return TRUE;
499 IPTR Graph__MUIM_Draw(Class *cl, Object *obj, struct MUIP_Draw *msg)
501 struct Graph_DATA *data = INST_DATA(cl, obj);
502 struct Graph_SourceDATA *sourceData;
503 struct Region *region;
504 struct Node *infoLine;
505 struct RastPort *renderPort;
506 struct Rectangle rect;
507 APTR clip = NULL;
508 UWORD pos, span = 1, offset = 0, src, objHeight, objWidth;
510 D(bug("[Graph] %s()\n", __func__);)
512 rect.MinX = _left(obj);
513 rect.MinY = _top(obj);
514 rect.MaxX = _right(obj);
515 rect.MaxY = _bottom(obj);
517 region = NewRegion();
518 if (region)
520 OrRectRegion(region, &rect);
522 clip = MUI_AddClipRegion(muiRenderInfo(obj), region);
525 DoSuperMethodA(cl, obj, (Msg)msg);
527 /* Render our graph.. */
528 if ((msg->flags & (MADF_DRAWOBJECT | MADF_DRAWUPDATE)))
530 if (data->graph_RastPort)
532 renderPort = data->graph_RastPort;
533 rect.MinX = 0;
534 rect.MinY = 0;
535 rect.MaxX = _right(obj) - _left(obj);
536 rect.MaxY = _bottom(obj) - _top(obj);
538 else
539 renderPort = _rp(obj);
541 objHeight = rect.MaxY - rect.MinY + 1;
542 objWidth = rect.MaxX - rect.MinX + 1;
544 data->graph_PeriodSize = ((float)objWidth / data->graph_PeriodCeiling) * data->ihn.ihn_Millis;
546 if (data->graph_Flags & GRAPHF_PERIODIC)
547 offset = data->graph_Tick / data->ihn.ihn_Millis;
550 bug("[Graph] %s: dimensions %d,%d\n", __func__, objWidth, objHeight);
551 bug("[Graph] %s: period size %d, span %d\n", __func__, (int)data->graph_PeriodSize, span);
552 bug("[Graph] %s: offset %d\n", __func__, offset);
555 // First fill the background ..
556 SetAPen(renderPort, data->graph_BackPen);
557 RectFill(renderPort, rect.MinX, rect.MinY, rect.MaxX, rect.MaxY);
559 if (data->graph_Flags & GRAPHF_DRAWSEGS)
561 // Draw the segment divisions..
562 SetAPen(renderPort, data->graph_SegmentPen);
563 data->graph_SegmentSize = (objWidth * data->graph_PeriodStepping) / data->graph_PeriodCeiling;
564 if (data->graph_SegmentSize < 2.0)
565 data->graph_SegmentSize = 2.0;
566 for (pos = 0; pos <= ((data->graph_PeriodCeiling / data->graph_PeriodStepping) + 1); pos++)
568 Move(renderPort, rect.MinX + (pos * data->graph_SegmentSize) - (offset * data->graph_PeriodSize), rect.MinY);
569 Draw(renderPort, rect.MinX + (pos * data->graph_SegmentSize) - (offset * data->graph_PeriodSize), rect.MaxY);
571 data->graph_SegmentSize = (objHeight * data->graph_ValStepping) / data->graph_ValCeiling;
572 if (data->graph_SegmentSize < 2.0)
573 data->graph_SegmentSize = 2.0;
574 for (pos = rect.MaxY; pos >= rect.MinY; pos -= data->graph_SegmentSize)
576 Move(renderPort, rect.MinX, pos);
577 Draw(renderPort, rect.MaxX, pos);
581 if (data->graph_Flags & GRAPHF_DRAWAXIS)
583 // Draw the Axis..
584 SetAPen(renderPort, data->graph_AxisPen);
585 Move(renderPort, rect.MinX, rect.MinY);
586 Draw(renderPort, rect.MaxX, rect.MinY);
587 Draw(renderPort, rect.MaxX, rect.MaxY);
588 Draw(renderPort, rect.MinX, rect.MaxY);
589 Draw(renderPort, rect.MinX, rect.MinY);
592 // Plot the entries..
593 if (data->graph_Sources)
595 for (src = 0; src < data->graph_SourceCount; src ++)
597 UWORD xpos, ypos;
598 LONG start;
600 sourceData = &data->graph_Sources[src];
602 if ((start = data->graph_EntryPtr - (objWidth / data->graph_PeriodSize)) < 0)
603 start = 0;
605 ypos = (objHeight * Graph__SumValues(&sourceData->gs_Entries[start], span))/ data->graph_ValCeiling;
606 start += span;
608 if (data->graph_Flags & GRAPHF_PERIODIC)
609 xpos = rect.MaxX - (data->graph_EntryPtr * data->graph_PeriodSize);
610 else
611 xpos = rect.MinX - (offset * data->graph_PeriodSize);
613 SetAPen(renderPort, data->graph_Sources[src].gs_PlotPen);
615 if (start == 1)
616 WritePixel(renderPort, xpos, rect.MaxY - ypos);
618 Move(renderPort, xpos, rect.MaxY - ypos);
620 for (pos = start; pos < data->graph_EntryPtr; pos += span)
622 ypos = (objHeight * Graph__SumValues(&sourceData->gs_Entries[pos], span))/ data->graph_ValCeiling;
624 Draw(renderPort,
625 xpos + (pos * data->graph_PeriodSize),
626 rect.MaxY - ypos);
631 // Add the InfoText
632 pos = ((rect.MinY + rect.MaxY) /2) - ((_font(obj)->tf_YSize * data->graph_ITHeight) /2) + _font(obj)->tf_Baseline;
634 if (!IsListEmpty(&data->graph_InfoText))
635 SetFont(renderPort, _font(obj));
637 ForeachNode(&data->graph_InfoText, infoLine)
639 UWORD txtLen = strlen(infoLine->ln_Name);
640 UWORD textWidth = TextLength(renderPort, infoLine->ln_Name, txtLen);
642 D(bug("[Graph] %s: pos = %d, strlen = %d, wid = %d\n", __func__, pos, txtLen, textWidth);)
644 if (textWidth > 0)
646 SetAPen(renderPort, _pens(obj)[MPEN_TEXT]);
647 Move(renderPort, ((rect.MinX + rect.MaxX) /2) - (textWidth / 2), pos);
648 Text(renderPort, (CONST_STRPTR)infoLine->ln_Name, txtLen);
649 pos += _font(obj)->tf_YSize;
652 if (renderPort != _rp(obj))
654 BltBitMapRastPort(
655 renderPort->BitMap,
658 _rp(obj),
659 _left(obj),
660 _top(obj),
661 _right(obj) - _left(obj) + 1,
662 _bottom(obj) - _top(obj) + 1,
663 0x0C0 );
666 if (region)
668 MUI_RemoveClipRegion(muiRenderInfo(obj), clip);
671 D(bug("[Graph] %s: done\n", __func__);)
673 return 0;
676 IPTR Graph__MUIM_Graph_GetSourceHandle(Class *cl, Object *obj, struct MUIP_Graph_GetSourceHandle *msg)
678 struct Graph_DATA *data;
679 IPTR retVal = 0;
681 D(bug("[Graph] %s(%d)\n", __func__, msg->SourceNo);)
683 data = INST_DATA(cl, obj);
684 if (msg->SourceNo >= data->graph_SourceCount)
685 Graph__UpdateSourceArray(data, (msg->SourceNo + 1));
687 retVal = (IPTR)&data->graph_Sources[msg->SourceNo];
689 return retVal;
692 IPTR Graph__MUIM_Graph_SetSourceAttrib(Class *cl, Object *obj, struct MUIP_Graph_SetSourceAttrib *msg)
694 struct Graph_SourceDATA *dataSource = (struct Graph_SourceDATA *)msg->SourceHandle;
696 D(bug("[Graph] %s()\n", __func__);)
698 switch (msg->Attrib)
700 case MUIV_Graph_Source_ReadHook:
701 dataSource->gs_ReadHook = (struct Hook *)msg->AttribVal;
702 break;
703 case MUIV_Graph_Source_PenSrc:
704 dataSource->gs_PlotPenSrc = msg->AttribVal;
705 break;
706 case MUIV_Graph_Source_Pen:
707 if (dataSource->gs_PlotPen != -1)
708 ReleasePen(_screen(obj)->ViewPort.ColorMap, dataSource->gs_PlotPen);
709 dataSource->gs_PlotPen = (WORD)msg->AttribVal;
710 break;
711 case MUIV_Graph_Source_FillPenSrc:
712 dataSource->gs_PlotPen = msg->AttribVal;
713 break;
714 case MUIV_Graph_Source_FillPen:
715 if (dataSource->gs_PlotFillPen != -1)
716 ReleasePen(_screen(obj)->ViewPort.ColorMap, dataSource->gs_PlotFillPen);
717 dataSource->gs_PlotFillPen = (WORD)msg->AttribVal;
718 break;
721 return 0;
724 IPTR Graph__MUIM_Graph_Reset(Class *cl, Object *obj, Msg msg)
726 D(bug("[Graph] %s()\n", __func__);)
728 return 0;
731 IPTR Graph__MUIM_Graph_Timer(Class *cl, Object *obj, Msg msg)
733 struct Graph_DATA *data;
734 int i;
736 D(bug("[Graph] %s()\n", __func__);)
738 data = INST_DATA(cl, obj);
740 if ((data->graph_Tick += data->ihn.ihn_Millis) > data->graph_PeriodStepping)
741 data->graph_Tick -= data->graph_PeriodStepping;
743 if (data->graph_Flags & GRAPHF_PERIODIC)
745 if (data->graph_SourceCount > 0)
747 BOOL updateEntries = FALSE, updated = FALSE, move = FALSE;
749 if (data->graph_Flags & GRAPHF_FIXEDLEN)
751 if (data->graph_EntryPtr >= data->graph_EntryCount)
753 data->graph_EntryPtr = data->graph_EntryCount - 1;
754 move = TRUE;
757 else
759 if (!(data->graph_EntryCount) || (data->graph_EntryPtr >= data->graph_EntryCount))
760 updateEntries = TRUE;
763 D(bug("[Graph] %s: reading entry %d\n", __func__, data->graph_EntryPtr);)
765 for (i = 0; i < data->graph_SourceCount; i ++)
767 if (data->graph_Sources[i].gs_ReadHook)
769 if (updateEntries)
771 Graph__UpdateSourceEntries(data, i, (data->graph_EntryPtr + 1));
772 updated = TRUE;
775 if (move)
777 CopyMem(&data->graph_Sources[i].gs_Entries[1], &data->graph_Sources[i].gs_Entries[0], sizeof(IPTR) * (data->graph_EntryCount - 1));
780 D(bug("[Graph] %s: source %d entries @ 0x%p\n", __func__, i, data->graph_Sources[i].gs_Entries);)
781 CALLHOOKPKT(data->graph_Sources[i].gs_ReadHook,
782 (APTR)&data->graph_Sources[i].gs_Entries[data->graph_EntryPtr],
783 data->graph_Sources[i].gs_ReadHook->h_Data);
786 if (updated)
787 data->graph_EntryCount++;
788 data->graph_EntryPtr++;
791 SET(obj, MUIA_Graph_PeriodicTick, TRUE);
794 return 0;