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 #define USE_FREETYPE 1
31 #include <freetype/freetype.h>
34 //----------------------------------------------------------------------------
36 //----------------------------------------------------------------------------
39 FT_Library g_freetypeLibrary
;
42 //----------------------------------------------------------------------------
44 //----------------------------------------------------------------------------
46 wxCanvasObject::wxCanvasObject( int x
, int y
, int width
, int height
)
52 m_area
.height
= height
;
58 void wxCanvasObject::Move( int x
, int y
)
68 // TODO: sometimes faster to merge into 1 Update or
69 // to break up into four
70 m_owner
->Update( old_x
, old_y
, m_area
.width
, m_area
.height
);
71 m_owner
->Update( x
, y
, m_area
.width
, m_area
.height
);
75 void wxCanvasObject::WriteSVG( wxTextOutputStream
&stream
)
79 void wxCanvasObject::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
83 //----------------------------------------------------------------------------
85 //----------------------------------------------------------------------------
87 wxCanvasRect::wxCanvasRect( int x
, int y
, int w
, int h
, unsigned char red
, unsigned char green
, unsigned char blue
)
88 : wxCanvasObject( x
, y
, w
, h
)
95 void wxCanvasRect::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
97 wxImage
*image
= m_owner
->GetBuffer();
99 for (int y
= clip_y
; y
< clip_y
+clip_height
; y
++)
100 for (int x
= clip_x
; x
< clip_x
+clip_width
; x
++)
101 image
->SetRGB( x
, y
, m_red
, m_green
, m_blue
);
104 void wxCanvasRect::WriteSVG( wxTextOutputStream
&stream
)
108 //----------------------------------------------------------------------------
110 //----------------------------------------------------------------------------
112 wxCanvasImage::wxCanvasImage( const wxImage
&image
, int x
, int y
)
113 : wxCanvasObject( x
, y
, image
.GetWidth(), image
.GetHeight() )
119 void wxCanvasImage::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
121 if ((clip_x
== m_area
.x
) &&
122 (clip_y
== m_area
.y
) &&
123 (clip_width
== m_area
.width
) &&
124 (clip_height
== m_area
.height
))
126 m_owner
->GetBuffer()->Paste( m_image
, clip_x
, clip_y
);
131 int start_x
= clip_x
- m_area
.x
;
132 int start_y
= clip_y
- m_area
.y
;
134 wxRect
rect( start_x
, start_y
, clip_width
, clip_height
);
135 wxImage
sub_image( m_image
.GetSubImage( rect
) );
136 m_owner
->GetBuffer()->Paste( sub_image
, clip_x
, clip_y
);
140 void wxCanvasImage::WriteSVG( wxTextOutputStream
&stream
)
145 //----------------------------------------------------------------------------
147 //----------------------------------------------------------------------------
149 wxCanvasControl::wxCanvasControl( wxWindow
*control
)
150 : wxCanvasObject( -1, -1, -1, -1 )
157 wxCanvasControl::~wxCanvasControl()
159 m_control
->Destroy();
162 void wxCanvasControl::Move( int x
, int y
)
164 m_control
->Move( x
, y
);
167 void wxCanvasControl::UpdateSize()
169 m_control
->GetSize( &m_area
.width
, &m_area
.height
);
170 m_control
->GetPosition( &m_area
.x
, &m_area
.y
);
173 //----------------------------------------------------------------------------
175 //----------------------------------------------------------------------------
187 wxCanvasText::wxCanvasText( const wxString
&text
, int x
, int y
, const wxString
&fontFile
, int size
)
188 : wxCanvasObject( x
, y
, -1, -1 )
191 m_fontFileName
= fontFile
;
200 m_area
.height
= m_size
;
201 m_alpha
= new unsigned char[100*m_size
];
202 memset( m_alpha
, 0, m_area
.width
*m_area
.height
);
205 wxFaceData
*data
= new wxFaceData
;
208 int error
= FT_New_Face( g_freetypeLibrary
,
213 error
= FT_Set_Char_Size( data
->m_face
,
222 wxCanvasText::~wxCanvasText()
225 wxFaceData
*data
= (wxFaceData
*) m_faceData
;
229 if (m_alpha
) delete [] m_alpha
;
232 void wxCanvasText::SetRGB( unsigned char red
, unsigned char green
, unsigned char blue
)
239 void wxCanvasText::SetFlag( int flag
)
244 void wxCanvasText::Render( int clip_x
, int clip_y
, int clip_width
, int clip_height
)
246 if (!m_alpha
) return;
248 wxImage
*image
= m_owner
->GetBuffer();
251 int start_x
= clip_x
- m_area
.x
;
252 int end_x
= clip_width
+ start_x
;
253 int start_y
= clip_y
- m_area
.y
;
254 int end_y
= clip_height
+ start_y
;
256 for (int y
= start_y
; y
< end_y
; y
++)
257 for (int x
= start_x
; x
< end_x
; x
++)
259 int alpha
= m_alpha
[y
*m_area
.width
+ x
];
262 int image_x
= m_area
.x
+x
;
263 int image_y
= m_area
.y
+y
;
266 image
->SetRGB( image_x
, image_y
, m_red
, m_green
, m_blue
);
269 int red1
= (m_red
* alpha
) / 255;
270 int green1
= (m_green
* alpha
) / 255;
271 int blue1
= (m_blue
* alpha
) / 255;
274 int red2
= image
->GetRed( image_x
, image_y
);
275 int green2
= image
->GetGreen( image_x
, image_y
);
276 int blue2
= image
->GetBlue( image_x
, image_y
);
277 red2
= (red2
* alpha
) / 255;
278 green2
= (green2
* alpha
) / 255;
279 blue2
= (blue2
* alpha
) / 255;
281 image
->SetRGB( image_x
, image_y
, red1
+red2
, green1
+green2
, blue1
+blue2
);
286 void wxCanvasText::WriteSVG( wxTextOutputStream
&stream
)
290 void wxCanvasText::CreateBuffer()
293 FT_Face face
= ((wxFaceData
*)m_faceData
)->m_face
;
294 FT_GlyphSlot slot
= face
->glyph
;
298 for (int n
= 0; n
< (int)m_text
.Len(); n
++)
300 FT_UInt index
= FT_Get_Char_Index( face
, m_text
[n
] );
302 int error
= FT_Load_Glyph( face
, index
, FT_LOAD_DEFAULT
);
305 error
= FT_Render_Glyph( face
->glyph
, ft_render_mode_normal
);
308 FT_Bitmap
*bitmap
= &slot
->bitmap
;
309 unsigned char* buffer
= bitmap
->buffer
;
310 for (int y
= 0; y
< bitmap
->rows
; y
++)
311 for (int x
= 0; x
< bitmap
->width
; x
++)
313 unsigned char alpha
= buffer
[ y
*bitmap
->pitch
+ x
];
314 if (alpha
== 0) continue;
316 int xx
= pen_x
+ slot
->bitmap_left
+ x
;
317 int yy
= pen_y
- slot
->bitmap_top
+ y
;
318 m_alpha
[ yy
* m_area
.width
+ xx
] = alpha
;
321 pen_x
+= slot
->advance
.x
>> 6;
322 pen_y
+= slot
->advance
.y
>> 6;
327 //----------------------------------------------------------------------------
329 //----------------------------------------------------------------------------
331 IMPLEMENT_CLASS(wxCanvas
,wxScrolledWindow
)
333 BEGIN_EVENT_TABLE(wxCanvas
,wxScrolledWindow
)
334 EVT_CHAR( wxCanvas::OnChar
)
335 EVT_PAINT( wxCanvas::OnPaint
)
336 EVT_SIZE( wxCanvas::OnSize
)
337 EVT_IDLE( wxCanvas::OnIdle
)
338 EVT_MOUSE_EVENTS( wxCanvas::OnMouse
)
339 EVT_SET_FOCUS( wxCanvas::OnSetFocus
)
340 EVT_KILL_FOCUS( wxCanvas::OnKillFocus
)
343 wxCanvas::wxCanvas( wxWindow
*parent
, wxWindowID id
,
344 const wxPoint
&position
, const wxSize
& size
, long style
) :
345 wxScrolledWindow( parent
, id
, position
, size
, style
)
347 m_needUpdate
= FALSE
;
348 m_objects
.DeleteContents( TRUE
);
354 wxCanvas::~wxCanvas()
356 wxNode
*node
= m_updateRects
.First();
359 wxRect
*rect
= (wxRect
*) node
->Data();
361 m_updateRects
.DeleteNode( node
);
362 node
= m_updateRects
.First();
366 void wxCanvas::SetArea( int width
, int height
)
368 m_buffer
= wxImage( width
, height
);
369 SetScrollbars( 10, 10, width
/10, height
/10 );
372 void wxCanvas::SetColour( unsigned char red
, unsigned char green
, unsigned char blue
)
378 unsigned char *data
= m_buffer
.GetData();
380 for (int y
= 0; y
< m_buffer
.GetHeight(); y
++)
381 for (int x
= 0; x
< m_buffer
.GetWidth(); x
++)
392 void wxCanvas::Update( int x
, int y
, int width
, int height
)
400 if (width
< 0) return;
407 if (height
< 0) return;
409 if (x
+width
> m_buffer
.GetWidth())
411 width
= m_buffer
.GetWidth() - x
;
413 if (width
< 0) return;
415 if (y
+height
> m_buffer
.GetHeight())
417 height
= m_buffer
.GetHeight() - y
;
419 if (height
< 0) return;
421 // update is within the buffer
424 // has to be blitted to screen later
425 m_updateRects
.Append(
426 (wxObject
*) new wxRect( x
,y
,width
,height
) );
428 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b)
429 for (int yy
= y
; yy
< y
+height
; yy
++)
430 for (int xx
= x
; xx
< x
+width
; xx
++)
431 m_buffer
.SetRGB( xx
, yy
, m_red
, m_green
, m_blue
);
433 // cycle through all objects
434 wxNode
*node
= m_objects
.First();
437 wxCanvasObject
*obj
= (wxCanvasObject
*) node
->Data();
439 if (!obj
->IsControl())
441 // If we have 10.000 objects, we will go through
442 // this 10.000 times for each update, so we have
443 // to optimise carefully.
444 int clip_x
= obj
->GetX();
445 int clip_width
= obj
->GetWidth();
448 clip_width
-= x
-clip_x
;
453 if (clip_x
+ clip_width
> x
+ width
)
454 clip_width
= x
+width
-clip_x
;
458 int clip_y
= obj
->GetY();
459 int clip_height
= obj
->GetHeight();
462 clip_height
-= y
-clip_y
;
467 if (clip_y
+ clip_height
> y
+ height
)
468 clip_height
= y
+height
-clip_y
;
471 obj
->Render( clip_x
, clip_y
, clip_width
, clip_height
);
481 void wxCanvas::BlitBuffer( wxDC
&dc
)
483 wxNode
*node
= m_updateRects
.First();
486 wxRect
*rect
= (wxRect
*) node
->Data();
487 wxImage
sub_image( m_buffer
.GetSubImage( *rect
) );
489 // DirectDraw here, please
492 int bpp
= wxDisplayDepth();
495 // the init code is doubled in wxImage
496 static bool s_hasInitialized
= FALSE
;
498 if (!s_hasInitialized
)
501 s_hasInitialized
= TRUE
;
506 CalcScrolledPosition( x
, y
, &x
, &y
);
508 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow
)->bin_window
,
509 m_wxwindow
->style
->black_gc
,
511 sub_image
.GetWidth(), sub_image
.GetHeight(),
514 sub_image
.GetWidth()*3 );
518 wxBitmap
bitmap( sub_image
.ConvertToBitmap() );
519 dc
.DrawBitmap( bitmap
, rect
->x
, rect
->y
);
524 wxBitmap
bitmap( sub_image
.ConvertToBitmap() );
525 dc
.DrawBitmap( bitmap
, rect
->x
, rect
->y
);
529 m_updateRects
.DeleteNode( node
);
530 node
= m_updateRects
.First();
533 m_needUpdate
= FALSE
;
536 void wxCanvas::UpdateNow()
538 if (!m_needUpdate
) return;
540 wxClientDC
dc( this );
546 void wxCanvas::Prepend( wxCanvasObject
* obj
)
548 m_objects
.Insert( obj
);
550 obj
->SetOwner( this );
552 if (!obj
->IsControl())
553 Update( obj
->GetX(), obj
->GetY(), obj
->GetWidth(), obj
->GetHeight() );
556 void wxCanvas::Append( wxCanvasObject
* obj
)
558 m_objects
.Append( obj
);
560 obj
->SetOwner( this );
562 if (!obj
->IsControl())
563 Update( obj
->GetX(), obj
->GetY(), obj
->GetWidth(), obj
->GetHeight() );
566 void wxCanvas::Insert( size_t before
, wxCanvasObject
* obj
)
568 m_objects
.Insert( before
, obj
);
570 obj
->SetOwner( this );
572 if (!obj
->IsControl())
573 Update( obj
->GetX(), obj
->GetY(), obj
->GetWidth(), obj
->GetHeight() );
576 void wxCanvas::Remove( wxCanvasObject
* obj
)
580 int w
= obj
->GetWidth();
581 int h
= obj
->GetHeight();
582 bool ic
= obj
->IsControl();
584 m_objects
.DeleteObject( obj
);
587 Update( x
, y
, w
, h
);
590 void wxCanvas::OnPaint(wxPaintEvent
&event
)
597 wxRegionIterator
it( GetUpdateRegion() );
602 CalcUnscrolledPosition( x
, y
, &x
, &y
);
604 int w
= it
.GetWidth();
605 int h
= it
.GetHeight();
607 if (x
+w
> m_buffer
.GetWidth())
608 w
= m_buffer
.GetWidth() - x
;
609 if (y
+h
> m_buffer
.GetHeight())
610 h
= m_buffer
.GetHeight() - y
;
612 if ((w
> 0) && (h
> 0))
613 m_updateRects
.Append( (wxObject
*) new wxRect( x
, y
, w
, h
) );
621 void wxCanvas::OnMouse(wxMouseEvent
&event
)
623 // Propagate to objects here
626 void wxCanvas::OnSize(wxSizeEvent
&event
)
631 void wxCanvas::OnIdle(wxIdleEvent
&event
)
637 void wxCanvas::OnSetFocus(wxFocusEvent
&event
)
641 void wxCanvas::OnKillFocus(wxFocusEvent
&event
)
645 void wxCanvas::OnChar(wxKeyEvent
&event
)
650 //--------------------------------------------------------------------
652 //--------------------------------------------------------------------
654 class wxCanvasModule
: public wxModule
657 virtual bool OnInit();
658 virtual void OnExit();
661 DECLARE_DYNAMIC_CLASS(wxCanvasModule
)
664 IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule
, wxModule
)
666 bool wxCanvasModule::OnInit()
669 int error
= FT_Init_FreeType( &g_freetypeLibrary
);
670 if (error
) return FALSE
;
676 void wxCanvasModule::OnExit()
679 FT_Done_FreeType( g_freetypeLibrary
);