Lightningbeam/GUI/Win32/ScrollableView.py

179 lines
6.1 KiB
Python

#--------------------------------------------------------------------
#
# PyGUI - ScrollableView - Win32
#
#--------------------------------------------------------------------
import win32con as wc, win32ui as ui, win32gui as gui
from GUI import export
from GUI.WinUtils import win_plain_class, win_none
from GUI import Canvas
from GUI.GScrollableViews import ScrollableView as GScrollableView, \
default_extent, default_line_scroll_amount, default_scrolling
from GUI.Geometry import add_pt, sub_pt, offset_rect, offset_rect_neg
from GUI.GDrawableContainers import default_size
from GUI.Geometry import offset_rect_neg
win_style = wc.WS_CHILD | wc.WS_CLIPCHILDREN | wc.WS_CLIPSIBLINGS | \
wc.WS_VISIBLE ###| wc.WS_VSCROLL| wc.WS_HSCROLL
win_ex_style = 0 # wc.WS_EX_CLIENTEDGE
win_default_rect = (0, 0, default_size[0], default_size[1])
win_scroll_flags = wc.SW_INVALIDATE | wc.SW_SCROLLCHILDREN
win_swp_flags = wc.SWP_DRAWFRAME #| wc.SWP_FRAMECHANGED
class ScrollableView(GScrollableView):
_line_scroll_amount = default_line_scroll_amount
_extent = (500, 500)
def __init__(self, **kwds):
kwds.setdefault('border', True)
kwds.setdefault('extent', default_extent)
kwds.setdefault('scrolling', default_scrolling)
win = ui.CreateWnd()
win.CreateWindowEx(win_ex_style, win_plain_class, None, win_style, win_default_rect, win_none, 0)
win.HookMessage(self._win_wm_hscroll, wc.WM_HSCROLL)
win.HookMessage(self._win_wm_vscroll, wc.WM_VSCROLL)
GScrollableView.__init__(self, _win = win)
self.set(**kwds)
def get_hscrolling(self):
return self._win_get_flag(wc.WS_HSCROLL)
def get_vscrolling(self):
return self._win_get_flag(wc.WS_VSCROLL)
def set_hscrolling(self, x):
#print "ScrollableView.set_hscrolling:", x ###
self._win_set_flag(x, wc.WS_HSCROLL, win_swp_flags)
self._win_update_h_scrollbar()
def set_vscrolling(self, x):
#print "ScrollableView.set_vscrolling:", x ###
self._win_set_flag(x, wc.WS_VSCROLL, win_swp_flags)
self._win_update_v_scrollbar()
def set_border(self, x):
self._border = x
self._win_set_ex_flag(x, wc.WS_EX_CLIENTEDGE, win_swp_flags)
def get_line_scroll_amount(self):
return self._line_scroll_amount
def get_extent(self):
return self._extent
def set_extent(self, extent):
self._extent = extent
self._win_update_scroll_sizes()
def get_scroll_offset(self):
return self._h_scroll_offset, self._v_scroll_offset
def set_scroll_offset(self, p):
px = int(round(p[0]))
py = int(round(p[1]))
if px <> self._h_scroll_offset or py <> self._v_scroll_offset:
self._win_update_scroll_offset(px, py)
def _win_update_scroll_sizes(self):
self._win_update_scroll_offset(self._h_scroll_offset, self._v_scroll_offset)
def _win_update_scroll_offset(self, px, py):
ex, ey = self.extent
vx, vy = self.content_size
xmax = max(0, ex - vx)
ymax = max(0, ey - vy)
x = max(0, min(px, xmax))
y = max(0, min(py, ymax))
self._win_scroll_to(x, y)
self._win_update_h_scrollbar()
self._win_update_v_scrollbar()
def _win_update_h_scrollbar(self):
self._win_update_scrollbar(self.hscrolling, wc.SB_HORZ, 0)
def _win_update_v_scrollbar(self):
self._win_update_scrollbar(self.vscrolling, wc.SB_VERT, 1)
def _win_update_scrollbar(self, enabled, nbar, i):
# It is important not to update a disabled scrollbar, or
# subtle problems occur.
if enabled:
#print "ScrollableView._win_update_scrollbar:", enabled, nbar, i ###
f = wc.SIF_DISABLENOSCROLL
info = (f, 0, self.extent[i], self.content_size[i], self.scroll_offset[i])
self._win.SetScrollInfo(nbar, info, True)
def _scroll_range(self):
return (xmax, ymax)
def _win_scroll_to(self, x, y):
dx = self._h_scroll_offset - x
dy = self._v_scroll_offset - y
if dx or dy:
hwnd = self._win.GetSafeHwnd()
gui.ScrollWindowEx(hwnd, dx, dy, None, None, None, win_scroll_flags)
self._h_scroll_offset = x
self._v_scroll_offset = y
def set_bounds(self, bounds):
GScrollableView.set_bounds(self, bounds)
self._win_update_scroll_sizes()
def _invalidate_rect(self, r):
win = self._win
s = self.scroll_offset
self._win.InvalidateRect(offset_rect_neg(r, s))
def local_to_global(self, p):
q = sub_pt(p, self.scroll_offset)
return self._win.ClientToScreen(q)
def global_to_local(self, g):
q = self._win.ScreenToClient(g)
return add_pt(q, self.scroll_offset)
# def _win_prepare_dc(self, dc):
# dc.SetWindowOrg(self.scroll_offset)
def _win_scroll_offset(self):
return self.scroll_offset
def _win_wm_hscroll(self, message):
code = message[2] & 0xffff
if code == 0:
self.scroll_line_left()
elif code == 1:
self.scroll_line_right()
elif code == 2:
self.scroll_page_left()
elif code == 3:
self.scroll_page_right()
elif code == 5:
x = self._win_thumb_track_pos(wc.SB_HORZ)
self.scroll_offset = (x, self._v_scroll_offset)
def _win_wm_vscroll(self, message):
code = message[2] & 0xffff
if code == 0:
self.scroll_line_up()
elif code == 1:
self.scroll_line_down()
elif code == 2:
self.scroll_page_up()
elif code == 3:
self.scroll_page_down()
elif code == 5:
y = self._win_thumb_track_pos(wc.SB_VERT)
self.scroll_offset = (self._h_scroll_offset, y)
def _win_thumb_track_pos(self, nbar):
info = self._win.GetScrollInfo(nbar)
return info[5]
def _win_adjust_bounds(self, bounds):
return offset_rect_neg(bounds, self.scroll_offset)
export(ScrollableView)