[pitivi] mainwindow: Replace the menubar and main toolbar by HeaderBar and MenuButton
- From: Thibault Saunier <tsaunier src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] mainwindow: Replace the menubar and main toolbar by HeaderBar and MenuButton
- Date: Wed, 2 Apr 2014 15:28:52 +0000 (UTC)
commit d48a39cbfa1f89b3f083791772eb853de87bcb3a
Author: Jean-François Fortin Tam <nekohayo gmail com>
Date: Fri Dec 27 15:34:13 2013 -0500
mainwindow: Replace the menubar and main toolbar by HeaderBar and MenuButton
Fixes bug #708375
Depends on GTK+ 3.10
This commit removes any dependency on GTK actions for the main window. It also
changes translatable strings and moves the "screenshot" feature to mainwindow.
data/ui/Makefile.am | 2 +-
data/ui/mainmenubutton.ui | 142 ++++++++++++++++++++
data/ui/mainwindow.xml | 51 -------
data/ui/timelinecontainer.xml | 37 ++----
pitivi/check.py | 2 +-
pitivi/mainwindow.py | 292 ++++++++++++++++++++++-------------------
pitivi/timeline/timeline.py | 48 -------
7 files changed, 310 insertions(+), 264 deletions(-)
---
diff --git a/data/ui/Makefile.am b/data/ui/Makefile.am
index c78335a..87e2be8 100644
--- a/data/ui/Makefile.am
+++ b/data/ui/Makefile.am
@@ -7,7 +7,7 @@ ui_DATA = \
effectslibrary.ui \
elementsettingsdialog.ui \
filelisterrordialog.ui \
- mainwindow.xml \
+ mainmenubutton.ui \
medialibrary.ui \
preferences.ui \
projectsettings.ui \
diff --git a/data/ui/mainmenubutton.ui b/data/ui/mainmenubutton.ui
new file mode 100644
index 0000000..f450bf3
--- /dev/null
+++ b/data/ui/mainmenubutton.ui
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.16.0 on Fri Dec 27 12:36:25 2013 -->
+<interface>
+ <!-- interface-requires gtk+ 3.10 -->
+ <object class="GtkMenu" id="menu">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">end</property>
+ <child>
+ <object class="GtkMenuItem" id="menu_new">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">New project</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_newProjectMenuCb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menu_open">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Open project...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_openProjectCb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menu_sep1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menu_save_as">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Save the current project under a new name or a
different location</property>
+ <property name="label" translatable="yes">Save As...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_saveProjectAsCb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menu_revert_to_saved">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Reload the current project</property>
+ <property name="label" translatable="yes">Revert to saved version</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_revertToSavedProjectCb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menu_export_tarball">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Export the current project and all its media in a
.tar archive</property>
+ <property name="label" translatable="yes">Export as Archive...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_exportProjectAsTarCb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menu_sep2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menu_save_frame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Export the frame at the current playhead position
as an image file.</property>
+ <property name="label" translatable="yes">Export current frame...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_screenshotCb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menu_sep3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menu_project_settings">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="tooltip_text" translatable="yes">Edit the project settings</property>
+ <property name="label" translatable="yes">Project Settings</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_projectSettingsCb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menu_preferences">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Preferences</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_prefsCb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="menu_sep4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menu_help">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">User Manual</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_userManualCb" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menu_about">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">About</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="_aboutCb" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ <object class="GtkMenuButton" id="menubutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="popup">menu</property>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">view-more-symbolic</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/data/ui/timelinecontainer.xml b/data/ui/timelinecontainer.xml
index ba9e343..550c81d 100644
--- a/data/ui/timelinecontainer.xml
+++ b/data/ui/timelinecontainer.xml
@@ -1,28 +1,4 @@
<ui>
- <menubar name="MainMenuBar">
- <menu action="View">
- <placeholder name="Timeline">
- <menuitem action="ZoomIn" />
- <menuitem action="ZoomOut" />
- <menuitem action="ZoomFit" />
- </placeholder>
- </menu>
- <menu action="Timeline">
- <placeholder name="Timeline">
- <menuitem action="Split" />
- <menuitem action="DeleteObj" />
- <separator />
- <menuitem action="GroupObj" />
- <menuitem action="UngroupObj" />
- <menuitem action="AlignObj" />
- <separator />
- <menuitem action="Keyframe" />
- <separator />
- <menuitem action="PlayPause" />
- <menuitem action="Screenshot" />
- </placeholder>
- </menu>
- </menubar>
<toolbar name="TimelineToolBar">
<placeholder name="Timeline">
<separator />
@@ -33,10 +9,19 @@
<toolitem action="AlignObj" />
</placeholder>
</toolbar>
- <accelerator action="PlayPause" />
- <accelerator action="DeleteObj" />
+ <accelerator action="ZoomIn" />
+ <accelerator action="ZoomOut" />
+ <accelerator action="ZoomFit" />
<accelerator action="ControlEqualAccel" />
<accelerator action="ControlKPAddAccel" />
<accelerator action="ControlKPSubtractAccel" />
+
+ <accelerator action="DeleteObj" />
+ <accelerator action="UngroupObj" />
+ <accelerator action="GroupObj" />
+ <accelerator action="AlignObj" />
+
+ <accelerator action="PlayPause" />
+ <accelerator action="Split" />
<accelerator action="Keyframe" />
</ui>
diff --git a/pitivi/check.py b/pitivi/check.py
index 88dc42e..0d29956 100644
--- a/pitivi/check.py
+++ b/pitivi/check.py
@@ -175,7 +175,7 @@ HARD_DEPENDENCIES = (CairoDependency("1.10.0"),
GtkOrClutterDependency("ClutterGst", "2.0.0"),
GstDependency("Gst", "1.2.0"),
GstDependency("GES", "1.2.0.0"),
- GtkOrClutterDependency("Gtk", "3.8.0"),
+ GtkOrClutterDependency("Gtk", "3.10.0"),
ClassicDependency("numpy", None),
GIDependency("Gio", None),
GstPluginDependency("gnonlin", "1.2.0"))
diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py
index f0fd190..da15ab6 100644
--- a/pitivi/mainwindow.py
+++ b/pitivi/mainwindow.py
@@ -51,10 +51,6 @@ from pitivi.utils.ui import info_name, beautify_time_delta, SPACING, \
from pitivi.viewer import ViewerContainer
-GlobalSettings.addConfigOption("fileSupportEnabled",
- environment="PITIVI_FILE_SUPPORT",
- default=False)
-
GlobalSettings.addConfigSection("main-window")
GlobalSettings.addConfigOption('mainWindowHPanePosition',
section="main-window",
@@ -126,7 +122,6 @@ Gtk.stock_add = lambda items: None
def create_stock_icons():
""" Creates the pitivi-only stock icons """
Gtk.stock_add([
- ('pitivi-render', _('Render'), 0, 0, 'pitivi'),
('pitivi-split', _('Split'), 0, 0, 'pitivi'),
('pitivi-keyframe', _('Keyframe'), 0, 0, 'pitivi'),
('pitivi-ungroup', _('Ungroup'), 0, 0, 'pitivi'),
@@ -136,7 +131,6 @@ def create_stock_icons():
('pitivi-gapless', _('Gapless mode'), 0, 0, 'pitivi'),
])
pixmaps = {
- "pitivi-render": "pitivi-render-24.png",
"pitivi-split": "pitivi-split-24.svg",
"pitivi-keyframe": "pitivi-keyframe-24.svg",
"pitivi-ungroup": "pitivi-ungroup-24.svg",
@@ -174,7 +168,10 @@ class PitiviMainWindow(Gtk.Window, Loggable):
self.settings = app.settings
self.prefsdialog = None
create_stock_icons()
- self._setActions()
+
+ self.uimanager = Gtk.UIManager()
+ self.add_accel_group(self.uimanager.get_accel_group())
+
self._createUi()
self.recent_manager = Gtk.RecentManager()
self._missingUriOnLoading = False
@@ -217,109 +214,9 @@ class PitiviMainWindow(Gtk.Window, Loggable):
def _renderCb(self, unused_button):
self.showRenderDialog(self.app.current_project)
- def _setActions(self):
- """
- Sets up the GtkActions. This allows managing the sensitivity of widgets
- to the mouse and keyboard shortcuts.
- """
- # Action list items can vary in size (1-6 items). The first one is the
- # name, and it is the only mandatory option. All the other options are
- # optional, and if omitted will default to None.
- #
- # name (required), stock ID, translatable label,
- # keyboard shortcut, translatable tooltip, callback function
- actions = [
- # In some cases we manually specify the translatable label,
- # because we want to have the "..." at the end, indicating
- # an action that requires "further interaction" from the user.
- ("NewProject", Gtk.STOCK_NEW, None,
- None, _("Create a new project"), self._newProjectMenuCb),
-
- ("OpenProject", Gtk.STOCK_OPEN, _("_Open..."),
- None, _("Open an existing project"), self._openProjectCb),
-
- ("SaveProject", Gtk.STOCK_SAVE, None,
- None, _("Save the current project"), self._saveProjectCb),
-
- ("SaveProjectAs", Gtk.STOCK_SAVE_AS, _("Save _As..."),
- None, _("Save the current project"), self._saveProjectAsCb),
-
- ("RevertToSavedProject", Gtk.STOCK_REVERT_TO_SAVED, None,
- None, _("Reload the current project"), self._revertToSavedProjectCb),
-
- ("ExportProject", Gtk.STOCK_HARDDISK, _("Export as Archive..."),
- None, _("Export the current project"), self._exportProjectAsTarCb),
-
- ("ProjectSettings", Gtk.STOCK_PROPERTIES, _("Project Settings"),
- None, _("Edit the project settings"), self._projectSettingsCb),
-
- ("RenderProject", 'pitivi-render', _("_Render..."),
- None, _("Export your project as a finished movie"), self._renderCb),
-
- ("Undo", Gtk.STOCK_UNDO, None,
- "<Ctrl>Z", _("Undo the last operation"), self._undoCb),
-
- ("Redo", Gtk.STOCK_REDO, None,
- "<Ctrl>Y", _("Redo the last operation that was undone"), self._redoCb),
-
- ("Preferences", Gtk.STOCK_PREFERENCES, None,
- None, None, self._prefsCb),
-
- ("Quit", Gtk.STOCK_QUIT, None, None, None, self._quitCb),
-
- ("About", Gtk.STOCK_ABOUT, None,
- None, _("Information about %s") % APPNAME, self._aboutCb),
-
- ("UserManual", Gtk.STOCK_HELP, _("User Manual"),
- "F1", None, self._userManualCb),
-
- # Set up the toplevel menu items for translation
- ("File", None, _("_Project")),
- ("Edit", None, _("_Edit")),
- ("View", None, _("_View")),
- ("Library", None, _("_Library")),
- ("Timeline", None, _("_Timeline")),
- ("Viewer", None, _("Previe_w")),
- ("Help", None, _("_Help")),
- ]
-
- self.main_actions = Gtk.ActionGroup(name="mainwindow")
- self.main_actions.add_actions(actions)
-
- important_actions = ("Undo", "SaveProject", "RenderProject")
- for action in self.main_actions.list_actions():
- action_name = action.get_name()
- if action_name in important_actions:
- # Force showing a label alongside the action's toolbar button
- action.props.is_important = True
- if action_name == "RenderProject":
- # the button is set sensitive when the timeline duration changes
- action.set_sensitive(False)
- self.render_button = action
- elif action_name in ["NewProject", "SaveProject", "SaveProjectAs", "OpenProject"]:
- if self.app.settings.fileSupportEnabled:
- action.set_sensitive(True)
- elif action_name in [
- "File", "Edit", "View", "Help",
- "UserManual", "About", "Quit", "ImportSourcesFolder",
- "Preferences", "Project", "ProjectSettings",
- "Library", "Timeline", "Viewer", "WindowizeViewer"
- ]: # One of the remaining known actions we expect to be sensitive
- action.set_sensitive(True)
- else:
- action.set_sensitive(False)
- self.log("%s has been made insensitive" % action_name)
-
- self.uimanager = Gtk.UIManager()
- self.add_accel_group(self.uimanager.get_accel_group())
- self.uimanager.insert_action_group(self.main_actions, 0)
- self.uimanager.add_ui_from_file(os.path.join(get_ui_dir(), "mainwindow.xml"))
-
def _createUi(self):
"""
Create the graphical interface with the following hierarchy in a vbox:
- -- Menubar
- -- Main toolbar
-- self.vpaned
---- self.mainhpaned (upper half)
------ self.secondaryhpaned (upper-left)
@@ -328,6 +225,8 @@ class PitiviMainWindow(Gtk.Window, Loggable):
------ Viewer (upper-right)
---- Timeline (bottom half)
+ In the window titlebar, there is also a HeaderBar widget.
+
The full hierarchy is also visible with accessibility tools like "sniff"
"""
self.set_title("%s" % APPNAME)
@@ -336,16 +235,21 @@ class PitiviMainWindow(Gtk.Window, Loggable):
self.add(vbox)
vbox.show()
- # Main menu & toolbar
- self.menu = self.uimanager.get_widget("/MainMenuBar")
- self._main_toolbar_box = Gtk.VBox() # To reparent after fullscreen
- self.toolbar = self.uimanager.get_widget("/MainToolBar")
- self.toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)
- self._main_toolbar_box.add(self.toolbar)
- vbox.pack_start(self.menu, False, True, 0)
- vbox.pack_start(self._main_toolbar_box, False, True, 0)
- self.menu.show()
- self._main_toolbar_box.show_all()
+ # Main "toolbar" (using client-side window decorations with HeaderBar)
+ self._headerbar = Gtk.HeaderBar()
+ self._create_headerbar_buttons()
+ builder = Gtk.Builder()
+ builder.add_from_file(os.path.join(get_ui_dir(), "mainmenubutton.ui"))
+ builder.connect_signals(self)
+ menubutton = builder.get_object("menubutton")
+ self._menubutton_items = {}
+ for widget in builder.get_object("menu").get_children():
+ self._menubutton_items[Gtk.Buildable.get_name(widget)] = widget
+
+ self._headerbar.pack_end(menubutton)
+ self._headerbar.set_show_close_button(True)
+ self._headerbar.show_all()
+ self.set_titlebar(self._headerbar)
# Set up our main containers, in the order documented above
self.vpaned = Gtk.VPaned() # Separates the timeline from tabs+viewer
@@ -394,13 +298,16 @@ class PitiviMainWindow(Gtk.Window, Loggable):
# Now, the lower part: the timeline
self.timeline_ui = TimelineContainer(self, self.app, self.uimanager)
self.timeline_ui.setProjectManager(self.app.projectManager)
-
self.vpaned.pack2(self.timeline_ui, resize=True, shrink=False)
+ # Enable our shortcuts for HeaderBar buttons and menu items:
+ self._set_keyboard_shortcuts()
+
# Identify widgets for AT-SPI, making our test suite easier to develop
# These will show up in sniff, accerciser, etc.
self.get_accessible().set_name("main window")
- self.toolbar.get_accessible().set_name("main toolbar")
+ self._headerbar.get_accessible().set_name("headerbar")
+ menubutton.get_accessible().set_name("main menu button")
self.vpaned.get_accessible().set_name("contents")
self.mainhpaned.get_accessible().set_name("upper half")
self.secondhpaned.get_accessible().set_name("tabs")
@@ -456,6 +363,74 @@ class PitiviMainWindow(Gtk.Window, Loggable):
def focusTimeline(self):
self.timeline_ui.grab_focus()
+ def _create_headerbar_buttons(self):
+ self.undo_button = Gtk.Button.new_from_icon_name("edit-undo-symbolic", Gtk.IconSize.LARGE_TOOLBAR)
+ self.undo_button.set_always_show_image(True)
+ self.undo_button.set_label(_("Undo"))
+ self.undo_button.connect("clicked", self._undoCb)
+
+ self.redo_button = Gtk.Button.new_from_icon_name("edit-redo-symbolic", Gtk.IconSize.LARGE_TOOLBAR)
+ self.redo_button.set_always_show_image(True)
+ self.redo_button.set_label(_("Redo"))
+ self.redo_button.connect("clicked", self._redoCb)
+
+ separator = Gtk.Separator()
+
+ self.save_button = Gtk.Button.new_from_icon_name("document-save", Gtk.IconSize.LARGE_TOOLBAR)
+ self.save_button.set_always_show_image(True)
+ self.save_button.set_label(_("Save"))
+ self.save_button.connect("clicked", self._saveProjectCb)
+
+ render_icon = Gtk.Image.new_from_file(os.path.join(get_pixmap_dir(), "pitivi-render-24.png"))
+ self.render_button = Gtk.Button()
+ self.render_button.set_image(render_icon)
+ self.render_button.set_always_show_image(True)
+ self.render_button.set_label(_("Render"))
+ self.render_button.set_tooltip_text(_("Export your project as a finished movie"))
+ self.render_button.set_sensitive(False) # The only one we have to set.
+ self.render_button.connect("clicked", self._renderCb)
+
+ self._headerbar.pack_start(self.undo_button)
+ self._headerbar.pack_start(self.redo_button)
+ self._headerbar.pack_start(separator)
+ self._headerbar.pack_start(self.save_button)
+ self._headerbar.pack_start(self.render_button)
+
+ def _set_keyboard_shortcuts(self):
+ """
+ You can't rely on Glade/GTKBuilder to set accelerators properly
+ on menu items or buttons, it just doesn't work.
+ GAction and GActionGroup are overkill and a massive PITA.
+
+ This code keeps things *really* simple, and it actually works.
+ Bonus points: the accelerators disable themselves when buttons or
+ menu items are set_sensitive(False), which is exactly what we want.
+ """
+ ctrl = Gdk.ModifierType.CONTROL_MASK
+ shift = Gdk.ModifierType.SHIFT_MASK
+ menus = self._menubutton_items
+ self.__set_accelerator(menus["menu_new"], Gdk.KEY_n, ctrl)
+ self.__set_accelerator(menus["menu_open"], Gdk.KEY_o, ctrl)
+ self.__set_accelerator(menus["menu_save_as"], Gdk.KEY_s, ctrl | shift)
+ self.__set_accelerator(menus["menu_help"], Gdk.KEY_F1)
+ self.__set_accelerator(self.undo_button, Gdk.KEY_z, ctrl)
+ self.__set_accelerator(self.redo_button, Gdk.KEY_z, ctrl | shift)
+ self.__set_accelerator(self.save_button, Gdk.KEY_s, ctrl)
+
+ def __set_accelerator(self, widget, key, mods=0, flags=Gtk.AccelFlags.VISIBLE):
+ """
+ Convenience function to deal with the madness of widget.add_accelerator
+ to set a keyboard shortcut onto a GTK Widget. It determines the proper
+ widget signal to emit and allows using default modifiers and flags.
+ """
+ accel_group = self.uimanager.get_accel_group()
+ if type(widget) in [Gtk.Button, Gtk.ToolItem]:
+ signal = "clicked"
+ else:
+ signal = "activate"
+
+ widget.add_accelerator(signal, accel_group, key, mods, flags)
+
## Missing Plugin Support
def _installPlugins(self, details, missingPluginsCallback):
@@ -506,7 +481,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
preview_window.preview()
def _projectChangedCb(self, unused_project):
- self.main_actions.get_action("SaveProject").set_sensitive(True)
+ self.save_button.set_sensitive(True)
self.updateTitle()
def _mediaLibrarySourceRemovedCb(self, unused_project, asset):
@@ -557,10 +532,6 @@ class PitiviMainWindow(Gtk.Window, Loggable):
ProjectSettingsDialog(self, self.app.current_project).window.run()
self.updateTitle()
- def _quitCb(self, unused_action):
- self._saveWindowSettings()
- self.app.shutdown()
-
def _userManualCb(self, unused_action):
show_user_manual()
@@ -674,6 +645,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
self.prefsdialog = PreferencesDialog(self.app)
self.prefsdialog.run()
+## Project management callbacks
def _projectManagerNewProjectLoadedCb(self, projectManager, unused_project, unused_fully_loaded):
"""
Once a new project has been loaded, wait for media library's
@@ -690,17 +662,15 @@ class PitiviMainWindow(Gtk.Window, Loggable):
#self._syncDoUndo(self.app.action_log)
self.updateTitle()
- # Enable export functionality
- self.main_actions.get_action("ExportProject").set_sensitive(True)
if self._missingUriOnLoading:
self.app.current_project.setModificationState(True)
- self.main_actions.get_action("SaveProject").set_sensitive(True)
+ self.save_button.set_sensitive(True)
self._missingUriOnLoading = False
if projectManager.disable_save is True:
# Special case: we enforce "Save as", but the normal "Save" button
# redirects to it if needed, so we still want it to be enabled:
- self.main_actions.get_action("SaveProject").set_sensitive(True)
+ self.save_button.set_sensitive(True)
if self.app.current_project.timeline.props.duration != 0:
self.render_button.set_sensitive(True)
@@ -731,7 +701,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
#self._syncDoUndo(self.app.action_log)
self.updateTitle()
- self.main_actions.get_action("SaveProject").set_sensitive(False)
+ self.save_button.set_sensitive(False)
if uri:
self.recent_manager.add_item(uri)
@@ -831,6 +801,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
self.medialibrary.storemodel.clear()
self.timeline_ui.setProject(None)
self.clipconfig.timeline = None
+ self.render_button.set_sensitive(False)
return False
def _projectManagerRevertingToSavedCb(self, unused_project_manager, unused_project):
@@ -982,6 +953,8 @@ class PitiviMainWindow(Gtk.Window, Loggable):
project.connect("asset-removed", self._mediaLibrarySourceRemovedCb)
project.connect("project-changed", self._projectChangedCb)
+## Undo/redo methods
+
def _actionLogCommit(self, action_log, unused_stack, nested):
if nested:
return
@@ -998,21 +971,17 @@ class PitiviMainWindow(Gtk.Window, Loggable):
self._syncDoUndo(action_log)
def _syncDoUndo(self, action_log):
- undo_action = self.main_actions.get_action("Undo")
can_undo = bool(action_log.undo_stacks)
- undo_action.set_sensitive(can_undo)
+ self.undo_button.set_sensitive(can_undo)
dirty = action_log.dirty()
- save_action = self.main_actions.get_action("SaveProject")
- save_action.set_sensitive(dirty)
+ self.save_button.set_sensitive(dirty)
if self.app.current_project.uri is not None:
- revert_action = self.main_actions.get_action("RevertToSavedProject")
- revert_action.set_sensitive(dirty)
+ self._menubutton_items["menu_revert_to_saved"].set_sensitive(dirty)
self.app.current_project.setModificationState(dirty)
- redo_action = self.main_actions.get_action("Redo")
can_redo = bool(action_log.redo_stacks)
- redo_action.set_sensitive(can_redo)
+ self.redo_button.set_sensitive(can_redo)
self.updateTitle()
## Pitivi current project callbacks
@@ -1058,6 +1027,10 @@ class PitiviMainWindow(Gtk.Window, Loggable):
return res
def _timelineDurationChangedCb(self, timeline, unused_duration):
+ """
+ When a clip is inserted into a blank timeline, enable the render button.
+ This callback is not triggered by loading a project.
+ """
duration = timeline.get_duration()
self.debug("Timeline duration changed to %s", duration)
self.render_button.set_sensitive(duration > 0)
@@ -1149,6 +1122,50 @@ class PitiviMainWindow(Gtk.Window, Loggable):
chooser.destroy()
return ret
+ def _screenshotCb(self, unused_action):
+ """
+ Export a snapshot of the current frame as an image file.
+ """
+ foo = self._showSaveScreenshotDialog()
+ if foo:
+ path, mime = foo[0], foo[1]
+ self.app.current_project.pipeline.save_thumbnail(-1, -1, mime, path)
+
+ def _showSaveScreenshotDialog(self):
+ """
+ Show a filechooser dialog asking the user where to save the snapshot
+ of the current frame and what file type to use.
+
+ Returns a list containing the full path and the mimetype if successful,
+ returns none otherwise.
+ """
+ chooser = Gtk.FileChooserDialog(title=_("Save As..."),
+ transient_for=self, action=Gtk.FileChooserAction.SAVE)
+ chooser.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+ Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
+ chooser.set_icon_name("pitivi")
+ chooser.set_select_multiple(False)
+ chooser.set_current_name(_("Untitled"))
+ chooser.props.do_overwrite_confirmation = True
+ formats = {_("PNG image"): ["image/png", ("png",)],
+ _("JPEG image"): ["image/jpeg", ("jpg", "jpeg")]}
+ for format in formats:
+ filt = Gtk.FileFilter()
+ filt.set_name(format)
+ filt.add_mime_type(formats.get(format)[0])
+ chooser.add_filter(filt)
+ response = chooser.run()
+ if response == Gtk.ResponseType.OK:
+ chosen_format = formats.get(chooser.get_filter().get_name())
+ chosen_ext = chosen_format[1][0]
+ chosen_mime = chosen_format[0]
+ uri = os.path.join(chooser.get_current_folder(), chooser.get_filename())
+ ret = [uri + "." + chosen_ext, chosen_mime]
+ else:
+ ret = None
+ chooser.destroy()
+ return ret
+
def updateTitle(self):
name = touched = ""
if self.app.current_project:
@@ -1159,6 +1176,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
if self.app.current_project.hasUnsavedModifications():
touched = "*"
title = "%s%s — %s" % (touched, name, APPNAME)
+ self._headerbar.set_title(title)
self.set_title(title)
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index c60adf8..1d45786 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -983,10 +983,6 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
("ZoomFit", Gtk.STOCK_ZOOM_FIT, None,
"<Control>0", zoom_fit_tooltip, self._zoomFitCb),
- ("Screenshot", None, _("Export current frame..."),
- None, _("Export the frame at the current playhead "
- "position as an image file."), self._screenshotCb),
-
# Alternate keyboard shortcuts to the actions above
("ControlEqualAccel", Gtk.STOCK_ZOOM_IN, None,
"<Control>equal", zoom_in_tooltip, self._zoomInCb),
@@ -1265,41 +1261,6 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
x += self.timeline.get_scroll_point().x
return x - CONTROL_WIDTH, y - height
- def _showSaveScreenshotDialog(self):
- """
- Show a filechooser dialog asking the user where to save the snapshot
- and what file type to use.
-
- Returns a list containing the full path and the mimetype if successful,
- returns none otherwise.
- """
- chooser = Gtk.FileChooserDialog(title=_("Save As..."), transient_for=self.app.gui,
- action=Gtk.FileChooserAction.SAVE)
- chooser.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
- Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
- chooser.set_icon_name("pitivi")
- chooser.set_select_multiple(False)
- chooser.set_current_name(_("Untitled"))
- chooser.props.do_overwrite_confirmation = True
- formats = {_("PNG image"): ["image/png", ("png",)],
- _("JPEG image"): ["image/jpeg", ("jpg", "jpeg")]}
- for format in formats:
- filt = Gtk.FileFilter()
- filt.set_name(format)
- filt.add_mime_type(formats.get(format)[0])
- chooser.add_filter(filt)
- response = chooser.run()
- if response == Gtk.ResponseType.OK:
- chosen_format = formats.get(chooser.get_filter().get_name())
- chosen_ext = chosen_format[1][0]
- chosen_mime = chosen_format[0]
- uri = os.path.join(chooser.get_current_folder(), chooser.get_filename())
- ret = [uri + "." + chosen_ext, chosen_mime]
- else:
- ret = None
- chooser.destroy()
- return ret
-
# Zoomable
def zoomChanged(self):
@@ -1425,15 +1386,6 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
def _zoomFitCb(self, unused, unused_2=None):
self._setBestZoomRatio(allow_zoom_in=True)
- def _screenshotCb(self, unused_action):
- """
- Export a snapshot of the current frame as an image file.
- """
- foo = self._showSaveScreenshotDialog()
- if foo:
- path, mime = foo[0], foo[1]
- self._project.pipeline.save_thumbnail(-1, -1, mime, path)
-
def _scrollEventCb(self, unused_embed, event):
deltas = event.get_scroll_deltas()
if event.state & Gdk.ModifierType.CONTROL_MASK:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]