+ return (int)(y + 0.5);
+}
+
+//----------------------------------------------------------------------------
+// wxVectorCanvas
+//----------------------------------------------------------------------------
+
+IMPLEMENT_CLASS(wxVectorCanvas,wxCanvas)
+
+BEGIN_EVENT_TABLE(wxVectorCanvas,wxCanvas)
+ EVT_SCROLLWIN( wxVectorCanvas::OnScroll )
+ EVT_CHAR( wxVectorCanvas::OnChar )
+ EVT_SIZE( wxVectorCanvas::OnSize )
+END_EVENT_TABLE()
+
+wxVectorCanvas::wxVectorCanvas( wxCanvasAdmin* admin, wxWindow *parent, wxWindowID id,
+ const wxPoint &position, const wxSize& size, long style ) :
+ wxCanvas( admin, parent, id, position, size, style )
+{
+ m_scrolled = FALSE;
+ m_yaxis = FALSE;
+}
+
+double wxVectorCanvas::GetMinX() const
+{
+ return m_virt_minX;
+}
+
+double wxVectorCanvas::GetMinY() const
+{
+ return m_virt_minY;
+}
+
+double wxVectorCanvas::GetMaxX() const
+{
+ return m_virt_maxX;
+}
+
+double wxVectorCanvas::GetMaxY() const
+{
+ return m_virt_maxY;
+}
+
+void wxVectorCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
+{
+ // If any updates are pending, do them now since they will
+ // expect the previous m_bufferX and m_bufferY as well as
+ // the previous device origin values.
+ wxClientDC dc( this );
+ dc.SetDeviceOrigin( m_oldDeviceX, m_oldDeviceY );
+ BlitBuffer( dc );
+
+ if (dy != 0)
+ {
+ double dyv=DeviceToLogicalYRel(dy);
+ m_virt_minY=m_virt_minY-dyv;
+ m_virt_maxY=m_virt_maxY-dyv;
+ }
+ if (dx != 0)
+ {
+ double dxv=DeviceToLogicalXRel(dx);
+ m_virt_minX=m_virt_minX-dxv;
+ m_virt_maxX=m_virt_maxX-dxv;
+ }
+
+ m_admin->SetActive(this);
+ SetMappingScroll(m_virt_minX,m_virt_minY,m_virt_maxX,m_virt_maxY,FALSE);
+
+
+ if (dy != 0)
+ {
+ if (dy > 0 && dy < m_buffer.GetHeight())
+ {
+ wxRect rect( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight()-dy);
+ wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
+ wxMemoryDC dcm;
+ dcm.SelectObject( m_buffer );
+ dcm.DrawBitmap( sub_bitmap, 0, dy, TRUE );
+ dcm.SelectObject( wxNullBitmap );
+
+ Update( 0, 0, m_buffer.GetWidth(), dy, TRUE );
+ }
+ else if (dy < 0 && dy > -m_buffer.GetHeight())
+ {
+ wxRect rect( 0, -dy, m_buffer.GetWidth(), m_buffer.GetHeight()+dy);
+ wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
+ wxMemoryDC dcm;
+ dcm.SelectObject( m_buffer );
+ dcm.DrawBitmap( sub_bitmap, 0, 0, TRUE );
+ dcm.SelectObject( wxNullBitmap );
+
+ Update( 0, m_buffer.GetHeight()+dy, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
+ }
+ else
+ Update( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
+ }
+
+ if (dx != 0)
+ {
+ if (dx > 0 && dx < m_buffer.GetWidth())
+ {
+ wxRect rect( 0, 0, m_buffer.GetWidth()-dx, m_buffer.GetHeight());
+ wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
+ wxMemoryDC dcm;
+ dcm.SelectObject( m_buffer );
+ dcm.DrawBitmap( sub_bitmap, dx, 0, TRUE );
+ dcm.SelectObject( wxNullBitmap );
+
+ Update( 0, 0, dx, m_buffer.GetHeight(), TRUE );
+ }
+ else if (dx < 0 && dx > -m_buffer.GetWidth())
+ {
+ wxRect rect( -dx, 0, m_buffer.GetWidth()+dx, m_buffer.GetHeight());
+ wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
+ wxMemoryDC dcm;
+ dcm.SelectObject( m_buffer );
+ dcm.DrawBitmap( sub_bitmap, 0, 0, TRUE );
+ dcm.SelectObject( wxNullBitmap );
+
+ Update( m_buffer.GetWidth()+dx, 0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
+ }
+ else
+ Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
+ }
+
+ wxWindow::ScrollWindow( dx, dy, rect );
+
+ //must be done now because quick repeated scrolling will prevent wxPaint
+ //from doing it properly
+ UpdateNow();
+}
+
+void wxVectorCanvas::OnSize(wxSizeEvent &event)
+{
+ int w,h;
+
+ GetClientSize( &w, &h );
+
+ wxMemoryDC dc;
+ m_buffer = wxBitmap( w, h );
+ dc.SelectObject( m_buffer );
+ dc.SetPen( *wxTRANSPARENT_PEN );
+ wxBrush brush( m_background , wxSOLID );
+ dc.SetBrush( brush );
+ dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
+ dc.SelectObject( wxNullBitmap );
+
+ wxNode *node = m_updateRects.First();
+ while (node)
+ {
+ wxRect *rect = (wxRect*) node->Data();
+ delete rect;
+ m_updateRects.DeleteNode( node );
+ node = m_updateRects.First();
+ }
+
+ m_frozen = FALSE;
+
+ m_admin->SetActive(this);
+ SetMappingScroll(m_virt_minX,m_virt_minY,m_virt_maxX,m_virt_maxY,FALSE);
+
+ Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
+
+// event.Skip();
+}
+
+// maps the virtual window (Real drawing to the window coordinates
+// also used for zooming
+void wxVectorCanvas::SetMappingScroll( double vx1, double vy1, double vx2, double vy2, bool border)
+{
+ int dwxi,dwyi;
+ GetClientSize(&dwxi,&dwyi);
+
+ if (vx2==vx1) vx2=vx1+100000;
+ if (vy2==vy1) vy2=vy1+100000;
+ m_virt_minX=vx1;
+ m_virt_minY=vy1;
+ m_virt_maxX=vx2;
+ m_virt_maxY=vy2;
+
+ double dwx=dwxi;
+ double dwy=dwyi;
+ if (dwx==0) dwx=1;
+ if (dwy==0) dwy=1;
+
+ double dvx = m_virt_maxX - m_virt_minX;
+ double dvy = m_virt_maxY - m_virt_minY;
+
+ // calculate the scaling factor for the virtual window
+ double temp_x=0;
+ double temp_y=0;
+ if ((dvy / dvx) < (dwy / dwx))
+ {
+ dvy = dvx * (dwy / dwx);
+ // calculate the change in the coordinates
+ temp_y = (dvy - (m_virt_maxY - m_virt_minY) )/ 2.0;
+ }
+ else
+ {
+ dvx = dvy * (dwx / dwy);
+ // calculate the change in the coordinates
+ temp_x = (dvx - (m_virt_maxX - m_virt_minX) )/ 2.0;
+ }
+
+ // add or substract the change from the original coordinates
+ m_virt_minX=m_virt_minX-temp_x;
+ m_virt_minY=m_virt_minY-temp_y;
+
+ m_virt_maxX=m_virt_maxX+temp_x;
+ m_virt_maxY=m_virt_maxY+temp_y;
+
+ // initialize the mapping_matrix used for mapping the
+ // virtual windows to the drawing window
+
+ // make mappingmatrix
+ m_mapping_matrix.Identity();
+ if (!border)
+ {
+ // translate the drawing to 0,0
+ if (m_yaxis)
+ m_mapping_matrix.Translate(-m_virt_minX,-m_virt_maxY);
+ else
+ m_mapping_matrix.Translate(-m_virt_minX,-m_virt_minY);
+ }
+ else
+ {
+ // make a small white border around the drawing
+ m_virt_minX=m_virt_minX- 0.05 * dvx;
+ m_virt_minY=m_virt_minY- 0.05 * dvy;
+
+ m_virt_maxX=m_virt_maxX+ 0.05 * dvx;
+ m_virt_maxY=m_virt_maxY+ 0.05 * dvy;
+
+ // translate the drawing to 0,0
+ if (m_yaxis)
+ m_mapping_matrix.Translate(-m_virt_minX,-m_virt_maxY);
+ else
+ m_mapping_matrix.Translate(-m_virt_minX,-m_virt_minY);
+ }
+
+ double scalefactor_x = dwx;
+ scalefactor_x /= (m_virt_maxX - m_virt_minX);
+
+ double scalefactor_y = dwy;
+ scalefactor_y /= (m_virt_maxY - m_virt_minY);
+
+ // scale the drawing so it fit's in the window
+ m_mapping_matrix.Scale(scalefactor_x, scalefactor_y, 0, 0);
+
+ // because of coordinate change mirror over X
+ // 0,0 in graphic computerscreens: upperleft corner
+ // 0,0 in cartesian: lowerleft corner
+ if (m_yaxis)
+ {
+ m_mapping_matrix.Mirror();
+ }
+ // make inverse of mapping matrix
+ // this is to set coordinates in the statusbar
+ // and the calculate screencoordinates to world coordinates used
+ // in zooming
+ m_inverse_mapping=m_mapping_matrix;
+ m_inverse_mapping.Invert();
+
+ if (m_scrolled)
+ SetScroll(m_virtm_minX,m_virtm_minY,m_virtm_maxX,m_virtm_maxY);
+
+ int dx2,dy2;
+ GetClientSize(&dx2,&dy2);
+ if ( dwxi != dx2 || dwyi != dy2) //scrollbar is/became empty
+ SetScroll(m_virtm_minX,m_virtm_minY,m_virtm_maxX,m_virtm_maxY);
+}
+
+
+void wxVectorCanvas::SetScroll(double vx1,double vy1,double vx2,double vy2)
+{
+ m_virtm_minX=vx1;
+ m_virtm_minY=vy1;
+ m_virtm_maxX=vx2;
+ m_virtm_maxY=vy2;
+
+ double dvx = m_virt_maxX - m_virt_minX;
+ double dvy = m_virt_maxY - m_virt_minY;
+ double dmvx = m_virtm_maxX - m_virtm_minX;
+ double dmvy = m_virtm_maxY - m_virtm_minY;
+
+ SetScrollbar(wxHORIZONTAL,(m_virt_minX-m_virtm_minX)/dmvx *1000,dvx/dmvx *1000,1000,FALSE);
+ if (m_yaxis)
+ {
+ SetScrollbar(wxVERTICAL,(m_virtm_maxY-m_virt_maxY)/dmvy *1000,dvy/dmvy *1000,1000,FALSE);
+ }
+ else
+ {
+ SetScrollbar(wxVERTICAL,(m_virt_minY-m_virtm_minY)/dmvy *1000,dvy/dmvy *1000,1000,FALSE);
+ }
+
+ m_scrolled=TRUE;
+}
+
+// coordinates conversions
+// -----------------------
+double wxVectorCanvas::DeviceToLogicalX(int x) const
+{
+ return m_inverse_mapping.GetValue(0,0) * x + m_inverse_mapping.GetValue(2,0);
+}
+
+double wxVectorCanvas::DeviceToLogicalY(int y) const
+{
+ return m_inverse_mapping.GetValue(1,1) * y + m_inverse_mapping.GetValue(2,1);
+}
+
+double wxVectorCanvas::DeviceToLogicalXRel(int x) const
+{
+ return x*m_inverse_mapping.GetValue(0,0);
+}
+
+double wxVectorCanvas::DeviceToLogicalYRel(int y) const
+{
+ return y*m_inverse_mapping.GetValue(1,1);
+}
+
+int wxVectorCanvas::LogicalToDeviceX(double x) const
+{
+ return (int) (m_mapping_matrix.GetValue(0,0) * x + m_mapping_matrix.GetValue(2,0) + 0.5);
+}
+
+int wxVectorCanvas::LogicalToDeviceY(double y) const
+{
+ return (int) (m_mapping_matrix.GetValue(1,1) * y + m_mapping_matrix.GetValue(2,1) + 0.5);
+}
+
+int wxVectorCanvas::LogicalToDeviceXRel(double x) const
+{
+ return (int) (x*m_mapping_matrix.GetValue(0,0) + 0.5);
+}
+
+int wxVectorCanvas::LogicalToDeviceYRel(double y) const
+{
+ return (int) (y*m_mapping_matrix.GetValue(1,1) + 0.5);
+}
+
+
+// return the inverse mapping matrix for zooming or coordinates
+wxTransformMatrix wxVectorCanvas::GetInverseMappingMatrix()
+{
+ return m_inverse_mapping;
+}
+
+wxTransformMatrix wxVectorCanvas::GetMappingMatrix()
+{
+ return m_mapping_matrix;
+}
+
+
+// ----------------------------------------------------------------------------
+// scrolling behaviour
+// ----------------------------------------------------------------------------
+
+void wxVectorCanvas::OnScroll(wxScrollWinEvent& event)
+{
+ if (event.GetEventType()==wxEVT_SCROLLWIN_THUMBRELEASE)
+ {
+ if (event.GetOrientation()==wxHORIZONTAL)
+ {
+ double x=m_virtm_minX+event.GetPosition()/1000.0*(m_virtm_maxX-m_virtm_minX);
+ x=LogicalToDeviceXRel(x-m_virt_minX);
+ ScrollWindow(-x, 0, (const wxRect *) NULL);
+ }
+ else
+ {
+ double y=m_virtm_minY+event.GetPosition()/1000.0*(m_virtm_maxY-m_virtm_minY);
+ y=LogicalToDeviceYRel(y-m_virt_minY);
+ ScrollWindow(0, -y, (const wxRect *) NULL);
+ }
+ }
+ else if (event.GetEventType()==wxEVT_SCROLLWIN_PAGEUP)
+ {
+ if (event.GetOrientation()==wxHORIZONTAL)
+ {
+ double x=GetBufferWidth();
+ ScrollWindow(x, 0, (const wxRect *) NULL);
+ }
+ else
+ {
+ double y=GetBufferHeight();
+ ScrollWindow(0, y, (const wxRect *) NULL);
+ }
+ }
+ else if (event.GetEventType()==wxEVT_SCROLLWIN_PAGEDOWN)
+ {
+ if (event.GetOrientation()==wxHORIZONTAL)
+ {
+ double x=-GetBufferWidth();
+ ScrollWindow(x, 0, (const wxRect *) NULL);
+ }
+ else
+ {
+ double y=-GetBufferHeight();
+ ScrollWindow(0, y, (const wxRect *) NULL);
+ }
+ }
+ else if (event.GetEventType()==wxEVT_SCROLLWIN_LINEUP)
+ {
+ if (event.GetOrientation()==wxHORIZONTAL)
+ {
+ int x=GetBufferWidth()/10;
+ ScrollWindow(x, 0, (const wxRect *) NULL);
+ }
+ else
+ {
+ int y=GetBufferHeight()/10;
+ ScrollWindow(0, y, (const wxRect *) NULL);
+ }
+ }
+ else if (event.GetEventType()==wxEVT_SCROLLWIN_LINEDOWN)
+ {
+ if (event.GetOrientation()==wxHORIZONTAL)
+ {
+ int x=-GetBufferWidth()/10;
+ ScrollWindow(x, 0, (const wxRect *) NULL);
+ }
+ else
+ {
+ int y=-GetBufferHeight()/10;
+ ScrollWindow(0, y, (const wxRect *) NULL);
+ }
+ }
+
+}
+
+void wxVectorCanvas::OnChar(wxKeyEvent& event)
+{
+ switch ( event.KeyCode() )
+ {
+ case WXK_PAGEUP:
+ case WXK_PRIOR:
+ {
+ double y=GetBufferHeight();
+ ScrollWindow(0, y, (const wxRect *) NULL);
+ }
+ break;
+ case WXK_PAGEDOWN:
+ case WXK_NEXT:
+ {
+ double y=-GetBufferHeight();
+ ScrollWindow(0, y, (const wxRect *) NULL);
+ }
+ break;
+ case WXK_HOME:
+ {
+ double y=m_virtm_minY;
+ y=LogicalToDeviceYRel(y-m_virt_minY);
+ ScrollWindow(0, -y, (const wxRect *) NULL);
+ }
+ break;
+ case WXK_END:
+ {
+ double y=m_virtm_minY+(m_virtm_maxY-m_virtm_minY);
+ y=LogicalToDeviceYRel(y-m_virt_minY);
+ ScrollWindow(0, -y, (const wxRect *) NULL);
+ }
+ break;
+ case WXK_UP:
+ {
+ int y;
+ if (!event.ControlDown())
+ y=GetBufferHeight()/10;
+ else
+ y=GetBufferHeight();
+ ScrollWindow(0, y, (const wxRect *) NULL);
+ }
+ break;
+
+ case WXK_DOWN:
+ {
+ int y;
+ if (!event.ControlDown())
+ y=-GetBufferHeight()/10;
+ else
+ y=-GetBufferHeight();
+ ScrollWindow(0, y, (const wxRect *) NULL);
+ }
+ break;
+
+ case WXK_LEFT:
+ {
+ int x;
+ if (!event.ControlDown())
+ x=GetBufferWidth()/10;
+ else
+ x=GetBufferWidth();
+ ScrollWindow(x, 0, (const wxRect *) NULL);
+ }
+ break;
+ case WXK_RIGHT:
+ {
+ int x;
+ if (!event.ControlDown())
+ x=-GetBufferWidth()/10;
+ else
+ x=-GetBufferWidth();
+ ScrollWindow(x, 0, (const wxRect *) NULL);
+ }
+ break;
+ default:
+ // not for us
+ event.Skip();
+ }
+}
+
+
+//----------------------------------------------------------------------------
+// wxCanvasAdmin
+//----------------------------------------------------------------------------
+
+wxCanvasAdmin::wxCanvasAdmin()
+{
+
+}
+
+wxCanvasAdmin::~wxCanvasAdmin()
+{
+}
+
+
+void wxCanvasAdmin::Append( wxCanvas* canvas )
+{
+ m_canvaslist.Append( canvas );
+}
+
+void wxCanvasAdmin::Remove( wxCanvas* canvas )
+{
+ m_canvaslist.DeleteObject( canvas );
+}
+
+void wxCanvasAdmin::Update(wxCanvasObject* obj, double x, double y, double width, double height)
+{
+ wxNode *node = m_canvaslist.First();
+ while (node)
+ {
+
+ wxCanvas *canvas = (wxCanvas*) node->Data();
+
+ if (m_active == canvas)
+ {
+ int xi = canvas->LogicalToDeviceX( x);
+ int yi = canvas->LogicalToDeviceY( y);
+ int wi = canvas->LogicalToDeviceXRel( width );
+ int hi = canvas->LogicalToDeviceYRel( height);
+ //update a little more then is strictly needed,
+ //to get rid of the 1 bit bugs
+ if (canvas->GetYaxis())
+ canvas->Update( xi-2, yi+hi-2, wi+4, -hi+4);
+ else
+ canvas->Update( xi-2, yi-2, wi+4, hi+4);
+ }
+ else
+ { wxCanvasObject* topobj=canvas->GetRoot()->Contains(obj);
+ if (topobj)
+ {
+ wxCanvas* tcanvas = m_active;
+ SetActive(canvas);
+
+ /*
+ //KKK TODO somehow the next does not work for update i do not know why
+ canvas->GetRoot()->CalcBoundingBox();
+ int xi = topobj->GetX();
+ int yi = topobj->GetY();
+ int wi = topobj->GetWidth();
+ int hi = topobj->GetHeight();
+ */
+ canvas->Update( 0,0, canvas->GetBufferWidth(),canvas->GetBufferHeight());
+ SetActive(tcanvas);
+ }
+ }
+
+ node = node->Next();
+ }
+}
+
+void wxCanvasAdmin::UpdateNow()
+{
+ wxNode *node = m_canvaslist.First();
+ while (node)
+ {
+ wxCanvas *canvas = (wxCanvas*) node->Data();
+
+ canvas->UpdateNow();
+ node = node->Next();
+ }
+}
+
+// coordinates conversions
+// -----------------------
+double wxCanvasAdmin::DeviceToLogicalX(int x) const
+{
+ return m_active->DeviceToLogicalX(x);
+}
+
+double wxCanvasAdmin::DeviceToLogicalY(int y) const
+{
+ return m_active->DeviceToLogicalY(y);
+}
+
+double wxCanvasAdmin::DeviceToLogicalXRel(int x) const
+{
+ return m_active->DeviceToLogicalXRel(x);
+}
+
+double wxCanvasAdmin::DeviceToLogicalYRel(int y) const
+{
+ return m_active->DeviceToLogicalYRel(y);
+}
+
+int wxCanvasAdmin::LogicalToDeviceX(double x) const
+{
+ return m_active->LogicalToDeviceX(x);
+}
+
+int wxCanvasAdmin::LogicalToDeviceY(double y) const
+{
+ return m_active->LogicalToDeviceY(y);
+}
+
+int wxCanvasAdmin::LogicalToDeviceXRel(double x) const
+{
+ return m_active->LogicalToDeviceXRel(x);
+}
+
+int wxCanvasAdmin::LogicalToDeviceYRel(double y) const
+{
+ return m_active->LogicalToDeviceYRel(y);
+}
+
+void wxCanvasAdmin::SetActive(wxCanvas* activate)
+{
+ wxNode *node = m_canvaslist.First();
+ while (node)
+ {
+ wxCanvas *canvas = (wxCanvas*) node->Data();
+
+ if (activate == canvas)
+ {
+ m_active=canvas;
+ break;
+ }
+ node = node->Next();
+ }
+}
+//--------------------------------------------------------------------
+// wxCanvasModule
+//--------------------------------------------------------------------
+
+class wxCanvasModule : public wxModule
+{
+public:
+ virtual bool OnInit();
+ virtual void OnExit();
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxCanvasModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
+
+bool wxCanvasModule::OnInit()
+{
+#if wxUSE_FREETYPE
+ int error = FT_Init_FreeType( &g_freetypeLibrary );
+ if (error) return FALSE;
+#endif
+
+ return TRUE;
+}
+
+void wxCanvasModule::OnExit()
+{
+#if wxUSE_FREETYPE