8000 Text box widget by HastingsGreer · Pull Request #5375 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Text box widget #5375

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

Closed
wants to merge 18 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e0440cc
Added a text entry widget, that allows usere to register to be notifi…
HastingsGreer Oct 27, 2015
5b06d3f
resolved merge conflict in CHANGELOG
HastingsGreer Jan 25, 2016
23c5a74
Added description of textbox widget and example
HastingsGreer Oct 31, 2015
1f37c22
Added a text box example: evaluates any string inputs as y(x).
HastingsGreer Oct 31, 2015
507b6a4
Whitespace adjustments for PEP8 compliance
HastingsGreer Oct 31, 2015
ff8afc3
Removed a newline that was accidentally commited
HastingsGreer Oct 31, 2015
f1df42f
removed w accidentally added to the first line
HastingsGreer Oct 31, 2015
606d4a3
fixed PEP8 formatting
HastingsGreer Oct 31, 2015
02b9ffd
Fixed formatting of textbox widget entry in whats_new.rst
HastingsGreer Oct 31, 2015
497452e
formatting changes for Pep8 compliance
HastingsGreer Nov 3, 2015
382057d
removed "time the" from end of document, added last commit by mistake
HastingsGreer Nov 3, 2015
06ab4ce
refactored "start typing" and "stop typing" into their own functions …
HastingsGreer Jan 20, 2016
9826a3c
fixed typos from last commit
HastingsGreer Jan 20, 2016
bf4bccd
made textbox lose focus when window is resized: this prevents cursor …
HastingsGreer Jan 20, 2016
954dfd0
added adjustable padding between label and text box
HastingsGreer Jan 20, 2016
b26ec58
removed trailing whitespace
HastingsGreer Jan 25, 2016
0025a26
enabled moving the cursor by clicking
HastingsGreer Feb 13, 2016
2734051
Document feature: caret can be moved by clicking
HastingsGreer Feb 26, 2016
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
formatting changes for Pep8 compliance
  • Loading branch information
HastingsGreer committed Jan 25, 2016
commit 497452eb890ab5cc1b6b0378e9db5405d1cf924e
159 changes: 85 additions & 74 deletions lib/matplotlib/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,14 +622,14 @@ def disconnect(self, cid):
except KeyError:
pass


class TextBox(AxesWidget):
"""
A GUI neutral text input box.

For the text box to remain responsive
you must keep a reference to it.
For the text box to remain responsive you must keep a reference to it.

The following attributes are accessible
The following attributes are accessible:

*ax*
The :class:`matplotlib.axes.Axes` the button renders into.
Expand All @@ -643,11 +643,13 @@ class TextBox(AxesWidget):
*hovercolor*
The color of the text box when hovering.

Call :meth:`on_text_change` to be updated whenever the text changes
Call :meth:`on_submit` to be updated whenever the user hits enter or leaves the text entry field
Call :meth:`on_text_change` to be updated whenever the text changes.

Call :meth:`on_submit` to be updated whenever the user hits enter or
leaves the text entry field.
"""

def __init__(self, ax, label, initial = '',
def __init__(self, ax, label, initial='',
color='.95', hovercolor='1'):
"""
Parameters
Expand All @@ -658,43 +660,48 @@ def __init__(self, ax, label, initial = '',

label : str
Label for this text box. Accepts string.

initial : str
Initial value in the text box

color : color
The color of the box

hovercolor : color
The color of the box when the mouse is over it
"""
AxesWidget.__init__(self, ax)
self.DIST_FROM_LEFT = .05

self.DIST_FROM_LEFT = .05

self.params_to_disable = []
for key in rcParams.keys():
for key in rcParams.keys():
if u'keymap' in key:
self.params_to_disable += [key]
self.params_to_disable += [key]

self.text = initial
self.label = ax.text(0.0,0.5, label,
self.label = ax.text(0.0, 0.5, label,
verticalalignment='center',
horizontalalignment='right',
transform=ax.transAxes)
self.text_disp = self._make_text_disp(self.text)

self.cnt = 0
self.change_observers = {}
self.submit_observers = {}

self.ax.set_xlim(0, 1) #If these lines are removed, the cursor won't appear
self.ax.set_ylim(0, 1) #the first time the box is clicked

self.cursor_index = 0;
self.cursor = self.ax.vlines(0, 0, 0) #because this is initialized, _render_cursor
self.cursor.set_visible(False) #can assume that cursor exists


# If these lines are removed, the cursor won't appear the first
# time the box is clicked:
self.ax.set_xlim(0, 1)
self.ax.set_ylim(0, 1)

self.cursor_index = 0

# Because this is initialized, _render_cursor
# can assume that cursor exists.
self.cursor = self.ax.vlines(0, 0, 0)
self.cursor.set_visible(False)

self.connect_event('button_press_event', self._click)
self.connect_event('button_release_event', self._release)
self.connect_event('motion_notify_event', self._motion)
Expand All @@ -707,105 +714,107 @@ def __init__(self, ax, label, initial = '',
self.hovercolor = hovercolor

self._lastcolor = color
self.capturekeystrokes = False

self.capturekeystrokes = False

def _make_text_disp(self, string):
return self.ax.text(self.DIST_FROM_LEFT, 0.5, string,
Copy link
Member

Choose a reason for hiding this comment

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

This spacing should be in display, not data coordinates. That will be tricky and may require the use of the inverse transform, but will result in spacing that doesn't change with the size of the figure.

verticalalignment='center',
horizontalalignment='left',
transform=self.ax.transAxes)
verticalalignment='center',
horizontalalignment='left',
transform=self.ax.transAxes)

def _rendercursor(self):
#this is a hack to figure out where the cursor should go.
#we draw the text up to where the cursor should go, measure
#save its dimensions, draw the real text, then put the cursor
#at the saved dimensions
# this is a hack to figure out where the cursor should go.
# we draw the text up to where the cursor should go, measure
# save its dimensions, draw the real text, then put the cursor
# at the saved dimensions

widthtext = self.text[:self.cursor_index]
no_text = False
if(widthtext == "" or widthtext == " " or widthtext == " "):
no_text = widthtext == ""
widthtext = ","
widthtext = ","

wt_disp = self._make_text_disp(widthtext)

self.ax.figure.canvas.draw()
bb = wt_disp.get_window_extent()
inv = self.ax.transData.inverted()
bb = inv.transform(bb)
wt_disp.set_visible(False)
if no_text:
bb[1, 0] = bb[0, 0]
#hack done
self.cursor.set_visible(False)
bb[1, 0] = bb[0, 0]
# hack done
self.cursor.set_visible(False)

self.cursor = self.ax.vlines(bb[1, 0], bb[0, 1], bb[1, 1])
self.ax.figure.canvas.draw()

def _notify_submit_observers(self):
for cid, func in six.iteritems(self.submit_observers):
func(self.text)

def _release(self, event):
if self.ignore(event):
return
if event.canvas.mouse_grabber != self.ax:
return
event.canvas.release_mouse(self.ax)

def _keypress(self, event):
if self.ignore(event):
return
if self.capturekeystrokes:
key = event.key

if(len(key) == 1):
self.text = (self.text[:self.cursor_index] + key +
self.text[self.cursor_index:])
self.cursor_index += 1
self.text = (self.text[:self.cursor_index] + key +
self.text[self.cursor_index:])
self.cursor_index += 1
elif key == "right":
if self.cursor_index != len(self.text):
self.cursor_index += 1
if self.cursor_index != len(self.text):
self.cursor_index += 1
elif key == "left":
if self.cursor_index != 0:
self.cursor_index -= 1
if self.cursor_index != 0:
self.cursor_index -= 1
elif key == "home":
self.cursor_index = 0
self.cursor_index = 0
elif key == "end":
self.cursor_index = len(self.text)
self.cursor_index = len(self.text)
elif(key == "backspace"):
if self.cursor_index != 0:
self.text = (self.text[:self.cursor_index - 1] +
self.text[self.cursor_index:])
self.text = (self.text[:self.cursor_index - 1] +
self.text[self.cursor_index:])
self.cursor_index -= 1
elif(key == "delete"):
if self.cursor_index != len(self.text):
self.text = (self.text[:self.cursor_index] +
self.text[self.cursor_index + 1:])
self.text = (self.text[:self.cursor_index] +
self.text[self.cursor_index + 1:])

self.text_disp.remove()
self.text_disp = self._make_text_disp(self.text)
self._rendercursor()
for cid, func in six.iteritems(self.change_observers):
func(self.text)
if key == "enter":
self._notify_submit_observers()
self._notify_submit_observers()

def _click(self, event):
if self.ignore(event):
return
if event.inaxes != self.ax:
notifysubmit = False
#because _notify_submit_users might throw an error in the
#user's code, we only want to call it once we've already done
#our cleanup.
notifysubmit = False
# because _notify_submit_users might throw an error in the
# user's code, we only want to call it once we've already done
# our cleanup.
if self.capturekeystrokes:
for key in self.params_to_disable:
for key in self.params_to_disable:
rcParams[key] = self.reset_params[key]
notifysubmit = True
notifysubmit = True
self.capturekeystrokes = False
self.cursor.set_visible(False)
self.ax.figure.canvas.draw()

if notifysubmit:
self._notify_submit_observers()
return
Expand Down Expand Up @@ -837,33 +846,35 @@ def _motion(self, event):

def on_text_change(self, func):
"""
When the text changes, call this *func* with event
When the text changes, call this *func* with event.

A connection id is returned which can be used to disconnect
A connection id is returned which can be used to disconnect.
"""
cid = self.cnt
self.change_observers[cid] = func
self.cnt += 1
return cid

def on_submit(self, func):
"""
When the user hits enter or leaves the submision box, call this *func* with event
When the user hits enter or leaves the submision box, call this
*func* with event.

A connection id is returned which can be used to disconnect
A connection id is returned which can be used to disconnect.
"""
cid = self.cnt
self.submit_observers[cid] = func
self.cnt += 1
return cid

def disconnect(self, cid):
"""remove the observer with connection id *cid*"""
try:
del self.observers[cid]
except KeyError:
pass


class RadioButtons(AxesWidget):
"""
A GUI neutral radio button.
Expand Down Expand Up @@ -2512,4 +2523,4 @@ def onmove(self, event):
self.ax.draw_artist(self.line)
self.canvas.blit(self.ax.bbox)
else:
self.canvas.draw_idle()
self.canvas.draw_idle()time the
0