Skip to content

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

Merged
merged 69 commits into from
Apr 9, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
8cceed4
navigation and toolbar coexistence
fariza Jan 23, 2014
3118a5a
mod keypress in figuremanager
fariza Jan 23, 2014
b4d5fcf
helper methods in toolbar and navigation
fariza Jan 24, 2014
1e8af47
Adding doc to base methods
fariza Jan 24, 2014
622cb95
property for active_toggle
fariza Jan 26, 2014
d1a9de4
simulate click
fariza Jan 27, 2014
3f89d52
activate renamed to trigger
fariza Jan 28, 2014
4f3c10b
toggle tools using enable/disable from its trigger method
fariza Jan 29, 2014
6065daa
simplifying _handle_toggle
fariza Jan 29, 2014
f6a2f19
reducing number of locks
fariza Jan 29, 2014
05db3b6
changing toggle and persistent attributes for issubclass
fariza Feb 4, 2014
c08fe56
bug in combined key press
fariza Feb 4, 2014
b207a72
untoggle zoom and pan from keypress while toggled
fariza Feb 4, 2014
9266447
classmethods for default tools modification
fariza Feb 6, 2014
a53419a
adding zaxis and some pep8
fariza May 1, 2014
704c717
removing legacy method dynamic update
fariza May 6, 2014
5056729
tk backend
fariza May 6, 2014
e6a4e1e
example working with Tk
fariza May 6, 2014
8942c47
duplicate code in keymap tool initialization
fariza Jul 24, 2014
022de6f
grammar corrections
fariza Jul 24, 2014
2c9a195
moving views and positions to tools
fariza Jul 24, 2014
cafe668
The views positions mixin automatically adds the clear as axobserver
fariza Jul 25, 2014
224f745
bug when navigation was not defined
fariza Jul 25, 2014
94c711e
Small refactor so that we first initiate the Navigation (ToolManager)…
OceanWolf Jul 28, 2014
67257e7
Moved default_tool initilisation to FigureManagerBase and cleaned.
OceanWolf Jul 29, 2014
ffa65d6
Temporary fix to backends
OceanWolf Jul 29, 2014
6739ee0
removing persistent tools
fariza Sep 3, 2014
d18206f
removing unregister
fariza Sep 4, 2014
34a52c8
change cursor inmediately after toggle
fariza Sep 5, 2014
c2da483
removing intoolbar
fariza Oct 15, 2014
44a9b0e
events working
fariza Oct 16, 2014
a2ed47f
using pydispatch
fariza Oct 17, 2014
0665890
using navigation as signal handler
fariza Oct 20, 2014
411e6e2
removing view positions singleton
fariza Oct 20, 2014
d484ebd
moving set_cursor completely out of navigation
fariza Oct 27, 2014
75bf97b
removing unused event class
fariza Nov 10, 2014
6cc040b
underscore in tool_trigger-xxx
fariza Nov 10, 2014
0ff5997
adding radio_group for toggle tools
fariza Nov 14, 2014
af6734f
scroll to zoom in zoom/pan tools
fariza Nov 28, 2014
78513d2
remove ToolAddedEvent incorporating the functionality into toolevent
fariza Dec 5, 2014
377ff54
eliminating repeated loop
fariza Jan 5, 2015
7dbbf58
replace draw by draw_idle in tools
fariza Jan 21, 2015
dd66b57
rename mpl_connect
fariza Jan 21, 2015
67a414f
cleaning navigation and toolbar dependencies
fariza Feb 4, 2015
e415d8d
Made NavigationBase.get_tool() more useful.
OceanWolf Feb 11, 2015
1213086
Refactored Toolbar out of NavigationBase
OceanWolf Feb 12, 2015
ba61dec
Some short cuts for adding tools
OceanWolf Feb 16, 2015
9f2ee2b
Lots of fixes
OceanWolf Feb 18, 2015
9da2b13
Rename ToolbarBase -> ToolContainerBase
OceanWolf Feb 18, 2015
110253f
Statusbar
OceanWolf Feb 20, 2015
e2804ea
tool group position
fariza Feb 26, 2015
9a64b7e
docstrings and small corrections by WeatherGod
fariza Mar 23, 2015
64f947f
tkbackend updated
fariza Mar 31, 2015
e8cd5d5
tacaswell comments aprl 1
fariza Apr 1, 2015
4bbcf4e
renaming tool_trigger_event
fariza Apr 1, 2015
73a2661
add_tools moved out of base classes
fariza Apr 1, 2015
1b83628
figure.setter in tools
fariza Apr 1, 2015
e4edd23
rename tools to default_tools to avoid confusion
fariza Apr 1, 2015
d4ac2fb
docstring helper add_tools methods
fariza Apr 1, 2015
a7640ef
rename navigation to toolmanager
fariza Apr 2, 2015
48a6971
tkagg updated for toolmanager and tool groups
fariza Apr 2, 2015
8dafe09
doc and minor code organization
fariza Apr 2, 2015
a0695d0
whats new
fariza Apr 3, 2015
328b169
missing object from class declaration
fariza Apr 3, 2015
aac4744
remove comments and docstrings
fariza Apr 3, 2015
f09b9ef
import with original name backend_tools
fariza Apr 3, 2015
def3a52
rename 2 -> to, example without gtk only code
fariza Apr 7, 2015
9ee7e25
zoom pan buttons order
fariza Apr 7, 2015
5eae4e1
matplotlib.rcParams['toolbar'] == 'None' starts toolmanager but not t…
fariza Apr 7, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
docstrings and small corrections by WeatherGod
  • Loading branch information
fariza committed Apr 7, 2015
commit 9a64b7eaed8cf1210e7759bef974878c2044fc44
6 changes: 3 additions & 3 deletions examples/user_interfaces/navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class allows to:
matplotlib.rcParams['toolbar'] = 'navigation'
Copy link
Member

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?

import matplotlib.pyplot as plt
from matplotlib.backend_tools import ToolBase
from gi.repository import Gtk, Gdk


class ListTools(ToolBase):
Expand All @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, should be a class docstring

Expand All @@ -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()
Expand Down
83 changes: 53 additions & 30 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""
Expand All @@ -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
----------
Expand All @@ -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
-----------
Expand All @@ -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::

Expand All @@ -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

Expand All @@ -3327,15 +3331,17 @@ def message_event(self, message, sender=None):

@property
def active_toggle(self):
"""Toggled Tool
"""
Toggled Tool

**dict** : Currently toggled tools
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstring is wrong nm, I was confused

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

numpy docstring please.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, does numpy doc play nice with properties?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need the **, numpydoc should take care of the markup on the way out to html

"""

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
----------
Expand All @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify this a bit. This is setting a property of NavigationBase to trigger the tool on a key stroke. This docstring and function name make it sound like this is modifying the Tool object in some way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of renaming to set_keymap?, we don't have keymaps for anything else than tools.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about update_keymap? 'set' makes me think it is being replaced. As this is a Navigation level function I think that is the correct sematics (even though you are replacing the keys for the given tool).

It might also be worth adding a append kwarg to skip removing all of the existing keys for the given tool.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename done, not sure about append

Copy link
Member

Choose a reason for hiding this comment

The 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....

Copy link
Member Author

Choose a reason for hiding this comment

The 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
----------
Expand All @@ -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)

Expand All @@ -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
----------
Expand All @@ -3401,7 +3409,8 @@ def remove_tool(self, name):
del self._tools[name]

def add_tools(self, tools):
Copy link
Member

Choose a reason for hiding this comment

The 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...

Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The 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 👎

Copy link
Member

Choose a reason for hiding this comment

The 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 AttributeError (which leads you to check your spelling).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is more for backend implementation. It was done automatically at __init__ but @OceanWolf talked me out of that

Copy link
Member

Choose a reason for hiding this comment

The 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 ToolContainer.addTool as @fariza mentions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OceanWolf where do you suggest to add that loop?
Don't you like the helper functions in backend_tools?

Copy link
Member

Choose a reason for hiding this comment

The 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 self.add_tool(tool_name, value_in_tools_dict) which does not get you the next level of unpacking you need to pass to add_tool.

Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

""" Add multiple tools to `NavigationBase`
"""
Add multiple tools to `NavigationBase`

Parameters
----------
Expand All @@ -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

Expand All @@ -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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably should do a # noqa here to keep pep8 from complaining. Might also need a comment explaining why to keep future devs from "fixing" this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't see the pep8 error here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be if not tool_cls ?

Wouldn't be simpler to just have self._get_cls_to_instantiate raise if it fails? If you want to do something else in that case then just try...execpt and if you want to die (which I am assuming is the default case) you don't have to do anything.

I suspect @WeatherGod also has a pyflake/pylint turned on.

Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done @tacaswell change, but still not see the pep8 error

Copy link
Member

Choose a reason for hiding this comment

The 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:
Copy link
Member

Choose a reason for hiding this comment

The 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?

Copy link
Member Author

Choose a reason for hiding this comment

The 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]

Expand All @@ -3454,7 +3463,7 @@ def add_tool(self, name, tool, *args, **kwargs):
self.set_tool_keymap(name, tool_cls.keymap)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be self._tools[name].keymap ? Might as well allow for per-instance key binding.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one who makes the sorting (by keymap) of the keypress events is NavigationBase.
It is easier to handleNavigationBase._keys dictionnary than looping throught all the tools finding their keymaps when an event occurs.
What we can do, if you insist in per-instance key binding, is to modify set_tool_keymap to set the tool keymap attribute at the same time.

Copy link
Member

Choose a reason for hiding this comment

The 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 ToolBase.keymap to ToolBase.default_keymap as I think that would make it a lot clearer!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite follow this yet..

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OceanWolf agreed and done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tacaswell set_tool_keymap(name, keymap) does per-instance key binding, it sets the keymap of the instance identified by name to the specified keymap. Here it takes the default keymap (a class level property) and binds it to the instance. Does that make it clearer for you?


# 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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, ask the instance object, not the class?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The radio_group is a class attribute, I don't think there is any difference if we access it from the class or from the object, is there?

Copy link
Member

Choose a reason for hiding this comment

The 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

A.bar:  good morning!
B.bar:  5
foo.bar:  5

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 __init__ which has the use-case of building a bunch of radio buttons to show one line each from several collections of lines) this this code will work as expected and will do no harm to the existing code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, seems fair

Expand All @@ -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
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put docstrings on these with the expected types?

Copy link
Member Author

Choose a reason for hiding this comment

The 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
Expand Down Expand Up @@ -3522,7 +3533,8 @@ def _get_cls_to_instantiate(self, callback_class):

def tool_trigger_event(self, name, sender=None, canvasevent=None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is a bit too ambiguous, can it be process_tool_trigger or emit_tool_trigger or something like that? (I don't have my head around the code enough to have a good idea yet, but I don't like this name)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, what do you think of just trigger_tool? it does both, emit the event and trigger the tool

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 to 'trigger_tool'

Copy link
Member Author

Choose a reason for hiding this comment

The 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
----------
Expand All @@ -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
"""
Expand Down Expand Up @@ -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
-----------
Expand All @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't lined up with the underscores below

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

----------
Expand All @@ -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
----------
Expand All @@ -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
----------
Expand Down Expand Up @@ -3670,7 +3688,8 @@ def _get_image_filename(self, image):
return fname

def trigger_tool(self, name):
"""Trigger the tool
"""
Trigger the tool

Parameters
----------
Expand All @@ -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

Expand Down Expand Up @@ -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
----------
Expand All @@ -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

Expand All @@ -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
----------
Expand Down
Loading