258 lines
7.0 KiB
Python
258 lines
7.0 KiB
Python
#
|
|
# Python GUI - Windows - Generic
|
|
#
|
|
|
|
import Exceptions
|
|
from GUI.Properties import overridable_property
|
|
from GUI import Container
|
|
from GUI import application
|
|
|
|
class Window(Container):
|
|
"""Top-level Container."""
|
|
|
|
menus = overridable_property('menus', "Menus to be available when this window is active.")
|
|
document = overridable_property('document', "Document with which this window is associated.")
|
|
title = overridable_property('title', "Title of the window.")
|
|
auto_position = overridable_property('auto_position', "Whether to position automatically when first shown.")
|
|
target = overridable_property('target', "Current target for key events and menu messages.")
|
|
tab_chain = overridable_property('tab_chain', "List of subcomponents in tabbing order.")
|
|
visible = overridable_property('visible', "Whether the window is currently shown.")
|
|
|
|
keeps_document_open = True
|
|
|
|
_default_width = 200
|
|
_default_height = 200
|
|
_modal_styles = ('modal_dialog', 'alert')
|
|
_dialog_styles = ('nonmodal_dialog', 'modal_dialog', 'alert')
|
|
|
|
_menus = []
|
|
_document = None
|
|
_closable = 0
|
|
_auto_position = True
|
|
_tab_chain = None
|
|
|
|
def __init__(self, style = 'standard', closable = None, **kwds):
|
|
if closable is None:
|
|
raise Exceptions.InternalError(
|
|
"'closable' parameter unspecified in call to generic Window.__init__")
|
|
Container.__init__(self, **kwds)
|
|
self._style = style
|
|
self._dialog_style = style.find('dialog') >= 0
|
|
self._closable = closable
|
|
application()._add_window(self)
|
|
|
|
def destroy(self):
|
|
"""Detaches the window from document and application and removes it
|
|
from the screen."""
|
|
self.set_document(None)
|
|
application()._remove_window(self)
|
|
Container.destroy(self)
|
|
|
|
#
|
|
# Message handling
|
|
#
|
|
|
|
def next_handler(self):
|
|
if self._document:
|
|
return self._document
|
|
else:
|
|
return application()
|
|
|
|
def dispatch(self, message, *args):
|
|
self.target.handle(message, *args)
|
|
|
|
#
|
|
# Menus
|
|
#
|
|
|
|
def get_menus(self):
|
|
return self._menus
|
|
|
|
def set_menus(self, x):
|
|
self._menus = x
|
|
|
|
#
|
|
# Document association
|
|
#
|
|
|
|
def get_document(self):
|
|
return self._document
|
|
|
|
def set_document(self, x):
|
|
if self._document != x:
|
|
if self._document:
|
|
self._document._windows.remove(self)
|
|
self._document = x
|
|
if self._document:
|
|
self._document._windows.append(self)
|
|
self.update_title()
|
|
|
|
#
|
|
# Title
|
|
#
|
|
|
|
def update_title(self):
|
|
"""Update the window's title after a change in its document's title."""
|
|
doc = self._document
|
|
if doc:
|
|
self.set_title(doc.title)
|
|
|
|
#
|
|
# Showing and Positioning
|
|
#
|
|
|
|
def get_auto_position(self):
|
|
return self._auto_position
|
|
|
|
def set_auto_position(self, v):
|
|
self._auto_position = v
|
|
|
|
def center(self):
|
|
"""Position the window in the centre of the screen."""
|
|
print "GWindow.center" ###
|
|
sl, st, sr, sb = self._screen_rect()
|
|
w, h = self.size
|
|
l = (sr - sl - w) // 2
|
|
t = (sb - st - h) // 2
|
|
self.position = (l, t)
|
|
|
|
def centre(self):
|
|
self.center()
|
|
|
|
def show(self):
|
|
if self._auto_position:
|
|
if self._style == 'standard':
|
|
self._stagger()
|
|
else:
|
|
self.center()
|
|
self._auto_position = False
|
|
self._show()
|
|
|
|
def _stagger(self):
|
|
pass
|
|
|
|
def _show(self):
|
|
self.visible = True
|
|
|
|
def hide(self):
|
|
self.visible = False
|
|
|
|
#
|
|
# Menu commands
|
|
#
|
|
|
|
def setup_menus(self, m):
|
|
Container.setup_menus(self, m)
|
|
app = application()
|
|
if self._closable:
|
|
m.close_cmd.enabled = 1
|
|
|
|
def close_cmd(self):
|
|
"""If this window is the only window belonging to a document
|
|
whose keeps_document_open attribute is true, then close the
|
|
document, else destroy the window."""
|
|
# app = application()
|
|
# if not app._may_close_a_window():
|
|
# #print "GWindow.close_cmd: Quitting the application" ###
|
|
# app.quit_cmd()
|
|
# else:
|
|
doc = self._document
|
|
n = 0
|
|
if doc:
|
|
for win in doc._windows:
|
|
if win is not self and win.keeps_document_open:
|
|
n += 1
|
|
if doc and n == 0:
|
|
doc.close_cmd()
|
|
else:
|
|
self.destroy()
|
|
|
|
#
|
|
# Tabbing
|
|
#
|
|
|
|
def get_tab_chain(self):
|
|
chain = self._tab_chain
|
|
if chain is None:
|
|
chain = []
|
|
self._build_tab_chain(chain)
|
|
self._tab_chain = chain
|
|
#print "Window.get_tab_chain:", chain ###
|
|
return chain
|
|
|
|
def _invalidate_tab_chain(self):
|
|
self._tab_chain = None
|
|
|
|
def _tab_to_next(self):
|
|
self._tab_to(1)
|
|
|
|
def _tab_to_prev(self):
|
|
self._tab_to(-1)
|
|
|
|
def _tab_to(self, direction):
|
|
#print "GWindow._tab_to:", direction ###
|
|
chain = self.tab_chain
|
|
if chain:
|
|
old_target = application().target
|
|
new_target = None
|
|
n = len(chain)
|
|
try:
|
|
i = chain.index(old_target)
|
|
except ValueError:
|
|
if direction > 0:
|
|
i = -1
|
|
else:
|
|
i = n
|
|
k = n
|
|
while k:
|
|
k -= 1
|
|
i = (i + direction) % n
|
|
comp = chain[i]
|
|
if comp._is_targetable():
|
|
new_target = comp
|
|
break
|
|
if new_target:
|
|
if old_target:
|
|
old_target._tab_out()
|
|
new_target._tab_in()
|
|
|
|
def key_down(self, event):
|
|
#print "GWindow.key_down:", event ###
|
|
if self._generic_tabbing and event.char == '\t':
|
|
#print "GWindow.key_down: doing generic tabbing" ###
|
|
if event.shift:
|
|
self._tab_to_prev()
|
|
else:
|
|
self._tab_to_next()
|
|
else:
|
|
Container.key_down(self, event)
|
|
|
|
# def _default_key_event(self, event):
|
|
# #print "GWindow._default_key_event" ###
|
|
# self.pass_event_to_next_handler(event)
|
|
|
|
#
|
|
# Other
|
|
#
|
|
|
|
def get_window(self):
|
|
return self
|
|
|
|
def first_dispatcher(self):
|
|
return self
|
|
|
|
def _document_needs_saving(self, state):
|
|
pass
|
|
|
|
def modal_event_loop(self):
|
|
"""Loop reading and handling events for the given window until
|
|
exit_event_loop() is called. Interaction with other windows is prevented
|
|
(although enabled application-wide menu commands can be used)."""
|
|
# Implementations can override this together with exit_modal_event_loop()
|
|
# to implement modal event loops in a different way.
|
|
application()._event_loop(self)
|
|
|
|
def exit_modal_event_loop(self):
|
|
# Cause the current call to modal_event_loop() to exit.
|
|
application()._exit_event_loop()
|