]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/canvas/canvas.cpp
Copied/merged from the 2.2 branch.
[wxWidgets.git] / contrib / src / canvas / canvas.cpp
CommitLineData
6a2c1874
RR
1/////////////////////////////////////////////////////////////////////////////
2// Name: canvas.cpp
3// Author: Robert Roebling
4// Created: XX/XX/XX
5// Copyright: 2000 (c) Robert Roebling
6// Licence: wxWindows Licence
7/////////////////////////////////////////////////////////////////////////////
8
9#ifdef __GNUG__
10 #pragma implementation "canvas.cpp"
11#endif
12
13// For compilers that support precompilation, includes "wx/wx.h".
14#include "wx/wxprec.h"
15
16#ifdef __BORLANDC__
17 #pragma hdrstop
18#endif
19
f9032263
RR
20#include "wx/canvas/canvas.h"
21#include "wx/canvas/polygon.h"
22#include "wx/canvas/liner.h"
6a2c1874
RR
23
24#ifdef __WXGTK__
25 #include <gtk/gtk.h>
26 #include <gdk/gdkrgb.h>
27 #include "wx/gtk/win_gtk.h"
28#endif
29
1e1af41e 30#ifndef wxUSE_FREETYPE
84fba40b 31 #define wxUSE_FREETYPE 0
1e1af41e 32#endif
d1f9b206 33
1e1af41e
RR
34#if wxUSE_FREETYPE
35 #include <freetype/freetype.h>
d1f9b206
RR
36#endif
37
84fba40b
RR
38//#define CANVASDEBUG
39
d1f9b206
RR
40//----------------------------------------------------------------------------
41// globals
42//----------------------------------------------------------------------------
43
84fba40b
RR
44const double pi = 3.1415926535;
45
1e1af41e 46#if wxUSE_FREETYPE
d1f9b206
RR
47FT_Library g_freetypeLibrary;
48#endif
6a2c1874
RR
49
50//----------------------------------------------------------------------------
51// wxCanvasObject
52//----------------------------------------------------------------------------
f03b31e8 53
4dbd4ee6 54wxCanvasObject::wxCanvasObject()
6a2c1874 55{
84fba40b
RR
56 // the default event handler is just this object
57 m_eventHandler=this;
58 m_admin = NULL;
4dbd4ee6
RR
59 m_isControl = FALSE;
60 m_isVector = FALSE;
61 m_isImage = FALSE;
84fba40b 62 m_visible = TRUE;
b5789150 63 m_dragmode = wxDRAG_ONTOP;
84fba40b 64// handy when debugging
b5789150 65// m_dragmode = wxDRAG_RECTANGLE;
84fba40b
RR
66 m_dragable = TRUE;
67}
68
69bool wxCanvasObject::ProcessCanvasObjectEvent(wxEvent& event)
70{
71 return m_eventHandler->ProcessEvent(event);
72}
73
74void wxCanvasObject::PushEventHandler(wxEvtHandler *handler)
75{
76 handler->SetNextHandler(GetEventHandler());
77 m_eventHandler=handler;
78}
79
80wxEvtHandler *wxCanvasObject::PopEventHandler(bool deleteHandler)
81{
82 wxEvtHandler *handlerA = m_eventHandler;
83 if ( handlerA )
84 {
85 wxEvtHandler *handlerB = handlerA->GetNextHandler();
86 handlerA->SetNextHandler((wxEvtHandler *)NULL);
87 m_eventHandler=handlerB;
88 if ( deleteHandler )
89 {
90 delete handlerA;
91 handlerA = (wxEvtHandler *)NULL;
92 }
93 }
94
95 return handlerA;
96}
97
98void wxCanvasObject::AppendEventHandler(wxEvtHandler *handler)
99{
100 GetEventHandler()->SetNextHandler(handler);
101}
102
103wxEvtHandler *wxCanvasObject::RemoveLastEventHandler(bool deleteHandler)
104{
105 //always the first in the row
106 wxEvtHandler *handlerA = m_eventHandler;
107 wxEvtHandler *handlerB=handlerA;
108 //goto the end
109 while ( handlerA->GetNextHandler() )
110 {
111 handlerB = handlerA;
112 handlerA = handlerA->GetNextHandler();
113 }
114
115 handlerB->SetNextHandler((wxEvtHandler *)NULL);
116 if ( deleteHandler )
117 {
118 delete handlerA;
119 }
120
121 return GetEventHandler();
122}
123
124wxRect wxCanvasObject::GetAbsoluteArea(const wxTransformMatrix& cworld)
125{
84fba40b
RR
126 wxBoundingBox tmp=m_bbox;
127 tmp.MapBbox(cworld);
128
84fba40b
RR
129 int x1 = m_admin->LogicalToDeviceX( tmp.GetMinX() );
130 int y1 = m_admin->LogicalToDeviceY( tmp.GetMinY() );
131 int x2 = m_admin->LogicalToDeviceX( tmp.GetMaxX() );
132 int y2 = m_admin->LogicalToDeviceY( tmp.GetMaxY() );
133
134 if (x1 > x2)
135 {
136 int tmp = x1;
137 x1 = x2;
138 x2 = tmp;
139 }
140 if (y1 > y2)
141 {
142 int tmp = y1;
143 y1 = y2;
144 y2 = tmp;
145 }
146
147 wxRect tmparea;
148 tmparea.x = x1;
149 tmparea.y = y1;
8636c073
RR
150 tmparea.width = x2-x1; // FIXME +1 ?
151 tmparea.height = y2-y1; // FIXME +1 ?
84fba40b
RR
152
153 return tmparea;
154}
155
156void wxCanvasObject::MoveAbsolute( double x, double y )
157{
158 //save old position of boundingbox
159 double oldx = GetXMin();
160 double oldy = GetYMin();
161 double w = m_bbox.GetWidth();
162 double h = m_bbox.GetHeight();
163
164 SetPosXY(x,y);
165
166 double newx=GetXMin();
167 double newy=GetYMin();
168
169 double leftu,rightu,bottomu,topu ;
170 leftu = wxMin (oldx, newx ) ;
171 rightu = wxMax (oldx + w, newx + w) ;
172 topu = wxMin (oldy, newy) ;
173 bottomu = wxMax (oldy + h, newy + h) ;
174
175 if ( rightu - leftu < 2*w && bottomu - topu < 2*h )
176 {
177 m_admin->Update( this,leftu, topu, rightu - leftu, bottomu - topu);
178 }
179 else
180 {
181 m_admin->Update( this, oldx, oldy, w, h );
182 m_admin->Update( this, newx, newy, w, h );
183 }
4dbd4ee6
RR
184}
185
84fba40b 186void wxCanvasObject::MoveRelative( double x, double y )
4dbd4ee6 187{
84fba40b
RR
188 //save old position of boundingbox
189 double oldx = GetXMin();
190 double oldy = GetYMin();
191 double w = m_bbox.GetWidth();
192 double h = m_bbox.GetHeight();
193
194 TransLate(x,y);
195
196 double newx=GetXMin();
197 double newy=GetYMin();
198
199 double leftu,rightu,bottomu,topu ;
200 leftu = wxMin (oldx, newx ) ;
201 rightu = wxMax (oldx + w, newx + w) ;
202 topu = wxMin (oldy, newy) ;
203 bottomu = wxMax (oldy + h, newy + h) ;
204
205 if ( rightu - leftu < 2*w && bottomu - topu < 2*h )
206 {
207 m_admin->Update( this,leftu, topu, rightu - leftu, bottomu - topu);
208 }
209 else
210 {
211 m_admin->Update( this, oldx, oldy, w, h );
212 m_admin->Update( this, newx, newy, w, h );
213 }
4dbd4ee6
RR
214}
215
84fba40b
RR
216
217void wxCanvasObject::DragStart()
4dbd4ee6 218{
b5789150 219 if (m_dragmode == wxDRAG_RECTANGLE)
84fba40b
RR
220 {
221 this->SetVisible(FALSE);
222 wxTransformMatrix help;
223 double x = GetXMin();
224 double y = GetYMin();
225 double w = m_bbox.GetWidth();
226 double h = m_bbox.GetHeight();
227 m_admin->Update( this, x, y, w, h );
228 m_admin->UpdateNow();
229
230 wxRect recold=GetAbsoluteArea(help);
231 wxClientDC dc(m_admin->GetActive());
232 dc.SetPen(*wxBLACK_PEN);
233 dc.SetBrush(*wxTRANSPARENT_BRUSH);
234 dc.SetLogicalFunction(wxINVERT);
235 dc.DrawRectangle(recold);
236 dc.SetBrush(wxNullBrush);
237 dc.SetPen(wxNullPen);
238 }
b5789150 239 else if (m_dragmode != wxDRAG_REDRAW)
84fba40b
RR
240 {
241 this->SetVisible(FALSE);
242 wxTransformMatrix help;
243 double x = GetXMin();
244 double y = GetYMin();
245 double w = m_bbox.GetWidth();
246 double h = m_bbox.GetHeight();
247
248 wxRect recnew=GetAbsoluteArea(help);
249
250 //redraw in buffer what should be there without this object
251 m_admin->Update( this, x, y, w, h );
252 m_admin->GetActive()->Freeze();
253
254 //save the drawing (without the object itself to a bitmap)
255 m_atnewpos = wxBitmap(recnew.width,recnew.height);
256 wxMemoryDC dcm;
257 dcm.SelectObject(*m_admin->GetActive()->GetBuffer());
258 wxMemoryDC tmp;
259 tmp.SelectObject(m_atnewpos);
260 tmp.Blit(0,0,recnew.width,recnew.height,&dcm,recnew.x,recnew.y,wxCOPY,FALSE);
261 tmp.SelectObject(wxNullBitmap);
262 dcm.SelectObject(wxNullBitmap);
263 }
6a2c1874
RR
264}
265
84fba40b
RR
266
267void wxCanvasObject::DragRelative( double x, double y)
6a2c1874 268{
b5789150 269 if (m_dragmode == wxDRAG_RECTANGLE)
84fba40b
RR
270 {
271 wxTransformMatrix help;
5143c96b 272
84fba40b 273 wxRect recold=GetAbsoluteArea(help);
dc16900b 274
84fba40b
RR
275 TransLate(x,y);
276
277 wxRect recnew=GetAbsoluteArea(help);
278
279 wxClientDC dc(m_admin->GetActive());
280 dc.SetPen(*wxBLACK_PEN);
281 dc.SetBrush(*wxTRANSPARENT_BRUSH);
282 dc.SetLogicalFunction(wxINVERT);
283 dc.DrawRectangle(recold);
284 dc.DrawRectangle(recnew);
285 dc.SetBrush(wxNullBrush);
286 dc.SetPen(wxNullPen);
287 }
b5789150 288 else if (m_dragmode != wxDRAG_REDRAW)
6a2c1874 289 {
84fba40b
RR
290 wxClientDC dc(m_admin->GetActive());
291 wxMemoryDC tmp;
292
293 wxTransformMatrix help;
294 wxRect recold=GetAbsoluteArea(help);
295
296 //restore what was there (without the object itself)
297 wxMemoryDC dcm;
298 dcm.SelectObject(*m_admin->GetActive()->GetBuffer());
299 tmp.SelectObject(m_atnewpos);
300 dcm.Blit(recold.x,recold.y,recold.width,recold.height,&tmp,0,0,wxCOPY,FALSE);
301
302 TransLate(x,y);
303
304 wxRect recnew=GetAbsoluteArea(help);
305
306 //save the contents of the buffer at the new position
307 tmp.Blit(0,0,recnew.width,recnew.height,&dcm,recnew.x,recnew.y,wxCOPY,FALSE);
308 tmp.SelectObject(wxNullBitmap);
309
310 //m_atnewpos = m_admin->GetActive()->GetBuffer()->GetSubBitmap( recnew );
311
312 this->SetVisible(TRUE);
313 //redraw object into the buffer
314 m_admin->GetActive()->SetDC(&dcm);
315 Render(&help,recnew.x,recnew.y,recnew.width,recnew.height);
316
317 //draw the union or seperate to the canvas
318 double leftu,rightu,bottomu,topu ;
319 leftu = wxMin (recold.x, recnew.x ) ;
320 rightu = wxMax (recold.x + recold.width, recnew.x + recnew.width ) ;
321 topu = wxMin (recold.y, recnew.y) ;
322 bottomu = wxMax (recold.y + recold.height, recnew.y + recnew.height) ;
323
324 if ( rightu - leftu < 2*recold.width && bottomu - topu < 2*recold.height)
325 {
326 dc.Blit(leftu,topu,rightu - leftu,bottomu - topu,&dcm,leftu,topu,wxCOPY,FALSE);
327 }
328 else
329 {
330 //do them seperate
331 //first redraw what should be at the old position in the canvas
332 dc.Blit(recold.x,recold.y,recold.width,recold.height,&dcm,recold.x,recold.y,wxCOPY,FALSE);
333 //blit the new position of the object to the canvas
334 dc.Blit(recnew.x,recnew.y,recnew.width,recnew.height,&dcm,recnew.x,recnew.y,wxCOPY,FALSE);
335 }
336 dcm.SelectObject(wxNullBitmap);
337 this->SetVisible(FALSE);
6a2c1874 338 }
b5789150
RR
339 else
340 MoveRelative(x,y);
84fba40b
RR
341}
342
343
344void wxCanvasObject::DragEnd()
345{
84fba40b
RR
346 m_atnewpos = wxBitmap(0,0);
347 m_admin->GetActive()->Thaw();
348 this->SetVisible(TRUE);
349 double x = GetXMin();
350 double y = GetYMin();
351 double w = m_bbox.GetWidth();
352 double h = m_bbox.GetHeight();
353 m_admin->Update( this, x, y, w, h );
354 m_admin->UpdateNow();
84fba40b
RR
355}
356
357wxCanvasObject* wxCanvasObject::IsHitWorld( double x, double y, double margin )
358{
359 if ((x >= m_bbox.GetMinX()-margin) &&
360 (x <= m_bbox.GetMaxX()+margin) &&
361 (y >= m_bbox.GetMinY()-margin) &&
f03b31e8
RR
362 (y <= m_bbox.GetMaxY()+margin))
363 {
84fba40b 364 return this;
f03b31e8
RR
365 }
366
84fba40b 367 return (wxCanvasObject*) NULL;
6a2c1874
RR
368}
369
84fba40b 370wxCanvasObject* wxCanvasObject::Contains( wxCanvasObject* obj )
239c1f50 371{
84fba40b
RR
372 if (obj == this)
373 return this;
f03b31e8 374
84fba40b 375 return (wxCanvasObject*) NULL;
239c1f50
RR
376}
377
dc16900b
KH
378void wxCanvasObject::CaptureMouse()
379{
84fba40b 380 m_admin->GetActive()->SetCaptureMouse( this );
dc16900b
KH
381}
382
383void wxCanvasObject::ReleaseMouse()
384{
84fba40b 385 m_admin->GetActive()->SetCaptureMouse( NULL );
dc16900b
KH
386}
387
388bool wxCanvasObject::IsCapturedMouse()
389{
f03b31e8 390 return (m_admin->GetActive()->GetCaptured() == this);
dc16900b
KH
391}
392
393
84fba40b 394void wxCanvasObject::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
6a2c1874
RR
395{
396}
397
84fba40b 398void wxCanvasObject::CalcBoundingBox()
1e1af41e
RR
399{
400}
401
402void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
6a2c1874
RR
403{
404}
405
fcbb6b37
KH
406//----------------------------------------------------------------------------
407// wxCanvasObjectGroup
408//----------------------------------------------------------------------------
409
84fba40b 410wxCanvasObjectGroup::wxCanvasObjectGroup(double x, double y)
fcbb6b37 411{
84fba40b
RR
412 lworld.Translate(x,y);
413 //no objects make the bounding box the x,y and take care of it later
414 m_bbox.Expand(x,y);
21840a6c
RR
415}
416
417wxCanvasObjectGroup::~wxCanvasObjectGroup()
418{
fcbb6b37
KH
419}
420
84fba40b 421void wxCanvasObjectGroup::PushEventHandler(wxEvtHandler *handler)
fcbb6b37 422{
84fba40b 423 wxCanvasObject::PushEventHandler(handler);
fcbb6b37
KH
424 wxNode *node = m_objects.First();
425 while (node)
426 {
427 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
428
84fba40b 429 obj->PushEventHandler(handler);
fcbb6b37
KH
430
431 node = node->Next();
432 }
433}
434
84fba40b 435wxEvtHandler *wxCanvasObjectGroup::PopEventHandler(bool deleteHandler)
fcbb6b37 436{
84fba40b
RR
437 wxNode *node = m_objects.First();
438 while (node)
21840a6c 439 {
84fba40b
RR
440 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
441
442 obj->PopEventHandler(deleteHandler);
443
444 node = node->Next();
21840a6c 445 }
84fba40b
RR
446 return wxCanvasObject::PopEventHandler(deleteHandler);
447}
448
449void wxCanvasObjectGroup::AppendEventHandler(wxEvtHandler *handler)
450{
451 wxCanvasObject::AppendEventHandler(handler);
452 wxNode *node = m_objects.First();
453 while (node)
454 {
455 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
456
457 obj->AppendEventHandler(handler);
458
459 node = node->Next();
460 }
461}
462
463wxEvtHandler *wxCanvasObjectGroup::RemoveLastEventHandler(bool deleteHandler)
464{
465 wxNode *node = m_objects.First();
466 while (node)
467 {
468 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
469
470 obj->RemoveLastEventHandler(deleteHandler);
471
472 node = node->Next();
473 }
474 return wxCanvasObject::RemoveLastEventHandler(deleteHandler);
475}
476
477void wxCanvasObjectGroup::TransLate( double x, double y )
478{
479 lworld.Translate(x,y);
480 CalcBoundingBox();
481}
482
483void wxCanvasObjectGroup::SetAdmin(wxCanvasAdmin* admin)
484{
485 m_admin=admin;
486 wxNode *node = m_objects.First();
487 while (node)
21840a6c 488 {
84fba40b
RR
489 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
490
491 obj->SetAdmin(admin);
fcbb6b37 492
84fba40b 493 node = node->Next();
21840a6c 494 }
fcbb6b37
KH
495}
496
fcbb6b37
KH
497void wxCanvasObjectGroup::DeleteContents( bool flag)
498{
499 m_objects.DeleteContents( flag );
84fba40b
RR
500 m_bbox.SetValid(FALSE);
501 CalcBoundingBox();
fcbb6b37
KH
502}
503
fcbb6b37
KH
504void wxCanvasObjectGroup::Prepend( wxCanvasObject* obj )
505{
506 m_objects.Insert( obj );
84fba40b 507 if (m_objects.First())
f03b31e8 508 {
84fba40b 509 m_bbox.Expand(obj->GetBbox());
f03b31e8 510 }
84fba40b
RR
511 else
512 {
513 m_bbox.SetValid(FALSE);
514 CalcBoundingBox();
515 }
fcbb6b37
KH
516}
517
518void wxCanvasObjectGroup::Append( wxCanvasObject* obj )
519{
520 m_objects.Append( obj );
84fba40b 521 if (m_objects.First())
f03b31e8 522 {
84fba40b 523 m_bbox.Expand(obj->GetBbox());
f03b31e8 524 }
84fba40b
RR
525 else
526 {
527 m_bbox.SetValid(FALSE);
528 CalcBoundingBox();
529 }
fcbb6b37
KH
530}
531
532void wxCanvasObjectGroup::Insert( size_t before, wxCanvasObject* obj )
533{
534 m_objects.Insert( before, obj );
84fba40b
RR
535 m_bbox.SetValid(FALSE);
536 if (m_objects.First())
f03b31e8 537 {
84fba40b 538 m_bbox.Expand(obj->GetBbox());
f03b31e8 539 }
84fba40b
RR
540 else
541 {
542 m_bbox.SetValid(FALSE);
543 CalcBoundingBox();
544 }
fcbb6b37
KH
545}
546
547void wxCanvasObjectGroup::Remove( wxCanvasObject* obj )
548{
549 m_objects.DeleteObject( obj );
84fba40b
RR
550 m_bbox.SetValid(FALSE);
551 CalcBoundingBox();
fcbb6b37
KH
552}
553
84fba40b 554void wxCanvasObjectGroup::CalcBoundingBox()
fcbb6b37 555{
84fba40b 556 m_bbox.SetValid(FALSE);
fcbb6b37
KH
557 wxNode *node = m_objects.First();
558 while (node)
559 {
560 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
561
fcbb6b37 562
84fba40b
RR
563 obj->CalcBoundingBox();
564 wxBoundingBox tmp;
565 tmp=obj->GetBbox();
566 tmp.MapBbox(lworld);
567
568 m_bbox.Expand( tmp );
fcbb6b37
KH
569 node = node->Next();
570 }
571}
572
84fba40b 573void wxCanvasObjectGroup::Render(wxTransformMatrix* cworld, int x, int y, int width, int height )
fcbb6b37 574{
84fba40b
RR
575 if (!m_visible) return;
576
577 wxTransformMatrix backup = *cworld;
578 *cworld *= lworld;
579
fcbb6b37 580 wxNode *node = m_objects.First();
84fba40b
RR
581
582 if (!node) return;
583
584
585#ifdef CANVASDEBUG
586 wxRect absarea=GetAbsoluteArea(*cworld);
587 wxDC *dc = m_admin->GetActive()->GetDC();
588 dc->SetPen(*wxBLACK_PEN);
589 dc->SetBrush(*wxTRANSPARENT_BRUSH);
590 dc->DrawRectangle( absarea.x , absarea.y , absarea.width , absarea.height );
591 dc->SetBrush(wxNullBrush);
592 dc->SetPen(wxNullPen);
593#endif
594 //TODO the next will only work if all boundingboxes stay up to date (problem when mowing currently
595 /*
596 if (! ( wxMax(absarea.x, x) < wxMin(absarea.x + absarea.width , x + width ) &&
597 wxMax(absarea.y, y) < wxMin(absarea.y + absarea.height , y + height )
598 )
599 )
600 return;
601 */
602
603 // cycle through all objects
fcbb6b37
KH
604 while (node)
605 {
606 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
607
84fba40b 608 if (!obj->IsControl() && obj->GetVisible())
fcbb6b37 609 {
84fba40b
RR
610
611 //get area at the absolute position
8636c073
RR
612 wxRect absareaobject = obj->GetAbsoluteArea(*cworld);
613
fcbb6b37
KH
614 // If we have 10.000 objects, we will go through
615 // this 10.000 times for each update, so we have
616 // to optimise carefully.
84fba40b
RR
617 int clip_x = absareaobject.x;
618 int clip_width = absareaobject.width;
fcbb6b37
KH
619 if (clip_x < x)
620 {
621 clip_width -= x-clip_x;
622 clip_x = x;
623 }
624 if (clip_width > 0)
625 {
626 if (clip_x + clip_width > x + width)
627 clip_width = x+width-clip_x;
628
629 if (clip_width > 0)
630 {
84fba40b
RR
631 int clip_y = absareaobject.y;
632 int clip_height = absareaobject.height;
fcbb6b37
KH
633 if (clip_y < y)
634 {
635 clip_height -= y-clip_y;
636 clip_y = y;
637 }
638 if (clip_height > 0)
639 {
640 if (clip_y + clip_height > y + height)
641 clip_height = y+height-clip_y;
642
643 if (clip_height > 0)
84fba40b
RR
644 {
645 obj->Render(cworld, clip_x, clip_y, clip_width, clip_height );
646 }
fcbb6b37
KH
647 }
648 }
649 }
650 }
651
652 node = node->Next();
653 }
84fba40b 654 *cworld = backup;
fcbb6b37
KH
655}
656
657void wxCanvasObjectGroup::WriteSVG( wxTextOutputStream &stream )
658{
659}
660
f03b31e8 661wxCanvasObject* wxCanvasObjectGroup::IsHitWorld( double x, double y, double margin )
fcbb6b37 662{
84fba40b
RR
663 //KKKfirst check if within bbox
664 //will only work if they are always uptodate
665 //if (!m_bbox.PointInBox(x,y,margin))
666 // return (wxCanvasObject*) NULL;
667
668 wxTransformMatrix inverse = lworld;
669 double xh,yh;
670 inverse.Invert();
671 inverse.TransformPoint(x,y,xh,yh);
672
673 wxCanvasObject *obj=0;
fcbb6b37
KH
674 wxNode *node = m_objects.Last();
675 while (node)
676 {
84fba40b 677 obj=(wxCanvasObject*) node->Data();
fcbb6b37 678
84fba40b 679 if (!obj->IsControl() )
fcbb6b37 680 {
880d870e 681 if (obj->IsHitWorld(xh,yh,margin))
fcbb6b37 682 {
84fba40b 683 return obj;
fcbb6b37
KH
684 }
685 }
686 node = node->Previous();
687 }
84fba40b
RR
688
689 return (wxCanvasObject*) NULL;
fcbb6b37
KH
690}
691
84fba40b 692wxCanvasObject* wxCanvasObjectGroup::Contains( wxCanvasObject* obj )
fcbb6b37 693{
84fba40b
RR
694 wxCanvasObject* cobj;
695 wxNode *node = m_objects.First();
fcbb6b37
KH
696 while (node)
697 {
84fba40b 698 cobj=(wxCanvasObject*) node->Data();
fcbb6b37 699
84fba40b 700 if (cobj->Contains(obj))
fcbb6b37 701 {
84fba40b 702 return obj;
fcbb6b37 703 }
84fba40b 704 node = node->Next();
fcbb6b37 705 }
5143c96b 706
21840a6c 707 return (wxCanvasObject*) NULL;
fcbb6b37
KH
708}
709
84fba40b
RR
710int wxCanvasObjectGroup::IndexOf( wxCanvasObject* obj )
711{
712 return m_objects.IndexOf( obj );
713}
714
fcbb6b37 715//----------------------------------------------------------------------------
84fba40b 716// wxCanvasObjectRef
fcbb6b37
KH
717//----------------------------------------------------------------------------
718
84fba40b 719wxCanvasObjectRef::wxCanvasObjectRef(double x, double y, wxCanvasObject* obj)
fcbb6b37
KH
720 : wxCanvasObject()
721{
f03b31e8 722 lworld.Translate(x,y);
84fba40b
RR
723 m_obj = obj;
724
725 m_bbox.SetValid(FALSE);
726 wxBoundingBox tmp;
727 tmp=obj->GetBbox();
728 tmp.MapBbox(lworld);
729 m_bbox.Expand( tmp );
fcbb6b37
KH
730}
731
84fba40b 732void wxCanvasObjectRef::PushEventHandler(wxEvtHandler *handler)
fcbb6b37 733{
84fba40b
RR
734 wxCanvasObject::PushEventHandler(handler);
735 m_obj->PushEventHandler(handler);
fcbb6b37
KH
736}
737
84fba40b 738wxEvtHandler *wxCanvasObjectRef::PopEventHandler(bool deleteHandler)
fcbb6b37 739{
84fba40b
RR
740 m_obj->PopEventHandler(deleteHandler);
741 return wxCanvasObject::PopEventHandler(deleteHandler);
742}
fcbb6b37 743
84fba40b
RR
744void wxCanvasObjectRef::AppendEventHandler(wxEvtHandler *handler)
745{
746 wxCanvasObject::AppendEventHandler(handler);
747 m_obj->AppendEventHandler(handler);
748}
749
750wxEvtHandler *wxCanvasObjectRef::RemoveLastEventHandler(bool deleteHandler)
751{
752 m_obj->RemoveLastEventHandler(deleteHandler);
753 return wxCanvasObject::RemoveLastEventHandler(deleteHandler);
754}
755
756void wxCanvasObjectRef::TransLate( double x, double y )
757{
758 lworld.Translate(x,y);
759 CalcBoundingBox();
760}
761
762wxCanvasObject* wxCanvasObjectRef::Contains( wxCanvasObject* obj )
763{
764 if (obj == this || m_obj->Contains(obj))
765 return this;
766
767 return (wxCanvasObject*) NULL;
768}
769
770
771void wxCanvasObjectRef::SetRotation(double rotation)
772{
773 lworld.SetRotation(rotation);
774 CalcBoundingBox();
775}
776
777void wxCanvasObjectRef::SetScale(double scalex,double scaley)
778{
779 lworld.Scale(scalex,scaley,lworld.GetValue(2,0),lworld.GetValue(2,1));
780 CalcBoundingBox();
fcbb6b37
KH
781}
782
84fba40b 783void wxCanvasObjectRef::SetAdmin(wxCanvasAdmin* admin)
fcbb6b37 784{
84fba40b
RR
785 m_admin = admin;
786 m_obj->SetAdmin(admin);
787}
788
789void wxCanvasObjectRef::CalcBoundingBox()
790{
791 m_bbox.SetValid(FALSE);
792 m_obj->CalcBoundingBox();
fcbb6b37 793
84fba40b
RR
794 wxBoundingBox tmp;
795 tmp=m_obj->GetBbox();
796 tmp.MapBbox(lworld);
797 m_bbox.Expand( tmp );
fcbb6b37
KH
798}
799
84fba40b 800void wxCanvasObjectRef::Render(wxTransformMatrix* cworld, int x, int y, int width, int height )
fcbb6b37 801{
84fba40b
RR
802 if (!m_visible) return;
803
804 //get the absolute area (without the local matrix included)
805 //the boundingbox is relative to the parent.
806 wxRect absarea=GetAbsoluteArea(*cworld);
fcbb6b37 807
84fba40b
RR
808 wxTransformMatrix backup = *cworld;
809 *cworld *= lworld;
810
811#ifdef CANVASDEBUG
812 wxDC *dc = m_admin->GetActive()->GetDC();
813 dc->SetPen(*wxBLACK_PEN);
814 dc->SetBrush(*wxTRANSPARENT_BRUSH);
815 dc->DrawRectangle( absarea.x , absarea.y , absarea.width , absarea.height );
816 dc->SetBrush(wxNullBrush);
817 dc->SetPen(wxNullPen);
818#endif
819
820 int clip_x = absarea.x;
821 int clip_width = absarea.width;
fcbb6b37
KH
822 if (clip_x < x)
823 {
824 clip_width -= x-clip_x;
825 clip_x = x;
826 }
827 if (clip_width > 0)
828 {
829 if (clip_x + clip_width > x + width)
830 clip_width = x+width-clip_x;
831
832 if (clip_width > 0)
833 {
84fba40b
RR
834 int clip_y = absarea.y;
835 int clip_height = absarea.height;
fcbb6b37
KH
836 if (clip_y < y)
837 {
838 clip_height -= y-clip_y;
839 clip_y = y;
840 }
841 if (clip_height > 0)
842 {
843 if (clip_y + clip_height > y + height)
844 clip_height = y+height-clip_y;
845
846 if (clip_height > 0)
84fba40b 847 m_obj->Render(cworld, clip_x, clip_y, clip_width, clip_height );
fcbb6b37
KH
848 }
849 }
850 }
fcbb6b37 851
84fba40b 852 *cworld = backup;
fcbb6b37
KH
853}
854
84fba40b 855void wxCanvasObjectRef::WriteSVG( wxTextOutputStream &stream )
fcbb6b37 856{
fcbb6b37
KH
857}
858
84fba40b 859wxCanvasObject* wxCanvasObjectRef::IsHitWorld( double x, double y, double margin )
fcbb6b37 860{
84fba40b
RR
861 //KKKfirst check if within bbox
862 //will only work if they are always uptodate
863 //if (!m_bbox.PointInBox(x,y,margin))
864 // return (wxCanvasObject*) NULL;
fcbb6b37 865
84fba40b
RR
866 wxTransformMatrix inverse = lworld;
867 double xh,yh;
868 inverse.Invert();
869 inverse.TransformPoint(x,y,xh,yh);
fcbb6b37 870
84fba40b
RR
871 if (m_obj->IsHitWorld(xh,yh,margin))
872 return this;
5143c96b 873
84fba40b
RR
874 return (wxCanvasObject*) NULL;
875}
5143c96b 876
5143c96b 877
fcbb6b37 878
5143c96b 879//----------------------------------------------------------------------------
84fba40b 880// wxCanvasRect
5143c96b
KH
881//----------------------------------------------------------------------------
882
84fba40b 883wxCanvasRect::wxCanvasRect( double x, double y, double w, double h , double radius )
5143c96b
KH
884 : wxCanvasObject()
885{
84fba40b
RR
886 m_x = x;
887 m_y = y;
888 m_width = w;
889 m_height = h;
890 m_radius = radius;
891
892 m_brush = *wxBLACK_BRUSH;
893 m_pen = *wxTRANSPARENT_PEN;
894 CalcBoundingBox();
5143c96b
KH
895}
896
84fba40b 897void wxCanvasRect::TransLate( double x, double y )
5143c96b 898{
84fba40b
RR
899 m_x += x;
900 m_y += y;
901 CalcBoundingBox();
5143c96b
KH
902}
903
84fba40b 904void wxCanvasRect::CalcBoundingBox()
5143c96b 905{
84fba40b
RR
906 m_bbox.SetMin( m_x , m_y);
907 m_bbox.SetMax( m_x + m_width ,m_y + m_height );
5143c96b
KH
908
909 //include the pen width also
84fba40b
RR
910//KKK m_bbox.EnLarge(m_pen.GetWidth()+m_radius);
911 m_bbox.EnLarge(m_pen.GetWidth()/2);
5143c96b
KH
912}
913
84fba40b 914void wxCanvasRect::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
5143c96b 915{
84fba40b
RR
916 if (!m_visible) return;
917
84fba40b 918 if (cworld->GetRotation())
5143c96b 919 {
84fba40b
RR
920 wxPoint *cpoints = new wxPoint[4];
921 double x;
922 double y;
923 cworld->TransformPoint( m_x, m_y, x, y );
924 cpoints[0].x = m_admin->LogicalToDeviceX(x);
925 cpoints[0].y = m_admin->LogicalToDeviceY(y);
926 cworld->TransformPoint( m_x , m_y + m_height, x, y );
927 cpoints[1].x = m_admin->LogicalToDeviceX(x);
928 cpoints[1].y = m_admin->LogicalToDeviceY(y);
929 cworld->TransformPoint( m_x + m_width, m_y + m_height, x, y );
930 cpoints[2].x = m_admin->LogicalToDeviceX(x);
931 cpoints[2].y = m_admin->LogicalToDeviceY(y);
932 cworld->TransformPoint( m_x + m_width, m_y , x, y );
933 cpoints[3].x = m_admin->LogicalToDeviceX(x);
934 cpoints[3].y = m_admin->LogicalToDeviceY(y);
935
936 wxDC *dc = m_admin->GetActive()->GetDC();
937 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
938 dc->SetBrush(m_brush);
939 int pw=m_pen.GetWidth();
940 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
941 dc->SetPen(m_pen);
942 dc->DrawPolygon(4, cpoints, 0,0,wxWINDING_RULE);
943 delete [] cpoints;
944 dc->SetBrush(wxNullBrush);
945 dc->SetPen(wxNullPen);
946 dc->DestroyClippingRegion();
947 m_pen.SetWidth(pw);
948 }
949 else
950 {
951 wxDC *dc = m_admin->GetActive()->GetDC();
952 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
953 dc->SetBrush(m_brush);
954 int pw=m_pen.GetWidth();
955 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
956 dc->SetPen(m_pen);
957 //yes the whole not only the clipping region, because we have a pen also
958 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
959 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
960 int w = m_admin->LogicalToDeviceXRel( m_width );
961 int h = m_admin->LogicalToDeviceYRel( m_height );
962 int r = m_admin->LogicalToDeviceYRel( m_radius );
963 if (w > 0 && w < 1) w=1;
964 if (w < 0 && w > -1) w=-1;
965 if (h > 0 && h < 1) h=1;
966 if (h < 0 && h > -1) h=-1;
967 if (m_radius)
968 dc->DrawRoundedRectangle( x,y,w,h,r);
969 else
970 dc->DrawRectangle( x,y,w,h);
971 dc->SetBrush(wxNullBrush);
972 dc->SetPen(wxNullPen);
973 dc->DestroyClippingRegion();
974 m_pen.SetWidth(pw);
5143c96b 975 }
5143c96b
KH
976}
977
84fba40b 978void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
5143c96b
KH
979{
980}
981
982//----------------------------------------------------------------------------
84fba40b 983// wxCanvasCircle
5143c96b
KH
984//----------------------------------------------------------------------------
985
84fba40b 986wxCanvasCircle::wxCanvasCircle( double x, double y, double radius )
5143c96b
KH
987 : wxCanvasObject()
988{
84fba40b
RR
989 m_x = x;
990 m_y = y;
991 m_radius = radius;
992
27d1065d
RR
993 m_brush = *wxBLACK_BRUSH;
994 m_pen = *wxTRANSPARENT_PEN;
84fba40b 995 CalcBoundingBox();
5143c96b
KH
996}
997
84fba40b 998void wxCanvasCircle::TransLate( double x, double y )
5143c96b 999{
84fba40b
RR
1000 m_x += x;
1001 m_y += y;
1002 CalcBoundingBox();
5143c96b
KH
1003}
1004
84fba40b 1005void wxCanvasCircle::CalcBoundingBox()
5143c96b 1006{
84fba40b
RR
1007 m_bbox.SetMin( m_x-m_radius , m_y-m_radius );
1008 m_bbox.SetMax( m_x+m_radius , m_y+m_radius );
5143c96b 1009
84fba40b
RR
1010 //include the pen width also
1011 m_bbox.EnLarge(m_pen.GetWidth()/2);
1012}
1013
1014void wxCanvasCircle::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
1015{
1016 if (!m_visible) return;
1017
84fba40b
RR
1018 wxDC *dc = m_admin->GetActive()->GetDC();
1019 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
1020 dc->SetBrush(m_brush);
1021 int pw=m_pen.GetWidth();
1022 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
1023 dc->SetPen(m_pen);
1024 //yes the whole not only the clipping region, because we have a pen also
1025 //and rotation on a circle is not important so only a shift with cworld
1026 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
1027 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
1028 int radius = m_admin->LogicalToDeviceXRel( m_radius );
1029 if (radius < 1) radius=1;
1030 dc->DrawCircle( x,y,radius);
1031 dc->SetBrush(wxNullBrush);
1032 dc->SetPen(wxNullPen);
1033 dc->DestroyClippingRegion();
1034 m_pen.SetWidth(pw);
5143c96b
KH
1035}
1036
84fba40b 1037void wxCanvasCircle::WriteSVG( wxTextOutputStream &stream )
5143c96b 1038{
84fba40b 1039}
5143c96b 1040
84fba40b
RR
1041wxCanvasObject* wxCanvasCircle::IsHitWorld( double x, double y, double margin )
1042{
1043 if ((x >= m_bbox.GetMinX()-margin) &&
1044 (x <= m_bbox.GetMaxX()+margin) &&
1045 (y >= m_bbox.GetMinY()-margin) &&
1046 (y <= m_bbox.GetMaxY()+margin)
1047 )
5143c96b 1048 {
84fba40b
RR
1049 if (m_radius+m_pen.GetWidth()/2+margin > sqrt(pow(m_x-x,2)+pow(m_y-y,2)))
1050 return this;
1051 else
1052 return (wxCanvasObject*) NULL;
5143c96b 1053 }
84fba40b
RR
1054 return (wxCanvasObject*) NULL;
1055}
5143c96b 1056
84fba40b
RR
1057//----------------------------------------------------------------------------
1058// wxCanvasEllipse
1059//----------------------------------------------------------------------------
1060
1061wxCanvasEllipse::wxCanvasEllipse( double x, double y, double width, double height )
1062 : wxCanvasObject()
1063{
1064 m_x = x;
1065 m_y = y;
1066 m_width = width;
1067 m_height = height;
1068
1069 m_brush = *wxBLACK_BRUSH;
1070 m_pen = *wxTRANSPARENT_PEN;
1071 CalcBoundingBox();
1072}
5143c96b 1073
84fba40b
RR
1074void wxCanvasEllipse::TransLate( double x, double y )
1075{
1076 m_x += x;
1077 m_y += y;
1078 CalcBoundingBox();
5143c96b
KH
1079}
1080
84fba40b 1081void wxCanvasEllipse::CalcBoundingBox()
5143c96b 1082{
84fba40b
RR
1083 m_bbox.SetMin( m_x, m_y );
1084 m_bbox.SetMax( m_x+m_width , m_y+m_height );
5143c96b 1085
84fba40b
RR
1086 //include the pen width also
1087 m_bbox.EnLarge(m_pen.GetWidth()/2);
1088}
5143c96b 1089
84fba40b
RR
1090void wxCanvasEllipse::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
1091{
1092 if (!m_visible) return;
5143c96b 1093
84fba40b
RR
1094 wxDC *dc = m_admin->GetActive()->GetDC();
1095 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
5143c96b 1096 dc->SetBrush(m_brush);
84fba40b
RR
1097 int pw=m_pen.GetWidth();
1098 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
5143c96b 1099 dc->SetPen(m_pen);
84fba40b
RR
1100 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
1101 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
1102 int w = m_admin->LogicalToDeviceXRel( m_width );
1103 int h = m_admin->LogicalToDeviceYRel( m_height );
1104 if (w > 0 && w < 1) w=1;
1105 if (w < 0 && w > -1) w=-1;
1106 if (h > 0 && h < 1) h=1;
1107 if (h < 0 && h > -1) h=-1;
1108 dc->DrawEllipse( x,y,w,h);
5143c96b
KH
1109 dc->SetBrush(wxNullBrush);
1110 dc->SetPen(wxNullPen);
1111 dc->DestroyClippingRegion();
84fba40b 1112 m_pen.SetWidth(pw);
5143c96b
KH
1113}
1114
84fba40b 1115void wxCanvasEllipse::WriteSVG( wxTextOutputStream &stream )
5143c96b
KH
1116{
1117}
1118
84fba40b
RR
1119wxCanvasObject* wxCanvasEllipse::IsHitWorld( double x, double y, double margin )
1120{
1121 if ((x >= m_bbox.GetMinX()-margin) &&
1122 (x <= m_bbox.GetMaxX()+margin) &&
1123 (y >= m_bbox.GetMinY()-margin) &&
1124 (y <= m_bbox.GetMaxY()+margin)
1125 )
1126 {
1127 double a=(m_width+m_pen.GetWidth())/2+margin ;
1128 double b=(m_height+m_pen.GetWidth())/2+margin;
1129 double c=pow((m_x+m_width/2-x)/a,2)+pow((m_y+m_height/2-y)/b,2);
1130 if ( 1 > c)
1131 return this;
1132 else
1133 return (wxCanvasObject*) NULL;
1134 }
1135 return (wxCanvasObject*) NULL;
1136}
fcbb6b37 1137
21544859 1138//----------------------------------------------------------------------------
84fba40b 1139// wxCanvasEllipticArc
21544859
RR
1140//----------------------------------------------------------------------------
1141
84fba40b 1142wxCanvasEllipticArc::wxCanvasEllipticArc( double x, double y, double width, double height, double start, double end )
4dbd4ee6 1143 : wxCanvasObject()
21544859 1144{
4dbd4ee6
RR
1145 m_x = x;
1146 m_y = y;
84fba40b
RR
1147 m_width = width;
1148 m_height = height;
1149 m_start = start;
1150 m_end = end;
dc16900b 1151
27d1065d
RR
1152 m_brush = *wxBLACK_BRUSH;
1153 m_pen = *wxTRANSPARENT_PEN;
84fba40b 1154 CalcBoundingBox();
21544859
RR
1155}
1156
84fba40b 1157void wxCanvasEllipticArc::TransLate( double x, double y )
4dbd4ee6 1158{
84fba40b
RR
1159 m_x += x;
1160 m_y += y;
1161 CalcBoundingBox();
4dbd4ee6
RR
1162}
1163
84fba40b 1164void wxCanvasEllipticArc::CalcBoundingBox()
21544859 1165{
84fba40b
RR
1166 m_bbox.SetMin( m_x, m_y );
1167 m_bbox.SetMax( m_x+m_width , m_y+m_height );
fcbb6b37 1168
84fba40b
RR
1169 //include the pen width also
1170 m_bbox.EnLarge(m_pen.GetWidth()/2);
1171}
fcbb6b37 1172
84fba40b
RR
1173void wxCanvasEllipticArc::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
1174{
1175 if (!m_visible) return;
fcbb6b37 1176
84fba40b
RR
1177 wxDC *dc = m_admin->GetActive()->GetDC();
1178 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
1179 dc->SetBrush(m_brush);
1180 int pw=m_pen.GetWidth();
1181 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
1182 dc->SetPen(m_pen);
1183 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
1184 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
1185 int w = m_admin->LogicalToDeviceXRel( m_width );
1186 int h = m_admin->LogicalToDeviceYRel( m_height );
1187 if (w > 0 && w < 1) w=1;
1188 if (w < 0 && w > -1) w=-1;
1189 if (h > 0 && h < 1) h=1;
1190 if (h < 0 && h > -1) h=-1;
1191 if (m_admin->GetActive()->GetYaxis())
1192 dc->DrawEllipticArc( x,y,w,h,-m_end,-m_start);
1193 else
1194 dc->DrawEllipticArc( x,y,w,h,m_start,m_end);
1195 dc->SetBrush(wxNullBrush);
1196 dc->SetPen(wxNullPen);
1197 dc->DestroyClippingRegion();
1198 m_pen.SetWidth(pw);
21544859
RR
1199}
1200
84fba40b
RR
1201void wxCanvasEllipticArc::WriteSVG( wxTextOutputStream &stream )
1202{
1203}
1204
1205wxCanvasObject* wxCanvasEllipticArc::IsHitWorld( double x, double y, double margin )
21544859 1206{
84fba40b
RR
1207 if ((x >= m_bbox.GetMinX()-margin) &&
1208 (x <= m_bbox.GetMaxX()+margin) &&
1209 (y >= m_bbox.GetMinY()-margin) &&
1210 (y <= m_bbox.GetMaxY()+margin)
1211 )
1212 {
1213 double a=(m_width+m_pen.GetWidth())/2+margin ;
1214 double b=(m_height+m_pen.GetWidth())/2+margin;
1215 double c=pow((m_x+m_width/2-x)/a,2)+pow((m_y+m_height/2-y)/b,2);
1216 if ( 1 > c)
1217 return this;
1218 else
1219 return (wxCanvasObject*) NULL;
1220 }
1221 return (wxCanvasObject*) NULL;
21544859
RR
1222}
1223
239c1f50
RR
1224//----------------------------------------------------------------------------
1225// wxCanvasLine
1226//----------------------------------------------------------------------------
1227
27d1065d 1228wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2 )
4dbd4ee6 1229 : wxCanvasObject()
239c1f50 1230{
4dbd4ee6
RR
1231 m_x1 = x1;
1232 m_y1 = y1;
1233 m_x2 = x2;
1234 m_y2 = y2;
1235
27d1065d 1236 m_pen = *wxBLACK_PEN;
84fba40b 1237 CalcBoundingBox();
239c1f50
RR
1238}
1239
84fba40b 1240void wxCanvasLine::TransLate( double x, double y )
4dbd4ee6 1241{
84fba40b
RR
1242 m_x1 += x;
1243 m_y1 += y;
1244 m_x2 += x;
1245 m_y2 += y;
1246 CalcBoundingBox();
1247}
1248
1249void wxCanvasLine::CalcBoundingBox()
1250{
1251 m_bbox.SetMin( m_x1 , m_y1);
1252 m_bbox.SetMax( m_x2 , m_y2);
1253
1254 //include the pen width also
1255 m_bbox.EnLarge(m_pen.GetWidth()/2);
4dbd4ee6
RR
1256}
1257
84fba40b 1258void wxCanvasLine::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
239c1f50 1259{
84fba40b 1260 if (!m_visible) return;
fcbb6b37 1261
84fba40b
RR
1262 double x1,y1,x2,y2;
1263 cworld->TransformPoint( m_x1, m_y1, x1, y1 );
1264 cworld->TransformPoint( m_x2, m_y2, x2, y2 );
1265 x1 = m_admin->LogicalToDeviceX( x1 );
1266 y1 = m_admin->LogicalToDeviceY( y1 );
1267 x2 = m_admin->LogicalToDeviceX( x2 );
1268 y2 = m_admin->LogicalToDeviceY( y2 );
5143c96b 1269
84fba40b
RR
1270 wxDC *dc = m_admin->GetActive()->GetDC();
1271 dc->SetClippingRegion( clip_x, clip_y, clip_width, clip_height );
1272 int pw=m_pen.GetWidth();
1273 m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
27d1065d 1274 dc->SetPen( m_pen );
84fba40b 1275 dc->DrawLine( x1, y1, x2, y2 );
5143c96b 1276
33ebcd80 1277 dc->DestroyClippingRegion();
84fba40b 1278 m_pen.SetWidth(pw);
239c1f50
RR
1279}
1280
1281void wxCanvasLine::WriteSVG( wxTextOutputStream &stream )
1282{
1e1af41e 1283 // no idea
239c1f50
RR
1284}
1285
84fba40b
RR
1286wxCanvasObject* wxCanvasLine::IsHitWorld( double x, double y, double margin )
1287{
1288 if ((x >= m_bbox.GetMinX()-margin) &&
1289 (x <= m_bbox.GetMaxX()+margin) &&
1290 (y >= m_bbox.GetMinY()-margin) &&
1291 (y <= m_bbox.GetMaxY()+margin)
1292 )
1293 {
1294 wxLine line1(m_x1,m_y1,m_x2,m_y2);
1295 wxPoint2DDouble P=wxPoint2DDouble(x,y);
1296 double distance;
1297 if (line1.PointInLine(P,distance,m_pen.GetWidth()/2+margin) == R_IN_AREA)
1298 return this;
1299 else
1300 return (wxCanvasObject*) NULL;
1301 }
1302 return (wxCanvasObject*) NULL;
1303}
1304
6a2c1874
RR
1305//----------------------------------------------------------------------------
1306// wxCanvasImage
1307//----------------------------------------------------------------------------
1308
4dbd4ee6
RR
1309wxCanvasImage::wxCanvasImage( const wxImage &image, double x, double y, double w, double h )
1310 : wxCanvasObject()
6a2c1874 1311{
4dbd4ee6
RR
1312 m_x = x;
1313 m_y = y;
1314 m_width = w;
1315 m_height = h;
dc16900b 1316
6a2c1874 1317 m_image = image;
84fba40b 1318
f03b31e8
RR
1319 m_orgw = m_image.GetWidth();
1320 m_orgh = m_image.GetHeight();
84fba40b 1321
6a2c1874 1322 m_isImage = TRUE;
84fba40b 1323 CalcBoundingBox();
6a2c1874
RR
1324}
1325
880d870e
RR
1326void wxCanvasImage::SetPosXY( double x, double y)
1327{
1328 m_x = x;
1329 m_y = y;
1330 CalcBoundingBox();
1331}
1332
84fba40b 1333void wxCanvasImage::TransLate( double x, double y )
4dbd4ee6 1334{
84fba40b
RR
1335 m_x += x;
1336 m_y += y;
1337 CalcBoundingBox();
1338}
1339
1340void wxCanvasImage::CalcBoundingBox()
1341{
f03b31e8
RR
1342 m_bbox.SetMin( m_x, m_y );
1343 m_bbox.SetMax( m_x + m_width, m_y + m_height );
84fba40b
RR
1344}
1345
1346void wxCanvasImage::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
1347{
1348 if (!m_visible) return;
880d870e 1349
84fba40b
RR
1350 wxRect tmparea;
1351
1352 tmparea.x = m_admin->LogicalToDeviceXRel( m_bbox.GetMinX());
1353 tmparea.y = m_admin->LogicalToDeviceYRel( m_bbox.GetMinY());
1354 tmparea.width = m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() );
1355 tmparea.height = m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() );
1356
1357 double x;
1358 double y;
1359 cworld->TransformPoint( m_x, m_y, x, y );
1360 x = m_admin->LogicalToDeviceX(x);
1361 y = m_admin->LogicalToDeviceY(y);
1362
dc16900b 1363
880d870e 1364 // What is this???
84fba40b
RR
1365 if ( m_orgw*5 < m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() ) ||
1366 m_orgw/5 > m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() ) ||
1367 m_orgh*5 < m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() ) ||
1368 m_orgh/5 > m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() )
1369 )
1370 {
1371 wxDC *dc = m_admin->GetActive()->GetDC();
1372 dc->SetClippingRegion(clip_x, clip_y, clip_width, clip_height);
1373 dc->SetBrush(*wxTRANSPARENT_BRUSH);
1374 dc->SetPen(*wxBLACK_PEN);
1375 //yes the whole not only the clipping region, because we have a pen also
1376 int x = m_admin->LogicalToDeviceX(cworld->GetValue(2,0) + m_x );
1377 int y = m_admin->LogicalToDeviceY(cworld->GetValue(2,1) + m_y );
1378 int w = m_admin->LogicalToDeviceXRel( m_width );
1379 int h = m_admin->LogicalToDeviceYRel( m_height );
1380 if (w < 1) w=1;
1381 if (h < 1) h=1;
1382 dc->DrawRectangle( x,y,w,h);
1383 dc->SetBrush(wxNullBrush);
1384 dc->SetPen(wxNullPen);
1385 dc->DestroyClippingRegion();
1386 return;
1387 }
880d870e
RR
1388
1389 wxImage tmp;
1390 bool is_cashed = FALSE;
84fba40b 1391
880d870e 1392 if (m_cImage.Ok() && (m_cW == m_bbox.GetWidth()) && (m_cH == m_bbox.GetHeight()))
33ebcd80 1393 {
880d870e
RR
1394 // use cached image
1395 tmp = m_cImage;
1396 is_cashed = TRUE;
33ebcd80
RR
1397 }
1398 else
1399 {
880d870e
RR
1400 if ((m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() ) == m_image.GetWidth()) &&
1401 (m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() ) == m_image.GetHeight()))
1402 {
1403 tmp = m_image;
1404 }
1405 else
1406 {
1407 tmp = m_image.Scale( m_admin->LogicalToDeviceXRel( m_bbox.GetWidth()),
1408 m_admin->LogicalToDeviceYRel( m_bbox.GetHeight()) );
1409 }
1410
1411 // create cached image
1412 m_cImage = tmp;
1413 m_cW = tmp.GetWidth();
1414 m_cH = tmp.GetHeight();
33ebcd80 1415 }
4dbd4ee6 1416
84fba40b
RR
1417// wxPoint centr(m_admin->LogicalToDeviceX(m_x),m_admin->LogicalToDeviceY(m_y));
1418 wxPoint centr(0,0);
fcbb6b37 1419
880d870e
RR
1420 wxBitmap bmp;
1421
1422 if (m_cBitmap.Ok() && is_cashed && (m_cR == cworld->GetRotation()))
d1f9b206 1423 {
880d870e 1424 bmp = m_cBitmap;
d1f9b206
RR
1425 }
1426 else
1427 {
880d870e
RR
1428 if (cworld->GetRotation())
1429 tmp = tmp.Rotate(-cworld->GetRotation()/180.0 * pi, centr, TRUE, NULL );
1430
1431 bmp = tmp.ConvertToBitmap();
1432
1433 // create cached bitmap
1434 m_cBitmap = bmp;
1435 m_cR = cworld->GetRotation();
d1f9b206 1436 }
5143c96b 1437
84fba40b
RR
1438 wxDC *dc = m_admin->GetActive()->GetDC();
1439
1440 wxPoint centr2;
1441 if (cworld->GetRotation()> 0)
33ebcd80 1442 {
84fba40b
RR
1443 centr2.x= (int) (x+m_height*sin(-cworld->GetRotation()/180.0 * pi));
1444 centr2.y= (int) y;
33ebcd80
RR
1445 }
1446 else
1447 {
84fba40b
RR
1448 centr2.x= (int) x;
1449 centr2.y= (int) (y-m_width*sin(-cworld->GetRotation()/180.0 * pi));
1450 }
5143c96b 1451
84fba40b
RR
1452 if (cworld->GetRotation() != 0)
1453 {
1454 //TODO clipping not right
1455 dc->DrawBitmap(bmp,centr2,TRUE );
1456// dc->DrawPoint(centr2);
1457// dc->DrawPoint(x,y);
1458 }
1459 else
1460 {
880d870e
RR
1461 dc->SetClippingRegion( clip_x, clip_y, clip_width, clip_height );
1462 dc->DrawBitmap( bmp, x, y, TRUE );
1463 dc->DestroyClippingRegion();
33ebcd80 1464 }
6a2c1874
RR
1465}
1466
1467void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
1468{
1469 // no idea
1470}
1471
3b111dbe
RR
1472//----------------------------------------------------------------------------
1473// wxCanvasCtrl
1474//----------------------------------------------------------------------------
1475
1476wxCanvasControl::wxCanvasControl( wxWindow *control )
4dbd4ee6 1477 : wxCanvasObject()
3b111dbe 1478{
21544859 1479 m_isControl = TRUE;
3b111dbe 1480 m_control = control;
84fba40b
RR
1481 CalcBoundingBox();
1482}
1483
1484double wxCanvasControl::GetPosX()
1485{
1486 int x,y ;
1487 m_control->GetPosition( &x, &y );
1488 return m_admin->DeviceToLogicalX(x);
1489}
1490
1491double wxCanvasControl::GetPosY()
1492{
1493 int x,y ;
1494 m_control->GetPosition( &x, &y );
1495 return m_admin->DeviceToLogicalY(y);
1496}
1497
1498void wxCanvasControl::SetPosXY( double x, double y)
1499{
1500 int xd = m_admin->LogicalToDeviceX(x);
1501 int yd = m_admin->LogicalToDeviceY(y);
1502 m_control->Move(xd,yd);
1503}
1504
1505
1506void wxCanvasControl::TransLate( double x, double y )
1507{
1508 int xdo,ydo;
1509 m_control->GetPosition( &xdo, &ydo );
1510 int xd = m_admin->LogicalToDeviceX(x)-xdo;
1511 int yd = m_admin->LogicalToDeviceY(y)-ydo;
1512 m_control->Move(xd,yd);
1513 CalcBoundingBox();
3b111dbe
RR
1514}
1515
1516wxCanvasControl::~wxCanvasControl()
1517{
1518 m_control->Destroy();
1519}
1520
84fba40b 1521void wxCanvasControl::CalcBoundingBox()
3b111dbe 1522{
84fba40b
RR
1523 wxRect tmparea;
1524
1525 m_control->GetSize( &tmparea.width, &tmparea.height );
1526 m_control->GetPosition( &tmparea.x, &tmparea.y );
1527
1528 m_bbox.SetMin( tmparea.x , tmparea.y);
1529 m_bbox.SetMax( tmparea.x + tmparea.width , tmparea.y + tmparea.height);
1530
3b111dbe
RR
1531}
1532
84fba40b 1533void wxCanvasControl::MoveRelative( double x, double y )
3b111dbe 1534{
84fba40b 1535 m_control->Move( m_admin->LogicalToDeviceX(x), m_admin->LogicalToDeviceX(y) );
3b111dbe
RR
1536}
1537
d1f9b206
RR
1538//----------------------------------------------------------------------------
1539// wxCanvasText
1540//----------------------------------------------------------------------------
1541
1542class wxFaceData
1543{
1544public:
1e1af41e 1545#if wxUSE_FREETYPE
d1f9b206
RR
1546 FT_Face m_face;
1547#else
1548 void *m_dummy;
dc16900b 1549#endif
d1f9b206
RR
1550};
1551
4dbd4ee6
RR
1552wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxString &fontFile, int size )
1553 : wxCanvasObject()
d1f9b206
RR
1554{
1555 m_text = text;
cb281cfc
RR
1556 m_fontFileName = fontFile;
1557 m_size = size;
dc16900b 1558
cb281cfc 1559 m_red = 0;
d1f9b206
RR
1560 m_green = 0;
1561 m_blue = 0;
dc16900b 1562
4dbd4ee6 1563 m_alpha = NULL;
dc16900b 1564
4dbd4ee6
RR
1565 m_x = x;
1566 m_y = y;
dc16900b
KH
1567
1568#if wxUSE_FREETYPE
d1f9b206
RR
1569 wxFaceData *data = new wxFaceData;
1570 m_faceData = data;
dc16900b 1571
d1f9b206 1572 int error = FT_New_Face( g_freetypeLibrary,
cb281cfc 1573 m_fontFileName,
d1f9b206
RR
1574 0,
1575 &(data->m_face) );
5143c96b 1576
d1f9b206
RR
1577 error = FT_Set_Char_Size( data->m_face,
1578 0,
cb281cfc
RR
1579 m_size*64,
1580 96, // screen dpi
d1f9b206
RR
1581 96 );
1582#endif
84fba40b 1583 CalcBoundingBox();
d1f9b206
RR
1584}
1585
1586wxCanvasText::~wxCanvasText()
1587{
fcbb6b37 1588#if wxUSE_FREETYPE
d1f9b206
RR
1589 wxFaceData *data = (wxFaceData*) m_faceData;
1590 delete data;
1591#endif
1592
1593 if (m_alpha) delete [] m_alpha;
1594}
1595
1596void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue )
1597{
1598 m_red = red;
1599 m_green = green;
1600 m_blue = blue;
1601}
1602
1603void wxCanvasText::SetFlag( int flag )
1604{
1605 m_flag = flag;
1606}
1607
84fba40b 1608void wxCanvasText::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
d1f9b206 1609{
84fba40b
RR
1610 if (!m_visible) return;
1611
1612 wxRect tmparea;
1613 tmparea.x = m_admin->LogicalToDeviceX( m_bbox.GetMinX());
1614 tmparea.y = m_admin->LogicalToDeviceY( m_bbox.GetMinY());
1615 tmparea.width = m_admin->LogicalToDeviceXRel( m_bbox.GetWidth() );
1616 tmparea.height = m_admin->LogicalToDeviceYRel( m_bbox.GetHeight() );
1617
1618 m_alpha = new unsigned char[tmparea.width*tmparea.height];
1619 memset( m_alpha, 0, tmparea.width*tmparea.height );
1620
d1f9b206 1621 if (!m_alpha) return;
fcbb6b37 1622
84fba40b
RR
1623#if wxUSE_FREETYPE
1624 FT_Face face = ((wxFaceData*)m_faceData)->m_face;
1625 FT_GlyphSlot slot = face->glyph;
1626 int pen_x = 0;
1627 int pen_y = m_size;
1628
1629 for (int n = 0; n < (int)m_text.Len(); n++)
1630 {
1631 FT_UInt index = FT_Get_Char_Index( face, m_text[(unsigned int)n] );
1632
1633 int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
1634 if (error) continue;
1635
1636 error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
1637 if (error) continue;
1638
1639 FT_Bitmap *bitmap = &slot->bitmap;
1640 unsigned char* buffer = bitmap->buffer;
1641 for (int y = 0; y < bitmap->rows; y++)
1642 for (int x = 0; x < bitmap->width; x++)
1643 {
1644 unsigned char alpha = buffer[ y*bitmap->pitch + x ];
1645 if (alpha == 0) continue;
1646
1647 int xx = pen_x + slot->bitmap_left + x;
1648 int yy = pen_y - slot->bitmap_top + y;
1649 m_alpha[ yy * tmparea.width + xx ] = alpha;
1650 }
1651
1652 pen_x += slot->advance.x >> 6;
1653 pen_y += slot->advance.y >> 6;
1654 }
1655#endif
1656
84fba40b
RR
1657 wxBitmap *bitmap = m_admin->GetActive()->GetBuffer();
1658 wxRect sub_rect( clip_x, clip_y, clip_width, clip_height );
96f5fca9 1659 wxBitmap sub_bitmap( bitmap->GetSubBitmap( sub_rect ) );
84fba40b 1660
96f5fca9
RR
1661 wxImage image( sub_bitmap );
1662
1663 // local coordinates
84fba40b 1664 int start_x = clip_x - tmparea.x;
96f5fca9 1665 int end_x = clip_width + start_x;
84fba40b 1666 int start_y = clip_y - tmparea.y;
96f5fca9
RR
1667 int end_y = clip_height + start_y;
1668
1669 for (int y = start_y; y < end_y; y++)
1670 for (int x = start_x; x < end_x; x++)
1671 {
84fba40b 1672 int alpha = m_alpha[y*tmparea.width + x];
96f5fca9
RR
1673 if (alpha)
1674 {
1675 int image_x = x - start_x;
1676 int image_y = y - start_y;
1677 if (alpha == 255)
1678 {
1679 image.SetRGB( image_x, image_y, m_red, m_green, m_blue );
1680 continue;
1681 }
1682 int red1 = (m_red * alpha) / 255;
1683 int green1 = (m_green * alpha) / 255;
1684 int blue1 = (m_blue * alpha) / 255;
1685
1686 alpha = 255-alpha;
1687 int red2 = image.GetRed( image_x, image_y );
1688 int green2 = image.GetGreen( image_x, image_y );
1689 int blue2 = image.GetBlue( image_x, image_y );
1690 red2 = (red2 * alpha) / 255;
1691 green2 = (green2 * alpha) / 255;
1692 blue2 = (blue2 * alpha) / 255;
1693
1694 image.SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
1695 }
1696 }
84fba40b 1697
96f5fca9 1698 sub_bitmap = image.ConvertToBitmap();
84fba40b
RR
1699
1700 wxDC *dc = m_admin->GetActive()->GetDC();
1701 dc->DrawBitmap( sub_bitmap, clip_x, clip_y );
d1f9b206
RR
1702}
1703
1704void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
1705{
1706}
1707
84fba40b 1708void wxCanvasText::TransLate( double x, double y )
d1f9b206 1709{
84fba40b
RR
1710 m_x += x;
1711 m_y += y;
1712 CalcBoundingBox();
1713}
dc16900b 1714
84fba40b
RR
1715void wxCanvasText::CalcBoundingBox()
1716{
1717 if (m_alpha) delete [] m_alpha;
dc16900b 1718
84fba40b
RR
1719 m_bbox.SetMin( m_x , m_y);
1720 m_bbox.SetMax( m_x + 100 , m_y + m_size + (m_size/2));
fcbb6b37 1721
fcbb6b37 1722
84fba40b 1723}
dc16900b 1724
84fba40b
RR
1725//----------------------------------------------------------------------------
1726// wxCanvas
1727//----------------------------------------------------------------------------
fcbb6b37 1728
8636c073 1729IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow)
fcbb6b37 1730
8636c073 1731BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow)
6a2c1874 1732 EVT_PAINT( wxCanvas::OnPaint )
6a2c1874 1733 EVT_IDLE( wxCanvas::OnIdle )
8636c073 1734 EVT_SIZE( wxCanvas::OnSize )
6a2c1874
RR
1735 EVT_MOUSE_EVENTS( wxCanvas::OnMouse )
1736 EVT_SET_FOCUS( wxCanvas::OnSetFocus )
1737 EVT_KILL_FOCUS( wxCanvas::OnKillFocus )
61b64bd9 1738 EVT_ERASE_BACKGROUND( wxCanvas::OnEraseBackground )
6a2c1874
RR
1739END_EVENT_TABLE()
1740
84fba40b 1741wxCanvas::wxCanvas( wxCanvasAdmin* admin, wxWindow *parent, wxWindowID id,
6a2c1874 1742 const wxPoint &position, const wxSize& size, long style ) :
8636c073 1743 wxScrolledWindow( parent, id, position, size, style )
6a2c1874 1744{
8636c073
RR
1745 // These are unused in wxVectorCanvas
1746 m_bufferX = 0;
1747 m_bufferY = 0;
1748
84fba40b 1749 m_admin = admin;
8636c073
RR
1750 m_admin->Append( this );
1751
6a2c1874 1752 m_needUpdate = FALSE;
84fba40b 1753 m_background = *wxWHITE;
239c1f50 1754 m_lastMouse = (wxCanvasObject*)NULL;
4dbd4ee6 1755 m_captureMouse = (wxCanvasObject*)NULL;
f03b31e8 1756 m_frozen = FALSE;
27d1065d
RR
1757 m_oldDeviceX = 0;
1758 m_oldDeviceY = 0;
8636c073 1759 m_root = (wxCanvasObjectGroup*)NULL;
6a2c1874
RR
1760}
1761
1762wxCanvas::~wxCanvas()
1763{
1764 wxNode *node = m_updateRects.First();
1765 while (node)
1766 {
1767 wxRect *rect = (wxRect*) node->Data();
1768 delete rect;
1769 m_updateRects.DeleteNode( node );
1770 node = m_updateRects.First();
1771 }
1772}
1773
8636c073
RR
1774double wxCanvas::GetMinX() const
1775{
1776 return 0.0;
1777}
1778
1779double wxCanvas::GetMinY() const
1780{
1781 return 0.0;
1782}
1783
1784double wxCanvas::GetMaxX() const
1785{
1786 int width;
1787 GetVirtualSize( &width, NULL );
1788 return width;
1789}
1790
1791double wxCanvas::GetMaxY() const
1792{
1793 int height;
1794 GetVirtualSize( NULL, &height );
1795 return height;
1796}
1797
84fba40b 1798void wxCanvas::SetColour( const wxColour& background )
cb281cfc 1799{
8636c073 1800 m_background = background;
84fba40b 1801 SetBackgroundColour( m_background );
61b64bd9 1802
239c1f50 1803 if (m_frozen) return;
dc16900b 1804
33ebcd80
RR
1805 wxMemoryDC dc;
1806 dc.SelectObject( m_buffer );
1807 dc.SetPen( *wxTRANSPARENT_PEN );
84fba40b 1808 wxBrush brush( m_background, wxSOLID );
33ebcd80
RR
1809 dc.SetBrush( brush );
1810 dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
1811 dc.SelectObject( wxNullBitmap );
cb281cfc
RR
1812}
1813
dc16900b 1814void wxCanvas::SetCaptureMouse( wxCanvasObject *obj )
4dbd4ee6 1815{
dc16900b
KH
1816 if (obj)
1817 {
1818 wxWindow::CaptureMouse();
1819 m_captureMouse = obj;
1820 }
1821 else
1822 {
1823 wxWindow::ReleaseMouse();
1824 m_captureMouse = NULL;
1825 }
4dbd4ee6
RR
1826}
1827
239c1f50
RR
1828void wxCanvas::Freeze()
1829{
1830 m_frozen = TRUE;
1831}
1832
1833void wxCanvas::Thaw()
1834{
1835 wxNode *node = m_updateRects.First();
1836 while (node)
1837 {
1838 wxRect *rect = (wxRect*) node->Data();
1839 delete rect;
1840 m_updateRects.DeleteNode( node );
1841 node = m_updateRects.First();
1842 }
dc16900b 1843
239c1f50 1844 m_frozen = FALSE;
dc16900b 1845
41328253 1846 if (m_buffer.Ok())
8636c073 1847 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight() );
239c1f50
RR
1848}
1849
41328253 1850void wxCanvas::Update( int x, int y, int width, int height, bool blit )
6a2c1874 1851{
8636c073
RR
1852 CalcScrolledPosition( 0, 0, &m_oldDeviceX, &m_oldDeviceY );
1853
84fba40b
RR
1854 m_admin->SetActive(this);
1855
1856 if (!m_root) return;
1857
239c1f50 1858 if (m_frozen) return;
fcbb6b37 1859
21544859 1860 // clip to buffer
8636c073 1861 if (x < m_bufferX)
21544859 1862 {
8636c073
RR
1863 width -= m_bufferX-x;
1864 x = m_bufferX;
21544859 1865 }
33ebcd80 1866 if (width <= 0) return;
dc16900b 1867
8636c073 1868 if (y < m_bufferY)
21544859 1869 {
8636c073
RR
1870 height -= m_bufferY-y;
1871 y = m_bufferY;
21544859 1872 }
33ebcd80 1873 if (height <= 0) return;
dc16900b 1874
8636c073 1875 if (x+width > m_bufferX+m_buffer.GetWidth())
21544859 1876 {
8636c073 1877 width = m_bufferX+m_buffer.GetWidth() - x;
21544859 1878 }
33ebcd80 1879 if (width <= 0) return;
dc16900b 1880
8636c073 1881 if (y+height > m_bufferY+m_buffer.GetHeight())
21544859 1882 {
8636c073 1883 height = m_bufferY+m_buffer.GetHeight() - y;
21544859 1884 }
33ebcd80 1885 if (height <= 0) return;
dc16900b 1886
21544859 1887 // update is within the buffer
6a2c1874 1888 m_needUpdate = TRUE;
dc16900b 1889
21544859 1890 // has to be blitted to screen later
41328253
RR
1891 if (blit)
1892 {
1893 m_updateRects.Append(
1894 (wxObject*) new wxRect( x,y,width,height ) );
1895 }
dc16900b 1896
84fba40b
RR
1897 wxTransformMatrix cworld;
1898
33ebcd80
RR
1899 wxMemoryDC dc;
1900 dc.SelectObject( m_buffer );
84fba40b 1901
33ebcd80 1902 dc.SetPen( *wxTRANSPARENT_PEN );
8636c073 1903 wxBrush brush( m_background, wxSOLID );
33ebcd80 1904 dc.SetBrush( brush );
8636c073 1905 dc.SetLogicalFunction(wxCOPY);
33ebcd80 1906
8636c073 1907#if 0
84fba40b
RR
1908 if (width != m_buffer.GetWidth() && height != m_buffer.GetHeight())
1909 {
84fba40b
RR
1910 dc.SetClippingRegion(x,y,width,height);
1911 dc.DrawRectangle(x-2,y-2,width+4,height+4);
1912 dc.DestroyClippingRegion();
1913 }
1914 else
1915 {
1916 dc.Clear();
84fba40b
RR
1917 dc.DrawRectangle(0,0,m_buffer.GetWidth(),m_buffer.GetHeight());
1918 }
8636c073
RR
1919#else
1920 // No idea, what the code up there does.
1921 dc.DrawRectangle( x-m_bufferX, y-m_bufferY, width, height );
1922#endif
1923
84fba40b
RR
1924 dc.SetBrush(wxNullBrush);
1925 dc.SetPen(wxNullPen);
1926
8636c073
RR
1927 dc.SetDeviceOrigin( m_oldDeviceX, m_oldDeviceY );
1928 m_renderDC = &dc;
84fba40b 1929
8636c073 1930 m_root->Render( &cworld, x, y, width, height );
5143c96b 1931
8636c073 1932 m_renderDC = NULL;
33ebcd80 1933 dc.SelectObject( wxNullBitmap );
6a2c1874
RR
1934}
1935
3b111dbe 1936void wxCanvas::BlitBuffer( wxDC &dc )
6a2c1874 1937{
6a2c1874
RR
1938 wxNode *node = m_updateRects.First();
1939 while (node)
1940 {
1941 wxRect *rect = (wxRect*) node->Data();
8636c073 1942
84fba40b
RR
1943 wxMemoryDC mdc;
1944 mdc.SelectObject( m_buffer );
8636c073
RR
1945 dc.Blit( rect->x,
1946 rect->y,
1947 rect->width,
1948 rect->height,
1949 &mdc,
1950 rect->x - m_bufferX,
1951 rect->y - m_bufferY );
84fba40b 1952 mdc.SelectObject( wxNullBitmap );
5143c96b 1953
6a2c1874
RR
1954 delete rect;
1955 m_updateRects.DeleteNode( node );
1956 node = m_updateRects.First();
1957 }
dc16900b 1958
3b111dbe
RR
1959 m_needUpdate = FALSE;
1960}
1961
1962void wxCanvas::UpdateNow()
1963{
61b64bd9
RR
1964 if (m_frozen) return;
1965
3b111dbe 1966 if (!m_needUpdate) return;
dc16900b 1967
3b111dbe
RR
1968 wxClientDC dc( this );
1969 PrepareDC( dc );
dc16900b 1970
3b111dbe 1971 BlitBuffer( dc );
6a2c1874
RR
1972}
1973
8636c073
RR
1974void wxCanvas::OnSize(wxSizeEvent &event)
1975{
1976 int w,h;
1977 GetClientSize( &w, &h );
1978 m_buffer = wxBitmap( w, h );
1979
1980 CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
1981
1982 wxNode *node = m_updateRects.First();
1983 while (node)
1984 {
1985 wxRect *rect = (wxRect*) node->Data();
1986 delete rect;
1987 m_updateRects.DeleteNode( node );
1988 node = m_updateRects.First();
1989 }
1990
1991 m_frozen = FALSE;
1992
1993 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
1994
1995 event.Skip();
1996}
1997
6a2c1874
RR
1998void wxCanvas::OnPaint(wxPaintEvent &event)
1999{
6a2c1874 2000 wxPaintDC dc(this);
3b111dbe 2001 PrepareDC( dc );
dc16900b 2002
41328253 2003 if (!m_buffer.Ok()) return;
fcbb6b37 2004
b85cfb6f 2005 if (m_frozen) return;
41328253 2006
6a2c1874
RR
2007 m_needUpdate = TRUE;
2008
2009 wxRegionIterator it( GetUpdateRegion() );
2010 while (it)
2011 {
2012 int x = it.GetX();
2013 int y = it.GetY();
dc16900b 2014
6a2c1874
RR
2015 int w = it.GetWidth();
2016 int h = it.GetHeight();
dc16900b 2017
21544859
RR
2018 if (x+w > m_buffer.GetWidth())
2019 w = m_buffer.GetWidth() - x;
2020 if (y+h > m_buffer.GetHeight())
2021 h = m_buffer.GetHeight() - y;
dc16900b 2022
21544859 2023 if ((w > 0) && (h > 0))
41328253 2024 {
8636c073
RR
2025 x += m_bufferX;
2026 y += m_bufferY;
21544859 2027 m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
41328253 2028 }
dc16900b 2029
6a2c1874
RR
2030 it++;
2031 }
dc16900b 2032
3b111dbe 2033 BlitBuffer( dc );
6a2c1874
RR
2034}
2035
41328253
RR
2036void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
2037{
61b64bd9 2038 // If any updates are pending, do them now since they will
27d1065d 2039 // expect the previous m_bufferX and m_bufferY as well as
84fba40b 2040 // the previous device origin values.
27d1065d
RR
2041 wxClientDC dc( this );
2042 dc.SetDeviceOrigin( m_oldDeviceX, m_oldDeviceY );
2043 BlitBuffer( dc );
41328253 2044
8636c073
RR
2045 // The buffer always starts at the top left corner of the
2046 // client area. Indeed, it is the client area.
2047 CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
2048
2049 // Update everything.
2050 Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
2051
2052 // Scroll, actually.
2053 wxWindow::ScrollWindow( dx, dy, rect );
2054}
2055
2056void wxCanvas::OnMouse(wxMouseEvent &event)
2057{
2058 m_admin->SetActive(this);
2059 if (!m_root)
84fba40b 2060 {
8636c073
RR
2061 event.Skip();
2062 return;
84fba40b
RR
2063 }
2064
8636c073
RR
2065 int x = event.GetX();
2066 int y = event.GetY();
41328253 2067
8636c073
RR
2068 //to world coordinates to do hit test in world coordinates
2069 double xw = DeviceToLogicalX( x );
2070 double yw = DeviceToLogicalY( y );
fcbb6b37 2071
8636c073
RR
2072 //make a select margin of 2 pixels, so also zero line thickness will be hit
2073 double margin = DeviceToLogicalXRel( 2 );
fcbb6b37 2074
8636c073 2075 if (event.GetEventType() == wxEVT_MOTION)
41328253 2076 {
8636c073 2077 if (m_captureMouse) //no matter what go to this one
61b64bd9 2078 {
8636c073
RR
2079 wxMouseEvent child_event( wxEVT_MOTION );
2080 child_event.SetEventObject(m_captureMouse);
2081 child_event.m_x = x;
2082 child_event.m_y = y;
2083 child_event.m_leftDown = event.m_leftDown;
2084 child_event.m_rightDown = event.m_rightDown;
2085 child_event.m_middleDown = event.m_middleDown;
2086 child_event.m_controlDown = event.m_controlDown;
2087 child_event.m_shiftDown = event.m_shiftDown;
2088 child_event.m_altDown = event.m_altDown;
2089 child_event.m_metaDown = event.m_metaDown;
fcbb6b37 2090
8636c073
RR
2091 m_captureMouse->ProcessCanvasObjectEvent( child_event );
2092 return;
61b64bd9
RR
2093 }
2094 else
2095 {
8636c073 2096 wxCanvasObject *obj = m_root->IsHitWorld(xw,yw,margin);
fcbb6b37 2097
8636c073
RR
2098 if (obj && !obj->IsControl())
2099 {
2100 wxMouseEvent child_event( wxEVT_MOTION );
2101 child_event.SetEventObject( obj );
2102 child_event.m_x = x;
2103 child_event.m_y = y;
2104 child_event.m_leftDown = event.m_leftDown;
2105 child_event.m_rightDown = event.m_rightDown;
2106 child_event.m_middleDown = event.m_middleDown;
2107 child_event.m_controlDown = event.m_controlDown;
2108 child_event.m_shiftDown = event.m_shiftDown;
2109 child_event.m_altDown = event.m_altDown;
2110 child_event.m_metaDown = event.m_metaDown;
41328253 2111
8636c073
RR
2112 if ((obj != m_lastMouse) && (m_lastMouse != NULL))
2113 {
2114 child_event.SetEventType( wxEVT_LEAVE_WINDOW );
2115 child_event.SetEventObject( m_lastMouse );
2116 child_event.m_x = x;
2117 child_event.m_y = y;
2118 m_lastMouse->ProcessCanvasObjectEvent( child_event );
fcbb6b37
KH
2119
2120 m_lastMouse = obj;
2121 child_event.SetEventType( wxEVT_ENTER_WINDOW );
2122 child_event.SetEventObject( m_lastMouse );
84fba40b
RR
2123 child_event.m_x = x;
2124 child_event.m_y = y;
2125 m_lastMouse->ProcessCanvasObjectEvent( child_event );
fcbb6b37
KH
2126
2127 child_event.SetEventType( wxEVT_MOTION );
2128 child_event.SetEventObject( obj );
239c1f50 2129 }
84fba40b
RR
2130
2131 obj->ProcessCanvasObjectEvent( child_event );
fcbb6b37 2132 return;
239c1f50 2133 }
239c1f50
RR
2134 }
2135 if (m_lastMouse)
2136 {
2137 wxMouseEvent child_event( wxEVT_LEAVE_WINDOW );
2138 child_event.SetEventObject( m_lastMouse );
84fba40b
RR
2139 child_event.m_x = x;
2140 child_event.m_y = y;
239c1f50
RR
2141 child_event.m_leftDown = event.m_leftDown;
2142 child_event.m_rightDown = event.m_rightDown;
2143 child_event.m_middleDown = event.m_middleDown;
2144 child_event.m_controlDown = event.m_controlDown;
2145 child_event.m_shiftDown = event.m_shiftDown;
2146 child_event.m_altDown = event.m_altDown;
2147 child_event.m_metaDown = event.m_metaDown;
84fba40b 2148 m_lastMouse->ProcessCanvasObjectEvent( child_event );
dc16900b 2149
239c1f50
RR
2150 m_lastMouse = (wxCanvasObject*) NULL;
2151 return;
2152 }
2153 }
872f1044
RR
2154 else
2155 {
2156 if (m_captureMouse) //no matter what go to this one
2157 {
2158 wxMouseEvent child_event( event.GetEventType() );
2159 child_event.SetEventObject(m_captureMouse);
84fba40b
RR
2160 child_event.m_x = x;
2161 child_event.m_y = y;
872f1044
RR
2162 child_event.m_leftDown = event.m_leftDown;
2163 child_event.m_rightDown = event.m_rightDown;
2164 child_event.m_middleDown = event.m_middleDown;
2165 child_event.m_controlDown = event.m_controlDown;
2166 child_event.m_shiftDown = event.m_shiftDown;
2167 child_event.m_altDown = event.m_altDown;
2168 child_event.m_metaDown = event.m_metaDown;
84fba40b 2169 m_captureMouse->ProcessCanvasObjectEvent( child_event );
872f1044
RR
2170 }
2171 else
2172 {
84fba40b 2173 wxCanvasObject *obj = m_root->IsHitWorld(xw,yw,margin);
872f1044
RR
2174
2175 if (obj && !obj->IsControl())
2176 {
2177 wxMouseEvent child_event( event.GetEventType() );
2178 child_event.SetEventObject( obj );
84fba40b
RR
2179 child_event.m_x = x;
2180 child_event.m_y = y;
872f1044
RR
2181 child_event.m_leftDown = event.m_leftDown;
2182 child_event.m_rightDown = event.m_rightDown;
2183 child_event.m_middleDown = event.m_middleDown;
2184 child_event.m_controlDown = event.m_controlDown;
2185 child_event.m_shiftDown = event.m_shiftDown;
2186 child_event.m_altDown = event.m_altDown;
2187 child_event.m_metaDown = event.m_metaDown;
84fba40b
RR
2188
2189 obj->ProcessCanvasObjectEvent( child_event );
872f1044
RR
2190 return;
2191 }
2192 }
2193 }
fcbb6b37 2194
239c1f50 2195 event.Skip();
6a2c1874
RR
2196}
2197
8636c073
RR
2198void wxCanvas::OnIdle(wxIdleEvent &event)
2199{
2200 m_admin->SetActive(this);
2201 UpdateNow();
2202 event.Skip();
2203}
2204
2205void wxCanvas::OnSetFocus(wxFocusEvent &event)
2206{
2207 m_admin->SetActive(this);
2208}
2209
2210void wxCanvas::OnKillFocus(wxFocusEvent &event)
2211{
2212}
2213
2214
2215void wxCanvas::OnEraseBackground(wxEraseEvent &event)
2216{
2217}
2218
2219// coordinates conversions
2220// -----------------------
2221double wxCanvas::DeviceToLogicalX(int x) const
2222{
2223 return (double)(x);
2224}
2225
2226double wxCanvas::DeviceToLogicalY(int y) const
2227{
2228 return (double)(y);
2229}
2230
2231double wxCanvas::DeviceToLogicalXRel(int x) const
2232{
2233 return (double)x;
2234}
2235
2236double wxCanvas::DeviceToLogicalYRel(int y) const
2237{
2238 return (double)y;
2239}
2240
2241int wxCanvas::LogicalToDeviceX(double x) const
2242{
2243 return (int)(x + 0.5);
2244}
2245
2246int wxCanvas::LogicalToDeviceY(double y) const
2247{
2248 return (int)(y + 0.5);
2249}
2250
2251int wxCanvas::LogicalToDeviceXRel(double x) const
2252{
2253 return (int)(x + 0.5);
2254}
2255
2256int wxCanvas::LogicalToDeviceYRel(double y) const
2257{
2258 return (int)(y + 0.5);
2259}
2260
2261//----------------------------------------------------------------------------
2262// wxVectorCanvas
2263//----------------------------------------------------------------------------
2264
2265IMPLEMENT_CLASS(wxVectorCanvas,wxCanvas)
2266
2267BEGIN_EVENT_TABLE(wxVectorCanvas,wxCanvas)
2268 EVT_SCROLLWIN( wxVectorCanvas::OnScroll )
2269 EVT_CHAR( wxVectorCanvas::OnChar )
2270 EVT_SIZE( wxVectorCanvas::OnSize )
2271END_EVENT_TABLE()
2272
2273wxVectorCanvas::wxVectorCanvas( wxCanvasAdmin* admin, wxWindow *parent, wxWindowID id,
2274 const wxPoint &position, const wxSize& size, long style ) :
2275 wxCanvas( admin, parent, id, position, size, style )
2276{
2277 m_scrolled = FALSE;
2278 m_yaxis = FALSE;
2279}
2280
2281double wxVectorCanvas::GetMinX() const
2282{
2283 return m_virt_minX;
2284}
2285
2286double wxVectorCanvas::GetMinY() const
2287{
2288 return m_virt_minY;
2289}
2290
2291double wxVectorCanvas::GetMaxX() const
2292{
2293 return m_virt_maxX;
2294}
2295
2296double wxVectorCanvas::GetMaxY() const
2297{
2298 return m_virt_maxY;
2299}
2300
2301void wxVectorCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
2302{
2303 // If any updates are pending, do them now since they will
2304 // expect the previous m_bufferX and m_bufferY as well as
2305 // the previous device origin values.
2306 wxClientDC dc( this );
2307 dc.SetDeviceOrigin( m_oldDeviceX, m_oldDeviceY );
2308 BlitBuffer( dc );
2309
2310 if (dy != 0)
2311 {
2312 double dyv=DeviceToLogicalYRel(dy);
2313 m_virt_minY=m_virt_minY-dyv;
2314 m_virt_maxY=m_virt_maxY-dyv;
2315 }
2316 if (dx != 0)
2317 {
2318 double dxv=DeviceToLogicalXRel(dx);
2319 m_virt_minX=m_virt_minX-dxv;
2320 m_virt_maxX=m_virt_maxX-dxv;
2321 }
2322
2323 m_admin->SetActive(this);
2324 SetMappingScroll(m_virt_minX,m_virt_minY,m_virt_maxX,m_virt_maxY,FALSE);
2325
2326
2327 if (dy != 0)
2328 {
2329 if (dy > 0 && dy < m_buffer.GetHeight())
2330 {
2331 wxRect rect( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight()-dy);
2332 wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2333 wxMemoryDC dcm;
2334 dcm.SelectObject( m_buffer );
2335 dcm.DrawBitmap( sub_bitmap, 0, dy, TRUE );
2336 dcm.SelectObject( wxNullBitmap );
2337
2338 Update( 0, 0, m_buffer.GetWidth(), dy, TRUE );
2339 }
2340 else if (dy < 0 && dy > -m_buffer.GetHeight())
2341 {
2342 wxRect rect( 0, -dy, m_buffer.GetWidth(), m_buffer.GetHeight()+dy);
2343 wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2344 wxMemoryDC dcm;
2345 dcm.SelectObject( m_buffer );
2346 dcm.DrawBitmap( sub_bitmap, 0, 0, TRUE );
2347 dcm.SelectObject( wxNullBitmap );
2348
2349 Update( 0, m_buffer.GetHeight()+dy, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
2350 }
2351 else
2352 Update( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
2353 }
2354
2355 if (dx != 0)
2356 {
2357 if (dx > 0 && dx < m_buffer.GetWidth())
2358 {
2359 wxRect rect( 0, 0, m_buffer.GetWidth()-dx, m_buffer.GetHeight());
2360 wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2361 wxMemoryDC dcm;
2362 dcm.SelectObject( m_buffer );
2363 dcm.DrawBitmap( sub_bitmap, dx, 0, TRUE );
2364 dcm.SelectObject( wxNullBitmap );
2365
2366 Update( 0, 0, dx, m_buffer.GetHeight(), TRUE );
2367 }
2368 else if (dx < 0 && dx > -m_buffer.GetWidth())
2369 {
2370 wxRect rect( -dx, 0, m_buffer.GetWidth()+dx, m_buffer.GetHeight());
2371 wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
2372 wxMemoryDC dcm;
2373 dcm.SelectObject( m_buffer );
2374 dcm.DrawBitmap( sub_bitmap, 0, 0, TRUE );
2375 dcm.SelectObject( wxNullBitmap );
2376
2377 Update( m_buffer.GetWidth()+dx, 0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
2378 }
2379 else
2380 Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight(), TRUE );
2381 }
2382
2383 wxWindow::ScrollWindow( dx, dy, rect );
2384
2385 //must be done now because quick repeated scrolling will prevent wxPaint
2386 //from doing it properly
2387 UpdateNow();
2388}
2389
2390void wxVectorCanvas::OnSize(wxSizeEvent &event)
6a2c1874 2391{
b85cfb6f 2392 int w,h;
84fba40b 2393
b85cfb6f 2394 GetClientSize( &w, &h );
84fba40b 2395
84fba40b 2396 wxMemoryDC dc;
33ebcd80 2397 m_buffer = wxBitmap( w, h );
84fba40b
RR
2398 dc.SelectObject( m_buffer );
2399 dc.SetPen( *wxTRANSPARENT_PEN );
2400 wxBrush brush( m_background , wxSOLID );
2401 dc.SetBrush( brush );
2402 dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() );
2403 dc.SelectObject( wxNullBitmap );
fcbb6b37 2404
b85cfb6f
RR
2405 wxNode *node = m_updateRects.First();
2406 while (node)
2407 {
2408 wxRect *rect = (wxRect*) node->Data();
2409 delete rect;
2410 m_updateRects.DeleteNode( node );
2411 node = m_updateRects.First();
2412 }
2413
2414 m_frozen = FALSE;
2415
84fba40b
RR
2416 m_admin->SetActive(this);
2417 SetMappingScroll(m_virt_minX,m_virt_minY,m_virt_maxX,m_virt_maxY,FALSE);
2418
2419 Update( 0,0, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE );
41328253 2420
8636c073 2421// event.Skip();
6a2c1874
RR
2422}
2423
84fba40b
RR
2424// maps the virtual window (Real drawing to the window coordinates
2425// also used for zooming
8636c073 2426void wxVectorCanvas::SetMappingScroll( double vx1, double vy1, double vx2, double vy2, bool border)
84fba40b
RR
2427{
2428 int dwxi,dwyi;
2429 GetClientSize(&dwxi,&dwyi);
2430
2431 if (vx2==vx1) vx2=vx1+100000;
2432 if (vy2==vy1) vy2=vy1+100000;
2433 m_virt_minX=vx1;
2434 m_virt_minY=vy1;
2435 m_virt_maxX=vx2;
2436 m_virt_maxY=vy2;
2437
2438 double dwx=dwxi;
2439 double dwy=dwyi;
2440 if (dwx==0) dwx=1;
2441 if (dwy==0) dwy=1;
2442
2443 double dvx = m_virt_maxX - m_virt_minX;
2444 double dvy = m_virt_maxY - m_virt_minY;
2445
2446 // calculate the scaling factor for the virtual window
2447 double temp_x=0;
2448 double temp_y=0;
2449 if ((dvy / dvx) < (dwy / dwx))
2450 {
2451 dvy = dvx * (dwy / dwx);
2452 // calculate the change in the coordinates
2453 temp_y = (dvy - (m_virt_maxY - m_virt_minY) )/ 2.0;
2454 }
2455 else
2456 {
2457 dvx = dvy * (dwx / dwy);
2458 // calculate the change in the coordinates
2459 temp_x = (dvx - (m_virt_maxX - m_virt_minX) )/ 2.0;
2460 }
2461
2462 // add or substract the change from the original coordinates
2463 m_virt_minX=m_virt_minX-temp_x;
2464 m_virt_minY=m_virt_minY-temp_y;
2465
2466 m_virt_maxX=m_virt_maxX+temp_x;
2467 m_virt_maxY=m_virt_maxY+temp_y;
2468
2469 // initialize the mapping_matrix used for mapping the
2470 // virtual windows to the drawing window
2471
2472 // make mappingmatrix
2473 m_mapping_matrix.Identity();
2474 if (!border)
f03b31e8 2475 {
84fba40b
RR
2476 // translate the drawing to 0,0
2477 if (m_yaxis)
2478 m_mapping_matrix.Translate(-m_virt_minX,-m_virt_maxY);
2479 else
2480 m_mapping_matrix.Translate(-m_virt_minX,-m_virt_minY);
f03b31e8 2481 }
84fba40b
RR
2482 else
2483 {
2484 // make a small white border around the drawing
2485 m_virt_minX=m_virt_minX- 0.05 * dvx;
2486 m_virt_minY=m_virt_minY- 0.05 * dvy;
2487
2488 m_virt_maxX=m_virt_maxX+ 0.05 * dvx;
2489 m_virt_maxY=m_virt_maxY+ 0.05 * dvy;
2490
2491 // translate the drawing to 0,0
2492 if (m_yaxis)
2493 m_mapping_matrix.Translate(-m_virt_minX,-m_virt_maxY);
2494 else
2495 m_mapping_matrix.Translate(-m_virt_minX,-m_virt_minY);
2496 }
2497
2498 double scalefactor_x = dwx;
2499 scalefactor_x /= (m_virt_maxX - m_virt_minX);
2500
2501 double scalefactor_y = dwy;
2502 scalefactor_y /= (m_virt_maxY - m_virt_minY);
2503
2504 // scale the drawing so it fit's in the window
2505 m_mapping_matrix.Scale(scalefactor_x, scalefactor_y, 0, 0);
2506
2507 // because of coordinate change mirror over X
2508 // 0,0 in graphic computerscreens: upperleft corner
2509 // 0,0 in cartesian: lowerleft corner
2510 if (m_yaxis)
2511 {
2512 m_mapping_matrix.Mirror();
2513 }
2514 // make inverse of mapping matrix
2515 // this is to set coordinates in the statusbar
2516 // and the calculate screencoordinates to world coordinates used
2517 // in zooming
2518 m_inverse_mapping=m_mapping_matrix;
2519 m_inverse_mapping.Invert();
2520
2521 if (m_scrolled)
2522 SetScroll(m_virtm_minX,m_virtm_minY,m_virtm_maxX,m_virtm_maxY);
2523
2524 int dx2,dy2;
2525 GetClientSize(&dx2,&dy2);
2526 if ( dwxi != dx2 || dwyi != dy2) //scrollbar is/became empty
2527 SetScroll(m_virtm_minX,m_virtm_minY,m_virtm_maxX,m_virtm_maxY);
2528}
2529
2530
8636c073 2531void wxVectorCanvas::SetScroll(double vx1,double vy1,double vx2,double vy2)
84fba40b
RR
2532{
2533 m_virtm_minX=vx1;
2534 m_virtm_minY=vy1;
2535 m_virtm_maxX=vx2;
2536 m_virtm_maxY=vy2;
2537
2538 double dvx = m_virt_maxX - m_virt_minX;
2539 double dvy = m_virt_maxY - m_virt_minY;
2540 double dmvx = m_virtm_maxX - m_virtm_minX;
2541 double dmvy = m_virtm_maxY - m_virtm_minY;
2542
f03b31e8 2543 SetScrollbar(wxHORIZONTAL,(m_virt_minX-m_virtm_minX)/dmvx *1000,dvx/dmvx *1000,1000,FALSE);
84fba40b
RR
2544 if (m_yaxis)
2545 {
f03b31e8 2546 SetScrollbar(wxVERTICAL,(m_virtm_maxY-m_virt_maxY)/dmvy *1000,dvy/dmvy *1000,1000,FALSE);
84fba40b
RR
2547 }
2548 else
2549 {
f03b31e8 2550 SetScrollbar(wxVERTICAL,(m_virt_minY-m_virtm_minY)/dmvy *1000,dvy/dmvy *1000,1000,FALSE);
84fba40b
RR
2551 }
2552
f03b31e8 2553 m_scrolled=TRUE;
84fba40b
RR
2554}
2555
2556// coordinates conversions
2557// -----------------------
8636c073 2558double wxVectorCanvas::DeviceToLogicalX(int x) const
61b64bd9 2559{
84fba40b 2560 return m_inverse_mapping.GetValue(0,0) * x + m_inverse_mapping.GetValue(2,0);
61b64bd9
RR
2561}
2562
8636c073 2563double wxVectorCanvas::DeviceToLogicalY(int y) const
84fba40b
RR
2564{
2565 return m_inverse_mapping.GetValue(1,1) * y + m_inverse_mapping.GetValue(2,1);
2566}
2567
8636c073 2568double wxVectorCanvas::DeviceToLogicalXRel(int x) const
84fba40b
RR
2569{
2570 return x*m_inverse_mapping.GetValue(0,0);
2571}
2572
8636c073 2573double wxVectorCanvas::DeviceToLogicalYRel(int y) const
84fba40b
RR
2574{
2575 return y*m_inverse_mapping.GetValue(1,1);
2576}
2577
8636c073 2578int wxVectorCanvas::LogicalToDeviceX(double x) const
84fba40b
RR
2579{
2580 return (int) (m_mapping_matrix.GetValue(0,0) * x + m_mapping_matrix.GetValue(2,0) + 0.5);
2581}
2582
8636c073 2583int wxVectorCanvas::LogicalToDeviceY(double y) const
84fba40b
RR
2584{
2585 return (int) (m_mapping_matrix.GetValue(1,1) * y + m_mapping_matrix.GetValue(2,1) + 0.5);
2586}
2587
8636c073 2588int wxVectorCanvas::LogicalToDeviceXRel(double x) const
84fba40b
RR
2589{
2590 return (int) (x*m_mapping_matrix.GetValue(0,0) + 0.5);
2591}
2592
8636c073 2593int wxVectorCanvas::LogicalToDeviceYRel(double y) const
84fba40b
RR
2594{
2595 return (int) (y*m_mapping_matrix.GetValue(1,1) + 0.5);
2596}
2597
2598
84fba40b 2599// return the inverse mapping matrix for zooming or coordinates
8636c073 2600wxTransformMatrix wxVectorCanvas::GetInverseMappingMatrix()
84fba40b
RR
2601{
2602 return m_inverse_mapping;
2603}
2604
8636c073 2605wxTransformMatrix wxVectorCanvas::GetMappingMatrix()
84fba40b
RR
2606{
2607 return m_mapping_matrix;
2608}
2609
2610
2611// ----------------------------------------------------------------------------
2612// scrolling behaviour
2613// ----------------------------------------------------------------------------
2614
8636c073 2615void wxVectorCanvas::OnScroll(wxScrollWinEvent& event)
84fba40b
RR
2616{
2617 if (event.GetEventType()==wxEVT_SCROLLWIN_THUMBRELEASE)
2618 {
2619 if (event.GetOrientation()==wxHORIZONTAL)
2620 {
2621 double x=m_virtm_minX+event.GetPosition()/1000.0*(m_virtm_maxX-m_virtm_minX);
2622 x=LogicalToDeviceXRel(x-m_virt_minX);
2623 ScrollWindow(-x, 0, (const wxRect *) NULL);
2624 }
2625 else
2626 {
2627 double y=m_virtm_minY+event.GetPosition()/1000.0*(m_virtm_maxY-m_virtm_minY);
2628 y=LogicalToDeviceYRel(y-m_virt_minY);
2629 ScrollWindow(0, -y, (const wxRect *) NULL);
2630 }
2631 }
2632 else if (event.GetEventType()==wxEVT_SCROLLWIN_PAGEUP)
2633 {
2634 if (event.GetOrientation()==wxHORIZONTAL)
2635 {
2636 double x=GetBufferWidth();
2637 ScrollWindow(x, 0, (const wxRect *) NULL);
2638 }
2639 else
2640 {
2641 double y=GetBufferHeight();
2642 ScrollWindow(0, y, (const wxRect *) NULL);
2643 }
2644 }
2645 else if (event.GetEventType()==wxEVT_SCROLLWIN_PAGEDOWN)
2646 {
2647 if (event.GetOrientation()==wxHORIZONTAL)
2648 {
2649 double x=-GetBufferWidth();
2650 ScrollWindow(x, 0, (const wxRect *) NULL);
2651 }
2652 else
2653 {
2654 double y=-GetBufferHeight();
2655 ScrollWindow(0, y, (const wxRect *) NULL);
2656 }
2657 }
2658 else if (event.GetEventType()==wxEVT_SCROLLWIN_LINEUP)
2659 {
2660 if (event.GetOrientation()==wxHORIZONTAL)
2661 {
2662 int x=GetBufferWidth()/10;
2663 ScrollWindow(x, 0, (const wxRect *) NULL);
2664 }
2665 else
2666 {
2667 int y=GetBufferHeight()/10;
2668 ScrollWindow(0, y, (const wxRect *) NULL);
2669 }
2670 }
2671 else if (event.GetEventType()==wxEVT_SCROLLWIN_LINEDOWN)
2672 {
2673 if (event.GetOrientation()==wxHORIZONTAL)
2674 {
2675 int x=-GetBufferWidth()/10;
2676 ScrollWindow(x, 0, (const wxRect *) NULL);
2677 }
2678 else
2679 {
2680 int y=-GetBufferHeight()/10;
2681 ScrollWindow(0, y, (const wxRect *) NULL);
2682 }
2683 }
2684
2685}
2686
8636c073 2687void wxVectorCanvas::OnChar(wxKeyEvent& event)
84fba40b
RR
2688{
2689 switch ( event.KeyCode() )
2690 {
2691 case WXK_PAGEUP:
2692 case WXK_PRIOR:
2693 {
2694 double y=GetBufferHeight();
2695 ScrollWindow(0, y, (const wxRect *) NULL);
2696 }
2697 break;
2698 case WXK_PAGEDOWN:
2699 case WXK_NEXT:
2700 {
2701 double y=-GetBufferHeight();
2702 ScrollWindow(0, y, (const wxRect *) NULL);
2703 }
2704 break;
2705 case WXK_HOME:
2706 {
2707 double y=m_virtm_minY;
2708 y=LogicalToDeviceYRel(y-m_virt_minY);
2709 ScrollWindow(0, -y, (const wxRect *) NULL);
2710 }
2711 break;
2712 case WXK_END:
2713 {
2714 double y=m_virtm_minY+(m_virtm_maxY-m_virtm_minY);
2715 y=LogicalToDeviceYRel(y-m_virt_minY);
2716 ScrollWindow(0, -y, (const wxRect *) NULL);
2717 }
2718 break;
2719 case WXK_UP:
2720 {
2721 int y;
2722 if (!event.ControlDown())
2723 y=GetBufferHeight()/10;
2724 else
2725 y=GetBufferHeight();
2726 ScrollWindow(0, y, (const wxRect *) NULL);
2727 }
2728 break;
2729
2730 case WXK_DOWN:
2731 {
2732 int y;
2733 if (!event.ControlDown())
2734 y=-GetBufferHeight()/10;
2735 else
2736 y=-GetBufferHeight();
2737 ScrollWindow(0, y, (const wxRect *) NULL);
2738 }
2739 break;
2740
2741 case WXK_LEFT:
2742 {
2743 int x;
2744 if (!event.ControlDown())
2745 x=GetBufferWidth()/10;
2746 else
2747 x=GetBufferWidth();
2748 ScrollWindow(x, 0, (const wxRect *) NULL);
2749 }
2750 break;
2751 case WXK_RIGHT:
2752 {
2753 int x;
2754 if (!event.ControlDown())
2755 x=-GetBufferWidth()/10;
2756 else
2757 x=-GetBufferWidth();
2758 ScrollWindow(x, 0, (const wxRect *) NULL);
2759 }
2760 break;
2761 default:
2762 // not for us
2763 event.Skip();
2764 }
2765}
2766
2767
8636c073
RR
2768//----------------------------------------------------------------------------
2769// wxCanvasAdmin
2770//----------------------------------------------------------------------------
84fba40b
RR
2771
2772wxCanvasAdmin::wxCanvasAdmin()
2773{
2774
2775}
2776
2777wxCanvasAdmin::~wxCanvasAdmin()
2778{
84fba40b
RR
2779}
2780
2781
2782void wxCanvasAdmin::Append( wxCanvas* canvas )
2783{
2784 m_canvaslist.Append( canvas );
2785}
2786
2787void wxCanvasAdmin::Remove( wxCanvas* canvas )
2788{
2789 m_canvaslist.DeleteObject( canvas );
2790}
2791
2792void wxCanvasAdmin::Update(wxCanvasObject* obj, double x, double y, double width, double height)
2793{
2794 wxNode *node = m_canvaslist.First();
2795 while (node)
2796 {
2797
2798 wxCanvas *canvas = (wxCanvas*) node->Data();
2799
2800 if (m_active == canvas)
2801 {
2802 int xi = canvas->LogicalToDeviceX( x);
2803 int yi = canvas->LogicalToDeviceY( y);
2804 int wi = canvas->LogicalToDeviceXRel( width );
2805 int hi = canvas->LogicalToDeviceYRel( height);
2806 //update a little more then is strictly needed,
2807 //to get rid of the 1 bit bugs
2808 if (canvas->GetYaxis())
2809 canvas->Update( xi-2, yi+hi-2, wi+4, -hi+4);
2810 else
2811 canvas->Update( xi-2, yi-2, wi+4, hi+4);
2812 }
2813 else
2814 { wxCanvasObject* topobj=canvas->GetRoot()->Contains(obj);
2815 if (topobj)
2816 {
2817 wxCanvas* tcanvas = m_active;
2818 SetActive(canvas);
2819
2820 /*
2821 //KKK TODO somehow the next does not work for update i do not know why
2822 canvas->GetRoot()->CalcBoundingBox();
2823 int xi = topobj->GetX();
2824 int yi = topobj->GetY();
2825 int wi = topobj->GetWidth();
2826 int hi = topobj->GetHeight();
2827 */
2828 canvas->Update( 0,0, canvas->GetBufferWidth(),canvas->GetBufferHeight());
2829 SetActive(tcanvas);
2830 }
2831 }
2832
2833 node = node->Next();
2834 }
2835}
2836
2837void wxCanvasAdmin::UpdateNow()
2838{
2839 wxNode *node = m_canvaslist.First();
2840 while (node)
2841 {
2842 wxCanvas *canvas = (wxCanvas*) node->Data();
2843
2844 canvas->UpdateNow();
2845 node = node->Next();
2846 }
2847}
2848
2849// coordinates conversions
2850// -----------------------
2851double wxCanvasAdmin::DeviceToLogicalX(int x) const
2852{
2853 return m_active->DeviceToLogicalX(x);
2854}
2855
2856double wxCanvasAdmin::DeviceToLogicalY(int y) const
2857{
2858 return m_active->DeviceToLogicalY(y);
2859}
2860
2861double wxCanvasAdmin::DeviceToLogicalXRel(int x) const
2862{
2863 return m_active->DeviceToLogicalXRel(x);
2864}
2865
2866double wxCanvasAdmin::DeviceToLogicalYRel(int y) const
2867{
2868 return m_active->DeviceToLogicalYRel(y);
2869}
2870
2871int wxCanvasAdmin::LogicalToDeviceX(double x) const
2872{
2873 return m_active->LogicalToDeviceX(x);
2874}
2875
2876int wxCanvasAdmin::LogicalToDeviceY(double y) const
2877{
2878 return m_active->LogicalToDeviceY(y);
2879}
2880
2881int wxCanvasAdmin::LogicalToDeviceXRel(double x) const
2882{
2883 return m_active->LogicalToDeviceXRel(x);
2884}
2885
2886int wxCanvasAdmin::LogicalToDeviceYRel(double y) const
2887{
2888 return m_active->LogicalToDeviceYRel(y);
2889}
2890
2891void wxCanvasAdmin::SetActive(wxCanvas* activate)
2892{
2893 wxNode *node = m_canvaslist.First();
2894 while (node)
2895 {
2896 wxCanvas *canvas = (wxCanvas*) node->Data();
2897
2898 if (activate == canvas)
2899 {
2900 m_active=canvas;
2901 break;
2902 }
2903 node = node->Next();
2904 }
2905}
8636c073
RR
2906//--------------------------------------------------------------------
2907// wxCanvasModule
2908//--------------------------------------------------------------------
2909
2910class wxCanvasModule : public wxModule
2911{
2912public:
2913 virtual bool OnInit();
2914 virtual void OnExit();
2915
2916private:
2917 DECLARE_DYNAMIC_CLASS(wxCanvasModule)
2918};
2919
2920IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
2921
2922bool wxCanvasModule::OnInit()
2923{
2924#if wxUSE_FREETYPE
2925 int error = FT_Init_FreeType( &g_freetypeLibrary );
2926 if (error) return FALSE;
2927#endif
2928
2929 return TRUE;
2930}
2931
2932void wxCanvasModule::OnExit()
2933{
2934#if wxUSE_FREETYPE
2935 FT_Done_FreeType( g_freetypeLibrary );
2936#endif
2937}
2938
2939
84fba40b
RR
2940
2941