]> git.saurik.com Git - wxWidgets.git/blame - src/generic/plot.cpp
1. wxTimer change - now generates EVT_TIMER()
[wxWidgets.git] / src / generic / plot.cpp
CommitLineData
981b2508
RR
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#endif
33
34#include "wx/generic/plot.h"
35
846e1424
RR
36#include <math.h>
37
981b2508
RR
38//-----------------------------------------------------------------------------
39// wxPlotCurve
40//-----------------------------------------------------------------------------
41
42IMPLEMENT_ABSTRACT_CLASS(wxPlotCurve, wxObject)
43
846e1424 44wxPlotCurve::wxPlotCurve( int offsetY, double startY, double endY )
981b2508
RR
45{
46 m_offsetY = offsetY;
846e1424
RR
47 m_startY = startY;
48 m_endY = endY;
981b2508
RR
49}
50
51//-----------------------------------------------------------------------------
52// wxPlotArea
53//-----------------------------------------------------------------------------
54
55IMPLEMENT_DYNAMIC_CLASS(wxPlotArea, wxWindow)
56
57BEGIN_EVENT_TABLE(wxPlotArea, wxWindow)
58 EVT_PAINT( wxPlotArea::OnPaint)
59 EVT_LEFT_DOWN( wxPlotArea::OnMouse)
60END_EVENT_TABLE()
61
62wxPlotArea::wxPlotArea( wxPlotWindow *parent )
63 : wxWindow( parent, -1, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER, "plotarea" )
64{
65 m_owner = parent;
66
67 SetBackgroundColour( *wxWHITE );
68}
69
70void wxPlotArea::OnMouse( wxMouseEvent &event )
71{
72 int client_width;
73 int client_height;
74 GetClientSize( &client_width, &client_height);
75 int view_x;
76 int view_y;
77 m_owner->GetViewStart( &view_x, &view_y );
78 view_x *= 10;
79 view_y *= 10;
80
81 int x = event.GetX();
82 int y = event.GetY();
83 x += view_x;
84 y += view_y;
85
86 wxNode *node = m_owner->m_curves.First();
87 while (node)
88 {
89 wxPlotCurve *curve = (wxPlotCurve*)node->Data();
90
846e1424
RR
91 double double_client_height = (double)client_height;
92 double range = curve->GetEndY() - curve->GetStartY();
93 double end = curve->GetEndY();
94 wxCoord offset_y = curve->GetOffsetY();
95
96 double dy = (end - curve->GetY( x )) / range;
97 wxCoord curve_y = (wxCoord)(dy * double_client_height) - offset_y - 1;
98
981b2508
RR
99 if ((y-curve_y < 4) && (y-curve_y > -4))
100 {
101 m_owner->SetCurrent( curve );
102 return;
103 }
104
105 node = node->Next();
106 }
107}
108
d3a809c7
RR
109void wxPlotArea::DeleteCurve( wxPlotCurve *curve, int from, int to )
110{
111 wxClientDC dc(this);
112 m_owner->PrepareDC( dc );
113 dc.SetPen( *wxWHITE_PEN );
114 DrawCurve( &dc, curve, from, to );
115}
116
117void wxPlotArea::DrawCurve( wxDC *dc, wxPlotCurve *curve, int from, int to )
981b2508 118{
d3a809c7
RR
119 int view_x;
120 int view_y;
121 m_owner->GetViewStart( &view_x, &view_y );
122 view_x *= 10;
123
124 if (from == -1)
125 from = view_x;
126
981b2508
RR
127 int client_width;
128 int client_height;
129 GetClientSize( &client_width, &client_height);
d3a809c7
RR
130
131 if (to == -1)
132 to = view_x + client_width;
133
134 int start_x = wxMax( from, curve->GetStartX() );
135 int end_x = wxMin( to, curve->GetEndX() );
136
137 start_x = wxMax( view_x, start_x );
138 end_x = wxMin( view_x + client_width, end_x );
139
140 double double_client_height = (double)client_height;
141 double range = curve->GetEndY() - curve->GetStartY();
142 double end = curve->GetEndY();
143 wxCoord offset_y = curve->GetOffsetY();
144
145 wxCoord y=0,last_y=0;
146 for (int x = start_x; x < end_x; x++)
147 {
148 double dy = (end - curve->GetY( x )) / range;
149 y = (wxCoord)(dy * double_client_height) - offset_y - 1;
150
151 if (x != start_x)
152 dc->DrawLine( x-1, last_y, x, y );
153
154 last_y = y;
155 }
156}
157
158void wxPlotArea::OnPaint( wxPaintEvent &WXUNUSED(event) )
159{
981b2508
RR
160 int view_x;
161 int view_y;
162 m_owner->GetViewStart( &view_x, &view_y );
163 view_x *= 10;
164 view_y *= 10;
165
166 wxPaintDC dc( this );
167 m_owner->PrepareDC( dc );
168
169 wxRegionIterator upd( GetUpdateRegion() );
170
171 while (upd)
172 {
173 int update_x = upd.GetX();
174 int update_y = upd.GetY();
175 int update_width = upd.GetWidth();
176
177 update_x += view_x;
178 update_y += view_y;
179
846e1424 180/*
981b2508
RR
181 if (m_owner->m_current)
182 {
183 dc.SetPen( *wxLIGHT_GREY_PEN );
184 int base_line = client_height - m_owner->m_current->GetOffsetY();
185 dc.DrawLine( update_x-1, base_line-1, update_x+update_width+2, base_line-1 );
186 }
846e1424 187*/
981b2508
RR
188
189 wxNode *node = m_owner->m_curves.First();
190 while (node)
191 {
192 wxPlotCurve *curve = (wxPlotCurve*)node->Data();
193
194 if (curve == m_owner->GetCurrent())
195 dc.SetPen( *wxBLACK_PEN );
196 else
197 dc.SetPen( *wxLIGHT_GREY_PEN );
d3a809c7
RR
198
199 DrawCurve( &dc, curve, update_x-1, update_x+update_width+2 );
981b2508 200
981b2508
RR
201 node = node->Next();
202 }
203 upd ++;
204 }
205}
206
207//-----------------------------------------------------------------------------
208// wxPlotWindow
209//-----------------------------------------------------------------------------
210
211#define ID_ENLARGE_100 1000
212#define ID_ENLARGE_50 1001
213#define ID_SHRINK_33 1002
214#define ID_SHRINK_50 1003
215
216#define ID_MOVE_UP 1006
217#define ID_MOVE_DOWN 1007
218
219
220IMPLEMENT_DYNAMIC_CLASS(wxPlotWindow, wxScrolledWindow)
221
222BEGIN_EVENT_TABLE(wxPlotWindow, wxScrolledWindow)
d3a809c7
RR
223 EVT_PAINT( wxPlotWindow::OnPaint)
224 EVT_BUTTON( ID_MOVE_UP, wxPlotWindow::OnMoveUp)
225 EVT_BUTTON( ID_MOVE_DOWN, wxPlotWindow::OnMoveDown)
226
227 EVT_BUTTON( ID_ENLARGE_100, wxPlotWindow::OnEnlarge100)
228 EVT_BUTTON( ID_ENLARGE_50, wxPlotWindow::OnEnlarge50)
229 EVT_BUTTON( ID_SHRINK_50, wxPlotWindow::OnShrink50)
230 EVT_BUTTON( ID_SHRINK_33, wxPlotWindow::OnShrink33)
981b2508
RR
231END_EVENT_TABLE()
232
233wxPlotWindow::wxPlotWindow( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, int flag )
234 : wxScrolledWindow( parent, id, pos, size, flag, "plotcanvas" )
235{
236 m_area = new wxPlotArea( this );
237
238 wxBoxSizer *mainsizer = new wxBoxSizer( wxHORIZONTAL );
239
240 wxBoxSizer *buttonlist = new wxBoxSizer( wxVERTICAL );
241 buttonlist->Add( new wxButton( this, ID_ENLARGE_100, _("+ 100%") ), 0, wxEXPAND|wxALL, 5 );
242 buttonlist->Add( new wxButton( this, ID_ENLARGE_50, _("+ 50%") ), 0, wxEXPAND|wxALL, 5 );
243 buttonlist->Add( new wxButton( this, ID_SHRINK_33, _("- 33%") ), 0, wxEXPAND|wxALL, 5 );
244 buttonlist->Add( new wxButton( this, ID_SHRINK_50, _("- 50%") ), 0, wxEXPAND|wxALL, 5 );
245 buttonlist->Add( 20,20, 0 );
246 buttonlist->Add( new wxButton( this, ID_MOVE_UP, _("Up") ), 0, wxEXPAND|wxALL, 5 );
247 buttonlist->Add( new wxButton( this, ID_MOVE_DOWN, _("Down") ), 0, wxEXPAND|wxALL, 5 );
248 buttonlist->Add( 20,20, 1 );
249
250 mainsizer->Add( buttonlist, 0, wxEXPAND );
251
252 mainsizer->Add( m_area, 1, wxEXPAND|wxLEFT, 50 );
253
254 SetAutoLayout( TRUE );
255 SetSizer( mainsizer );
256
257 SetTargetWindow( m_area );
258
259 SetBackgroundColour( *wxWHITE );
260
261 m_current = (wxPlotCurve*) NULL;
262}
263
264wxPlotWindow::~wxPlotWindow()
265{
266}
267
268void wxPlotWindow::Add( wxPlotCurve *curve )
269{
270 m_curves.Append( curve );
271 if (!m_current) m_current = curve;
272}
273
274size_t wxPlotWindow::GetCount()
275{
276 return m_curves.GetCount();
277}
278
279wxPlotCurve *wxPlotWindow::GetAt( size_t n )
280{
281 wxNode *node = m_curves.Nth( n );
282 if (!node)
283 return (wxPlotCurve*) NULL;
284
285 return (wxPlotCurve*) node->Data();
286}
287
288void wxPlotWindow::SetCurrent( wxPlotCurve* current )
289{
290 m_current = current;
846e1424 291 m_area->Refresh( FALSE );
981b2508 292
d3a809c7
RR
293 RedrawYAxis();
294}
295
296wxPlotCurve *wxPlotWindow::GetCurrent()
297{
298 return m_current;
299}
300
301void wxPlotWindow::Move( wxPlotCurve* curve, int pixels_up )
302{
303 m_area->DeleteCurve( curve );
304
305 curve->SetOffsetY( curve->GetOffsetY() + pixels_up );
306
307 m_area->Refresh( FALSE );
308
309 RedrawYAxis();
310}
311
312void wxPlotWindow::OnMoveUp( wxCommandEvent& WXUNUSED(event) )
313{
314 if (!m_current) return;
315
316 Move( m_current, 25 );
317}
318
319void wxPlotWindow::OnMoveDown( wxCommandEvent& WXUNUSED(event) )
320{
321 if (!m_current) return;
322
323 Move( m_current, -25 );
324}
325
326void wxPlotWindow::Enlarge( wxPlotCurve *curve, double factor )
327{
328 m_area->DeleteCurve( curve );
329
330 double range = curve->GetEndY() - curve->GetStartY();
331 double new_range = range * factor;
332 double middle = curve->GetEndY() - range/2;
333 curve->SetStartY( middle - new_range / 2 );
334 curve->SetEndY( middle + new_range / 2 );
335
336 m_area->Refresh( FALSE );
337
338 RedrawYAxis();
339}
340
341void wxPlotWindow::OnEnlarge100( wxCommandEvent& WXUNUSED(event) )
342{
343 if (!m_current) return;
344
345 Enlarge( m_current, 2.0 );
346}
347
348void wxPlotWindow::OnEnlarge50( wxCommandEvent& WXUNUSED(event) )
349{
350 if (!m_current) return;
351
352 Enlarge( m_current, 1.5 );
353}
354
355void wxPlotWindow::OnShrink50( wxCommandEvent& WXUNUSED(event) )
356{
357 if (!m_current) return;
358
359 Enlarge( m_current, 0.5 );
360}
361
362void wxPlotWindow::OnShrink33( wxCommandEvent& WXUNUSED(event) )
363{
364 if (!m_current) return;
981b2508 365
d3a809c7
RR
366 Enlarge( m_current, 0.6666666 );
367}
368
369void wxPlotWindow::RedrawYAxis()
370{
981b2508
RR
371 int client_width;
372 int client_height;
373 GetClientSize( &client_width, &client_height);
d3a809c7
RR
374
375 wxPoint pos( m_area->GetPosition() );
376
846e1424 377 wxRect rect(pos.x-45,0,45,client_height);
981b2508
RR
378 Refresh(TRUE,&rect);
379}
380
981b2508
RR
381void wxPlotWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
382{
383 wxPaintDC dc( this );
384
385 if (!m_current) return;
386
387 int client_width;
388 int client_height;
389 GetClientSize( &client_width, &client_height);
390
391 dc.SetPen( *wxBLACK_PEN );
392
393 wxPoint pos( m_area->GetPosition() );
394
846e1424
RR
395 double range = m_current->GetEndY() - m_current->GetStartY();
396 double offset = ((double) m_current->GetOffsetY() / (double)client_height ) * range;
397 double start = m_current->GetStartY() - offset;
398 double end = m_current->GetEndY() - offset;
399 int int_log_range = (int)floor( log10( range ) );
400 double step = 1.0;
401 if (int_log_range > 0)
402 {
403 for (int i = 0; i < int_log_range; i++)
404 step *= 10;
405 }
406 if (int_log_range < 0)
407 {
408 for (int i = 0; i < -int_log_range; i++)
409 step /= 10;
410 }
411 double lower = ceil(start / step) * step;
412 double upper = floor(end / step) * step;
d3a809c7
RR
413
414 // if too few values, shrink size
846e1424 415 int steps = (int)ceil((upper-lower)/step);
d3a809c7
RR
416 if (steps < 4)
417 {
418 step /= 2;
419 if (lower-step > start) lower -= step;
420 if (upper+step < end) upper += step;
421 }
422
423 // if still too few, again
424 steps = (int)ceil((upper-lower)/step);
425 if (steps < 4)
846e1424
RR
426 {
427 step /= 2;
428 if (lower-step > start) lower -= step;
d3a809c7 429 if (upper+step < end) upper += step;
846e1424
RR
430 }
431
432 double current = lower;
433 while (current < upper+(step/2))
434 {
435 int y = (int)((m_current->GetEndY()-current) / range * (double)client_height) - 1;
436 y -= m_current->GetOffsetY();
437 if ((y > 10) && (y < client_height-7))
438 {
439 dc.DrawLine( pos.x-15, y, pos.x-7, y );
440 wxString label;
8ca97ad0 441 label.Printf( wxT("%.1f"), current );
846e1424
RR
442 dc.DrawText( label, pos.x-45, y-7 );
443 }
444
445 current += step;
446 }
447
d3a809c7
RR
448 dc.DrawLine( pos.x-15, 6, pos.x-15, client_height-5 );
449 dc.DrawLine( pos.x-19, 8, pos.x-15, 2 );
450 dc.DrawLine( pos.x-10, 9, pos.x-15, 2 );
981b2508 451
981b2508
RR
452}
453