]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/plot.cpp
long -> wxCoord
[wxWidgets.git] / src / generic / plot.cpp
index ca02719c094be88d125c047d28e7a8bad187fef3..cf2dfddf960875c7e38c9be4a2d241a8a379a5d8 100644 (file)
 
 #include "wx/generic/plot.h"
 
+#include <math.h>
+
 //-----------------------------------------------------------------------------
 // wxPlotCurve
 //-----------------------------------------------------------------------------
 
 IMPLEMENT_ABSTRACT_CLASS(wxPlotCurve, wxObject)
 
-wxPlotCurve::wxPlotCurve( int offsetY )
+wxPlotCurve::wxPlotCurve( int offsetY, double startY, double endY )
 {
     m_offsetY = offsetY;
+    m_startY = startY;
+    m_endY = endY;
 }
 
 //-----------------------------------------------------------------------------
@@ -84,10 +88,14 @@ void wxPlotArea::OnMouse( wxMouseEvent &event )
     {
         wxPlotCurve *curve = (wxPlotCurve*)node->Data();
             
-        wxCoord offset_y = client_height - curve->GetOffsetY();
-
-        double dy = curve->GetY( x );
-        int curve_y = (wxCoord)(-dy * 100) + offset_y - 1;
+        double double_client_height = (double)client_height;
+        double range = curve->GetEndY() - curve->GetStartY();
+        double end = curve->GetEndY();
+        wxCoord offset_y = curve->GetOffsetY();
+            
+        double dy = (end - curve->GetY( x )) / range;
+        wxCoord curve_y = (wxCoord)(dy * double_client_height) - offset_y - 1;
+                
         if ((y-curve_y < 4) && (y-curve_y > -4))
         {
             m_owner->SetCurrent( curve );
@@ -98,11 +106,57 @@ void wxPlotArea::OnMouse( wxMouseEvent &event )
     }
 }
 
-void wxPlotArea::OnPaint( wxPaintEvent &WXUNUSED(event) )
+void wxPlotArea::DeleteCurve( wxPlotCurve *curve, int from, int to )
+{
+    wxClientDC dc(this);
+    m_owner->PrepareDC( dc );
+    dc.SetPen( *wxWHITE_PEN );
+    DrawCurve( &dc, curve, from, to );
+}
+
+void wxPlotArea::DrawCurve( wxDC *dc, wxPlotCurve *curve, int from, int to )
 {
+    int view_x;
+    int view_y;
+    m_owner->GetViewStart( &view_x, &view_y );
+    view_x *= 10;
+    
+    if (from == -1)
+        from = view_x;
+
     int client_width;
     int client_height;
     GetClientSize( &client_width, &client_height);
+    
+    if (to == -1)
+        to = view_x + client_width;
+        
+    int start_x = wxMax( from, curve->GetStartX() );
+    int end_x = wxMin( to, curve->GetEndX() );
+
+    start_x = wxMax( view_x, start_x );
+    end_x = wxMin( view_x + client_width, end_x );
+
+    double double_client_height = (double)client_height;
+    double range = curve->GetEndY() - curve->GetStartY();
+    double end = curve->GetEndY();
+    wxCoord offset_y = curve->GetOffsetY();
+            
+    wxCoord y=0,last_y=0;
+    for (int x = start_x; x < end_x; x++)
+    {
+        double dy = (end - curve->GetY( x )) / range;
+        y = (wxCoord)(dy * double_client_height) - offset_y - 1;
+            
+        if (x != start_x)
+           dc->DrawLine( x-1, last_y, x, y );
+            
+        last_y = y;
+    }
+}
+
+void wxPlotArea::OnPaint( wxPaintEvent &WXUNUSED(event) )
+{
     int view_x;
     int view_y;
     m_owner->GetViewStart( &view_x, &view_y );
@@ -123,12 +177,14 @@ void wxPlotArea::OnPaint( wxPaintEvent &WXUNUSED(event) )
         update_x += view_x;
         update_y += view_y;
         
+/*
         if (m_owner->m_current)
         {
             dc.SetPen( *wxLIGHT_GREY_PEN );
             int base_line = client_height - m_owner->m_current->GetOffsetY();
             dc.DrawLine( update_x-1, base_line-1, update_x+update_width+2, base_line-1 );
         }
+*/
         
         wxNode *node = m_owner->m_curves.First();
         while (node)
@@ -139,22 +195,9 @@ void wxPlotArea::OnPaint( wxPaintEvent &WXUNUSED(event) )
                 dc.SetPen( *wxBLACK_PEN );
             else
                 dc.SetPen( *wxLIGHT_GREY_PEN );
-            wxCoord offset_y = client_height - curve->GetOffsetY();
+                
+            DrawCurve( &dc, curve, update_x-1, update_x+update_width+2 );
 
-            int start_x = wxMax( update_x-1, curve->GetStartX() );
-            int end_x = wxMin( update_x+update_width+2, curve->GetEndX() );
-            
-            wxCoord y=0,last_y=0;
-            for (int x = start_x; x < end_x; x++)
-            {
-                double dy = curve->GetY( x );
-                y = (wxCoord)(-dy * 100) + offset_y - 1;
-            
-                if (x != start_x)
-                    dc.DrawLine( x-1, last_y, x, y );
-            
-                last_y = y;
-            }
             node = node->Next();
         }
         upd ++;
@@ -177,7 +220,14 @@ void wxPlotArea::OnPaint( wxPaintEvent &WXUNUSED(event) )
 IMPLEMENT_DYNAMIC_CLASS(wxPlotWindow, wxScrolledWindow)
 
 BEGIN_EVENT_TABLE(wxPlotWindow, wxScrolledWindow)
-  EVT_PAINT(        wxPlotWindow::OnPaint)
+  EVT_PAINT(                   wxPlotWindow::OnPaint)
+  EVT_BUTTON(  ID_MOVE_UP,     wxPlotWindow::OnMoveUp)
+  EVT_BUTTON(  ID_MOVE_DOWN,   wxPlotWindow::OnMoveDown)
+  
+  EVT_BUTTON(  ID_ENLARGE_100, wxPlotWindow::OnEnlarge100)
+  EVT_BUTTON(  ID_ENLARGE_50,  wxPlotWindow::OnEnlarge50)
+  EVT_BUTTON(  ID_SHRINK_50,   wxPlotWindow::OnShrink50)
+  EVT_BUTTON(  ID_SHRINK_33,   wxPlotWindow::OnShrink33)
 END_EVENT_TABLE()
 
 wxPlotWindow::wxPlotWindow( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, int flag )
@@ -238,15 +288,9 @@ wxPlotCurve *wxPlotWindow::GetAt( size_t n )
 void wxPlotWindow::SetCurrent( wxPlotCurve* current )
 {
     m_current = current;
-    m_area->Refresh( TRUE );
+    m_area->Refresh( FALSE );
     
-    wxPoint pos( m_area->GetPosition() );
-    
-    int client_width;
-    int client_height;
-    GetClientSize( &client_width, &client_height);
-    wxRect rect(pos.x-40,0,40,client_height);
-    Refresh(TRUE,&rect);
+    RedrawYAxis();
 }
 
 wxPlotCurve *wxPlotWindow::GetCurrent()
@@ -254,6 +298,86 @@ wxPlotCurve *wxPlotWindow::GetCurrent()
     return m_current;
 }
 
+void wxPlotWindow::Move( wxPlotCurve* curve, int pixels_up )
+{
+    m_area->DeleteCurve( curve );
+    
+    curve->SetOffsetY( curve->GetOffsetY() + pixels_up );
+    
+    m_area->Refresh( FALSE );
+    
+    RedrawYAxis();
+}
+
+void wxPlotWindow::OnMoveUp( wxCommandEvent& WXUNUSED(event) )
+{
+    if (!m_current) return;
+    
+    Move( m_current, 25 );
+}
+
+void wxPlotWindow::OnMoveDown( wxCommandEvent& WXUNUSED(event) )
+{
+    if (!m_current) return;
+    
+    Move( m_current, -25 );
+}
+
+void wxPlotWindow::Enlarge( wxPlotCurve *curve, double factor )
+{
+    m_area->DeleteCurve( curve );
+    
+    double range = curve->GetEndY() - curve->GetStartY();
+    double new_range = range * factor;
+    double middle = curve->GetEndY() - range/2;
+    curve->SetStartY( middle - new_range / 2 );
+    curve->SetEndY( middle + new_range / 2 );
+    
+    m_area->Refresh( FALSE );
+    
+    RedrawYAxis();
+}
+
+void wxPlotWindow::OnEnlarge100( wxCommandEvent& WXUNUSED(event) )
+{
+    if (!m_current) return;
+    
+    Enlarge( m_current, 2.0 );
+}
+
+void wxPlotWindow::OnEnlarge50( wxCommandEvent& WXUNUSED(event) )
+{
+    if (!m_current) return;
+    
+    Enlarge( m_current, 1.5 );
+}
+
+void wxPlotWindow::OnShrink50( wxCommandEvent& WXUNUSED(event) )
+{
+    if (!m_current) return;
+    
+    Enlarge( m_current, 0.5 );
+}
+
+void wxPlotWindow::OnShrink33( wxCommandEvent& WXUNUSED(event) )
+{
+    if (!m_current) return;
+    
+    Enlarge( m_current, 0.6666666 );
+}
+
+void wxPlotWindow::RedrawYAxis()
+{
+    int client_width;
+    int client_height;
+    GetClientSize( &client_width, &client_height);
+    
+    wxPoint pos( m_area->GetPosition() );
+    
+    wxRect rect(pos.x-45,0,45,client_height);
+    Refresh(TRUE,&rect);
+}
+
 void wxPlotWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
 {
     wxPaintDC dc( this );
@@ -268,11 +392,62 @@ void wxPlotWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
     
     wxPoint pos( m_area->GetPosition() );
     
-    dc.DrawLine( pos.x-15, 5, pos.x-15, client_height-5 );
-    dc.DrawLine( pos.x-19, 9, pos.x-15, 5 );
-    dc.DrawLine( pos.x-10, 10, pos.x-15, 5 );
+    double range = m_current->GetEndY() - m_current->GetStartY();
+    double offset = ((double) m_current->GetOffsetY() / (double)client_height ) * range;
+    double start = m_current->GetStartY() - offset;
+    double end = m_current->GetEndY() - offset;
+    int int_log_range = (int)floor( log10( range ) );
+    double step = 1.0;
+    if (int_log_range > 0)
+    {
+        for (int i = 0; i < int_log_range; i++)
+           step *= 10; 
+    }
+    if (int_log_range < 0)
+    {
+        for (int i = 0; i < -int_log_range; i++)
+           step /= 10; 
+    }
+    double lower = ceil(start / step) * step;
+    double upper = floor(end / step) * step;
+    
+    // if too few values, shrink size
+    int steps = (int)ceil((upper-lower)/step);
+    if (steps < 4)
+    {
+        step /= 2;
+        if (lower-step > start) lower -= step;
+        if (upper+step < end) upper += step;
+    }
+    
+    // if still too few, again
+    steps = (int)ceil((upper-lower)/step);
+    if (steps < 4)
+    {
+        step /= 2;
+        if (lower-step > start) lower -= step;
+        if (upper+step < end) upper += step;
+    }
+    
+    double current = lower;
+    while (current < upper+(step/2))
+    {
+        int y = (int)((m_current->GetEndY()-current) / range * (double)client_height) - 1;
+        y -= m_current->GetOffsetY();
+        if ((y > 10) && (y < client_height-7))
+        {
+            dc.DrawLine( pos.x-15, y, pos.x-7, y );
+            wxString label;
+            label.Printf( wxT("%.1f"), current );
+            dc.DrawText( label, pos.x-45, y-7 );
+        }
+
+        current += step;
+    }
+    
+    dc.DrawLine( pos.x-15, 6, pos.x-15, client_height-5 );
+    dc.DrawLine( pos.x-19, 8, pos.x-15, 2 );
+    dc.DrawLine( pos.x-10, 9, pos.x-15, 2 );
     
-    int y = client_height - m_current->GetOffsetY() - 1;
-    dc.DrawLine( pos.x-15, y, pos.x-7, y );
 }