diff --git a/fullscreen_controls.py b/fullscreen_controls.py new file mode 100644 index 0000000..9d9ec72 --- /dev/null +++ b/fullscreen_controls.py @@ -0,0 +1,58 @@ +from gi.repository import Gtk + + +@Gtk.Template(resource_path="/io/thomasross/mirage/fullscreen-controls.ui") +class FullscreenControls(Gtk.Widget): + __gtype_name__ = "FullscreenControls" + + slideshow_delay_adjustment = Gtk.Template.Child() + + left_window = Gtk.Template.Child() + slideshow_start_button = Gtk.Template.Child() + slideshow_stop_button = Gtk.Template.Child() + + right_window = Gtk.Template.Child() + + def insert_action_group(self, *args, **kwargs): + self.left_window.insert_action_group(*args, **kwargs) + self.right_window.insert_action_group(*args, **kwargs) + + def set_screen(self, *args, **kwargs): + self.left_window.set_screen(*args, **kwargs) + self.right_window.set_screen(*args, **kwargs) + + def show_all(self, *args, **kwargs): + self.left_window.show_all(*args, **kwargs) + self.right_window.show_all(*args, **kwargs) + + def hide(self, *args, **kwargs): + self.left_window.hide(*args, **kwargs) + self.right_window.hide(*args, **kwargs) + + def modify_bg(self, *args, **kwargs): + self.left_window.modify_bg(*args, **kwargs) + self.right_window.modify_bg(*args, **kwargs) + + def position(self, width, height, x, y): + left_window_height = self.left_window.get_allocation().height + right_window_width = self.right_window.get_allocation().width + right_window_height = self.right_window.get_allocation().height + self.left_window.move(2 + x, int(height - left_window_height - 2)) + self.right_window.move( + width - right_window_width - 2 + x, int(height - right_window_height - 2) + ) + + def set_slideshow_delay(self, delay): + self.slideshow_delay_adjustment.set_value(delay) + + def set_slideshow_playing(self, playing): + if playing: + self.slideshow_start_button.hide() + self.slideshow_start_button.set_no_show_all(True) + self.slideshow_stop_button.show() + self.slideshow_stop_button.set_no_show_all(False) + else: + self.slideshow_start_button.show() + self.slideshow_start_button.set_no_show_all(False) + self.slideshow_stop_button.hide() + self.slideshow_stop_button.set_no_show_all(True) diff --git a/mirage.py b/mirage.py index 2825ec1..48e0425 100755 --- a/mirage.py +++ b/mirage.py @@ -24,11 +24,16 @@ gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Gdk, GdkPixbuf, GObject, GLib +from gi.repository import Gtk, Gdk, GdkPixbuf, GObject, GLib, Gio import os, sys, getopt, configparser, string, gc import random, urllib.request, gettext, locale import stat, time, subprocess, shutil, filecmp import tempfile, socket, threading + +resources = Gio.resource_load("mirage.gresource") +Gio.resources_register(resources) + +from fullscreen_controls import FullscreenControls try: import hashlib @@ -68,9 +73,15 @@ return False -class Base: - def __init__(self): - +class Base(Gtk.Application): + def __init__(self, *args, **kwargs): + super().__init__( + *args, + application_id="io.thomasross.mirage", + flags=Gio.ApplicationFlags.NON_UNIQUE + ) + + def do_activate(self): Gdk.threads_init() # FIX THIS! Does not work on windows and what happens if mo-files exists @@ -146,7 +157,6 @@ self.slideshow_mode = False self.slideshow_random = False self.slideshow_controls_visible = False # fullscreen slideshow controls - self.controls_moving = False self.zoomvalue = 2 self.quality_save = 90 self.updating_adjustments = False @@ -160,6 +170,12 @@ "Create Thumbnail", "Create Thumbnails", "Move to Favorites", + ] + self.action_hashes = [ + "d47444d623dfd3d943b50ce5f43f3a0937dc25d6", + "2984214616cbf75e6035c9a1374f6419e40719b1", + "b80d24c876c479486571a37ad2ef90f897f5cfff", + "d497998eee206191ffc6d1045b118038e3ab83c6", ] self.action_shortcuts = [ "e", @@ -183,8 +199,6 @@ self.image_zoomed = False self.start_in_fullscreen = False self.running_custom_actions = False - self.merge_id = None - self.actionGroupCustom = None self.merge_id_recent = None self.actionGroupRecent = None self.open_hidden_files = False @@ -321,8 +335,10 @@ and conf.has_option("actions", "shortcuts[" + str(i) + "]") and conf.has_option("actions", "batch[" + str(i) + "]") ): - self.action_names.append( - conf.get("actions", "names[" + str(i) + "]") + name = conf.get("actions", "names[" + str(i) + "]") + self.action_names.append(name) + self.action_hashes.append( + hashlib.sha1(name.encode("utf8")).hexdigest() ) self.action_commands.append( conf.get("actions", "commands[" + str(i) + "]") @@ -363,374 +379,62 @@ self.find_path("mirage_blank.png") ) - # Define the main menubar and toolbar: - actions = ( - ("FileMenu", None, _("_File")), - ("EditMenu", None, _("_Edit")), - ("ViewMenu", None, _("_View")), - ("GoMenu", None, _("_Go")), - ("HelpMenu", None, _("_Help")), - ("ActionSubMenu", None, _("Custom _Actions")), + # Define the actions + self.action_group = Gio.SimpleActionGroup() + + actions = [ + ## Main Menubar + # File + ("open-file", self.open_file), + ("open-folder", self.open_folder), + ("open-file-remote", self.open_file_remote), + ("save-image", self.save_image), + ("save-image-as", self.save_image_as), + ("screenshot", self.screenshot), + ("show-properties", self.show_properties), + ("exit-app", self.exit_app), + # Edit + ("rotate-left", self.rotate_left), + ("rotate-right", self.rotate_right), + ("flip-image-vert", self.flip_image_vert), + ("flip-image-horiz", self.flip_image_horiz), + ("crop-image", self.crop_image), + ("resize-image", self.resize_image), + ("saturation", self.saturation), + ("rename-image", self.rename_image), + ("delete-image", self.delete_image), + ("show-custom-actions", self.show_custom_actions), + ("show-prefs", self.show_prefs), + # View + ("zoom-out", self.zoom_out), + ("zoom-in", self.zoom_in), + ("zoom-1-to-1", self.zoom_1_to_1_action), + ("zoom-to-fit-window", self.zoom_to_fit_window_action), + ("toggle-toolbar", None, None, "true", self.toggle_toolbar), + ("toggle-thumbpane", None, None, "true", self.toggle_thumbpane), + ("toggle-status-bar", None, None, "true", self.toggle_status_bar), + ("enter-fullscreen", self.enter_fullscreen), + # Go + ("goto-next-image", self.goto_next_image), + ("goto-prev-image", self.goto_prev_image), + ("goto-random-image", self.goto_random_image), + ("goto-first-image", self.goto_first_image), + ("goto-last-image", self.goto_last_image), + ("start-slideshow", self.toggle_slideshow), + ("stop-slideshow", self.toggle_slideshow), + # Help + ("show-help", self.show_help), + ("show-about", self.show_about), + # Other ( - "Open Image", - Gtk.STOCK_FILE, - _("_Open Image..."), - "O", - _("Open Image"), - self.open_file, + "toggle-slideshow-shuffle", + None, + None, + "false", + self.toggle_slideshow_shuffle, ), - ( - "Open Remote Image", - Gtk.STOCK_NETWORK, - _("Open _Remote image..."), - None, - _("Open Remote Image"), - self.open_file_remote, - ), - ( - "Open Folder", - Gtk.STOCK_DIRECTORY, - _("Open _Folder..."), - "F", - _("Open Folder"), - self.open_folder, - ), - ( - "Save", - Gtk.STOCK_SAVE, - _("_Save Image"), - "S", - _("Save Image"), - self.save_image, - ), - ( - "Save As", - Gtk.STOCK_SAVE, - _("Save Image _As..."), - "S", - _("Save Image As"), - self.save_image_as, - ), - ("Crop", None, _("_Crop..."), None, _("Crop Image"), self.crop_image), - ( - "Resize", - None, - _("R_esize..."), - None, - _("Resize Image"), - self.resize_image, - ), - ( - "Saturation", - None, - _("_Saturation..."), - None, - _("Modify saturation"), - self.saturation, - ), - ("Quit", Gtk.STOCK_QUIT, _("_Quit"), "Q", _("Quit"), self.exit_app), - ( - "Previous Image", - Gtk.STOCK_GO_BACK, - _("_Previous Image"), - "Left", - _("Previous Image"), - self.goto_prev_image, - ), - ( - "Next Image", - Gtk.STOCK_GO_FORWARD, - _("_Next Image"), - "Right", - _("Next Image"), - self.goto_next_image, - ), - ( - "Previous2", - Gtk.STOCK_GO_BACK, - _("_Previous"), - "Left", - _("Previous"), - self.goto_prev_image, - ), - ( - "Next2", - Gtk.STOCK_GO_FORWARD, - _("_Next"), - "Right", - _("Next"), - self.goto_next_image, - ), - ( - "Random Image", - None, - _("_Random Image"), - "R", - _("Random Image"), - self.goto_random_image, - ), - ( - "First Image", - Gtk.STOCK_GOTO_FIRST, - _("_First Image"), - "Home", - _("First Image"), - self.goto_first_image, - ), - ( - "Last Image", - Gtk.STOCK_GOTO_LAST, - _("_Last Image"), - "End", - _("Last Image"), - self.goto_last_image, - ), - ( - "In", - Gtk.STOCK_ZOOM_IN, - _("Zoom _In"), - "Up", - _("Zoom In"), - self.zoom_in, - ), - ( - "Out", - Gtk.STOCK_ZOOM_OUT, - _("Zoom _Out"), - "Down", - _("Zoom Out"), - self.zoom_out, - ), - ( - "Fit", - Gtk.STOCK_ZOOM_FIT, - _("Zoom To _Fit"), - "0", - _("Fit"), - self.zoom_to_fit_window_action, - ), - ( - "1:1", - Gtk.STOCK_ZOOM_100, - _("_1:1"), - "1", - _("1:1"), - self.zoom_1_to_1_action, - ), - ( - "Rotate Left", - None, - _("Rotate _Left"), - "Left", - _("Rotate Left"), - self.rotate_left, - ), - ( - "Rotate Right", - None, - _("Rotate _Right"), - "Right", - _("Rotate Right"), - self.rotate_right, - ), - ( - "Flip Vertically", - None, - _("Flip _Vertically"), - "V", - _("Flip Vertically"), - self.flip_image_vert, - ), - ( - "Flip Horizontally", - None, - _("Flip _Horizontally"), - "H", - _("Flip Horizontally"), - self.flip_image_horiz, - ), - ("About", Gtk.STOCK_ABOUT, _("_About"), None, _("About"), self.show_about), - ( - "Contents", - Gtk.STOCK_HELP, - _("_Contents"), - "F1", - _("Contents"), - self.show_help, - ), - ( - "Preferences", - Gtk.STOCK_PREFERENCES, - _("_Preferences..."), - "P", - _("Preferences"), - self.show_prefs, - ), - ( - "Full Screen", - Gtk.STOCK_FULLSCREEN, - _("_Full Screen"), - "F11", - _("Full Screen"), - self.enter_fullscreen, - ), - ( - "Exit Full Screen", - Gtk.STOCK_LEAVE_FULLSCREEN, - _("E_xit Full Screen"), - None, - _("Exit Full Screen"), - self.leave_fullscreen, - ), - ( - "Start Slideshow", - Gtk.STOCK_MEDIA_PLAY, - _("_Start Slideshow"), - "F5", - _("Start Slideshow"), - self.toggle_slideshow, - ), - ( - "Stop Slideshow", - Gtk.STOCK_MEDIA_STOP, - _("_Stop Slideshow"), - "F5", - _("Stop Slideshow"), - self.toggle_slideshow, - ), - ( - "Delete Image", - Gtk.STOCK_DELETE, - _("_Delete..."), - "Delete", - _("Delete Image"), - self.delete_image, - ), - ( - "Rename Image", - None, - _("Re_name..."), - "F2", - _("Rename Image"), - self.rename_image, - ), - ( - "Take Screenshot", - None, - _("_Take Screenshot..."), - None, - _("Take Screenshot"), - self.screenshot, - ), - ( - "Properties", - Gtk.STOCK_PROPERTIES, - _("_Properties..."), - None, - _("Properties"), - self.show_properties, - ), - ( - "Custom Actions", - None, - _("_Configure..."), - None, - _("Custom Actions"), - self.show_custom_actions, - ), - ("MiscKeysMenuHidden", None, "Keys"), - ( - "Escape", - None, - "", - "Escape", - _("Exit Full Screen"), - self.leave_fullscreen, - ), - ("Minus", None, "", "minus", _("Zoom Out"), self.zoom_out), - ("Plus", None, "", "plus", _("Zoom In"), self.zoom_in), - ("Equal", None, "", "equal", _("Zoom In"), self.zoom_in), - ("Space", None, "", "space", _("Next Image"), self.goto_next_image), - ( - "Ctrl-KP_Insert", - None, - "", - "KP_Insert", - _("Fit"), - self.zoom_to_fit_window_action, - ), - ( - "Ctrl-KP_End", - None, - "", - "KP_End", - _("1:1"), - self.zoom_1_to_1_action, - ), - ( - "Ctrl-KP_Subtract", - None, - "", - "KP_Subtract", - _("Zoom Out"), - self.zoom_out, - ), - ("Ctrl-KP_Add", None, "", "KP_Add", _("Zoom In"), self.zoom_in), - ( - "Ctrl-KP_0", - None, - "", - "KP_0", - _("Fit"), - self.zoom_to_fit_window_action, - ), - ("Ctrl-KP_1", None, "", "KP_1", _("1:1"), self.zoom_1_to_1_action), - ("Full Screen Key", None, "", "Return", None, self.enter_fullscreen), - ("Prev", None, "", "Up", _("Previous Image"), self.goto_prev_image), - ("Next", None, "", "Down", _("Next Image"), self.goto_next_image), - ("PgUp", None, "", "Page_Up", _("Previous Image"), self.goto_prev_image), - ("PgDn", None, "", "Page_Down", _("Next Image"), self.goto_next_image), - ( - "BackSpace", - None, - "", - "BackSpace", - _("Previous Image"), - self.goto_prev_image, - ), - ("OriginalSize", None, "", "1", _("1:1"), self.zoom_1_to_1_action), - ("ZoomIn", None, "", "KP_Add", _("Zoom In"), self.zoom_in), - ("ZoomOut", None, "", "KP_Subtract", _("Zoom Out"), self.zoom_out), - ) - toggle_actions = ( - ( - "Status Bar", - None, - _("_Status Bar"), - None, - _("Status Bar"), - self.toggle_status_bar, - self.statusbar_show, - ), - ( - "Toolbar", - None, - _("_Toolbar"), - None, - _("Toolbar"), - self.toggle_toolbar, - self.toolbar_show, - ), - ( - "Thumbnails Pane", - None, - _("Thumbnails _Pane"), - None, - _("Thumbnails Pane"), - self.toggle_thumbpane, - self.thumbpane_show, - ), - ) + ] + self.action_group.add_action_entries(actions) # Populate keys[]: self.keys = [] @@ -739,147 +443,53 @@ if actions[i][3] != None: self.keys.append([actions[i][4], actions[i][3]]) - uiDescription = """ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - """ - # Create interface - self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL) + self.window = Gtk.ApplicationWindow.new(self) self.window.set_has_resize_grip(True) + self.window.insert_action_group("app", self.action_group) + self.popup_menu.insert_action_group("app", self.action_group) + self.fullscreen_controls.insert_action_group("app", self.action_group) self.update_title() icon_path = self.find_path("mirage.png") try: - Gtk.window_set_default_icon_from_file(icon_path) + Gtk.Window.set_default_icon_from_file(icon_path) except: pass vbox = Gtk.VBox(False, 0) - self.UIManager = Gtk.UIManager() - actionGroup = Gtk.ActionGroup("Actions") - actionGroup.add_actions(actions) - actionGroup.add_toggle_actions(toggle_actions) - self.UIManager.insert_action_group(actionGroup, 0) - self.UIManager.add_ui_from_string(uiDescription) + + # Hidden hotkeys + hotkeys = ( + ("app.zoom-out", "KP_Subtract"), + ("app.zoom-out", "minus"), + ("app.zoom-out", "KP_Subtract"), + ("app.zoom-in", "plus"), + ("app.zoom-in", "equal"), + ("app.zoom-in", "KP_Add"), + ("app.zoom-in", "KP_Add"), + ("app.zoom-1-to-1", "1"), + ("app.zoom-1-to-1", "KP_End"), + ("app.zoom-1-to-1", "KP_1"), + ("app.zoom-to-fit-window", "KP_Insert"), + ("app.zoom-to-fit-window", "KP_0"), + ("app.enter-fullscreen", "Return"), + ("app.leave-fullscreen", "Escape"), + ("app.goto-next-image", "space"), + ("app.goto-next-image", "Down"), + ("app.goto-next-image", "Page_Down"), + ("app.goto-prev-image", "BackSpace"), + ("app.goto-prev-image", "Up"), + ("app.goto-prev-image", "Page_Up"), + ) + for action_name, hotkey in hotkeys: + self.set_accels_for_action( + action_name, self.get_accels_for_action(action_name) + [hotkey] + ) + self.refresh_custom_actions_menu() self.refresh_recent_files_menu() - self.window.add_accel_group(self.UIManager.get_accel_group()) - self.menubar = self.UIManager.get_widget("/MainMenu") - vbox.pack_start(self.menubar, False, False, 0) - self.toolbar = self.UIManager.get_widget("/MainToolbar") + vbox.pack_start(self.toolbar, False, False, 0) + self.layout = Gtk.Layout() self.vscroll = Gtk.VScrollbar(None) self.vscroll.set_adjustment(self.layout.get_vadjustment()) @@ -967,66 +577,10 @@ self.window.add(vbox) self.window.set_size_request(width, height) - # Slideshow control: - self.slideshow_window = Gtk.Window(Gtk.WindowType.POPUP) - self.slideshow_controls = Gtk.HBox() - self.ss_back = Gtk.Button() - self.ss_back.add( - Gtk.Image.new_from_stock(Gtk.STOCK_GO_BACK, Gtk.IconSize.BUTTON) - ) - self.ss_back.set_property("can-focus", False) - self.ss_back.connect("clicked", self.goto_prev_image) - self.ss_start = Gtk.Button("", Gtk.STOCK_MEDIA_PLAY) - self.ss_start.get_child().get_child().get_children()[1].set_text("") - self.ss_start.set_property("can-focus", False) - self.ss_start.connect("clicked", self.toggle_slideshow) - self.ss_stop = Gtk.Button("", Gtk.STOCK_MEDIA_STOP) - self.ss_stop.get_child().get_child().get_children()[1].set_text("") - self.ss_stop.set_property("can-focus", False) - self.ss_stop.connect("clicked", self.toggle_slideshow) - self.ss_forward = Gtk.Button("", Gtk.STOCK_GO_FORWARD) - self.ss_forward.get_child().get_child().get_children()[1].set_text("") - self.ss_forward.set_property("can-focus", False) - self.ss_forward.connect("clicked", self.goto_next_image) - self.slideshow_controls.pack_start(self.ss_back, False, False, 0) - self.slideshow_controls.pack_start(self.ss_start, False, False, 0) - self.slideshow_controls.pack_start(self.ss_stop, False, False, 0) - self.slideshow_controls.pack_start(self.ss_forward, False, False, 0) - self.slideshow_window.add(self.slideshow_controls) if self.simple_bgcolor: - self.slideshow_window.modify_bg(Gtk.StateType.NORMAL, None) + self.fullscreen_controls.modify_bg(Gtk.StateType.NORMAL, None) else: - self.slideshow_window.modify_bg(Gtk.StateType.NORMAL, self.bgcolor) - self.slideshow_window2 = Gtk.Window(Gtk.WindowType.POPUP) - self.slideshow_controls2 = Gtk.HBox() - try: - self.ss_exit = Gtk.Button("", Gtk.STOCK_LEAVE_FULLSCREEN) - self.ss_exit.get_child().get_child().get_children()[1].set_text("") - except: - self.ss_exit = Gtk.Button() - self.ss_exit.set_image( - Gtk.Image.new_from_stock("leave-fullscreen", Gtk.IconSize.MENU) - ) - self.ss_exit.set_property("can-focus", False) - self.ss_exit.connect("clicked", self.leave_fullscreen) - self.ss_randomize = Gtk.ToggleButton() - self.ss_randomize.set_image( - Gtk.Image.new_from_icon_name("media-playlist-shuffle", Gtk.IconSize.MENU) - ) - self.ss_randomize.connect("toggled", self.random_changed) - - spin_adj = Gtk.Adjustment(self.slideshow_delay, 0, 50000, 1, 100, 0) - self.ss_delayspin = Gtk.SpinButton.new(spin_adj, 1.0, 0) - self.ss_delayspin.set_numeric(True) - self.ss_delayspin.connect("changed", self.delay_changed) - self.slideshow_controls2.pack_start(self.ss_randomize, False, False, 0) - self.slideshow_controls2.pack_start(self.ss_delayspin, False, False, 0) - self.slideshow_controls2.pack_start(self.ss_exit, False, False, 0) - self.slideshow_window2.add(self.slideshow_controls2) - if self.simple_bgcolor: - self.slideshow_window2.modify_bg(Gtk.StateType.NORMAL, None) - else: - self.slideshow_window2.modify_bg(Gtk.StateType.NORMAL, self.bgcolor) + self.fullscreen_controls.modify_bg(Gtk.StateType.NORMAL, self.bgcolor) # Connect signals self.window.connect("delete_event", self.delete_event) @@ -1060,12 +614,15 @@ ) self.layout.connect("motion-notify-event", self.mouse_moved) self.layout.connect("button-release-event", self.button_released) - self.imageview.connect("expose-event", self.expose_event) + # self.imageview.connect("expose-event", self.expose_event) TODO self.thumb_sel_handler = self.thumbpane.get_selection().connect( "changed", self.thumbpane_selection_changed ) self.thumb_scroll_handler = self.thumbscroll.get_vscrollbar().connect( "value-changed", self.thumbpane_scrolled + ) + self.fullscreen_controls.slideshow_delay_adjustment.connect( + "value-changed", self.slideshow_delay_changed ) # Since GNOME does its own thing for the toolbar style... @@ -1112,32 +669,17 @@ ): go_into_fullscreen = True if go_into_fullscreen or self.start_in_fullscreen: - self.enter_fullscreen(None) + self.enter_fullscreen(None, None, None) self.statusbar.set_no_show_all(True) self.statusbar2.set_no_show_all(True) self.toolbar.set_no_show_all(True) - self.menubar.set_no_show_all(True) self.thumbscroll.set_no_show_all(True) self.window.show_all() - self.ss_exit.set_size_request( - self.ss_start.size_request()[0], self.ss_stop.size_request()[1] - ) - self.ss_randomize.set_size_request(self.ss_start.size_request()[0], -1) - self.ss_start.set_size_request(self.ss_start.size_request()[0] * 2, -1) - self.ss_stop.set_size_request(self.ss_stop.size_request()[0] * 2, -1) - self.UIManager.get_widget("/Popup/Exit Full Screen").hide() + self.set_leave_fullscreen_visible(False) self.layout.set_can_focus(True) self.window.set_focus(self.layout) - # sets the visibility of some menu entries self.set_slideshow_sensitivities() - self.UIManager.get_widget("/MainMenu/MiscKeysMenuHidden").set_property( - "visible", False - ) - if opts != []: - for o, a in opts: - if o in ("-f", "--fullscreen"): - self.UIManager.get_widget("/Popup/Exit Full Screen").show() # If arguments (filenames) were passed, try to open them: self.image_list = [] @@ -1152,7 +694,25 @@ if opts != []: for o, a in opts: if o in ("-s", "--slideshow"): - self.toggle_slideshow(None) + self.toggle_slideshow(None, None, None) + + def do_startup(self): + Gtk.Application.do_startup(self) + + toolbar_builder = Gtk.Builder.new_from_resource( + "/io/thomasross/mirage/toolbar.ui" + ) + self.toolbar = toolbar_builder.get_object("toolbar") + self.fullscreen_controls = FullscreenControls() + self.popup_menu = Gtk.Menu.new_from_model(self.get_menu_by_id("popup-menu")) + + def add_remove_action(self, action_name, activate, visible): + if visible and not self.action_group.lookup_action(action_name): + action = Gio.SimpleAction.new(action_name, None) + action.connect("activate", activate, None) + self.action_group.add_action(action) + elif not visible: + self.action_group.remove_action(action_name) def get_pointer(self, window): display = window.get_display() @@ -1162,98 +722,52 @@ return window.get_device_position(device)[1:] def refresh_recent_files_menu(self): - if self.merge_id_recent: - self.UIManager.remove_ui(self.merge_id_recent) - if self.actionGroupRecent: - self.UIManager.remove_action_group(self.actionGroupRecent) - self.actionGroupRecent = None - self.actionGroupRecent = Gtk.ActionGroup("RecentFiles") - self.UIManager.ensure_update() - for i in range(len(self.recentfiles)): - if len(self.recentfiles[i]) > 0: - filename = self.recentfiles[i].split("/")[-1] - if len(filename) > 0: - if len(filename) > 27: - # Replace end of file name (excluding extension) with .. - try: - menu_name = ( - filename[:25] + ".." + os.path.splitext(filename)[1] - ) - except: - menu_name = filename[0] - else: - menu_name = filename - menu_name = menu_name.replace("_", "__") - action = [ - ( - str(i), - None, - menu_name, - "" + str(i + 1), - None, - self.recent_action_click, - ) - ] - self.actionGroupRecent.add_actions(action) - uiDescription = """ - - - - - """ - for i in range(len(self.recentfiles)): - if len(self.recentfiles[i]) > 0: - uiDescription = ( - uiDescription + """""" - ) - uiDescription = uiDescription + """""" - self.merge_id_recent = self.UIManager.add_ui_from_string(uiDescription) - self.UIManager.insert_action_group(self.actionGroupRecent, 0) - self.UIManager.get_widget("/MainMenu/MiscKeysMenuHidden").set_property( - "visible", False - ) + recent_files_section = self.get_menu_by_id("recent-files-section") + + # Clear the old recent files + recent_files_section.remove_all() + for action in self.action_group.list_actions(): + if action.startswith("recent-file-{}"): + self.action_group.remove_action(action) + + for i, recent_file in enumerate(self.recentfiles): + filename = os.path.basename(recent_file) + if not filename: + continue + + if len(filename) > 27: + filename = "{}..{}".format(filename[:25], os.path.splitext(filename)[1]) + + action_name = "recent-file-{}".format( + hashlib.sha1(recent_file.encode("utf8")).hexdigest() + ) + action = Gio.SimpleAction.new(action_name, None) + action.connect("activate", self.recent_action_click, recent_file) + self.action_group.add_action(action) + self.set_accels_for_action("app." + action_name, ["{}".format(i + 1)]) + + menu_item = Gio.MenuItem.new(filename, "app." + action_name) + recent_files_section.insert_item(i, menu_item) def refresh_custom_actions_menu(self): - if self.merge_id: - self.UIManager.remove_ui(self.merge_id) - if self.actionGroupCustom: - self.UIManager.remove_action_group(self.actionGroupCustom) - self.actionGroupCustom = None - self.actionGroupCustom = Gtk.ActionGroup("CustomActions") - self.UIManager.ensure_update() - for i in range(len(self.action_names)): - action = [ - ( - self.action_names[i], - None, - self.action_names[i], - self.action_shortcuts[i], - None, - self.custom_action_click, - ) - ] - self.actionGroupCustom.add_actions(action) - uiDescription = """ - - - - - """ - for i in range(len(self.action_names)): - uiDescription = ( - uiDescription - + """""" - ) - uiDescription = uiDescription + """""" - self.merge_id = self.UIManager.add_ui_from_string(uiDescription) - self.UIManager.insert_action_group(self.actionGroupCustom, 0) - self.UIManager.get_widget("/MainMenu/MiscKeysMenuHidden").set_property( - "visible", False - ) + custom_actions_section = self.get_menu_by_id("custom-actions-section") + + # Clear the old actions + custom_actions_section.remove_all() + for action in self.action_group.list_actions(): + if action.startswith("custom-"): + self.action_group.remove_action(action) + + for i, name in enumerate(self.action_names): + action_name = "custom-{}".format(self.action_hashes[i]) + + action = Gio.SimpleAction.new(action_name, None) + action.connect("activate", self.custom_action_click, self.action_hashes[i]) + self.action_group.add_action(action) + self.set_accels_for_action("app." + action_name, [self.action_shortcuts[i]]) + + menu_item = Gio.MenuItem.new(name, "app." + action_name) + custom_actions_section.insert_item(i, menu_item) def thumbpane_update_images(self, clear_first=False, force_upto_imgnum=-1): self.stop_now = False @@ -1543,12 +1057,12 @@ if event.keyval == Gdk.keyval_from_name( "Left" ) or event.keyval == Gdk.keyval_from_name("Up"): - self.goto_prev_image(None) + self.goto_prev_image(None, None, None) return elif event.keyval == Gdk.keyval_from_name( "Right" ) or event.keyval == Gdk.keyval_from_name("Down"): - self.goto_next_image(None) + self.goto_next_image(None, None, None) return shortcut = Gtk.accelerator_name(event.keyval, event.get_state()) if "Escape" in shortcut: @@ -1660,38 +1174,33 @@ else: return True - def recent_action_click(self, action): + def recent_action_click(self, action, parameter, filename): self.stop_now = True while Gtk.events_pending(): Gtk.main_iteration() cancel = self.autosave_image() if cancel: return - index = int(action.get_name()) if ( - os.path.isfile(self.recentfiles[index]) - or os.path.exists(self.recentfiles[index]) - or self.recentfiles[index].startswith("http://") - or self.recentfiles[index].startswith("ftp://") + os.path.isfile(filename) + or os.path.exists(filename) + or filename.startswith("http://") + or filename.startswith("ftp://") ): - self.expand_filelist_and_load_image([self.recentfiles[index]]) + self.expand_filelist_and_load_image([filename]) else: self.image_list = [] self.curr_img_in_list = 0 - self.image_list.append(self.recentfiles[index]) + self.image_list.append(filename) self.image_load_failed(False) - self.recent_file_remove_and_refresh(index) - - def recent_file_remove_and_refresh_name(self, rmfile): + self.recent_file_remove_and_refresh(filename) + + def recent_file_remove_and_refresh(self, rmfile): try: self.recentfiles.remove(rmfile) except ValueError: pass - self.refresh_recent_files_menu() - - def recent_file_remove_and_refresh(self, index_num): - self.recentfiles.pop(index_num) self.refresh_recent_files_menu() def recent_file_add_and_refresh(self, addfile): @@ -1703,18 +1212,17 @@ self.recentfiles.insert(0, addfile) self.refresh_recent_files_menu() - def custom_action_click(self, action): - if self.UIManager.get_widget( - "/MainMenu/EditMenu/ActionSubMenu/" + action.get_name() - ).get_property("sensitive"): - for i in range(len(self.action_shortcuts)): + def custom_action_click(self, action, parameter, action_hash): + for i, hash in enumerate(self.action_hashes): + if hash == action_hash: try: - if action.get_name() == self.action_names[i]: - self.parse_action_command( - self.action_commands[i], self.action_batch[i] - ) + self.parse_action_command( + self.action_commands[i], self.action_batch[i] + ) except: pass + + break def parse_action_command2(self, cmd, imagename): # Executes the given command using ``os.system``, substituting "%"-macros approprately. @@ -1726,10 +1234,10 @@ cmd = cmd.strip() # [NEXT] and [PREV] are only valid alone or at the end of the command if cmd == "[NEXT]": - self.goto_next_image(None) + self.goto_next_image(None, None, None) return elif cmd == "[PREV]": - self.goto_prev_image(None) + self.goto_prev_image(None, None, None) return # -1=go to previous, 1=go to next, 0=don't change prev_or_next = 0 @@ -1776,153 +1284,99 @@ error_dialog.run() error_dialog.destroy() elif prev_or_next == 1: - self.goto_next_image(None) + self.goto_next_image(None, None, None) elif prev_or_next == -1: - self.goto_prev_image(None) + self.goto_prev_image(None, None, None) self.running_custom_actions = False def set_go_sensitivities(self, enable): - self.UIManager.get_widget("/MainMenu/GoMenu/Previous Image").set_sensitive( - enable - ) - self.UIManager.get_widget("/MainMenu/GoMenu/Next Image").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/GoMenu/Random Image").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/GoMenu/First Image").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/GoMenu/Last Image").set_sensitive(enable) - self.UIManager.get_widget("/Popup/Previous Image").set_sensitive(enable) - self.UIManager.get_widget("/Popup/Next Image").set_sensitive(enable) - self.UIManager.get_widget("/MainToolbar/Previous2").set_sensitive(enable) - self.UIManager.get_widget("/MainToolbar/Next2").set_sensitive(enable) - self.ss_forward.set_sensitive(enable) - self.ss_back.set_sensitive(enable) + self.action_group.lookup_action("goto-next-image").set_enabled(enable) + self.action_group.lookup_action("goto-prev-image").set_enabled(enable) + self.action_group.lookup_action("goto-random-image").set_enabled(enable) + self.action_group.lookup_action("goto-first-image").set_enabled(enable) + self.action_group.lookup_action("goto-last-image").set_enabled(enable) def set_image_sensitivities(self, enable): self.set_zoom_in_sensitivities(enable) self.set_zoom_out_sensitivities(enable) - self.UIManager.get_widget("/MainMenu/ViewMenu/1:1").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/ViewMenu/Fit").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/EditMenu/Delete Image").set_sensitive( - enable - ) - self.UIManager.get_widget("/MainMenu/EditMenu/Rename Image").set_sensitive( - enable - ) - self.UIManager.get_widget("/MainMenu/EditMenu/Crop").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/EditMenu/Resize").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/EditMenu/Saturation").set_sensitive(enable) - self.UIManager.get_widget("/MainToolbar/1:1").set_sensitive(enable) - self.UIManager.get_widget("/MainToolbar/Fit").set_sensitive(enable) - self.UIManager.get_widget("/Popup/1:1").set_sensitive(enable) - self.UIManager.get_widget("/Popup/Fit").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/FileMenu/Save As").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/FileMenu/Save").set_sensitive(False) - self.UIManager.get_widget("/MainMenu/FileMenu/Properties").set_sensitive(False) + self.action_group.lookup_action("save-image").set_enabled(enable) + self.action_group.lookup_action("save-image-as").set_enabled(enable) + self.action_group.lookup_action("show-properties").set_enabled(enable) + + self.action_group.lookup_action("crop-image").set_enabled(enable) + self.action_group.lookup_action("resize-image").set_enabled(enable) + self.action_group.lookup_action("saturation").set_enabled(enable) + self.action_group.lookup_action("rename-image").set_enabled(enable) + self.action_group.lookup_action("delete-image").set_enabled(enable) + + self.action_group.lookup_action("zoom-1-to-1").set_enabled(enable) + self.action_group.lookup_action("zoom-to-fit-window").set_enabled(enable) + # Only jpeg, png, and bmp images are currently supported for saving if len(self.image_list) > 0: + self.action_group.lookup_action("save-image").set_enabled(False) try: filetype = GdkPixbuf.Pixbuf.get_file_info(self.currimg_name)[0]["name"] - self.UIManager.get_widget( - "/MainMenu/FileMenu/Properties" - ).set_sensitive(True) if self.filetype_is_writable(filetype): - self.UIManager.get_widget("/MainMenu/FileMenu/Save").set_sensitive( - enable - ) + self.action_group.lookup_action("save-image").set_enabled(enable) except: - self.UIManager.get_widget("/MainMenu/FileMenu/Save").set_sensitive( - False - ) - if self.actionGroupCustom: - for action in self.action_names: - self.UIManager.get_widget( - "/MainMenu/EditMenu/ActionSubMenu/" + action - ).set_sensitive(enable) + pass + + for action in self.action_group.list_actions(): + if action.startswith("custom-"): + self.action_group.lookup_action(action).set_enabled(enable) + if not HAS_IMGFUNCS: enable = False - self.UIManager.get_widget("/MainMenu/EditMenu/Rotate Left").set_sensitive( - enable - ) - self.UIManager.get_widget("/MainMenu/EditMenu/Rotate Right").set_sensitive( - enable - ) - self.UIManager.get_widget("/MainMenu/EditMenu/Flip Vertically").set_sensitive( - enable - ) - self.UIManager.get_widget("/MainMenu/EditMenu/Flip Horizontally").set_sensitive( - enable - ) + + self.action_group.lookup_action("rotate-left").set_enabled(enable) + self.action_group.lookup_action("rotate-right").set_enabled(enable) + self.action_group.lookup_action("flip-image-vert").set_enabled(enable) + self.action_group.lookup_action("flip-image-horiz").set_enabled(enable) def set_zoom_in_sensitivities(self, enable): - self.UIManager.get_widget("/MainMenu/ViewMenu/In").set_sensitive(enable) - self.UIManager.get_widget("/MainToolbar/In").set_sensitive(enable) - self.UIManager.get_widget("/Popup/In").set_sensitive(enable) + self.action_group.lookup_action("zoom-in").set_enabled(enable) def set_zoom_out_sensitivities(self, enable): - self.UIManager.get_widget("/MainMenu/ViewMenu/Out").set_sensitive(enable) - self.UIManager.get_widget("/MainToolbar/Out").set_sensitive(enable) - self.UIManager.get_widget("/Popup/Out").set_sensitive(enable) + self.action_group.lookup_action("zoom-out").set_enabled(enable) def set_next_image_sensitivities(self, enable): - self.UIManager.get_widget("/MainToolbar/Next2").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/GoMenu/Next Image").set_sensitive(enable) - self.UIManager.get_widget("/Popup/Next Image").set_sensitive(enable) - self.ss_forward.set_sensitive(enable) + self.action_group.lookup_action("goto-next-image").set_enabled(enable) def set_previous_image_sensitivities(self, enable): - self.UIManager.get_widget("/MainToolbar/Previous2").set_sensitive(enable) - self.UIManager.get_widget("/MainMenu/GoMenu/Previous Image").set_sensitive( - enable - ) - self.UIManager.get_widget("/Popup/Previous Image").set_sensitive(enable) - self.ss_back.set_sensitive(enable) + self.action_group.lookup_action("goto-prev-image").set_enabled(enable) def set_first_image_sensitivities(self, enable): - self.UIManager.get_widget("/MainMenu/GoMenu/First Image").set_sensitive(enable) + self.action_group.lookup_action("goto-first-image").set_enabled(enable) def set_last_image_sensitivities(self, enable): - self.UIManager.get_widget("/MainMenu/GoMenu/Last Image").set_sensitive(enable) + self.action_group.lookup_action("goto-last-image").set_enabled(enable) def set_random_image_sensitivities(self, enable): - self.UIManager.get_widget("/MainMenu/GoMenu/Random Image").set_sensitive(enable) + self.action_group.lookup_action("goto-random-image").set_enabled(enable) + + def set_start_slideshow_visible(self, visible): + self.add_remove_action("start-slideshow", self.toggle_slideshow, visible) + + def set_stop_slideshow_visible(self, visible): + self.add_remove_action("stop-slideshow", self.toggle_slideshow, visible) def set_slideshow_sensitivities(self): if len(self.image_list) <= 1: - self.UIManager.get_widget("/MainMenu/GoMenu/Start Slideshow").show() - self.UIManager.get_widget("/MainMenu/GoMenu/Start Slideshow").set_sensitive( - False - ) - self.UIManager.get_widget("/MainMenu/GoMenu/Stop Slideshow").hide() - self.UIManager.get_widget("/MainMenu/GoMenu/Stop Slideshow").set_sensitive( - False - ) + self.set_start_slideshow_visible(True) + self.action_group.lookup_action("start-slideshow").set_enabled(False) + + self.set_stop_slideshow_visible(False) elif self.slideshow_mode: - self.UIManager.get_widget("/MainMenu/GoMenu/Start Slideshow").hide() - self.UIManager.get_widget("/MainMenu/GoMenu/Start Slideshow").set_sensitive( - False - ) - self.UIManager.get_widget("/MainMenu/GoMenu/Stop Slideshow").show() - self.UIManager.get_widget("/MainMenu/GoMenu/Stop Slideshow").set_sensitive( - True - ) + self.set_start_slideshow_visible(False) + + self.set_stop_slideshow_visible(True) + self.action_group.lookup_action("stop-slideshow").set_enabled(True) else: - self.UIManager.get_widget("/MainMenu/GoMenu/Start Slideshow").show() - self.UIManager.get_widget("/MainMenu/GoMenu/Start Slideshow").set_sensitive( - True - ) - self.UIManager.get_widget("/MainMenu/GoMenu/Stop Slideshow").hide() - self.UIManager.get_widget("/MainMenu/GoMenu/Stop Slideshow").set_sensitive( - False - ) - if self.slideshow_mode: - self.UIManager.get_widget("/Popup/Start Slideshow").hide() - self.UIManager.get_widget("/Popup/Stop Slideshow").show() - else: - self.UIManager.get_widget("/Popup/Start Slideshow").show() - self.UIManager.get_widget("/Popup/Stop Slideshow").hide() - if len(self.image_list) <= 1: - self.UIManager.get_widget("/Popup/Start Slideshow").set_sensitive(False) - else: - self.UIManager.get_widget("/Popup/Start Slideshow").set_sensitive(True) + self.set_start_slideshow_visible(True) + self.action_group.lookup_action("start-slideshow").set_enabled(True) + + self.set_stop_slideshow_visible(False) def set_zoom_sensitivities(self): if not self.currimg_is_animation: @@ -1953,22 +1407,33 @@ print(" " + _("uses same syntax as custom actions,\n")) print(" " + _("i.e. mirage -o 'echo file is %F'")) - def delay_changed(self, action): - self.curr_slideshow_delay = self.ss_delayspin.get_value() + def slideshow_delay_changed(self, action): + self.curr_slideshow_delay = ( + self.fullscreen_controls.slideshow_delay_adjustment.get_value() + ) if self.slideshow_mode: GObject.source_remove(self.timer_delay) if self.curr_slideshow_random: self.timer_delay = GObject.timeout_add( - int(self.curr_slideshow_delay * 1000), self.goto_random_image, "ss" + int(self.curr_slideshow_delay * 1000), + self.goto_random_image, + None, + None, + "ss", ) else: self.timer_delay = GObject.timeout_add( - (self.curr_slideshow_delay * 1000), self.goto_next_image, "ss" + (self.curr_slideshow_delay * 1000), + self.goto_next_image, + None, + None, + "ss", ) self.window.set_focus(self.layout) - def random_changed(self, action): - self.curr_slideshow_random = self.ss_randomize.get_active() + def toggle_slideshow_shuffle(self, action, value, data): + action.set_state(value) + self.curr_slideshow_random = value.get_boolean() def motion_cb(self, widget, context, x, y, time): context.drag_status(Gdk.DragAction.COPY, time) @@ -1993,7 +1458,6 @@ self.set_image_sensitivities(False) self.update_statusbar() self.loaded_img_in_list = -1 - return def expose_event(self, widget, event): if self.updating_adjustments: @@ -2127,7 +1591,7 @@ self.closing_app = True self.save_settings() - def exit_app(self, action): + def exit_app(self, action, parameter, data): cancel = self.autosave_image() if cancel: return True @@ -2212,23 +1676,21 @@ def available_image_height(self): height = self.window.get_size()[1] if not self.fullscreen_mode: - height -= self.menubar.size_request()[1] + height -= self.menubar.size_request()[1] # TODO if self.toolbar_show: height -= self.toolbar.size_request()[1] if self.statusbar_show: height -= self.statusbar.size_request()[1] return height - def save_image(self, action): - if self.UIManager.get_widget("/MainMenu/FileMenu/Save").get_property( - "sensitive" - ): + def save_image(self, action, parameter, data): + if self.action_group.lookup_action("save-image").get_enabled(): self.save_image_now( self.currimg_name, GdkPixbuf.Pixbuf.get_file_info(self.currimg_name)[0]["name"], ) - def save_image_as(self, action): + def save_image_as(self, action, parameter, data): dialog = Gtk.FileChooserDialog( title=_("Save As"), action=Gtk.FileChooserAction.SAVE, @@ -2299,7 +1761,7 @@ error_dialog.destroy() while Gtk.events_pending(): Gtk.main_iteration() - self.save_image_as(None) + self.save_image_as(None, None, None) else: error_dialog.destroy() except: @@ -2321,16 +1783,11 @@ # the app to freeze. if self.image_modified: if self.savemode == 1: - temp = self.UIManager.get_widget( - "/MainMenu/FileMenu/Save" - ).get_property("sensitive") - self.UIManager.get_widget("/MainMenu/FileMenu/Save").set_property( - "sensitive", True - ) - self.save_image(None) - self.UIManager.get_widget("/MainMenu/FileMenu/Save").set_property( - "sensitive", temp - ) + action = self.action_group.lookup_action("save-image") + temp = action.get_enabled() + action.set_enabled(True) + self.save_image(None, None, None) + action.set_enabled(temp) elif self.savemode == 2: dialog = Gtk.MessageDialog( self.window, @@ -2347,16 +1804,11 @@ response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.YES: - temp = self.UIManager.get_widget( - "/MainMenu/FileMenu/Save" - ).get_property("sensitive") - self.UIManager.get_widget("/MainMenu/FileMenu/Save").set_property( - "sensitive", True - ) - self.save_image(None) - self.UIManager.get_widget("/MainMenu/FileMenu/Save").set_property( - "sensitive", temp - ) + action = self.action_group.lookup_action("save-image") + temp = action.get_enabled() + action.set_enabled(True) + self.save_image(None, None, None) + action.set_enabled(temp) self.image_modified = False elif response == Gtk.ResponseType.NO: self.image_modified = False @@ -2378,13 +1830,13 @@ return True return False - def open_file(self, action): + def open_file(self, action, parameter, data): self.stop_now = True while Gtk.events_pending(): Gtk.main_iteration() - self.open_file_or_folder(action, True) - - def open_file_remote(self, action): + self.open_file_or_folder(True) + + def open_file_remote(self, action, parameter, data): # Prompt user for the url: dialog = Gtk.Dialog( _("Open Remote"), @@ -2420,13 +1872,13 @@ else: dialog.destroy() - def open_folder(self, action): + def open_folder(self, action, parameter, data): self.stop_now = True while Gtk.events_pending(): Gtk.main_iteration() - self.open_file_or_folder(action, False) - - def open_file_or_folder(self, action, isfile): + self.open_file_or_folder(False) + + def open_file_or_folder(self, isfile): self.thumbpane_create_dir() cancel = self.autosave_image() if cancel: @@ -2512,26 +1964,28 @@ and not self.user_prompt_visible and not self.slideshow_controls_visible ): - pix_data = """/* XPM */ - static char * invisible_xpm[] = { - "1 1 1 1", - " c None", - " "};""" - color = Gdk.Color() - pix = Gdk.pixmap_create_from_data(None, pix_data, 1, 1, 1, color, color) - invisible = Gdk.Cursor.new(pix, pix, color, color, 0, 0) + invisible = Gdk.Cursor.new_for_display( + self.window.get_window().get_display(), Gdk.CursorType.BLANK_CURSOR + ) self.change_cursor(invisible) + return False - def enter_fullscreen(self, action): + def set_enter_fullscreen_visible(self, visible): + self.add_remove_action("enter-fullscreen", self.enter_fullscreen, visible) + + def set_leave_fullscreen_visible(self, visible): + self.add_remove_action("leave-fullscreen", self.leave_fullscreen, visible) + + def enter_fullscreen(self, action, parameter, data): if not self.fullscreen_mode: self.fullscreen_mode = True - self.UIManager.get_widget("/Popup/Full Screen").hide() - self.UIManager.get_widget("/Popup/Exit Full Screen").show() + self.set_enter_fullscreen_visible(False) + self.set_leave_fullscreen_visible(True) self.statusbar.hide() self.statusbar2.hide() self.toolbar.hide() - self.menubar.hide() + self.window.set_show_menubar(False) self.thumbscroll.hide() self.thumbpane.hide() self.window.fullscreen() @@ -2544,17 +1998,16 @@ self.layout.modify_bg(Gtk.StateType.NORMAL, None) self.leave_fullscreen(action) - def leave_fullscreen(self, action): + def leave_fullscreen(self, action, parameter, data): if self.fullscreen_mode: self.slideshow_controls_visible = False - self.slideshow_window.hide_all() - self.slideshow_window2.hide_all() + self.fullscreen_controls.hide() self.fullscreen_mode = False - self.UIManager.get_widget("/Popup/Full Screen").show() - self.UIManager.get_widget("/Popup/Exit Full Screen").hide() + self.set_enter_fullscreen_visible(True) + self.set_leave_fullscreen_visible(False) if self.toolbar_show: self.toolbar.show() - self.menubar.show() + self.window.set_show_menubar(True) if self.statusbar_show: self.statusbar.show() self.statusbar2.show() @@ -2568,8 +2021,9 @@ if self.simple_bgcolor: self.layout.modify_bg(Gtk.StateType.NORMAL, None) - def toggle_status_bar(self, action): - if self.statusbar.get_property("visible"): + def toggle_status_bar(self, action, value, data): + action.set_state(value) + if not value.get_boolean(): self.statusbar.hide() self.statusbar2.hide() self.statusbar_show = False @@ -2583,8 +2037,9 @@ else: self.zoom_to_fit_window(None, False, False) - def toggle_thumbpane(self, action): - if self.thumbscroll.get_property("visible"): + def toggle_thumbpane(self, action, value, data): + action.set_state(value) + if not value.get_boolean(): self.thumbscroll.hide() self.thumbpane.hide() self.thumbpane_show = False @@ -2600,8 +2055,9 @@ else: self.zoom_to_fit_window(None, False, False) - def toggle_toolbar(self, action): - if self.toolbar.get_property("visible"): + def toggle_toolbar(self, action, value, data): + action.set_state(value) + if not value.get_boolean(): self.toolbar.hide() self.toolbar_show = False else: @@ -2644,7 +2100,7 @@ status_text = _("Scanning...") self.statusbar2.push(self.statusbar2.get_context_id(""), status_text) - def show_custom_actions(self, action): + def show_custom_actions(self, action, parameter, data): self.actions_dialog = Gtk.Dialog( title=_("Configure Custom Actions"), parent=self.window ) @@ -3021,6 +2477,9 @@ dialog.destroy() if add_call: self.action_names.append(name) + self.action_hashes.append( + hashlib.sha1(name.encode("utf8")).hexdigest() + ) self.action_commands.append(command) self.action_shortcuts.append(shortcut) self.action_batch.append(batch) @@ -3028,6 +2487,9 @@ (model, iter) = self.actionwidget.get_selection().get_selected() (rownum,) = self.actionstore.get_path(iter) self.action_names[rownum] = name + self.action_hashes[rownum] = hashlib.sha1( + name.encode("utf8") + ).hexdigest() self.action_commands[rownum] = command self.action_shortcuts[rownum] = shortcut self.action_batch[rownum] = batch @@ -3070,14 +2532,17 @@ if rownum < len(self.action_names) - 1: # Move item down: temp_name = self.action_names[rownum] + temp_hash = self.action_hashes[rownum] temp_shortcut = self.action_shortcuts[rownum] temp_command = self.action_commands[rownum] temp_batch = self.action_batch[rownum] self.action_names[rownum] = self.action_names[rownum + 1] + self.action_hashes[rownum] = self.action_hashes[rownum + 1] self.action_shortcuts[rownum] = self.action_shortcuts[rownum + 1] self.action_commands[rownum] = self.action_commands[rownum + 1] self.action_batch[rownum] = self.action_batch[rownum + 1] self.action_names[rownum + 1] = temp_name + self.action_hashes[rownum + 1] = temp_hash self.action_shortcuts[rownum + 1] = temp_shortcut self.action_commands[rownum + 1] = temp_command self.action_batch[rownum + 1] = temp_batch @@ -3107,14 +2572,17 @@ if rownum > 0: # Move item down: temp_name = self.action_names[rownum] + temp_hash = self.action_hashes[rownum] temp_shortcut = self.action_shortcuts[rownum] temp_command = self.action_commands[rownum] temp_batch = self.action_batch[rownum] self.action_names[rownum] = self.action_names[rownum - 1] + self.action_hashes[rownum] = self.action_hashes[rownum - 1] self.action_shortcuts[rownum] = self.action_shortcuts[rownum - 1] self.action_commands[rownum] = self.action_commands[rownum - 1] self.action_batch[rownum] = self.action_batch[rownum - 1] self.action_names[rownum - 1] = temp_name + self.action_hashes[rownum - 1] = temp_hash self.action_shortcuts[rownum - 1] = temp_shortcut self.action_commands[rownum - 1] = temp_command self.action_batch[rownum - 1] = temp_batch @@ -3198,6 +2666,7 @@ if iter != None: (row,) = self.actionstore.get_path(iter) self.action_names.pop(row) + self.action_hashes.pop(row) self.action_shortcuts.pop(row) self.action_commands.pop(row) self.action_batch.pop(row) @@ -3233,7 +2702,7 @@ self.tvcolumn2.set_attributes(self.cell, text=2) self.tvcolumn1.set_expand(True) - def screenshot(self, action): + def screenshot(self, action, parameter, data): cancel = self.autosave_image() if cancel: return @@ -3425,7 +2894,7 @@ del pix self.window.present() - def show_properties(self, action): + def show_properties(self, action, parameter, data): show_props = Gtk.Dialog(_("Properties"), self.window) show_props.set_has_separator(False) show_props.set_resizable(False) @@ -3546,7 +3015,7 @@ show_props.run() show_props.destroy() - def show_prefs(self, action): + def show_prefs(self, action, parameter, data): prev_thumbnail_size = self.thumbnail_size self.prefs_dialog = Gtk.Dialog(_("Mirage Preferences"), self.window) self.prefs_dialog.set_has_separator(False) @@ -4521,6 +3990,7 @@ self.preloading_images = preloadnav.get_active() self.listwrap_mode = combobox2.get_active() self.slideshow_delay = delayspin.get_value() + self.fullscreen_controls.set_slideshow_delay(self.slideshow_delay) self.curr_slideshow_delay = self.slideshow_delay self.slideshow_random = randomize.get_active() self.curr_slideshow_random = self.slideshow_random @@ -4560,11 +4030,11 @@ else: self.defaultdir.set_sensitive(False) - def rename_image(self, action): + def rename_image(self, action, parameter, data): if len(self.image_list) > 0: temp_slideshow_mode = self.slideshow_mode if self.slideshow_mode: - self.toggle_slideshow(None) + self.toggle_slideshow(None, None, None) rename_dialog = Gtk.Dialog( _("Rename Image"), self.window, Gtk.DialogFlags.MODAL ) @@ -4626,7 +4096,7 @@ ) except: pass - self.recent_file_remove_and_refresh_name(self.currimg_name) + self.recent_file_remove_and_refresh(self.currimg_name) self.currimg_name = new_filename self.register_file_with_recent_docs(self.currimg_name) self.update_title() @@ -4643,18 +4113,18 @@ error_dialog.destroy() rename_dialog.destroy() if temp_slideshow_mode: - self.toggle_slideshow(None) + self.toggle_slideshow(None, None, None) def select_rename_text(self, widget): filename = os.path.basename(self.currimg_name) fileext = os.path.splitext(os.path.basename(self.currimg_name))[1] self.rename_txt.select_region(0, len(filename) - len(fileext)) - def delete_image(self, action): + def delete_image(self, action, parameter, data): if len(self.image_list) > 0: temp_slideshow_mode = self.slideshow_mode if self.slideshow_mode: - self.toggle_slideshow(None) + self.toggle_slideshow(None, None, None) delete_dialog = Gtk.Dialog( _("Delete Image"), self.window, Gtk.DialogFlags.MODAL ) @@ -4697,7 +4167,7 @@ os.remove(self.thumbnail_get_name(self.currimg_name)[1]) except: pass - self.recent_file_remove_and_refresh_name(self.currimg_name) + self.recent_file_remove_and_refresh(self.currimg_name) iter = self.thumblist.get_iter((self.curr_img_in_list,)) try: self.thumbnail_loaded.pop(self.curr_img_in_list) @@ -4745,7 +4215,7 @@ error_dialog.destroy() delete_dialog.destroy() if temp_slideshow_mode: - self.toggle_slideshow(None) + self.toggle_slideshow(None, None, None) def defaultdir_clicked(self, button): getdir = Gtk.FileChooserDialog( @@ -4784,8 +4254,7 @@ self.bgcolor = widget.get_property("color") if not self.simple_bgcolor: self.layout.modify_bg(Gtk.StateType.NORMAL, self.bgcolor) - self.slideshow_window.modify_bg(Gtk.StateType.NORMAL, self.bgcolor) - self.slideshow_window2.modify_bg(Gtk.StateType.NORMAL, self.bgcolor) + self.fullscreen_controls.modify_bg(Gtk.StateType.NORMAL, self.bgcolor) def simple_bgcolor_selected(self, widget): if widget.get_active(): @@ -4795,7 +4264,7 @@ self.simple_bgcolor = False self.bgcolor_selected(self.colorbutton) - def show_about(self, action): + def show_about(self, action, parameter, data): # Help > About self.about_dialog = Gtk.AboutDialog() try: @@ -4832,7 +4301,7 @@ def show_website(self, dialog, blah, link): self.browser_load(link) - def show_help(self, action): + def show_help(self, action, parameter, data): self.browser_load("http://mirageiv.berlios.de/docs.html") def browser_load(self, docslink): @@ -4873,16 +4342,16 @@ # Zooming of the image by Ctrl-mousewheel if event.get_state() & Gdk.ModifierType.CONTROL_MASK: if event.direction == Gdk.ScrollDirection.UP: - self.zoom_in(None) + self.zoom_in(None, None, None) elif event.direction == Gdk.ScrollDirection.DOWN: - self.zoom_out(None) + self.zoom_out(None, None, None) return True # Navigation of images with mousewheel: else: if event.direction == Gdk.ScrollDirection.UP: - self.goto_prev_image(None) + self.goto_prev_image(None, None, None) elif event.direction == Gdk.ScrollDirection.DOWN: - self.goto_next_image(None) + self.goto_next_image(None, None, None) return True def mouse_moved(self, widget, event): @@ -4938,9 +4407,8 @@ self.prevmousey = event.y_root # Right-click popup: elif self.image_loaded and event.button == 3: - self.UIManager.get_widget("/Popup").popup( - None, None, None, event.button, event.time - ) + self.popup_menu.popup_at_pointer(event) + return True def button_released(self, widget, event): @@ -4949,10 +4417,11 @@ self.change_cursor(None) return True - def zoom_in(self, action): - if self.currimg_name != "" and self.UIManager.get_widget( - "/MainMenu/ViewMenu/In" - ).get_property("sensitive"): + def zoom_in(self, action, parameter, data): + if ( + self.currimg_name != "" + and self.action_group.lookup_action("zoom-in").get_enabled() + ): self.image_zoomed = True self.currimg_zoomratio = self.currimg_zoomratio * 1.25 self.set_zoom_sensitivities() @@ -4960,10 +4429,11 @@ self.put_zoom_image_to_window(False) self.update_statusbar() - def zoom_out(self, action): - if self.currimg_name != "" and self.UIManager.get_widget( - "/MainMenu/ViewMenu/Out" - ).get_property("sensitive"): + def zoom_out(self, action, parameter, data): + if ( + self.currimg_name != "" + and self.action_group.lookup_action("zoom-out").get_enabled() + ): if self.currimg_zoomratio == self.min_zoomratio: # No point in proceeding.. return @@ -4976,7 +4446,7 @@ self.put_zoom_image_to_window(False) self.update_statusbar() - def zoom_to_fit_window_action(self, action): + def zoom_to_fit_window_action(self, action, parameter, data): self.zoom_to_fit_window(action, False, False) def zoom_to_fit_window(self, action, is_preloadimg_next, is_preloadimg_prev): @@ -5009,9 +4479,7 @@ else: if self.currimg_name != "" and ( self.slideshow_mode - or self.UIManager.get_widget("/MainMenu/ViewMenu/Fit").get_property( - "sensitive" - ) + or self.action_group.lookup_action("zoom-to-fit-window").get_enabled() ): self.image_zoomed = True self.last_mode = self.open_mode_fit @@ -5089,7 +4557,7 @@ self.last_image_action_was_fit = True self.last_image_action_was_smart_fit = True - def zoom_1_to_1_action(self, action): + def zoom_1_to_1_action(self, action, parameter, data): self.zoom_1_to_1(action, False, False) def zoom_1_to_1(self, action, is_preloadimg_next, is_preloadimg_prev): @@ -5105,9 +4573,7 @@ or self.currimg_is_animation or ( not self.currimg_is_animation - and self.UIManager.get_widget( - "/MainMenu/ViewMenu/1:1" - ).get_property("sensitive") + and self.action_group.lookup_action("zoom-1-to-1").get_enabled() ) ): self.image_zoomed = True @@ -5117,18 +4583,16 @@ self.put_zoom_image_to_window(False) self.update_statusbar() - def rotate_left(self, action): - self.rotate_left_or_right( - self.UIManager.get_widget("/MainMenu/EditMenu/Rotate Left"), 90 - ) - - def rotate_right(self, action): - self.rotate_left_or_right( - self.UIManager.get_widget("/MainMenu/EditMenu/Rotate Right"), 270 - ) - - def rotate_left_or_right(self, widget, angle): - if self.currimg_name != "" and widget.get_property("sensitive"): + def rotate_left(self, action, parameter, data): + if self.action_group.lookup_action("rotate-left").get_enabled(): + self.rotate_left_or_right(90) + + def rotate_right(self, action, parameter, data): + if self.action_group.lookup_action("rotate-right").get_enabled(): + self.rotate_left_or_right(270) + + def rotate_left_or_right(self, angle): + if self.currimg_name != "": self.currimg_pixbuf_original = self.image_rotate( self.currimg_pixbuf_original, angle ) @@ -5150,18 +4614,16 @@ self.update_statusbar() self.image_modified = True - def flip_image_vert(self, action): - self.flip_image_vert_or_horiz( - self.UIManager.get_widget("/MainMenu/EditMenu/Flip Vertically"), True - ) - - def flip_image_horiz(self, action): - self.flip_image_vert_or_horiz( - self.UIManager.get_widget("/MainMenu/EditMenu/Flip Horizontally"), False - ) - - def flip_image_vert_or_horiz(self, widget, vertical): - if self.currimg_name != "" and widget.get_property("sensitive"): + def flip_image_vert(self, action, parameter, data): + if self.action_group.lookup_action("flip-image-vert").get_enabled(): + self.flip_image_vert_or_horiz(True) + + def flip_image_horiz(self, action, parameter, data): + if self.action_group.lookup_action("flip-image-horiz").get_enabled(): + self.flip_image_vert_or_horiz(False) + + def flip_image_vert_or_horiz(self, vertical): + if self.currimg_name != "": self.currimg_pixbuf = self.image_flip(self.currimg_pixbuf, vertical) self.currimg_pixbuf_original = self.image_flip( self.currimg_pixbuf_original, vertical @@ -5215,7 +4677,7 @@ except: return pix - def crop_image(self, action): + def crop_image(self, action, parameter, data): dialog = Gtk.Dialog( _("Crop Image"), self.window, @@ -5670,7 +5132,7 @@ if not (state & Gdk.ModifierType.BUTTON1_MASK): self.drawing_crop_rectangle = False - def saturation(self, action): + def saturation(self, action, parameter, data): dialog = Gtk.Dialog( _("Saturation"), self.window, @@ -5730,7 +5192,7 @@ pass gc.collect() - def resize_image(self, action): + def resize_image(self, action, parameter, data): dialog = Gtk.Dialog( _("Resize Image"), self.window, @@ -5846,20 +5308,20 @@ otherspinbox.set_value(target_value) self.ignore_preserve_aspect_callback = False - def goto_prev_image(self, action): - self.goto_image("PREV", action) - - def goto_next_image(self, action): - self.goto_image("NEXT", action) - - def goto_random_image(self, action): - self.goto_image("RANDOM", action) - - def goto_first_image(self, action): - self.goto_image("FIRST", action) - - def goto_last_image(self, action): - self.goto_image("LAST", action) + def goto_prev_image(self, action, parameter, data): + self.goto_image("PREV", data) + + def goto_next_image(self, action, parameter, data): + self.goto_image("NEXT", data) + + def goto_random_image(self, action, parameter, data): + self.goto_image("RANDOM", data) + + def goto_first_image(self, action, parameter, data): + self.goto_image("FIRST", data) + + def goto_last_image(self, action, parameter, data): + self.goto_image("LAST", data) def goto_image(self, location, action): # location can be "LAST", "FIRST", "NEXT", "PREV", "RANDOM", or a number @@ -5924,7 +5386,7 @@ if self.listwrap_mode == 0: if location == "NEXT": if self.slideshow_mode: - self.toggle_slideshow(None) + self.toggle_slideshow(None, None, None) return elif ( location == "PREV" or location == "NEXT" @@ -5999,7 +5461,7 @@ else: self.change_cursor(None) if self.slideshow_mode: - self.toggle_slideshow(None) + self.toggle_slideshow(None, None, None) return if location == "RANDOM": # Find random image that hasn't already been chosen: @@ -6032,12 +5494,16 @@ self.timer_delay = GObject.timeout_add( int(self.curr_slideshow_delay * 1000), self.goto_random_image, + None, + None, "ss", ) else: self.timer_delay = GObject.timeout_add( int(self.curr_slideshow_delay * 1000), self.goto_next_image, + None, + None, "ss", ) GObject.idle_add(self.thumbpane_select, self.curr_img_in_list) @@ -6545,13 +6011,7 @@ self.preloadimg_prev_in_list = -1 def change_cursor(self, type): - for i in Gdk.window_get_toplevels(): - if ( - i.get_window_type() != Gdk.WINDOW_TEMP - and i.get_window_type() != Gdk.WINDOW_CHILD - ): - i.set_cursor(type) - self.layout.window.set_cursor(type) + self.window.get_window().set_cursor(type) def expand_filelist_and_load_image(self, inputlist): # Takes the current list (i.e. ["pic.jpg", "pic2.gif", "../images"]) and @@ -6716,7 +6176,7 @@ ): first_image_loaded = True if self.slideshow_mode: - self.toggle_slideshow(None) + self.toggle_slideshow(None, None, None) if self.verbose and self.currimg_name != "": print(_("Loading: %s") % self.currimg_name) try: @@ -6977,11 +6437,11 @@ return new_pix return old_pix - def toggle_slideshow(self, action): + def toggle_slideshow(self, action, parameter, data): if len(self.image_list) > 1: if not self.slideshow_mode: if self.slideshow_in_fullscreen and not self.fullscreen_mode: - self.enter_fullscreen(None) + self.enter_fullscreen(None, None, None) self.slideshow_mode = True self.update_title() self.set_slideshow_sensitivities() @@ -6989,6 +6449,8 @@ self.timer_delay = GObject.timeout_add( int(self.curr_slideshow_delay * 1000), self.goto_next_image, + None, + None, "ss", ) else: @@ -6996,10 +6458,11 @@ self.timer_delay = GObject.timeout_add( int(self.curr_slideshow_delay * 1000), self.goto_random_image, + None, + None, "ss", ) - self.ss_start.hide() - self.ss_stop.show() + self.fullscreen_controls.set_slideshow_playing(True) timer_screensaver = GObject.timeout_add( 1000, self.disable_screensaver_in_slideshow_mode ) @@ -7009,8 +6472,7 @@ self.update_title() self.set_slideshow_sensitivities() self.set_zoom_sensitivities() - self.ss_stop.hide() - self.ss_start.show() + self.fullscreen_controls.set_slideshow_playing(False) def update_title(self): if len(self.image_list) == 0: @@ -7028,69 +6490,37 @@ self.window.set_title(title) def slideshow_controls_show(self): - if not self.slideshow_controls_visible and not self.controls_moving: - self.slideshow_controls_visible = True - - self.ss_delayspin.set_value(self.curr_slideshow_delay) - self.ss_randomize.set_active(self.curr_slideshow_random) - - if self.slideshow_mode: - self.ss_start.set_no_show_all(True) - self.ss_stop.set_no_show_all(False) - else: - self.ss_start.set_no_show_all(False) - self.ss_stop.set_no_show_all(True) - - (xpos, ypos) = self.window.get_position() - screen = self.window.get_screen() - self.slideshow_window.set_screen(screen) - self.slideshow_window2.set_screen(screen) - - self.slideshow_window.show_all() - self.slideshow_window2.show_all() - if not self.closing_app: - while Gtk.events_pending(): - Gtk.main_iteration() - - ss_winheight = self.slideshow_window.get_allocation().height - ss_win2width = self.slideshow_window2.get_allocation().width - winheight = self.window.get_allocation().height - winwidth = self.window.get_allocation().width - y = -3.0 - self.controls_moving = True - while y < ss_winheight: - self.slideshow_window.move(2 + xpos, int(winheight - y - 2)) - self.slideshow_window2.move( - winwidth - ss_win2width - 2 + xpos, int(winheight - y - 2) - ) - y += 0.05 - if not self.closing_app: - while Gtk.events_pending(): - Gtk.main_iteration() - self.controls_moving = False + if self.slideshow_controls_visible: + return + + self.slideshow_controls_visible = True + + self.fullscreen_controls.set_slideshow_delay(self.curr_slideshow_delay) + + if self.slideshow_mode: + self.fullscreen_controls.set_slideshow_playing(True) + else: + self.fullscreen_controls.set_slideshow_playing(False) + + screen = self.window.get_screen() + self.fullscreen_controls.set_screen(screen) + self.fullscreen_controls.show_all() + + if not self.closing_app: + while Gtk.events_pending(): + Gtk.main_iteration() + + width = self.window.get_allocation().width + height = self.window.get_allocation().height + (x, y) = self.window.get_position() + self.fullscreen_controls.position(width, height, x, y) def slideshow_controls_hide(self): - if self.slideshow_controls_visible and not self.controls_moving: - self.slideshow_controls_visible = False - - (xpos, ypos) = self.window.get_position() - - ss_winheight = self.slideshow_window.get_allocation().height - ss_win2width = self.slideshow_window2.get_allocation().width - winheight = self.window.get_allocation().height - winwidth = self.window.get_allocation().width - y = float(self.slideshow_window.get_allocation().height * 1.0) - self.controls_moving = True - while y > -3: - self.slideshow_window.move(2 + xpos, int(winheight - y - 2)) - self.slideshow_window2.move( - winwidth - ss_win2width - 2 + xpos, int(winheight - y - 2) - ) - y -= 0.05 - if not self.closing_app: - while Gtk.events_pending(): - Gtk.main_iteration() - self.controls_moving = False + if not self.slideshow_controls_visible: + return + + self.slideshow_controls_visible = False + self.fullscreen_controls.hide() def disable_screensaver_in_slideshow_mode(self): if self.slideshow_mode and self.disable_screensaver: @@ -7105,12 +6535,9 @@ 1000, self.disable_screensaver_in_slideshow_mode ) - def main(self): - Gtk.main() - if __name__ == "__main__": base = Base() Gdk.threads_enter() - base.main() + base.run([]) Gdk.threads_leave() diff --git a/resources/fullscreen-controls.ui b/resources/fullscreen-controls.ui new file mode 100644 index 0000000..9a2a0cb --- /dev/null +++ b/resources/fullscreen-controls.ui @@ -0,0 +1,139 @@ + + + + + + media-playback-start + + + media-playback-stop + + + go-previous + + + go-next + + + media-playlist-shuffle + + + view-restore + + + + 0 + 0 + 50000 + 1 + 100 + 0 + + + + diff --git a/resources/gtk/menus.ui b/resources/gtk/menus.ui new file mode 100644 index 0000000..4d90ac0 --- /dev/null +++ b/resources/gtk/menus.ui @@ -0,0 +1,332 @@ + + + + + _File +
+ + document-open + _Open Image... + app.open-file + <Control>o + + + folder + Open _Folder... + app.open-folder + <Control>f + + + network-workgroup + Open _Remote Image... + app.open-file-remote + +
+
+ + document-save + _Save Image + app.save-image + <Control>s + + + document-save-as + Save Image _As... + app.save-image-as + <Shift><Control>s + +
+
+ + camera-photo + _Take Screenshot... + app.screenshot + +
+
+ + document-properties + _Properties... + app.show-properties + +
+
+
+ + application-exit + _Quit + app.exit-app + <Control>q + +
+
+ + _Edit +
+ + object-rotate-left + Rotate _Left + app.rotate-left + <Control>Left + + + object-rotate-right + Rotate _Right + app.rotate-right + <Control>Right + + + object-flip-vertical + Flip _Vertically + app.flip-image-vert + <Control>v + + + object-flip-horizontal + Flip _Horizontally + app.flip-image-horiz + <Control>h + +
+
+ + _Crop... + app.crop-image + + + R_esize... + app.resize-image + + + _Saturation... + app.saturation + +
+
+ + Re_name... + app.rename-image + F2 + + + edit-delete + _Delete... + app.delete-image + Delete + +
+
+ + Custom _Actions +
+
+
+ + _Configure... + app.show-custom-actions + +
+
+ + preferences-system + _Preferences... + app.show-prefs + <Control>p + +
+
+ + _View +
+ + zoom-out + Zoom _Out + app.zoom-out + <Control>Down + + + zoom-in + Zoom _In + app.zoom-in + <Control>Up + + + zoom-original + _1:1 + app.zoom-1-to-1 + <Control>1 + + + zoom-fit-best + Zoom to _Fit + app.zoom-to-fit-window + <Control>0 + +
+
+ + _Toolbar + app.toggle-toolbar + + + Thumbnails _Pane + app.toggle-thumbpane + + + _Status Bar + app.toggle-status-bar + +
+
+ + view-fullscreen + _Full Screen + app.enter-fullscreen + F11 + action-missing + + + view-restore + E_xit Full Screen + app.leave-fullscreen + F11 + action-missing + +
+
+ + _Go +
+ + go-next + _Next Image + app.goto-next-image + Right + + + go-previous + _Previous Image + app.goto-prev-image + Left + + + media-playlist-shuffle + _Random Image + app.goto-random-image + R + +
+
+ + go-first + _First Image + app.goto-first-image + Home + + + go-last + _Last Image + app.goto-last-image + End + +
+
+ + media-playback-start + _Start Slideshow + app.start-slideshow + F5 + action-missing + + + media-playback-stop + _Stop Slideshow + app.stop-slideshow + F5 + action-missing + +
+
+ + _Help +
+ + help-contents + _Contents + app.show-help + F1 + + + help-about + _About + app.show-about + +
+
+
+ + +
+ + go-next + Next Image + app.goto-next-image + + + go-previous + Previous Image + app.goto-prev-image + +
+
+ + zoom-out + Zoom Out + app.zoom-out + + + zoom-in + Zoom In + app.zoom-in + + + zoom-original + 1:1 + app.zoom-1-to-1 + + + zoom-fit-best + Zoom to Fit + app.zoom-to-fit-window + +
+
+ + media-playback-start + Start Slideshow + app.start-slideshow + action-missing + + + media-playback-start + Stop Slideshow + app.stop-slideshow + action-missing + +
+
+ + view-fullscreen + Full Screen + app.enter-fullscreen + action-missing + + + view-restore + Exit Full Screen + app.leave-fullscreen + action-missing + +
+
+
diff --git a/resources/mirage.gresource.xml b/resources/mirage.gresource.xml new file mode 100644 index 0000000..a5aebed --- /dev/null +++ b/resources/mirage.gresource.xml @@ -0,0 +1,9 @@ + + + + gtk/menus.ui + + toolbar.ui + fullscreen-controls.ui + + diff --git a/resources/toolbar.ui b/resources/toolbar.ui new file mode 100644 index 0000000..237d012 --- /dev/null +++ b/resources/toolbar.ui @@ -0,0 +1,56 @@ + + + + + + document-open + Open Image + app.open-file + + + + + + go-previous + Previous + app.goto-prev-image + + + + + go-next + Next + app.goto-next-image + + + + + + zoom-out + Zoom Out + app.zoom-out + + + + + zoom-in + Zoom In + app.zoom-in + + + + + zoom-original + 1:1 + app.zoom-1-to-1 + + + + + zoom-fit-best + Fit + app.zoom-to-fit-window + + + +