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