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