Upstream tarball 20080304
[amule.git] / src / OScopeCtrl.cpp
blobc3c5c4af62414a3244710aa8e03de60e972ab564
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <cmath>
27 #include <wx/dcmemory.h>
28 #include <wx/dcclient.h>
30 #include <common/Format.h>
32 #include "amule.h" // Needed for theApp
33 #include "amuleDlg.h" // Needed for CamuleDlg
34 #include "Logger.h" // Needed for AddLogLineM
35 #include "OScopeCtrl.h" // Interface declarations
36 #include "OtherFunctions.h" // Needed for CastSecondsToHM
38 BEGIN_EVENT_TABLE(COScopeCtrl,wxControl)
39 EVT_PAINT(COScopeCtrl::OnPaint)
40 EVT_SIZE(COScopeCtrl::OnSize)
41 EVT_TIMER(TIMER_OSCOPE,COScopeCtrl::OnTimer)
42 END_EVENT_TABLE()
45 COScopeCtrl::COScopeCtrl(int cntTrends, int nDecimals, StatsGraphType type, wxWindow*parent)
46 : wxControl(parent,-1, wxDefaultPosition, wxDefaultSize), timerRedraw(this, TIMER_OSCOPE)
48 COLORREF crPreset [ 16 ] = {
49 RGB( 0xFF, 0x00, 0x00 ), RGB( 0xFF, 0xC0, 0xC0 ),
50 RGB( 0xFF, 0xFF, 0x00 ), RGB( 0xFF, 0xA0, 0x00 ),
51 RGB( 0xA0, 0x60, 0x00 ), RGB( 0x00, 0xFF, 0x00 ),
52 RGB( 0x00, 0xA0, 0x00 ), RGB( 0x00, 0x00, 0xFF ),
53 RGB( 0x00, 0xA0, 0xFF ), RGB( 0x00, 0xFF, 0xFF ),
54 RGB( 0x00, 0xA0, 0xA0 ), RGB( 0xC0, 0xC0, 0xFF ),
55 RGB( 0xFF, 0x00, 0xFF ), RGB( 0xA0, 0x00, 0xA0 ),
56 RGB( 0xFF, 0xFF, 0xFF ), RGB( 0x80, 0x80, 0x80 )
58 // since plotting is based on a LineTo for each new point
59 // we need a starting point (i.e. a "previous" point)
60 // use 0.0 as the default first point.
61 // these are public member variables, and can be changed outside
62 // (after construction).
63 // G.Hayduk: NTrends is the number of trends that will be drawn on
64 // the plot. First 15 plots have predefined colors, but others will
65 // be drawn with white, unless you call SetPlotColor
66 nTrends = cntTrends;
67 pdsTrends = new PlotData_t[nTrends];
69 dcPlot=NULL;
70 dcGrid=NULL;
71 bmapPlot=NULL;
72 bmapGrid=NULL;
73 memDC = NULL;
74 memBitmap = NULL;
76 PlotData_t* ppds = pdsTrends;
77 for(unsigned i=0; i<nTrends; ++i, ++ppds){
78 ppds->crPlot = (i<15 ? crPreset[i] : RGB(255, 255, 255));
79 ppds->penPlot=*(wxThePenList->FindOrCreatePen(wxColour(GetRValue(ppds->crPlot),GetGValue(ppds->crPlot),GetBValue(ppds->crPlot)),1,wxSOLID));
80 ppds->fPrev = ppds->fLowerLimit = ppds->fUpperLimit = 0.0;
83 oldwidth=oldheight=0;
84 bRecreateGraph = bRecreateGrid = bStopped = false;
85 nDelayedPoints = 0;
86 sLastTimestamp = 0.0;
87 sLastPeriod = 1.0;
88 nShiftPixels = 1;
89 nYDecimals = nDecimals;
90 crBackground = RGB( 0, 0, 0) ; // see also SetBackgroundColor
91 crGrid = RGB( 0, 255, 255) ; // see also SetGridColor
92 brushBack=*(wxTheBrushList->FindOrCreateBrush(wxColour(GetRValue(crBackground),GetGValue(crBackground),GetBValue(crBackground)),wxSOLID));
94 strXUnits = wxT("X"); // can also be set with SetXUnits
95 strYUnits = wxT("Y"); // can also be set with SetYUnits
97 bmapOldGrid = NULL ;
98 bmapOldPlot = NULL ;
100 nXGrids = 6;
101 nYGrids = 5;
103 graph_type = type;
105 timerRedraw.SetOwner(this);
107 // Ensure that various size-constraints are calculated (via OnSize).
108 SetClientSize(GetClientSize());
109 } // COScopeCtrl
113 COScopeCtrl::~COScopeCtrl()
115 // just to be picky restore the bitmaps for the two memory dc's
116 // (these dc's are being destroyed so there shouldn't be any leaks)
117 if (bmapOldGrid != NULL)
118 dcGrid->SelectObject(wxNullBitmap);
119 if (bmapOldPlot != NULL)
120 dcPlot->SelectObject(wxNullBitmap);
121 delete [] pdsTrends;
123 if (memDC) {
124 memDC->SelectObject(wxNullBitmap);
127 delete memDC;
128 delete dcGrid;
129 delete dcPlot;
130 if(bmapPlot) delete bmapPlot;
131 if(bmapGrid) delete bmapGrid;
132 if (memBitmap) delete memBitmap;
133 } // ~COScopeCtrl
136 void COScopeCtrl::SetRange(float fLower, float fUpper, unsigned iTrend)
138 PlotData_t* ppds = pdsTrends+iTrend;
139 if ((ppds->fLowerLimit == fLower) && (ppds->fUpperLimit == fUpper))
140 return;
141 ppds->fLowerLimit = fLower;
142 ppds->fUpperLimit = fUpper;
143 ppds->fVertScale = (float)nPlotHeight / (fUpper-fLower);
144 ppds->yPrev = GetPlotY(ppds->fPrev, ppds);
145 if (iTrend==0)
146 InvalidateCtrl();
147 else
148 InvalidateGraph();
149 } // SetRange
152 void COScopeCtrl::SetRanges(float fLower, float fUpper)
154 for(unsigned iTrend=0; iTrend<nTrends; ++iTrend)
155 SetRange(fLower, fUpper, iTrend);
156 } // SetRanges
159 // G.Hayduk: Apart from setting title of axis, now you can optionally set
160 // the limits strings (string which will be placed on the left and right of axis)
161 void COScopeCtrl::SetXUnits(const wxString& strUnits, const wxString& strMin, const wxString& strMax)
163 strXUnits = strUnits;
164 strXMin = strMin;
165 strXMax = strMax;
166 InvalidateGrid() ;
167 } // SetXUnits
170 void COScopeCtrl::SetYUnits(const wxString& strUnits, const wxString& strMin, const wxString& strMax)
172 strYUnits = strUnits;
173 strYMin = strMin;
174 strYMax = strMax;
175 InvalidateGrid();
176 } // SetYUnits
179 void COScopeCtrl::SetGridColor(COLORREF cr)
181 if (cr == crGrid)
182 return;
183 crGrid = cr;
184 InvalidateGrid() ;
185 } // SetGridColor
188 void COScopeCtrl::SetPlotColor(COLORREF cr, unsigned iTrend)
190 PlotData_t* ppds = pdsTrends+iTrend;
191 if (ppds->crPlot == cr)
192 return;
193 ppds->crPlot = cr;
194 ppds->penPlot=*(wxThePenList->FindOrCreatePen(wxColour(GetRValue(ppds->crPlot),GetGValue(ppds->crPlot),GetBValue(ppds->crPlot)),1,wxSOLID));
195 InvalidateGraph();
196 } // SetPlotColor
199 void COScopeCtrl::SetBackgroundColor(COLORREF cr)
201 if (crBackground == cr)
202 return;
203 crBackground = cr;
204 brushBack=*(wxTheBrushList->FindOrCreateBrush(wxColour(GetRValue(crBackground),GetGValue(crBackground),GetBValue(crBackground)),wxSOLID));
205 InvalidateCtrl() ;
206 } // SetBackgroundColor
209 void COScopeCtrl::RecreateGrid()
212 if (!dcGrid) {
213 return;
216 // There is a lot of drawing going on here - particularly in terms of
217 // drawing the grid. Don't panic, this is all being drawn (only once)
218 // to a bitmap. The result is then BitBlt'd to the control whenever needed.
219 bRecreateGrid = false;
220 if(nClientWidth==0 || nClientHeight==0)
221 return;
222 unsigned j, GridPos;
223 int nCharacters ;
224 wxPen solidPen=*(wxThePenList->FindOrCreatePen(wxColour(GetRValue(crGrid),GetGValue(crGrid),GetBValue(crGrid)),1,wxSOLID));
225 wxString strTemp;
227 // fill the grid background
228 dcGrid->SetBrush(brushBack);
229 dcGrid->SetPen(*wxTRANSPARENT_PEN);
230 dcGrid->DrawRectangle(rectClient.left,rectClient.top,rectClient.right-rectClient.left,
231 rectClient.bottom-rectClient.top);
232 // draw the plot rectangle: determine how wide the y axis scaling values are,
233 // add the units digit, decimal point, one decimal place, and an extra space
234 nCharacters = std::abs((int)std::log10(std::fabs(pdsTrends[0].fUpperLimit))) ;
235 nCharacters = std::max(nCharacters, std::abs((int)std::log10(std::fabs(pdsTrends[0].fLowerLimit)))) + 4;
237 // adjust the plot rectangle dimensions
238 // assume 6 pixels per character (this may need to be adjusted)
239 rectPlot.left = rectClient.left + 6*7+4;
240 nPlotWidth = rectPlot.right-rectPlot.left;
241 // draw the plot rectangle
242 dcGrid->SetPen(solidPen);
243 dcGrid->DrawLine(rectPlot.left-1,rectPlot.top,rectPlot.right+1,rectPlot.top);
244 dcGrid->DrawLine(rectPlot.right+1,rectPlot.top,rectPlot.right+1,rectPlot.bottom+1);
245 dcGrid->DrawLine(rectPlot.right+1,rectPlot.bottom+1,rectPlot.left-1,rectPlot.bottom+1);
246 dcGrid->DrawLine(rectPlot.left-1,rectPlot.bottom+1,rectPlot.left-1,rectPlot.top);
247 dcGrid->SetPen(wxNullPen);
249 // draw the dotted lines,
250 // G.Hayduk: added configurable number of grids
251 wxColour col(GetRValue(crGrid),GetGValue(crGrid),GetBValue(crGrid));
252 wxPen grPen(col,1,wxSOLID);
253 dcGrid->SetPen(grPen);
255 for(j=1; j<(nYGrids+1); ++j){
256 GridPos = (rectPlot.bottom-rectPlot.top)*j/( nYGrids + 1 ) + rectPlot.top ;
257 for (unsigned int i = rectPlot.left; i < rectPlot.right; i += 4)
258 dcGrid->DrawPoint(i,GridPos);
261 // create some fonts (horizontal and vertical)
262 wxFont* axisFont = new wxFont(10,wxSWISS,wxNORMAL,wxNORMAL,FALSE);
263 dcGrid->SetFont(*axisFont);//,this);
265 // y max
266 dcGrid->SetTextForeground(wxColour(GetRValue(crGrid),GetGValue(crGrid),GetBValue(crGrid)));
267 if( strYMax.IsEmpty() ) {
268 strTemp = wxString::Format(wxT("%.*f"), nYDecimals, pdsTrends[ 0 ].fUpperLimit);
269 } else {
270 strTemp = strYMax;
272 wxCoord sizX,sizY;
273 dcGrid->GetTextExtent(strTemp,&sizX,&sizY);
274 dcGrid->DrawText(strTemp,rectPlot.left-4-sizX,rectPlot.top-7);
275 // y min
276 if( strYMin.IsEmpty() ) {
277 strTemp = wxString::Format(wxT("%.*f"), nYDecimals, pdsTrends[ 0 ].fLowerLimit) ;
278 } else {
279 strTemp = strYMin;
281 dcGrid->GetTextExtent(strTemp,&sizX,&sizY);
282 dcGrid->DrawText(strTemp,rectPlot.left-4-sizX, rectPlot.bottom);
284 // x units
285 strTemp = CastSecondsToHM((nPlotWidth/nShiftPixels) * (int)floor(sLastPeriod+0.5));
286 // floor(x + 0.5) is a way of doing round(x) that works with gcc < 3 ...
287 if (bStopped) {
288 strXUnits = CFormat( _("Disabled [%s]") ) % strTemp;
289 } else {
290 strXUnits = strTemp;
293 dcGrid->GetTextExtent(strXUnits,&sizX,&sizY);
294 dcGrid->DrawText(strXUnits,(rectPlot.left+rectPlot.right)/2-sizX/2,rectPlot.bottom+4);
296 // y units
297 if (!strYUnits.IsEmpty()) {
298 dcGrid->GetTextExtent(strYUnits,&sizX,&sizY);
299 dcGrid->DrawText(strYUnits, rectPlot.left-4-sizX, (rectPlot.top+rectPlot.bottom)/2-sizY/2);
301 // if(!strYUnits.IsEmpty())
302 // dcGrid->DrawRotatedText(strYUnits,(rectClient.left+rectPlot.left+4)/2/*+(sizY*2)*/,
303 // ((rectPlot.bottom+rectPlot.top)/2)+sizX/2,90.0);
304 // no more drawing to this bitmap is needed until the setting are changed
306 delete axisFont;
308 if (bRecreateGraph)
309 RecreateGraph(false);
310 // finally, force the plot area to redraw
311 wxRect rect;
312 rect.x=rectClient.left;
313 rect.y=rectClient.top;
314 rect.width=rectClient.right-rectClient.left;
315 rect.height=rectClient.bottom-rectClient.top;
316 Refresh(FALSE,&rect);
317 } // RecreateGrid
320 void COScopeCtrl::AppendPoints(double sTimestamp, const std::vector<float *> &apf)
322 sLastTimestamp = sTimestamp;
323 ShiftGraph(1);
324 DrawPoints(apf, 1);
325 Refresh(FALSE);
326 } // AppendPoints
330 void COScopeCtrl::OnPaint(wxPaintEvent& WXUNUSED(evt))
331 { // no real plotting work is performed here unless we are coming out of a hidden state;
332 // normally, just putting the existing bitmaps on the client to avoid flicker,
333 // establish a memory dc and then BitBlt it to the client
334 if (bRecreateGrid || bRecreateGraph) {
335 timerRedraw.Stop();
336 if (bRecreateGrid)
337 RecreateGrid(); // this will also recreate the graph if that flag is set
338 else if (bRecreateGraph)
339 RecreateGraph(true);
342 if (nDelayedPoints>0) { // we've just come out of hiding, so catch up
343 int n = std::min(nPlotWidth, nDelayedPoints);
344 nDelayedPoints = 0; // (this is more efficient than plotting in the
345 PlotHistory(n, true, false); // background because the bitmap is shifted only
346 } // once for all delayed points together)
348 wxPaintDC dc(this);
349 DoBlit();
350 dc.Blit(0,0,nClientWidth,nClientHeight, memDC,0,0);
352 } // OnPaint
354 void COScopeCtrl::DoBlit()
356 if (!memDC) {
357 wxASSERT(!memBitmap);
358 memBitmap = new wxBitmap(nClientWidth,nClientHeight);
359 memDC = new wxMemoryDC;
360 memDC->SelectObject(*memBitmap);
361 } else {
362 wxASSERT(memBitmap);
363 if ((memBitmap->GetHeight() != nClientHeight)
364 || (memBitmap->GetWidth() != nClientWidth)) {
365 // New bitmap.
366 memDC->SelectObject(wxNullBitmap);
367 delete memBitmap;
368 memBitmap = new wxBitmap(nClientWidth,nClientHeight);
369 memDC->SelectObject(*memBitmap);
373 wxASSERT(memDC);
375 // We have assured that we have a valid and resized if needed
376 // wxDc and bitmap. Proceed to blit.
378 memDC->Blit(0,0,nClientWidth,nClientHeight,dcGrid,0,0);
379 // now add the plot on top as a "pattern" via SRCPAINT.
380 // works well with dark background and a light plot
381 memDC->Blit(0,0,nClientWidth,nClientHeight,dcPlot,0,0
382 #ifndef __WXMAC__
383 ,wxOR
384 #endif
387 // Ready.
392 void COScopeCtrl::OnSize(wxSizeEvent& evt)
394 // This gets called repeatedly as the user resizes the app;
395 // we use the timer mechanism through InvalidateCtrl to avoid unnecessary redrawing
396 // NOTE: OnSize automatically gets called during the setup of the control
397 if(oldwidth==evt.GetSize().GetWidth() && oldheight==evt.GetSize().GetHeight())
398 return;
399 oldwidth=evt.GetSize().GetWidth();
400 oldheight=evt.GetSize().GetHeight();
401 wxRect myrect=GetClientRect();
402 rectClient.left=myrect.x;
403 rectClient.top=myrect.y;
404 rectClient.right=myrect.x+myrect.width;
405 rectClient.bottom=myrect.y+myrect.height;
406 if(myrect.width<1 || myrect.height<1)
407 return;
409 // set some member variables to avoid multiple function calls
410 nClientHeight = myrect.height;
411 nClientWidth = myrect.width;
412 // the "left" coordinate and "width" will be modified in
413 // InvalidateCtrl to be based on the y axis scaling
414 rectPlot.left = 20 ;
415 rectPlot.top = 10 ;
416 rectPlot.right = std::max(rectPlot.left+1, rectClient.right-10);
417 rectPlot.bottom = std::max(rectPlot.top+1, rectClient.bottom-25);
418 nPlotHeight = rectPlot.bottom-rectPlot.top;
419 nPlotWidth = rectPlot.right-rectPlot.left;
420 PlotData_t* ppds = pdsTrends;
421 for(unsigned iTrend=0; iTrend<nTrends; ++iTrend, ++ppds) {
422 ppds->fVertScale = (float)nPlotHeight / (ppds->fUpperLimit-ppds->fLowerLimit);
423 ppds->yPrev = GetPlotY(ppds->fPrev, ppds);
426 // destroy grid dc and bitmap (InvalidateCtrl recreates them in new size)
427 if(dcGrid) {
428 dcGrid->SelectObject(wxNullBitmap);
429 delete dcGrid;
431 dcGrid=new wxMemoryDC;
432 if(bmapGrid)
433 delete bmapGrid;
434 bmapGrid = new wxBitmap(nClientWidth,nClientHeight);
435 dcGrid->SelectObject(*bmapGrid);
437 if(dcPlot) {
438 dcPlot->SelectObject(wxNullBitmap);
439 delete dcPlot;
441 dcPlot=new wxMemoryDC;
442 if(bmapPlot)
443 delete bmapPlot;
444 bmapPlot = new wxBitmap(nClientWidth, nClientHeight);
445 dcPlot->SelectObject(*bmapPlot);
447 InvalidateCtrl();
448 } // OnSize
451 void COScopeCtrl::ShiftGraph(unsigned cntPoints)
453 if (dcPlot == NULL)
454 return;
455 unsigned cntPixelOffset = cntPoints*nShiftPixels;
456 if (cntPixelOffset >= (unsigned)nPlotWidth)
457 cntPixelOffset = nPlotWidth;
458 else
459 dcPlot->Blit(rectPlot.left,rectPlot.top+1, nPlotWidth, nPlotHeight, dcPlot,
460 rectPlot.left+cntPixelOffset, rectPlot.top+1); // scroll graph to the left
461 // clear a rectangle over the right side of plot prior to adding the new points
462 dcPlot->SetPen(*wxTRANSPARENT_PEN);
463 dcPlot->SetBrush(brushBack); // fill with background color
464 dcPlot->DrawRectangle(rectPlot.right-cntPixelOffset+1, rectPlot.top,
465 cntPixelOffset, rectPlot.bottom-rectPlot.top+1);
466 } // ShiftGraph
470 unsigned COScopeCtrl::GetPlotY(float fPlot, PlotData_t* ppds)
472 if (fPlot <= ppds->fLowerLimit)
473 return rectPlot.bottom;
474 else if (fPlot >= ppds->fUpperLimit)
475 return rectPlot.top+1;
476 else
477 return rectPlot.bottom - (unsigned)((fPlot - ppds->fLowerLimit) * ppds->fVertScale);
478 } // GetPlotY
482 void COScopeCtrl::DrawPoints(const std::vector<float *> &apf, unsigned cntPoints)
483 { // this appends a new set of data points to a graph; all of the plotting is
484 // directed to the memory based bitmap associated with dcPlot
485 // the will subsequently be BitBlt'd to the client in OnPaint
486 if (dcPlot == NULL) {
487 printf("COScopeCtrl::DrawPoints - dcPlot==NULL unexpected\n");
488 return;
490 // draw the next line segement
491 unsigned x, y, yPrev;
492 unsigned cntPixelOffset = std::min((unsigned)(nPlotWidth-1), (cntPoints-1)*nShiftPixels);
493 PlotData_t* ppds = pdsTrends;
495 for (unsigned iTrend=0; iTrend<nTrends; ++iTrend, ++ppds) {
496 const float* pf = apf[iTrend] + cntPoints - 1;
497 yPrev = ppds->yPrev;
498 dcPlot->SetPen(ppds->penPlot);
499 for (x=rectPlot.right-cntPixelOffset; x<=rectPlot.right; x+=nShiftPixels) {
500 y = GetPlotY(*pf--, ppds);
501 dcPlot->DrawLine(x-nShiftPixels, yPrev, x, y);
502 yPrev = y;
504 ppds->fPrev = *(pf+1);
505 ppds->yPrev = yPrev;
507 } // DrawPoints
510 #ifndef CLIENT_GUI
511 void COScopeCtrl::PlotHistory(unsigned cntPoints, bool bShiftGraph, bool bRefresh)
513 wxASSERT(graph_type != GRAPH_INVALID);
515 if (graph_type != GRAPH_INVALID) {
516 unsigned i;
517 unsigned cntFilled;
518 std::vector<float *> apf(nTrends);
519 try {
520 for (i = 0; i < nTrends; ++i) {
521 apf[i] = new float[cntPoints];
523 double sFinal = (bStopped ? sLastTimestamp : -1.0);
524 cntFilled = theApp->m_statistics->GetHistory(cntPoints, sLastPeriod, sFinal, apf, graph_type);
525 if (cntFilled >1 || (bShiftGraph && cntFilled!=0)) {
526 if (bShiftGraph) { // delayed points - we have an fPrev
527 ShiftGraph(cntFilled);
528 } else { // fresh graph, we need to preset fPrev, yPrev
529 PlotData_t* ppds = pdsTrends;
530 for(i=0; i<nTrends; ++i, ++ppds)
531 ppds->yPrev = GetPlotY(ppds->fPrev = *(apf[i] + cntFilled - 1), ppds);
532 cntFilled--;
534 DrawPoints(apf, cntFilled);
535 if (bRefresh)
536 Refresh(FALSE);
538 for (i = 0; i < nTrends; ++i) {
539 delete [] apf[i];
541 } catch(std::bad_alloc) {
542 // Failed memory allocation
543 AddLogLineM(true, wxString(
544 wxT("Error: COScopeCtrl::PlotHistory: Insuficient memory, cntPoints == ")) <<
545 cntPoints << wxT("."));
546 for (i = 0; i < nTrends; ++i) {
547 delete [] apf[i];
550 } else {
551 // No history (yet) for Kad.
553 } // PlotHistory
554 #else
555 //#warning CORE/GUI -- EC needed
556 void COScopeCtrl::PlotHistory(unsigned, bool, bool)
559 #endif
562 void COScopeCtrl::RecreateGraph(bool bRefresh)
564 bRecreateGraph = false;
565 nDelayedPoints = 0;
566 dcPlot->SetBrush(brushBack);
567 dcPlot->SetPen(*wxTRANSPARENT_PEN);
568 dcPlot->DrawRectangle(rectClient.left, rectClient.top, rectClient.right-rectClient.left,
569 rectClient.bottom-rectClient.top);
570 PlotHistory(nPlotWidth, false, bRefresh);
571 } // RecreateGraph
574 void COScopeCtrl::Reset(double sNewPeriod)
576 bool bStoppedPrev = bStopped;
577 bStopped = false;
578 if (sLastPeriod != sNewPeriod || bStoppedPrev) {
579 sLastPeriod = sNewPeriod;
580 InvalidateCtrl();
582 } // Reset
585 void COScopeCtrl::Stop()
587 bStopped = true;
588 bRecreateGraph = false;
589 RecreateGrid();
590 } // Stop
593 void COScopeCtrl::InvalidateCtrl(bool bInvalidateGraph, bool bInvalidateGrid)
595 timerRedraw.Stop();
596 timerRedraw.SetOwner(this,TIMER_OSCOPE);
597 if (bInvalidateGraph)
598 bRecreateGraph = true;
599 if (bInvalidateGrid)
600 bRecreateGrid = true;
601 timerRedraw.Start(100);
602 } // InvalidateCtrl
605 void COScopeCtrl::OnTimer(wxTimerEvent& WXUNUSED(evt))
606 /* The timer is used to consolidate redrawing of the graphs: when the user resizes
607 the application, we get multiple calls to OnSize. If he changes several parameters
608 in the Preferences, we get several individual SetXYZ calls. If we were to try to
609 recreate the graphs for each such event, performance would be sluggish, but with
610 the timer, each event (if they come in quick succession) simply restarts the timer
611 until there is a little pause and OnTimer actually gets called and does its work.
614 if( !theApp->amuledlg || !theApp->amuledlg->SafeState()) {
615 return;
617 timerRedraw.Stop();
618 if (bRecreateGrid) {
619 RecreateGrid(); // this will also recreate the graph if that flag is set
620 } else if (bRecreateGraph) {
621 RecreateGraph(true);
624 } // OnTimer
625 // File_checked_for_headers