Lightningbeam/GUI/Win32/Window.py

344 lines
12 KiB
Python
Executable File

#--------------------------------------------------------------------
#
# PyGUI - Window - Win32
#
#--------------------------------------------------------------------
import win32con as wc, win32ui as ui, win32gui as gui, win32api as api
from GUI import export
from GUI import WinUtils
from GUI.Geometry import rect_size, sub_pt
from GUI import application
from GUI.Exceptions import Cancel
from GUI.WinEvents import win_message_to_event
from GUI.WinMenus import MenuBar, win_id_to_command
from GUI.GMenus import search_list_for_key
from GUI import Component
from GUI.GWindows import Window as GWindow
#--------------------------------------------------------------------
capabilities = ('hidable', 'zoomable', 'resizable', 'movable', 'closable')
win_defaults = {
'standard': (1, 1, 1, 1, 1),
'nonmodal_dialog': (1, 0, 0, 1, 1),
'modal_dialog': (0, 0, 0, 1, 1),
'alert': (0, 0, 0, 1, 1),
'fullscreen': (0, 0, 0, 0, 0),
}
win_base_flags = wc.WS_CLIPCHILDREN
win_border_flags = wc.WS_DLGFRAME
win_capability_flags = {
'hidable': wc.WS_MINIMIZEBOX | wc.WS_SYSMENU,
'zoomable': wc.WS_MAXIMIZEBOX | wc.WS_SYSMENU,
'resizable': wc.WS_THICKFRAME,
'movable': wc.WS_BORDER,
'closable': wc.WS_SYSMENU,
}
win_no_menu_styles = ('nonmodal_dialog', 'modal_dialog',
'alert', 'fullscreen')
win_ex_flags = 0 #wc.WS_EX_WINDOWEDGE
win_no_ex_flags = wc.WS_EX_CLIENTEDGE
def win_calculate_flags(style, kwds):
# Calculate window flags from the options present in kwds, and
# fill in kwds with default values for missing options that need
# to be passed to the base class constructor.
flags = win_base_flags
if style != 'fullscreen':
flags |= win_border_flags
try:
defaults = win_defaults[style]
except KeyError:
raise ValueError("Invalid window style '%s'" % style)
for name, default in zip(capabilities, defaults):
value = kwds.pop(name, default)
if name == 'closable':
kwds[name] = value
if value:
flags |= win_capability_flags[name]
return flags
#def win_adjust_flags(flags, kwds, option_name, opt_flags):
# option = kwds.pop(option_name, None)
# if option is not None:
# if option:
# flags |= opt_flags
# else:
# flags &= ~opt_flags
# return flags
def win_next_wnd(wnd):
wnd = getattr(wnd, '_win', wnd)
#print "win_next_wnd:", wnd ###
return wnd.GetWindow(wc.GW_HWNDNEXT)
#--------------------------------------------------------------------
class Window(GWindow):
_win_hooks_events = True
_win_has_menubar = True
_win_captures_mouse = True
_win_need_menubar_update = True
_win_saved_target = False
_win_fullscreen = False
def __init__(self, **kwds):
style = kwds.get('style', 'standard')
flags = win_calculate_flags(style, kwds)
#if style == 'fullscreen':
# rect = WinUtils.win_screen_rect
#else:
rect = (0, 0, self._default_width, self._default_height)
frame = ui.CreateFrame()
frame.CreateWindow(None, "New Window", 0, rect)
hwnd = frame.GetSafeHwnd()
#api.SetClassLong(hwnd, wc.GCL_HBRBACKGROUND, win_bg_hbrush)
api.SetClassLong(hwnd, wc.GCL_HBRBACKGROUND, 0)
# print "Window: Setting style:" ###
# win_deconstruct_style(flags) ###
frame.ModifyStyle(-1, flags)
# print "Window: Style is now:" ###
# win_deconstruct_style(frame.GetStyle()) ###
frame.ModifyStyleEx(win_no_ex_flags, win_ex_flags)
if style == 'fullscreen':
self._win_fullscreen = True
frame.HookMessage(self._win_wm_initmenu, wc.WM_INITMENU)
self._win = frame
if style in win_no_menu_styles:
self._win_has_menubar = False
else:
self._win_set_empty_menubar()
kwds['closable'] = flags & wc.WS_CAPTION <> 0
GWindow.__init__(self, _win = frame, **kwds)
def OnPaint(self):
win = self._win
dc, ps = win.BeginPaint()
rect = win.GetClientRect()
dc.FillSolidRect(rect, WinUtils.win_bg_color)
if self._win_has_menubar:
l, t, r, b = rect
dc.Draw3dRect((l, t, r + 1, t + 2),
WinUtils.win_color3dshadow, WinUtils.win_color3dhilight)
win.EndPaint(ps)
def _win_install_event_hooks(self):
self._win.HookMessage(self._wm_activate, wc.WM_ACTIVATE)
#self._win.HookMessage(self._wm_setfocus, wc.WM_SETFOCUS)
self._win.HookMessage(self._wm_windowposchanging, wc.WM_WINDOWPOSCHANGING)
self._win.HookMessage(self._wm_windowposchanged, wc.WM_WINDOWPOSCHANGED)
GWindow._win_install_event_hooks(self)
def _wm_activate(self, msg):
wParam = msg[2]
#print "Window._wm_activate:", msg ###
#print "...wParam =", wParam ###
if wParam == wc.WA_INACTIVE:
#print "Window: Deactivating:", self ###
try:
target = ui.GetFocus()
#print "...target =", target ###
except ui.error, e:
#print "...no target", e ###
target = None
if isinstance(target, Component) and target is not self:
#print "...saving target", target ###
self._win_saved_target = target
def _win_wm_setfocus(self, msg):
#print "Window._win_wm_setfocus:", self ###
target = self._win_saved_target
if target and target.window == self:
#print "...restoring target", target ###
target._win.SetFocus()
self._win_saved_target = None
else:
GWindow._win_wm_setfocus(self, msg)
def get_target(self):
if self._win_is_active():
try:
target = ui.GetFocus()
except ui.error:
target = None
if target and isinstance(target, Component):
return target
return self._saved_target or self
def _win_is_active(self):
try:
active_win = ui.GetActiveWindow()
except ui.error:
active_win = None
return active_win is self
# def _wm_setfocus(self, *args):
# print "Window._wm_setfocus:", args ###
def _wm_windowposchanging(self, message):
#print "Window._wm_windowposchanging"
self._win_old_size = rect_size(self._bounds)
#print "...old size =", self._win_old_size
def _wm_windowposchanged(self, message):
#print "Window._wm_windowposchanged"
old_size = self._win_old_size
new_bounds = self._win_get_actual_bounds()
self._bounds = new_bounds
new_size = rect_size(new_bounds)
#print "...new size =", new_size
if old_size != new_size:
self._resized(sub_pt(new_size, old_size))
def _win_set_empty_menubar(self):
# A completely empty menu bar collapses to zero height, and
# controlling the window bounds is too complicated if the
# menu bar comes and goes, so we add a dummy item to it.
menubar = MenuBar()
menubar.win_menu.AppendMenu(0, 0, "")
self._win.SetMenu(menubar.win_menu)
self._win_menubar = menubar
def get_title(self):
return self._win.GetWindowText()
def set_title(self, x):
self._win.SetWindowText(x)
def get_visible(self):
return self._win.IsWindowVisible()
def set_visible(self, x):
#print "Window.set_visible:", x, self ###
if x:
self._win_update_menubar()
self._win.ShowWindow()
else:
self._win.ShowWindow(wc.SW_HIDE)
def _show(self):
self._win_update_menubar()
win = self._win
if self._win_fullscreen:
win.ShowWindow(wc.SW_SHOWMAXIMIZED)
# win.SetWindowPos(wc.HWND_TOP, (0, 0, 0, 0),
# wc.SWP_NOMOVE | wc.SWP_NOSIZE | wc.SWP_SHOWWINDOW)
win.ShowWindow(wc.SW_SHOWNORMAL)
win.SetActiveWindow()
# def get_bounds(self):
# win = self._win
# r = win.ClientToScreen(win.GetClientRect())
# return r
def _win_get_actual_bounds(self):
win = self._win
return win.ClientToScreen(win.GetClientRect())
def _win_move_window(self, rect):
win = self._win
l, t, r, b = win.CalcWindowRect(rect)
if self._win_has_menubar:
t -= WinUtils.win_menubar_height
self._win.MoveWindow((l, t, r, b))
def set_menus(self, x):
GWindow.set_menus(self, x)
self._win_menus_changed()
def _stagger(self):
#print "Window._stagger:", self ###
win = win_next_wnd(self._win)
while win and not (isinstance(win, Window) and win.visible):
#print "...win =", win ###
win = win_next_wnd(win)
if win:
l, t, r, b = win._win.GetWindowRect()
hwnd = self._win.GetSafeHwnd()
gui.SetWindowPos(hwnd, 0, l + 20, t + 20, 0, 0,
wc.SWP_NOSIZE | wc.SWP_NOZORDER)
def OnClose(self):
#print "Window:", self, "OnClose"
try:
self.close_cmd()
except Cancel:
pass
except:
application().report_error()
def _win_menus_changed(self):
self._win_need_menubar_update = True
if self.visible:
self._win_update_menubar()
def _win_update_menubar(self):
#print "Window._win_update_menubar:", self ###
if self._win_need_menubar_update:
all_menus = application()._effective_menus_for_window(self)
self._all_menus = all_menus
if self._win_has_menubar:
if all_menus:
menubar = MenuBar()
for menu in all_menus:
menubar.append_menu(menu)
self._win.SetMenu(menubar.win_menu)
self._win_menubar = menubar
else:
self._win_set_empty_menubar()
self._win_need_menubar_update = False
def _win_wm_initmenu(self, message):
#print "Window._win_wm_initmenu:", self ###
self._win_perform_menu_setup()
def _win_perform_menu_setup(self):
#print "Window._win_perform_menu_setup:", self ###
application()._perform_menu_setup(self._all_menus)
def _win_menu_command(self, id):
command = win_id_to_command(id)
if command:
application().dispatch_menu_command(command)
def _win_possible_menu_key(self, key, shift, option):
self._win_perform_menu_setup()
command = search_list_for_key(self._all_menus, key, shift, option)
if command:
application().dispatch_menu_command(command)
return True
def _screen_rect(self):
return WinUtils.win_screen_rect
def modal_event_loop(self):
disabled = []
for window in application().windows:
if window is not self:
if not window._win.EnableWindow(False):
#print "Window.modal_event_loop: disabled", window.title ###
disabled.append(window)
status = self._win.RunModalLoop(0)
if status:
print "Window._modal_event_loop:", self, "status =", status ###
#raise Cancel
for window in disabled:
#print "Window.modal_event_loop: enabling", window.title ###
window._win.EnableWindow(True)
if status <> 0: ###
from GUI.Exceptions import InternalError ###
raise InternalError("RunModalLoop returned %s" % status) ###
def exit_modal_event_loop(self):
self._win.EndModalLoop(0)
export(Window)