2 Copyright © 2017, The AROS Development Team. All rights reserved.
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>
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
)
40 if (count
> data
->graph_SourceCount
)
41 copycnt
= data
->graph_SourceCount
;
45 newSourceArray
= AllocMem(sizeof(struct Graph_SourceDATA
) * count
, MEMF_ANY
);
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
)
83 dataSource
= &data
->graph_Sources
[sourceNo
];
85 newEntries
= AllocMem(sizeof(IPTR
) * count
, MEMF_ANY
);
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
);)
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
);
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;
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
168 TAG_MORE
, (IPTR
) msg
->ops_AttrList
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
);
202 IPTR
Graph__OM_DISPOSE(Class
*cl
, Object
*obj
, Msg msg
)
204 struct Graph_DATA
*data
= INST_DATA(cl
, obj
);
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
;
234 D(bug("[Graph] %s()\n", __func__
);)
236 while ((tag
= NextTagItem(&tags
)) != NULL
)
240 /* Aggreagte mode plots the sum of source entries/no of sources */
241 case MUIA_Graph_Aggregate
:
242 data
->graph_Flags
&= ~GRAPHF_AGGR
;
244 data
->graph_Flags
|= GRAPHF_AGGR
;
247 /* Set the info text to display */
248 case MUIA_Graph_InfoText
:
249 Graph__ParseInfoText(cl
, obj
, (char *)tag
->ti_Data
);
253 /* Set the input value ceiling and stepping */
254 case MUIA_Graph_ValueCeiling
:
255 data
->graph_ValCeiling
= tag
->ti_Data
;
258 case MUIA_Graph_ValueStep
:
259 data
->graph_ValStepping
= tag
->ti_Data
;
262 /* Set the period ceiling and stepping */
263 case MUIA_Graph_PeriodCeiling
:
264 data
->graph_PeriodCeiling
= tag
->ti_Data
;
267 case MUIA_Graph_PeriodStep
:
268 data
->graph_PeriodStepping
= tag
->ti_Data
;
271 /* Set or turn off periodic update mode */
272 case MUIA_Graph_PeriodInterval
:
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
);
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
;
294 /* Set or turn off Fixed entry count mode */
295 case MUIA_Graph_EntryCount
:
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
;
308 data
->graph_Flags
&= ~GRAPHF_FIXEDLEN
;
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
);
326 D(bug("[Graph] %s()\n", __func__
);)
328 switch(msg
->opg_AttrID
)
330 case MUIA_Graph_ValueCeiling
:
331 *(msg
->opg_Storage
) = data
->graph_ValCeiling
;
334 case MUIA_Graph_EntryCount
:
335 *(msg
->opg_Storage
) = data
->graph_EntryCount
;
338 case MUIA_Graph_PeriodInterval
:
339 *(msg
->opg_Storage
) = data
->ihn
.ihn_Millis
;
343 retval
= DoSuperMethodA(cl
, obj
, (Msg
)msg
);
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
,
368 OBP_Precision
, PRECISION_GUI
,
369 OBP_FailIfBad
, FALSE
,
372 data
->graph_AxisPen
= ObtainBestPen(_screen(obj
)->ViewPort
.ColorMap
,
376 OBP_Precision
, PRECISION_GUI
,
377 OBP_FailIfBad
, FALSE
,
380 data
->graph_SegmentPen
= ObtainBestPen(_screen(obj
)->ViewPort
.ColorMap
,
384 OBP_Precision
, PRECISION_GUI
,
385 OBP_FailIfBad
, FALSE
,
388 data
->graph_Flags
|= GRAPHF_SETUP
;
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
;
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
;
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();
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
;
488 rect
.MaxX
= _right(obj
) - _left(obj
);
489 rect
.MaxY
= _bottom(obj
) - _top(obj
);
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
);
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
);)
544 rect
.MinX
+ (pos
* data
->graph_SegmentSize
) - offset
,
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
);)
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
))
577 _right(obj
) - _left(obj
) + 1,
578 _bottom(obj
) - _top(obj
) + 1,
584 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
587 D(bug("[Graph] %s: done\n", __func__
);)
592 IPTR
Graph__MUIM_Graph_GetSourceHandle(Class
*cl
, Object
*obj
, struct MUIP_Graph_GetSourceHandle
*msg
)
594 struct Graph_DATA
*data
;
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
];
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__
);)
616 case MUIV_Graph_Source_ReadHook
:
617 dataSource
->gs_ReadHook
= (struct Hook
*)msg
->AttribVal
;
619 case MUIV_Graph_Source_Pen
:
620 dataSource
->gs_PlotPen
= (WORD
)msg
->AttribVal
;
622 case MUIV_Graph_Source_FillPen
:
623 dataSource
->gs_PlotFillPen
= (WORD
)msg
->AttribVal
;
630 IPTR
Graph__MUIM_Graph_Reset(Class
*cl
, Object
*obj
, Msg msg
)
632 D(bug("[Graph] %s()\n", __func__
);)
637 IPTR
Graph__MUIM_Graph_Timer(Class
*cl
, Object
*obj
, Msg msg
)
639 struct Graph_DATA
*data
;
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;
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
)
677 Graph__UpdateSourceEntries(data
, i
, (data
->graph_EntryPtr
+ 1));
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
);
693 data
->graph_EntryCount
++;
694 data
->graph_EntryPtr
++;
697 SET(obj
, MUIA_Graph_PeriodicTick
, TRUE
);