1 /////////////////////////////////////////////////////////////////////////////
3 // Author: Robert Roebling
5 // Copyright: 2000 (c) Robert Roebling
6 // Licence: wxWindows Licence
7 /////////////////////////////////////////////////////////////////////////////
10 #pragma implementation "canvas.cpp"
13 // For compilers that support precompilation, includes "wx/wx.h".
14 #include "wx/wxprec.h"
20 #include "wx/canvas/canvas.h"
24 #include <gdk/gdkrgb.h>
25 #include "wx/gtk/win_gtk.h"
28 #ifndef wxUSE_FREETYPE
29 #define wxUSE_FREETYPE 1
33 #include <freetype/freetype.h>
36 //----------------------------------------------------------------------------
38 //----------------------------------------------------------------------------
41 FT_Library g_freetypeLibrary
;
44 //----------------------------------------------------------------------------
46 //----------------------------------------------------------------------------
48 wxCanvasObject::wxCanvasObject( int x
, int y
, int width
, int height
)
54 m_area
.height
= height
;
60 void wxCanvasObject::Move( int x
, int y
)
70 // TODO: sometimes faster to merge into 1 Update or
71 // to break up into four
72 m_owner
->Update( old_x
, old_y
, m_area
.width
, m_area
.height
);
73 m_owner
->Update( x
, y
, m_area
.width
, m_area
.height
);
77 bool wxCanvasObject::IsHit( int x
, int y
, int margin
)
79 return ((x
>= m_area
.x
-margin
) &&
80 (x
<= m_area
.x
+m_area
.width
+margin
) &&
81 (y
>= m_area
.y
-margin
) &&
82 (y
<= m_area
.y
+m_area
.height
+margin
));
85 void wxCanvasObject::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
89 void wxCanvasObject::Rerender()
93 void wxCanvasObject::WriteSVG( wxTextOutputStream
&stream
)
97 //----------------------------------------------------------------------------
99 //----------------------------------------------------------------------------
101 wxCanvasRect::wxCanvasRect( int x
, int y
, int w
, int h
, unsigned char red
, unsigned char green
, unsigned char blue
)
102 : wxCanvasObject( x
, y
, w
, h
)
109 void wxCanvasRect::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
111 wxImage
*image
= m_owner
->GetBuffer();
113 for (int y
= clip_y
; y
< clip_y
+clip_height
; y
++)
114 for (int x
= clip_x
; x
< clip_x
+clip_width
; x
++)
115 image
->SetRGB( x
, y
, m_red
, m_green
, m_blue
);
118 void wxCanvasRect::WriteSVG( wxTextOutputStream
&stream
)
122 //----------------------------------------------------------------------------
124 //----------------------------------------------------------------------------
126 wxCanvasLine::wxCanvasLine( int x
, int y
, int w
, int h
, unsigned char red
, unsigned char green
, unsigned char blue
)
127 : wxCanvasObject( x
, y
, w
, h
)
134 void wxCanvasLine::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
136 wxImage
*image
= m_owner
->GetBuffer();
138 if ((m_area
.width
== 0) && (m_area
.height
== 0))
140 image
->SetRGB( m_area
.x
, m_area
.y
, m_red
, m_green
, m_blue
);
146 int x2
= m_area
.x
+m_area
.width
;
147 int y2
= m_area
.y
+m_area
.height
;
149 wxInt32 d
, ii
, jj
, di
, ai
, si
, dj
, aj
, sj
;
152 si
= (di
< 0)? -1 : 1;
155 sj
= (dj
< 0)? -1 : 1;
167 if ((ii
>= clip_x
) && (ii
<= clip_x
+clip_width
) &&
168 (jj
>= clip_y
) && (jj
<= clip_y
+clip_height
))
170 image
->SetRGB( ii
, jj
, m_red
, m_blue
, m_green
);
188 if ((ii
>= clip_x
) && (ii
<= clip_x
+clip_width
) &&
189 (jj
>= clip_y
) && (jj
<= clip_y
+clip_height
))
191 image
->SetRGB( ii
, jj
, m_red
, m_blue
, m_green
);
205 void wxCanvasLine::WriteSVG( wxTextOutputStream
&stream
)
210 //----------------------------------------------------------------------------
212 //----------------------------------------------------------------------------
214 wxCanvasImage::wxCanvasImage( const wxImage
&image
, int x
, int y
)
215 : wxCanvasObject( x
, y
, image
.GetWidth(), image
.GetHeight() )
221 void wxCanvasImage::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
223 if ((clip_x
== m_area
.x
) &&
224 (clip_y
== m_area
.y
) &&
225 (clip_width
== m_area
.width
) &&
226 (clip_height
== m_area
.height
))
228 m_owner
->GetBuffer()->Paste( m_image
, clip_x
, clip_y
);
233 int start_x
= clip_x
- m_area
.x
;
234 int start_y
= clip_y
- m_area
.y
;
236 wxRect
rect( start_x
, start_y
, clip_width
, clip_height
);
237 wxImage
sub_image( m_image
.GetSubImage( rect
) );
238 m_owner
->GetBuffer()->Paste( sub_image
, clip_x
, clip_y
);
242 void wxCanvasImage::WriteSVG( wxTextOutputStream
&stream
)
247 //----------------------------------------------------------------------------
249 //----------------------------------------------------------------------------
251 wxCanvasControl::wxCanvasControl( wxWindow
*control
)
252 : wxCanvasObject( -1, -1, -1, -1 )
259 wxCanvasControl::~wxCanvasControl()
261 m_control
->Destroy();
264 void wxCanvasControl::Move( int x
, int y
)
266 m_control
->Move( x
, y
);
269 void wxCanvasControl::UpdateSize()
271 m_control
->GetSize( &m_area
.width
, &m_area
.height
);
272 m_control
->GetPosition( &m_area
.x
, &m_area
.y
);
275 //----------------------------------------------------------------------------
277 //----------------------------------------------------------------------------
289 wxCanvasText::wxCanvasText( const wxString
&text
, int x
, int y
, const wxString
&fontFile
, int size
)
290 : wxCanvasObject( x
, y
, -1, -1 )
293 m_fontFileName
= fontFile
;
302 m_area
.height
= m_size
;
303 m_alpha
= new unsigned char[100*m_size
];
304 memset( m_alpha
, 0, m_area
.width
*m_area
.height
);
307 wxFaceData
*data
= new wxFaceData
;
310 int error
= FT_New_Face( g_freetypeLibrary
,
315 error
= FT_Set_Char_Size( data
->m_face
,
324 wxCanvasText::~wxCanvasText()
327 wxFaceData
*data
= (wxFaceData
*) m_faceData
;
331 if (m_alpha
) delete [] m_alpha
;
334 void wxCanvasText::SetRGB( unsigned char red
, unsigned char green
, unsigned char blue
)
341 void wxCanvasText::SetFlag( int flag
)
346 void wxCanvasText::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
348 if (!m_alpha
) return;
350 wxImage
*image
= m_owner
->GetBuffer();
353 int start_x
= clip_x
- m_area
.x
;
354 int end_x
= clip_width
+ start_x
;
355 int start_y
= clip_y
- m_area
.y
;
356 int end_y
= clip_height
+ start_y
;
358 for (int y
= start_y
; y
< end_y
; y
++)
359 for (int x
= start_x
; x
< end_x
; x
++)
361 int alpha
= m_alpha
[y
*m_area
.width
+ x
];
364 int image_x
= m_area
.x
+x
;
365 int image_y
= m_area
.y
+y
;
368 image
->SetRGB( image_x
, image_y
, m_red
, m_green
, m_blue
);
371 int red1
= (m_red
* alpha
) / 255;
372 int green1
= (m_green
* alpha
) / 255;
373 int blue1
= (m_blue
* alpha
) / 255;
376 int red2
= image
->GetRed( image_x
, image_y
);
377 int green2
= image
->GetGreen( image_x
, image_y
);
378 int blue2
= image
->GetBlue( image_x
, image_y
);
379 red2
= (red2
* alpha
) / 255;
380 green2
= (green2
* alpha
) / 255;
381 blue2
= (blue2
* alpha
) / 255;
383 image
->SetRGB( image_x
, image_y
, red1
+red2
, green1
+green2
, blue1
+blue2
);
388 void wxCanvasText::WriteSVG( wxTextOutputStream
&stream
)
392 void wxCanvasText::CreateBuffer()
395 FT_Face face
= ((wxFaceData
*)m_faceData
)->m_face
;
396 FT_GlyphSlot slot
= face
->glyph
;
400 for (int n
= 0; n
< (int)m_text
.Len(); n
++)
402 FT_UInt index
= FT_Get_Char_Index( face
, m_text
[n
] );
404 int error
= FT_Load_Glyph( face
, index
, FT_LOAD_DEFAULT
);
407 error
= FT_Render_Glyph( face
->glyph
, ft_render_mode_normal
);
410 FT_Bitmap
*bitmap
= &slot
->bitmap
;
411 unsigned char* buffer
= bitmap
->buffer
;
412 for (int y
= 0; y
< bitmap
->rows
; y
++)
413 for (int x
= 0; x
< bitmap
->width
; x
++)
415 unsigned char alpha
= buffer
[ y
*bitmap
->pitch
+ x
];
416 if (alpha
== 0) continue;
418 int xx
= pen_x
+ slot
->bitmap_left
+ x
;
419 int yy
= pen_y
- slot
->bitmap_top
+ y
;
420 m_alpha
[ yy
* m_area
.width
+ xx
] = alpha
;
423 pen_x
+= slot
->advance
.x
>> 6;
424 pen_y
+= slot
->advance
.y
>> 6;
429 //----------------------------------------------------------------------------
431 //----------------------------------------------------------------------------
433 IMPLEMENT_CLASS(wxCanvas
,wxScrolledWindow
)
435 BEGIN_EVENT_TABLE(wxCanvas
,wxScrolledWindow
)
436 EVT_CHAR( wxCanvas::OnChar
)
437 EVT_PAINT( wxCanvas::OnPaint
)
438 EVT_SIZE( wxCanvas::OnSize
)
439 EVT_IDLE( wxCanvas::OnIdle
)
440 EVT_MOUSE_EVENTS( wxCanvas::OnMouse
)
441 EVT_SET_FOCUS( wxCanvas::OnSetFocus
)
442 EVT_KILL_FOCUS( wxCanvas::OnKillFocus
)
445 wxCanvas::wxCanvas( wxWindow
*parent
, wxWindowID id
,
446 const wxPoint
&position
, const wxSize
& size
, long style
) :
447 wxScrolledWindow( parent
, id
, position
, size
, style
)
449 m_needUpdate
= FALSE
;
450 m_objects
.DeleteContents( TRUE
);
454 m_lastMouse
= (wxCanvasObject
*)NULL
;
458 wxCanvas::~wxCanvas()
460 wxNode
*node
= m_updateRects
.First();
463 wxRect
*rect
= (wxRect
*) node
->Data();
465 m_updateRects
.DeleteNode( node
);
466 node
= m_updateRects
.First();
470 void wxCanvas::SetArea( int width
, int height
)
472 m_buffer
= wxImage( width
, height
);
473 SetScrollbars( 10, 10, width
/10, height
/10 );
476 void wxCanvas::SetColour( unsigned char red
, unsigned char green
, unsigned char blue
)
482 if (m_frozen
) return;
484 unsigned char *data
= m_buffer
.GetData();
486 for (int y
= 0; y
< m_buffer
.GetHeight(); y
++)
487 for (int x
= 0; x
< m_buffer
.GetWidth(); x
++)
498 void wxCanvas::Freeze()
503 void wxCanvas::Thaw()
505 wxNode
*node
= m_updateRects
.First();
508 wxRect
*rect
= (wxRect
*) node
->Data();
510 m_updateRects
.DeleteNode( node
);
511 node
= m_updateRects
.First();
516 Update( 0, 0, m_buffer
.GetWidth(), m_buffer
.GetHeight() );
519 void wxCanvas::Update( int x
, int y
, int width
, int height
)
521 if (m_frozen
) return;
529 if (width
< 0) return;
536 if (height
< 0) return;
538 if (x
+width
> m_buffer
.GetWidth())
540 width
= m_buffer
.GetWidth() - x
;
542 if (width
< 0) return;
544 if (y
+height
> m_buffer
.GetHeight())
546 height
= m_buffer
.GetHeight() - y
;
548 if (height
< 0) return;
550 // update is within the buffer
553 // has to be blitted to screen later
554 m_updateRects
.Append(
555 (wxObject
*) new wxRect( x
,y
,width
,height
) );
557 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
558 for (int yy
= y
; yy
< y
+height
; yy
++)
559 for (int xx
= x
; xx
< x
+width
; xx
++)
560 m_buffer
.SetRGB( xx
, yy
, m_red
, m_green
, m_blue
);
562 // cycle through all objects
563 wxNode
*node
= m_objects
.First();
566 wxCanvasObject
*obj
= (wxCanvasObject
*) node
->Data();
568 if (!obj
->IsControl())
570 // If we have 10.000 objects, we will go through
571 // this 10.000 times for each update, so we have
572 // to optimise carefully.
573 int clip_x
= obj
->GetX();
574 int clip_width
= obj
->GetWidth();
577 clip_width
-= x
-clip_x
;
582 if (clip_x
+ clip_width
> x
+ width
)
583 clip_width
= x
+width
-clip_x
;
587 int clip_y
= obj
->GetY();
588 int clip_height
= obj
->GetHeight();
591 clip_height
-= y
-clip_y
;
596 if (clip_y
+ clip_height
> y
+ height
)
597 clip_height
= y
+height
-clip_y
;
600 obj
->Render( clip_x
, clip_y
, clip_width
, clip_height
);
610 void wxCanvas::BlitBuffer( wxDC
&dc
)
612 wxNode
*node
= m_updateRects
.First();
615 wxRect
*rect
= (wxRect
*) node
->Data();
616 wxImage
sub_image( m_buffer
.GetSubImage( *rect
) );
618 // DirectDraw here, please
621 int bpp
= wxDisplayDepth();
624 // the init code is doubled in wxImage
625 static bool s_hasInitialized
= FALSE
;
627 if (!s_hasInitialized
)
630 s_hasInitialized
= TRUE
;
635 CalcScrolledPosition( x
, y
, &x
, &y
);
637 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow
)->bin_window
,
638 m_wxwindow
->style
->black_gc
,
640 sub_image
.GetWidth(), sub_image
.GetHeight(),
643 sub_image
.GetWidth()*3 );
647 wxBitmap
bitmap( sub_image
.ConvertToBitmap() );
648 dc
.DrawBitmap( bitmap
, rect
->x
, rect
->y
);
653 wxBitmap
bitmap( sub_image
.ConvertToBitmap() );
654 dc
.DrawBitmap( bitmap
, rect
->x
, rect
->y
);
658 m_updateRects
.DeleteNode( node
);
659 node
= m_updateRects
.First();
662 m_needUpdate
= FALSE
;
665 void wxCanvas::UpdateNow()
667 if (!m_needUpdate
) return;
669 wxClientDC
dc( this );
675 void wxCanvas::Prepend( wxCanvasObject
* obj
)
677 m_objects
.Insert( obj
);
679 obj
->SetOwner( this );
681 if (!obj
->IsControl())
682 Update( obj
->GetX(), obj
->GetY(), obj
->GetWidth(), obj
->GetHeight() );
685 void wxCanvas::Append( wxCanvasObject
* obj
)
687 m_objects
.Append( obj
);
689 obj
->SetOwner( this );
691 if (!obj
->IsControl())
692 Update( obj
->GetX(), obj
->GetY(), obj
->GetWidth(), obj
->GetHeight() );
695 void wxCanvas::Insert( size_t before
, wxCanvasObject
* obj
)
697 m_objects
.Insert( before
, obj
);
699 obj
->SetOwner( this );
701 if (!obj
->IsControl())
702 Update( obj
->GetX(), obj
->GetY(), obj
->GetWidth(), obj
->GetHeight() );
705 void wxCanvas::Remove( wxCanvasObject
* obj
)
709 int w
= obj
->GetWidth();
710 int h
= obj
->GetHeight();
711 bool ic
= obj
->IsControl();
713 m_objects
.DeleteObject( obj
);
716 Update( x
, y
, w
, h
);
719 void wxCanvas::OnPaint(wxPaintEvent
&event
)
726 wxRegionIterator
it( GetUpdateRegion() );
731 CalcUnscrolledPosition( x
, y
, &x
, &y
);
733 int w
= it
.GetWidth();
734 int h
= it
.GetHeight();
736 if (x
+w
> m_buffer
.GetWidth())
737 w
= m_buffer
.GetWidth() - x
;
738 if (y
+h
> m_buffer
.GetHeight())
739 h
= m_buffer
.GetHeight() - y
;
741 if ((w
> 0) && (h
> 0))
742 m_updateRects
.Append( (wxObject
*) new wxRect( x
, y
, w
, h
) );
750 void wxCanvas::OnMouse(wxMouseEvent
&event
)
752 // should we implement mouse capture ?
754 int x
= event
.GetX();
755 int y
= event
.GetY();
756 CalcUnscrolledPosition( x
, y
, &x
, &y
);
758 if (event
.GetEventType() == wxEVT_MOTION
)
760 wxNode
*node
= m_objects
.First();
763 wxCanvasObject
*obj
= (wxCanvasObject
*) node
->Data();
765 if (!obj
->IsControl())
769 wxMouseEvent
child_event( wxEVT_MOTION
);
770 child_event
.SetEventObject( obj
);
771 child_event
.m_x
= x
- obj
->GetX();
772 child_event
.m_y
= y
- obj
->GetY();
773 child_event
.m_leftDown
= event
.m_leftDown
;
774 child_event
.m_rightDown
= event
.m_rightDown
;
775 child_event
.m_middleDown
= event
.m_middleDown
;
776 child_event
.m_controlDown
= event
.m_controlDown
;
777 child_event
.m_shiftDown
= event
.m_shiftDown
;
778 child_event
.m_altDown
= event
.m_altDown
;
779 child_event
.m_metaDown
= event
.m_metaDown
;
781 if ((obj
!= m_lastMouse
) && (m_lastMouse
!= NULL
))
783 child_event
.SetEventType( wxEVT_LEAVE_WINDOW
);
784 child_event
.SetEventObject( m_lastMouse
);
785 child_event
.m_x
= x
- m_lastMouse
->GetX();
786 child_event
.m_y
= y
- m_lastMouse
->GetY();
787 m_lastMouse
->ProcessEvent( child_event
);
790 child_event
.SetEventType( wxEVT_ENTER_WINDOW
);
791 child_event
.SetEventObject( m_lastMouse
);
792 child_event
.m_x
= x
- m_lastMouse
->GetX();
793 child_event
.m_y
= y
- m_lastMouse
->GetY();
794 m_lastMouse
->ProcessEvent( child_event
);
796 child_event
.SetEventType( wxEVT_MOTION
);
797 child_event
.SetEventObject( obj
);
799 obj
->ProcessEvent( child_event
);
807 wxMouseEvent
child_event( wxEVT_LEAVE_WINDOW
);
808 child_event
.SetEventObject( m_lastMouse
);
809 child_event
.m_x
= x
- m_lastMouse
->GetX();
810 child_event
.m_y
= y
- m_lastMouse
->GetY();
811 child_event
.m_leftDown
= event
.m_leftDown
;
812 child_event
.m_rightDown
= event
.m_rightDown
;
813 child_event
.m_middleDown
= event
.m_middleDown
;
814 child_event
.m_controlDown
= event
.m_controlDown
;
815 child_event
.m_shiftDown
= event
.m_shiftDown
;
816 child_event
.m_altDown
= event
.m_altDown
;
817 child_event
.m_metaDown
= event
.m_metaDown
;
818 m_lastMouse
->ProcessEvent( child_event
);
820 m_lastMouse
= (wxCanvasObject
*) NULL
;
827 void wxCanvas::OnSize(wxSizeEvent
&event
)
832 void wxCanvas::OnIdle(wxIdleEvent
&event
)
838 void wxCanvas::OnSetFocus(wxFocusEvent
&event
)
842 void wxCanvas::OnKillFocus(wxFocusEvent
&event
)
846 void wxCanvas::OnChar(wxKeyEvent
&event
)
851 //--------------------------------------------------------------------
853 //--------------------------------------------------------------------
855 class wxCanvasModule
: public wxModule
858 virtual bool OnInit();
859 virtual void OnExit();
862 DECLARE_DYNAMIC_CLASS(wxCanvasModule
)
865 IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule
, wxModule
)
867 bool wxCanvasModule::OnInit()
870 int error
= FT_Init_FreeType( &g_freetypeLibrary
);
871 if (error
) return FALSE
;
877 void wxCanvasModule::OnExit()
880 FT_Done_FreeType( g_freetypeLibrary
);