1 #include "../Common/Common.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
) {
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
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
);
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
;
50 // The lines between origin and pointer is draw here
51 decoration_cr
= cairo_create(m_pDecorationSurface
);
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
);
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
) ;
68 m_pPangoInk
= new PangoRectangle
;
69 gtk_widget_add_events(m_pCanvas
, GDK_ALL_EVENTS_MASK
);
73 // Free the buffer pixmaps
77 cairo_destroy(display_cr
);
78 cairo_destroy(decoration_cr
);
80 g_object_unref(m_pDummyBuffer
);
81 g_object_unref(m_pDisplayBuffer
);
82 g_object_unref(m_pDecorationBuffer
);
83 g_object_unref(m_pOnscreenBuffer
);
89 void CCanvas::Blank() {
90 // FIXME - this is replicated throughout this file - do something
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();
107 gdk_draw_rectangle(m_pOffscreenBuffer
, graphics_context
, TRUE
, 0, 0, m_iWidth
, m_iHeight
);
113 void CCanvas::Display() {
114 // FIXME - Some of this stuff is probably not needed
115 // GdkRectangle update_rect;
117 GdkGC
*graphics_context
;
120 GdkColormap
*colormap
;
123 graphics_context
= m_pCanvas
->style
->fg_gc
[GTK_WIDGET_STATE(m_pCanvas
)];
127 colormap
= gdk_colormap_get_system();
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);
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);
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);
164 // GdkRectangle sRect = {0, 0, m_iWidth, m_iHeight};
165 // gdk_window_begin_paint_rect(m_pCanvas->window, &sRect);
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
);
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
);
175 // gdk_window_end_paint(m_pCanvas->window);
177 // Restore original graphics context (?)
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
) {
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();
213 iHeight
= y2
- y1
+ 1;
217 iHeight
= y1
- y2
+ 1;
223 cairo_set_line_width(cr
, iThickness
);
224 cairo_rectangle(cr
, iLeft
, iTop
, iWidth
+ 1, iHeight
+ 1);
227 gdk_draw_rectangle(m_pOffscreenBuffer
, graphics_context
, TRUE
, iLeft
, iTop
, iWidth
, iHeight
);
232 if( iOutlineColour
== -1 )
235 SET_COLOR(iOutlineColour
);
238 cairo_set_line_width(cr
, iThickness
);
239 cairo_rectangle(cr
, iLeft
+ 0.5, iTop
+ 0.5, iWidth
, iHeight
);
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
);
249 void CCanvas::DrawCircle(screenint iCX
, screenint iCY
, screenint iR
, int iColour
, int iFillColour
, int iThickness
, bool bFill
) {
252 if(iThickness
== 1) // This is to make it work propely on Windows
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();
265 SET_COLOR(iFillColour
);
267 cairo_arc(cr
, iCX
, iCY
, iR
, 0, 2*M_PI
);
270 gdk_draw_arc(m_pOffscreenBuffer
, graphics_context
, true, iCX
- iR
, iCY
- iR
, 2*iR
, 2*iR
, 0, 23040);
276 cairo_set_line_width(cr
, iThickness
);
277 cairo_arc(cr
, iCX
, iCY
, iR
, 0, 2*M_PI
);
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);
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
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();
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
);
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
);
327 void CCanvas::Polyline(Dasher::CDasherScreen::point
*Points
, int Number
, int iWidth
, int Colour
) {
329 // FIXME - combine this with polygon?
333 if(iWidth
== 1) // This is to make it work propely on Windows
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();
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);
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
);
370 void CCanvas::DrawString(const std::string
&String
, int x1
, int y1
, int size
) {
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();
384 PangoLayout
*pLayout(m_pPangoCache
->GetLayout(cr
, String
, size
));
386 PangoLayout
*pLayout(m_pPangoCache
->GetLayout(GTK_WIDGET(m_pCanvas
), String
, size
));
389 pango_layout_get_pixel_extents(pLayout
, m_pPangoInk
, NULL
);
392 cairo_translate(cr
, x1
, y1
-(int)m_pPangoInk
->height
/2);
393 pango_cairo_show_layout(cr
, pLayout
);
395 gdk_draw_layout(m_pOffscreenBuffer
, graphics_context
, x1
, y1
- m_pPangoInk
->height
/ 2, pLayout
);
401 void CCanvas::TextSize(const std::string
&String
, int *Width
, int *Height
, int size
) {
404 PangoLayout
*pLayout(m_pPangoCache
->GetLayout(cr
, String
, size
));
406 PangoLayout
*pLayout(m_pPangoCache
->GetLayout(GTK_WIDGET(m_pCanvas
), String
, size
));
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
) {
417 case 0: // Switch to display buffer
421 m_pOffscreenBuffer
= m_pDisplayBuffer
;
424 case 1: // Switch to decorations buffer
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
);
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
;
443 void CCanvas::SetColourScheme(const CColourIO::ColourInfo
*pColourScheme
) {
444 int iNumColours(pColourScheme
->Reds
.size());
448 delete[] cairo_colours
;
449 cairo_colours
= new my_cairo_colour_t
[iNumColours
];
453 colours
= new GdkColor
[iNumColours
];
456 for(int i
= 0; i
< iNumColours
; i
++) {
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;
463 colours
[i
].red
=pColourScheme
->Reds
[i
]*257;
464 colours
[i
].green
=pColourScheme
->Greens
[i
]*257;
465 colours
[i
].blue
=pColourScheme
->Blues
[i
]*257;
470 bool CCanvas::GetCanvasSize(GdkRectangle
*pRectangle
)
472 if ((pRectangle
== NULL
) || (m_pCanvas
== NULL
))
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.
481 gdk_window_get_position(m_pCanvas
->window
, &iX
, &iY
);
485 pRectangle
->width
= m_iWidth
;
486 pRectangle
->height
= m_iHeight
;