2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <guichaz@yahoo.fr>
25 #include <gdk/gdkkeysyms.h> /* GDK_* */
30 #include "rendering.h"
32 #include "mnemonics.h"
34 #include "next_image.h"
37 #include "math_floats.h"
38 #include "files_list.h"
40 #include "open_dialog.h"
43 #include "scrollbars.h"
46 #include "images_menus.h"
47 #include "collection.h"
51 #include "tree_browser.h"
52 #include "gliv-image.h"
54 extern options_struct
*options
;
55 extern GlivImage
*current_image
;
56 extern GtkMenuBar
*menu_bar
;
58 void set_menu_label(GtkMenuItem
* item
, const gchar
* text
, gboolean mnemonic
)
63 /* Find the label to change. */
64 children
= gtk_container_get_children(GTK_CONTAINER(item
));
65 while (children
!= NULL
&& GTK_IS_ACCEL_LABEL(children
->data
) == FALSE
)
66 children
= children
->next
;
71 label
= children
->data
;
75 gtk_label_set_text_with_mnemonic(GTK_LABEL(label
), add_mnemonic(text
));
78 gtk_label_set_text(GTK_LABEL(label
), text
);
81 static GtkMenuShell
*add_menu(const gchar
* name
)
85 static gboolean first_time
= TRUE
;
93 name
= add_mnemonic(_(name
));
94 item
= GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(name
));
95 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar
), GTK_WIDGET(item
));
97 menu
= GTK_MENU_SHELL(gtk_menu_new());
98 gtk_menu_shell_append(menu
, gtk_tearoff_menu_item_new());
99 gtk_menu_item_set_submenu(item
, GTK_WIDGET(menu
));
105 /* Should not collide with a keysym */
106 #define CTRL (1 << 31)
108 static GtkMenuItem
*add_menu_item(GtkMenuShell
* menu
,
109 const gchar
* menu_name
, const gchar
* name
,
110 GCallback func
, guint key
, gpointer data
)
112 GtkMenuItem
*menu_item
;
115 const gchar
*menu_item_name
;
117 menu_item_name
= add_mnemonic(_(name
));
118 menu_item
= GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(menu_item_name
));
120 gtk_menu_shell_append(menu
, GTK_WIDGET(menu_item
));
124 g_signal_connect_swapped(menu_item
, "activate", func
, data
);
126 if (key
>= GDK_A
&& key
<= GDK_Z
)
127 mod
= GDK_SHIFT_MASK
;
128 else if (key
& CTRL
) {
130 mod
= GDK_CONTROL_MASK
;
134 accel_path
= g_strconcat("<GLiv>/", menu_name
, "/", name
, NULL
);
135 gtk_accel_map_add_entry(accel_path
, key
, mod
);
136 gtk_menu_item_set_accel_path(menu_item
, accel_path
);
142 static gboolean
toggle_alpha_checks(void)
144 options
->alpha_checks
^= TRUE
;
145 refresh(REFRESH_IMAGE
);
150 static gboolean
menu_fullscreen(void)
152 toggle_fullscreen(!options
->fullscreen
);
156 #define MAXIMIZE (1 << 0)
157 #define SCALE_DOWN (1 << 1)
159 static gboolean
menu_maximize(gint what
)
161 gboolean old_maximize
, old_scale_down
;
163 if (current_image
== NULL
)
166 old_maximize
= options
->maximize
;
167 old_scale_down
= options
->scaledown
;
169 options
->maximize
= ((what
& MAXIMIZE
) != 0);
170 options
->scaledown
= ((what
& SCALE_DOWN
) != 0);
172 matrix_set_max_zoom(-1, -1, TRUE
);
174 options
->maximize
= old_maximize
;
175 options
->scaledown
= old_scale_down
;
177 refresh(REFRESH_IMAGE
| REFRESH_STATUS
| APPEND_HISTORY
);
182 /* Must be kept in sync with 'enum image_position' */
187 TRANSFO_BOTTOM_RIGHT
,
194 TRANSFO_ROTATE_BIG_PLUS
,
195 TRANSFO_ROTATE_BIG_MINUS
,
196 TRANSFO_ROTATE_SMALL_PLUS
,
197 TRANSFO_ROTATE_SMALL_MINUS
,
209 static gboolean
menu_transfo(enum transfo transfo
)
211 if (current_image
== NULL
)
216 case TRANSFO_TOP_LEFT
:
217 case TRANSFO_TOP_RIGHT
:
218 case TRANSFO_BOTTOM_LEFT
:
219 case TRANSFO_BOTTOM_RIGHT
:
221 enum image_position old_pos
= options
->initial_pos
;
222 options
->initial_pos
= transfo
;
223 matrix_set_initial_position();
224 options
->initial_pos
= old_pos
;
230 case TRANSFO_MOVE_LEFT
:
231 matrix_move(MOVE_OFFSET
, 0.0);
234 case TRANSFO_MOVE_RIGHT
:
235 matrix_move(-MOVE_OFFSET
, 0.0);
238 case TRANSFO_MOVE_UP
:
239 matrix_move(0.0, MOVE_OFFSET
);
242 case TRANSFO_MOVE_DOWN
:
243 matrix_move(0.0, -MOVE_OFFSET
);
248 case TRANSFO_ROTATE_BIG_PLUS
:
249 matrix_rotate(BIG_ROTATION
);
252 case TRANSFO_ROTATE_BIG_MINUS
:
253 matrix_rotate(-BIG_ROTATION
);
256 case TRANSFO_ROTATE_SMALL_PLUS
:
257 matrix_rotate(SMALL_ROTATION
);
260 case TRANSFO_ROTATE_SMALL_MINUS
:
261 matrix_rotate(-SMALL_ROTATION
);
266 case TRANSFO_ZOOM_IN
:
267 case TRANSFO_ZOOM_OUT
:
269 gboolean zoom_pointer
= options
->zoom_pointer
;
270 options
->zoom_pointer
= FALSE
;
272 if (transfo
== TRANSFO_ZOOM_IN
)
273 zoom_in(ZOOM_FACTOR
);
275 zoom_in(1.0 / ZOOM_FACTOR
);
277 options
->zoom_pointer
= zoom_pointer
;
281 case TRANSFO_FIT_WIDTH
:
282 matrix_fit(TRUE
, FALSE
);
285 case TRANSFO_FIT_HEIGHT
:
286 matrix_fit(FALSE
, TRUE
);
302 g_printerr("Unknown transformation: %d\n", transfo
);
306 refresh(REFRESH_IMAGE
| REFRESH_STATUS
| APPEND_HISTORY
);
310 #define SEPARATOR gtk_menu_shell_append(menu, gtk_separator_menu_item_new())
312 #define ADD_MENU_ITEM(str, signal_func, key, val) \
313 add_menu_item(menu, menu_name, str, G_CALLBACK(signal_func), key, \
314 GINT_TO_POINTER(val))
316 #define ADD_MENU(str) \
318 menu = add_menu(str); \
320 gtk_menu_set_accel_group(GTK_MENU(menu), accel_group); \
323 /* Used to add an images menu. */
324 static GtkMenuItem
*add_special_menu(const gchar
* name
, GCallback rebuild_menu
)
329 gchar
*menu_name
= NULL
;
331 menu
= add_menu(name
);
333 children
= gtk_container_get_children(GTK_CONTAINER(menu
));
334 item
= GTK_MENU_ITEM(gtk_menu_get_attach_widget(GTK_MENU(menu
)));
335 g_list_free(children
);
337 ADD_MENU_ITEM(_("Rebuild this menu"), rebuild_menu
, 0, 0);
338 ADD_MENU_ITEM(_("Open thumbnails browser..."), show_tree_browser
, 0, 0);
343 #define ADD_SPECIAL_MENU(str, cb) cb(add_special_menu(str, G_CALLBACK(cb)))
345 static GtkMenuShell
*add_submenu(GtkMenuShell
* menu
, const gchar
* name
)
350 item
= add_menu_item(menu
, NULL
, name
, NULL
, 0, NULL
);
351 submenu
= GTK_MENU(gtk_menu_new());
353 gtk_menu_item_set_submenu(item
, GTK_WIDGET(submenu
));
354 gtk_menu_shell_append(GTK_MENU_SHELL(submenu
), gtk_tearoff_menu_item_new());
357 return GTK_MENU_SHELL(submenu
);
361 #define ADD_SUBMENU(name) \
363 submenu = add_submenu(menu, name); \
364 gtk_menu_set_accel_group(GTK_MENU(submenu), accel_group); \
365 submenu_name = g_strconcat(menu_name, "/", name, NULL); \
368 #define END_SUBMENU() \
371 g_free(submenu_name); \
374 #define ADD_SUBMENU_ITEM(name, action, key) \
375 add_menu_item(submenu, submenu_name, name, G_CALLBACK(menu_transfo), key, \
376 GINT_TO_POINTER(action))
378 /* GtkAction are not supported in gtk+-2 < 2.3 */
379 extern const guint gtk_minor_version
;
382 GtkAccelGroup
*create_menus(void)
384 GtkMenuShell
*menu
, *submenu
;
385 GtkAccelGroup
*accel_group
;
386 GtkMenuItem
*item
, *current_image_item
, *every_image_item
;
387 gchar
*menu_name
, *submenu_name
;
389 menu_bar
= GTK_MENU_BAR(gtk_menu_bar_new());
391 /* This will go away when we support actions. */
392 if (gtk_minor_version
>= 3)
393 g_signal_connect(menu_bar
, "can-activate-accel", G_CALLBACK(gtk_true
),
396 accel_group
= gtk_accel_group_new();
398 gtk_settings_set_long_property(gtk_settings_get_default(),
399 "gtk-can-change-accels", 1, "GLiv");
403 ADD_MENU(N_("File"));
404 ADD_MENU_ITEM(N_("Open..."), menu_open
, GDK_o
, FALSE
);
405 ADD_MENU_ITEM(N_("Open directory..."), menu_open
, GDK_O
, TRUE
);
406 SEPARATOR
; /* ------------------------------------ */
407 ADD_MENU_ITEM(N_("Load collection..."), deserialize_collection
, 0, 0);
408 ADD_MENU_ITEM(N_("Save collection..."), serialize_collection_gui
, 0, 0);
409 SEPARATOR
; /* ------------------------------------ */
410 ADD_MENU_ITEM(N_("Quit"), gui_quit
, GDK_q
, 0);
414 ADD_MENU(N_("Commands"));
415 ADD_MENU_ITEM(N_("Load previous image"), load_direction
, GDK_p
, -1);
416 ADD_MENU_ITEM(N_("Load next image"), load_direction
, GDK_n
, 1);
417 ADD_MENU_ITEM(N_("Load the Nth image..."), menu_image_nr
, GDK_g
, 0);
418 ADD_MENU_ITEM(N_("Load first image"), load_1st_image
, GDK_comma
, 0);
419 ADD_MENU_ITEM(N_("Load last image"), load_last_image
, GDK_period
, 0);
420 ADD_MENU_ITEM(N_("Load random image"), load_random_image
, GDK_x
, 0);
421 ADD_MENU_ITEM(N_("Reload the current image"), reload_current_image
, 0, 0);
422 SEPARATOR
; /* ------------------------------------ */
423 ADD_MENU_ITEM(N_("Sort images list"), reorder_files
, 0, FALSE
);
424 ADD_MENU_ITEM(N_("Shuffle images list"), reorder_files
, 0, TRUE
);
425 SEPARATOR
; /* ------------------------------------ */
426 ADD_MENU_ITEM(N_("Rebuild images menus"), rebuild_images_menus
, 0, 0);
427 item
= ADD_MENU_ITEM(N_("Stop rebuilding the images menu"),
428 cancel_using_tree
, 0, 0);
429 set_stop_rebuilding_menu(item
);
430 SEPARATOR
; /* ------------------------------------ */
431 ADD_MENU_ITEM(N_("Toggle floating windows"), toggle_floating_windows
,
433 item
= ADD_MENU_ITEM(N_("Start the slide show"), toggle_slide_show
,
435 set_slide_show_menu(item
);
437 ADD_MENU_ITEM(N_("Remove the current file"), confirm_remove_current
,
439 SEPARATOR
; /* ------------------------------------ */
440 ADD_MENU_ITEM(N_("Edit actions..."), edit_actions
, 0, 0);
441 current_image_item
= ADD_MENU_ITEM(_("Action on the current image"),
443 every_image_item
= ADD_MENU_ITEM(_("Action on every image"), NULL
, 0, 0);
445 /*************************/
446 /* Transformations menu. */
447 ADD_MENU(N_("Transformations"));
448 ADD_MENU_ITEM(N_("Undo"), undo
, GDK_u
, 0);
449 ADD_MENU_ITEM(N_("Redo"), redo
, GDK_y
, 0);
450 ADD_MENU_ITEM(N_("Clear history"), clear_history
, GDK_c
, 0);
451 SEPARATOR
; /* ------------------------------------ */
452 ADD_SUBMENU(N_("Move"));
453 ADD_SUBMENU_ITEM(N_("Move left"), TRANSFO_MOVE_LEFT
, GDK_Left
);
454 ADD_SUBMENU_ITEM(N_("Move right"), TRANSFO_MOVE_RIGHT
, GDK_Right
);
455 ADD_SUBMENU_ITEM(N_("Move up"), TRANSFO_MOVE_UP
, GDK_Up
);
456 ADD_SUBMENU_ITEM(N_("Move down"), TRANSFO_MOVE_DOWN
, GDK_Down
);
459 ADD_SUBMENU(N_("Set position"));
460 ADD_SUBMENU_ITEM(N_("Center"), TRANSFO_CENTER
, 0);
461 ADD_SUBMENU_ITEM(N_("Top left"), TRANSFO_TOP_LEFT
, GDK_Home
);
462 ADD_SUBMENU_ITEM(N_("Top right"), TRANSFO_TOP_RIGHT
, 0);
463 ADD_SUBMENU_ITEM(N_("Bottom left"), TRANSFO_BOTTOM_LEFT
, 0);
464 ADD_SUBMENU_ITEM(N_("Bottom right"), TRANSFO_BOTTOM_RIGHT
, 0);
467 ADD_SUBMENU(N_("Rotation"));
468 ADD_SUBMENU_ITEM(N_("Rotate +90 deg"), TRANSFO_ROTATE_BIG_PLUS
,
470 ADD_SUBMENU_ITEM(N_("Rotate -90 deg"), TRANSFO_ROTATE_BIG_MINUS
,
472 ADD_SUBMENU_ITEM(N_("Rotate +0.1 deg"), TRANSFO_ROTATE_SMALL_PLUS
,
474 ADD_SUBMENU_ITEM(N_("Rotate -0.1 deg"), TRANSFO_ROTATE_SMALL_MINUS
,
478 SEPARATOR
; /* ------------------------------------ */
480 ADD_MENU_ITEM(N_("Horizontal flip"), menu_transfo
, GDK_z
, TRANSFO_FLIP_H
);
482 ADD_MENU_ITEM(N_("Vertical flip"), menu_transfo
, GDK_e
, TRANSFO_FLIP_V
);
484 SEPARATOR
; /* ------------------------------------ */
486 ADD_MENU_ITEM(N_("Maximize small image"), menu_maximize
, GDK_M
, MAXIMIZE
);
487 ADD_MENU_ITEM(N_("Scale down large image"), menu_maximize
, GDK_l
,
489 ADD_MENU_ITEM(N_("Image fit window"), menu_maximize
, GDK_m
,
490 MAXIMIZE
| SCALE_DOWN
);
492 ADD_MENU_ITEM(N_("Zoom in"), menu_transfo
, GDK_plus
, TRANSFO_ZOOM_IN
);
493 ADD_MENU_ITEM(N_("Zoom out"), menu_transfo
, GDK_minus
, TRANSFO_ZOOM_OUT
);
494 ADD_MENU_ITEM(N_("Fit width"), menu_transfo
, 0, TRANSFO_FIT_WIDTH
);
495 ADD_MENU_ITEM(N_("Fit height"), menu_transfo
, 0, TRANSFO_FIT_HEIGHT
);
497 SEPARATOR
; /* ------------------------------------ */
499 ADD_MENU_ITEM(N_("Reset"), menu_transfo
, GDK_r
, TRANSFO_RESET
);
503 ADD_MENU(N_("Options"));
504 ADD_MENU_ITEM(N_("Toggle Fullscreen mode"), menu_fullscreen
, GDK_f
, 0);
505 ADD_MENU_ITEM(N_("Toggle Menu Bar"), toggle_menu_bar
, GDK_b
, 0);
506 ADD_MENU_ITEM(N_("Toggle Status Bar"), toggle_status_bar
, GDK_i
, 0);
507 ADD_MENU_ITEM(N_("Toggle Scrollbars"), toggle_scrollbars
, GDK_s
, 0);
508 ADD_MENU_ITEM(N_("Toggle Alpha checks"), toggle_alpha_checks
, GDK_a
, 0);
509 SEPARATOR
; /* ------------------------------------ */
510 ADD_MENU_ITEM(N_("Hide the cursor"), hide_cursor
, GDK_d
, 0);
511 ADD_MENU_ITEM(N_("Set this window as server"), start_server
, 0, 0);
512 SEPARATOR
; /* ------------------------------------ */
513 ADD_MENU_ITEM(N_("Options..."), show_options
, GDK_t
, 0);
515 /*********************/
516 /* Directories menu. */
517 ADD_SPECIAL_MENU(N_("Directories"), rebuild_directories
);
521 ADD_SPECIAL_MENU(N_("Images"), rebuild_images
);
523 /*******************************/
524 /* Menus rebuilding indicator. */
525 item
= GTK_MENU_ITEM(gtk_menu_item_new_with_label(""));
526 set_rebuilding_entry(item
);
527 gtk_widget_set_sensitive(GTK_WIDGET(item
), FALSE
);
528 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar
), GTK_WIDGET(item
));
532 ADD_MENU(N_("Help"));
533 ADD_MENU_ITEM(N_("About..."), show_about_box
, 0, 0);
534 ADD_MENU_ITEM(N_("Controls..."), toggle_help
, GDK_h
, 0);
539 init_actions(accel_group
, current_image_item
, every_image_item
);