tagging release
[dasher.git] / Src / Gtk2 / Canvas.cpp
blob3ef7e0e9cd1b654e26e16e60c3d81ecc447ca6ba
1 #include "../Common/Common.h"
3 #include "Canvas.h"
4 #include "DasherControl.h"
6 #include "../DasherCore/DasherTypes.h"
8 using namespace Dasher;
10 CCanvas::CCanvas(GtkWidget *pCanvas, CPangoCache *pPangoCache)
11 : CDasherScreen(pCanvas->allocation.width, pCanvas->allocation.height) {
13 #if WITH_CAIRO
14 cairo_colours = 0;
15 #else
16 colours = 0;
17 #endif
19 m_pCanvas = pCanvas;
20 m_pPangoCache = pPangoCache;
22 m_iWidth = m_pCanvas->allocation.width;
23 m_iHeight = m_pCanvas->allocation.height;
25 // Construct the buffer pixmaps
26 // FIXME - only allocate without cairo
28 #if WITH_CAIRO
30 m_pDisplaySurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, m_iWidth, m_iHeight);
31 m_pDecorationSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, m_iWidth, m_iHeight);
32 m_pOnscreenSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, m_iWidth, m_iHeight);
34 #else
36 m_pDummyBuffer = gdk_pixmap_new(pCanvas->window, m_iWidth, m_iHeight, -1);
38 m_pDisplayBuffer = gdk_pixmap_new(pCanvas->window, m_iWidth, m_iHeight, -1);
39 m_pDecorationBuffer = gdk_pixmap_new(pCanvas->window, m_iWidth, m_iHeight, -1);
40 m_pOnscreenBuffer = gdk_pixmap_new(pCanvas->window, m_iWidth, m_iHeight, -1);
42 // Set the display buffer to be current
44 m_pOffscreenBuffer = m_pDisplayBuffer;
46 #endif
49 #if WITH_CAIRO
50 // The lines between origin and pointer is draw here
51 decoration_cr = cairo_create(m_pDecorationSurface);
52 cr = decoration_cr;
53 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
54 cairo_set_line_width(cr, 1.0);
56 // Base stuff are drawn here
57 display_cr = cairo_create(m_pDisplaySurface);
58 cr = display_cr;
59 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
60 cairo_set_line_width(cr, 1.0);
62 onscreen_cr = cairo_create(m_pOnscreenSurface);
64 widget_cr = gdk_cairo_create(m_pCanvas->window) ;
66 #endif
68 m_pPangoInk = new PangoRectangle;
69 gtk_widget_add_events(m_pCanvas, GDK_ALL_EVENTS_MASK);
72 CCanvas::~CCanvas() {
73 // Free the buffer pixmaps
75 #if WITH_CAIRO
76 cr = NULL;
77 cairo_destroy(display_cr);
78 cairo_destroy(decoration_cr);
79 #else
80 g_object_unref(m_pDummyBuffer);
81 g_object_unref(m_pDisplayBuffer);
82 g_object_unref(m_pDecorationBuffer);
83 g_object_unref(m_pOnscreenBuffer);
84 #endif
86 delete m_pPangoInk;
89 void CCanvas::Blank() {
90 // FIXME - this is replicated throughout this file - do something
91 // about that
92 #if WITH_CAIRO
93 #else
94 GdkGC *graphics_context;
95 GdkColormap *colormap;
97 graphics_context = m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)];
98 colormap = gdk_colormap_get_system();
99 #endif
101 BEGIN_DRAWING;
102 SET_COLOR(0);
104 #if WITH_CAIRO
105 cairo_paint(cr);
106 #else
107 gdk_draw_rectangle(m_pOffscreenBuffer, graphics_context, TRUE, 0, 0, m_iWidth, m_iHeight);
108 #endif
110 END_DRAWING;
113 void CCanvas::Display() {
114 // FIXME - Some of this stuff is probably not needed
115 // GdkRectangle update_rect;
117 GdkGC *graphics_context;
118 #if WITH_CAIRO
119 #else
120 GdkColormap *colormap;
121 #endif
123 graphics_context = m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)];
125 #if WITH_CAIRO
126 #else
127 colormap = gdk_colormap_get_system();
128 #endif
130 BEGIN_DRAWING;
131 SET_COLOR(0);
133 // Copy the offscreen buffer into the onscreen buffer
135 // TODO: Reimplement (kind of important!)
137 // gdk_draw_drawable(m_pOnscreenBuffer, m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)], m_pOffscreenBuffer, 0, 0, 0, 0, m_iWidth, m_iHeight);
139 // BEGIN_DRAWING;
141 // cairo_set_source_surface(onscreen_cr, m_pDecorationSurface, 0, 0);
142 // cairo_rectangle(onscreen_cr, 0, 0, m_iWidth, m_iHeight);
143 // cairo_fill(onscreen_cr);
147 // END_DRAWING;
149 // Blank the offscreen buffer (?)
151 // gdk_draw_rectangle(m_pOffscreenBuffer, graphics_context, TRUE, 0, 0, m_iWidth, m_iHeight);
153 // Invalidate the full canvas to force it to be redrawn on-screen
155 // update_rect.x = 0;
156 // update_rect.y = 0;
157 // update_rect.width = m_iWidth;
158 // update_rect.height = m_iHeight;
160 // gdk_window_invalidate_rect(m_pCanvas->window, &update_rect, FALSE);
162 // BEGIN_DRAWING;
164 // GdkRectangle sRect = {0, 0, m_iWidth, m_iHeight};
165 // gdk_window_begin_paint_rect(m_pCanvas->window, &sRect);
167 #if WITH_CAIRO
168 cairo_set_source_surface(widget_cr, m_pDecorationSurface, 0, 0);
169 cairo_rectangle(widget_cr, 0, 0, m_iWidth, m_iHeight);
170 cairo_fill(widget_cr);
171 #else
172 gdk_draw_drawable(m_pCanvas->window, m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)], m_pDecorationBuffer, 0, 0, 0, 0, m_iWidth, m_iHeight);
173 #endif
175 // gdk_window_end_paint(m_pCanvas->window);
177 // Restore original graphics context (?)
179 END_DRAWING;
181 // gtk_main_iteration_do(0);
184 void CCanvas::DrawRectangle(int x1, int y1, int x2, int y2, int Color, int iOutlineColour, Opts::ColorSchemes ColorScheme, bool bDrawOutline, bool bFill, int iThickness) {
186 #if WITH_CAIRO
187 #else
188 GdkGC *graphics_context;
189 GdkColormap *colormap;
191 graphics_context = m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)];
192 colormap = gdk_colormap_get_system();
193 #endif
195 BEGIN_DRAWING;
197 int iLeft;
198 int iTop;
199 int iWidth;
200 int iHeight;
202 if( x2 > x1 ) {
203 iLeft = x1;
204 iWidth = x2 - x1;
206 else {
207 iLeft = x2;
208 iWidth = x1 - x2;
211 if( y2 > y1 ) {
212 iTop = y1 - 1;
213 iHeight = y2 - y1 + 1;
215 else {
216 iTop = y2 - 1;
217 iHeight = y1 - y2 + 1;
220 if(bFill) {
221 SET_COLOR(Color);
222 #if WITH_CAIRO
223 cairo_set_line_width(cr, iThickness);
224 cairo_rectangle(cr, iLeft, iTop, iWidth + 1, iHeight + 1);
225 cairo_fill(cr);
226 #else
227 gdk_draw_rectangle(m_pOffscreenBuffer, graphics_context, TRUE, iLeft, iTop, iWidth, iHeight);
228 #endif
231 if(bDrawOutline) {
232 if( iOutlineColour == -1 )
233 SET_COLOR(3);
234 else
235 SET_COLOR(iOutlineColour);
237 #if WITH_CAIRO
238 cairo_set_line_width(cr, iThickness);
239 cairo_rectangle(cr, iLeft + 0.5, iTop + 0.5, iWidth, iHeight);
240 cairo_stroke(cr);
241 #else
242 gdk_gc_set_line_attributes(graphics_context, iThickness, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND );
243 gdk_draw_rectangle(m_pOffscreenBuffer, graphics_context, FALSE, iLeft, iTop, iWidth, iHeight);
244 #endif
246 END_DRAWING;
249 void CCanvas::DrawCircle(screenint iCX, screenint iCY, screenint iR, int iColour, int iFillColour, int iThickness, bool bFill) {
250 #if WITH_CAIRO
251 #else
252 if(iThickness == 1) // This is to make it work propely on Windows
253 iThickness = 0;
255 GdkGC *graphics_context;
256 GdkColormap *colormap;
258 graphics_context = m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)];
259 colormap = gdk_colormap_get_system();
260 #endif
262 BEGIN_DRAWING;
264 if(bFill) {
265 SET_COLOR(iFillColour);
266 #if WITH_CAIRO
267 cairo_arc(cr, iCX, iCY, iR, 0, 2*M_PI);
268 cairo_fill(cr);
269 #else
270 gdk_draw_arc(m_pOffscreenBuffer, graphics_context, true, iCX - iR, iCY - iR, 2*iR, 2*iR, 0, 23040);
271 #endif
274 SET_COLOR(iColour);
275 #if WITH_CAIRO
276 cairo_set_line_width(cr, iThickness);
277 cairo_arc(cr, iCX, iCY, iR, 0, 2*M_PI);
278 cairo_stroke(cr);
279 #else
280 gdk_gc_set_line_attributes(graphics_context, iThickness, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND );
281 gdk_draw_arc(m_pOffscreenBuffer, graphics_context, false, iCX - iR, iCY - iR, 2*iR, 2*iR, 0, 23040);
282 #endif
284 END_DRAWING;
287 void CCanvas::Polygon(Dasher::CDasherScreen::point *Points, int Number, int Colour, int iWidth) {
289 if(iWidth == 1) // This is to make it work propely on Windows
290 iWidth = 0;
292 #if WITH_CAIRO
293 #else
294 GdkGC *graphics_context;
295 GdkColormap *colormap;
297 graphics_context = m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)];
298 colormap = gdk_colormap_get_system();
299 #endif
301 BEGIN_DRAWING;
302 SET_COLOR(Colour);
304 #if WITH_CAIRO
305 cairo_move_to(cr, Points[0].x, Points[0].y);
306 for (int i=1; i < Number; i++)
307 cairo_line_to(cr, Points[i].x, Points[i].y);
308 cairo_close_path(cr);
309 cairo_fill(cr);
310 #else
311 GdkPoint *gdk_points;
312 gdk_points = (GdkPoint *) g_malloc(Number * sizeof(GdkPoint));
314 for(int i = 0; i < Number; i++) {
315 gdk_points[i].x = Points[i].x;
316 gdk_points[i].y = Points[i].y;
319 gdk_gc_set_line_attributes(graphics_context, iWidth, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND );
320 gdk_draw_polygon(m_pOffscreenBuffer, graphics_context, TRUE, gdk_points, Number);
321 g_free(gdk_points);
322 #endif
324 END_DRAWING;
327 void CCanvas::Polyline(Dasher::CDasherScreen::point *Points, int Number, int iWidth, int Colour) {
329 // FIXME - combine this with polygon?
331 #if WITH_CAIRO
332 #else
333 if(iWidth == 1) // This is to make it work propely on Windows
334 iWidth = 0;
336 GdkGC *graphics_context;
337 GdkColormap *colormap;
339 graphics_context = m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)];
340 colormap = gdk_colormap_get_system();
341 #endif
343 BEGIN_DRAWING;
344 SET_COLOR(Colour);
346 #if WITH_CAIRO
347 cairo_set_line_width(cr, iWidth);
348 cairo_move_to(cr, Points[0].x+.5, Points[0].y+.5);
349 for (int i=1; i < Number; i++)
350 cairo_line_to(cr, Points[i].x+.5, Points[i].y+.5);
351 cairo_stroke(cr);
352 #else
353 GdkPoint *gdk_points;
354 gdk_points = (GdkPoint *) g_malloc(Number * sizeof(GdkPoint));
356 gdk_gc_set_line_attributes(graphics_context, iWidth, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND );
358 for(int i = 0; i < Number; i++) {
359 gdk_points[i].x = Points[i].x;
360 gdk_points[i].y = Points[i].y;
363 gdk_draw_lines(m_pOffscreenBuffer, graphics_context, gdk_points, Number);
364 g_free(gdk_points);
365 #endif
367 END_DRAWING;
370 void CCanvas::DrawString(const std::string &String, int x1, int y1, int size) {
371 #if WITH_CAIRO
372 #else
373 GdkGC *graphics_context;
374 GdkColormap *colormap;
376 graphics_context = m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)];
377 colormap = gdk_colormap_get_system();
378 #endif
380 BEGIN_DRAWING;
381 SET_COLOR(4);
383 #if WITH_CAIRO
384 PangoLayout *pLayout(m_pPangoCache->GetLayout(cr, String, size));
385 #else
386 PangoLayout *pLayout(m_pPangoCache->GetLayout(GTK_WIDGET(m_pCanvas), String, size));
387 #endif
389 pango_layout_get_pixel_extents(pLayout, m_pPangoInk, NULL);
391 #if WITH_CAIRO
392 cairo_translate(cr, x1, y1-(int)m_pPangoInk->height/2);
393 pango_cairo_show_layout(cr, pLayout);
394 #else
395 gdk_draw_layout(m_pOffscreenBuffer, graphics_context, x1, y1 - m_pPangoInk->height / 2, pLayout);
396 #endif
398 END_DRAWING;
401 void CCanvas::TextSize(const std::string &String, int *Width, int *Height, int size) {
403 #if WITH_CAIRO
404 PangoLayout *pLayout(m_pPangoCache->GetLayout(cr, String, size));
405 #else
406 PangoLayout *pLayout(m_pPangoCache->GetLayout(GTK_WIDGET(m_pCanvas), String, size));
407 #endif
408 pango_layout_get_pixel_extents(pLayout, m_pPangoInk, NULL);
410 *Width = m_pPangoInk->width;
411 *Height = m_pPangoInk->height;
414 void CCanvas::SendMarker(int iMarker) {
416 switch(iMarker) {
417 case 0: // Switch to display buffer
418 #if WITH_CAIRO
419 cr = display_cr;
420 #else
421 m_pOffscreenBuffer = m_pDisplayBuffer;
422 #endif
423 break;
424 case 1: // Switch to decorations buffer
426 #if WITH_CAIRO
427 BEGIN_DRAWING;
428 cairo_set_source_surface(decoration_cr, m_pDisplaySurface, 0, 0);
429 cairo_rectangle(decoration_cr, 0, 0, m_iWidth, m_iHeight);
430 cairo_fill(decoration_cr);
431 END_DRAWING;
432 #else
433 gdk_draw_drawable(m_pDecorationBuffer, m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)], m_pDisplayBuffer, 0, 0, 0, 0, m_iWidth, m_iHeight);
434 m_pOffscreenBuffer = m_pDecorationBuffer;
435 #endif
436 #if WITH_CAIRO
437 cr = decoration_cr;
438 #endif
439 break;
443 void CCanvas::SetColourScheme(const CColourIO::ColourInfo *pColourScheme) {
444 int iNumColours(pColourScheme->Reds.size());
446 #if WITH_CAIRO
447 if (cairo_colours)
448 delete[] cairo_colours;
449 cairo_colours = new my_cairo_colour_t[iNumColours];
450 #else
451 if (colours)
452 delete[] colours;
453 colours = new GdkColor[iNumColours];
454 #endif
456 for(int i = 0; i < iNumColours; i++) {
457 #if WITH_CAIRO
458 cairo_colours[i].r = pColourScheme->Reds[i] / 255.0;
459 cairo_colours[i].g = pColourScheme->Greens[i] / 255.0;
460 cairo_colours[i].b = pColourScheme->Blues[i] / 255.0;
461 #else
462 colours[i].pixel=0;
463 colours[i].red=pColourScheme->Reds[i]*257;
464 colours[i].green=pColourScheme->Greens[i]*257;
465 colours[i].blue=pColourScheme->Blues[i]*257;
466 #endif
470 bool CCanvas::GetCanvasSize(GdkRectangle *pRectangle)
472 if ((pRectangle == NULL) || (m_pCanvas == NULL))
473 return false;
475 // Using gtk_window_get_frame_extents() only seems to return the position
476 // and size of the parent Dasher window. So we'll get the widgets position
477 // and use its size to determine the bounding rectangle.
478 int iX = 0;
479 int iY = 0;
481 gdk_window_get_position(m_pCanvas->window, &iX, &iY);
483 pRectangle->x = iX;
484 pRectangle->y = iY;
485 pRectangle->width = m_iWidth;
486 pRectangle->height = m_iHeight;
488 return true;