#--------------------------------------------------------------------
#
#   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)
