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