264 lines
8.4 KiB
Python
Executable File
264 lines
8.4 KiB
Python
Executable File
#--------------------------------------------------------------------
|
|
#
|
|
# PyGUI - Component - Win32
|
|
#
|
|
#--------------------------------------------------------------------
|
|
|
|
import win32con as wc, win32ui as ui, win32gui as gui, win32api as api
|
|
|
|
from GUI import export
|
|
from GUI.Geometry import sub_pt
|
|
from GUI import application
|
|
from GUI.WinUtils import win_none, win_event_messages
|
|
from GUI.WinEvents import win_message_to_event, win_prev_key_state
|
|
from GUI.Exceptions import Cancel
|
|
from GUI.GComponents import Component as GComponent, transform_coords
|
|
|
|
win_swp_flags = wc.SWP_NOACTIVATE | wc.SWP_NOZORDER
|
|
win_sws_flags = win_swp_flags | wc.SWP_NOMOVE
|
|
|
|
# Virtual key code to menu key char
|
|
win_menu_key_map = {
|
|
0xc0: '`',
|
|
0xbd: '-',
|
|
0xbb: '=',
|
|
0xdb: '[',
|
|
0xdd: ']',
|
|
0xba: ';',
|
|
0xde: "'",
|
|
0xbc: ',',
|
|
0xbe: '.',
|
|
0xbf: '/',
|
|
0xdc: '\\',
|
|
}
|
|
|
|
# Virtual key codes of modifier keys
|
|
win_virt_modifiers = (0x10, 0x11, 0x12, 0x14, 0x90)
|
|
|
|
# Translate virtual key code to menu key char
|
|
def win_translate_virtual_menu_key(virt):
|
|
if 0x41 <= virt <= 0x5a or 0x30 <= virt <= 0x39:
|
|
return chr(virt)
|
|
else:
|
|
return win_menu_key_map.get(virt)
|
|
|
|
#--------------------------------------------------------------------
|
|
|
|
class Component(GComponent):
|
|
|
|
_has_local_coords = True
|
|
_win_hooks_events = False
|
|
_win_transparent = False
|
|
_win_captures_mouse = False
|
|
|
|
_h_scroll_offset = 0
|
|
_v_scroll_offset = 0
|
|
_win_tracking_mouse = False
|
|
|
|
def __init__(self, _win, **kwds):
|
|
if self._win_transparent:
|
|
_win.ModifyStyleEx(0, wc.WS_EX_TRANSPARENT, 0)
|
|
self._win = _win
|
|
self._bounds = self._win_get_actual_bounds()
|
|
_win.AttachObject(self)
|
|
self._win_install_event_hooks()
|
|
GComponent.__init__(self, **kwds)
|
|
|
|
def destroy(self):
|
|
GComponent.destroy(self)
|
|
wo = self._win
|
|
if wo:
|
|
wo.AttachObject(None)
|
|
wo.ShowWindow(wc.SW_HIDE)
|
|
application()._win_recycle(wo)
|
|
#self._win = None
|
|
|
|
def _win_get_flag(self, flag):
|
|
return self._win.GetStyle() & flag != 0
|
|
|
|
def _win_set_flag(self, b, flag, swp_flags = 0):
|
|
if b:
|
|
state = flag
|
|
else:
|
|
state = 0
|
|
self._win.ModifyStyle(flag, state, swp_flags)
|
|
|
|
def _win_set_ex_flag(self, b, flag, swp_flags = 0):
|
|
if b:
|
|
state = flag
|
|
else:
|
|
state = 0
|
|
self._win.ModifyStyleEx(flag, state, swp_flags)
|
|
|
|
def _change_container(self, new_container):
|
|
GComponent._change_container(self, new_container)
|
|
if new_container:
|
|
win_new_parent = new_container._win
|
|
else:
|
|
win_new_parent = win_none
|
|
hwnd = self._win.GetSafeHwnd()
|
|
gui.SetParent(hwnd, win_new_parent.GetSafeHwnd())
|
|
if new_container:
|
|
self._win_move_window(self._bounds)
|
|
|
|
def _win_install_event_hooks(self):
|
|
def hook(message):
|
|
return self._win_event_message(message)
|
|
win = self._win
|
|
for msg in win_event_messages:
|
|
win.HookMessage(hook, msg)
|
|
win.HookMessage(self._win_wm_setfocus, wc.WM_SETFOCUS)
|
|
win.HookMessage(self._win_wm_killfocus, wc.WM_KILLFOCUS)
|
|
|
|
def _win_wm_setfocus(self, msg):
|
|
#print "Component._win_wm_setfocus:", self ###
|
|
self.targeted()
|
|
return True
|
|
|
|
def targeted(self):
|
|
pass
|
|
|
|
def _win_wm_killfocus(self, msg):
|
|
#print "Component._win_wm_killfocus:", self ###
|
|
self.untargeted()
|
|
return True
|
|
|
|
def untargeted(self):
|
|
pass
|
|
|
|
def _win_on_ctlcolor(self, dc, typ):
|
|
pass
|
|
|
|
# def OnCtlColor(self, dc, comp, typ):
|
|
# #print "Component.OnCtlColor" ###
|
|
# meth = getattr(comp, '_win_on_ctlcolor', None)
|
|
# if meth:
|
|
# return meth(dc, typ)
|
|
|
|
def get_bounds(self):
|
|
return self._bounds
|
|
|
|
def set_bounds(self, rect):
|
|
self._win_move_window(rect)
|
|
self._win_change_bounds(rect)
|
|
|
|
def _win_change_bounds(self, rect):
|
|
l0, t0, r0, b0 = self._bounds
|
|
l1, t1, r1, b1 = rect
|
|
w0 = r0 - l0
|
|
h0 = b0 - t0
|
|
w1 = r1 - l1
|
|
h1 = b1 - t1
|
|
self._bounds = rect
|
|
if w0 != w1 or h0 != h1:
|
|
self._resized((w1 - w0, h1 - h0))
|
|
|
|
def _win_move_window(self, bounds):
|
|
container = self.container
|
|
if container:
|
|
rect = container._win_adjust_bounds(bounds)
|
|
self._win.MoveWindow(rect)
|
|
|
|
def _win_adjust_bounds(self, bounds):
|
|
# Scrollable views override this to adjust for the scroll offset.
|
|
return bounds
|
|
|
|
def _win_get_actual_bounds(self):
|
|
win = self._win
|
|
parent = win.GetParent()
|
|
sbounds = win.GetWindowRect()
|
|
return parent._win.ScreenToClient(sbounds)
|
|
|
|
def become_target(self):
|
|
#print "Component.become_target:", self ###
|
|
window = self.window
|
|
if window:
|
|
if window._win_is_active():
|
|
#print "...setting focus" ###
|
|
self._win.SetFocus()
|
|
else:
|
|
#print "...saving focus in", window ###
|
|
window._win_saved_target = self
|
|
|
|
def invalidate_rect(self, r):
|
|
#print "Component.invalidate_rect:", self, r ###
|
|
self._invalidate_rect(r)
|
|
if self._win_transparent:
|
|
cont = self.container
|
|
if cont:
|
|
cont.invalidate_rect(self.local_to_container(r))
|
|
|
|
def _invalidate_rect(self, r):
|
|
self._win.InvalidateRect(r)
|
|
|
|
def local_to_global(self, p):
|
|
return self._win.ClientToScreen(p)
|
|
|
|
def global_to_local(self, p):
|
|
return self._win.ScreenToClient(p)
|
|
|
|
def container_to_local(self, p):
|
|
return transform_coords(self.container, self, p)
|
|
|
|
def local_to_container(self, p):
|
|
return transform_coords(self, self.container, p)
|
|
|
|
def _win_event_message(self, message):
|
|
try:
|
|
if 0:
|
|
from WinUtils import win_message_name ###
|
|
print "Component._win_event_message: %s 0x%08x 0x%08x" % ( ###
|
|
win_message_name(message[1]),
|
|
message[2] & 0xffffffff,
|
|
message[3] & 0xffffffff) ###
|
|
event = win_message_to_event(message, self)
|
|
kind = event.kind
|
|
if kind.startswith('key') and message[2] in win_virt_modifiers:
|
|
# Do not produce Events for modifier keys
|
|
return True
|
|
if kind == 'mouse_down' and self._win_captures_mouse:
|
|
self._win.SetCapture()
|
|
if self._win_tracking_mouse:
|
|
if 'mouse' in kind:
|
|
self._win_mouse_event = event
|
|
api.PostQuitMessage(0)
|
|
pass_message = False
|
|
else:
|
|
if kind == 'key_down' and event.control and event.char:
|
|
key = win_translate_virtual_menu_key(message[2])
|
|
top = self._win.GetTopLevelFrame()
|
|
if top._win_possible_menu_key(key, event.shift, event.option):
|
|
return False
|
|
pass_message = not self._event_custom_handled(event)
|
|
if kind == 'mouse_up' and self._win_captures_mouse:
|
|
self._win.ReleaseCapture()
|
|
# #<<<
|
|
# if kind.startswith('key'):
|
|
# if pass_message:
|
|
# print "Component._win_event_message: passing", event ###
|
|
# else:
|
|
# print "Component._win_event_message: absorbing", event ###
|
|
# #>>>
|
|
return pass_message
|
|
except Cancel:
|
|
pass
|
|
except:
|
|
application().report_error()
|
|
# print "Component._win_event_message: Posting quit message with 1" ###
|
|
# api.PostQuitMessage(1)
|
|
|
|
def _win_dump_flags(self):
|
|
from WinUtils import win_deconstruct_style, win_deconstruct_style_ex
|
|
print "%s.%s: style:" % (self.__class__.__module__, self.__class__.__name__)
|
|
win_deconstruct_style(self._win.GetStyle())
|
|
win_deconstruct_style_ex(self._win.GetExStyle())
|
|
|
|
# def PreTranslateMessage(self, message):
|
|
# print "Component.PreTranslateMessage:", self, \
|
|
# message[0], win_message_name(message[1]), \
|
|
# message[2]
|
|
#
|
|
#from WinUtils import win_message_name
|
|
|
|
export(Component)
|