home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / contrib / src / plot / plot.cpp < prev    next >
C/C++ Source or Header  |  2002-01-31  |  33KB  |  1,159 lines

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