]>
Commit | Line | Data |
---|---|---|
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 | |
39 | FT_Library g_freetypeLibrary; | |
40 | #endif | |
6a2c1874 RR |
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 | ||
239c1f50 RR |
75 | bool wxCanvasObject::IsHit( int x, int y, int margin ) |
76 | { | |
77 | return ((x >= m_area.x-margin) && | |
78 | (x <= m_area.x+m_area.width+margin) && | |
79 | (y >= m_area.y-margin) && | |
80 | (y <= m_area.y+m_area.height+margin)); | |
81 | } | |
82 | ||
6a2c1874 RR |
83 | void wxCanvasObject::WriteSVG( wxTextOutputStream &stream ) |
84 | { | |
85 | } | |
86 | ||
87 | void wxCanvasObject::Render( int clip_x, int clip_y, int clip_width, int clip_height ) | |
88 | { | |
89 | } | |
90 | ||
21544859 RR |
91 | //---------------------------------------------------------------------------- |
92 | // wxCanvasRect | |
93 | //---------------------------------------------------------------------------- | |
94 | ||
95 | wxCanvasRect::wxCanvasRect( int x, int y, int w, int h, unsigned char red, unsigned char green, unsigned char blue ) | |
96 | : wxCanvasObject( x, y, w, h ) | |
97 | { | |
98 | m_red = red; | |
99 | m_green = green; | |
100 | m_blue = blue; | |
101 | } | |
102 | ||
103 | void wxCanvasRect::Render( int clip_x, int clip_y, int clip_width, int clip_height ) | |
104 | { | |
105 | wxImage *image = m_owner->GetBuffer(); | |
106 | // speed up later | |
107 | for (int y = clip_y; y < clip_y+clip_height; y++) | |
108 | for (int x = clip_x; x < clip_x+clip_width; x++) | |
109 | image->SetRGB( x, y, m_red, m_green, m_blue ); | |
110 | } | |
111 | ||
112 | void wxCanvasRect::WriteSVG( wxTextOutputStream &stream ) | |
113 | { | |
114 | } | |
115 | ||
239c1f50 RR |
116 | //---------------------------------------------------------------------------- |
117 | // wxCanvasLine | |
118 | //---------------------------------------------------------------------------- | |
119 | ||
120 | wxCanvasLine::wxCanvasLine( int x, int y, int w, int h, unsigned char red, unsigned char green, unsigned char blue ) | |
121 | : wxCanvasObject( x, y, w, h ) | |
122 | { | |
123 | m_red = red; | |
124 | m_green = green; | |
125 | m_blue = blue; | |
126 | } | |
127 | ||
128 | void wxCanvasLine::Render( int clip_x, int clip_y, int clip_width, int clip_height ) | |
129 | { | |
130 | wxImage *image = m_owner->GetBuffer(); | |
131 | ||
132 | if ((m_area.width == 0) && (m_area.height == 0)) | |
133 | { | |
134 | image->SetRGB( m_area.x, m_area.y, m_red, m_green, m_blue ); | |
135 | } | |
136 | else | |
137 | { | |
138 | int x1 = m_area.x; | |
139 | int y1 = m_area.y; | |
140 | int x2 = m_area.x+m_area.width; | |
141 | int y2 = m_area.y+m_area.height; | |
142 | ||
143 | wxInt32 d, ii, jj, di, ai, si, dj, aj, sj; | |
144 | di = x1 - x2; | |
145 | ai = abs(di) << 1; | |
146 | si = (di < 0)? -1 : 1; | |
147 | dj = y1 - y2; | |
148 | aj = abs(dj) << 1; | |
149 | sj = (dj < 0)? -1 : 1; | |
150 | ||
151 | ii = x2; | |
152 | jj = y2; | |
153 | ||
154 | if (ai > aj) | |
155 | { | |
156 | // iterate over i | |
157 | d = aj - (ai >> 1); | |
158 | ||
159 | while (ii != x1) | |
160 | { | |
161 | if ((ii >= clip_x) && (ii <= clip_x+clip_width) && | |
162 | (jj >= clip_y) && (jj <= clip_y+clip_height)) | |
163 | { | |
164 | image->SetRGB( ii, jj, m_red, m_blue, m_green ); | |
165 | } | |
166 | if (d >= 0) | |
167 | { | |
168 | jj += sj; | |
169 | d -= ai; | |
170 | } | |
171 | ii += si; | |
172 | d += aj; | |
173 | } | |
174 | } | |
175 | else | |
176 | { | |
177 | // iterate over j | |
178 | d = ai - (aj >> 1); | |
179 | ||
180 | while (jj != y1) | |
181 | { | |
182 | if ((ii >= clip_x) && (ii <= clip_x+clip_width) && | |
183 | (jj >= clip_y) && (jj <= clip_y+clip_height)) | |
184 | { | |
185 | image->SetRGB( ii, jj, m_red, m_blue, m_green ); | |
186 | } | |
187 | if (d >= 0) | |
188 | { | |
189 | ii += si; | |
190 | d -= aj; | |
191 | } | |
192 | jj += sj; | |
193 | d += ai; | |
194 | } | |
195 | } | |
196 | } | |
197 | } | |
198 | ||
199 | void wxCanvasLine::WriteSVG( wxTextOutputStream &stream ) | |
200 | { | |
201 | } | |
202 | ||
6a2c1874 RR |
203 | //---------------------------------------------------------------------------- |
204 | // wxCanvasImage | |
205 | //---------------------------------------------------------------------------- | |
206 | ||
207 | wxCanvasImage::wxCanvasImage( const wxImage &image, int x, int y ) | |
208 | : wxCanvasObject( x, y, image.GetWidth(), image.GetHeight() ) | |
209 | { | |
210 | m_image = image; | |
211 | m_isImage = TRUE; | |
212 | } | |
213 | ||
214 | void wxCanvasImage::Render( int clip_x, int clip_y, int clip_width, int clip_height ) | |
215 | { | |
21544859 RR |
216 | if ((clip_x == m_area.x) && |
217 | (clip_y == m_area.y) && | |
218 | (clip_width == m_area.width) && | |
219 | (clip_height == m_area.height)) | |
d1f9b206 | 220 | { |
21544859 | 221 | m_owner->GetBuffer()->Paste( m_image, clip_x, clip_y ); |
d1f9b206 RR |
222 | } |
223 | else | |
224 | { | |
21544859 RR |
225 | // local coordinates |
226 | int start_x = clip_x - m_area.x; | |
227 | int start_y = clip_y - m_area.y; | |
228 | ||
229 | wxRect rect( start_x, start_y, clip_width, clip_height ); | |
d1f9b206 | 230 | wxImage sub_image( m_image.GetSubImage( rect ) ); |
21544859 | 231 | m_owner->GetBuffer()->Paste( sub_image, clip_x, clip_y ); |
d1f9b206 | 232 | } |
6a2c1874 RR |
233 | } |
234 | ||
235 | void wxCanvasImage::WriteSVG( wxTextOutputStream &stream ) | |
236 | { | |
237 | // no idea | |
238 | } | |
239 | ||
3b111dbe RR |
240 | //---------------------------------------------------------------------------- |
241 | // wxCanvasCtrl | |
242 | //---------------------------------------------------------------------------- | |
243 | ||
244 | wxCanvasControl::wxCanvasControl( wxWindow *control ) | |
245 | : wxCanvasObject( -1, -1, -1, -1 ) | |
246 | { | |
21544859 | 247 | m_isControl = TRUE; |
3b111dbe RR |
248 | m_control = control; |
249 | UpdateSize(); | |
250 | } | |
251 | ||
252 | wxCanvasControl::~wxCanvasControl() | |
253 | { | |
254 | m_control->Destroy(); | |
255 | } | |
256 | ||
257 | void wxCanvasControl::Move( int x, int y ) | |
258 | { | |
259 | m_control->Move( x, y ); | |
260 | } | |
261 | ||
262 | void wxCanvasControl::UpdateSize() | |
263 | { | |
264 | m_control->GetSize( &m_area.width, &m_area.height ); | |
265 | m_control->GetPosition( &m_area.x, &m_area.y ); | |
266 | } | |
267 | ||
d1f9b206 RR |
268 | //---------------------------------------------------------------------------- |
269 | // wxCanvasText | |
270 | //---------------------------------------------------------------------------- | |
271 | ||
272 | class wxFaceData | |
273 | { | |
274 | public: | |
275 | #if USE_FREETYPE | |
276 | FT_Face m_face; | |
277 | #else | |
278 | void *m_dummy; | |
279 | #endif | |
280 | }; | |
281 | ||
cb281cfc | 282 | wxCanvasText::wxCanvasText( const wxString &text, int x, int y, const wxString &fontFile, int size ) |
d1f9b206 RR |
283 | : wxCanvasObject( x, y, -1, -1 ) |
284 | { | |
285 | m_text = text; | |
cb281cfc RR |
286 | m_fontFileName = fontFile; |
287 | m_size = size; | |
d1f9b206 | 288 | |
cb281cfc | 289 | m_red = 0; |
d1f9b206 RR |
290 | m_green = 0; |
291 | m_blue = 0; | |
292 | ||
293 | // test | |
cb281cfc RR |
294 | m_area.width = 100; |
295 | m_area.height = m_size; | |
296 | m_alpha = new unsigned char[100*m_size]; | |
297 | memset( m_alpha, 0, m_area.width*m_area.height ); | |
d1f9b206 RR |
298 | |
299 | #if USE_FREETYPE | |
d1f9b206 RR |
300 | wxFaceData *data = new wxFaceData; |
301 | m_faceData = data; | |
302 | ||
303 | int error = FT_New_Face( g_freetypeLibrary, | |
cb281cfc | 304 | m_fontFileName, |
d1f9b206 RR |
305 | 0, |
306 | &(data->m_face) ); | |
307 | ||
308 | error = FT_Set_Char_Size( data->m_face, | |
309 | 0, | |
cb281cfc RR |
310 | m_size*64, |
311 | 96, // screen dpi | |
d1f9b206 | 312 | 96 ); |
cb281cfc | 313 | CreateBuffer(); |
d1f9b206 RR |
314 | #endif |
315 | } | |
316 | ||
317 | wxCanvasText::~wxCanvasText() | |
318 | { | |
319 | #if USE_FREETYPE | |
320 | wxFaceData *data = (wxFaceData*) m_faceData; | |
321 | delete data; | |
322 | #endif | |
323 | ||
324 | if (m_alpha) delete [] m_alpha; | |
325 | } | |
326 | ||
327 | void wxCanvasText::SetRGB( unsigned char red, unsigned char green, unsigned char blue ) | |
328 | { | |
329 | m_red = red; | |
330 | m_green = green; | |
331 | m_blue = blue; | |
332 | } | |
333 | ||
334 | void wxCanvasText::SetFlag( int flag ) | |
335 | { | |
336 | m_flag = flag; | |
337 | } | |
338 | ||
339 | void wxCanvasText::Render( int clip_x, int clip_y, int clip_width, int clip_height ) | |
340 | { | |
341 | if (!m_alpha) return; | |
342 | ||
343 | wxImage *image = m_owner->GetBuffer(); | |
344 | ||
21544859 RR |
345 | // local coordinates |
346 | int start_x = clip_x - m_area.x; | |
347 | int end_x = clip_width + start_x; | |
348 | int start_y = clip_y - m_area.y; | |
349 | int end_y = clip_height + start_y; | |
d1f9b206 RR |
350 | |
351 | for (int y = start_y; y < end_y; y++) | |
352 | for (int x = start_x; x < end_x; x++) | |
353 | { | |
354 | int alpha = m_alpha[y*m_area.width + x]; | |
355 | if (alpha) | |
356 | { | |
357 | int image_x = m_area.x+x; | |
358 | int image_y = m_area.y+y; | |
cb281cfc | 359 | if (alpha == 255) |
d1f9b206 RR |
360 | { |
361 | image->SetRGB( image_x, image_y, m_red, m_green, m_blue ); | |
362 | continue; | |
363 | } | |
cb281cfc RR |
364 | int red1 = (m_red * alpha) / 255; |
365 | int green1 = (m_green * alpha) / 255; | |
366 | int blue1 = (m_blue * alpha) / 255; | |
d1f9b206 | 367 | |
cb281cfc | 368 | alpha = 255-alpha; |
d1f9b206 RR |
369 | int red2 = image->GetRed( image_x, image_y ); |
370 | int green2 = image->GetGreen( image_x, image_y ); | |
371 | int blue2 = image->GetBlue( image_x, image_y ); | |
cb281cfc RR |
372 | red2 = (red2 * alpha) / 255; |
373 | green2 = (green2 * alpha) / 255; | |
374 | blue2 = (blue2 * alpha) / 255; | |
d1f9b206 RR |
375 | |
376 | image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 ); | |
377 | } | |
378 | } | |
379 | } | |
380 | ||
381 | void wxCanvasText::WriteSVG( wxTextOutputStream &stream ) | |
382 | { | |
383 | } | |
384 | ||
385 | void wxCanvasText::CreateBuffer() | |
386 | { | |
387 | #if USE_FREETYPE | |
388 | FT_Face face = ((wxFaceData*)m_faceData)->m_face; | |
389 | FT_GlyphSlot slot = face->glyph; | |
390 | int pen_x = 0; | |
cb281cfc | 391 | int pen_y = m_size; |
d1f9b206 | 392 | |
cb281cfc | 393 | for (int n = 0; n < (int)m_text.Len(); n++) |
d1f9b206 RR |
394 | { |
395 | FT_UInt index = FT_Get_Char_Index( face, m_text[n] ); | |
396 | ||
397 | int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); | |
398 | if (error) continue; | |
399 | ||
cb281cfc | 400 | error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); |
d1f9b206 RR |
401 | if (error) continue; |
402 | ||
cb281cfc RR |
403 | FT_Bitmap *bitmap = &slot->bitmap; |
404 | unsigned char* buffer = bitmap->buffer; | |
405 | for (int y = 0; y < bitmap->rows; y++) | |
406 | for (int x = 0; x < bitmap->width; x++) | |
407 | { | |
408 | unsigned char alpha = buffer[ y*bitmap->pitch + x ]; | |
409 | if (alpha == 0) continue; | |
410 | ||
411 | int xx = pen_x + slot->bitmap_left + x; | |
412 | int yy = pen_y - slot->bitmap_top + y; | |
413 | m_alpha[ yy * m_area.width + xx ] = alpha; | |
414 | } | |
415 | ||
d1f9b206 RR |
416 | pen_x += slot->advance.x >> 6; |
417 | pen_y += slot->advance.y >> 6; | |
418 | } | |
419 | #endif | |
420 | } | |
421 | ||
6a2c1874 RR |
422 | //---------------------------------------------------------------------------- |
423 | // wxCanvas | |
424 | //---------------------------------------------------------------------------- | |
425 | ||
426 | IMPLEMENT_CLASS(wxCanvas,wxScrolledWindow) | |
427 | ||
428 | BEGIN_EVENT_TABLE(wxCanvas,wxScrolledWindow) | |
429 | EVT_CHAR( wxCanvas::OnChar ) | |
430 | EVT_PAINT( wxCanvas::OnPaint ) | |
431 | EVT_SIZE( wxCanvas::OnSize ) | |
432 | EVT_IDLE( wxCanvas::OnIdle ) | |
433 | EVT_MOUSE_EVENTS( wxCanvas::OnMouse ) | |
434 | EVT_SET_FOCUS( wxCanvas::OnSetFocus ) | |
435 | EVT_KILL_FOCUS( wxCanvas::OnKillFocus ) | |
436 | END_EVENT_TABLE() | |
437 | ||
438 | wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id, | |
439 | const wxPoint &position, const wxSize& size, long style ) : | |
440 | wxScrolledWindow( parent, id, position, size, style ) | |
441 | { | |
442 | m_needUpdate = FALSE; | |
443 | m_objects.DeleteContents( TRUE ); | |
cb281cfc RR |
444 | m_red = 0; |
445 | m_green = 0; | |
446 | m_blue = 0; | |
239c1f50 RR |
447 | m_lastMouse = (wxCanvasObject*)NULL; |
448 | m_frozen = FALSE; | |
6a2c1874 RR |
449 | } |
450 | ||
451 | wxCanvas::~wxCanvas() | |
452 | { | |
453 | wxNode *node = m_updateRects.First(); | |
454 | while (node) | |
455 | { | |
456 | wxRect *rect = (wxRect*) node->Data(); | |
457 | delete rect; | |
458 | m_updateRects.DeleteNode( node ); | |
459 | node = m_updateRects.First(); | |
460 | } | |
461 | } | |
462 | ||
463 | void wxCanvas::SetArea( int width, int height ) | |
464 | { | |
465 | m_buffer = wxImage( width, height ); | |
466 | SetScrollbars( 10, 10, width/10, height/10 ); | |
467 | } | |
468 | ||
cb281cfc RR |
469 | void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char blue ) |
470 | { | |
471 | m_red = red; | |
472 | m_green = green; | |
473 | m_blue = blue; | |
474 | ||
239c1f50 RR |
475 | if (m_frozen) return; |
476 | ||
cb281cfc RR |
477 | unsigned char *data = m_buffer.GetData(); |
478 | ||
479 | for (int y = 0; y < m_buffer.GetHeight(); y++) | |
480 | for (int x = 0; x < m_buffer.GetWidth(); x++) | |
481 | { | |
482 | data[0] = red; | |
483 | data++; | |
484 | data[0] = green; | |
485 | data++; | |
486 | data[0] = blue; | |
487 | data++; | |
488 | } | |
489 | } | |
490 | ||
239c1f50 RR |
491 | void wxCanvas::Freeze() |
492 | { | |
493 | m_frozen = TRUE; | |
494 | } | |
495 | ||
496 | void wxCanvas::Thaw() | |
497 | { | |
498 | wxNode *node = m_updateRects.First(); | |
499 | while (node) | |
500 | { | |
501 | wxRect *rect = (wxRect*) node->Data(); | |
502 | delete rect; | |
503 | m_updateRects.DeleteNode( node ); | |
504 | node = m_updateRects.First(); | |
505 | } | |
506 | ||
507 | m_frozen = FALSE; | |
508 | ||
509 | Update( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() ); | |
510 | } | |
511 | ||
6a2c1874 RR |
512 | void wxCanvas::Update( int x, int y, int width, int height ) |
513 | { | |
239c1f50 RR |
514 | if (m_frozen) return; |
515 | ||
21544859 RR |
516 | // clip to buffer |
517 | if (x < 0) | |
518 | { | |
519 | width -= x; | |
520 | x = 0; | |
521 | } | |
522 | if (width < 0) return; | |
523 | ||
524 | if (y < 0) | |
525 | { | |
526 | height -= y; | |
527 | y = 0; | |
528 | } | |
529 | if (height < 0) return; | |
530 | ||
531 | if (x+width > m_buffer.GetWidth()) | |
532 | { | |
533 | width = m_buffer.GetWidth() - x; | |
534 | } | |
535 | if (width < 0) return; | |
536 | ||
537 | if (y+height > m_buffer.GetHeight()) | |
538 | { | |
539 | height = m_buffer.GetHeight() - y; | |
540 | } | |
541 | if (height < 0) return; | |
542 | ||
543 | // update is within the buffer | |
6a2c1874 RR |
544 | m_needUpdate = TRUE; |
545 | ||
21544859 | 546 | // has to be blitted to screen later |
6a2c1874 RR |
547 | m_updateRects.Append( |
548 | (wxObject*) new wxRect( x,y,width,height ) ); | |
549 | ||
21544859 RR |
550 | // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b) |
551 | for (int yy = y; yy < y+height; yy++) | |
552 | for (int xx = x; xx < x+width; xx++) | |
cb281cfc | 553 | m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue ); |
6a2c1874 | 554 | |
21544859 | 555 | // cycle through all objects |
6a2c1874 RR |
556 | wxNode *node = m_objects.First(); |
557 | while (node) | |
558 | { | |
559 | wxCanvasObject *obj = (wxCanvasObject*) node->Data(); | |
21544859 RR |
560 | |
561 | if (!obj->IsControl()) | |
6a2c1874 | 562 | { |
21544859 RR |
563 | // If we have 10.000 objects, we will go through |
564 | // this 10.000 times for each update, so we have | |
565 | // to optimise carefully. | |
566 | int clip_x = obj->GetX(); | |
567 | int clip_width = obj->GetWidth(); | |
568 | if (clip_x < x) | |
569 | { | |
570 | clip_width -= x-clip_x; | |
571 | clip_x = x; | |
572 | } | |
573 | if (clip_width > 0) | |
574 | { | |
575 | if (clip_x + clip_width > x + width) | |
576 | clip_width = x+width-clip_x; | |
577 | ||
578 | if (clip_width > 0) | |
579 | { | |
580 | int clip_y = obj->GetY(); | |
581 | int clip_height = obj->GetHeight(); | |
582 | if (clip_y < y) | |
583 | { | |
584 | clip_height -= y-clip_y; | |
585 | clip_y = y; | |
586 | } | |
587 | if (clip_height > 0) | |
588 | { | |
589 | if (clip_y + clip_height > y + height) | |
590 | clip_height = y+height-clip_y; | |
591 | ||
592 | if (clip_height > 0) | |
593 | obj->Render( clip_x, clip_y, clip_width, clip_height ); | |
594 | } | |
595 | } | |
596 | } | |
6a2c1874 RR |
597 | } |
598 | ||
599 | node = node->Next(); | |
600 | } | |
601 | } | |
602 | ||
3b111dbe | 603 | void wxCanvas::BlitBuffer( wxDC &dc ) |
6a2c1874 | 604 | { |
6a2c1874 RR |
605 | wxNode *node = m_updateRects.First(); |
606 | while (node) | |
607 | { | |
608 | wxRect *rect = (wxRect*) node->Data(); | |
609 | wxImage sub_image( m_buffer.GetSubImage( *rect ) ); | |
610 | ||
611 | // DirectDraw here, please | |
612 | ||
613 | #ifdef __WXGTK__ | |
614 | int bpp = wxDisplayDepth(); | |
615 | if (bpp > 8) | |
616 | { | |
617 | // the init code is doubled in wxImage | |
618 | static bool s_hasInitialized = FALSE; | |
619 | ||
620 | if (!s_hasInitialized) | |
621 | { | |
622 | gdk_rgb_init(); | |
623 | s_hasInitialized = TRUE; | |
624 | } | |
625 | ||
626 | int x = rect->x; | |
627 | int y = rect->y; | |
628 | CalcScrolledPosition( x, y, &x, &y ); | |
629 | ||
630 | gdk_draw_rgb_image( GTK_PIZZA(m_wxwindow)->bin_window, | |
631 | m_wxwindow->style->black_gc, | |
632 | x, y, | |
633 | sub_image.GetWidth(), sub_image.GetHeight(), | |
634 | GDK_RGB_DITHER_NONE, | |
635 | sub_image.GetData(), | |
636 | sub_image.GetWidth()*3 ); | |
637 | } | |
638 | else | |
639 | { | |
640 | wxBitmap bitmap( sub_image.ConvertToBitmap() ); | |
641 | dc.DrawBitmap( bitmap, rect->x, rect->y ); | |
642 | } | |
643 | #endif | |
644 | ||
645 | #ifndef __WXGTK__ | |
646 | wxBitmap bitmap( sub_image.ConvertToBitmap() ); | |
647 | dc.DrawBitmap( bitmap, rect->x, rect->y ); | |
648 | #endif | |
649 | ||
650 | delete rect; | |
651 | m_updateRects.DeleteNode( node ); | |
652 | node = m_updateRects.First(); | |
653 | } | |
3b111dbe RR |
654 | |
655 | m_needUpdate = FALSE; | |
656 | } | |
657 | ||
658 | void wxCanvas::UpdateNow() | |
659 | { | |
660 | if (!m_needUpdate) return; | |
661 | ||
662 | wxClientDC dc( this ); | |
663 | PrepareDC( dc ); | |
664 | ||
665 | BlitBuffer( dc ); | |
6a2c1874 RR |
666 | } |
667 | ||
668 | void wxCanvas::Prepend( wxCanvasObject* obj ) | |
669 | { | |
670 | m_objects.Insert( obj ); | |
671 | ||
672 | obj->SetOwner( this ); | |
673 | ||
674 | if (!obj->IsControl()) | |
675 | Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); | |
676 | } | |
677 | ||
678 | void wxCanvas::Append( wxCanvasObject* obj ) | |
679 | { | |
680 | m_objects.Append( obj ); | |
681 | ||
682 | obj->SetOwner( this ); | |
683 | ||
684 | if (!obj->IsControl()) | |
685 | Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); | |
686 | } | |
687 | ||
688 | void wxCanvas::Insert( size_t before, wxCanvasObject* obj ) | |
689 | { | |
690 | m_objects.Insert( before, obj ); | |
691 | ||
692 | obj->SetOwner( this ); | |
693 | ||
694 | if (!obj->IsControl()) | |
695 | Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); | |
696 | } | |
697 | ||
698 | void wxCanvas::Remove( wxCanvasObject* obj ) | |
699 | { | |
700 | int x = obj->GetX(); | |
701 | int y = obj->GetY(); | |
702 | int w = obj->GetWidth(); | |
703 | int h = obj->GetHeight(); | |
704 | bool ic = obj->IsControl(); | |
705 | ||
706 | m_objects.DeleteObject( obj ); | |
707 | ||
708 | if (!ic) | |
709 | Update( x, y, w, h ); | |
710 | } | |
711 | ||
712 | void wxCanvas::OnPaint(wxPaintEvent &event) | |
713 | { | |
6a2c1874 | 714 | wxPaintDC dc(this); |
3b111dbe | 715 | PrepareDC( dc ); |
6a2c1874 RR |
716 | |
717 | m_needUpdate = TRUE; | |
718 | ||
719 | wxRegionIterator it( GetUpdateRegion() ); | |
720 | while (it) | |
721 | { | |
722 | int x = it.GetX(); | |
723 | int y = it.GetY(); | |
724 | CalcUnscrolledPosition( x, y, &x, &y ); | |
725 | ||
726 | int w = it.GetWidth(); | |
727 | int h = it.GetHeight(); | |
6a2c1874 | 728 | |
21544859 RR |
729 | if (x+w > m_buffer.GetWidth()) |
730 | w = m_buffer.GetWidth() - x; | |
731 | if (y+h > m_buffer.GetHeight()) | |
732 | h = m_buffer.GetHeight() - y; | |
733 | ||
734 | if ((w > 0) && (h > 0)) | |
735 | m_updateRects.Append( (wxObject*) new wxRect( x, y, w, h ) ); | |
6a2c1874 RR |
736 | |
737 | it++; | |
738 | } | |
3b111dbe RR |
739 | |
740 | BlitBuffer( dc ); | |
6a2c1874 RR |
741 | } |
742 | ||
743 | void wxCanvas::OnMouse(wxMouseEvent &event) | |
744 | { | |
239c1f50 RR |
745 | // should we implement mouse capture ? |
746 | ||
747 | int x = event.GetX(); | |
748 | int y = event.GetY(); | |
749 | CalcUnscrolledPosition( x, y, &x, &y ); | |
750 | ||
751 | if (event.GetEventType() == wxEVT_MOTION) | |
752 | { | |
753 | wxNode *node = m_objects.First(); | |
754 | while (node) | |
755 | { | |
756 | wxCanvasObject *obj = (wxCanvasObject*) node->Data(); | |
757 | ||
758 | if (!obj->IsControl()) | |
759 | { | |
760 | if (obj->IsHit(x,y)) | |
761 | { | |
762 | wxMouseEvent child_event( wxEVT_MOTION ); | |
763 | child_event.SetEventObject( obj ); | |
764 | child_event.m_x = x + obj->GetX(); | |
765 | child_event.m_y = y + obj->GetY(); | |
766 | child_event.m_leftDown = event.m_leftDown; | |
767 | child_event.m_rightDown = event.m_rightDown; | |
768 | child_event.m_middleDown = event.m_middleDown; | |
769 | child_event.m_controlDown = event.m_controlDown; | |
770 | child_event.m_shiftDown = event.m_shiftDown; | |
771 | child_event.m_altDown = event.m_altDown; | |
772 | child_event.m_metaDown = event.m_metaDown; | |
773 | ||
774 | if ((obj != m_lastMouse) && (m_lastMouse != NULL)) | |
775 | { | |
776 | child_event.SetEventType( wxEVT_LEAVE_WINDOW ); | |
777 | child_event.SetEventObject( m_lastMouse ); | |
778 | child_event.m_x = x + m_lastMouse->GetX(); | |
779 | child_event.m_y = y + m_lastMouse->GetY(); | |
780 | m_lastMouse->ProcessEvent( child_event ); | |
781 | ||
782 | m_lastMouse = obj; | |
783 | child_event.SetEventType( wxEVT_ENTER_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 ); | |
788 | ||
789 | child_event.SetEventType( wxEVT_MOTION ); | |
790 | child_event.SetEventObject( obj ); | |
791 | } | |
792 | obj->ProcessEvent( child_event ); | |
793 | return; | |
794 | } | |
795 | } | |
796 | node = node->Next(); | |
797 | } | |
798 | if (m_lastMouse) | |
799 | { | |
800 | wxMouseEvent child_event( wxEVT_LEAVE_WINDOW ); | |
801 | child_event.SetEventObject( m_lastMouse ); | |
802 | child_event.m_x = x + m_lastMouse->GetX(); | |
803 | child_event.m_y = y + m_lastMouse->GetY(); | |
804 | child_event.m_leftDown = event.m_leftDown; | |
805 | child_event.m_rightDown = event.m_rightDown; | |
806 | child_event.m_middleDown = event.m_middleDown; | |
807 | child_event.m_controlDown = event.m_controlDown; | |
808 | child_event.m_shiftDown = event.m_shiftDown; | |
809 | child_event.m_altDown = event.m_altDown; | |
810 | child_event.m_metaDown = event.m_metaDown; | |
811 | m_lastMouse->ProcessEvent( child_event ); | |
812 | ||
813 | m_lastMouse = (wxCanvasObject*) NULL; | |
814 | return; | |
815 | } | |
816 | } | |
817 | event.Skip(); | |
6a2c1874 RR |
818 | } |
819 | ||
820 | void wxCanvas::OnSize(wxSizeEvent &event) | |
821 | { | |
822 | event.Skip(); | |
823 | } | |
824 | ||
825 | void wxCanvas::OnIdle(wxIdleEvent &event) | |
826 | { | |
827 | UpdateNow(); | |
828 | event.Skip(); | |
829 | } | |
830 | ||
831 | void wxCanvas::OnSetFocus(wxFocusEvent &event) | |
832 | { | |
833 | } | |
834 | ||
835 | void wxCanvas::OnKillFocus(wxFocusEvent &event) | |
836 | { | |
837 | } | |
838 | ||
839 | void wxCanvas::OnChar(wxKeyEvent &event) | |
840 | { | |
841 | event.Skip(); | |
842 | } | |
843 | ||
d1f9b206 RR |
844 | //-------------------------------------------------------------------- |
845 | // wxCanvasModule | |
846 | //-------------------------------------------------------------------- | |
847 | ||
848 | class wxCanvasModule : public wxModule | |
849 | { | |
850 | public: | |
851 | virtual bool OnInit(); | |
852 | virtual void OnExit(); | |
853 | ||
854 | private: | |
855 | DECLARE_DYNAMIC_CLASS(wxCanvasModule) | |
856 | }; | |
857 | ||
858 | IMPLEMENT_DYNAMIC_CLASS(wxCanvasModule, wxModule) | |
6a2c1874 | 859 | |
d1f9b206 RR |
860 | bool wxCanvasModule::OnInit() |
861 | { | |
862 | #if USE_FREETYPE | |
863 | int error = FT_Init_FreeType( &g_freetypeLibrary ); | |
864 | if (error) return FALSE; | |
865 | #endif | |
866 | ||
867 | return TRUE; | |
868 | } | |
869 | ||
870 | void wxCanvasModule::OnExit() | |
871 | { | |
872 | #if USE_FREETYPE | |
cb281cfc | 873 | FT_Done_FreeType( g_freetypeLibrary ); |
d1f9b206 RR |
874 | #endif |
875 | } |