1 #include "../Common/Common.h"
4 #include "DasherControl.h"
6 #include "../DasherCore/DasherTypes.h"
8 using namespace Dasher
;
10 extern "C" gint
canvas_expose_event(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
);
12 CCanvas::CCanvas(GtkWidget
*pCanvas
, CPangoCache
*pPangoCache
)
13 : CDasherScreen(pCanvas
->allocation
.width
, pCanvas
->allocation
.height
) {
22 m_pPangoCache
= pPangoCache
;
24 m_iWidth
= m_pCanvas
->allocation
.width
;
25 m_iHeight
= m_pCanvas
->allocation
.height
;
27 // Construct the buffer pixmaps
28 // FIXME - only allocate without cairo
31 m_pDummyBuffer
= gdk_pixmap_new(pCanvas
->window
, m_iWidth
, m_iHeight
, -1);
33 m_pDisplayBuffer
= gdk_pixmap_new(pCanvas
->window
, m_iWidth
, m_iHeight
, -1);
34 m_pDecorationBuffer
= gdk_pixmap_new(pCanvas
->window
, m_iWidth
, m_iHeight
, -1);
35 m_pOnscreenBuffer
= gdk_pixmap_new(pCanvas
->window
, m_iWidth
, m_iHeight
, -1);
37 // Set the display buffer to be current
39 m_pOffscreenBuffer
= m_pDisplayBuffer
;
43 // The lines between origin and pointer is draw here
44 decoration_cr
= gdk_cairo_create(m_pDecorationBuffer
);
46 cairo_set_line_cap(cr
, CAIRO_LINE_CAP_SQUARE
);
47 cairo_set_line_width(cr
, 1.0);
49 // Base stuff are drawn here
50 display_cr
= gdk_cairo_create(m_pDisplayBuffer
);
52 cairo_set_line_cap(cr
, CAIRO_LINE_CAP_SQUARE
);
53 cairo_set_line_width(cr
, 1.0);
56 m_pPangoInk
= new PangoRectangle
;
58 lSignalHandler
= g_signal_connect(m_pCanvas
, "expose_event", G_CALLBACK(canvas_expose_event
), this);
60 /* gtk_widget_add_events(m_pCanvas, GDK_EXPOSURE_MASK);
61 gtk_widget_add_events(m_pCanvas, GDK_BUTTON_PRESS_MASK);
62 gtk_widget_add_events(m_pCanvas, GDK_BUTTON_RELEASE_MASK);
64 gtk_widget_add_events(m_pCanvas
, GDK_ALL_EVENTS_MASK
);
68 // Free the buffer pixmaps
72 cairo_destroy(display_cr
);
73 cairo_destroy(decoration_cr
);
76 g_object_unref(m_pDummyBuffer
);
77 g_object_unref(m_pDisplayBuffer
);
78 g_object_unref(m_pDecorationBuffer
);
79 g_object_unref(m_pOnscreenBuffer
);
81 g_signal_handler_disconnect(m_pCanvas
, lSignalHandler
);
86 void CCanvas::Blank() {
87 // FIXME - this is replicated throughout this file - do something
91 GdkGC
*graphics_context
;
92 GdkColormap
*colormap
;
94 graphics_context
= m_pCanvas
->style
->fg_gc
[GTK_WIDGET_STATE(m_pCanvas
)];
95 colormap
= gdk_colormap_get_system();
104 gdk_draw_rectangle(m_pOffscreenBuffer
, graphics_context
, TRUE
, 0, 0, m_iWidth
, m_iHeight
);
110 void CCanvas::Display() {
112 // FIXME - Some of this stuff is probably not needed
114 GdkRectangle update_rect
;
116 GdkGC
*graphics_context
;
119 GdkColormap
*colormap
;
122 graphics_context
= m_pCanvas
->style
->fg_gc
[GTK_WIDGET_STATE(m_pCanvas
)];
126 colormap
= gdk_colormap_get_system();
132 // Copy the offscreen buffer into the onscreen buffer
134 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
);
136 // Blank the offscreen buffer (?)
138 gdk_draw_rectangle(m_pOffscreenBuffer
, graphics_context
, TRUE
, 0, 0, m_iWidth
, m_iHeight
);
140 // Invalidate the full canvas to force it to be redrawn on-screen
144 update_rect
.width
= m_iWidth
;
145 update_rect
.height
= m_iHeight
;
147 gdk_window_invalidate_rect(m_pCanvas
->window
, &update_rect
, FALSE
);
149 // Restore original graphics context (?)
153 gtk_main_iteration_do(0);
156 void CCanvas::DrawRectangle(int x1
, int y1
, int x2
, int y2
, int Color
, int iOutlineColour
, Opts::ColorSchemes ColorScheme
, bool bDrawOutline
, bool bFill
, int iThickness
) {
160 GdkGC
*graphics_context
;
161 GdkColormap
*colormap
;
163 graphics_context
= m_pCanvas
->style
->fg_gc
[GTK_WIDGET_STATE(m_pCanvas
)];
164 colormap
= gdk_colormap_get_system();
195 cairo_set_line_width(cr
, iThickness
);
196 cairo_rectangle(cr
, x1
, y1
, x2
-x1
+1.0, y2
-y1
+1.0);
199 gdk_draw_rectangle(m_pOffscreenBuffer
, graphics_context
, TRUE
, iLeft
, iTop
, iWidth
, iHeight
);
204 if( iOutlineColour
== -1 )
207 SET_COLOR(iOutlineColour
);
210 cairo_set_line_width(cr
, iThickness
);
211 cairo_rectangle(cr
, x1
+.5, y1
+.5, x2
-x1
, y2
-y1
);
214 gdk_gc_set_line_attributes(graphics_context
, iThickness
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
215 gdk_draw_rectangle(m_pOffscreenBuffer
, graphics_context
, FALSE
, iLeft
, iTop
, iWidth
, iHeight
);
221 void CCanvas::DrawCircle(screenint iCX
, screenint iCY
, screenint iR
, int iColour
, int iFillColour
, int iThickness
, bool bFill
) {
224 if(iThickness
== 1) // This is to make it work propely on Windows
227 GdkGC
*graphics_context
;
228 GdkColormap
*colormap
;
230 graphics_context
= m_pCanvas
->style
->fg_gc
[GTK_WIDGET_STATE(m_pCanvas
)];
231 colormap
= gdk_colormap_get_system();
237 SET_COLOR(iFillColour
);
239 cairo_arc(cr
, iCX
, iCY
, iR
, 0, 2*M_PI
);
242 gdk_draw_arc(m_pOffscreenBuffer
, graphics_context
, true, iCX
- iR
, iCY
- iR
, 2*iR
, 2*iR
, 0, 23040);
248 cairo_set_line_width(cr
, iThickness
);
249 cairo_arc(cr
, iCX
, iCY
, iR
, 0, 2*M_PI
);
252 gdk_gc_set_line_attributes(graphics_context
, iThickness
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
253 gdk_draw_arc(m_pOffscreenBuffer
, graphics_context
, false, iCX
- iR
, iCY
- iR
, 2*iR
, 2*iR
, 0, 23040);
259 void CCanvas::Polygon(Dasher::CDasherScreen::point
*Points
, int Number
, int Colour
, int iWidth
) {
261 if(iWidth
== 1) // This is to make it work propely on Windows
266 GdkGC
*graphics_context
;
267 GdkColormap
*colormap
;
269 graphics_context
= m_pCanvas
->style
->fg_gc
[GTK_WIDGET_STATE(m_pCanvas
)];
270 colormap
= gdk_colormap_get_system();
277 cairo_move_to(cr
, Points
[0].x
, Points
[0].y
);
278 for (int i
=1; i
< Number
; i
++)
279 cairo_line_to(cr
, Points
[i
].x
, Points
[i
].y
);
280 cairo_close_path(cr
);
283 GdkPoint
*gdk_points
;
284 gdk_points
= (GdkPoint
*) g_malloc(Number
* sizeof(GdkPoint
));
286 for(int i
= 0; i
< Number
; i
++) {
287 gdk_points
[i
].x
= Points
[i
].x
;
288 gdk_points
[i
].y
= Points
[i
].y
;
291 gdk_gc_set_line_attributes(graphics_context
, iWidth
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
292 gdk_draw_polygon(m_pOffscreenBuffer
, graphics_context
, TRUE
, gdk_points
, Number
);
299 void CCanvas::Polyline(Dasher::CDasherScreen::point
*Points
, int Number
, int iWidth
, int Colour
) {
301 // FIXME - combine this with polygon?
305 if(iWidth
== 1) // This is to make it work propely on Windows
308 GdkGC
*graphics_context
;
309 GdkColormap
*colormap
;
311 graphics_context
= m_pCanvas
->style
->fg_gc
[GTK_WIDGET_STATE(m_pCanvas
)];
312 colormap
= gdk_colormap_get_system();
319 cairo_set_line_width(cr
, iWidth
);
320 cairo_move_to(cr
, Points
[0].x
+.5, Points
[0].y
+.5);
321 for (int i
=1; i
< Number
; i
++)
322 cairo_line_to(cr
, Points
[i
].x
+.5, Points
[i
].y
+.5);
325 GdkPoint
*gdk_points
;
326 gdk_points
= (GdkPoint
*) g_malloc(Number
* sizeof(GdkPoint
));
328 gdk_gc_set_line_attributes(graphics_context
, iWidth
, GDK_LINE_SOLID
, GDK_CAP_ROUND
, GDK_JOIN_ROUND
);
330 for(int i
= 0; i
< Number
; i
++) {
331 gdk_points
[i
].x
= Points
[i
].x
;
332 gdk_points
[i
].y
= Points
[i
].y
;
335 gdk_draw_lines(m_pOffscreenBuffer
, graphics_context
, gdk_points
, Number
);
342 void CCanvas::DrawString(const std::string
&String
, int x1
, int y1
, int size
) {
345 GdkGC
*graphics_context
;
346 GdkColormap
*colormap
;
348 graphics_context
= m_pCanvas
->style
->fg_gc
[GTK_WIDGET_STATE(m_pCanvas
)];
349 colormap
= gdk_colormap_get_system();
356 PangoLayout
*pLayout(m_pPangoCache
->GetLayout(cr
, String
, size
));
358 PangoLayout
*pLayout(m_pPangoCache
->GetLayout(GTK_WIDGET(m_pCanvas
), String
, size
));
361 pango_layout_get_pixel_extents(pLayout
, m_pPangoInk
, NULL
);
364 cairo_translate(cr
, x1
, y1
-(int)m_pPangoInk
->height
/2);
365 pango_cairo_show_layout(cr
, pLayout
);
367 gdk_draw_layout(m_pOffscreenBuffer
, graphics_context
, x1
, y1
- m_pPangoInk
->height
/ 2, pLayout
);
373 void CCanvas::TextSize(const std::string
&String
, int *Width
, int *Height
, int size
) {
376 PangoLayout
*pLayout(m_pPangoCache
->GetLayout(cr
, String
, size
));
378 PangoLayout
*pLayout(m_pPangoCache
->GetLayout(GTK_WIDGET(m_pCanvas
), String
, size
));
380 pango_layout_get_pixel_extents(pLayout
, m_pPangoInk
, NULL
);
382 *Width
= m_pPangoInk
->width
;
383 *Height
= m_pPangoInk
->height
;
386 void CCanvas::SendMarker(int iMarker
) {
389 case 0: // Switch to display buffer
390 m_pOffscreenBuffer
= m_pDisplayBuffer
;
395 case 1: // Switch to decorations buffer
396 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
);
397 m_pOffscreenBuffer
= m_pDecorationBuffer
;
405 bool CCanvas::ExposeEvent(GtkWidget
*pWidget
, GdkEventExpose
*pEvent
) {
406 gdk_draw_drawable(m_pCanvas
->window
, m_pCanvas
->style
->fg_gc
[GTK_WIDGET_STATE(m_pCanvas
)], m_pOnscreenBuffer
, pEvent
->area
.x
, pEvent
->area
.y
, pEvent
->area
.x
, pEvent
->area
.y
, pEvent
->area
.width
, pEvent
->area
.height
);
410 void CCanvas::SetColourScheme(const Dasher::CCustomColours
*Colours
) {
411 int iNumColours(Colours
->GetNumColours());
415 delete[] cairo_colours
;
416 cairo_colours
= new my_cairo_colour_t
[iNumColours
];
420 colours
= new GdkColor
[iNumColours
];
423 for(int i
= 0; i
< iNumColours
; i
++) {
425 cairo_colours
[i
].r
= Colours
->GetRed(i
) / 255.0;
426 cairo_colours
[i
].g
= Colours
->GetGreen(i
) / 255.0;
427 cairo_colours
[i
].b
= Colours
->GetBlue(i
) / 255.0;
430 colours
[i
].red
=Colours
->GetRed(i
)*257;
431 colours
[i
].green
=Colours
->GetGreen(i
)*257;
432 colours
[i
].blue
=Colours
->GetBlue(i
)*257;
437 bool CCanvas::GetCanvasSize(GdkRectangle
*pRectangle
)
439 if ((pRectangle
== NULL
) || (m_pCanvas
== NULL
))
442 // Using gtk_window_get_frame_extents() only seems to return the position
443 // and size of the parent Dasher window. So we'll get the widgets position
444 // and use its size to determine the bounding rectangle.
448 gdk_window_get_position(m_pCanvas
->window
, &iX
, &iY
);
452 pRectangle
->width
= m_iWidth
;
453 pRectangle
->height
= m_iHeight
;
458 extern "C" gint
canvas_expose_event(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
) {
459 return ((CCanvas
*)data
)->ExposeEvent(widget
, event
);