]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/plot/plot.cpp
Assert correction.
[wxWidgets.git] / contrib / src / plot / plot.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: plot.cpp
3 // Purpose: wxPlotWindow
4 // Author: Robert Roebling
5 // Modified by:
6 // Created: 12/01/2000
7 // RCS-ID: $Id$
8 // Copyright: (c) Robert Roebling
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "plot.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/object.h"
25 #include "wx/font.h"
26 #include "wx/colour.h"
27 #include "wx/settings.h"
28 #include "wx/sizer.h"
29 #include "wx/log.h"
30 #include "wx/intl.h"
31 #include "wx/dcclient.h"
32 #include "wx/stattext.h"
33 #endif
34
35 #include "wx/plot/plot.h"
36 #include "wx/bmpbuttn.h"
37 #include "wx/module.h"
38
39 #include <math.h>
40
41 // ----------------------------------------------------------------------------
42 // XPMs
43 // ----------------------------------------------------------------------------
44
45 #if !defined(__WXMSW__) && !defined(__WXPM__)
46 #include "wx/plot/plot_enl.xpm"
47 #include "wx/plot/plot_shr.xpm"
48 #include "wx/plot/plot_zin.xpm"
49 #include "wx/plot/plot_zot.xpm"
50 #include "wx/plot/plot_up.xpm"
51 #include "wx/plot/plot_dwn.xpm"
52 #endif
53
54 //----------------------------------------------------------------------------
55 // event types
56 //----------------------------------------------------------------------------
57
58 DEFINE_EVENT_TYPE(wxEVT_PLOT_SEL_CHANGING);
59 DEFINE_EVENT_TYPE(wxEVT_PLOT_SEL_CHANGED);
60 DEFINE_EVENT_TYPE(wxEVT_PLOT_CLICKED);
61 DEFINE_EVENT_TYPE(wxEVT_PLOT_DOUBLECLICKED);
62 DEFINE_EVENT_TYPE(wxEVT_PLOT_ZOOM_IN);
63 DEFINE_EVENT_TYPE(wxEVT_PLOT_ZOOM_OUT);
64 DEFINE_EVENT_TYPE(wxEVT_PLOT_VALUE_SEL_CREATING);
65 DEFINE_EVENT_TYPE(wxEVT_PLOT_VALUE_SEL_CREATED);
66 DEFINE_EVENT_TYPE(wxEVT_PLOT_VALUE_SEL_CHANGING);
67 DEFINE_EVENT_TYPE(wxEVT_PLOT_VALUE_SEL_CHANGED);
68 DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_SEL_CREATING);
69 DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_SEL_CREATED);
70 DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_SEL_CHANGING);
71 DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_SEL_CHANGED);
72 DEFINE_EVENT_TYPE(wxEVT_PLOT_BEGIN_X_LABEL_EDIT);
73 DEFINE_EVENT_TYPE(wxEVT_PLOT_END_X_LABEL_EDIT);
74 DEFINE_EVENT_TYPE(wxEVT_PLOT_BEGIN_Y_LABEL_EDIT);
75 DEFINE_EVENT_TYPE(wxEVT_PLOT_END_Y_LABEL_EDIT);
76 DEFINE_EVENT_TYPE(wxEVT_PLOT_BEGIN_TITLE_EDIT);
77 DEFINE_EVENT_TYPE(wxEVT_PLOT_END_TITLE_EDIT);
78 DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_CREATE);
79
80 //----------------------------------------------------------------------------
81 // accessor functions for the bitmaps (may return NULL, check for it!)
82 //----------------------------------------------------------------------------
83
84 static wxBitmap *GetEnlargeBitmap();
85 static wxBitmap *GetShrinkBitmap();
86 static wxBitmap *GetZoomInBitmap();
87 static wxBitmap *GetZoomOutBitmap();
88 static wxBitmap *GetUpBitmap();
89 static wxBitmap *GetDownBitmap();
90
91 //-----------------------------------------------------------------------------
92 // consts
93 //-----------------------------------------------------------------------------
94
95 #define wxPLOT_SCROLL_STEP 30
96
97 //-----------------------------------------------------------------------------
98 // wxPlotEvent
99 //-----------------------------------------------------------------------------
100
101 wxPlotEvent::wxPlotEvent( wxEventType commandType, int id )
102 : wxNotifyEvent( commandType, id )
103 {
104 m_curve = (wxPlotCurve*) NULL;
105 m_zoom = 1.0;
106 m_position = 0;
107 }
108
109 //-----------------------------------------------------------------------------
110 // wxPlotCurve
111 //-----------------------------------------------------------------------------
112
113 IMPLEMENT_ABSTRACT_CLASS(wxPlotCurve, wxObject)
114
115 wxPlotCurve::wxPlotCurve( int offsetY, double startY, double endY )
116 : m_penNormal(*wxGREY_PEN), m_penSelected(*wxBLACK_PEN)
117 {
118 m_offsetY = offsetY;
119 m_startY = startY;
120 m_endY = endY;
121 }
122
123 //-----------------------------------------------------------------------------
124 // wxPlotOnOffCurve
125 //-----------------------------------------------------------------------------
126
127 IMPLEMENT_CLASS(wxPlotOnOffCurve, wxObject)
128
129 #include "wx/arrimpl.cpp"
130 WX_DEFINE_OBJARRAY(wxArrayPlotOnOff);
131
132 wxPlotOnOffCurve::wxPlotOnOffCurve( int offsetY )
133 {
134 m_offsetY = offsetY;
135 m_minX = -1;
136 m_maxX = -1;
137 }
138
139 void wxPlotOnOffCurve::Add( wxInt32 on, wxInt32 off, void *clientData )
140 {
141 wxASSERT_MSG( on > 0, _T("plot index < 0") );
142 wxASSERT( on <= off );
143
144 if (m_minX == -1)
145 m_minX = on;
146 if (off > m_maxX)
147 m_maxX = off;
148
149 wxPlotOnOff *v = new wxPlotOnOff;
150 v->m_on = on;
151 v->m_off = off;
152 v->m_clientData = clientData;
153 m_marks.Add( v );
154 }
155
156 size_t wxPlotOnOffCurve::GetCount()
157 {
158 return m_marks.GetCount();
159 }
160
161 wxInt32 wxPlotOnOffCurve::GetOn( size_t index )
162 {
163 wxPlotOnOff *v = &m_marks.Item( index );
164 return v->m_on;
165 }
166
167 wxInt32 wxPlotOnOffCurve::GetOff( size_t index )
168 {
169 wxPlotOnOff *v = &m_marks.Item( index );
170 return v->m_off;
171 }
172
173 void* wxPlotOnOffCurve::GetClientData( size_t index )
174 {
175 wxPlotOnOff *v = &m_marks.Item( index );
176 return v->m_clientData;
177 }
178
179 wxPlotOnOff *wxPlotOnOffCurve::GetAt( size_t index )
180 {
181 return &m_marks.Item( index );
182 }
183
184 void wxPlotOnOffCurve::DrawOnLine( wxDC &dc, wxCoord y, wxCoord start, wxCoord end, void *WXUNUSED(clientData) )
185 {
186 dc.DrawLine( start, y, start, y-30 );
187 dc.DrawLine( start, y-30, end, y-30 );
188 dc.DrawLine( end, y-30, end, y );
189 }
190
191 void wxPlotOnOffCurve::DrawOffLine( wxDC &dc, wxCoord y, wxCoord start, wxCoord end )
192 {
193 dc.DrawLine( start, y, end, y );
194 }
195
196 //-----------------------------------------------------------------------------
197 // wxPlotArea
198 //-----------------------------------------------------------------------------
199
200 IMPLEMENT_DYNAMIC_CLASS(wxPlotArea, wxWindow)
201
202 BEGIN_EVENT_TABLE(wxPlotArea, wxWindow)
203 EVT_PAINT( wxPlotArea::OnPaint)
204 EVT_LEFT_DOWN( wxPlotArea::OnMouse)
205 EVT_LEFT_DCLICK( wxPlotArea::OnMouse)
206 END_EVENT_TABLE()
207
208 wxPlotArea::wxPlotArea( wxPlotWindow *parent )
209 : wxWindow( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER, _T("plotarea") )
210 {
211 m_owner = parent;
212
213 m_zooming = false;
214
215 SetBackgroundColour( *wxWHITE );
216 }
217
218 void wxPlotArea::OnMouse( wxMouseEvent &event )
219 {
220 int client_width;
221 int client_height;
222 GetClientSize( &client_width, &client_height);
223 int view_x;
224 int view_y;
225 m_owner->GetViewStart( &view_x, &view_y );
226 view_x *= wxPLOT_SCROLL_STEP;
227 view_y *= wxPLOT_SCROLL_STEP;
228
229 wxCoord x = event.GetX();
230 wxCoord y = event.GetY();
231 x += view_x;
232 y += view_y;
233
234 wxList::compatibility_iterator node = m_owner->m_curves.GetFirst();
235 while (node)
236 {
237 wxPlotCurve *curve = (wxPlotCurve*)node->GetData();
238
239 double double_client_height = (double)client_height;
240 double range = curve->GetEndY() - curve->GetStartY();
241 double end = curve->GetEndY();
242 wxCoord offset_y = curve->GetOffsetY();
243
244 double dy = (end - curve->GetY( (wxInt32)(x/m_owner->GetZoom()) )) / range;
245 wxCoord curve_y = (wxCoord)(dy * double_client_height) - offset_y - 1;
246
247 if ((y-curve_y < 4) && (y-curve_y > -4))
248 {
249 wxPlotEvent event1( event.ButtonDClick() ? wxEVT_PLOT_DOUBLECLICKED : wxEVT_PLOT_CLICKED, m_owner->GetId() );
250 event1.SetEventObject( m_owner );
251 event1.SetZoom( m_owner->GetZoom() );
252 event1.SetCurve( curve );
253 event1.SetPosition( (int)floor(x/m_owner->GetZoom()) );
254 m_owner->GetEventHandler()->ProcessEvent( event1 );
255
256 if (curve != m_owner->GetCurrentCurve())
257 {
258 wxPlotEvent event2( wxEVT_PLOT_SEL_CHANGING, m_owner->GetId() );
259 event2.SetEventObject( m_owner );
260 event2.SetZoom( m_owner->GetZoom() );
261 event2.SetCurve( curve );
262 if (!m_owner->GetEventHandler()->ProcessEvent( event2 ) || event2.IsAllowed())
263 {
264 m_owner->SetCurrentCurve( curve );
265 }
266 }
267 return;
268 }
269
270 node = node->GetNext();
271 }
272 }
273
274 void wxPlotArea::DeleteCurve( wxPlotCurve *curve, int from, int to )
275 {
276 wxClientDC dc(this);
277 m_owner->PrepareDC( dc );
278 dc.SetPen( *wxWHITE_PEN );
279 DrawCurve( &dc, curve, from, to );
280 }
281
282 void wxPlotArea::DrawCurve( wxDC *dc, wxPlotCurve *curve, int from, int to )
283 {
284 int view_x;
285 int view_y;
286 m_owner->GetViewStart( &view_x, &view_y );
287 view_x *= wxPLOT_SCROLL_STEP;
288
289 if (from == -1)
290 from = view_x;
291
292 int client_width;
293 int client_height;
294 GetClientSize( &client_width, &client_height);
295
296 if (to == -1)
297 to = view_x + client_width;
298
299 double zoom = m_owner->GetZoom();
300
301 int start_x = wxMax( from, (int)floor(curve->GetStartX()*zoom) );
302 int end_x = wxMin( to, (int)floor(curve->GetEndX()*zoom) );
303
304 start_x = wxMax( view_x, start_x );
305 end_x = wxMin( view_x + client_width, end_x );
306
307 end_x++;
308
309 double double_client_height = (double)client_height;
310 double range = curve->GetEndY() - curve->GetStartY();
311 double end = curve->GetEndY();
312 wxCoord offset_y = curve->GetOffsetY();
313
314 wxCoord last_y=0;
315 for (int x = start_x; x < end_x; x++)
316 {
317 double dy = (end - curve->GetY( (wxInt32)(x/zoom) )) / range;
318 wxCoord y = (wxCoord)(dy * double_client_height) - offset_y - 1;
319
320 if (x != start_x)
321 dc->DrawLine( x-1, last_y, x, y );
322
323 last_y = y;
324 }
325 }
326
327 void wxPlotArea::DrawOnOffCurve( wxDC *dc, wxPlotOnOffCurve *curve, int from, int to )
328 {
329 int view_x;
330 int view_y;
331 m_owner->GetViewStart( &view_x, &view_y );
332 view_x *= wxPLOT_SCROLL_STEP;
333
334 if (from == -1)
335 from = view_x;
336
337 int client_width;
338 int client_height;
339 GetClientSize( &client_width, &client_height);
340
341 if (to == -1)
342 to = view_x + client_width;
343
344 double zoom = m_owner->GetZoom();
345
346 int start_x = wxMax( from, (int)floor(curve->GetStartX()*zoom) );
347 int end_x = wxMin( to, (int)floor(curve->GetEndX()*zoom) );
348
349 start_x = wxMax( view_x, start_x );
350 end_x = wxMin( view_x + client_width, end_x );
351
352 end_x++;
353
354 wxCoord offset_y = curve->GetOffsetY();
355 wxCoord last_off = -5;
356
357 if (curve->GetCount() == 0)
358 return;
359
360 for (size_t index = 0; index < curve->GetCount(); index++)
361 {
362 wxPlotOnOff *p = curve->GetAt( index );
363
364 wxCoord on = (wxCoord)(p->m_on*zoom);
365 wxCoord off = (wxCoord)(p->m_off*zoom);
366
367 if (end_x < on)
368 {
369 curve->DrawOffLine( *dc, client_height-offset_y, last_off, on );
370 break;
371 }
372
373 if (off >= start_x)
374 {
375 curve->DrawOffLine( *dc, client_height-offset_y, last_off, on );
376 curve->DrawOnLine( *dc, client_height-offset_y, on, off, p->m_clientData );
377 }
378 last_off = off;
379 }
380
381 wxPlotOnOff *p = curve->GetAt( curve->GetCount()-1 );
382 wxCoord off = (wxCoord)(p->m_off*zoom);
383 if (off < end_x)
384 curve->DrawOffLine( *dc, client_height-offset_y, off, to );
385 }
386
387 void wxPlotArea::OnPaint( wxPaintEvent &WXUNUSED(event) )
388 {
389 int view_x;
390 int view_y;
391 m_owner->GetViewStart( &view_x, &view_y );
392 view_x *= wxPLOT_SCROLL_STEP;
393 view_y *= wxPLOT_SCROLL_STEP;
394
395 wxPaintDC dc( this );
396 m_owner->PrepareDC( dc );
397
398 wxRegionIterator upd( GetUpdateRegion() );
399
400 while (upd)
401 {
402 int update_x = upd.GetX() + view_x;
403 int update_width = upd.GetWidth();
404
405 /*
406 if (m_owner->m_current)
407 {
408 dc.SetPen( *wxLIGHT_GREY_PEN );
409 int base_line = client_height - m_owner->m_current->GetOffsetY();
410 dc.DrawLine( update_x-1, base_line-1, update_x+update_width+2, base_line-1 );
411 }
412 */
413
414 wxList::compatibility_iterator node = m_owner->m_curves.GetFirst();
415 while (node)
416 {
417 wxPlotCurve *curve = (wxPlotCurve*) node->GetData();
418
419 if (curve == m_owner->GetCurrentCurve())
420 dc.SetPen( curve->GetPenSelected() );
421 else
422 dc.SetPen( curve->GetPenNormal() );
423
424 DrawCurve( &dc, curve, update_x-1, update_x+update_width+2 );
425
426 node = node->GetNext();
427 }
428
429 dc.SetPen( *wxRED_PEN );
430
431 node = m_owner->m_onOffCurves.GetFirst();
432 while (node)
433 {
434 wxPlotOnOffCurve *curve = (wxPlotOnOffCurve*) node->GetData();
435
436 DrawOnOffCurve( &dc, curve, update_x-1, update_x+update_width+2 );
437
438 node = node->GetNext();
439 }
440
441 upd ++;
442 }
443 }
444
445 void wxPlotArea::ScrollWindow( int dx, int dy, const wxRect *rect )
446 {
447 wxWindow::ScrollWindow( dx, dy, rect );
448 // m_owner->m_xaxis->ScrollWindow( dx, 0 );
449 }
450
451 //-----------------------------------------------------------------------------
452 // wxPlotXAxisArea
453 //-----------------------------------------------------------------------------
454
455 IMPLEMENT_DYNAMIC_CLASS(wxPlotXAxisArea, wxWindow)
456
457 BEGIN_EVENT_TABLE(wxPlotXAxisArea, wxWindow)
458 EVT_PAINT( wxPlotXAxisArea::OnPaint)
459 EVT_LEFT_DOWN( wxPlotXAxisArea::OnMouse)
460 END_EVENT_TABLE()
461
462 wxPlotXAxisArea::wxPlotXAxisArea( wxPlotWindow *parent )
463 : wxWindow( parent, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,40), 0, _T("plotxaxisarea") )
464 {
465 m_owner = parent;
466
467 SetBackgroundColour( *wxWHITE );
468 SetFont( *wxSMALL_FONT );
469 }
470
471 void wxPlotXAxisArea::OnMouse( wxMouseEvent &event )
472 {
473 int client_width;
474 int client_height;
475 GetClientSize( &client_width, &client_height);
476 int view_x;
477 int view_y;
478 m_owner->GetViewStart( &view_x, &view_y );
479 view_x *= wxPLOT_SCROLL_STEP;
480 view_y *= wxPLOT_SCROLL_STEP;
481
482 wxCoord x = event.GetX() + view_x;
483 wxCoord y = event.GetY() + view_y;
484
485 /* TO DO: do something here */
486 wxUnusedVar(x);
487 wxUnusedVar(y);
488 }
489
490 void wxPlotXAxisArea::OnPaint( wxPaintEvent &WXUNUSED(event) )
491 {
492 int view_x;
493 int view_y;
494 m_owner->GetViewStart( &view_x, &view_y );
495 view_x *= wxPLOT_SCROLL_STEP;
496 view_y *= wxPLOT_SCROLL_STEP;
497
498 wxPaintDC dc( this );
499
500 int client_width;
501 int client_height;
502 GetClientSize( &client_width, &client_height);
503
504 double zoom = m_owner->GetZoom();
505
506 double ups = m_owner->GetUnitsPerValue() / zoom;
507
508 double start = view_x * ups;
509 double end = (view_x + client_width) * ups;
510 double range = end - start;
511
512 int int_log_range = (int)floor( log10( range ) );
513 double step = 1.0;
514 if (int_log_range > 0)
515 {
516 for (int i = 0; i < int_log_range; i++)
517 step *= 10;
518 }
519 if (int_log_range < 0)
520 {
521 for (int i = 0; i < -int_log_range; i++)
522 step /= 10;
523 }
524 double lower = ceil(start / step) * step;
525 double upper = floor(end / step) * step;
526
527 // if too few values, shrink size
528 if ((range/step) < 4)
529 {
530 step /= 2;
531 if (lower-step > start) lower -= step;
532 if (upper+step < end) upper += step;
533 }
534
535 // if still too few, again
536 if ((range/step) < 4)
537 {
538 step /= 2;
539 if (lower-step > start) lower -= step;
540 if (upper+step < end) upper += step;
541 }
542
543 dc.SetBrush( *wxWHITE_BRUSH );
544 dc.SetPen( *wxTRANSPARENT_PEN );
545 dc.DrawRectangle( 4, 5, client_width-14, 10 );
546 dc.DrawRectangle( 0, 20, client_width, 20 );
547 dc.SetPen( *wxBLACK_PEN );
548
549 double current = lower;
550 while (current < upper+(step/2))
551 {
552 int x = (int)ceil((current-start) / range * (double)client_width) - 1;
553 if ((x > 4) && (x < client_width-25))
554 {
555 dc.DrawLine( x, 5, x, 15 );
556 wxString label;
557 if (range < 50)
558 {
559 label.Printf( _T("%f"), current );
560 while (label.Last() == _T('0'))
561 label.RemoveLast();
562 if ((label.Last() == _T('.')) || (label.Last() == _T(',')))
563 label.Append( _T('0') );
564 }
565 else
566 label.Printf( _T("%d"), (int)floor(current) );
567 dc.DrawText( label, x-4, 20 );
568 }
569
570 current += step;
571 }
572
573 dc.DrawLine( 0, 15, client_width-8, 15 );
574 dc.DrawLine( client_width-4, 15, client_width-10, 10 );
575 dc.DrawLine( client_width-4, 15, client_width-10, 20 );
576 }
577
578 //-----------------------------------------------------------------------------
579 // wxPlotYAxisArea
580 //-----------------------------------------------------------------------------
581
582 IMPLEMENT_DYNAMIC_CLASS(wxPlotYAxisArea, wxWindow)
583
584 BEGIN_EVENT_TABLE(wxPlotYAxisArea, wxWindow)
585 EVT_PAINT( wxPlotYAxisArea::OnPaint)
586 EVT_LEFT_DOWN( wxPlotYAxisArea::OnMouse)
587 END_EVENT_TABLE()
588
589 wxPlotYAxisArea::wxPlotYAxisArea( wxPlotWindow *parent )
590 : wxWindow( parent, wxID_ANY, wxDefaultPosition, wxSize(60,wxDefaultCoord), 0, _T("plotyaxisarea") )
591 {
592 m_owner = parent;
593
594 SetBackgroundColour( *wxWHITE );
595 SetFont( *wxSMALL_FONT );
596 }
597
598 void wxPlotYAxisArea::OnMouse( wxMouseEvent &WXUNUSED(event) )
599 {
600 /* do something here */
601 }
602
603 void wxPlotYAxisArea::OnPaint( wxPaintEvent &WXUNUSED(event) )
604 {
605 wxPaintDC dc( this );
606
607 wxPlotCurve *curve = m_owner->GetCurrentCurve();
608
609 if (!curve) return;
610
611 int client_width;
612 int client_height;
613 GetClientSize( &client_width, &client_height);
614
615
616 double range = curve->GetEndY() - curve->GetStartY();
617 double offset = ((double) curve->GetOffsetY() / (double)client_height ) * range;
618 double start = curve->GetStartY() - offset;
619 double end = curve->GetEndY() - offset;
620
621 int int_log_range = (int)floor( log10( range ) );
622 double step = 1.0;
623 if (int_log_range > 0)
624 {
625 for (int i = 0; i < int_log_range; i++)
626 step *= 10;
627 }
628 if (int_log_range < 0)
629 {
630 for (int i = 0; i < -int_log_range; i++)
631 step /= 10;
632 }
633 double lower = ceil(start / step) * step;
634 double upper = floor(end / step) * step;
635
636 // if too few values, shrink size
637 if ((range/step) < 4)
638 {
639 step /= 2;
640 if (lower-step > start) lower -= step;
641 if (upper+step < end) upper += step;
642 }
643
644 // if still too few, again
645 if ((range/step) < 4)
646 {
647 step /= 2;
648 if (lower-step > start) lower -= step;
649 if (upper+step < end) upper += step;
650 }
651
652 dc.SetPen( *wxBLACK_PEN );
653
654 double current = lower;
655 while (current < upper+(step/2))
656 {
657 int y = (int)((curve->GetEndY()-current) / range * (double)client_height) - 1;
658 y -= curve->GetOffsetY();
659 if ((y > 10) && (y < client_height-7))
660 {
661 dc.DrawLine( client_width-15, y, client_width-7, y );
662 wxString label;
663 if (range < 50)
664 {
665 label.Printf( _T("%f"), current );
666 while (label.Last() == _T('0'))
667 label.RemoveLast();
668 if ((label.Last() == _T('.')) || (label.Last() == _T(',')))
669 label.Append( _T('0') );
670 }
671 else
672 label.Printf( _T("%d"), (int)floor(current) );
673 dc.DrawText( label, 5, y-7 );
674 }
675
676 current += step;
677 }
678
679 dc.DrawLine( client_width-15, 6, client_width-15, client_height );
680 dc.DrawLine( client_width-15, 2, client_width-20, 8 );
681 dc.DrawLine( client_width-15, 2, client_width-10, 8 );
682 }
683
684 //-----------------------------------------------------------------------------
685 // wxPlotWindow
686 //-----------------------------------------------------------------------------
687
688 #define ID_ENLARGE 1000
689 #define ID_SHRINK 1002
690
691 #define ID_MOVE_UP 1006
692 #define ID_MOVE_DOWN 1007
693
694 #define ID_ZOOM_IN 1010
695 #define ID_ZOOM_OUT 1011
696
697
698 IMPLEMENT_DYNAMIC_CLASS(wxPlotWindow, wxScrolledWindow)
699
700 BEGIN_EVENT_TABLE(wxPlotWindow, wxScrolledWindow)
701 EVT_BUTTON( ID_MOVE_UP, wxPlotWindow::OnMoveUp)
702 EVT_BUTTON( ID_MOVE_DOWN, wxPlotWindow::OnMoveDown)
703
704 EVT_BUTTON( ID_ENLARGE, wxPlotWindow::OnEnlarge)
705 EVT_BUTTON( ID_SHRINK, wxPlotWindow::OnShrink)
706
707 EVT_BUTTON( ID_ZOOM_IN, wxPlotWindow::OnZoomIn)
708 EVT_BUTTON( ID_ZOOM_OUT, wxPlotWindow::OnZoomOut)
709
710 EVT_SCROLLWIN( wxPlotWindow::OnScroll2)
711 END_EVENT_TABLE()
712
713 wxPlotWindow::wxPlotWindow( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, int flag )
714 : wxScrolledWindow( parent, id, pos, size, flag, _T("plotcanvas") ),
715 m_titleStaticText( NULL )
716 {
717 m_xUnitsPerValue = 1.0;
718 m_xZoom = 1.0;
719
720 m_enlargeAroundWindowCentre = false;
721 m_scrollOnThumbRelease = false;
722
723 m_area = new wxPlotArea( this );
724 wxBoxSizer *mainsizer = new wxBoxSizer( wxHORIZONTAL );
725
726 if ((GetWindowStyleFlag() & wxPLOT_BUTTON_ALL) != 0)
727 {
728 wxBoxSizer *buttonlist = new wxBoxSizer( wxVERTICAL );
729 if ((GetWindowStyleFlag() & wxPLOT_BUTTON_ENLARGE) != 0)
730 {
731 buttonlist->Add( new wxBitmapButton( this, ID_ENLARGE, *GetEnlargeBitmap() ), 0, wxEXPAND|wxALL, 2 );
732 buttonlist->Add( new wxBitmapButton( this, ID_SHRINK, *GetShrinkBitmap() ), 0, wxEXPAND|wxALL, 2 );
733 buttonlist->Add( 20,10, 0 );
734 }
735 if ((GetWindowStyleFlag() & wxPLOT_BUTTON_MOVE) != 0)
736 {
737 buttonlist->Add( new wxBitmapButton( this, ID_MOVE_UP, *GetUpBitmap() ), 0, wxEXPAND|wxALL, 2 );
738 buttonlist->Add( new wxBitmapButton( this, ID_MOVE_DOWN, *GetDownBitmap() ), 0, wxEXPAND|wxALL, 2 );
739 buttonlist->Add( 20,10, 0 );
740 }
741 if ((GetWindowStyleFlag() & wxPLOT_BUTTON_ZOOM) != 0)
742 {
743 buttonlist->Add( new wxBitmapButton( this, ID_ZOOM_IN, *GetZoomInBitmap() ), 0, wxEXPAND|wxALL, 2 );
744 buttonlist->Add( new wxBitmapButton( this, ID_ZOOM_OUT, *GetZoomOutBitmap() ), 0, wxEXPAND|wxALL, 2 );
745 }
746 mainsizer->Add( buttonlist, 0, wxEXPAND|wxALL, 4 );
747 }
748
749 wxBoxSizer *plotsizer = new wxBoxSizer( wxHORIZONTAL );
750
751 //Add sizer to hold the title and plot.
752 //Title to be added later.
753 m_plotAndTitleSizer = new wxBoxSizer( wxVERTICAL );
754 m_plotAndTitleSizer->Add( plotsizer, 1, wxEXPAND | wxTOP, 10 );
755
756 if ((GetWindowStyleFlag() & wxPLOT_Y_AXIS) != 0)
757 {
758 m_yaxis = new wxPlotYAxisArea( this );
759
760 wxBoxSizer *vert1 = new wxBoxSizer( wxVERTICAL );
761 plotsizer->Add( vert1, 1, wxEXPAND|wxTOP,10 );
762 vert1->Add( m_yaxis, 1 );
763 if ((GetWindowStyleFlag() & wxPLOT_X_AXIS) != 0)
764 vert1->Add( 60, 40 );
765 }
766 else
767 {
768 m_yaxis = (wxPlotYAxisArea*) NULL;
769 }
770
771 if ((GetWindowStyleFlag() & wxPLOT_X_AXIS) != 0)
772 {
773 m_xaxis = new wxPlotXAxisArea( this );
774
775 wxBoxSizer *vert2 = new wxBoxSizer( wxVERTICAL );
776 plotsizer->Add( vert2, 5, wxEXPAND);
777 vert2->Add( m_area, 1, wxEXPAND|wxTOP,10 );
778 vert2->Add( m_xaxis, 0, wxEXPAND );
779 }
780 else
781 {
782 plotsizer->Add( m_area, 1, wxEXPAND );
783 m_xaxis = (wxPlotXAxisArea*) NULL;
784 }
785
786 mainsizer->Add( m_plotAndTitleSizer, 1, wxEXPAND );
787
788 SetAutoLayout( true );
789 SetSizer( mainsizer );
790 mainsizer->Fit(this);
791 mainsizer->SetSizeHints(this);
792
793 SetTargetWindow( m_area );
794
795 SetBackgroundColour( *wxWHITE );
796
797 m_current = (wxPlotCurve*) NULL;
798 }
799
800 wxPlotWindow::~wxPlotWindow()
801 {
802 }
803
804 void wxPlotWindow::Add( wxPlotCurve *curve )
805 {
806 m_curves.Append( curve );
807 if (!m_current) m_current = curve;
808
809 ResetScrollbar();
810 }
811
812 size_t wxPlotWindow::GetCount()
813 {
814 return m_curves.GetCount();
815 }
816
817 wxPlotCurve *wxPlotWindow::GetAt( size_t n )
818 {
819 wxList::compatibility_iterator node = m_curves.Item( n );
820 if (!node)
821 return (wxPlotCurve*) NULL;
822
823 return (wxPlotCurve*) node->GetData();
824 }
825
826 void wxPlotWindow::SetCurrentCurve( wxPlotCurve* current )
827 {
828 m_current = current;
829 m_area->Refresh( false );
830
831 RedrawYAxis();
832
833 wxPlotEvent event( wxEVT_PLOT_SEL_CHANGED, GetId() );
834 event.SetEventObject( this );
835 event.SetZoom( GetZoom() );
836 event.SetCurve( m_current );
837 GetEventHandler()->ProcessEvent( event );
838 }
839
840 void wxPlotWindow::Delete( wxPlotCurve* curve )
841 {
842 wxList::compatibility_iterator node = m_curves.Find( curve );
843 if (!node) return;
844
845 m_curves.DeleteObject( curve );
846
847 m_area->DeleteCurve( curve );
848 m_area->Refresh( false );
849
850 if (curve == m_current) m_current = (wxPlotCurve *) NULL;
851 }
852
853 wxPlotCurve *wxPlotWindow::GetCurrentCurve()
854 {
855 return m_current;
856 }
857
858 void wxPlotWindow::Add( wxPlotOnOffCurve *curve )
859 {
860 m_onOffCurves.Append( curve );
861 }
862
863 void wxPlotWindow::Delete( wxPlotOnOffCurve* curve )
864 {
865 wxList::compatibility_iterator node = m_onOffCurves.Find( curve );
866 if (!node) return;
867
868 m_onOffCurves.DeleteObject( curve );
869 }
870
871 size_t wxPlotWindow::GetOnOffCurveCount()
872 {
873 return m_onOffCurves.GetCount();
874 }
875
876 wxPlotOnOffCurve *wxPlotWindow::GetOnOffCurveAt( size_t n )
877 {
878 wxList::compatibility_iterator node = m_onOffCurves.Item( n );
879 if (!node)
880 return (wxPlotOnOffCurve*) NULL;
881
882 return (wxPlotOnOffCurve*) node->GetData();
883 }
884
885 void wxPlotWindow::Move( wxPlotCurve* curve, int pixels_up )
886 {
887 m_area->DeleteCurve( curve );
888
889 curve->SetOffsetY( curve->GetOffsetY() + pixels_up );
890
891 m_area->Refresh( false );
892
893 RedrawYAxis();
894 }
895
896 void wxPlotWindow::OnMoveUp( wxCommandEvent& WXUNUSED(event) )
897 {
898 if (!m_current) return;
899
900 Move( m_current, 25 );
901 }
902
903 void wxPlotWindow::OnMoveDown( wxCommandEvent& WXUNUSED(event) )
904 {
905 if (!m_current) return;
906
907 Move( m_current, -25 );
908 }
909
910 void wxPlotWindow::Enlarge( wxPlotCurve *curve, double factor )
911 {
912 m_area->DeleteCurve( curve );
913
914 int client_width;
915 int client_height;
916 m_area->GetClientSize( &client_width, &client_height);
917 double offset = (double)curve->GetOffsetY() / (double)client_height;
918
919 double range = curve->GetEndY() - curve->GetStartY();
920 offset *= range;
921
922 double new_range = range / factor;
923 double new_offset = offset / factor;
924
925 if (m_enlargeAroundWindowCentre)
926 {
927 double middle = curve->GetStartY() - offset + range/2;
928
929 curve->SetStartY( middle - new_range / 2 + new_offset );
930 curve->SetEndY( middle + new_range / 2 + new_offset );
931 }
932 else
933 {
934 curve->SetStartY( (curve->GetStartY() - offset)/factor + new_offset );
935 curve->SetEndY( (curve->GetEndY() - offset)/factor + new_offset );
936 }
937
938 m_area->Refresh( false );
939 RedrawYAxis();
940 }
941
942 void wxPlotWindow::SetUnitsPerValue( double upv )
943 {
944 m_xUnitsPerValue = upv;
945
946 RedrawXAxis();
947 }
948
949 void wxPlotWindow::SetZoom( double zoom )
950 {
951 double old_zoom = m_xZoom;
952 m_xZoom = zoom;
953
954 int view_x = 0;
955 int view_y = 0;
956 GetViewStart( &view_x, &view_y );
957
958 wxInt32 max = 0;
959 wxList::compatibility_iterator node = m_curves.GetFirst();
960 while (node)
961 {
962 wxPlotCurve *curve = (wxPlotCurve*) node->GetData();
963 if (curve->GetEndX() > max)
964 max = curve->GetEndX();
965 node = node->GetNext();
966 }
967 SetScrollbars( wxPLOT_SCROLL_STEP, wxPLOT_SCROLL_STEP,
968 (int)((max*m_xZoom)/wxPLOT_SCROLL_STEP)+1, 0,
969 (int)(view_x*zoom/old_zoom), 0,
970 true );
971
972 RedrawXAxis();
973 m_area->Refresh( true );
974 }
975
976 void wxPlotWindow::ResetScrollbar()
977 {
978 wxInt32 max = 0;
979 wxList::compatibility_iterator node = m_curves.GetFirst();
980 while (node)
981 {
982 wxPlotCurve *curve = (wxPlotCurve*) node->GetData();
983 if (curve->GetEndX() > max)
984 max = curve->GetEndX();
985 node = node->GetNext();
986 }
987
988 SetScrollbars( wxPLOT_SCROLL_STEP, wxPLOT_SCROLL_STEP,
989 (int)(((max*m_xZoom)/wxPLOT_SCROLL_STEP)+1), 0 );
990 }
991
992 void wxPlotWindow::AddChartTitle(const wxString& title, wxFont font,
993 wxColour colour)
994 {
995 m_title = title;
996 m_titleFont = font;
997 m_titleColour = colour;
998 DrawChartTitle();
999 }
1000
1001 void wxPlotWindow::DrawChartTitle()
1002 {
1003 if(m_title.size() != 0)
1004 {
1005 //If it is already added, remove child and delete
1006 if(m_titleStaticText)
1007 {
1008 RemoveChild( m_titleStaticText );
1009 m_titleStaticText->Destroy();
1010 }
1011
1012 //Create the text control and set the font, colour
1013 m_titleStaticText = new wxStaticText( this, -1, m_title );
1014 m_titleStaticText->SetFont( m_titleFont );
1015 m_titleStaticText->SetForegroundColour( m_titleColour );
1016
1017 //Create a sizer for the title. Prepend it to the Plot + Title sizer.
1018 wxBoxSizer* titleSizer = new wxBoxSizer( wxHORIZONTAL );
1019 titleSizer->Add( m_titleStaticText, 0, wxALIGN_CENTER | wxALL, 10 );
1020 m_plotAndTitleSizer->Prepend( titleSizer, 0, wxALIGN_CENTER_HORIZONTAL );
1021
1022 //Finally, force layout
1023 m_plotAndTitleSizer->Layout();
1024 }
1025 }
1026
1027 void wxPlotWindow::RedrawXAxis()
1028 {
1029 if (m_xaxis)
1030 m_xaxis->Refresh( true );
1031 }
1032
1033 void wxPlotWindow::RedrawYAxis()
1034 {
1035 if (m_yaxis)
1036 m_yaxis->Refresh( true );
1037 }
1038
1039 void wxPlotWindow::RedrawEverything()
1040 {
1041 if (m_xaxis)
1042 m_xaxis->Refresh( true );
1043 if (m_yaxis)
1044 m_yaxis->Refresh( true );
1045 m_area->Refresh( true );
1046
1047 DrawChartTitle();
1048 }
1049
1050 void wxPlotWindow::OnZoomIn( wxCommandEvent& WXUNUSED(event) )
1051 {
1052 SetZoom( m_xZoom * 1.5 );
1053 }
1054
1055 void wxPlotWindow::OnZoomOut( wxCommandEvent& WXUNUSED(event) )
1056 {
1057 SetZoom( m_xZoom * 0.6666 );
1058 }
1059
1060 void wxPlotWindow::OnEnlarge( wxCommandEvent& WXUNUSED(event) )
1061 {
1062 if (!m_current) return;
1063
1064 Enlarge( m_current, 1.5 );
1065 }
1066
1067 void wxPlotWindow::OnShrink( wxCommandEvent& WXUNUSED(event) )
1068 {
1069 if (!m_current) return;
1070
1071 Enlarge( m_current, 0.6666666 );
1072 }
1073
1074 void wxPlotWindow::OnScroll2( wxScrollWinEvent& event )
1075 {
1076 if ((!m_scrollOnThumbRelease) || (event.GetEventType() != wxEVT_SCROLLWIN_THUMBTRACK))
1077 {
1078 wxScrolledWindow::OnScroll( event );
1079 RedrawXAxis();
1080 }
1081 }
1082
1083 // ----------------------------------------------------------------------------
1084 // global functions
1085 // ----------------------------------------------------------------------------
1086
1087 // FIXME MT-UNSAFE
1088 static wxBitmap *GetEnlargeBitmap()
1089 {
1090 static wxBitmap* s_bitmap = (wxBitmap *) NULL;
1091 static bool s_loaded = false;
1092
1093 if ( !s_loaded )
1094 {
1095 s_loaded = true; // set it to true anyhow, we won't try again
1096
1097 #if defined(__WXMSW__) || defined(__WXPM__)
1098 s_bitmap = new wxBitmap(_T("plot_enl_bmp"), wxBITMAP_TYPE_RESOURCE);
1099 #else
1100 s_bitmap = new wxBitmap( plot_enl_xpm );
1101 #endif
1102 }
1103
1104 return s_bitmap;
1105 }
1106
1107 static wxBitmap *GetShrinkBitmap()
1108 {
1109 static wxBitmap* s_bitmap = (wxBitmap *) NULL;
1110 static bool s_loaded = false;
1111
1112 if ( !s_loaded )
1113 {
1114 s_loaded = true; // set it to true anyhow, we won't try again
1115
1116 #if defined(__WXMSW__) || defined(__WXPM__)
1117 s_bitmap = new wxBitmap(_T("plot_shr_bmp"), wxBITMAP_TYPE_RESOURCE);
1118 #else
1119 s_bitmap = new wxBitmap( plot_shr_xpm );
1120 #endif
1121 }
1122
1123 return s_bitmap;
1124 }
1125
1126 static wxBitmap *GetZoomInBitmap()
1127 {
1128 static wxBitmap* s_bitmap = (wxBitmap *) NULL;
1129 static bool s_loaded = false;
1130
1131 if ( !s_loaded )
1132 {
1133 s_loaded = true; // set it to true anyhow, we won't try again
1134
1135 #if defined(__WXMSW__) || defined(__WXPM__)
1136 s_bitmap = new wxBitmap(_T("plot_zin_bmp"), wxBITMAP_TYPE_RESOURCE);
1137 #else
1138 s_bitmap = new wxBitmap( plot_zin_xpm );
1139 #endif
1140 }
1141
1142 return s_bitmap;
1143 }
1144
1145 static wxBitmap *GetZoomOutBitmap()
1146 {
1147 static wxBitmap* s_bitmap = (wxBitmap *) NULL;
1148 static bool s_loaded = false;
1149
1150 if ( !s_loaded )
1151 {
1152 s_loaded = true; // set it to true anyhow, we won't try again
1153
1154 #if defined(__WXMSW__) || defined(__WXPM__)
1155 s_bitmap = new wxBitmap(_T("plot_zot_bmp"), wxBITMAP_TYPE_RESOURCE);
1156 #else
1157 s_bitmap = new wxBitmap( plot_zot_xpm );
1158 #endif
1159 }
1160
1161 return s_bitmap;
1162 }
1163
1164 static wxBitmap *GetUpBitmap()
1165 {
1166 static wxBitmap* s_bitmap = (wxBitmap *) NULL;
1167 static bool s_loaded = false;
1168
1169 if ( !s_loaded )
1170 {
1171 s_loaded = true; // set it to true anyhow, we won't try again
1172
1173 #if defined(__WXMSW__) || defined(__WXPM__)
1174 s_bitmap = new wxBitmap(_T("plot_up_bmp"), wxBITMAP_TYPE_RESOURCE);
1175 #else
1176 s_bitmap = new wxBitmap( plot_up_xpm );
1177 #endif
1178 }
1179
1180 return s_bitmap;
1181 }
1182
1183 static wxBitmap *GetDownBitmap()
1184 {
1185 static wxBitmap* s_bitmap = (wxBitmap *) NULL;
1186 static bool s_loaded = false;
1187
1188 if ( !s_loaded )
1189 {
1190 s_loaded = true; // set it to true anyhow, we won't try again
1191
1192 #if defined(__WXMSW__) || defined(__WXPM__)
1193 s_bitmap = new wxBitmap(_T("plot_dwn_bmp"), wxBITMAP_TYPE_RESOURCE);
1194 #else
1195 s_bitmap = new wxBitmap( plot_dwn_xpm );
1196 #endif
1197 }
1198
1199 return s_bitmap;
1200 }
1201