]> git.saurik.com Git - wxWidgets.git/blame_incremental - contrib/src/plot/plot.cpp
wxOS2/OW warning and build fixes.
[wxWidgets.git] / contrib / src / plot / plot.cpp
... / ...
CommitLineData
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
58DEFINE_EVENT_TYPE(wxEVT_PLOT_SEL_CHANGING);
59DEFINE_EVENT_TYPE(wxEVT_PLOT_SEL_CHANGED);
60DEFINE_EVENT_TYPE(wxEVT_PLOT_CLICKED);
61DEFINE_EVENT_TYPE(wxEVT_PLOT_DOUBLECLICKED);
62DEFINE_EVENT_TYPE(wxEVT_PLOT_ZOOM_IN);
63DEFINE_EVENT_TYPE(wxEVT_PLOT_ZOOM_OUT);
64DEFINE_EVENT_TYPE(wxEVT_PLOT_VALUE_SEL_CREATING);
65DEFINE_EVENT_TYPE(wxEVT_PLOT_VALUE_SEL_CREATED);
66DEFINE_EVENT_TYPE(wxEVT_PLOT_VALUE_SEL_CHANGING);
67DEFINE_EVENT_TYPE(wxEVT_PLOT_VALUE_SEL_CHANGED);
68DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_SEL_CREATING);
69DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_SEL_CREATED);
70DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_SEL_CHANGING);
71DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_SEL_CHANGED);
72DEFINE_EVENT_TYPE(wxEVT_PLOT_BEGIN_X_LABEL_EDIT);
73DEFINE_EVENT_TYPE(wxEVT_PLOT_END_X_LABEL_EDIT);
74DEFINE_EVENT_TYPE(wxEVT_PLOT_BEGIN_Y_LABEL_EDIT);
75DEFINE_EVENT_TYPE(wxEVT_PLOT_END_Y_LABEL_EDIT);
76DEFINE_EVENT_TYPE(wxEVT_PLOT_BEGIN_TITLE_EDIT);
77DEFINE_EVENT_TYPE(wxEVT_PLOT_END_TITLE_EDIT);
78DEFINE_EVENT_TYPE(wxEVT_PLOT_AREA_CREATE);
79
80//----------------------------------------------------------------------------
81// accessor functions for the bitmaps (may return NULL, check for it!)
82//----------------------------------------------------------------------------
83
84static wxBitmap *GetEnlargeBitmap();
85static wxBitmap *GetShrinkBitmap();
86static wxBitmap *GetZoomInBitmap();
87static wxBitmap *GetZoomOutBitmap();
88static wxBitmap *GetUpBitmap();
89static wxBitmap *GetDownBitmap();
90
91//-----------------------------------------------------------------------------
92// consts
93//-----------------------------------------------------------------------------
94
95#define wxPLOT_SCROLL_STEP 30
96
97//-----------------------------------------------------------------------------
98// wxPlotEvent
99//-----------------------------------------------------------------------------
100
101wxPlotEvent::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
113IMPLEMENT_ABSTRACT_CLASS(wxPlotCurve, wxObject)
114
115wxPlotCurve::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
127IMPLEMENT_CLASS(wxPlotOnOffCurve, wxObject)
128
129#include "wx/arrimpl.cpp"
130WX_DEFINE_OBJARRAY(wxArrayPlotOnOff);
131
132wxPlotOnOffCurve::wxPlotOnOffCurve( int offsetY )
133{
134 m_offsetY = offsetY;
135 m_minX = -1;
136 m_maxX = -1;
137}
138
139void 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
156size_t wxPlotOnOffCurve::GetCount()
157{
158 return m_marks.GetCount();
159}
160
161wxInt32 wxPlotOnOffCurve::GetOn( size_t index )
162{
163 wxPlotOnOff *v = &m_marks.Item( index );
164 return v->m_on;
165}
166
167wxInt32 wxPlotOnOffCurve::GetOff( size_t index )
168{
169 wxPlotOnOff *v = &m_marks.Item( index );
170 return v->m_off;
171}
172
173void* wxPlotOnOffCurve::GetClientData( size_t index )
174{
175 wxPlotOnOff *v = &m_marks.Item( index );
176 return v->m_clientData;
177}
178
179wxPlotOnOff *wxPlotOnOffCurve::GetAt( size_t index )
180{
181 return &m_marks.Item( index );
182}
183
184void 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
191void 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
200IMPLEMENT_DYNAMIC_CLASS(wxPlotArea, wxWindow)
201
202BEGIN_EVENT_TABLE(wxPlotArea, wxWindow)
203 EVT_PAINT( wxPlotArea::OnPaint)
204 EVT_LEFT_DOWN( wxPlotArea::OnMouse)
205 EVT_LEFT_DCLICK( wxPlotArea::OnMouse)
206END_EVENT_TABLE()
207
208wxPlotArea::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
218void 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
274void 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
282void 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
327void 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
387void 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
445void 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
455IMPLEMENT_DYNAMIC_CLASS(wxPlotXAxisArea, wxWindow)
456
457BEGIN_EVENT_TABLE(wxPlotXAxisArea, wxWindow)
458 EVT_PAINT( wxPlotXAxisArea::OnPaint)
459 EVT_LEFT_DOWN( wxPlotXAxisArea::OnMouse)
460END_EVENT_TABLE()
461
462wxPlotXAxisArea::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
471void 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
490void 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
582IMPLEMENT_DYNAMIC_CLASS(wxPlotYAxisArea, wxWindow)
583
584BEGIN_EVENT_TABLE(wxPlotYAxisArea, wxWindow)
585 EVT_PAINT( wxPlotYAxisArea::OnPaint)
586 EVT_LEFT_DOWN( wxPlotYAxisArea::OnMouse)
587END_EVENT_TABLE()
588
589wxPlotYAxisArea::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
598void wxPlotYAxisArea::OnMouse( wxMouseEvent &WXUNUSED(event) )
599{
600 /* do something here */
601}
602
603void 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
698IMPLEMENT_DYNAMIC_CLASS(wxPlotWindow, wxScrolledWindow)
699
700BEGIN_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)
711END_EVENT_TABLE()
712
713wxPlotWindow::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
800wxPlotWindow::~wxPlotWindow()
801{
802}
803
804void wxPlotWindow::Add( wxPlotCurve *curve )
805{
806 m_curves.Append( curve );
807 if (!m_current) m_current = curve;
808
809 ResetScrollbar();
810}
811
812size_t wxPlotWindow::GetCount()
813{
814 return m_curves.GetCount();
815}
816
817wxPlotCurve *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
826void 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
840void 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
853wxPlotCurve *wxPlotWindow::GetCurrentCurve()
854{
855 return m_current;
856}
857
858void wxPlotWindow::Add( wxPlotOnOffCurve *curve )
859{
860 m_onOffCurves.Append( curve );
861}
862
863void 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
871size_t wxPlotWindow::GetOnOffCurveCount()
872{
873 return m_onOffCurves.GetCount();
874}
875
876wxPlotOnOffCurve *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
885void 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
896void wxPlotWindow::OnMoveUp( wxCommandEvent& WXUNUSED(event) )
897{
898 if (!m_current) return;
899
900 Move( m_current, 25 );
901}
902
903void wxPlotWindow::OnMoveDown( wxCommandEvent& WXUNUSED(event) )
904{
905 if (!m_current) return;
906
907 Move( m_current, -25 );
908}
909
910void 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
942void wxPlotWindow::SetUnitsPerValue( double upv )
943{
944 m_xUnitsPerValue = upv;
945
946 RedrawXAxis();
947}
948
949void 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
976void 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
992void 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
1001void 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
1027void wxPlotWindow::RedrawXAxis()
1028{
1029 if (m_xaxis)
1030 m_xaxis->Refresh( true );
1031}
1032
1033void wxPlotWindow::RedrawYAxis()
1034{
1035 if (m_yaxis)
1036 m_yaxis->Refresh( true );
1037}
1038
1039void 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
1050void wxPlotWindow::OnZoomIn( wxCommandEvent& WXUNUSED(event) )
1051{
1052 SetZoom( m_xZoom * 1.5 );
1053}
1054
1055void wxPlotWindow::OnZoomOut( wxCommandEvent& WXUNUSED(event) )
1056{
1057 SetZoom( m_xZoom * 0.6666 );
1058}
1059
1060void wxPlotWindow::OnEnlarge( wxCommandEvent& WXUNUSED(event) )
1061{
1062 if (!m_current) return;
1063
1064 Enlarge( m_current, 1.5 );
1065}
1066
1067void wxPlotWindow::OnShrink( wxCommandEvent& WXUNUSED(event) )
1068{
1069 if (!m_current) return;
1070
1071 Enlarge( m_current, 0.6666666 );
1072}
1073
1074void 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
1088static 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
1107static 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
1126static 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
1145static 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
1164static 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
1183static 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