344 lines
12 KiB
Python
Executable File
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)
|