Skip to content

Commit

Permalink
Auto-generate mnemonics to activate tools (#300)
Browse files Browse the repository at this point in the history
  • Loading branch information
maoschanz committed Jul 16, 2021
1 parent 24fcf5b commit cbe6c6e
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 9 deletions.
1 change: 1 addition & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ drawing (1.0.0) unstable; urgency=low

* dynamically change the label of the "options" submenu in the menu-bar, to increase its discoverability
*
* enable tools with "alt+letter" mnemonics
* artificially limited framerate to avoid overloading the CPU (#162)
* toggle the menubar with ctrl+f2
*
Expand Down
14 changes: 7 additions & 7 deletions src/tools/abstract_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __init__(self, tool_id, label, icon_name, window, **kwargs):
# The tool's identity
self.id = tool_id
self.menu_id = 0
self.label = label
self.label = self.mnemolabel = label
self.icon_name = icon_name
# The options it supports
self.accept_selection = False
Expand All @@ -47,7 +47,6 @@ def __init__(self, tool_id, label, icon_name, window, **kwargs):
self.cursor_name = 'cell'
self._ongoing_operation = False
# Once everything is set, build the UI
self.build_row()
self.try_build_pane()

############################################################################
Expand Down Expand Up @@ -114,7 +113,7 @@ def adapt_to_window_size(self, available_width):
pass

def add_item_to_menu(self, tools_menu):
tools_menu.append(self.label, 'win.active_tool::' + self.id)
tools_menu.append(self.mnemolabel, 'win.active_tool::' + self.id)

def get_options_model(self):
"""Returns a Gio.MenuModel corresponding to the tool's options. It'll be
Expand Down Expand Up @@ -144,24 +143,25 @@ def build_row(self):
relief = Gtk.ReliefStyle.NONE, \
draw_indicator = False, \
valign = Gtk.Align.CENTER, \
tooltip_text = self.label \
tooltip_text = self.label, \
)

self.row.set_detailed_action_name('win.active_tool::' + self.id)
self.label_widget = Gtk.Label(label=self.label)
self._label_widget = Gtk.Label(use_underline=True, label=self.mnemolabel)
if self.window.gsettings.get_boolean('big-icons'):
size = Gtk.IconSize.LARGE_TOOLBAR
else:
size = Gtk.IconSize.SMALL_TOOLBAR
image = Gtk.Image().new_from_icon_name(self.icon_name, size)
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
box.add(image)
box.add(self.label_widget)
box.add(self._label_widget)
self.row.add(box)
self.row.show_all()
return self.row

def set_show_label(self, label_visible):
self.label_widget.set_visible(label_visible)
self._label_widget.set_visible(label_visible)
if label_visible:
self.row.get_children()[0].set_halign(Gtk.Align.START)
else:
Expand Down
6 changes: 5 additions & 1 deletion src/tools/classic_tools/tool_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class ToolExperiment(AbstractClassicTool):

def __init__(self, window, **kwargs):
super().__init__('experiment', _("Experiment"), 'applications-utilities-symbolic', window)
self.row.get_style_context().add_class('destructive-action')

# In order to draw pressure-sensitive lines, the path is collected as
# an array whose elements are dicts (keys are 'x', 'y', 'p'). An actual
Expand Down Expand Up @@ -57,6 +56,11 @@ def __init__(self, window, **kwargs):
self.add_tool_action_enum('experiment_operator', self._operator_label)
self.add_tool_action_enum('experiment_mode', self._selected_mode)

def build_row(self):
super().build_row()
self.row.get_style_context().add_class('destructive-action')
return self.row

def get_edition_status(self):
return "You're not supposed to use this tool (development only)."

Expand Down
57 changes: 56 additions & 1 deletion src/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ def _init_tools(self):
# self._load_tool('skew', ToolSkew, disabled_tools, dev)
self._load_tool('filters', ToolFilters, disabled_tools, dev)

self._add_auto_mnemonics()

# Side pane buttons for tools, and their menubar items if they don't
# exist yet (they're defined on the application level)
self._build_tool_rows()
Expand All @@ -220,6 +222,59 @@ def _init_tools(self):
# method, will be called later because it requires an active image,
# which doesn't exist yet at this point of the window init process.

def _add_auto_mnemonics(self):
# I don't want useful tools lacking a mnemonic accelerator because a
# useless one "stole" its letters, so the mnemonics are decided in the
# following order:
sorted_tools = [
'pencil',
'text',
'rect_select',
'crop',
'scale',
'rotate',
'shape',
'filters',
'line',
'highlight',
'arc',
'picker',
'brush',
'free_select',
'eraser',
'skew',
'paint',
'color_select',
'points',
'experiment'
]
for tool_id in self.tools:
if tool_id not in sorted_tools:
print("Warning: " + tool_id + "will not have a mnemonic")

underlined_chars = {}
for tool_id in sorted_tools:
if tool_id not in self.tools:
continue
letter_index = 0
while(letter_index >= 0):
if letter_index == len(self.tools[tool_id].label):
letter_index = -1
continue
ith_char = self.tools[tool_id].label[letter_index]
letter_index += 1

if ith_char.isalpha() \
and ith_char.upper() not in underlined_chars.values() \
and ith_char.lower() not in underlined_chars.values():
underlined_chars[tool_id] = ith_char
letter_index = -1

for tool_id in underlined_chars:
c = underlined_chars[tool_id]
new_label = self.tools[tool_id].label.replace(c, "_" + c, 1)
self.tools[tool_id].mnemolabel = new_label

def _enable_first_tool(self):
"""Near the end of the window initialisation process, this method is
called once to make sure all things related to the active tool, mostly
Expand Down Expand Up @@ -247,7 +302,7 @@ def _build_tool_rows(self):
"""Adds each tool's button to the side pane."""
group = None
for tool_id in self.tools:
row = self.tools[tool_id].row
row = self.tools[tool_id].build_row()
if group is None:
group = row
else:
Expand Down

0 comments on commit cbe6c6e

Please sign in to comment.