Mercurial > pidgin
comparison src/gtkwhiteboard.c @ 11475:7fab28c991f3
[gaim-migrate @ 13717]
merging gaim-doodle/whiteboard/whatever you like to call it.
Needs some cleanups and doxygen comments, but has basic functionality
committer: Tailor Script <tailor@pidgin.im>
author | Gary Kramlich <grim@reaperworld.com> |
---|---|
date | Fri, 09 Sep 2005 04:40:21 +0000 |
parents | |
children | 4539174a88bd |
comparison
equal
deleted
inserted
replaced
11474:7e9635b73ed6 | 11475:7fab28c991f3 |
---|---|
1 /* | |
2 * gaim | |
3 * | |
4 * Gaim is the legal property of its developers, whose names are too numerous | |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 * | |
22 */ | |
23 | |
24 // INCLUDES ============================================================================================ | |
25 | |
26 #include <stdlib.h> | |
27 | |
28 #include "blist.h" | |
29 | |
30 #include "gtkwhiteboard.h" | |
31 | |
32 // GLOBALS ============================================================================================= | |
33 | |
34 //GList *buttonList = NULL; | |
35 | |
36 //GdkColor DefaultColor[PALETTE_NUM_COLORS]; | |
37 | |
38 static gboolean LocalShutdownRequest; | |
39 | |
40 static int LastX; // Tracks last position of the mouse when drawing | |
41 static int LastY; | |
42 static int MotionCount; // Tracks how many brush motions made | |
43 static int BrushState = BRUSH_STATE_UP; | |
44 | |
45 static GaimWhiteboardUiOps ui_ops = | |
46 { | |
47 gaim_gtk_whiteboard_create, | |
48 gaim_gtk_whiteboard_destroy, | |
49 gaim_gtk_whiteboard_set_dimensions, | |
50 gaim_gtk_whiteboard_draw_brush_point, | |
51 gaim_gtk_whiteboard_draw_brush_line, | |
52 gaim_gtk_whiteboard_clear | |
53 }; | |
54 | |
55 // FUNCTIONS ============================================================================================ | |
56 | |
57 GaimWhiteboardUiOps *gaim_gtk_whiteboard_get_ui_ops( void ) | |
58 { | |
59 return( &ui_ops ); | |
60 } | |
61 | |
62 // ------------------------------------------------------------------------------------------------------ | |
63 | |
64 void gaim_gtk_whiteboard_create( GaimWhiteboard *wb ) | |
65 { | |
66 //g_print( "gaim_gtk_whiteboard_create()\n" ); | |
67 | |
68 int i; | |
69 | |
70 GtkWidget *window; | |
71 GtkWidget *drawing_area; | |
72 | |
73 GtkWidget *hbox_palette; | |
74 GtkWidget *vbox_palette_above_canvas_and_controls; | |
75 GtkWidget *hbox_canvas_and_controls; | |
76 GtkWidget *vbox_controls; | |
77 | |
78 // -------------------------- | |
79 // |[][][][palette[][][][][]| | |
80 // |------------------------| | |
81 // | canvas | con | | |
82 // | | trol| | |
83 // | | s | | |
84 // | | | | |
85 // | | | | |
86 // -------------------------- | |
87 | |
88 GtkWidget *clear_button; | |
89 GtkWidget *save_button; | |
90 | |
91 GtkWidget *palette_color_box[PALETTE_NUM_COLORS]; | |
92 GdkPixbuf *palette_color_area[PALETTE_NUM_COLORS]; | |
93 | |
94 GaimGtkWhiteboard *gtkwb = g_new0( GaimGtkWhiteboard, 1 ); | |
95 gtkwb->wb = wb; | |
96 wb->ui_data = gtkwb; | |
97 | |
98 // Get dimensions (default?) for the whiteboard canvas | |
99 if( wb->prpl_ops && wb->prpl_ops->get_dimensions ) | |
100 wb->prpl_ops->get_dimensions( wb, >kwb->width, >kwb->height ); | |
101 | |
102 window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); | |
103 gtkwb->window = window; | |
104 gtk_widget_set_name( window, wb->who ); | |
105 | |
106 // Try and set window title as the name of the buddy, else just use their username | |
107 const char *window_title = gaim_contact_get_alias( gaim_buddy_get_contact( gaim_find_buddy( wb->account, wb->who ) ) ); | |
108 if( window_title ) | |
109 gtk_window_set_title( ( GtkWindow* )( window ), window_title ); | |
110 else | |
111 gtk_window_set_title( ( GtkWindow* )( window ), wb->who ); | |
112 | |
113 gtk_window_set_resizable( ( GtkWindow* )( window ), FALSE ); | |
114 | |
115 g_signal_connect( G_OBJECT( window ), "destroy", | |
116 G_CALLBACK( gaim_gtk_whiteboard_exit ), ( gpointer )( gtkwb ) ); | |
117 | |
118 // Create vertical box to place palette above the canvas and controls | |
119 vbox_palette_above_canvas_and_controls = gtk_vbox_new( FALSE, 0 ); | |
120 gtk_container_add( GTK_CONTAINER( window ), vbox_palette_above_canvas_and_controls ); | |
121 gtk_widget_show( vbox_palette_above_canvas_and_controls ); | |
122 | |
123 // Create horizontal box for the palette and all its entries | |
124 hbox_palette = gtk_hbox_new( FALSE, 0 ); | |
125 gtk_container_add( GTK_CONTAINER( vbox_palette_above_canvas_and_controls ), hbox_palette ); | |
126 gtk_widget_show( hbox_palette ); | |
127 | |
128 // Create horizontal box to seperate the canvas from the controls | |
129 hbox_canvas_and_controls = gtk_hbox_new( FALSE, 0 ); | |
130 gtk_container_add( GTK_CONTAINER( vbox_palette_above_canvas_and_controls ), hbox_canvas_and_controls ); | |
131 gtk_widget_show( hbox_canvas_and_controls ); | |
132 | |
133 for( i = 0; i < PALETTE_NUM_COLORS; i++ ) | |
134 { | |
135 //palette_color_area[i] = | |
136 | |
137 palette_color_box[i] = gtk_image_new_from_pixbuf( NULL ); | |
138 gtk_widget_set_size_request( palette_color_box[i], gtkwb->width / PALETTE_NUM_COLORS ,32 ); | |
139 gtk_container_add( GTK_CONTAINER( hbox_palette ), palette_color_box[i] ); | |
140 | |
141 | |
142 | |
143 gtk_widget_show( palette_color_box[i] ); | |
144 } | |
145 | |
146 // Create the drawing area | |
147 drawing_area = gtk_drawing_area_new(); | |
148 gtkwb->drawing_area = drawing_area; | |
149 gtk_widget_set_size_request( GTK_WIDGET( drawing_area ), gtkwb->width, gtkwb->height ); | |
150 gtk_box_pack_start( GTK_BOX( hbox_canvas_and_controls ), drawing_area, TRUE, TRUE, 8 ); | |
151 | |
152 gtk_widget_show( drawing_area ); | |
153 | |
154 // Signals used to handle backing pixmap | |
155 g_signal_connect( G_OBJECT( drawing_area ), "expose_event", | |
156 G_CALLBACK( gaim_gtk_whiteboard_expose_event ), ( gpointer )( gtkwb ) ); | |
157 | |
158 g_signal_connect( G_OBJECT( drawing_area ), "configure_event", | |
159 G_CALLBACK( gaim_gtk_whiteboard_configure_event ), ( gpointer )( gtkwb ) ); | |
160 | |
161 // Event signals | |
162 g_signal_connect( G_OBJECT( drawing_area ), "button_press_event", | |
163 G_CALLBACK( gaim_gtk_whiteboard_brush_down ), ( gpointer )( gtkwb ) ); | |
164 | |
165 g_signal_connect( G_OBJECT( drawing_area ), "motion_notify_event", | |
166 G_CALLBACK( gaim_gtk_whiteboard_brush_motion ), ( gpointer )( gtkwb ) ); | |
167 | |
168 g_signal_connect( G_OBJECT( drawing_area ), "button_release_event", | |
169 G_CALLBACK( gaim_gtk_whiteboard_brush_up ), ( gpointer )( gtkwb ) ); | |
170 | |
171 gtk_widget_set_events( drawing_area, GDK_EXPOSURE_MASK | | |
172 GDK_LEAVE_NOTIFY_MASK | | |
173 GDK_BUTTON_PRESS_MASK | | |
174 GDK_POINTER_MOTION_MASK | | |
175 GDK_BUTTON_RELEASE_MASK | | |
176 GDK_POINTER_MOTION_HINT_MASK ); | |
177 | |
178 // Create vertical box to contain the controls | |
179 vbox_controls = gtk_vbox_new( FALSE, 0 ); | |
180 gtk_container_add( GTK_CONTAINER( hbox_canvas_and_controls ), vbox_controls ); | |
181 gtk_widget_show( vbox_controls ); | |
182 | |
183 // Add a clear button | |
184 clear_button = gtk_button_new_with_label( "Clear" ); | |
185 gtk_widget_set_size_request( clear_button, 96 ,32 ); | |
186 gtk_box_pack_start( GTK_BOX( vbox_controls ), clear_button, FALSE, FALSE, 0 ); | |
187 gtk_widget_show( clear_button ); | |
188 | |
189 g_signal_connect( G_OBJECT( clear_button ), "clicked", | |
190 G_CALLBACK( gaim_gtk_whiteboard_button_clear_press ), ( gpointer )( gtkwb ) ); | |
191 | |
192 // Add a save button | |
193 save_button = gtk_button_new_with_label( "Save" ); | |
194 gtk_widget_set_size_request( save_button, 96 ,32 ); | |
195 gtk_box_pack_start( GTK_BOX( vbox_controls ), save_button, FALSE, FALSE, 8 ); | |
196 gtk_widget_show( save_button ); | |
197 | |
198 g_signal_connect( G_OBJECT( save_button ), "clicked", | |
199 G_CALLBACK( gaim_gtk_whiteboard_button_save_press ), ( gpointer )( gtkwb ) ); | |
200 | |
201 // Make all this (window) visible | |
202 gtk_widget_show( window ); | |
203 | |
204 gaim_gtk_whiteboard_set_canvas_as_icon( gtkwb ); | |
205 | |
206 // TODO Specific protocol/whiteboard assignment here? Needs a UI Op? | |
207 // Set default brush size and color | |
208 //ds->brush_size = DOODLE_BRUSH_MEDIUM; | |
209 //ds->brush_color = 0; // black | |
210 } | |
211 | |
212 // ------------------------------------------------------------------------------------------------------ | |
213 | |
214 void gaim_gtk_whiteboard_destroy( GaimWhiteboard *wb ) | |
215 { | |
216 //g_print( "gaim_gtk_whiteboard_destroy()\n" ); | |
217 | |
218 GaimGtkWhiteboard *gtkwb = wb->ui_data; | |
219 | |
220 // TODO Ask if user wants to save picture before the session is closed | |
221 | |
222 // Clear graphical memory | |
223 if( gtkwb->pixmap ) | |
224 { | |
225 //g_print( "---gtkwb->pixmap = %p\n", gtkwb->pixmap ); | |
226 g_object_unref( gtkwb->pixmap ); | |
227 gtkwb->pixmap = NULL; | |
228 } | |
229 | |
230 if( gtkwb->window ) | |
231 { | |
232 //g_print( "---gtkwb->window = %p\n", gtkwb->window ); | |
233 gtk_widget_destroy( gtkwb->window ); | |
234 gtkwb->window = NULL; | |
235 } | |
236 } | |
237 | |
238 // ------------------------------------------------------------------------------------------------------ | |
239 | |
240 void gaim_gtk_whiteboard_exit( GtkWidget *widget, gpointer data ) | |
241 { | |
242 //g_print( "gaim_gtk_whiteboard_exit()\n" ); | |
243 | |
244 GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); | |
245 GaimWhiteboard *wb = gtkwb->wb; | |
246 | |
247 if( gtkwb->window && gtkwb->pixmap ) | |
248 { | |
249 LocalShutdownRequest = TRUE; | |
250 | |
251 //g_print( "---gtkwb->window = %p\n", gtkwb->window ); | |
252 gaim_gtk_whiteboard_destroy( wb ); | |
253 } | |
254 else | |
255 LocalShutdownRequest = FALSE; | |
256 | |
257 if( gtkwb ) | |
258 { | |
259 //g_print( "---gtkwb = %p\n", gtkwb ); | |
260 g_free( gtkwb ); | |
261 | |
262 gtkwb = NULL; | |
263 wb->ui_data = NULL; | |
264 } | |
265 | |
266 // Destroy whiteboard core, if the local user exited the whiteboard window | |
267 if( wb && LocalShutdownRequest ) | |
268 { | |
269 //g_print( "---wb = %p\n", wb ); | |
270 gaim_whiteboard_destroy( wb ); | |
271 wb = NULL; | |
272 } | |
273 } | |
274 | |
275 // ------------------------------------------------------------------------------------------------------ | |
276 /* | |
277 // Whiteboard start button on conversation window (move this code to gtkconv? and use new prpl_info member?) | |
278 void gaim_gtkwhiteboard_button_start_press( GtkButton *button, gpointer data ) | |
279 { | |
280 GaimConversation *conv = data; | |
281 GaimAccount *account = gaim_conversation_get_account( conv ); | |
282 GaimConnection *gc = gaim_account_get_connection( account ); | |
283 char *to = ( char* )( gaim_conversation_get_name( conv ) ); | |
284 | |
285 // Only handle this if local client requested Doodle session (else local client would have sent one) | |
286 GaimWhiteboard *wb = gaim_whiteboard_get( account, to ); | |
287 | |
288 // Write a local message to this conversation showing that | |
289 // a request for a Doodle session has been made | |
290 gaim_conv_im_write( GAIM_CONV_IM( conv ), "", _("Sent Doodle request."), | |
291 GAIM_MESSAGE_NICK | GAIM_MESSAGE_RECV, time( NULL ) ); | |
292 | |
293 yahoo_doodle_command_send_request( gc, to ); | |
294 yahoo_doodle_command_send_ready( gc, to ); | |
295 | |
296 // Insert this 'session' in the list. At this point, it's only a requested session. | |
297 wb = gaim_whiteboard_create( account, to, DOODLE_STATE_REQUESTING ); | |
298 } | |
299 */ | |
300 // ------------------------------------------------------------------------------------------------------ | |
301 | |
302 gboolean gaim_gtk_whiteboard_configure_event( GtkWidget *widget, GdkEventConfigure *event, gpointer data ) | |
303 { | |
304 //g_print( "gaim_gtk_whiteboard_configure_event | %s\n", ds->who ); | |
305 | |
306 GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); | |
307 | |
308 GdkPixmap *pixmap = gtkwb->pixmap; | |
309 | |
310 if( pixmap ) | |
311 g_object_unref( pixmap ); | |
312 | |
313 pixmap = gdk_pixmap_new( widget->window, | |
314 widget->allocation.width, | |
315 widget->allocation.height, | |
316 -1 ); | |
317 | |
318 gtkwb->pixmap = pixmap; | |
319 | |
320 gdk_draw_rectangle( pixmap, | |
321 widget->style->white_gc, | |
322 TRUE, | |
323 0, 0, | |
324 widget->allocation.width, | |
325 widget->allocation.height ); | |
326 | |
327 return( TRUE ); | |
328 } | |
329 | |
330 // ------------------------------------------------------------------------------------------------------ | |
331 | |
332 gboolean gaim_gtk_whiteboard_expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer data ) | |
333 { | |
334 //g_print( "gaim_gtk_whiteboard_expose_event | %s\n", ds->who ); | |
335 | |
336 GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); | |
337 GdkPixmap *pixmap = gtkwb->pixmap; | |
338 | |
339 gdk_draw_drawable( widget->window, | |
340 widget->style->fg_gc[GTK_WIDGET_STATE( widget )], | |
341 pixmap, | |
342 event->area.x, event->area.y, | |
343 event->area.x, event->area.y, | |
344 event->area.width, event->area.height ); | |
345 | |
346 return( FALSE ); | |
347 } | |
348 | |
349 // ------------------------------------------------------------------------------------------------------ | |
350 | |
351 gboolean gaim_gtk_whiteboard_brush_down( GtkWidget *widget, GdkEventButton *event, gpointer data ) | |
352 { | |
353 GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); | |
354 //g_print( "gaim_gtk_whiteboard_brush_down | %s\n", gtkwb->wb->who ); | |
355 GdkPixmap *pixmap = gtkwb->pixmap; | |
356 | |
357 GaimWhiteboard *wb = gtkwb->wb; | |
358 GList *draw_list = wb->draw_list; | |
359 | |
360 int *x0 = NULL; | |
361 int *y0 = NULL; | |
362 | |
363 if( BrushState != BRUSH_STATE_UP ) | |
364 { | |
365 // Potential double-click DOWN to DOWN? | |
366 | |
367 g_print( "***Bad brush state transition %d to DOWN\n", BrushState ); | |
368 | |
369 BrushState = BRUSH_STATE_DOWN; | |
370 | |
371 //return( FALSE ); | |
372 } | |
373 | |
374 BrushState = BRUSH_STATE_DOWN; | |
375 | |
376 if( event->button == 1 && pixmap != NULL ) | |
377 { | |
378 // Check if draw_list has contents; if so, clear it | |
379 if( draw_list ) | |
380 draw_list = gaim_whiteboard_draw_list_destroy( draw_list ); | |
381 | |
382 x0 = g_new0( int, 1 ); | |
383 y0 = g_new0( int, 1 ); | |
384 | |
385 *x0 = event->x; | |
386 *y0 = event->y; | |
387 | |
388 // Set tracking variables | |
389 LastX = *x0; | |
390 LastY = *y0; | |
391 | |
392 MotionCount = 0; | |
393 | |
394 draw_list = g_list_append( draw_list, ( gpointer )( x0 ) ); | |
395 draw_list = g_list_append( draw_list, ( gpointer )( y0 ) ); | |
396 | |
397 gaim_gtk_whiteboard_draw_brush_point( gtkwb->wb, | |
398 event->x, event->y, | |
399 0,5 );//gtkwb->brush_color, gtkwb->brush_size ); NOTE temp const prot uiop | |
400 } | |
401 | |
402 wb->draw_list = draw_list; | |
403 | |
404 return( TRUE ); | |
405 } | |
406 | |
407 // ------------------------------------------------------------------------------------------------------ | |
408 | |
409 gboolean gaim_gtk_whiteboard_brush_motion( GtkWidget *widget, GdkEventMotion *event, gpointer data ) | |
410 { | |
411 int x; | |
412 int y; | |
413 int *dx; | |
414 int *dy; | |
415 | |
416 GdkModifierType state; | |
417 | |
418 GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); | |
419 //g_print( "gaim_gtk_whiteboard_brush_motion | %s\n", gtkwb->wb->who ); | |
420 GdkPixmap *pixmap = gtkwb->pixmap; | |
421 | |
422 GaimWhiteboard *wb = gtkwb->wb; | |
423 GList *draw_list = wb->draw_list; | |
424 | |
425 if( event->is_hint ) | |
426 gdk_window_get_pointer( event->window, &x, &y, &state ); | |
427 else | |
428 { | |
429 x = event->x; | |
430 y = event->y; | |
431 state = event->state; | |
432 } | |
433 | |
434 if( state & GDK_BUTTON1_MASK && pixmap != NULL ) | |
435 { | |
436 if( ( BrushState != BRUSH_STATE_DOWN ) && ( BrushState != BRUSH_STATE_MOTION ) ) | |
437 { | |
438 g_print( "***Bad brush state transition %d to MOTION\n", BrushState ); | |
439 | |
440 BrushState = BRUSH_STATE_MOTION; | |
441 | |
442 return( FALSE ); | |
443 } | |
444 BrushState = BRUSH_STATE_MOTION; | |
445 | |
446 dx = g_new0( int, 1 ); | |
447 dy = g_new0( int, 1 ); | |
448 | |
449 *dx = x - LastX; | |
450 *dy = y - LastY; | |
451 | |
452 MotionCount++; | |
453 | |
454 // NOTE 100 is a temporary constant for how many deltas/motions in a stroke (needs UI Ops?) | |
455 if( MotionCount == 100 ) | |
456 { | |
457 draw_list = g_list_append( draw_list, ( gpointer )( dx ) ); | |
458 draw_list = g_list_append( draw_list, ( gpointer )( dy ) ); | |
459 | |
460 // Send draw list to prpl draw_list handler | |
461 if( gtkwb->wb->prpl_ops && gtkwb->wb->prpl_ops->send_draw_list ) | |
462 gtkwb->wb->prpl_ops->send_draw_list( gtkwb->wb, draw_list ); | |
463 | |
464 // The brush stroke is finished, clear the list for another one | |
465 if( draw_list ) | |
466 draw_list = gaim_whiteboard_draw_list_destroy( draw_list ); | |
467 | |
468 int *x0 = g_new0( int, 1 ); | |
469 int *y0 = g_new0( int, 1 ); | |
470 | |
471 *x0 = LastX; | |
472 *y0 = LastY; | |
473 | |
474 // Reset motion tracking | |
475 MotionCount = 0; | |
476 | |
477 draw_list = g_list_append( draw_list, ( gpointer )( x0 ) ); | |
478 draw_list = g_list_append( draw_list, ( gpointer )( y0 ) ); | |
479 | |
480 dx = g_new0( int, 1 ); | |
481 dy = g_new0( int, 1 ); | |
482 | |
483 *dx = x - LastX; | |
484 *dy = y - LastY; | |
485 } | |
486 | |
487 draw_list = g_list_append( draw_list, ( gpointer )( dx ) ); | |
488 draw_list = g_list_append( draw_list, ( gpointer )( dy ) ); | |
489 | |
490 gaim_gtk_whiteboard_draw_brush_line( gtkwb->wb, | |
491 LastX, LastY, | |
492 x, y, | |
493 0, 5 );//gtkwb->brush_color, gtkwb->brush_size ); temp const proto ui ops? | |
494 | |
495 // Set tracking variables | |
496 LastX = x; | |
497 LastY = y; | |
498 } | |
499 | |
500 wb->draw_list = draw_list; | |
501 | |
502 return( TRUE ); | |
503 } | |
504 | |
505 // ------------------------------------------------------------------------------------------------------ | |
506 | |
507 gboolean gaim_gtk_whiteboard_brush_up( GtkWidget *widget, GdkEventButton *event, gpointer data ) | |
508 { | |
509 GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); | |
510 //g_print( "gaim_gtk_whiteboard_brush_up | %s\n", gtkwb->wb->who ); | |
511 GdkPixmap *pixmap = gtkwb->pixmap; | |
512 | |
513 GaimWhiteboard *wb = gtkwb->wb; | |
514 GList *draw_list = wb->draw_list; | |
515 | |
516 if( ( BrushState != BRUSH_STATE_DOWN ) && ( BrushState != BRUSH_STATE_MOTION ) ) | |
517 { | |
518 g_print( "***Bad brush state transition %d to UP\n", BrushState ); | |
519 | |
520 BrushState = BRUSH_STATE_UP; | |
521 | |
522 return( FALSE ); | |
523 } | |
524 BrushState = BRUSH_STATE_UP; | |
525 | |
526 if( event->button == 1 && pixmap != NULL ) | |
527 { | |
528 // If the brush was never moved, express two sets of two deltas | |
529 // That's a 'point,' but not for Yahoo! | |
530 //if( ( event->x == LastX ) && ( event->y == LastY ) ) | |
531 if( MotionCount == 0 ) | |
532 { | |
533 int index; | |
534 | |
535 for( index = 0; index < 2; index++ ) // NOTE Yahoo Doodle specific! | |
536 { | |
537 int *x0 = NULL; | |
538 int *y0 = NULL; | |
539 | |
540 x0 = g_new0( int, 1 ); | |
541 y0 = g_new0( int, 1 ); | |
542 | |
543 draw_list = g_list_append( draw_list, ( gpointer )( x0 ) ); | |
544 draw_list = g_list_append( draw_list, ( gpointer )( y0 ) ); | |
545 } | |
546 } | |
547 //else | |
548 // MotionCount = 0; | |
549 | |
550 // Send draw list to prpl draw_list handler | |
551 if( gtkwb->wb->prpl_ops && gtkwb->wb->prpl_ops->send_draw_list ) | |
552 gtkwb->wb->prpl_ops->send_draw_list( gtkwb->wb, draw_list ); | |
553 | |
554 gaim_gtk_whiteboard_set_canvas_as_icon( gtkwb ); | |
555 | |
556 // The brush stroke is finished, clear the list for another one | |
557 if( draw_list ) | |
558 draw_list = gaim_whiteboard_draw_list_destroy( draw_list ); | |
559 | |
560 wb->draw_list = draw_list; | |
561 } | |
562 | |
563 return( TRUE ); | |
564 } | |
565 | |
566 // ------------------------------------------------------------------------------------------------------ | |
567 | |
568 // void gaim_gtk_whiteboard_draw_brush_point( GtkWidget *widget, GaimGtkWhiteboard *gtkwb, | |
569 // int x, int y, int color, int size ) | |
570 void gaim_gtk_whiteboard_draw_brush_point( GaimWhiteboard *wb, int x, int y, int color, int size ) | |
571 { | |
572 //g_print( "goodle_doodle_session_draw_brush | %s\n", ds->who ); | |
573 | |
574 GaimGtkWhiteboard *gtkwb = wb->ui_data; | |
575 GtkWidget *widget = gtkwb->drawing_area; | |
576 GdkPixmap *pixmap = gtkwb->pixmap; | |
577 | |
578 GdkRectangle update_rect; | |
579 | |
580 update_rect.x = x - size / 2; | |
581 update_rect.y = y - size / 2; | |
582 update_rect.width = size; | |
583 update_rect.height = size; | |
584 | |
585 // Interpret and convert color | |
586 GdkGC *gfx_con = gdk_gc_new( pixmap ); | |
587 GdkColor col; | |
588 | |
589 gaim_gtk_whiteboard_rgb24_to_rgb48( color, &col ); | |
590 | |
591 gdk_gc_set_rgb_fg_color( gfx_con, &col ); | |
592 //gdk_gc_set_rgb_bg_color( gfx_con, &col ); | |
593 | |
594 // NOTE 5 is a size constant for now... this is because of how poorly the gdk_draw_arc draws small circles | |
595 if( size < 5 ) | |
596 { | |
597 // Draw a rectangle/square | |
598 gdk_draw_rectangle( pixmap, | |
599 gfx_con, | |
600 TRUE, | |
601 update_rect.x, update_rect.y, | |
602 update_rect.width, update_rect.height ); | |
603 } | |
604 else | |
605 { | |
606 // Draw a circle | |
607 gdk_draw_arc( pixmap, | |
608 gfx_con, | |
609 TRUE, | |
610 update_rect.x, update_rect.y, | |
611 update_rect.width, update_rect.height, | |
612 0, FULL_CIRCLE_DEGREES ); | |
613 } | |
614 | |
615 gtk_widget_queue_draw_area( widget, | |
616 update_rect.x, update_rect.y, | |
617 update_rect.width, update_rect.height ); | |
618 | |
619 gdk_gc_unref( gfx_con ); | |
620 } | |
621 | |
622 // ------------------------------------------------------------------------------------------------------ | |
623 // Uses Bresenham's algorithm (as provided by Wikipedia) | |
624 // void gaim_gtk_whiteboard_draw_brush_line( GtkWidget *widget, GaimGtkWhiteboard *gtkwb, | |
625 // int x0, int y0, int x1, int y1, int color, int size ) | |
626 void gaim_gtk_whiteboard_draw_brush_line( GaimWhiteboard *wb, int x0, int y0, int x1, int y1, int color, int size ) | |
627 { | |
628 int temp; | |
629 | |
630 int xstep; | |
631 int ystep; | |
632 | |
633 gboolean steep = abs( y1 - y0 ) > abs( x1 - x0 ); | |
634 | |
635 if( steep ) | |
636 { | |
637 temp = x0; x0 = y0; y0 = temp; | |
638 temp = x1; x1 = y1; y1 = temp; | |
639 } | |
640 | |
641 int dx = abs( x1 - x0 ); | |
642 int dy = abs( y1 - y0 ); | |
643 | |
644 int error = 0; | |
645 int derror = dy; | |
646 | |
647 int x = x0; | |
648 int y = y0; | |
649 | |
650 if( x0 < x1 ) | |
651 xstep = 1; | |
652 else | |
653 xstep = -1; | |
654 | |
655 if( y0 < y1 ) | |
656 ystep = 1; | |
657 else | |
658 ystep = -1; | |
659 | |
660 if( steep ) | |
661 gaim_gtk_whiteboard_draw_brush_point( wb, y, x, color, size ); | |
662 else | |
663 gaim_gtk_whiteboard_draw_brush_point( wb, x, y, color, size ); | |
664 | |
665 while( x != x1 ) | |
666 { | |
667 x = x + xstep; | |
668 error = error + derror; | |
669 | |
670 if( ( error * 2 ) >= dx ) | |
671 { | |
672 y = y + ystep; | |
673 error = error - dx; | |
674 } | |
675 | |
676 if( steep ) | |
677 gaim_gtk_whiteboard_draw_brush_point( wb, y, x, color, size ); | |
678 else | |
679 gaim_gtk_whiteboard_draw_brush_point( wb, x, y, color, size ); | |
680 } | |
681 } | |
682 | |
683 // ------------------------------------------------------------------------------------------------------ | |
684 | |
685 void gaim_gtk_whiteboard_set_dimensions( GaimWhiteboard *wb, int width, int height ) | |
686 { | |
687 GaimGtkWhiteboard *gtkwb = wb->ui_data; | |
688 | |
689 gtkwb->width = width; | |
690 gtkwb->height = height; | |
691 } | |
692 | |
693 // ------------------------------------------------------------------------------------------------------ | |
694 | |
695 void gaim_gtk_whiteboard_clear( GaimWhiteboard *wb ) | |
696 { | |
697 GaimGtkWhiteboard *gtkwb = wb->ui_data; | |
698 GdkPixmap *pixmap = gtkwb->pixmap; | |
699 GtkWidget *drawing_area = gtkwb->drawing_area; | |
700 | |
701 gdk_draw_rectangle( pixmap, | |
702 drawing_area->style->white_gc, | |
703 TRUE, | |
704 0, 0, | |
705 drawing_area->allocation.width, drawing_area->allocation.height ); | |
706 | |
707 gtk_widget_queue_draw_area( drawing_area, | |
708 0, 0, | |
709 drawing_area->allocation.width, drawing_area->allocation.height ); | |
710 } | |
711 | |
712 // ------------------------------------------------------------------------------------------------------ | |
713 | |
714 void gaim_gtk_whiteboard_button_clear_press( GtkWidget *widget, gpointer data ) | |
715 { | |
716 GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); | |
717 | |
718 gaim_gtk_whiteboard_clear( gtkwb->wb ); | |
719 | |
720 gaim_gtk_whiteboard_set_canvas_as_icon( gtkwb ); | |
721 | |
722 // Do protocol specific clearing procedures | |
723 if( gtkwb->wb->prpl_ops && gtkwb->wb->prpl_ops->clear ) | |
724 gtkwb->wb->prpl_ops->clear( gtkwb->wb ); | |
725 } | |
726 | |
727 // ------------------------------------------------------------------------------------------------------ | |
728 | |
729 void gaim_gtk_whiteboard_button_save_press( GtkWidget *widget, gpointer data ) | |
730 { | |
731 GaimGtkWhiteboard *gtkwb = ( GaimGtkWhiteboard* )( data ); | |
732 GdkPixbuf *pixbuf; | |
733 | |
734 GtkWidget *dialog; | |
735 | |
736 dialog = gtk_file_chooser_dialog_new ("Save File", | |
737 GTK_WINDOW(gtkwb->window), | |
738 GTK_FILE_CHOOSER_ACTION_SAVE, | |
739 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
740 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, | |
741 NULL ); | |
742 | |
743 //gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER( dialog ), (gboolean)(TRUE) ); | |
744 | |
745 // if( user_edited_a_new_document ) | |
746 { | |
747 // gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( dialog ), default_folder_for_saving ); | |
748 gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER( dialog ), "whiteboard.jpg" ); | |
749 } | |
750 // else | |
751 // gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), filename_for_existing_document); | |
752 | |
753 int result = gtk_dialog_run( GTK_DIALOG( dialog ) ); | |
754 | |
755 if( result == GTK_RESPONSE_ACCEPT ) | |
756 { | |
757 char *filename; | |
758 | |
759 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER( dialog ) ); | |
760 | |
761 gtk_widget_destroy( dialog ); | |
762 | |
763 // Makes an icon from the whiteboard's canvas 'image' | |
764 pixbuf = gdk_pixbuf_get_from_drawable( NULL, | |
765 ( GdkDrawable* )( gtkwb->pixmap ), | |
766 gdk_drawable_get_colormap( gtkwb->pixmap ), | |
767 0, 0, | |
768 0, 0, | |
769 gtkwb->width, gtkwb->height ); | |
770 | |
771 if( gdk_pixbuf_save( pixbuf, | |
772 filename, | |
773 "jpeg", | |
774 NULL, | |
775 "quality", | |
776 "100", | |
777 NULL ) ) | |
778 g_print( "File Saved...\n" ); | |
779 else | |
780 g_print( "File not Saved... Error\n" ); | |
781 } | |
782 else | |
783 if( result == GTK_RESPONSE_CANCEL ) | |
784 { | |
785 gtk_widget_destroy( dialog ); | |
786 | |
787 g_print( "File not Saved... Canceled\n" ); | |
788 } | |
789 } | |
790 | |
791 // ------------------------------------------------------------------------------------------------------ | |
792 | |
793 void gaim_gtk_whiteboard_set_canvas_as_icon( GaimGtkWhiteboard *gtkwb ) | |
794 { | |
795 GdkPixbuf *pixbuf; | |
796 | |
797 // Makes an icon from the whiteboard's canvas 'image' | |
798 pixbuf = gdk_pixbuf_get_from_drawable( NULL, | |
799 ( GdkDrawable* )( gtkwb->pixmap ), | |
800 gdk_drawable_get_colormap( gtkwb->pixmap ), | |
801 0, 0, | |
802 0, 0, | |
803 gtkwb->width, gtkwb->height ); | |
804 | |
805 gtk_window_set_icon( ( GtkWindow* )( gtkwb->window ), pixbuf ); | |
806 } | |
807 | |
808 // ------------------------------------------------------------------------------------------------------ | |
809 | |
810 void gaim_gtk_whiteboard_rgb24_to_rgb48( int color_rgb, GdkColor *color ) | |
811 { | |
812 color->red = ( color_rgb >> 8 ) | 0xFF; | |
813 color->green = ( color_rgb & 0xFF00 ) | 0xFF; | |
814 color->blue = ( ( color_rgb & 0xFF ) << 8 ) | 0xFF; | |
815 } | |
816 | |
817 // ------------------------------------------------------------------------------------------------------ | |
818 |