aboutsummaryrefslogtreecommitdiffstats
path: root/mvc/widgets/gtk/window.py
diff options
context:
space:
mode:
authorJesús Eduardo <heckyel@hyperbola.info>2017-09-11 17:47:17 -0500
committerJesús Eduardo <heckyel@hyperbola.info>2017-09-11 17:47:17 -0500
commit14738704ede6dfa6ac79f362a9c1f7f40f470cdc (patch)
tree31c83bdd188ae7b64d7169974d6f066ccfe95367 /mvc/widgets/gtk/window.py
parenteb1896583afbbb622cadcde1a24e17173f61904f (diff)
downloadlibrevideoconverter-14738704ede6dfa6ac79f362a9c1f7f40f470cdc.tar.lz
librevideoconverter-14738704ede6dfa6ac79f362a9c1f7f40f470cdc.tar.xz
librevideoconverter-14738704ede6dfa6ac79f362a9c1f7f40f470cdc.zip
rename mvc at lvc
Diffstat (limited to 'mvc/widgets/gtk/window.py')
-rw-r--r--mvc/widgets/gtk/window.py708
1 files changed, 0 insertions, 708 deletions
diff --git a/mvc/widgets/gtk/window.py b/mvc/widgets/gtk/window.py
deleted file mode 100644
index 3859a1a..0000000
--- a/mvc/widgets/gtk/window.py
+++ /dev/null
@@ -1,708 +0,0 @@
-# @Base: Miro - an RSS based video player application
-# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
-# Jesus Eduardo (Heckyel) | 2017
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-# In addition, as a special exception, the copyright holders give
-# permission to link the code of portions of this program with the OpenSSL
-# library.
-#
-# You must obey the GNU General Public License in all respects for all of
-# the code used other than OpenSSL. If you modify file(s) with this
-# exception, you may extend this exception to your version of the file(s),
-# but you are not obligated to do so. If you do not wish to do so, delete
-# this exception statement from your version. If you delete this exception
-# statement from all source files in the program, then also delete it here.
-
-""".window -- GTK Window widget."""
-
-import gobject
-import gtk
-import os
-
-from mvc import resources
-from mvc import signals
-
-import keymap
-import layout
-import widgets
-import wrappermap
-
-# keeps the objects alive until destroy() is called
-alive_windows = set()
-running_dialogs = set()
-
-class WrappedWindow(gtk.Window):
- def do_map(self):
- gtk.Window.do_map(self)
- wrappermap.wrapper(self).emit('show')
-
- def do_unmap(self):
- gtk.Window.do_unmap(self)
- wrappermap.wrapper(self).emit('hide')
- def do_focus_in_event(self, event):
- gtk.Window.do_focus_in_event(self, event)
- wrappermap.wrapper(self).emit('active-change')
- def do_focus_out_event(self, event):
- gtk.Window.do_focus_out_event(self, event)
- wrappermap.wrapper(self).emit('active-change')
-
- def do_key_press_event(self, event):
- if self.activate_key(event): # event activated a menu item
- return
-
- if self.propagate_key_event(event): # event handled by widget
- return
-
- ret = keymap.translate_gtk_event(event)
- if ret is not None:
- key, modifiers = ret
- rv = wrappermap.wrapper(self).emit('key-press', key, modifiers)
- if not rv:
- gtk.Window.do_key_press_event(self, event)
-
- def _get_focused_wrapper(self):
- """Get the wrapper of the widget with keyboard focus"""
- focused = self.get_focus()
- # some of our widgets created children for their use
- # (GtkSearchTextEntry). If we don't find a wrapper for
- # focused, try it's parents
- while focused is not None:
- try:
- wrapper = wrappermap.wrapper(focused)
- except KeyError:
- focused = focused.get_parent()
- else:
- return wrapper
- return None
-
- def change_focus_using_wrapper(self, direction):
- my_wrapper = wrappermap.wrapper(self)
- focused_wrapper = self._get_focused_wrapper()
- if direction == gtk.DIR_TAB_FORWARD:
- to_focus = my_wrapper.get_next_tab_focus(focused_wrapper, True)
- elif direction == gtk.DIR_TAB_BACKWARD:
- to_focus = my_wrapper.get_next_tab_focus(focused_wrapper, False)
- else:
- return False
- if to_focus is not None:
- to_focus.focus()
- return True
- return False
-
- def do_focus(self, direction):
- if not self.change_focus_using_wrapper(direction):
- gtk.Window.do_focus(self, direction)
-
-gobject.type_register(WrappedWindow)
-
-class WindowBase(signals.SignalEmitter):
- def __init__(self):
- signals.SignalEmitter.__init__(self)
- self.create_signal('use-custom-style-changed')
- self.create_signal('key-press')
- self.create_signal('show')
- self.create_signal('hide')
-
- def set_window(self, window):
- self._window = window
- window.connect('style-set', self.on_style_set)
- wrappermap.add(window, self)
- self.calc_use_custom_style()
-
- def on_style_set(self, widget, old_style):
- old_use_custom_style = self.use_custom_style
- self.calc_use_custom_style()
- if old_use_custom_style != self.use_custom_style:
- self.emit('use-custom-style-changed')
-
- def calc_use_custom_style(self):
- if self._window is not None:
- base = self._window.style.base[gtk.STATE_NORMAL]
- # Decide if we should use a custom style. Right now the
- # formula is the base color is a very light shade of
- # gray/white (lighter than #f0f0f0).
- self.use_custom_style = ((base.red == base.green == base.blue) and
- base.red >= 61680)
-
-
-class Window(WindowBase):
- """The main Libre window. """
-
- def __init__(self, title, rect=None):
- """Create the Libre Main Window. Title is the name to give the
- window, rect specifies the position it should have on screen.
- """
- WindowBase.__init__(self)
- self.set_window(self._make_gtk_window())
- self._window.set_title(title)
- self.setup_icon()
- if rect:
- self._window.set_default_size(rect.width, rect.height)
- self._window.set_default_size(rect.width, rect.height)
- self._window.set_gravity(gtk.gdk.GRAVITY_CENTER)
- self._window.move(rect.x, rect.y)
-
- self.create_signal('active-change')
- self.create_signal('will-close')
- self.create_signal('did-move')
- self.create_signal('file-drag-motion')
- self.create_signal('file-drag-received')
- self.create_signal('file-drag-leave')
- self.create_signal('on-shown')
- self.drag_signals = []
- alive_windows.add(self)
-
- self._window.connect('delete-event', self.on_delete_window)
- self._window.connect('map-event', lambda w, a: self.emit('on-shown'))
- # XXX: Define MVCWindow/MiroWindow style not hard code this
- self._window.set_resizable(False)
-
- def setup_icon(self):
- icon_pixbuf = gtk.gdk.pixbuf_new_from_file(
- resources.image_path("mvc-logo.png"))
- self._window.set_icon(icon_pixbuf)
-
-
- def accept_file_drag(self, val):
- if not val:
- self._window.drag_dest_set(0, [], 0)
- for handle in self.drag_signals:
- self.disconnect(handle)
- self.drag_signals = []
- else:
- self._window.drag_dest_set(
- gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_DROP,
- [('text/uri-list', 0, 0)],
- gtk.gdk.ACTION_COPY)
- for signal, callback in (
- ('drag-motion', self.on_drag_motion),
- ('drag-data-received', self.on_drag_data_received),
- ('drag-leave', self.on_drag_leave)):
- self.drag_signals.append(
- self._window.connect(signal, callback))
-
- def on_drag_motion(self, widget, context, x, y, time):
- self.emit('file-drag-motion')
-
- def on_drag_data_received(self, widget, context, x, y, selection_data,
- info, time):
- self.emit('file-drag-received', selection_data.get_uris())
-
- def on_drag_leave(self, widget, context, time):
- self.emit('file-drag-leave')
-
- def on_delete_window(self, widget, event):
- # when the user clicks on the X in the corner of the window we
- # want that to close the window, but also trigger our
- # will-close signal and all that machinery unless the window
- # is currently hidden--then we don't do anything.
- if not self._window.window.is_visible():
- return
- self.close()
- return True
-
- def _make_gtk_window(self):
- return WrappedWindow()
-
- def set_title(self, title):
- self._window.set_title(title)
-
- def get_title(self):
- self._window.get_title()
-
- def center(self):
- self._window.set_position(gtk.WIN_POS_CENTER)
-
- def show(self):
- if self not in alive_windows:
- raise ValueError("Window destroyed")
- self._window.show()
-
- def close(self):
- if hasattr(self, "_closing"):
- return
- self._closing = True
- # Keep a reference to the widget in case will-close signal handler
- # calls destroy()
- old_window = self._window
- self.emit('will-close')
- old_window.hide()
- del self._closing
-
- def destroy(self):
- self.close()
- self._window = None
- alive_windows.discard(self)
-
- def is_active(self):
- return self._window.is_active()
-
- def is_visible(self):
- return self._window.props.visible
-
- def get_next_tab_focus(self, current, is_forward):
- return None
-
- def set_content_widget(self, widget):
- """Set the widget that will be drawn in the content area for this
- window.
-
- It will be allocated the entire area of the widget, except the
- space needed for the titlebar, frame and other decorations.
- When the window is resized, content should also be resized.
- """
- self._add_content_widget(widget)
- widget._widget.show()
- self.content_widget = widget
-
- def _add_content_widget(self, widget):
- self._window.add(widget._widget)
-
- def get_content_widget(self, widget):
- """Get the current content widget."""
- return self.content_widget
-
- def get_frame(self):
- pos = self._window.get_position()
- size = self._window.get_size()
- return widgets.Rect(pos[0], pos[1], size[0], size[1])
-
- def set_frame(self, x=None, y=None, width=None, height=None):
- if x is not None or y is not None:
- pos = self._window.get_position()
- x = x if x is not None else pos[0]
- y = y if y is not None else pos[1]
- self._window.move(x, y)
-
- if width is not None or height is not None:
- size = self._window.get_size()
- width = width if width is not None else size[0]
- height = height if height is not None else size[1]
- self._window.resize(width, height)
-
- def get_monitor_geometry(self):
- """Returns a Rect of the geometry of the monitor that this
- window is currently on.
-
- :returns: Rect
- """
- gtkwindow = self._window
- gdkwindow = gtkwindow.window
- screen = gtkwindow.get_screen()
-
- monitor = screen.get_monitor_at_window(gdkwindow)
- return screen.get_monitor_geometry(monitor)
-
- def check_position_and_fix(self):
- """This pulls the geometry of the monitor of the screen this
- window is on as well as the position of the window.
-
- It then makes sure that the position y is greater than the
- monitor geometry y. This makes sure that the titlebar of
- the window is showing.
- """
- gtkwindow = self._window
- gdkwindow = gtkwindow.window
- monitor_geom = self.get_monitor_geometry()
-
- frame_extents = gdkwindow.get_frame_extents()
- position = gtkwindow.get_position()
-
- # if the frame is not visible, then we move the window so that
- # it is
- if frame_extents.y < monitor_geom.y:
- gtkwindow.move(position[0],
- monitor_geom.y + (position[1] - frame_extents.y))
-
-
-
-class DialogWindow(Window):
- def __init__(self, title, rect=None):
- Window.__init__(self, title, rect)
- self._window.set_resizable(False)
-
-class MainWindow(Window):
- def __init__(self, title, rect):
- Window.__init__(self, title, rect)
- self.vbox = gtk.VBox()
- self._window.add(self.vbox)
- self.vbox.show()
- self._add_app_menubar()
- self.create_signal('save-dimensions')
- self.create_signal('save-maximized')
- self._window.connect('key-release-event', self.on_key_release)
- self._window.connect('window-state-event', self.on_window_state_event)
- self._window.connect('configure-event', self.on_configure_event)
-
- def _make_gtk_window(self):
- return WrappedWindow()
-
- def on_delete_window(self, widget, event):
- return True
-
- def on_configure_event(self, widget, event):
- (x, y) = self._window.get_position()
- (width, height) = self._window.get_size()
- self.emit('save-dimensions', x, y, width, height)
-
- def on_window_state_event(self, widget, event):
- maximized = bool(
- event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED)
- self.emit('save-maximized', maximized)
-
- def on_key_release(self, widget, event):
- if app.playback_manager.is_playing:
- if gtk.gdk.keyval_name(event.keyval) in ('Right', 'Left',
- 'Up', 'Down'):
- return True
-
- def _add_app_menubar(self):
- self.menubar = app.widgetapp.menubar
- self.vbox.pack_start(self.menubar._widget, expand=False)
- self.connect_menu_keyboard_shortcuts()
-
- def _add_content_widget(self, widget):
- self.vbox.pack_start(widget._widget, expand=True)
-
-
-class DialogBase(WindowBase):
- def set_transient_for(self, window):
- self._window.set_transient_for(window._window)
-
- def run(self):
- running_dialogs.add(self)
- try:
- return self._run()
- finally:
- running_dialogs.remove(self)
- self._window = None
-
- def _run(self):
- """Run the dialog. Must be implemented by subclasses."""
- raise NotImplementedError()
-
- def destroy(self):
- if self._window is not None:
- self._window.response(gtk.RESPONSE_NONE)
- # don't set self._window to None yet. We will unset it when we
- # return from the _run() method
-
-class Dialog(DialogBase):
- def __init__(self, title, description=None):
- """Create a dialog."""
- DialogBase.__init__(self)
- self.create_signal('open')
- self.create_signal('close')
- self.set_window(gtk.Dialog(title))
- self._window.set_default_size(425, -1)
- self.extra_widget = None
- self.buttons_to_add = []
- wrappermap.add(self._window, self)
- self.description = description
-
- def build_content(self):
- packing_vbox = layout.VBox(spacing=20)
- packing_vbox._widget.set_border_width(6)
- if self.description is not None:
- label = gtk.Label(self.description)
- label.set_line_wrap(True)
- label.set_size_request(390, -1)
- label.set_selectable(True)
- packing_vbox._widget.pack_start(label)
- if self.extra_widget:
- packing_vbox._widget.pack_start(self.extra_widget._widget)
- return packing_vbox
-
- def add_button(self, text):
- from mvc.widgets import dialogs
- _stock = {
- dialogs.BUTTON_OK.text: gtk.STOCK_OK,
- dialogs.BUTTON_CANCEL.text: gtk.STOCK_CANCEL,
- dialogs.BUTTON_YES.text: gtk.STOCK_YES,
- dialogs.BUTTON_NO.text: gtk.STOCK_NO,
- dialogs.BUTTON_QUIT.text: gtk.STOCK_QUIT,
- dialogs.BUTTON_REMOVE.text: gtk.STOCK_REMOVE,
- dialogs.BUTTON_DELETE.text: gtk.STOCK_DELETE,
- }
- if text in _stock:
- # store both the text and the stock ID
- text = _stock[text], text
- self.buttons_to_add.append(text)
-
- def pack_buttons(self):
- # There's a couple tricky things here:
- # 1) We need to add them in the reversed order we got them, since GTK
- # lays them out left-to-right
- #
- # 2) We can't use 0 as a response-id. GTK only reserves positive
- # response_ids for the user.
- response_id = len(self.buttons_to_add)
- for text in reversed(self.buttons_to_add):
- label = None
- if isinstance(text, tuple): # stock ID, text
- text, label = text
- button = self._window.add_button(text, response_id)
- if label is not None:
- button.set_label(label)
- response_id -= 1
- self.buttons_to_add = []
- self._window.set_default_response(1)
-
- def _run(self):
- self.pack_buttons()
- packing_vbox = self.build_content()
- self._window.vbox.pack_start(packing_vbox._widget, True, True)
- self._window.show_all()
- response = self._window.run()
- self._window.hide()
- if response == gtk.RESPONSE_DELETE_EVENT:
- return -1
- else:
- return response - 1 # response IDs started at 1
-
- def set_extra_widget(self, widget):
- self.extra_widget = widget
-
- def get_extra_widget(self):
- return self.extra_widget
-
-class FileDialogBase(DialogBase):
- def _run(self):
- ret = self._window.run()
- self._window.hide()
- if ret == gtk.RESPONSE_OK:
- self._files = self._window.get_filenames()
- return 0
-
-class FileOpenDialog(FileDialogBase):
- def __init__(self, title):
- FileDialogBase.__init__(self)
- self._files = None
- fcd = gtk.FileChooserDialog(title,
- action=gtk.FILE_CHOOSER_ACTION_OPEN,
- buttons=(gtk.STOCK_CANCEL,
- gtk.RESPONSE_CANCEL,
- gtk.STOCK_OPEN,
- gtk.RESPONSE_OK))
-
- self.set_window(fcd)
-
- def set_filename(self, text):
- self._window.set_filename(text)
-
- def set_select_multiple(self, value):
- self._window.set_select_multiple(value)
-
- def add_filters(self, filters):
- for name, ext_list in filters:
- f = gtk.FileFilter()
- f.set_name(name)
- for mem in ext_list:
- f.add_pattern('*.%s' % mem)
- self._window.add_filter(f)
-
- f = gtk.FileFilter()
- f.set_name(_('All files'))
- f.add_pattern('*')
- self._window.add_filter(f)
-
- def get_filenames(self):
- return [unicode(f) for f in self._files]
-
- def get_filename(self):
- if self._files is None:
- # clicked Cancel
- return None
- else:
- return unicode(self._files[0])
-
- # provide a common interface for file chooser dialogs
- get_path = get_filename
- def set_path(self, path):
- # set_filename puts the whole path in the filename field
- self._window.set_current_folder(os.path.dirname(path))
- self._window.set_current_name(os.path.basename(path))
-
-class FileSaveDialog(FileDialogBase):
- def __init__(self, title):
- FileDialogBase.__init__(self)
- self._files = None
- fcd = gtk.FileChooserDialog(title,
- action=gtk.FILE_CHOOSER_ACTION_SAVE,
- buttons=(gtk.STOCK_CANCEL,
- gtk.RESPONSE_CANCEL,
- gtk.STOCK_SAVE,
- gtk.RESPONSE_OK))
- self.set_window(fcd)
-
- def set_filename(self, text):
- self._window.set_current_name(text)
-
- def get_filename(self):
- if self._files is None:
- # clicked Cancel
- return None
- else:
- return unicode(self._files[0])
-
- # provide a common interface for file chooser dialogs
- get_path = get_filename
- def set_path(self, path):
- # set_filename puts the whole path in the filename field
- self._window.set_current_folder(os.path.dirname(path))
- self._window.set_current_name(os.path.basename(path))
-
-class DirectorySelectDialog(FileDialogBase):
- def __init__(self, title):
- FileDialogBase.__init__(self)
- self._files = None
- choose_str = 'Choose'
- fcd = gtk.FileChooserDialog(
- title,
- action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
- buttons=(gtk.STOCK_CANCEL,
- gtk.RESPONSE_CANCEL,
- choose_str, gtk.RESPONSE_OK))
- self.set_window(fcd)
-
- def set_directory(self, text):
- self._window.set_filename(text)
-
- def get_directory(self):
- if self._files is None:
- # clicked Cancel
- return None
- else:
- return unicode(self._files[0])
-
- # provide a common interface for file chooser dialogs
- get_path = get_directory
- set_path = set_directory
-
-class AboutDialog(Dialog):
- def __init__(self):
- Dialog.__init__(self, "Libre Video Converter")
-# _("About %(appname)s",
-# {'appname': app.config.get(prefs.SHORT_APP_NAME)}))
-# self.add_button(_("Close"))
- self.add_button("Close")
- self._window.set_has_separator(False)
-
- def build_content(self):
- packing_vbox = layout.VBox(spacing=20)
- #icon_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
- # resources.share_path('icons/hicolor/128x128/apps/miro.png'),
- # 48, 48)
- #packing_vbox._widget.pack_start(gtk.image_new_from_pixbuf(icon_pixbuf))
- #if app.config.get(prefs.APP_REVISION_NUM):
- # version = "%s (%s)" % (
- # app.config.get(prefs.APP_VERSION),
- # app.config.get(prefs.APP_REVISION_NUM))
- #else:
- # version = "%s" % app.config.get(prefs.APP_VERSION)
- version = '3.0'
- #name_label = gtk.Label(
- # '<span size="xx-large" weight="bold">%s %s</span>' % (
- # app.config.get(prefs.SHORT_APP_NAME), version))
- name_label = gtk.Label(
- '<span size="xx-large" weight="bold">%s %s</span>' % (
- 'Libre Video Converter', version))
- name_label.set_use_markup(True)
- packing_vbox._widget.pack_start(name_label)
- copyright_text = 'Copyright (c) Jesus Eduardo (Heckyel) | 2017'
- copyright_label = gtk.Label('<small>%s</small>' % copyright_text)
- copyright_label.set_use_markup(True)
- copyright_label.set_justify(gtk.JUSTIFY_CENTER)
- packing_vbox._widget.pack_start(copyright_label)
-
- # FIXME - make the project url clickable
- #packing_vbox._widget.pack_start(
- # gtk.Label(app.config.get(prefs.PROJECT_URL)))
-
- #contributor_label = gtk.Label(
- # _("Thank you to all the people who contributed to %(appname)s "
- # "%(version)s:",
- # {"appname": app.config.get(prefs.SHORT_APP_NAME),
- # "version": app.config.get(prefs.APP_VERSION)}))
- #contributor_label.set_justify(gtk.JUSTIFY_CENTER)
- #packing_vbox._widget.pack_start(contributor_label)
-
- # get contributors, remove newlines and wrap it
- #contributors = open(resources.path('CREDITS'), 'r').readlines()
- #contributors = [c[2:].strip()
- # for c in contributors if c.startswith("* ")]
- #contributors = ", ".join(contributors)
-
- # show contributors
- #contrib_buffer = gtk.TextBuffer()
- #contrib_buffer.set_text(contributors)
-
- #contrib_view = gtk.TextView(contrib_buffer)
- #contrib_view.set_editable(False)
- #contrib_view.set_cursor_visible(False)
- #contrib_view.set_wrap_mode(gtk.WRAP_WORD)
- #contrib_window = gtk.ScrolledWindow()
- #contrib_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
- #contrib_window.add(contrib_view)
- #contrib_window.set_size_request(-1, 100)
- #packing_vbox._widget.pack_start(contrib_window)
-
- # FIXME - make the project url clickable
- #donate_label = gtk.Label(
- # _("To help fund continued %(appname)s development, visit the "
- # "donation page at:",
- # {"appname": app.config.get(prefs.SHORT_APP_NAME)}))
- #donate_label.set_justify(gtk.JUSTIFY_CENTER)
- #packing_vbox._widget.pack_start(donate_label)
-
- #packing_vbox._widget.pack_start(
- # gtk.Label(app.config.get(prefs.DONATE_URL)))
- return packing_vbox
-
- def on_contrib_link_event(self, texttag, widget, event, iter_):
- if event.type == gtk.gdk.BUTTON_PRESS:
- resources.open_url('https://notabug.org/heckyel/librevideoconverter')
-
-type_map = {
- 0: gtk.MESSAGE_WARNING,
- 1: gtk.MESSAGE_INFO,
- 2: gtk.MESSAGE_ERROR
-}
-
-class AlertDialog(DialogBase):
- def __init__(self, title, description, alert_type):
- DialogBase.__init__(self)
- message_type = type_map.get(alert_type, gtk.MESSAGE_INFO)
- self.set_window(gtk.MessageDialog(type=message_type,
- message_format=description))
- self._window.set_title(title)
- self.description = description
-
- def add_button(self, text):
- self._window.add_button(_stock.get(text, text), 1)
- self._window.set_default_response(1)
-
- def _run(self):
- self._window.set_modal(False)
- self._window.show_all()
- response = self._window.run()
- self._window.hide()
- if response == gtk.RESPONSE_DELETE_EVENT:
- return -1
- else:
- # response IDs start at 1
- return response - 1