-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
MEP22: Navigation by events #3652
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
8cceed4
3118a5a
b4d5fcf
1e8af47
622cb95
d1a9de4
3f89d52
4f3c10b
6065daa
f6a2f19
05db3b6
c08fe56
b207a72
9266447
a53419a
704c717
5056729
e6a4e1e
8942c47
022de6f
2c9a195
cafe668
224f745
94c711e
67257e7
ffa65d6
6739ee0
d18206f
34a52c8
c2da483
44a9b0e
a2ed47f
0665890
411e6e2
d484ebd
75bf97b
6cc040b
0ff5997
af6734f
78513d2
377ff54
7dbbf58
dd66b57
67a414f
e415d8d
1213086
ba61dec
9f2ee2b
9da2b13
110253f
e2804ea
9a64b7e
64f947f
e8cd5d5
4bbcf4e
73a2661
1b83628
e4edd23
d4ac2fb
a7640ef
48a6971
8dafe09
a0695d0
328b169
aac4744
f09b9ef
def3a52
9ee7e25
5eae4e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ class allows to: | |
matplotlib.rcParams['toolbar'] = 'navigation' | ||
import matplotlib.pyplot as plt | ||
from matplotlib.backend_tools import ToolBase | ||
from gi.repository import Gtk, Gdk | ||
|
||
|
||
class ListTools(ToolBase): | ||
|
@@ -36,10 +37,10 @@ def trigger(self, *args, **kwargs): | |
keys)) | ||
print('_' * 80) | ||
print("Active Toggle tools") | ||
print("{0:12} {1:45}").format("Group", "Active") | ||
print("{0:12} {1:45}".format("Group", "Active")) | ||
print('-' * 80) | ||
for group, active in self.navigation.active_toggle.items(): | ||
print("{0:12} {1:45}").format(group, active) | ||
print("{0:12} {1:45}".format(group, active)) | ||
|
||
|
||
# ref: at https://github.com/matplotlib/matplotlib/issues/1987 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, should be a class docstring |
||
|
@@ -49,7 +50,6 @@ class CopyToolGTK3(ToolBase): | |
description = 'Copy canvas' | ||
|
||
def trigger(self, *args, **kwargs): | ||
from gi.repository import Gtk, Gdk | ||
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) | ||
window = self.figure.canvas.get_window() | ||
x, y, width, height = window.get_geometry() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3244,7 +3244,8 @@ def __init__(self, name, sender, tool, canvasevent=None, data=None): | |
|
||
|
||
class NavigationMessageEvent(object): | ||
"""Event carrying messages from navigation | ||
""" | ||
Event carrying messages from navigation | ||
|
||
Messages usually get displayed to the user by the toolbar | ||
""" | ||
|
@@ -3255,7 +3256,8 @@ def __init__(self, name, sender, message): | |
|
||
|
||
class NavigationBase(object): | ||
"""Helper class that groups all the user interactions for a FigureManager | ||
""" | ||
Helper class that groups all the user interactions for a FigureManager | ||
|
||
Attributes | ||
---------- | ||
|
@@ -3281,7 +3283,8 @@ def __init__(self, canvas): | |
self.messagelock = widgets.LockDraw() | ||
|
||
def nav_connect(self, s, func): | ||
"""Connect event with string *s* to *func*. | ||
""" | ||
Connect event with string *s* to *func*. | ||
|
||
Parameters | ||
----------- | ||
|
@@ -3306,7 +3309,8 @@ def func(event) | |
return self._callbacks.connect(s, func) | ||
|
||
def nav_disconnect(self, cid): | ||
"""Disconnect callback id cid | ||
""" | ||
Disconnect callback id cid | ||
|
||
Example usage:: | ||
|
||
|
@@ -3317,7 +3321,7 @@ def nav_disconnect(self, cid): | |
return self._callbacks.disconnect(cid) | ||
|
||
def message_event(self, message, sender=None): | ||
""" Emit a tool_message_event event""" | ||
""" Emit a `NavigationMessageEvent`""" | ||
if sender is None: | ||
sender = self | ||
|
||
|
@@ -3327,15 +3331,17 @@ def message_event(self, message, sender=None): | |
|
||
@property | ||
def active_toggle(self): | ||
"""Toggled Tool | ||
""" | ||
Toggled Tool | ||
|
||
**dict** : Currently toggled tools | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. numpy docstring please. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually, does numpy doc play nice with properties? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't need the |
||
""" | ||
|
||
return self._toggled | ||
|
||
def get_tool_keymap(self, name): | ||
"""Get the keymap associated with the specified tool | ||
""" | ||
Get the keymap associated with the specified tool | ||
|
||
Parameters | ||
---------- | ||
|
@@ -3355,7 +3361,8 @@ def _remove_keys(self, name): | |
del self._keys[k] | ||
|
||
def set_tool_keymap(self, name, *keys): | ||
"""Set the keymap to associate with the specified tool | ||
""" | ||
Set the keymap to associate with the specified tool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you clarify this a bit. This is setting a property of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think of renaming to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about It might also be worth adding a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rename done, not sure about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this done and not pushed? I am not seeing the code change.... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am finishing all the current comments and push the commit, give me 5 😉 |
||
|
||
Parameters | ||
---------- | ||
|
@@ -3365,7 +3372,7 @@ def set_tool_keymap(self, name, *keys): | |
""" | ||
|
||
if name not in self._tools: | ||
raise AttributeError('%s not in Tools' % name) | ||
raise KeyError('%s not in Tools' % name) | ||
|
||
self._remove_keys(name) | ||
|
||
|
@@ -3377,7 +3384,8 @@ def set_tool_keymap(self, name, *keys): | |
self._keys[k] = name | ||
|
||
def remove_tool(self, name): | ||
"""Remove tool from `Navigation` | ||
""" | ||
Remove tool from `Navigation` | ||
|
||
Parameters | ||
---------- | ||
|
@@ -3401,7 +3409,8 @@ def remove_tool(self, name): | |
del self._tools[name] | ||
|
||
def add_tools(self, tools): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How strongly do you feel about keeping both the singular and plural versions of this? The similarity (leading to many typos) and the difference in signature/what they can do is going to be confusing. If this function stays I think it needs to be able to pass args/kwargs through to the constructors. Is there any terrifying input parsing we could use to mush this into one function? I am not seeing a way quickly... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tacaswell, me and @fariza had a discussion on args/kwargs etcetrra over in fariza#11 where I introduced them. I would have thought the difference in signature would solve the typos problem, I mean if you make a typo, you will get a python error telling you you passed the wrong number of arguments to the function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can think of renaming the methods (suggestions any one?), but playing magic with arguments is 👎 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great, sold on 👎 for args magic (we have it else where where I do not like it, but supposedly users like that sort of thing) What is the use case for bulk adding tools? Writing this loop in user code does not strike me as super onerous. My worry with the typo is getting an exception about args being wrong (which leads you to check what you are passing in) rather than an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is more for backend implementation. It was done automatically at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ooh, brain wave, how about: for tool in six.iteritems(tools):
self.add_tool(*tool) Or get rid of it altogether, I think it has changed a lot (becoming a lot simpler), especially since we split the adding of tools to the toolbar out and into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @OceanWolf where do you suggest to add that loop? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 On putting this helper function as a module-level function. Breaks the OO abstraction a bit, but it keeps the base objects simpler. @OceanWolf That would unpack as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I like that too, brain just sluggish and getting distracted by quite a few conversations. I don't mind, just so long as no core-logic changes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
""" Add multiple tools to `NavigationBase` | ||
""" | ||
Add multiple tools to `NavigationBase` | ||
|
||
Parameters | ||
---------- | ||
|
@@ -3414,7 +3423,8 @@ def add_tools(self, tools): | |
self.add_tool(name, tool) | ||
|
||
def add_tool(self, name, tool, *args, **kwargs): | ||
"""Add tool to `NavigationBase` | ||
""" | ||
Add tool to `NavigationBase` | ||
|
||
Add a tool to the tools controlled by Navigation | ||
|
||
|
@@ -3440,11 +3450,10 @@ def add_tool(self, name, tool, *args, **kwargs): | |
|
||
tool_cls = self._get_cls_to_instantiate(tool) | ||
if tool_cls is False: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably should do a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I don't see the pep8 error here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be Wouldn't be simpler to just have I suspect @WeatherGod also has a pyflake/pylint turned on. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also, I am reading and commenting top-down. Sorry if some of these seem dumb in light of code I have not read yet. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done @tacaswell change, but still not see the pep8 error There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Different versions of pep8? I find myself curious to learn about this as Travis doesn't complain. |
||
warnings.warn('Impossible to find class for %s' % str(tool)) | ||
return | ||
raise ValueError('Impossible to find class for %s' % str(tool)) | ||
|
||
if name in self._tools: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be done first in this function? Do we want to check to make sure that they are the same type? Again, why warn rather than raise? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used warn because i don't think that adding twice the same tool represents a major fault and your program will keep working as expected (you already have the tool) |
||
warnings.warn('A tool_cls with the same name already exist, ' | ||
warnings.warn('A "Tool class" with the same name already exists, ' | ||
'not added') | ||
return self._tools[name] | ||
|
||
|
@@ -3454,7 +3463,7 @@ def add_tool(self, name, tool, *args, **kwargs): | |
self.set_tool_keymap(name, tool_cls.keymap) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The one who makes the sorting (by keymap) of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh? per-instance key binding happens, this just sets the default keymap. @fariza I think you should rename There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't quite follow this yet.. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @OceanWolf agreed and done There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tacaswell |
||
|
||
# For toggle tools init the radio_group in self._toggled | ||
if getattr(tool_cls, 'toggled', False) is not False: | ||
if isinstance(self._tools[name], tools.ToolToggleBase): | ||
# None group is not mutually exclusive, a set is used to keep track | ||
# of all toggled tools in this group | ||
if tool_cls.radio_group is None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, ask the instance object, not the class? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. class foo(object):
bar = 5
def __init__(self):
self.baz = 7
A = foo()
B = foo()
A.bar = 'good morning!'
print()
print("A.bar: ", A.bar)
print("B.bar: ", B.bar)
print("foo.bar: ", foo.bar) gives
so by looking at the instance attribute, if it has not been set, it falls back to the class level attribute, but if the instance attribute is set (by any means) (ex a tool that takes a radio group as part of its There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, seems fair |
||
|
@@ -3471,8 +3480,10 @@ def _tool_added_event(self, tool): | |
self._callbacks.process(s, event) | ||
|
||
def _handle_toggle(self, tool, sender, canvasevent, data): | ||
# Toggle tools, need to untoggle prior to using other Toggle tool | ||
# Called from tool_trigger_event | ||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you put docstrings on these with the expected types? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
Toggle tools, need to untoggle prior to using other Toggle tool | ||
Called from tool_trigger_event | ||
""" | ||
|
||
radio_group = tool.radio_group | ||
# radio_group None is not mutually exclusive | ||
|
@@ -3522,7 +3533,8 @@ def _get_cls_to_instantiate(self, callback_class): | |
|
||
def tool_trigger_event(self, name, sender=None, canvasevent=None, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This name is a bit too ambiguous, can it be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree, what do you think of just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 to 'trigger_tool' There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
data=None): | ||
"""Trigger a tool and emit the tool-trigger-[name] event | ||
""" | ||
Trigger a tool and emit the tool_trigger_[name] event | ||
|
||
Parameters | ||
---------- | ||
|
@@ -3549,7 +3561,8 @@ def tool_trigger_event(self, name, sender=None, canvasevent=None, | |
self._callbacks.process(s, event) | ||
|
||
def _trigger_tool(self, name, sender=None, canvasevent=None, data=None): | ||
"""Trigger on a tool | ||
""" | ||
Trigger on a tool | ||
|
||
Method to actually trigger the tool | ||
""" | ||
|
@@ -3578,7 +3591,8 @@ def tools(self): | |
return self._tools | ||
|
||
def get_tool(self, name, warn=True): | ||
"""Return the tool object, also accepts the actual tool for convenience | ||
""" | ||
Return the tool object, also accepts the actual tool for convenience | ||
|
||
Parameters | ||
----------- | ||
|
@@ -3597,7 +3611,8 @@ def get_tool(self, name, warn=True): | |
|
||
|
||
class ToolContainerBase(object): | ||
"""Base class for all tool containers, e.g. toolbars. | ||
""" | ||
Base class for all tool containers, e.g. toolbars. | ||
|
||
Attributes | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't lined up with the underscores below There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
---------- | ||
|
@@ -3611,14 +3626,16 @@ def __init__(self, navigation): | |
self._remove_tool_cbk) | ||
|
||
def _tool_toggled_cbk(self, event): | ||
"""Captures the 'tool-trigger-toolname | ||
""" | ||
Captures the 'tool_trigger_[name]' | ||
|
||
This only gets used for toggled tools | ||
""" | ||
self.toggle_toolitem(event.tool.name, event.tool.toggled) | ||
|
||
def add_tools(self, tools): | ||
""" Add multiple tools to the container. | ||
""" | ||
Add multiple tools to the container. | ||
|
||
Parameters | ||
---------- | ||
|
@@ -3634,7 +3651,8 @@ def add_tools(self, tools): | |
self.add_tool(tool, group, position) | ||
|
||
def add_tool(self, tool, group, position=-1): | ||
"""Adds a tool to this container | ||
""" | ||
Adds a tool to this container | ||
|
||
Parameters | ||
---------- | ||
|
@@ -3670,7 +3688,8 @@ def _get_image_filename(self, image): | |
return fname | ||
|
||
def trigger_tool(self, name): | ||
"""Trigger the tool | ||
""" | ||
Trigger the tool | ||
|
||
Parameters | ||
---------- | ||
|
@@ -3681,7 +3700,8 @@ def trigger_tool(self, name): | |
self.navigation.tool_trigger_event(name, sender=self) | ||
|
||
def add_toolitem(self, name, group, position, image, description, toggle): | ||
"""Add a toolitem to the container | ||
""" | ||
Add a toolitem to the container | ||
|
||
This method must get implemented per backend | ||
|
||
|
@@ -3711,7 +3731,8 @@ def add_toolitem(self, name, group, position, image, description, toggle): | |
raise NotImplementedError | ||
|
||
def toggle_toolitem(self, name, toggled): | ||
"""Toggle the toolitem without firing event | ||
""" | ||
Toggle the toolitem without firing event | ||
|
||
Parameters | ||
---------- | ||
|
@@ -3723,7 +3744,8 @@ def toggle_toolitem(self, name, toggled): | |
raise NotImplementedError | ||
|
||
def remove_toolitem(self, name): | ||
"""Remove a toolitem from the `ToolContainer` | ||
""" | ||
Remove a toolitem from the `ToolContainer` | ||
|
||
This method must get implemented per backend | ||
|
||
|
@@ -3750,7 +3772,8 @@ def _message_cbk(self, event): | |
self.set_message(event.message) | ||
|
||
def set_message(self, s): | ||
"""Display a message on toolbar or in status bar | ||
""" | ||
Display a message on toolbar or in status bar | ||
|
||
Parameters | ||
---------- | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these are examples, I would suggest getting rid of extraneous commented out code, and also highlight important lines of code such as this one. For example, is it important that it gets called before importing pyplot? What is it for? Perhaps a short docstring at the top of this example would help explain its purpose/goal that it is demonstrating?