You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
909 lines
28 KiB
Python
909 lines
28 KiB
Python
# /usr/bin/env python
|
|
'''
|
|
Module FIG
|
|
------------
|
|
Module for manipulating windows/figures created using
|
|
pylab or enthought.mayavi.mlab on the windows platform.
|
|
|
|
Figure manipulation involves
|
|
maximization, minimization, hiding, closing, stacking or tiling.
|
|
|
|
It is assumed that the figures are uniquely numbered in the following way:
|
|
Figure 1
|
|
Figure 2
|
|
....
|
|
or
|
|
TVTK scene 1
|
|
TVTK scene 2
|
|
TVTK scene 3
|
|
...
|
|
|
|
Example
|
|
-------
|
|
>>> import pylab as p
|
|
>>> import wafo.fig as fig
|
|
>>> for ix in range(6):
|
|
... f = p.figure(ix)
|
|
>>> fig.stack('all')
|
|
>>> fig.stack(1,2)
|
|
>>> fig.hide(1)
|
|
>>> fig.restore(1)
|
|
>>> fig.tile()
|
|
>>> fig.pile()
|
|
>>> fig.maximize(4)
|
|
>>> fig.close('all')
|
|
'''
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
# import win32api
|
|
import win32gui
|
|
import win32con
|
|
import wx
|
|
import numpy
|
|
|
|
from win32gui import (EnumWindows, MoveWindow, GetWindowRect, FindWindow,
|
|
ShowWindow, BringWindowToTop)
|
|
|
|
__all__ = ['close', 'cycle', 'hide', 'keep', 'maximize', 'minimize', 'pile',
|
|
'restore', 'stack', 'tile', 'find_all_figure_numbers', 'set_size']
|
|
|
|
# Figure format strings to recognize in window title
|
|
FIGURE_TITLE_FORMATS = ('Figure', 'TVTK Scene', 'Chaco Plot Window: Figure')
|
|
_SCREENSIZE = None
|
|
|
|
|
|
class CycleDialog(wx.Dialog):
|
|
|
|
def _get_buttons(self):
|
|
hbox = wx.BoxSizer(wx.HORIZONTAL)
|
|
buttons = ['Forward', 'Back', 'Cancel']
|
|
callbacks = [self.on_forward, self.on_backward, self.on_cancel]
|
|
for button, callback in zip(buttons, callbacks):
|
|
button = wx.Button(self, -1, button, size=(70, 30))
|
|
self.Bind(wx.EVT_BUTTON, callback, button)
|
|
hbox.Add(button, 1, wx.ALIGN_CENTER)
|
|
return hbox
|
|
|
|
def _get_message(self):
|
|
label = ('Press back or forward to display previous or next figure(s),'
|
|
' respectively. Press cancel to quit.')
|
|
message = wx.StaticText(self, label=label, size=(240, 25))
|
|
return message
|
|
|
|
def __init__(self, parent, interval=None, title='Cycle dialog'):
|
|
super(CycleDialog, self).__init__(parent, title=title, size=(260, 130))
|
|
if isinstance(interval, (float, int)):
|
|
self.interval_milli_sec = interval * 1000
|
|
else:
|
|
self.interval_milli_sec = 30
|
|
|
|
self.timer = wx.Timer(self)
|
|
self.Bind(wx.EVT_TIMER, self.on_forward, self.timer)
|
|
|
|
vbox = wx.BoxSizer(wx.VERTICAL)
|
|
vbox.Add(self._get_message(), 0, wx.ALIGN_CENTER | wx.TOP, 20)
|
|
vbox.Add(self._get_buttons(), 1, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
|
|
self.SetSizer(vbox)
|
|
|
|
def ShowModal(self, *args, **kwargs):
|
|
self.timer.Start(self.interval_milli_sec, oneShot=True)
|
|
return super(CycleDialog, self).ShowModal(*args, **kwargs)
|
|
|
|
def on_forward(self, evt):
|
|
self.EndModal(wx.ID_FORWARD)
|
|
|
|
def on_backward(self, evt):
|
|
self.EndModal(wx.ID_BACKWARD)
|
|
|
|
def on_cancel(self, evt):
|
|
self.EndModal(wx.ID_CANCEL)
|
|
|
|
|
|
def _get_cycle_dialog(parent=None, interval=None):
|
|
app = wx.GetApp()
|
|
if not app:
|
|
app = wx.App(redirect=False)
|
|
frame = wx.Frame(None)
|
|
app.SetTopWindow(frame)
|
|
dlg = CycleDialog(parent, interval)
|
|
return dlg
|
|
|
|
|
|
def get_window_position_and_size(window_handle):
|
|
pos = GetWindowRect(window_handle)
|
|
return pos[0], pos[1], pos[2] - pos[0], pos[3] - pos[1]
|
|
|
|
|
|
def get_screen_position_and_size(window_handles):
|
|
"""Return screen position; X, Y and size; width, height.
|
|
|
|
Parameters
|
|
----------
|
|
window_handles: list of handles to open window figures
|
|
(Note: only needed the first time)
|
|
|
|
Returns
|
|
--------
|
|
X : coordinate of the left side of the screen.
|
|
Y : coordinate of the top of the screen.
|
|
width : screen horizontal size
|
|
height : screen vertical size
|
|
|
|
"""
|
|
# pylint: disable=global-statement
|
|
global _SCREENSIZE
|
|
if _SCREENSIZE is None:
|
|
window_handle = window_handles[0]
|
|
pos = get_window_position_and_size(window_handle)
|
|
_show_windows((window_handle,), win32con.SW_SHOWMAXIMIZED)
|
|
_SCREENSIZE = get_window_position_and_size(window_handle)
|
|
MoveWindow(window_handle, pos[0], pos[1], pos[2], pos[3], 1)
|
|
return _SCREENSIZE
|
|
|
|
|
|
def _get_screen_size(wnds):
|
|
screen_width, screen_height = get_screen_position_and_size(wnds)[2:4]
|
|
return screen_width, screen_height
|
|
|
|
|
|
def _windowEnumerationHandler(handle, result_list):
|
|
"""Pass to win32gui.EnumWindows() to generate list of window handle, window
|
|
text tuples."""
|
|
# pylint: disable=no-member
|
|
if win32gui.IsWindowVisible(handle):
|
|
result_list.append((handle, win32gui.GetWindowText(handle)))
|
|
|
|
|
|
def _find_window_handles_and_titles(wantedTitle=None):
|
|
"""Return list of window handle and window title tuples.
|
|
|
|
Parameter
|
|
---------
|
|
wantedTitle:
|
|
|
|
"""
|
|
handles_n_titles = []
|
|
EnumWindows(_windowEnumerationHandler, handles_n_titles)
|
|
if wantedTitle is None:
|
|
return handles_n_titles
|
|
else:
|
|
return [(handle, title)
|
|
for handle, title in handles_n_titles
|
|
if title.startswith(wantedTitle)]
|
|
|
|
|
|
def find_figure_handles(*figure_numbers):
|
|
"""Find figure handles from figure numbers."""
|
|
wnd_handles = []
|
|
for figure_number in _parse_figure_numbers(*figure_numbers):
|
|
for format_ in FIGURE_TITLE_FORMATS:
|
|
winTitle = format_ + ' %d' % figure_number
|
|
handle = FindWindow(None, winTitle)
|
|
if not handle == 0:
|
|
wnd_handles.append(handle)
|
|
return wnd_handles
|
|
|
|
|
|
def find_all_figure_numbers():
|
|
"""Return list of all figure numbers.
|
|
|
|
Example
|
|
-------
|
|
>>> import fig
|
|
>>> import pylab as p
|
|
>>> for ix in range(5):
|
|
... f = p.figure(ix)
|
|
... p.draw()
|
|
|
|
fig.find_all_figure_numbers()
|
|
[0, 1, 2, 3, 4]
|
|
|
|
>>> fig.close()
|
|
|
|
"""
|
|
figure_numbers = []
|
|
for wantedTitle in FIGURE_TITLE_FORMATS:
|
|
handles_n_titles = _find_window_handles_and_titles(wantedTitle)
|
|
for _handle, title in handles_n_titles:
|
|
try:
|
|
number = int(title.split()[-1])
|
|
figure_numbers.append(number)
|
|
except (TypeError, ValueError):
|
|
pass
|
|
# pylint: disable=no-member
|
|
return numpy.unique(figure_numbers).tolist()
|
|
|
|
|
|
def _parse_figure_numbers(*args):
|
|
figure_numbers = []
|
|
for arg in args:
|
|
if isinstance(arg, (list, tuple, set)):
|
|
for val in arg:
|
|
figure_numbers.append(int(val))
|
|
elif isinstance(arg, int):
|
|
figure_numbers.append(arg)
|
|
elif arg == 'all':
|
|
figure_numbers = find_all_figure_numbers()
|
|
break
|
|
else:
|
|
raise TypeError('Only integers arguments accepted!')
|
|
|
|
if len(figure_numbers) == 0:
|
|
figure_numbers = find_all_figure_numbers()
|
|
return figure_numbers
|
|
|
|
|
|
def _show_figure(figure_numbers, command):
|
|
"""Sets the specified figure's show state.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers: list of figure numbers
|
|
command: one of following commands:
|
|
SW_FORCEMINIMIZE:
|
|
Minimizes a window, even if the thread that owns the window is not
|
|
responding. This flag should only be used when minimizing windows
|
|
from a different thread.
|
|
SW_HIDE:
|
|
Hides the window and activates another window.
|
|
SW_MAXIMIZE:
|
|
Maximizes the specified window.
|
|
SW_MINIMIZE:
|
|
Minimizes the specified window and activates the next top-level window
|
|
in the Z order.
|
|
SW_RESTORE:
|
|
Activates and displays the window. If the window is minimized or
|
|
maximized, the system restores it to its original size and position.
|
|
An application should specify this flag when restoring a minimized
|
|
window.
|
|
SW_SHOW:
|
|
Activates the window and displays it in its current size and position.
|
|
SW_SHOWDEFAULT:
|
|
Sets the show state based on the SW_ value specified in the STARTUPINFO
|
|
structure passed to the CreateProcess function by the program that
|
|
started the application.
|
|
SW_SHOWMAXIMIZED:
|
|
Activates the window and displays it as a maximized window.
|
|
SW_SHOWMINIMIZED:
|
|
Activates the window and displays it as a minimized window.
|
|
SW_SHOWMINNOACTIVE:
|
|
Displays the window as a minimized window. This value is similar to
|
|
SW_SHOWMINIMIZED, except the window is not activated.
|
|
SW_SHOWNA:
|
|
Displays the window in its current size and position. This value is
|
|
similar to SW_SHOW, except the window is not activated.
|
|
SW_SHOWNOACTIVATE:
|
|
Displays a window in its most recent size and position. This value is
|
|
similar to SW_SHOWNORMAL, except the window is not actived.
|
|
SW_SHOWNORMAL:
|
|
Activates and displays a window. If the window is minimized or
|
|
maximized, the system restores it to its original size and position.
|
|
An application should specify this flag when displaying the window for
|
|
the first time.
|
|
|
|
"""
|
|
for number in _parse_figure_numbers(*figure_numbers):
|
|
for format_ in FIGURE_TITLE_FORMATS:
|
|
title = format_ + ' %d' % number
|
|
handle = FindWindow(None, title)
|
|
if not handle == 0:
|
|
BringWindowToTop(handle)
|
|
ShowWindow(handle, command)
|
|
|
|
|
|
def _show_windows(handles, command, redraw_now=False):
|
|
"""Sets the specified window's show state.
|
|
|
|
Parameters
|
|
----------
|
|
handles: list of window handles
|
|
command: one of following commands:
|
|
SW_FORCEMINIMIZE:
|
|
Minimizes a window, even if the thread that owns the window is not
|
|
responding. This flag should only be used when minimizing windows
|
|
from a different thread.
|
|
SW_HIDE:
|
|
Hides the window and activates another window.
|
|
SW_MAXIMIZE:
|
|
Maximizes the specified window.
|
|
SW_MINIMIZE:
|
|
Minimizes the specified window and activates the next top-level window
|
|
in the Z order.
|
|
SW_RESTORE:
|
|
Activates and displays the window. If the window is minimized or
|
|
maximized, the system restores it to its original size and position.
|
|
An application should specify this flag when restoring a minimized
|
|
window.
|
|
SW_SHOW:
|
|
Activates the window and displays it in its current size and position.
|
|
SW_SHOWDEFAULT:
|
|
Sets the show state based on the SW_ value specified in the STARTUPINFO
|
|
structure passed to the CreateProcess function by the program that
|
|
started the application.
|
|
SW_SHOWMAXIMIZED:
|
|
Activates the window and displays it as a maximized window.
|
|
SW_SHOWMINIMIZED:
|
|
Activates the window and displays it as a minimized window.
|
|
SW_SHOWMINNOACTIVE:
|
|
Displays the window as a minimized window. This value is similar to
|
|
SW_SHOWMINIMIZED, except the window is not activated.
|
|
SW_SHOWNA:
|
|
Displays the window in its current size and position. This value is
|
|
similar to SW_SHOW, except the window is not activated.
|
|
SW_SHOWNOACTIVATE:
|
|
Displays a window in its most recent size and position. This value is
|
|
similar to SW_SHOWNORMAL, except the window is not actived.
|
|
SW_SHOWNORMAL:
|
|
Activates and displays a window. If the window is minimized or
|
|
maximized, the system restores it to its original size and position.
|
|
An application should specify this flag when displaying the window for
|
|
the first time.
|
|
|
|
redraw_now :
|
|
|
|
"""
|
|
# pylint: disable=no-member
|
|
for handle in handles:
|
|
if not handle == 0:
|
|
BringWindowToTop(handle)
|
|
ShowWindow(handle, command)
|
|
if redraw_now:
|
|
rect = GetWindowRect(handle)
|
|
win32gui.RedrawWindow(handle, rect, None, win32con.RDW_UPDATENOW)
|
|
|
|
|
|
def keep(*figure_numbers):
|
|
"""Keeps figure windows of your choice and closes the rest.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers specifying which figures to keep.
|
|
|
|
Example:
|
|
--------
|
|
# keep only figures 1,2,3,5 and 7
|
|
>>> import pylab as p
|
|
>>> import wafo.fig as fig
|
|
>>> for ix in range(10):
|
|
... f = p.figure(ix)
|
|
>>> fig.keep( range(1,4), 5, 7)
|
|
|
|
or
|
|
fig.keep([range(1,4), 5, 7])
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.close
|
|
|
|
"""
|
|
figs2keep = []
|
|
for fig in figure_numbers:
|
|
if isinstance(fig, (list, tuple, set)):
|
|
for val in fig:
|
|
figs2keep.append(int(val))
|
|
elif isinstance(fig, int):
|
|
figs2keep.append(fig)
|
|
else:
|
|
raise TypeError('Only integers arguments accepted!')
|
|
|
|
if len(figs2keep) > 0:
|
|
allfigs = set(find_all_figure_numbers())
|
|
figs2delete = allfigs.difference(figs2keep)
|
|
close(figs2delete)
|
|
|
|
|
|
def close(*figure_numbers):
|
|
""" Close figure window(s)
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to close (default 'all').
|
|
|
|
Examples
|
|
--------
|
|
>>> import pylab as p
|
|
>>> import wafo.fig as fig
|
|
>>> for ix in range(5):
|
|
... f = p.figure(ix)
|
|
>>> fig.close(3,4) # close figure 3 and 4
|
|
>>> fig.close('all') # close all remaining figures
|
|
|
|
or even simpler
|
|
fig.close() # close all remaining figures
|
|
|
|
See also
|
|
--------
|
|
fig.keep
|
|
|
|
"""
|
|
# pylint: disable=no-member
|
|
for handle in find_figure_handles(*figure_numbers):
|
|
if win32gui.SendMessage(handle, win32con.WM_CLOSE, 0, 0):
|
|
win32gui.SendMessage(handle, win32con.WM_DESTROY, 0, 0)
|
|
|
|
|
|
def restore(*figure_numbers):
|
|
"""Restore figures window size and position to its default value.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to restor (default 'all').
|
|
|
|
Description
|
|
-----------
|
|
RESTORE Activates and displays the window. If the window is minimized
|
|
or maximized, the system restores it to its original size and position.
|
|
|
|
Examples
|
|
---------
|
|
>>> import pylab as p
|
|
>>> import wafo.fig as fig
|
|
>>> for ix in range(5):
|
|
... f = p.figure(ix)
|
|
>>> fig.restore('all') #Restores all figures
|
|
>>> fig.restore() #same as restore('all')
|
|
>>> fig.restore(p.gcf().number) #Restores the current figure
|
|
>>> fig.restore(3) #Restores figure 3
|
|
>>> fig.restore([2, 4]) #Restores figures 2 and 4
|
|
|
|
or alternatively
|
|
fig.restore(2, 4)
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.close,
|
|
fig.keep
|
|
|
|
"""
|
|
SW_RESTORE = win32con.SW_RESTORE
|
|
# SW_RESTORE = win32con.SW_SHOWDEFAULT
|
|
# SW_RESTORE = win32con.SW_SHOWNORMAL
|
|
_show_figure(figure_numbers, SW_RESTORE)
|
|
|
|
|
|
def hide(*figure_numbers):
|
|
"""hide figure(s) window.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to hide (default 'all').
|
|
|
|
Examples:
|
|
--------
|
|
>>> import wafo.fig as fig
|
|
>>> import pylab as p
|
|
>>> for ix in range(5):
|
|
... f = p.figure(ix)
|
|
>>> fig.hide('all') #hides all unhidden figures
|
|
>>> fig.hide() #same as hide('all')
|
|
>>> fig.hide(p.gcf().number) #hides the current figure
|
|
>>> fig.hide(3) #hides figure 3
|
|
>>> fig.hide([2, 4]) #hides figures 2 and 4
|
|
|
|
or alternatively
|
|
fig.hide(2, 4)
|
|
>>> fig.restore(list(range(5)))
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.cycle,
|
|
fig.keep,
|
|
fig.restore
|
|
|
|
"""
|
|
_show_figure(figure_numbers, win32con.SW_HIDE)
|
|
|
|
|
|
def minimize(*figure_numbers):
|
|
"""Minimize figure(s) window size.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to minimize (default 'all').
|
|
|
|
Examples:
|
|
---------
|
|
>>> import wafo.fig as fig
|
|
>>> import pylab as p
|
|
>>> for ix in range(5):
|
|
... f = p.figure(ix)
|
|
>>> fig.minimize('all') #Minimizes all unhidden figures
|
|
>>> fig.minimize() #same as minimize('all')
|
|
>>> fig.minimize(p.gcf().number) #Minimizes the current figure
|
|
>>> fig.minimize(3) #Minimizes figure 3
|
|
>>> fig.minimize([2, 4]) #Minimizes figures 2 and 4
|
|
|
|
or alternatively
|
|
fig.minimize(2, 4)
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.cycle,
|
|
fig.keep,
|
|
fig.restore
|
|
|
|
"""
|
|
_show_figure(figure_numbers, win32con.SW_SHOWMINIMIZED)
|
|
|
|
|
|
def maximize(*figure_numbers):
|
|
"""Maximize figure(s) window size.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to maximize (default 'all').
|
|
|
|
Examples:
|
|
---------
|
|
>>> import pylab as p
|
|
>>> import wafo.fig as fig
|
|
>>> for ix in range(5):
|
|
... f = p.figure(ix)
|
|
>>> fig.maximize('all') #Maximizes all unhidden figures
|
|
>>> fig.maximize() #same as maximize('all')
|
|
>>> fig.maximize(p.gcf().number) #Maximizes the current figure
|
|
>>> fig.maximize(3) #Maximizes figure 3
|
|
>>> fig.maximize([2, 4]) #Maximizes figures 2 and 4
|
|
|
|
or alternatively
|
|
fig.maximize(2, 4)
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.cycle,
|
|
fig.keep,
|
|
fig.restore
|
|
|
|
"""
|
|
_show_figure(figure_numbers, win32con.SW_SHOWMAXIMIZED)
|
|
|
|
|
|
def pile(*figure_numbers, **kwds):
|
|
"""Pile figure windows.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to pile (default 'all').
|
|
kwds : dict with the following keys
|
|
position :
|
|
width :
|
|
height :
|
|
|
|
Description
|
|
-------------
|
|
PILE piles all open figure windows on top of eachother
|
|
with complete overlap. PILE(FIGS) can be used to specify which
|
|
figures that should be piled. Figures are not sorted when specified.
|
|
|
|
Example:
|
|
--------
|
|
>>> import pylab as p
|
|
>>> import wafo.fig as fig
|
|
>>> for ix in range(7):
|
|
... f = p.figure(ix)
|
|
>>> fig.pile() # pile all open figures
|
|
>>> fig.pile(range(1,4), 5, 7) # pile figure 1,2,3,5 and 7
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.cycle, fig.keep, fig.maximize, fig.restore,
|
|
fig.stack, fig.tile
|
|
|
|
"""
|
|
wnds = find_figure_handles(*figure_numbers)
|
|
numfigs = len(wnds)
|
|
if numfigs > 0:
|
|
screen_width, screen_height = _get_screen_size(wnds)
|
|
pos = kwds.get(
|
|
'position', (int(screen_width / 5), int(screen_height / 4)))
|
|
width = kwds.get('width', int(screen_width / 2.5))
|
|
height = kwds.get('height', int(screen_height / 2))
|
|
|
|
for wnd in wnds:
|
|
MoveWindow(wnd, pos[0], pos[1], width, height, 1)
|
|
BringWindowToTop(wnd)
|
|
|
|
|
|
def set_size(*figure_numbers, **kwds):
|
|
"""Set size for figure windows.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to pile (default 'all').
|
|
kwds : dict with the following keys
|
|
width :
|
|
height :
|
|
|
|
Description
|
|
-------------
|
|
Set size sets the size of all open figure windows. SET_SIZE(FIGS)
|
|
can be used to specify which figures that should be resized.
|
|
Figures are not sorted when specified.
|
|
|
|
Example:
|
|
--------
|
|
>>> import pylab as p
|
|
>>> import fig
|
|
>>> for ix in range(7):
|
|
... f = p.figure(ix)
|
|
>>> fig.set_size(7, width=150, height=100)
|
|
>>> fig.set_size(range(1,4), 5,width=250, height=170)
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.cycle, fig.keep, fig.maximize, fig.restore,
|
|
fig.stack, fig.tile
|
|
|
|
"""
|
|
handles = find_figure_handles(*figure_numbers)
|
|
numfigs = len(handles)
|
|
if numfigs > 0:
|
|
screen_width, screen_height = _get_screen_size(handles)
|
|
width = kwds.get('width', int(screen_width / 2.5))
|
|
height = kwds.get('height', int(screen_height / 2))
|
|
new_pos = kwds.get('position', None)
|
|
pos = new_pos
|
|
for handle in handles:
|
|
if not new_pos:
|
|
pos = get_window_position_and_size(handle)
|
|
MoveWindow(handle, pos[0], pos[1], width, height, 1)
|
|
BringWindowToTop(handle)
|
|
|
|
|
|
def stack(*figure_numbers, **kwds):
|
|
"""Stack figure windows.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to stack (default 'all').
|
|
kwds : dict with the following keys
|
|
figs_per_stack :
|
|
number of figures per stack (default depends on screenheight)
|
|
|
|
Description
|
|
-----------
|
|
STACK stacks all open figure windows on top of eachother
|
|
with maximum overlap. STACK(FIGS) can be used to specify which
|
|
figures that should be stacked. Figures are not sorted when specified.
|
|
|
|
Example:
|
|
--------
|
|
>>> import pylab as p
|
|
>>> import wafo.fig as fig
|
|
>>> for ix in range(7):
|
|
... f = p.figure(ix)
|
|
>>> fig.stack() # stack all open figures
|
|
>>> fig.stack(range(1,4), 5, 7) # stack figure 1,2,3,5 and 7
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.cycle, fig.keep, fig.maximize, fig.restore,
|
|
fig.pile, fig.tile
|
|
|
|
"""
|
|
wnds = find_figure_handles(*figure_numbers)
|
|
numfigs = len(wnds)
|
|
if numfigs > 0:
|
|
screenpos = get_screen_position_and_size(wnds)
|
|
y_step = 25
|
|
x_step = border = 5
|
|
|
|
figs_per_stack = kwds.get(
|
|
'figs_per_stack',
|
|
int(numpy.fix(0.7 * (screenpos[3] - border) / y_step)))
|
|
|
|
for iy in range(numfigs):
|
|
pos = get_window_position_and_size(wnds[iy])
|
|
# print('[x, y, w, h] = ', pos)
|
|
ix = iy % figs_per_stack
|
|
ypos = int(screenpos[1] + ix * y_step + border)
|
|
xpos = int(screenpos[0] + ix * x_step + border)
|
|
MoveWindow(wnds[iy], xpos, ypos, pos[2], pos[3], 1)
|
|
BringWindowToTop(wnds[iy])
|
|
|
|
|
|
def tile(*figure_numbers, **kwds):
|
|
"""Tile figure windows.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to tile (default 'all').
|
|
kwds : dict with key pairs
|
|
specifying how many pairs of figures that are tiled at a time
|
|
|
|
Description
|
|
-----------
|
|
TILE places all open figure windows around on the screen with no
|
|
overlap. TILE(FIGS) can be used to specify which figures that
|
|
should be tiled. Figures are not sorted when specified.
|
|
|
|
Example:
|
|
--------
|
|
>>> import pylab as p
|
|
>>> import wafo.fig as fig
|
|
>>> for ix in range(7):
|
|
... f = p.figure(ix)
|
|
>>> fig.tile() # tile all open figures
|
|
>>> fig.tile( range(1,4), 5, 7) # tile figure 1,2,3,5 and 7
|
|
>>> fig.tile(range(1,11), pairs=2) # tile figure 1 to 10 two at a time
|
|
>>> fig.tile(range(1,11), pairs=3) # tile figure 1 to 10 three at a time
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.cycle, fig.keep, fig.maximize, fig.minimize
|
|
fig.restore, fig.pile, fig.stack
|
|
|
|
"""
|
|
wnds = find_figure_handles(*figure_numbers)
|
|
|
|
nfigs = len(wnds)
|
|
# Number of windows.
|
|
|
|
if nfigs > 0:
|
|
nfigspertile = kwds.get('pairs', nfigs)
|
|
|
|
ceil = numpy.ceil
|
|
sqrt = numpy.sqrt
|
|
maximum = numpy.maximum
|
|
|
|
nlayers = int(ceil(nfigs / nfigspertile))
|
|
|
|
# Number of figures horisontally.
|
|
nh = maximum(int(ceil(sqrt(nfigspertile))), 2)
|
|
# Number of figures vertically.
|
|
nv = maximum(int(ceil(nfigspertile / nh)), 2)
|
|
|
|
screenpos = get_screen_position_and_size(wnds)
|
|
screen_width, screen_heigth = screenpos[2:4]
|
|
|
|
hspc = 10 # Horisontal space.
|
|
topspc = 20 # Space above top figure.
|
|
medspc = 10 # Space between figures.
|
|
botspc = 20 # Space below bottom figure.
|
|
|
|
figwid = (screen_width - (nh + 1) * hspc) / nh
|
|
fighgt = (screen_heigth - (topspc + botspc) - (nv - 1) * medspc) / nv
|
|
|
|
figwid = int(numpy.round(figwid))
|
|
fighgt = int(numpy.round(fighgt))
|
|
|
|
idx = 0
|
|
for unused_ix in range(nlayers):
|
|
for row in range(nv):
|
|
figtop = int(screenpos[1] + topspc + row * (fighgt + medspc))
|
|
for col in range(nh):
|
|
if (row) * nh + col < nfigspertile:
|
|
if idx < nfigs:
|
|
figlft = int(
|
|
screenpos[0] + (col + 1) * hspc + col * figwid)
|
|
fighnd = wnds[idx]
|
|
MoveWindow(fighnd, figlft, figtop, figwid, fighgt,
|
|
1)
|
|
# Set position.
|
|
BringWindowToTop(fighnd)
|
|
idx += 1
|
|
|
|
|
|
class _CycleGenerator(object):
|
|
|
|
"""Cycle through figure windows.
|
|
|
|
Parameters
|
|
----------
|
|
figure_numbers : list of integers or string
|
|
specifying which figures to cycle through (default 'all').
|
|
kwds : dict with the following keys
|
|
pairs : number of figures to cycle in pairs (default 1)
|
|
maximize: If True maximize figure when viewing (default False)
|
|
interval : pause interval in seconds
|
|
|
|
Description
|
|
-----------
|
|
CYCLE brings up all open figure in ascending order and pauses after
|
|
each figure. Press escape to quit cycling, backspace to display previous
|
|
figure(s) and press any other key to display next figure(s)
|
|
When done, the figures are sorted in ascending order.
|
|
|
|
CYCLE(maximize=True) does the same thing, except figures are maximized.
|
|
CYCLE(pairs=2) cycle through all figures in pairs of 2.
|
|
|
|
Examples:
|
|
>>> import pylab as p
|
|
>>> import wafo.fig as fig
|
|
>>> for ix in range(4):
|
|
... f = p.figure(ix)
|
|
|
|
fig.cycle(range(3), interval=1) # Cycle trough figure 0 to 2
|
|
|
|
# Cycle trough figure 0 to 2 with figures maximized
|
|
fig.cycle(range(3), maximize=True, interval=1)
|
|
fig.cycle(interval=1) # Cycle through all figures one at a time
|
|
fig.tile(pairs=2, interval=1)
|
|
fig.cycle(pairs=2, interval=2) # Cycle through all figures two at a time
|
|
|
|
fig.cycle(pairs=2) # Manually cycle through all figures two at a time
|
|
>>> fig.close()
|
|
|
|
See also
|
|
--------
|
|
fig.keep, fig.maximize, fig.restore, fig.pile,
|
|
fig.stack, fig.tile
|
|
|
|
"""
|
|
escape_key = chr(27)
|
|
backspace_key = chr(8)
|
|
|
|
def __init__(self, **kwds):
|
|
self.dialog = None
|
|
maximize = kwds.get('maximize', False)
|
|
pairs = kwds.get('pairs', 1)
|
|
self.interval = kwds.get('interval', 'user_defined')
|
|
self.nfigspercycle = 1
|
|
if maximize:
|
|
self.command = win32con.SW_SHOWMAXIMIZED
|
|
else:
|
|
self.command = win32con.SW_SHOWNORMAL
|
|
if pairs is not None:
|
|
self.nfigspercycle = pairs
|
|
|
|
def _set_options(self, kwds):
|
|
self.__init__(**kwds)
|
|
|
|
def _iterate(self, handles):
|
|
i = 0
|
|
numfigs = len(handles)
|
|
self.dialog = _get_cycle_dialog(parent=None, interval=self.interval)
|
|
while 0 <= i and i < numfigs:
|
|
iu = min(i + self.nfigspercycle, numfigs)
|
|
yield handles[i:iu]
|
|
i = self.next_index(i)
|
|
self.dialog.Destroy()
|
|
raise StopIteration
|
|
|
|
def next_index(self, i):
|
|
result = self.dialog.ShowModal()
|
|
if result == wx.ID_FORWARD:
|
|
i += self.nfigspercycle
|
|
elif result == wx.ID_BACKWARD:
|
|
i -= self.nfigspercycle
|
|
else:
|
|
i = -1
|
|
return i
|
|
|
|
def __call__(self, *figure_numbers, **kwds):
|
|
handles = find_figure_handles(*figure_numbers)
|
|
numfigs = len(handles)
|
|
if numfigs > 0:
|
|
self._set_options(kwds)
|
|
for handle in self._iterate(handles):
|
|
_show_windows(handle, self.command, redraw_now=True)
|
|
|
|
_show_windows(handles, win32con.SW_SHOWNORMAL)
|
|
|
|
cycle = _CycleGenerator()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
from wafo.testing import test_docstrings
|
|
import matplotlib
|
|
matplotlib.interactive(True)
|
|
test_docstrings(__file__)
|