Add es and gl locales for gpicview.
[lxde/gpicview.git] / src / mainwin.cpp
CommitLineData
1d48a247
HJYP
1/***************************************************************************
2 * Copyright (C) 2007 by PCMan (Hong Jen Yee) *
3 * pcman.tw@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
24
25#include "mainwin.h"
26#include <new>
27#include <glib/gi18n.h>
28#include <glib/gstdio.h>
29#include <gdk/gdkkeysyms.h>
30
0ed1aa41 31#include <unistd.h>
1d48a247
HJYP
32#include <string.h>
33#include <errno.h>
da8bd946 34#include <math.h>
1d48a247 35
9c52ae58 36#include "image-view.h"
1d48a247
HJYP
37#include "working-area.h"
38
39gpointer MainWin::_parent_class = NULL;
40
41// For drag & drop
42GtkTargetEntry drop_targets[] =
43{
44 {"text/uri-list", 0, 0},
45 {"text/plain", 0, 1}
46};
47
48// Begin of GObject-related stuff
49
50void MainWin::_init( GTypeInstance *instance, gpointer g_class )
51{
52 ::new( instance ) MainWin(); // placement new
53}
54
55GType MainWin::_get_type()
56{
57 static GType g_define_type_id = 0;
58 if (G_UNLIKELY (g_define_type_id == 0))
59 {
60 static const GTypeInfo g_define_type_info = {
61 sizeof (MainWin::Class),
62 (GBaseInitFunc) NULL,
63 (GBaseFinalizeFunc) NULL,
64 (GClassInitFunc) MainWin::_class_init,
65 (GClassFinalizeFunc) NULL,
66 NULL, /* class_data */
67 sizeof (MainWin),
68 0, /* n_preallocs */
69 (GInstanceInitFunc) MainWin::_init,
70 };
71 g_define_type_id = g_type_register_static (GTK_TYPE_WINDOW, "MainWin", &g_define_type_info, (GTypeFlags)0);
72 }
73 return g_define_type_id;
74}
75
76void MainWin::_class_init( MainWin::Class* klass )
77{
78 _parent_class = g_type_class_peek_parent (klass);
79
80 GObjectClass * obj_class;
81 GtkWidgetClass *widget_class;
82
83 obj_class = ( GObjectClass * ) klass;
84// obj_class->set_property = _set_property;
85// obj_class->get_property = _get_property;
86 obj_class->finalize = _finalize;
87
88 widget_class = GTK_WIDGET_CLASS ( klass );
89 widget_class->delete_event = on_delete_event;
90 widget_class->size_allocate = on_size_allocate;
91 widget_class->key_press_event = on_key_press_event;
92}
93
94void MainWin::_finalize(GObject *self)
95{
96 ((MainWin*)self)->~MainWin();
97}
98
99// End of GObject-related stuff
100
101MainWin::MainWin()
102{
103 gtk_window_set_title( (GtkWindow*)this, _("Image Viewer"));
104 gtk_window_set_icon_from_file( (GtkWindow*)this, PACKAGE_DATA_DIR"/pixmaps/gpicview.png", NULL );
105 gtk_window_set_default_size( (GtkWindow*)this, 640, 480 );
106
107 GtkWidget* box = gtk_vbox_new( FALSE, 0 );
108 gtk_container_add( (GtkContainer*)this, box);
109
110 // image area
111 evt_box = gtk_event_box_new();
5bfec971 112 GTK_WIDGET_SET_FLAGS( evt_box, GTK_CAN_FOCUS );
1d48a247
HJYP
113 gtk_widget_add_events( evt_box,
114 GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|
115 GDK_BUTTON_RELEASE_MASK|GDK_SCROLL_MASK );
116 g_signal_connect( evt_box, "button-press-event", G_CALLBACK(on_button_press), this );
117 g_signal_connect( evt_box, "button-release-event", G_CALLBACK(on_button_release), this );
118 g_signal_connect( evt_box, "motion-notify-event", G_CALLBACK(on_mouse_move), this );
5bfec971
HJYP
119 g_signal_connect( evt_box, "scroll-event", G_CALLBACK(on_scroll_event), this );
120 // Set bg color to white
121 GdkColor white = {0, 65535, 65535, 65535};
122 gtk_widget_modify_bg( evt_box, GTK_STATE_NORMAL, &white );
1d48a247 123
9c52ae58
HJYP
124 img_view = ImageView::create();
125 gtk_container_add( (GtkContainer*)evt_box, (GtkWidget*)img_view);
1d48a247 126
2c34ffe0
HJYP
127 const char scroll_style[]=
128 "style \"gpicview-scroll\" {"
129 "GtkScrolledWindow::scrollbar-spacing=0"
130 "}"
131 "class \"GtkScrolledWindow\" style \"gpicview-scroll\"";
132 gtk_rc_parse_string( scroll_style );
1d48a247
HJYP
133 scroll = gtk_scrolled_window_new( NULL, NULL );
134 gtk_scrolled_window_set_shadow_type( (GtkScrolledWindow*)scroll, GTK_SHADOW_NONE );
135 gtk_scrolled_window_set_policy((GtkScrolledWindow*)scroll,
136 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
137 GtkAdjustment *hadj, *vadj;
138 hadj = gtk_scrolled_window_get_hadjustment((GtkScrolledWindow*)scroll);
139 hadj->page_increment = 10;
140 gtk_adjustment_changed(hadj);
1d48a247
HJYP
141 vadj = gtk_scrolled_window_get_vadjustment((GtkScrolledWindow*)scroll);
142 vadj->page_increment = 10;
143 gtk_adjustment_changed(vadj);
9c52ae58
HJYP
144
145 img_view->set_adjustments( hadj, vadj ); // dirty hack :-(
1d48a247 146 gtk_scrolled_window_add_with_viewport( (GtkScrolledWindow*)scroll, evt_box );
2c34ffe0
HJYP
147 GtkWidget* viewport = gtk_bin_get_child( (GtkBin*)scroll );
148 gtk_viewport_set_shadow_type( (GtkViewport*)viewport, GTK_SHADOW_NONE );
149 gtk_container_set_border_width( (GtkContainer*)viewport, 0 );
1d48a247
HJYP
150
151 gtk_box_pack_start( (GtkBox*)box, scroll, TRUE, TRUE, 0 );
152
153 // build toolbar
154 tooltips = gtk_tooltips_new();
9c52ae58
HJYP
155#if GTK_CHECK_VERSION(2, 10, 0)
156 g_object_ref_sink(tooltips);
1d48a247 157#else
9c52ae58 158 gtk_object_sink((GtkObject*)tooltips);
1d48a247 159#endif
1d48a247 160
9c52ae58 161 create_nav_bar( box );
1d48a247
HJYP
162 gtk_widget_show_all( box );
163
164 hand_cursor = gdk_cursor_new_for_display( gtk_widget_get_display((GtkWidget*)this), GDK_FLEUR );
165
5bfec971 166// zoom_mode = ZOOM_NONE;
1d48a247
HJYP
167 zoom_mode = ZOOM_FIT;
168
169 // Set up drag & drop
170 gtk_drag_dest_set( (GtkWidget*)this, GTK_DEST_DEFAULT_ALL,
171 drop_targets, G_N_ELEMENTS(drop_targets), GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_ASK) );
172 g_signal_connect( this, "drag-data-received", G_CALLBACK(on_drag_data_received), this );
173}
174
175MainWin::~MainWin()
176{
177 close();
178 gdk_cursor_unref( hand_cursor );
9c52ae58 179
1d48a247
HJYP
180 g_object_unref( tooltips );
181
182 // FIXME: Put this here is weird
183 gtk_main_quit();
184}
185
186void MainWin::create_nav_bar( GtkWidget* box )
187{
188 nav_bar = gtk_hbox_new( FALSE, 0 );
189
190 add_nav_btn( GTK_STOCK_GO_BACK, _("Previous"), G_CALLBACK(on_prev) );
191 add_nav_btn( GTK_STOCK_GO_FORWARD, _("Next"), G_CALLBACK(on_next) );
192
193 gtk_box_pack_start( (GtkBox*)nav_bar, gtk_vseparator_new(), FALSE, FALSE, 0 );
194
195 add_nav_btn( GTK_STOCK_ZOOM_OUT, _("Zoom Out"), G_CALLBACK(on_zoom_out) );
196 add_nav_btn( GTK_STOCK_ZOOM_IN, _("Zoom In"), G_CALLBACK(on_zoom_in) );
5bfec971
HJYP
197
198// percent = gtk_entry_new(); // show scale (in percentage)
199// g_signal_connect( percent, "activate", G_CALLBACK(on_percentage), this );
200// gtk_widget_set_size_request( percent, 45, -1 );
201// gtk_box_pack_start( (GtkBox*)nav_bar, percent, FALSE, FALSE, 2 );
202
1d48a247
HJYP
203 btn_fit = add_nav_btn( GTK_STOCK_ZOOM_FIT, _("Fit Image To Window Size"),
204 G_CALLBACK(on_zoom_fit), true );
205 btn_orig = add_nav_btn( GTK_STOCK_ZOOM_100, _("Original Size"),
206 G_CALLBACK(on_orig_size), true );
1d48a247 207 gtk_toggle_button_set_active( (GtkToggleButton*)btn_fit, TRUE );
5bfec971 208
1d48a247
HJYP
209#ifndef GTK_STOCK_FULLSCREEN
210#define GTK_STOCK_FULLSCREEN "gtk-fullscreen"
211#endif
212 add_nav_btn( GTK_STOCK_FULLSCREEN, _(" Full Screen"), G_CALLBACK(on_full_screen) ); // gtk+ 2.8+
213
214 gtk_box_pack_start( (GtkBox*)nav_bar, gtk_vseparator_new(), FALSE, FALSE, 0 );
215
216 add_nav_btn( "gtk-counterclockwise", _("Rotate Counterclockwise"),
217 G_CALLBACK(on_rotate_counterclockwise) );
218 add_nav_btn( "gtk-clockwise", _("Rotate Clockwise"), G_CALLBACK(on_rotate_clockwise) );
219
220 gtk_box_pack_start( (GtkBox*)nav_bar, gtk_vseparator_new(), FALSE, FALSE, 0 );
221
222 add_nav_btn( GTK_STOCK_OPEN, _("Open File"), G_CALLBACK(on_open) );
223 add_nav_btn( GTK_STOCK_SAVE, _("Save File"), G_CALLBACK(on_save) );
224 add_nav_btn( GTK_STOCK_SAVE_AS, _("Save File As"), G_CALLBACK(on_save_as) );
225 add_nav_btn( GTK_STOCK_DELETE, _("Delete File"), G_CALLBACK(on_delete) );
226
227/*
228 gtk_box_pack_start( (GtkBox*)nav_bar, gtk_vseparator_new(), FALSE, FALSE, 0 );
229
230 add_nav_btn( GTK_STOCK_PREFERENCES, _("Preference"), G_CALLBACK(on_preference) );
231*/
232
233 GtkWidget* align = gtk_alignment_new( 0.5, 0, 0, 0 );
234 gtk_container_add( (GtkContainer*)align, nav_bar );
235 gtk_box_pack_start( (GtkBox*)box, align, FALSE, TRUE, 2 );
236}
237
238gboolean MainWin::on_delete_event( GtkWidget* widget, GdkEventAny* evt )
239{
240 gtk_widget_destroy( widget );
241 return TRUE;
242}
243
da8bd946 244bool MainWin::open( const char* file_path, ZoomMode zoom )
1d48a247
HJYP
245{
246 close();
247 GError* err = NULL;
9c52ae58
HJYP
248 pix = gdk_pixbuf_new_from_file( file_path, &err );
249 if( ! pix )
1d48a247
HJYP
250 {
251 show_error( err->message );
252 return false;
253 }
d8ce3af1 254
da8bd946
HJYP
255 zoom_mode = zoom;
256
5bfec971 257 // select most suitable viewing mode
d8ce3af1 258 if( zoom == ZOOM_NONE )
1d48a247 259 {
9c52ae58
HJYP
260 int w = gdk_pixbuf_get_width( pix );
261 int h = gdk_pixbuf_get_height( pix );
1d48a247 262
1d48a247
HJYP
263 GdkRectangle area;
264 get_working_area( gtk_widget_get_screen((GtkWidget*)this), &area );
da8bd946 265// g_debug("determine best zoom mode: orig size: w=%d, h=%d", w, h);
9c52ae58 266 // FIXME: actually this is a little buggy :-(
da8bd946 267 if( w < area.width && h < area.height && (w >= 640 || h >= 480) )
1d48a247
HJYP
268 {
269 gtk_scrolled_window_set_policy( (GtkScrolledWindow*)scroll,
5bfec971 270 GTK_POLICY_NEVER, GTK_POLICY_NEVER );
9c52ae58 271 gtk_widget_set_size_request( (GtkWidget*)img_view, w, h );
5bfec971
HJYP
272 GtkRequisition req;
273 gtk_widget_size_request ( (GtkWidget*)this, &req );
9c52ae58
HJYP
274 if( req.width < 640 ) req.width = 640;
275 if( req.height < 480 ) req.height = 480;
5bfec971 276 gtk_window_resize( (GtkWindow*)this, req.width, req.height );
9c52ae58 277 gtk_widget_set_size_request( (GtkWidget*)img_view, -1, -1 );
1d48a247 278 gtk_scrolled_window_set_policy( (GtkScrolledWindow*)scroll,
5bfec971
HJYP
279 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
280 zoom_mode = ZOOM_ORIG;
1d48a247
HJYP
281 }
282 else
5bfec971 283 zoom_mode = ZOOM_FIT;
5bfec971 284 }
5bfec971
HJYP
285
286 if( zoom_mode == ZOOM_FIT )
d8ce3af1
HJYP
287 {
288 gtk_toggle_button_set_active( (GtkToggleButton*)btn_fit, TRUE );
5bfec971 289 fit_window_size();
d8ce3af1 290 }
5bfec971 291 else if( zoom_mode == ZOOM_SCALE ) // scale
d8ce3af1
HJYP
292 {
293 gtk_toggle_button_set_active( (GtkToggleButton*)btn_orig, FALSE );
294 gtk_toggle_button_set_active( (GtkToggleButton*)btn_fit, FALSE );
5bfec971 295 scale_image( scale );
d8ce3af1 296 }
5bfec971
HJYP
297 else if( zoom_mode == ZOOM_ORIG ) // original size
298 {
d8ce3af1 299 gtk_toggle_button_set_active( (GtkToggleButton*)btn_orig, TRUE );
9c52ae58 300 img_view->set_scale( 1.0 );
1d48a247
HJYP
301 center_image();
302 }
303
9c52ae58
HJYP
304 img_view->set_pixbuf( pix );
305
1d48a247
HJYP
306// while (gtk_events_pending ())
307// gtk_main_iteration ();
308
309 // build file list
310 char* dir_path = g_path_get_dirname( file_path );
311 img_list.open_dir( dir_path );
76e88fcf 312 img_list.sort_by_name( GTK_SORT_ASCENDING );
1d48a247 313 g_free( dir_path );
76e88fcf 314
1d48a247
HJYP
315 char* base_name = g_path_get_basename( file_path );
316 img_list.set_current( base_name );
76e88fcf
HJYP
317
318 char* disp_name = g_filename_display_name( base_name );
1d48a247
HJYP
319 g_free( base_name );
320
76e88fcf
HJYP
321 gtk_window_set_title( (GtkWindow*)this, disp_name );
322 g_free( disp_name );
1d48a247
HJYP
323
324 return true;
325}
326
327void MainWin::close()
328{
9c52ae58
HJYP
329 if( pix )
330 {
331 g_object_unref( pix );
332 pix = NULL;
1d48a247
HJYP
333 }
334}
335
336void MainWin::show_error( const char* message )
337{
338 GtkWidget* dlg = gtk_message_dialog_new( (GtkWindow*)this,
339 GTK_DIALOG_MODAL,
340 GTK_MESSAGE_ERROR,
341 GTK_BUTTONS_OK,
342 message );
343 gtk_dialog_run( (GtkDialog*)dlg );
344 gtk_widget_destroy( dlg );
345}
346
347void MainWin::on_size_allocate( GtkWidget* widget, GtkAllocation *allocation )
348{
349 GTK_WIDGET_CLASS(_parent_class)->size_allocate( widget, allocation );
52c867e9 350 if( GTK_WIDGET_REALIZED (widget) )
1d48a247 351 {
52c867e9 352 MainWin* self = (MainWin*)widget;
9c52ae58 353
52c867e9
HJYP
354 if( self->zoom_mode == ZOOM_FIT )
355 {
356 while(gtk_events_pending ())
357 gtk_main_iteration(); // makes it more fluid
1d48a247 358
52c867e9
HJYP
359 allocation = &self->scroll->allocation;
360 self->fit_window_size();
361 }
1d48a247
HJYP
362 }
363}
364
da8bd946 365void MainWin::fit_size( int width, int height, bool can_strech, GdkInterpType type )
1d48a247 366{
9c52ae58 367 if( ! pix )
1d48a247
HJYP
368 return;
369
9c52ae58
HJYP
370 int orig_w = gdk_pixbuf_get_width(pix);
371 int orig_h = gdk_pixbuf_get_height(pix);
1d48a247 372
da8bd946
HJYP
373 if( can_strech || (orig_w > width || orig_h > height) )
374 {
375 double xscale = double(width) / orig_w;
376 double yscale = double(height) / orig_h;
377 double final_scale = xscale < yscale ? xscale : yscale;
1d48a247 378
da8bd946
HJYP
379 scale_image( final_scale, type );
380 }
381 else // use original size if the image is smaller than the window
382 {
383 scale = 1.0;
9c52ae58 384 img_view->set_scale( 1.0, type );
da8bd946 385 }
1d48a247
HJYP
386}
387
da8bd946 388void MainWin::fit_window_size( bool can_strech, GdkInterpType type )
1d48a247 389{
94fcf707
HJYP
390 zoom_mode = ZOOM_FIT;
391
9c52ae58 392 if( pix == NULL )
da8bd946 393 return;
94fcf707
HJYP
394
395 fit_size( scroll->allocation.width, scroll->allocation.height, can_strech, type );
1d48a247
HJYP
396}
397
398GtkWidget* MainWin::add_nav_btn( const char* icon, const char* tip, GCallback cb, bool toggle )
399{
400 GtkWidget* img = gtk_image_new_from_stock(icon, GTK_ICON_SIZE_SMALL_TOOLBAR);
401 GtkWidget* btn;
402 if( G_UNLIKELY(toggle) )
403 {
404 btn = gtk_toggle_button_new();
405 g_signal_connect( btn, "toggled", cb, this );
406 }
407 else
408 {
409 btn = gtk_button_new();
410 g_signal_connect( btn, "clicked", cb, this );
411 }
412 gtk_button_set_relief( (GtkButton*)btn, GTK_RELIEF_NONE );
413 gtk_button_set_focus_on_click( (GtkButton*)btn, FALSE );
414 gtk_container_add( (GtkContainer*)btn, img );
415 gtk_tooltips_set_tip( tooltips, btn, tip, NULL );
416 gtk_box_pack_start( (GtkBox*)nav_bar, btn, FALSE, FALSE, 0 );
417 return btn;
418}
419
420void MainWin::on_zoom_fit_menu( GtkMenuItem* item, MainWin* self )
421{
422 gtk_button_clicked( (GtkButton*)self->btn_fit );
423}
424
425void MainWin::on_zoom_fit( GtkToggleButton* btn, MainWin* self )
426{
427 if( ! btn->active )
428 {
429 if( self->zoom_mode == ZOOM_FIT )
430 gtk_toggle_button_set_active( btn, TRUE );
431 return;
432 }
1d48a247
HJYP
433 gtk_toggle_button_set_active( (GtkToggleButton*)self->btn_orig, FALSE );
434
435 self->fit_window_size();
436}
437
438void MainWin::on_full_screen( GtkWidget* btn, MainWin* self )
439{
440 if( ! self->full_screen )
441 {
5bfec971
HJYP
442 static GdkColor black = {0};
443 gtk_widget_modify_bg( self->evt_box, GTK_STATE_NORMAL, &black );
1d48a247
HJYP
444 gtk_widget_hide( gtk_widget_get_parent(self->nav_bar) );
445 gtk_window_fullscreen( (GtkWindow*)self );
446 }
447 else
448 {
5bfec971
HJYP
449// gtk_widget_reset_rc_styles( self->evt_box );
450 static GdkColor white = {0, 65535, 65535, 65535};
451 gtk_widget_modify_bg( self->evt_box, GTK_STATE_NORMAL, &white );
1d48a247
HJYP
452 gtk_widget_show( gtk_widget_get_parent(self->nav_bar) );
453 gtk_window_unfullscreen( (GtkWindow*)self );
454 }
455 self->full_screen = ! self->full_screen;
456}
457
458void MainWin::on_orig_size_menu( GtkToggleButton* btn, MainWin* self )
459{
460 gtk_button_clicked( (GtkButton*)self->btn_orig );
461}
462
463void MainWin::on_orig_size( GtkToggleButton* btn, MainWin* self )
464{
465 // This callback could be called from activate signal of menu item.
466 if( GTK_IS_MENU_ITEM(btn) )
467 {
468 gtk_button_clicked( (GtkButton*)self->btn_orig );
469 return;
470 }
471
472 if( ! btn->active )
473 {
474 if( self->zoom_mode == ZOOM_ORIG )
475 gtk_toggle_button_set_active( btn, TRUE );
476 return;
477 }
478 self->zoom_mode = ZOOM_ORIG;
479 self->scale = 1.0;
94fcf707
HJYP
480// gtk_scrolled_window_set_policy( (GtkScrolledWindow*)self->scroll,
481// GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1d48a247
HJYP
482
483 gtk_toggle_button_set_active( (GtkToggleButton*)self->btn_fit, FALSE );
484
9c52ae58 485 if( ! self->pix )
1d48a247
HJYP
486 return;
487
9c52ae58 488 self->img_view->set_scale( 1.0 );
1d48a247 489
9c52ae58
HJYP
490 while (gtk_events_pending ())
491 gtk_main_iteration ();
492
493 self->center_image(); // FIXME: This doesn't work well. Why?
1d48a247
HJYP
494}
495
496void MainWin::on_prev( GtkWidget* btn, MainWin* self )
497{
498 if( self->img_list.is_empty() )
499 return;
500
501 const char* name = self->img_list.get_prev();
502
503 if( ! name && self->img_list.has_multiple_files() )
504 {
505 // FIXME: need to ask user first?
506 name = self->img_list.get_last();
507 }
508
509 if( name )
510 {
511 char* file_path = self->img_list.get_current_file_path();
512 self->open( file_path );
513 g_free( file_path );
514 }
515}
516
517void MainWin::on_next( GtkWidget* btn, MainWin* self )
518{
519 if( self->img_list.is_empty() )
520 return;
521
522 const char* name = self->img_list.get_next();
523
524 if( ! name && self->img_list.has_multiple_files() )
525 {
526 // FIXME: need to ask user first?
527 name = self->img_list.get_first();
528 }
529
530 if( name )
531 {
532 char* file_path = self->img_list.get_current_file_path();
533 self->open( file_path );
534 g_free( file_path );
535 }
536}
537
538void MainWin::on_rotate_clockwise( GtkWidget* btn, MainWin* self )
539{
540 self->rotate_image( GDK_PIXBUF_ROTATE_CLOCKWISE );
541}
542
543void MainWin::on_rotate_counterclockwise( GtkWidget* btn, MainWin* self )
544{
545 self->rotate_image( GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE );
546}
547
548static void on_update_preview( GtkFileChooser *chooser, GtkImage* img )
549{
550 char* file = gtk_file_chooser_get_preview_filename( chooser );
551 GdkPixbuf* pix = NULL;
552 if( file )
553 {
554 pix = gdk_pixbuf_new_from_file_at_scale( file, 128, 128, TRUE, NULL );
555 g_free( file );
556 }
1d48a247 557 if( pix )
9c52ae58
HJYP
558 {
559 gtk_image_set_from_pixbuf( img, pix );
560 g_object_unref( pix );
561 }
1d48a247
HJYP
562}
563
564void MainWin::on_save_as( GtkWidget* btn, MainWin* self )
565{
9c52ae58 566 if( ! self->pix )
1d48a247
HJYP
567 return;
568
569 GtkFileChooser* dlg = (GtkFileChooser*)gtk_file_chooser_dialog_new( NULL, (GtkWindow*)self,
570 GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL,
571 GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL );
572
573 gtk_file_chooser_set_current_folder( dlg, self->img_list.get_dir() );
574
575 GtkWidget* img = gtk_image_new();
576 gtk_widget_set_size_request( img, 128, 128 );
577 gtk_file_chooser_set_preview_widget( dlg, img );
578 g_signal_connect( dlg, "update-preview", G_CALLBACK(on_update_preview), img );
579
580 GtkFileFilter *filter;
581
582 /*
583 /// TODO: determine file type from file name
584 filter = gtk_file_filter_new();
585 gtk_file_filter_set_name( filter, _("Determined by File Name") );
586 gtk_file_filter_add_pixbuf_formats( filter );
587 gtk_file_chooser_add_filter( dlg, filter );
588 */
589
590 GSList* modules = gdk_pixbuf_get_formats();
591 GSList* module;
592 for( module = modules; module; module = module->next )
593 {
594 GdkPixbufFormat* format = (GdkPixbufFormat*)module->data;
595 if( ! gdk_pixbuf_format_is_writable( format ) )
596 continue;
597
598 filter = gtk_file_filter_new();
599
600 char* desc = gdk_pixbuf_format_get_description( format );
601 char* name = gdk_pixbuf_format_get_name( format );
602 char* tmp = g_strjoin( ": ", name, desc, NULL );
603 g_free( desc );
604 g_free( name );
605 gtk_file_filter_set_name( filter, tmp );
606 g_free( tmp );
607
608 char** mimes = gdk_pixbuf_format_get_mime_types( format ), **mime;
609 for( mime = mimes; *mime ; ++mime )
610 gtk_file_filter_add_mime_type( filter, *mime );
611 g_strfreev( mimes );
612 gtk_file_chooser_add_filter( dlg, filter );
613 }
614
615 if( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK )
616 {
617 filter = gtk_file_chooser_get_filter( dlg );
618 const char* filter_name = gtk_file_filter_get_name( filter );
619 char* p = strstr( filter_name, ": " );
620 char* type = NULL;
621 if( ! p ) // auto detection
622 {
623 /// TODO: auto file type
624 }
625 else
626 {
627 type = g_strndup( filter_name, (p - filter_name) );
628 }
629 char* file = gtk_file_chooser_get_filename( dlg );
630 // g_debug("type = %s", type);
631 self->save( file, type );
632 g_free( file );
633 g_free( type );
634 }
635 gtk_widget_destroy( (GtkWidget*)dlg );
636}
637
638void MainWin::on_save( GtkWidget* btn, MainWin* self )
639{
9c52ae58 640 if( ! self->pix )
1d48a247
HJYP
641 return;
642
643 char* file_name = g_build_filename( self->img_list.get_dir(),
644 self->img_list.get_current(), NULL );
645 GdkPixbufFormat* info;
646 info = gdk_pixbuf_get_file_info( file_name, NULL, NULL );
647 char* type = gdk_pixbuf_format_get_name( info );
648 self->save( file_name, type, true );
649 g_free( file_name );
650 g_free( type );
651}
652
653void MainWin::on_open( GtkWidget* btn, MainWin* self )
654{
655 GtkFileChooser* dlg = (GtkFileChooser*)gtk_file_chooser_dialog_new( NULL, (GtkWindow*)self,
656 GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
657 GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL );
658
659 if( self->img_list.get_dir() )
660 gtk_file_chooser_set_current_folder( dlg, self->img_list.get_dir() );
661
662 GtkWidget* img = gtk_image_new();
663 gtk_widget_set_size_request( img, 128, 128 );
664 gtk_file_chooser_set_preview_widget( dlg, img );
665 g_signal_connect( dlg, "update-preview", G_CALLBACK(on_update_preview), img );
666
667 GtkFileFilter *filter = gtk_file_filter_new();
668 gtk_file_filter_set_name( filter, _("All Supported Images") );
669 gtk_file_filter_add_pixbuf_formats( filter );
670 gtk_file_chooser_add_filter( dlg, filter );
671
672 filter = gtk_file_filter_new();
673 gtk_file_filter_set_name( filter, _("All Files") );
674 gtk_file_filter_add_pattern( filter, "*" );
675 gtk_file_chooser_add_filter( dlg, filter );
676
677 char* file = NULL;
678 if( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK )
679 file = gtk_file_chooser_get_filename( dlg );
680 gtk_widget_destroy( (GtkWidget*)dlg );
681
682 if( file )
683 {
d8ce3af1 684 self->open( file, ZOOM_NONE );
1d48a247
HJYP
685 g_free( file );
686 }
687}
688
689void MainWin::on_zoom_in( GtkWidget* btn, MainWin* self )
690{
5bfec971 691 self->zoom_mode = ZOOM_SCALE;
1d48a247
HJYP
692 gtk_toggle_button_set_active( (GtkToggleButton*)self->btn_fit, FALSE );
693 gtk_toggle_button_set_active( (GtkToggleButton*)self->btn_orig, FALSE );
94fcf707
HJYP
694// gtk_scrolled_window_set_policy( (GtkScrolledWindow*)self->scroll,
695// GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1d48a247
HJYP
696
697 double scale = self->scale;
9c52ae58 698 if( self->pix && scale < 20.0 )
1d48a247
HJYP
699 {
700// busy(true);
9c52ae58
HJYP
701 scale *= 1.05;
702 if( scale > 20.0 )
703 scale = 20.0;
704 if( self->scale != scale )
705 self->scale_image( scale );
1d48a247
HJYP
706// adjust_adjustment_on_zoom(oldscale);
707// busy(false);
708 }
709}
710
711void MainWin::on_zoom_out( GtkWidget* btn, MainWin* self )
712{
5bfec971 713 self->zoom_mode = ZOOM_SCALE;
1d48a247
HJYP
714 gtk_toggle_button_set_active( (GtkToggleButton*)self->btn_fit, FALSE );
715 gtk_toggle_button_set_active( (GtkToggleButton*)self->btn_orig, FALSE );
94fcf707
HJYP
716// gtk_scrolled_window_set_policy( (GtkScrolledWindow*)self->scroll,
717// GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1d48a247
HJYP
718
719 double scale = self->scale;
9c52ae58 720 if( self->pix && scale > 0.02 )
1d48a247
HJYP
721 {
722// busy(true);
da8bd946 723
9c52ae58
HJYP
724 scale /= 1.05;
725 if( scale < 0.02 )
726 scale = 0.02;
727 if( self->scale != scale )
da8bd946 728 self->scale_image( scale );
1d48a247
HJYP
729// adjust_adjustment_on_zoom(oldscale);
730// busy(false);
731 }
732}
733
734void MainWin::on_preference( GtkWidget* btn, MainWin* self )
735{
736 self->show_error( "Not implemented yet!" );
737}
738
739void MainWin::on_quit( GtkWidget* btn, MainWin* self )
740{
741 gtk_widget_destroy( (GtkWidget*)self );
742}
743
744gboolean MainWin::on_button_press( GtkWidget* widget, GdkEventButton* evt, MainWin* self )
745{
9c52ae58
HJYP
746 if( ! GTK_WIDGET_HAS_FOCUS( widget ) )
747 gtk_widget_grab_focus( widget );
5bfec971 748
1d48a247
HJYP
749 if( evt->type == GDK_BUTTON_PRESS)
750 {
751 if( evt->button == 1 ) // left button
752 {
9c52ae58 753 if( ! self->pix )
1d48a247
HJYP
754 return FALSE;
755 self->dragging = true;
756 gtk_widget_get_pointer( (GtkWidget*)self, &self->drag_old_x ,&self->drag_old_y );
757 gdk_window_set_cursor( widget->window, self->hand_cursor );
758 }
759 else if( evt->button == 3 ) // right button
760 {
761 self->show_popup_menu( evt );
762 }
763 }
764 else if( evt->type == GDK_2BUTTON_PRESS && evt->button == 1 ) // double clicked
765 {
766 on_full_screen( NULL, self );
767 }
1d48a247
HJYP
768 return FALSE;
769}
770
771gboolean MainWin::on_mouse_move( GtkWidget* widget, GdkEventMotion* evt, MainWin* self )
772{
773 if( ! self->dragging )
1d48a247 774 return FALSE;
9c52ae58 775
1d48a247
HJYP
776 int cur_x, cur_y;
777 gtk_widget_get_pointer( (GtkWidget*)self, &cur_x ,&cur_y );
778
779 int dx = (self->drag_old_x - cur_x);
780 int dy = (self->drag_old_y - cur_y);
781
782 GtkAdjustment *hadj, *vadj;
783 hadj = gtk_scrolled_window_get_hadjustment((GtkScrolledWindow*)self->scroll);
784 vadj = gtk_scrolled_window_get_vadjustment((GtkScrolledWindow*)self->scroll);
785
9c52ae58
HJYP
786 GtkRequisition req;
787 gtk_widget_size_request( (GtkWidget*)self->img_view, &req );
1d48a247
HJYP
788
789 if( ABS(dx) > 4 )
790 {
791 self->drag_old_x = cur_x;
9c52ae58 792 if( req.width > hadj->page_size )
1d48a247
HJYP
793 {
794 gdouble x = gtk_adjustment_get_value (hadj) + dx;
795 if( x < hadj->lower )
796 x = hadj->lower;
797 else if( (x + hadj->page_size) > hadj->upper )
798 x = hadj->upper - hadj->page_size;
799
800 if( x != hadj->value )
801 gtk_adjustment_set_value (hadj, x );
802 }
803 }
804
805 if( ABS(dy) > 4 )
806 {
9c52ae58 807 if( req.height > vadj->page_size )
1d48a247
HJYP
808 {
809 self->drag_old_y = cur_y;
810 gdouble y = gtk_adjustment_get_value (vadj) + dy;
811 if( y < vadj->lower )
812 y = vadj->lower;
813 else if( (y + vadj->page_size) > vadj->upper )
814 y = vadj->upper - vadj->page_size;
815
816 if( y != vadj->value )
817 gtk_adjustment_set_value (vadj, y );
818 }
819 }
820 return FALSE;
821}
822
823gboolean MainWin::on_button_release( GtkWidget* widget, GdkEventButton* evt, MainWin* self )
824{
825 self->dragging = false;
826 gdk_window_set_cursor( widget->window, NULL );
827 return FALSE;
828}
829
5bfec971
HJYP
830gboolean MainWin::on_scroll_event( GtkWidget* widget, GdkEventScroll* evt, MainWin* self )
831{
832 switch( evt->direction )
833 {
834 case GDK_SCROLL_UP:
835 on_zoom_out( NULL, self );
836 break;
837 case GDK_SCROLL_DOWN:
838 on_zoom_in( NULL, self );
839 break;
840 case GDK_SCROLL_LEFT:
841 on_prev( NULL, self );
842 break;
843 case GDK_SCROLL_RIGHT:
844 on_next( NULL, self );
845 break;
846 }
da8bd946 847 return TRUE;
5bfec971
HJYP
848}
849
1d48a247
HJYP
850gboolean MainWin::on_key_press_event(GtkWidget* widget, GdkEventKey * key)
851{
852 MainWin* self = (MainWin*)widget;
853 switch( key->keyval )
854 {
5bfec971
HJYP
855 case GDK_Left:
856 case GDK_KP_Left:
857 case GDK_leftarrow:
1d48a247
HJYP
858 case GDK_Return:
859 case GDK_space:
860 case GDK_Next:
5bfec971
HJYP
861 case GDK_KP_Down:
862 case GDK_Down:
863 case GDK_downarrow:
1d48a247
HJYP
864 on_next( NULL, self );
865 break;
5bfec971
HJYP
866 case GDK_Right:
867 case GDK_KP_Right:
868 case GDK_rightarrow:
1d48a247
HJYP
869 case GDK_Prior:
870 case GDK_BackSpace:
5bfec971
HJYP
871 case GDK_KP_Up:
872 case GDK_Up:
873 case GDK_uparrow:
1d48a247
HJYP
874 on_prev( NULL, self );
875 break;
876 case GDK_KP_Add:
877 case GDK_plus:
641adad3 878 case GDK_equal:
1d48a247
HJYP
879 on_zoom_in( NULL, self );
880 break;
881 case GDK_KP_Subtract:
882 case GDK_minus:
883 on_zoom_out( NULL, self );
884 break;
1d48a247 885 case GDK_s:
641adad3 886// case GDK_S:
1d48a247
HJYP
887 on_save( NULL, self );
888 break;
889 case GDK_l:
5bfec971 890// case GDK_L:
1d48a247
HJYP
891 on_rotate_counterclockwise( NULL, self );
892 break;
893 case GDK_r:
5bfec971 894// case GDK_R:
1d48a247
HJYP
895 on_rotate_clockwise( NULL, self );
896 break;
897 case GDK_f:
5bfec971 898// case GDK_F:
1d48a247
HJYP
899 if( self->zoom_mode != ZOOM_FIT )
900 gtk_button_clicked((GtkButton*)self->btn_fit );
901 break;
902 case GDK_g:
5bfec971 903// case GDK_G:
1d48a247
HJYP
904 if( self->zoom_mode != ZOOM_ORIG )
905 gtk_button_clicked((GtkButton*)self->btn_orig );
906 break;
907 case GDK_o:
5bfec971
HJYP
908// case GDK_O:
909 on_open( NULL, self );
910 break;
911 case GDK_Delete:
912 case GDK_d:
913// case GDK_D:
914 on_delete( NULL, self );
1d48a247
HJYP
915 break;
916 case GDK_Escape:
917 if( self->full_screen )
918 on_full_screen( NULL, self );
919 else
920 on_quit( NULL, self );
921 break;
922 case GDK_F11:
923 on_full_screen( NULL, self );
924 break;
925
926 default:
927 GTK_WIDGET_CLASS(_parent_class)->key_press_event( widget, key );
928 }
929 return FALSE;
930}
931
932void MainWin::center_image()
933{
934 GtkAdjustment *hadj, *vadj;
935 hadj = gtk_scrolled_window_get_hadjustment((GtkScrolledWindow*)scroll);
936 vadj = gtk_scrolled_window_get_vadjustment((GtkScrolledWindow*)scroll);
937
9c52ae58
HJYP
938 GtkRequisition req;
939 gtk_widget_size_request( (GtkWidget*)img_view, &req );
1d48a247 940
9c52ae58
HJYP
941 if( req.width > hadj->page_size )
942 gtk_adjustment_set_value(hadj, ( hadj->upper - hadj->page_size ) / 2 );
1d48a247 943
9c52ae58
HJYP
944 if( req.height > vadj->page_size )
945 gtk_adjustment_set_value(vadj, ( vadj->upper - vadj->page_size ) / 2 );
1d48a247
HJYP
946}
947
948void MainWin::rotate_image( GdkPixbufRotation angle )
949{
9c52ae58 950 if( ! pix )
1d48a247
HJYP
951 return;
952
9c52ae58
HJYP
953 GdkPixbuf* rpix = NULL;
954 rpix = gdk_pixbuf_rotate_simple( pix, angle );
955 g_object_unref( pix );
956 pix = rpix;
957 img_view->set_pixbuf( pix );
1d48a247 958
1d48a247
HJYP
959 if( zoom_mode == ZOOM_FIT )
960 fit_window_size();
1d48a247
HJYP
961}
962
963bool MainWin::scale_image( double new_scale, GdkInterpType type )
964{
965 if( G_UNLIKELY( new_scale == 1.0 ) )
966 {
967 gtk_toggle_button_set_active( (GtkToggleButton*)btn_orig, TRUE );
968 return true;
969 }
9c52ae58
HJYP
970 scale = new_scale;
971 img_view->set_scale( new_scale, type );
2c34ffe0 972
9c52ae58 973 return true;
1d48a247
HJYP
974}
975
976bool MainWin::save( const char* file_path, const char* type, bool confirm )
977{
9c52ae58 978 if( ! pix )
1d48a247
HJYP
979 return false;
980
981 if( confirm ) // check existing file
982 {
983 if( g_file_test( file_path, G_FILE_TEST_EXISTS ) )
984 {
985 GtkWidget* dlg = gtk_message_dialog_new( (GtkWindow*)this,
986 GTK_DIALOG_MODAL,
987 GTK_MESSAGE_QUESTION,
988 GTK_BUTTONS_YES_NO,
989 _("The file name you selected already exist.\nDo you want to overwrite existing file?\n(Warning: The quality of original image might be lost)") );
990 if( gtk_dialog_run( (GtkDialog*)dlg ) != GTK_RESPONSE_YES )
991 {
992 gtk_widget_destroy( dlg );
993 return false;
994 }
995 gtk_widget_destroy( dlg );
996 }
997 }
998
999 GError* err = NULL;
9c52ae58 1000 if( ! gdk_pixbuf_save( pix, file_path, type, &err, NULL ) )
1d48a247
HJYP
1001 {
1002 show_error( err->message );
1003 return false;
1004 }
1005
1006 return true;
1007}
1008
1009void MainWin::on_delete( GtkWidget* btn, MainWin* self )
1010{
1011 char* file_path = self->img_list.get_current_file_path();
1012 if( file_path )
1013 {
1014 GtkWidget* dlg = gtk_message_dialog_new( (GtkWindow*)self,
1015 GTK_DIALOG_MODAL,
1016 GTK_MESSAGE_QUESTION,
1017 GTK_BUTTONS_YES_NO,
1018 _("Are you sure you want to delete current file?\n\nWarning: Once deleted, the file cannot be recovered.") );
1019 int resp = gtk_dialog_run( (GtkDialog*)dlg );
1020 gtk_widget_destroy( dlg );
1021
1022 if( resp == GTK_RESPONSE_YES )
1023 {
1024 g_unlink( file_path );
1025 if( errno )
1026 self->show_error( g_strerror(errno) );
1027 g_free( file_path );
1028 }
1029 }
1030}
1031
5bfec971 1032#include "ptk-menu.h"
1d48a247
HJYP
1033void MainWin::show_popup_menu( GdkEventButton* evt )
1034{
5bfec971 1035/*
1d48a247
HJYP
1036 GtkMenuShell* popup = (GtkMenuShell*)gtk_menu_new();
1037
1038 GtkWidget *item;
1039 add_menu_item( popup, _("Previous"), GTK_STOCK_GO_BACK, G_CALLBACK(on_prev) );
1040 add_menu_item( popup, _("Next"), GTK_STOCK_GO_FORWARD, G_CALLBACK(on_next) );
1041
1042 gtk_menu_shell_append( popup, gtk_separator_menu_item_new() );
1043
1044 add_menu_item( popup, _("Zoom Out"), GTK_STOCK_ZOOM_OUT, G_CALLBACK(on_zoom_out) );
1045 add_menu_item( popup, _("Zoom In"), GTK_STOCK_ZOOM_IN, G_CALLBACK(on_zoom_in) );
1046 add_menu_item( popup, _("Fit Image To Window Size"), GTK_STOCK_ZOOM_OUT,
1047 G_CALLBACK(on_zoom_fit_menu) );
1048 add_menu_item( popup, _("Original Size"), GTK_STOCK_ZOOM_100,
1049 G_CALLBACK(on_orig_size_menu) );
1050
1051#ifndef GTK_STOCK_FULLSCREEN
1052// This stock item is only available after gtk+ 2.8
1053#define GTK_STOCK_FULLSCREEN "gtk-fullscreen"
1054#endif
1055 add_menu_item( popup, _("Full Screen"), GTK_STOCK_FULLSCREEN, G_CALLBACK(on_full_screen) );
1056
1057 gtk_menu_shell_append( popup, gtk_separator_menu_item_new() );
1058
1059 add_menu_item( popup, _("Rotate Counterclockwise"), "gtk-counterclockwise",
1060 G_CALLBACK(on_rotate_counterclockwise) );
1061 add_menu_item( popup, _("Rotate Clockwise"), "gtk-clockwise",
1062 G_CALLBACK(on_rotate_clockwise) );
1063
1064 gtk_menu_shell_append( popup, gtk_separator_menu_item_new() );
1065
1066 add_menu_item( popup, _("Open File"), GTK_STOCK_OPEN, G_CALLBACK(on_open) );
1067 add_menu_item( popup, _("Save File"), GTK_STOCK_SAVE, G_CALLBACK(on_save) );
1068 add_menu_item( popup, _("Save As"), GTK_STOCK_SAVE_AS, G_CALLBACK(on_save_as) );
1069 add_menu_item( popup, _("Delete File"), GTK_STOCK_DELETE, G_CALLBACK(on_delete) );
1070
1071 gtk_menu_shell_append( popup, gtk_separator_menu_item_new() );
1072
1073 item = gtk_image_menu_item_new_from_stock( GTK_STOCK_ABOUT, NULL );
1074 g_signal_connect(item, "activate", G_CALLBACK(on_about), this);
1075 gtk_menu_shell_append( popup, item );
5bfec971 1076*/
1d48a247 1077
5bfec971
HJYP
1078 static PtkMenuItemEntry menu_def[] =
1079 {
1080 PTK_IMG_MENU_ITEM( N_( "Previous" ), GTK_STOCK_GO_BACK, on_prev, GDK_leftarrow, 0 ),
1081 PTK_IMG_MENU_ITEM( N_( "Next" ), GTK_STOCK_GO_FORWARD, on_next, GDK_rightarrow, 0 ),
1082 PTK_SEPARATOR_MENU_ITEM,
1083 PTK_IMG_MENU_ITEM( N_( "Zoom Out" ), GTK_STOCK_ZOOM_OUT, on_zoom_out, GDK_minus, 0 ),
1084 PTK_IMG_MENU_ITEM( N_( "Zoom In" ), GTK_STOCK_ZOOM_IN, on_zoom_in, GDK_plus, 0 ),
1085 PTK_IMG_MENU_ITEM( N_( "Fit Image To Window Size" ), GTK_STOCK_ZOOM_FIT, on_zoom_fit_menu, GDK_F, 0 ),
1086 PTK_IMG_MENU_ITEM( N_( "Original Size" ), GTK_STOCK_ZOOM_100, on_orig_size_menu, GDK_G, 0 ),
1087 PTK_SEPARATOR_MENU_ITEM,
0c8ac162 1088 PTK_IMG_MENU_ITEM( N_( "Full Screen" ), GTK_STOCK_FULLSCREEN, on_full_screen, GDK_F11, 0 ),
5bfec971
HJYP
1089 PTK_SEPARATOR_MENU_ITEM,
1090 PTK_IMG_MENU_ITEM( N_( "Rotate Counterclockwise" ), "gtk-counterclockwise", on_rotate_counterclockwise, GDK_L, 0 ),
1091 PTK_IMG_MENU_ITEM( N_( "Rotate Clockwise" ), "gtk-clockwise", on_rotate_clockwise, GDK_R, 0 ),
1092 PTK_SEPARATOR_MENU_ITEM,
1093 PTK_IMG_MENU_ITEM( N_("Open File"), GTK_STOCK_OPEN, G_CALLBACK(on_open), GDK_O, 0 ),
1094 PTK_IMG_MENU_ITEM( N_("Save File"), GTK_STOCK_SAVE, G_CALLBACK(on_save), GDK_S, 0 ),
1095 PTK_IMG_MENU_ITEM( N_("Save As"), GTK_STOCK_SAVE_AS, G_CALLBACK(on_save_as), GDK_A, 0 ),
1096 PTK_IMG_MENU_ITEM( N_("Delete File"), GTK_STOCK_DELETE, G_CALLBACK(on_delete), GDK_Delete, 0 ),
1097 PTK_SEPARATOR_MENU_ITEM,
1098 PTK_STOCK_MENU_ITEM( GTK_STOCK_ABOUT, on_about ),
1099 PTK_MENU_END
1100 };
1101
1102 // This accel group is useless. It's only used to display accels in popup menu
1103 GtkAccelGroup* accel_group = gtk_accel_group_new();
1104 GtkMenuShell* popup = (GtkMenuShell*)ptk_menu_new_from_data( menu_def, this, accel_group );
1d48a247
HJYP
1105
1106 gtk_widget_show_all( (GtkWidget*)popup );
1107 g_signal_connect( popup, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
1108 gtk_menu_popup( (GtkMenu*)popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
1109}
1110
5bfec971 1111/*
1d48a247
HJYP
1112GtkWidget* MainWin::add_menu_item( GtkMenuShell* menu, const char* label,
1113 const char* icon, GCallback cb, bool toggle )
1114{
1115 GtkWidget* item;
1116 if( G_UNLIKELY(toggle) )
1117 {
1118 item = gtk_check_menu_item_new_with_mnemonic( label );
1119 g_signal_connect( item, "toggled", cb, this );
1120 }
1121 else
1122 {
1123 if( icon )
1124 {
1125 item = gtk_image_menu_item_new_with_mnemonic( label);
1126 GtkWidget* img = gtk_image_new_from_stock( icon, GTK_ICON_SIZE_MENU );
1127 gtk_image_menu_item_set_image( (GtkImageMenuItem*)item, img );
1128 }
1129 else {
1130 item = gtk_menu_item_new_with_mnemonic( label );
1131 }
1132 g_signal_connect( item, "activate", cb, this );
1133 }
1134 gtk_menu_shell_append( (GtkMenuShell*)menu, item );
1135}
5bfec971 1136*/
1d48a247
HJYP
1137
1138void MainWin::on_about( GtkWidget* menu, MainWin* self )
1139{
1140 GtkWidget * about_dlg;
1141 const gchar *authors[] =
1142 {
1143 "洪任諭 Hong Jen Yee <pcman.tw@gmail.com>",
9c52ae58 1144 _(" * Refer to source code of EOG image viewer"),
1d48a247
HJYP
1145 _(" * Some icons are taken from gimmage"),
1146 NULL
1147 };
1148 /* TRANSLATORS: Replace this string with your names, one name per line. */
1149 gchar *translators = _( "translator-credits" );
1150
1151 about_dlg = gtk_about_dialog_new ();
1152 gtk_container_set_border_width ( GTK_CONTAINER ( about_dlg ), 2 );
1153 gtk_about_dialog_set_version ( GTK_ABOUT_DIALOG ( about_dlg ), VERSION );
1154 gtk_about_dialog_set_name ( GTK_ABOUT_DIALOG ( about_dlg ), _( "GPicView" ) );
1155 gtk_about_dialog_set_copyright ( GTK_ABOUT_DIALOG ( about_dlg ), _( "Copyright (C) 2007" ) );
1156 gtk_about_dialog_set_comments ( GTK_ABOUT_DIALOG ( about_dlg ), _( "Lightweight image viewer\n\nDeveloped by Hon Jen Yee (PCMan)" ) );
1157 gtk_about_dialog_set_license ( GTK_ABOUT_DIALOG ( about_dlg ), "GPicView\n\nCopyright (C) 2007 Hong Jen Yee (PCMan)\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA." );
b9ca6e3b 1158 gtk_about_dialog_set_website ( GTK_ABOUT_DIALOG ( about_dlg ), "http://lxde.sourceforge.net/gpicview/" );
1d48a247
HJYP
1159 gtk_about_dialog_set_authors ( GTK_ABOUT_DIALOG ( about_dlg ), authors );
1160 gtk_about_dialog_set_translator_credits ( GTK_ABOUT_DIALOG ( about_dlg ), translators );
1161 gtk_window_set_transient_for( GTK_WINDOW( about_dlg ), GTK_WINDOW( self ) );
1162
1163 gtk_dialog_run( GTK_DIALOG( about_dlg ) );
1164 gtk_widget_destroy( about_dlg );
1165}
1166
1167void MainWin::on_drag_data_received( GtkWidget* widget, GdkDragContext *drag_context,
1168 int x, int y, GtkSelectionData* data, guint info, guint time, MainWin* self )
1169{
1170 if( ! data || data->length <= 0)
1171 return;
1172
1d48a247
HJYP
1173 char* file = NULL;
1174 if( info == 0 ) // text/uri-list
1175 {
1176 char** uris = gtk_selection_data_get_uris( data );
1177 if( uris )
1178 {
1179 file = g_filename_from_uri(*uris, NULL, NULL);
1180 g_strfreev( uris );
1181 }
1182 }
1183 else if( info == 1 ) // text/plain
1184 {
1185 file = (char*)gtk_selection_data_get_text( data );
1186 }
1187 if( file )
1188 {
1189 self->open( file );
1190 g_free( file );
1191 }
1192}