]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/canvas/canvas.cpp
ada4ce48e454f64db4483554a8581b1e8ce988f0
[wxWidgets.git] / contrib / src / canvas / canvas.cpp
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
20 #include "wx/canvas/canvas.h"
21
22 #ifdef __WXGTK__
23 #include <gtk/gtk.h>
24 #include <gdk/gdkrgb.h>
25 #include "wx/gtk/win_gtk.h"
26 #endif
27
28 #define USE_FREETYPE 0
29
30 #if USE_FREETYPE
31 #include <freetype/freetype.h>
32 #endif
33
34 //----------------------------------------------------------------------------
35 // globals
36 //----------------------------------------------------------------------------
37
38 #if USE_FREETYPE
39 FT_Library g_freetypeLibrary;
40 #endif
41
42 //----------------------------------------------------------------------------
43 // wxCanvasObject
44 //----------------------------------------------------------------------------
45
46 wxCanvasObject::wxCanvasObject( int x, int y, int width, int height )
47 {
48 m_owner = NULL;
49 m_area.x = x;
50 m_area.y = y;
51 m_area.width = width;
52 m_area.height = height;
53 m_isControl = FALSE;
54 m_isVector = FALSE;
55 m_isImage = FALSE;
56 }
57
58 void wxCanvasObject::Move( int x, int y )
59 {
60 int old_x = m_area.x;
61 int old_y = m_area.y;
62
63 m_area.x = x;
64 m_area.y = y;
65
66 if (!m_isControl)
67 {
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 );
72 }
73 }
74
75 void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
76 {
77 }
78
79 void wxCanvasObject::Render( int clip_x, int clip_y, int clip_width, int clip_height )
80 {
81 }
82
83 //----------------------------------------------------------------------------
84 // wxCanvasImage
85 //----------------------------------------------------------------------------
86
87 wxCanvasImage::wxCanvasImage( const wxImage &image, int x, int y )
88 : wxCanvasObject( x, y, image.GetWidth(), image.GetHeight() )
89 {
90 m_image = image;
91 m_isImage = TRUE;
92 }
93
94 void wxCanvasImage::Render( int clip_x, int clip_y, int clip_width, int clip_height )
95 {
96 int start_x = wxMax( 0, clip_x-m_area.x );
97 int end_x = wxMin( m_area.width, clip_width+clip_x-m_area.x );
98 int start_y = wxMax( 0, clip_y-m_area.y );
99 int end_y = wxMin( m_area.height, clip_height+clip_y-m_area.y );
100
101 if (end_x < start_x) return;
102 if (end_y < start_y) return;
103
104 if ((start_x == 0) &&
105 (start_y == 0) &&
106 (end_x == m_area.width) &&
107 (end_y == m_area.height))
108 {
109 m_owner->GetBuffer()->Paste( m_image, m_area.x, m_area.y );
110 }
111 else
112 {
113 wxRect rect( start_x, start_y, end_x-start_x, end_y-start_y );
114 wxImage sub_image( m_image.GetSubImage( rect ) );
115 m_owner->GetBuffer()->Paste( sub_image, m_area.x+start_x, m_area.y+start_y );
116 }
117 }
118
119 void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
120 {
121 // no idea
122 }
123
124 //----------------------------------------------------------------------------
125 // wxCanvasCtrl
126 //----------------------------------------------------------------------------
127
128 wxCanvasControl::wxCanvasControl( wxWindow *control )
129 : wxCanvasObject( -1, -1, -1, -1 )
130 {
131 m_control = control;
132 UpdateSize();
133 }
134
135 wxCanvasControl::~wxCanvasControl()
136 {
137 m_control->Destroy();
138 }
139
140 void wxCanvasControl::Move( int x, int y )
141 {
142 m_control->Move( x, y );
143 }
144
145 void wxCanvasControl::UpdateSize()
146 {
147 m_control->GetSize( &m_area.width, &m_area.height );
148 m_control->GetPosition( &m_area.x, &m_area.y );
149 }
150
151 //----------------------------------------------------------------------------
152 // wxCanvasText
153 //----------------------------------------------------------------------------
154
155 class wxFaceData
156 {
157 public:
158 #if USE_FREETYPE
159 FT_Face m_face;
160 #else
161 void *m_dummy;
162 #endif
163 };
164
165 wxCanvasText::wxCanvasText( const wxString &text, int x, int y )
166 : wxCanvasObject( x, y, -1, -1 )
167 {
168 m_text = text;
169 m_alpha = NULL;
170
171 m_red = 255;
172 m_green = 0;
173 m_blue = 0;
174
175 // test
176 m_area.width = 128;
177 m_area.height = 128;
178 m_alpha = new unsigned char[128*128];
179 for (int y = 0; y < m_area.height; y++)
180 for (int x = 0; x < m_area.width; x++)
181 m_alpha[y*m_area.width + x] = x;
182
183 #if USE_FREETYPE
184 CreateBuffer();
185 wxFaceData *data = new wxFaceData;
186 m_faceData = data;
187
188 int error = FT_New_Face( g_freetypeLibrary,
189 "~/TrueType/times.ttf",
190 0,
191 &(data->m_face) );
192
193 error = FT_Set_Char_Size( data->m_face,
194 0,
195 16*64,
196 96,
197 96 );
198 #endif
199 }
200
201 wxCanvasText::~wxCanvasText()
202 {
203 #if USE_FREETYPE
204 wxFaceData *data = (wxFaceData*) m_faceData;
205 delete data;
206 #endif
207
208 if (m_alpha) delete [] m_alpha;
209 }
210
211 void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue )
212 {
213 m_red = red;
214 m_green = green;
215 m_blue = blue;
216 }
217
218 void wxCanvasText::SetFlag( int flag )
219 {
220 m_flag = flag;
221 }
222
223 void wxCanvasText::Render( int clip_x, int clip_y, int clip_width, int clip_height )
224 {
225 if (!m_alpha) return;
226
227 wxImage *image = m_owner->GetBuffer();
228
229 int start_x = wxMax( 0, clip_x-m_area.x );
230 int end_x = wxMin( m_area.width, clip_width+clip_x-m_area.x );
231 int start_y = wxMax( 0, clip_y-m_area.y );
232 int end_y = wxMin( m_area.height, clip_height+clip_y-m_area.y );
233
234 for (int y = start_y; y < end_y; y++)
235 for (int x = start_x; x < end_x; x++)
236 {
237 int alpha = m_alpha[y*m_area.width + x];
238 if (alpha)
239 {
240 int image_x = m_area.x+x;
241 int image_y = m_area.y+y;
242 if (alpha == 128)
243 {
244 image->SetRGB( image_x, image_y, m_red, m_green, m_blue );
245 continue;
246 }
247 int red1 = (m_red * alpha) / 128;
248 int green1 = (m_green * alpha) / 128;
249 int blue1 = (m_blue * alpha) / 128;
250
251 alpha = 128-alpha;
252 int red2 = image->GetRed( image_x, image_y );
253 int green2 = image->GetGreen( image_x, image_y );
254 int blue2 = image->GetBlue( image_x, image_y );
255 red2 = (red2 * alpha) / 128;
256 green2 = (green2 * alpha) / 128;
257 blue2 = (blue2 * alpha) / 128;
258
259 image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
260 }
261 }
262 }
263
264 void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
265 {
266 }
267
268 void wxCanvasText::CreateBuffer()
269 {
270 #if USE_FREETYPE
271 FT_Face face = ((wxFaceData*)m_faceData)->m_face;
272 FT_GlyphSlot slot = face->glyph;
273 int pen_x = 0;
274 int pen_y = 0;
275
276 for (int n = 0; n < m_text.Len(); n++)
277 {
278 FT_UInt index = FT_Get_Char_Index( face, m_text[n] );
279
280 int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
281 if (error) continue;
282
283 error = FT_Render_Glyph( face->glyph, ft_render_antialias );
284 if (error) continue;
285
286 pen_x += slot->advance.x >> 6;
287 pen_y += slot->advance.y >> 6;
288 }
289 #endif
290 }
291
292 //----------------------------------------------------------------------------
293 // wxCanvas
294 //----------------------------------------------------------------------------
295
296 IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow)
297
298 BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow)
299 EVT_CHAR( wxCanvas::OnChar )
300 EVT_PAINT( wxCanvas::OnPaint )
301 EVT_SIZE( wxCanvas::OnSize )
302 EVT_IDLE( wxCanvas::OnIdle )
303 EVT_MOUSE_EVENTS( wxCanvas::OnMouse )
304 EVT_SET_FOCUS( wxCanvas::OnSetFocus )
305 EVT_KILL_FOCUS( wxCanvas::OnKillFocus )
306 END_EVENT_TABLE()
307
308 wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
309 const wxPoint &position, const wxSize& size, long style ) :
310 wxScrolledWindow( parent, id, position, size, style )
311 {
312 m_needUpdate = FALSE;
313 m_objects.DeleteContents( TRUE );
314 }
315
316 wxCanvas::~wxCanvas()
317 {
318 wxNode *node = m_updateRects.First();
319 while (node)
320 {
321 wxRect *rect = (wxRect*) node->Data();
322 delete rect;
323 m_updateRects.DeleteNode( node );
324 node = m_updateRects.First();
325 }
326 }
327
328 void wxCanvas::SetArea( int width, int height )
329 {
330 m_buffer = wxImage( width, height );
331 SetScrollbars( 10, 10, width/10, height/10 );
332 }
333
334 void wxCanvas::Update( int x, int y, int width, int height )
335 {
336 m_needUpdate = TRUE;
337
338 m_updateRects.Append(
339 (wxObject*) new wxRect( x,y,width,height ) );
340
341 // speed up with direct access, maybe add wxImage::Clear(x,y,w,h)
342 int xx,yy,ww,hh;
343 for (yy = y; yy < y+height; yy++)
344 for (xx = x; xx < x+width; xx++)
345 m_buffer.SetRGB( xx, yy, 0, 0, 0 );
346
347 wxNode *node = m_objects.First();
348 while (node)
349 {
350 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
351 xx = obj->GetX();
352 yy = obj->GetY();
353 ww = obj->GetWidth();
354 hh = obj->GetHeight();
355
356 if (!obj->IsControl()) // calc intersection !
357 {
358 obj->Render( x, y, width, height );
359 }
360
361 node = node->Next();
362 }
363 }
364
365 void wxCanvas::BlitBuffer( wxDC &dc )
366 {
367 wxNode *node = m_updateRects.First();
368 while (node)
369 {
370 wxRect *rect = (wxRect*) node->Data();
371 wxImage sub_image( m_buffer.GetSubImage( *rect ) );
372
373 // DirectDraw here, please
374
375 #ifdef __WXGTK__
376 int bpp = wxDisplayDepth();
377 if (bpp > 8)
378 {
379 // the init code is doubled in wxImage
380 static bool s_hasInitialized = FALSE;
381
382 if (!s_hasInitialized)
383 {
384 gdk_rgb_init();
385 s_hasInitialized = TRUE;
386 }
387
388 int x = rect->x;
389 int y = rect->y;
390 CalcScrolledPosition( x, y, &x, &y );
391
392 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window,
393 m_wxwindow->style->black_gc,
394 x, y,
395 sub_image.GetWidth(), sub_image.GetHeight(),
396 GDK_RGB_DITHER_NONE,
397 sub_image.GetData(),
398 sub_image.GetWidth()*3 );
399 }
400 else
401 {
402 wxBitmap bitmap( sub_image.ConvertToBitmap() );
403 dc.DrawBitmap( bitmap, rect->x, rect->y );
404 }
405 #endif
406
407 #ifndef __WXGTK__
408 wxBitmap bitmap( sub_image.ConvertToBitmap() );
409 dc.DrawBitmap( bitmap, rect->x, rect->y );
410 #endif
411
412 delete rect;
413 m_updateRects.DeleteNode( node );
414 node = m_updateRects.First();
415 }
416
417 m_needUpdate = FALSE;
418 }
419
420 void wxCanvas::UpdateNow()
421 {
422 if (!m_needUpdate) return;
423
424 wxClientDC dc( this );
425 PrepareDC( dc );
426
427 BlitBuffer( dc );
428 }
429
430 void wxCanvas::Prepend( wxCanvasObject* obj )
431 {
432 m_objects.Insert( obj );
433
434 obj->SetOwner( this );
435
436 if (!obj->IsControl())
437 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
438 }
439
440 void wxCanvas::Append( wxCanvasObject* obj )
441 {
442 m_objects.Append( obj );
443
444 obj->SetOwner( this );
445
446 if (!obj->IsControl())
447 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
448 }
449
450 void wxCanvas::Insert( size_t before, wxCanvasObject* obj )
451 {
452 m_objects.Insert( before, obj );
453
454 obj->SetOwner( this );
455
456 if (!obj->IsControl())
457 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
458 }
459
460 void wxCanvas::Remove( wxCanvasObject* obj )
461 {
462 int x = obj->GetX();
463 int y = obj->GetY();
464 int w = obj->GetWidth();
465 int h = obj->GetHeight();
466 bool ic = obj->IsControl();
467
468 m_objects.DeleteObject( obj );
469
470 if (!ic)
471 Update( x, y, w, h );
472 }
473
474 void wxCanvas::OnPaint(wxPaintEvent &event)
475 {
476 wxPaintDC dc(this);
477 PrepareDC( dc );
478
479 m_needUpdate = TRUE;
480
481 wxRegionIterator it( GetUpdateRegion() );
482 while (it)
483 {
484 int x = it.GetX();
485 int y = it.GetY();
486 CalcUnscrolledPosition( x, y, &x, &y );
487
488 int w = it.GetWidth();
489 int h = it.GetHeight();
490 if (x + w > m_buffer.GetWidth())
491 w = m_buffer.GetWidth()-x;
492 if (y + h > m_buffer.GetHeight())
493 h = m_buffer.GetHeight()-y;
494
495 m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
496
497 it++;
498 }
499
500 BlitBuffer( dc );
501 }
502
503 void wxCanvas::OnMouse(wxMouseEvent &event)
504 {
505 // Propagate to objects here
506 }
507
508 void wxCanvas::OnSize(wxSizeEvent &event)
509 {
510 event.Skip();
511 }
512
513 void wxCanvas::OnIdle(wxIdleEvent &event)
514 {
515 UpdateNow();
516 event.Skip();
517 }
518
519 void wxCanvas::OnSetFocus(wxFocusEvent &event)
520 {
521 }
522
523 void wxCanvas::OnKillFocus(wxFocusEvent &event)
524 {
525 }
526
527 void wxCanvas::OnChar(wxKeyEvent &event)
528 {
529 event.Skip();
530 }
531
532 //--------------------------------------------------------------------
533 // wxCanvasModule
534 //--------------------------------------------------------------------
535
536 class wxCanvasModule : public wxModule
537 {
538 public:
539 virtual bool OnInit();
540 virtual void OnExit();
541
542 private:
543 DECLARE_DYNAMIC_CLASS(wxCanvasModule)
544 };
545
546 IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
547
548 bool wxCanvasModule::OnInit()
549 {
550 #if USE_FREETYPE
551 int error = FT_Init_FreeType( &g_freetypeLibrary );
552 if (error) return FALSE;
553 #endif
554
555 return TRUE;
556 }
557
558 void wxCanvasModule::OnExit()
559 {
560 #if USE_FREETYPE
561 // Close FreeType
562 #endif
563 }