OSDN Git Service

version bump
[mypaint-anime/master.git] / gui / drawwindow.py
index 344a453..f5ba5f9 100644 (file)
@@ -13,16 +13,16 @@ This is the main drawing window, containing menu actions.
 Painting is done in tileddrawwidget.py.
 """
 
-MYPAINT_VERSION="0.9.1+git"
+MYPAINT_VERSION="1.0.0"
 
-import os, math, time
+import os, math, time, webbrowser
 from gettext import gettext as _
 
 import gtk, gobject
 from gtk import gdk, keysyms
 import pango
 
-import colorselectionwindow, historypopup, stategroup, colorpicker, windowing, layout
+import colorselectionwindow, historypopup, stategroup, colorpicker, windowing, layout, toolbar
 import dialogs
 from lib import helpers
 import stock
@@ -129,11 +129,10 @@ def button_press_cb_abstraction(drawwindow, win, event, doc):
         return True
 
     # Dispatch regular GTK events.
-    for ag in drawwindow.action_group, doc.action_group:
-        action = ag.get_action(action_name)
-        if action is not None:
-            action.activate()
-            return True
+    action = drawwindow.app.find_action(action_name)
+    if action is not None:
+        action.activate()
+        return True
 
 def button_release_cb_abstraction(win, event, doc):
     #print event.device, event.button
@@ -182,6 +181,14 @@ class Window (windowing.MainWindow, layout.MainWindow):
 
         lm = app.layout_manager
         layout.MainWindow.__init__(self, lm)
+
+        # Park the focus on the main tdw rather than on the toolbar. Default
+        # activation doesn't really mean much for MyPaint's main window, so
+        # it's safe to do this and it looks better.
+        self.main_widget.set_can_default(True)
+        self.main_widget.set_can_focus(True)
+        self.main_widget.grab_focus()
+
         self.main_widget.connect("button-press-event", self.button_press_cb)
         self.main_widget.connect("button-release-event",self.button_release_cb)
         self.main_widget.connect("scroll-event", self.scroll_cb)
@@ -213,8 +220,10 @@ class Window (windowing.MainWindow, layout.MainWindow):
             ('ColorMenu',    None, _('Color')),
             ('ColorPickerPopup',    gtk.STOCK_COLOR_PICKER, _('Pick Color'), 'r', None, self.popup_cb),
             ('ColorHistoryPopup',  None, _('Color History'), 'x', None, self.popup_cb),
-            ('ColorChangerPopup', None, _('Color Changer'), 'v', None, self.popup_cb),
+            ('ColorChangerCrossedBowlPopup', None, _('Color Changer (crossed bowl)'), 'v', None, self.popup_cb),
+            ('ColorChangerWashPopup', None, _('Color Changer (washed)'), 'c', None, self.popup_cb),
             ('ColorRingPopup',  None, _('Color Ring'), None, None, self.popup_cb),
+            ('ColorDetailsDialog', None, _("Color Details"), None, None, self.color_details_dialog_cb),
 
             ('ContextMenu',  None, _('Brushkeys')),
             ('ContextHelp',  gtk.STOCK_HELP, _('Help!'), None, None, self.show_infodialog_cb),
@@ -236,7 +245,9 @@ class Window (windowing.MainWindow, layout.MainWindow):
             ('ScratchCopyBackground',  None, _('Copy Background to Scratchpad'), None, None, self.scratchpad_copy_background_cb),
 
             ('BrushMenu',    None, _('Brush')),
-            ('ImportBrushPack',       gtk.STOCK_OPEN, _('Import brush package...'), '', None, self.import_brush_pack_cb),
+            ('BrushChooserPopup', stock.TOOL_BRUSH, _("Change Brush..."), 'b', None, self.brush_chooser_popup_cb),
+            ('DownloadBrushPack', gtk.STOCK_OPEN, _('Download more brushes (in web browser)'), '', None, self.download_brush_pack_cb),
+            ('ImportBrushPack', gtk.STOCK_OPEN, _('Import brush package...'), '', None, self.import_brush_pack_cb),
 
             ('HelpMenu',   None, _('Help')),
             ('Docu', gtk.STOCK_INFO, _('Where is the Documentation?'), None, None, self.show_infodialog_cb),
@@ -253,11 +264,13 @@ class Window (windowing.MainWindow, layout.MainWindow):
             ('ViewMenu', None, _('View')),
             ('MenuishBarMenu', None, _('Toolbars')),
             ('ShowPopupMenu',    None, _('Popup Menu'), 'Menu', None, self.popupmenu_show_cb),
-            ('Fullscreen',   gtk.STOCK_FULLSCREEN, _('Fullscreen'), 'F11', None, self.fullscreen_cb),
+            ('Fullscreen',   gtk.STOCK_FULLSCREEN, None, 'F11', None, self.fullscreen_cb),
             ('ViewHelp',  gtk.STOCK_HELP, _('Help'), None, None, self.show_infodialog_cb),
             ]
         ag = self.action_group = gtk.ActionGroup('WindowActions')
+        self.app.add_action_group(ag)
         ag.add_actions(actions)
+        self.update_fullscreen_action()
 
         # Toggle actions
         toggle_actions = [
@@ -273,10 +286,12 @@ class Window (windowing.MainWindow, layout.MainWindow):
             ('BackgroundWindow', gtk.STOCK_PAGE_SETUP,
                     _('Background'), None, None, self.toggle_window_cb),
             ('BrushSelectionWindow', stock.TOOL_BRUSH,
-                    None, None, _("Toggle the Brush selector"),
+                    None, None,
+                    _("Edit and reorganise Brush Lists"),
                     self.toggle_window_cb),
             ('BrushSettingsWindow', gtk.STOCK_PROPERTIES,
-                    _('Brush Editor'), '<control>b', None,
+                    _('Brush Settings Editor'), '<control>b',
+                    _("Change Brush Settings in detail"),
                     self.toggle_window_cb),
             ('ColorSelectionWindow', stock.TOOL_COLOR_SELECTOR,
                     None, None, _("Toggle the Colour Triangle"),
@@ -340,25 +355,31 @@ class Window (windowing.MainWindow, layout.MainWindow):
         # Keyboard handling
         for action in self.action_group.list_actions():
             self.app.kbm.takeover_action(action)
-        self.app.ui_manager.insert_action_group(ag, -1)
 
     def init_stategroups(self):
         sg = stategroup.StateGroup()
         p2s = sg.create_popup_state
-        changer = p2s(colorselectionwindow.ColorChangerPopup(self.app))
+        changer_crossed_bowl = p2s(colorselectionwindow.ColorChangerCrossedBowlPopup(self.app))
+        changer_wash = p2s(colorselectionwindow.ColorChangerWashPopup(self.app))
         ring = p2s(colorselectionwindow.ColorRingPopup(self.app))
         hist = p2s(historypopup.HistoryPopup(self.app, self.app.doc.model))
         pick = self.colorpick_state = p2s(colorpicker.ColorPicker(self.app, self.app.doc.model))
 
         self.popup_states = {
-            'ColorChangerPopup': changer,
+            'ColorChangerCrossedBowlPopup': changer_crossed_bowl,
+            'ColorChangerWashPopup': changer_wash,
             'ColorRingPopup': ring,
             'ColorHistoryPopup': hist,
             'ColorPickerPopup': pick,
             }
-        changer.next_state = ring
-        ring.next_state = changer
-        changer.autoleave_timeout = None
+
+        # not sure how useful this is; we can't cycle at the moment
+        changer_crossed_bowl.next_state = ring
+        ring.next_state = changer_wash
+        changer_wash.next_state = ring
+
+        changer_wash.autoleave_timeout = None
+        changer_crossed_bowl.autoleave_timeout = None
         ring.autoleave_timeout = None
 
         pick.max_key_hit_duration = 0.0
@@ -379,26 +400,8 @@ class Window (windowing.MainWindow, layout.MainWindow):
         self.menubar = self.app.ui_manager.get_widget('/Menubar')
 
     def init_toolbar(self):
-        toolbarpath = os.path.join(self.app.datapath, 'gui/toolbar.xml')
-        toolbarbar_xml = open(toolbarpath).read()
-        self.app.ui_manager.add_ui_from_string(toolbarbar_xml)
-        self.toolbar1 = self.app.ui_manager.get_widget('/toolbar1')
-        self.toolbar1.set_style(gtk.TOOLBAR_ICONS)
-        self.toolbar1.set_border_width(0)
-        self.toolbar1.connect("style-set", self.on_toolbar1_style_set)
-        self.toolbar = gtk.HBox()
-        self.menu_button = FakeMenuButton(_("MyPaint"), self.popupmenu)
-        self.menu_button.set_border_width(0)
-        self.toolbar.pack_start(self.menu_button, False, False)
-        self.toolbar.pack_start(self.toolbar1, True, True)
-        self.menu_button.set_flags(gtk.CAN_DEFAULT)
-        self.set_default(self.menu_button)
-
-    def on_toolbar1_style_set(self, widget, oldstyle):
-        style = widget.style.copy()
-        self.menu_button.set_style(style)
-        style = widget.style.copy()
-        self.toolbar.set_style(style)
+        self.toolbar_manager = toolbar.ToolbarManager(self)
+        self.toolbar = self.toolbar_manager.toolbar1
 
     def _clone_menu(self, xml, name, owner=None):
         """
@@ -609,6 +612,16 @@ class Window (windowing.MainWindow, layout.MainWindow):
         state.activate(action)
 
 
+    def brush_chooser_popup_cb(self, action):
+        # It may be even nicer to do this as a real popup state with
+        # mouse-out to cancel. The Action is named accordingly. For now
+        # though a modal dialog will do as an implementation.
+        dialogs.change_current_brush_quick(self.app)
+
+    def color_details_dialog_cb(self, action):
+        dialogs.change_current_color_detailed(self.app)
+
+
     # User-toggleable UI pieces: things like toolbars, status bars, menu bars.
     # Saved between sessions.
 
@@ -664,9 +677,9 @@ class Window (windowing.MainWindow, layout.MainWindow):
         toolbar_visible = self.toolbar.get_property("visible")
         menubar_visible = self.menubar.get_property("visible")
         if toolbar_visible and menubar_visible:
-            self.menu_button.hide()
+            self.toolbar_manager.menu_button.hide()
         else:
-            self.menu_button.show_all()
+            self.toolbar_manager.menu_button.show_all()
 
 
     def on_menuishbar_radio_change(self, radioaction, current):
@@ -755,13 +768,25 @@ class Window (windowing.MainWindow, layout.MainWindow):
                 self.set_show_subwindows(True)
                 del self._restore_subwindows_on_unfullscreen
         self.update_menu_button()
+        self.update_fullscreen_action()
+
+    def update_fullscreen_action(self):
+        action = self.action_group.get_action("Fullscreen")
+        if self.is_fullscreen:
+            action.set_stock_id(gtk.STOCK_LEAVE_FULLSCREEN)
+            action.set_tooltip(_("Leave Fullscreen Mode"))
+            action.set_label(_("UnFullscreen"))
+        else:
+            action.set_stock_id(gtk.STOCK_FULLSCREEN)
+            action.set_tooltip(_("Enter Fullscreen Mode"))
+            action.set_label(_("Fullscreen"))
 
     def popupmenu_show_cb(self, action):
         self.show_popupmenu()
 
     def show_popupmenu(self, event=None):
         self.menubar.set_sensitive(False)   # excessive feedback?
-        self.menu_button.set_sensitive(False)
+        self.toolbar_manager.menu_button.set_sensitive(False)
         button = 1
         time = 0
         if event is not None:
@@ -783,7 +808,7 @@ class Window (windowing.MainWindow, layout.MainWindow):
         # the other. Makes it clear that the popups are the same thing as
         # the full menu, maybe.
         self.menubar.set_sensitive(True)
-        self.menu_button.set_sensitive(True)
+        self.toolbar_manager.menu_button.set_sensitive(True)
         self.popupmenu_last_active = self.popupmenu.get_active()
 
     # BEGIN -- Scratchpad menu options
@@ -889,6 +914,11 @@ class Window (windowing.MainWindow, layout.MainWindow):
         enabled = self.app.doc.model.frame_enabled
         self.app.doc.model.set_frame_enabled(not enabled)
 
+    def download_brush_pack_cb(self, *junk):
+        url = 'http://wiki.mypaint.info/index.php?title=Brush_Packages/redirect_mypaint_1.0_gui'
+        print 'URL:', url
+        webbrowser.open(url)
+
     def import_brush_pack_cb(self, *junk):
         format_id, filename = dialogs.open_dialog(_("Import brush package..."), self,
                                  [(_("MyPaint brush package (*.zip)"), "*.zip")])
@@ -932,6 +962,8 @@ class Window (windowing.MainWindow, layout.MainWindow):
             u'David Grundberg (%s)' % _('programming'),
             u"Krzysztof Pasek (%s)" % _('programming'),
             u"Ben O'Steen (%s)" % _('programming'),
+            u"Ferry Jérémie (%s)" % _('programming'),
+            u"しげっち 'sigetch' (%s)" % _('programming'),
             ])
         d.set_artists([
             u"Artis Rozentāls (%s)" % _('brushes'),
@@ -1006,106 +1038,3 @@ class Window (windowing.MainWindow, layout.MainWindow):
         self.app.message_dialog(text[action.get_name()])
 
 
-class FakeMenuButton(gtk.EventBox):
-    """Launches the popup menu when clicked.
-
-    One of these sits to the left of the real toolbar when the main menu bar is
-    hidden. In addition to providing access to a popup menu associated with the
-    main view, this is a little more compliant with Fitts's Law than a normal
-    `gtk.MenuBar`: when the window is fullscreened with only the "toolbar"
-    present the ``(0, 0)`` screen pixel hits this button. Support note: Compiz
-    edge bindings sometimes get in the way of this, so turn those off if you
-    want Fitts's compliance.
-    """
-
-    def __init__(self, text, menu):
-        gtk.EventBox.__init__(self)
-        self.menu = menu
-        self.label = gtk.Label(text)
-        self.label.set_padding(8, 0)
-
-        # Text settings
-        #self.label.set_angle(5)
-        attrs = pango.AttrList()
-        attrs.change(pango.AttrWeight(pango.WEIGHT_HEAVY, 0, -1))
-        self.label.set_attributes(attrs)
-
-        # Intercept mouse clicks and use them for activating the togglebutton
-        # even if they're in its border, or (0, 0). Fitts would approve.
-        invis = self.invis_window = gtk.EventBox()
-        invis.set_visible_window(False)
-        invis.set_above_child(True)
-        invis.connect("button-press-event", self.on_button_press)
-        invis.connect("enter-notify-event", self.on_enter)
-        invis.connect("leave-notify-event", self.on_leave)
-
-        # The underlying togglebutton can default and focus. Might as well make
-        # the Return key do something useful rather than invoking the 1st
-        # toolbar item.
-        self.togglebutton = gtk.ToggleButton()
-        self.togglebutton.add(self.label)
-        self.togglebutton.set_relief(gtk.RELIEF_HALF)
-        self.togglebutton.set_flags(gtk.CAN_FOCUS)
-        self.togglebutton.set_flags(gtk.CAN_DEFAULT)
-        self.togglebutton.connect("toggled", self.on_togglebutton_toggled)
-
-        invis.add(self.togglebutton)
-        self.add(invis)
-        for sig in "selection-done", "deactivate", "cancel":
-            menu.connect(sig, self.on_menu_dismiss)
-
-
-    def on_enter(self, widget, event):
-        # Not this set_state(). That one.
-        #self.togglebutton.set_state(gtk.STATE_PRELIGHT)
-        gtk.Widget.set_state(self.togglebutton, gtk.STATE_PRELIGHT)
-
-
-    def on_leave(self, widget, event):
-        #self.togglebutton.set_state(gtk.STATE_NORMAL)
-        gtk.Widget.set_state(self.togglebutton, gtk.STATE_NORMAL)
-
-
-    def on_button_press(self, widget, event):
-        # Post the menu. Menu operation is much more convincing if we call
-        # popup() with event details here rather than leaving it to the toggled
-        # handler.
-        pos_func = self._get_popup_menu_position
-        self.menu.popup(None, None, pos_func, event.button, event.time)
-        self.togglebutton.set_active(True)
-
-
-    def on_togglebutton_toggled(self, togglebutton):
-        # Post the menu from a keypress. Dismiss handler untoggles it.
-        if togglebutton.get_active():
-            if not self.menu.get_property("visible"):
-                pos_func = self._get_popup_menu_position
-                self.menu.popup(None, None, pos_func, 1, 0)
-
-
-    def on_menu_dismiss(self, *a, **kw):
-        # Reset the button state when the user's finished, and
-        # park focus back on the menu button.
-        self.set_state(gtk.STATE_NORMAL)
-        self.togglebutton.set_active(False)
-        self.togglebutton.grab_focus()
-
-
-    def _get_popup_menu_position(self, menu, *junk):
-        # Underneath the button, at the same x position.
-        x, y = self.window.get_origin()
-        y += self.allocation.height
-        return x, y, True
-
-
-    def set_style(self, style):
-        # Propagate style changes to all children as well. Since this button is
-        # stored on the toolbar, the main window makes it share a style with
-        # it. Looks prettier.
-        gtk.EventBox.set_style(self, style)
-        style = style.copy()
-        widget = self.togglebutton
-        widget.set_style(style)
-        style = style.copy()
-        widget = widget.get_child()
-        widget.set_style(style)