]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/canvas/canvas.cpp
1. Setting the listctrl as the event object before sending the event
[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
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
cb281cfc 28#define USE_FREETYPE 1
d1f9b206
RR
29
30#if USE_FREETYPE
31#include <freetype/freetype.h>
32#endif
33
34//----------------------------------------------------------------------------
35// globals
36//----------------------------------------------------------------------------
37
38#if USE_FREETYPE
39FT_Library g_freetypeLibrary;
40#endif
6a2c1874
RR
41
42//----------------------------------------------------------------------------
43// wxCanvasObject
44//----------------------------------------------------------------------------
45
46wxCanvasObject::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
58void 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
75void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
76{
77}
78
79void wxCanvasObject::Render( int clip_x, int clip_y, int clip_width, int clip_height )
80{
81}
82
21544859
RR
83//----------------------------------------------------------------------------
84// wxCanvasRect
85//----------------------------------------------------------------------------
86
87wxCanvasRect::wxCanvasRect( int x, int y, int w, int h, unsigned char red, unsigned char green, unsigned char blue )
88 : wxCanvasObject( x, y, w, h )
89{
90 m_red = red;
91 m_green = green;
92 m_blue = blue;
93}
94
95void wxCanvasRect::Render( int clip_x, int clip_y, int clip_width, int clip_height )
96{
97 wxImage *image = m_owner->GetBuffer();
98 // speed up later
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 );
102}
103
104void wxCanvasRect::WriteSVG( wxTextOutputStream &stream )
105{
106}
107
6a2c1874
RR
108//----------------------------------------------------------------------------
109// wxCanvasImage
110//----------------------------------------------------------------------------
111
112wxCanvasImage::wxCanvasImage( const wxImage &image, int x, int y )
113 : wxCanvasObject( x, y, image.GetWidth(), image.GetHeight() )
114{
115 m_image = image;
116 m_isImage = TRUE;
117}
118
119void wxCanvasImage::Render( int clip_x, int clip_y, int clip_width, int clip_height )
120{
21544859
RR
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))
d1f9b206 125 {
21544859 126 m_owner->GetBuffer()->Paste( m_image, clip_x, clip_y );
d1f9b206
RR
127 }
128 else
129 {
21544859
RR
130 // local coordinates
131 int start_x = clip_x - m_area.x;
132 int start_y = clip_y - m_area.y;
133
134 wxRect rect( start_x, start_y, clip_width, clip_height );
d1f9b206 135 wxImage sub_image( m_image.GetSubImage( rect ) );
21544859 136 m_owner->GetBuffer()->Paste( sub_image, clip_x, clip_y );
d1f9b206 137 }
6a2c1874
RR
138}
139
140void wxCanvasImage::WriteSVG( wxTextOutputStream &stream )
141{
142 // no idea
143}
144
3b111dbe
RR
145//----------------------------------------------------------------------------
146// wxCanvasCtrl
147//----------------------------------------------------------------------------
148
149wxCanvasControl::wxCanvasControl( wxWindow *control )
150 : wxCanvasObject( -1, -1, -1, -1 )
151{
21544859 152 m_isControl = TRUE;
3b111dbe
RR
153 m_control = control;
154 UpdateSize();
155}
156
157wxCanvasControl::~wxCanvasControl()
158{
159 m_control->Destroy();
160}
161
162void wxCanvasControl::Move( int x, int y )
163{
164 m_control->Move( x, y );
165}
166
167void wxCanvasControl::UpdateSize()
168{
169 m_control->GetSize( &m_area.width, &m_area.height );
170 m_control->GetPosition( &m_area.x, &m_area.y );
171}
172
d1f9b206
RR
173//----------------------------------------------------------------------------
174// wxCanvasText
175//----------------------------------------------------------------------------
176
177class wxFaceData
178{
179public:
180#if USE_FREETYPE
181 FT_Face m_face;
182#else
183 void *m_dummy;
184#endif
185};
186
cb281cfc 187wxCanvasText::wxCanvasText( const wxString &text, int x, int y, const wxString &fontFile, int size )
d1f9b206
RR
188 : wxCanvasObject( x, y, -1, -1 )
189{
190 m_text = text;
cb281cfc
RR
191 m_fontFileName = fontFile;
192 m_size = size;
d1f9b206 193
cb281cfc 194 m_red = 0;
d1f9b206
RR
195 m_green = 0;
196 m_blue = 0;
197
198 // test
cb281cfc
RR
199 m_area.width = 100;
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 );
d1f9b206
RR
203
204#if USE_FREETYPE
d1f9b206
RR
205 wxFaceData *data = new wxFaceData;
206 m_faceData = data;
207
208 int error = FT_New_Face( g_freetypeLibrary,
cb281cfc 209 m_fontFileName,
d1f9b206
RR
210 0,
211 &(data->m_face) );
212
213 error = FT_Set_Char_Size( data->m_face,
214 0,
cb281cfc
RR
215 m_size*64,
216 96, // screen dpi
d1f9b206 217 96 );
cb281cfc 218 CreateBuffer();
d1f9b206
RR
219#endif
220}
221
222wxCanvasText::~wxCanvasText()
223{
224#if USE_FREETYPE
225 wxFaceData *data = (wxFaceData*) m_faceData;
226 delete data;
227#endif
228
229 if (m_alpha) delete [] m_alpha;
230}
231
232void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue )
233{
234 m_red = red;
235 m_green = green;
236 m_blue = blue;
237}
238
239void wxCanvasText::SetFlag( int flag )
240{
241 m_flag = flag;
242}
243
244void wxCanvasText::Render( int clip_x, int clip_y, int clip_width, int clip_height )
245{
246 if (!m_alpha) return;
247
248 wxImage *image = m_owner->GetBuffer();
249
21544859
RR
250 // local coordinates
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;
d1f9b206
RR
255
256 for (int y = start_y; y < end_y; y++)
257 for (int x = start_x; x < end_x; x++)
258 {
259 int alpha = m_alpha[y*m_area.width + x];
260 if (alpha)
261 {
262 int image_x = m_area.x+x;
263 int image_y = m_area.y+y;
cb281cfc 264 if (alpha == 255)
d1f9b206
RR
265 {
266 image->SetRGB( image_x, image_y, m_red, m_green, m_blue );
267 continue;
268 }
cb281cfc
RR
269 int red1 = (m_red * alpha) / 255;
270 int green1 = (m_green * alpha) / 255;
271 int blue1 = (m_blue * alpha) / 255;
d1f9b206 272
cb281cfc 273 alpha = 255-alpha;
d1f9b206
RR
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 );
cb281cfc
RR
277 red2 = (red2 * alpha) / 255;
278 green2 = (green2 * alpha) / 255;
279 blue2 = (blue2 * alpha) / 255;
d1f9b206
RR
280
281 image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
282 }
283 }
284}
285
286void wxCanvasText::WriteSVG( wxTextOutputStream &stream )
287{
288}
289
290void wxCanvasText::CreateBuffer()
291{
292#if USE_FREETYPE
293 FT_Face face = ((wxFaceData*)m_faceData)->m_face;
294 FT_GlyphSlot slot = face->glyph;
295 int pen_x = 0;
cb281cfc 296 int pen_y = m_size;
d1f9b206 297
cb281cfc 298 for (int n = 0; n < (int)m_text.Len(); n++)
d1f9b206
RR
299 {
300 FT_UInt index = FT_Get_Char_Index( face, m_text[n] );
301
302 int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
303 if (error) continue;
304
cb281cfc 305 error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
d1f9b206
RR
306 if (error) continue;
307
cb281cfc
RR
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++)
312 {
313 unsigned char alpha = buffer[ y*bitmap->pitch + x ];
314 if (alpha == 0) continue;
315
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;
319 }
320
d1f9b206
RR
321 pen_x += slot->advance.x >> 6;
322 pen_y += slot->advance.y >> 6;
323 }
324#endif
325}
326
6a2c1874
RR
327//----------------------------------------------------------------------------
328// wxCanvas
329//----------------------------------------------------------------------------
330
331IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow)
332
333BEGIN_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 )
341END_EVENT_TABLE()
342
343wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
344 const wxPoint &position, const wxSize& size, long style ) :
345 wxScrolledWindow( parent, id, position, size, style )
346{
347 m_needUpdate = FALSE;
348 m_objects.DeleteContents( TRUE );
cb281cfc
RR
349 m_red = 0;
350 m_green = 0;
351 m_blue = 0;
6a2c1874
RR
352}
353
354wxCanvas::~wxCanvas()
355{
356 wxNode *node = m_updateRects.First();
357 while (node)
358 {
359 wxRect *rect = (wxRect*) node->Data();
360 delete rect;
361 m_updateRects.DeleteNode( node );
362 node = m_updateRects.First();
363 }
364}
365
366void wxCanvas::SetArea( int width, int height )
367{
368 m_buffer = wxImage( width, height );
369 SetScrollbars( 10, 10, width/10, height/10 );
370}
371
cb281cfc
RR
372void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char blue )
373{
374 m_red = red;
375 m_green = green;
376 m_blue = blue;
377
378 unsigned char *data = m_buffer.GetData();
379
380 for (int y = 0; y < m_buffer.GetHeight(); y++)
381 for (int x = 0; x < m_buffer.GetWidth(); x++)
382 {
383 data[0] = red;
384 data++;
385 data[0] = green;
386 data++;
387 data[0] = blue;
388 data++;
389 }
390}
391
6a2c1874
RR
392void wxCanvas::Update( int x, int y, int width, int height )
393{
21544859
RR
394 // clip to buffer
395 if (x < 0)
396 {
397 width -= x;
398 x = 0;
399 }
400 if (width < 0) return;
401
402 if (y < 0)
403 {
404 height -= y;
405 y = 0;
406 }
407 if (height < 0) return;
408
409 if (x+width > m_buffer.GetWidth())
410 {
411 width = m_buffer.GetWidth() - x;
412 }
413 if (width < 0) return;
414
415 if (y+height > m_buffer.GetHeight())
416 {
417 height = m_buffer.GetHeight() - y;
418 }
419 if (height < 0) return;
420
421 // update is within the buffer
6a2c1874
RR
422 m_needUpdate = TRUE;
423
21544859 424 // has to be blitted to screen later
6a2c1874
RR
425 m_updateRects.Append(
426 (wxObject*) new wxRect( x,y,width,height ) );
427
21544859
RR
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++)
cb281cfc 431 m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue );
6a2c1874 432
21544859 433 // cycle through all objects
6a2c1874
RR
434 wxNode *node = m_objects.First();
435 while (node)
436 {
437 wxCanvasObject *obj = (wxCanvasObject*) node->Data();
21544859
RR
438
439 if (!obj->IsControl())
6a2c1874 440 {
21544859
RR
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();
446 if (clip_x < x)
447 {
448 clip_width -= x-clip_x;
449 clip_x = x;
450 }
451 if (clip_width > 0)
452 {
453 if (clip_x + clip_width > x + width)
454 clip_width = x+width-clip_x;
455
456 if (clip_width > 0)
457 {
458 int clip_y = obj->GetY();
459 int clip_height = obj->GetHeight();
460 if (clip_y < y)
461 {
462 clip_height -= y-clip_y;
463 clip_y = y;
464 }
465 if (clip_height > 0)
466 {
467 if (clip_y + clip_height > y + height)
468 clip_height = y+height-clip_y;
469
470 if (clip_height > 0)
471 obj->Render( clip_x, clip_y, clip_width, clip_height );
472 }
473 }
474 }
6a2c1874
RR
475 }
476
477 node = node->Next();
478 }
479}
480
3b111dbe 481void wxCanvas::BlitBuffer( wxDC &dc )
6a2c1874 482{
6a2c1874
RR
483 wxNode *node = m_updateRects.First();
484 while (node)
485 {
486 wxRect *rect = (wxRect*) node->Data();
487 wxImage sub_image( m_buffer.GetSubImage( *rect ) );
488
489 // DirectDraw here, please
490
491#ifdef __WXGTK__
492 int bpp = wxDisplayDepth();
493 if (bpp > 8)
494 {
495 // the init code is doubled in wxImage
496 static bool s_hasInitialized = FALSE;
497
498 if (!s_hasInitialized)
499 {
500 gdk_rgb_init();
501 s_hasInitialized = TRUE;
502 }
503
504 int x = rect->x;
505 int y = rect->y;
506 CalcScrolledPosition( x, y, &x, &y );
507
508 gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window,
509 m_wxwindow->style->black_gc,
510 x, y,
511 sub_image.GetWidth(), sub_image.GetHeight(),
512 GDK_RGB_DITHER_NONE,
513 sub_image.GetData(),
514 sub_image.GetWidth()*3 );
515 }
516 else
517 {
518 wxBitmap bitmap( sub_image.ConvertToBitmap() );
519 dc.DrawBitmap( bitmap, rect->x, rect->y );
520 }
521#endif
522
523#ifndef __WXGTK__
524 wxBitmap bitmap( sub_image.ConvertToBitmap() );
525 dc.DrawBitmap( bitmap, rect->x, rect->y );
526#endif
527
528 delete rect;
529 m_updateRects.DeleteNode( node );
530 node = m_updateRects.First();
531 }
3b111dbe
RR
532
533 m_needUpdate = FALSE;
534}
535
536void wxCanvas::UpdateNow()
537{
538 if (!m_needUpdate) return;
539
540 wxClientDC dc( this );
541 PrepareDC( dc );
542
543 BlitBuffer( dc );
6a2c1874
RR
544}
545
546void wxCanvas::Prepend( wxCanvasObject* obj )
547{
548 m_objects.Insert( obj );
549
550 obj->SetOwner( this );
551
552 if (!obj->IsControl())
553 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
554}
555
556void wxCanvas::Append( wxCanvasObject* obj )
557{
558 m_objects.Append( obj );
559
560 obj->SetOwner( this );
561
562 if (!obj->IsControl())
563 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
564}
565
566void wxCanvas::Insert( size_t before, wxCanvasObject* obj )
567{
568 m_objects.Insert( before, obj );
569
570 obj->SetOwner( this );
571
572 if (!obj->IsControl())
573 Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
574}
575
576void wxCanvas::Remove( wxCanvasObject* obj )
577{
578 int x = obj->GetX();
579 int y = obj->GetY();
580 int w = obj->GetWidth();
581 int h = obj->GetHeight();
582 bool ic = obj->IsControl();
583
584 m_objects.DeleteObject( obj );
585
586 if (!ic)
587 Update( x, y, w, h );
588}
589
590void wxCanvas::OnPaint(wxPaintEvent &event)
591{
6a2c1874 592 wxPaintDC dc(this);
3b111dbe 593 PrepareDC( dc );
6a2c1874
RR
594
595 m_needUpdate = TRUE;
596
597 wxRegionIterator it( GetUpdateRegion() );
598 while (it)
599 {
600 int x = it.GetX();
601 int y = it.GetY();
602 CalcUnscrolledPosition( x, y, &x, &y );
603
604 int w = it.GetWidth();
605 int h = it.GetHeight();
6a2c1874 606
21544859
RR
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;
611
612 if ((w > 0) && (h > 0))
613 m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) );
6a2c1874
RR
614
615 it++;
616 }
3b111dbe
RR
617
618 BlitBuffer( dc );
6a2c1874
RR
619}
620
621void wxCanvas::OnMouse(wxMouseEvent &event)
622{
623 // Propagate to objects here
624}
625
626void wxCanvas::OnSize(wxSizeEvent &event)
627{
628 event.Skip();
629}
630
631void wxCanvas::OnIdle(wxIdleEvent &event)
632{
633 UpdateNow();
634 event.Skip();
635}
636
637void wxCanvas::OnSetFocus(wxFocusEvent &event)
638{
639}
640
641void wxCanvas::OnKillFocus(wxFocusEvent &event)
642{
643}
644
645void wxCanvas::OnChar(wxKeyEvent &event)
646{
647 event.Skip();
648}
649
d1f9b206
RR
650//--------------------------------------------------------------------
651// wxCanvasModule
652//--------------------------------------------------------------------
653
654class wxCanvasModule : public wxModule
655{
656public:
657 virtual bool OnInit();
658 virtual void OnExit();
659
660private:
661 DECLARE_DYNAMIC_CLASS(wxCanvasModule)
662};
663
664IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule)
6a2c1874 665
d1f9b206
RR
666bool wxCanvasModule::OnInit()
667{
668#if USE_FREETYPE
669 int error = FT_Init_FreeType( &g_freetypeLibrary );
670 if (error) return FALSE;
671#endif
672
673 return TRUE;
674}
675
676void wxCanvasModule::OnExit()
677{
678#if USE_FREETYPE
cb281cfc 679 FT_Done_FreeType( g_freetypeLibrary );
d1f9b206
RR
680#endif
681}