diff --git a/Lib/lib-stdwin/Abstract.py b/Lib/lib-stdwin/Abstract.py new file mode 100644 index 00000000000..d6015271d9f --- /dev/null +++ b/Lib/lib-stdwin/Abstract.py @@ -0,0 +1,53 @@ +# Abstract classes for parents and children. +# Do not use as base class -- this is for documentation only. +# Note that the tree must be built top down. + +class AbstractParent(): + # + # Upcalls from child to parent + # + def addchild(self, child): unimpl() + def delchild(self, child): unimpl() + # + def need_mouse(self, child): unimpl() + def no_mouse(self, child): unimpl() + # + def need_timer(self, child): unimpl() + def no_timer(self, child): unimpl() + # + # XXX need_kbd, no_kbd; focus??? + # + def begindrawing(self): return unimpl() + def beginmeasuring(self): return unimpl() + # + def change(self, area): unimpl() + def scroll(self, (area, (dh, dv))): unimpl() + def settimer(self, itimer): unimpl() + +class AbstractChild(): + # + # Downcalls from parent to child + # + def destroy(self): unimpl() + # + def minsize(self, m): return unimpl() + def getbounds(self): return unimpl() + def setbounds(self, bounds): unimpl() + def draw(self, (d, area)): unimpl() + # + # Downcalls only made after certain upcalls + # + def mouse_down(self, detail): unimpl() + def mouse_move(self, detail): unimpl() + def mouse_up(self, detail): unimpl() + # + def timer(self): unimpl() + +# A "Split" is a child that manages one or more children. +# (This terminology is due to DEC SRC, except for CSplits.) +# A child of a split may be another split, a button, a slider, etc. +# Certain upcalls and downcalls can be handled transparently, but +# for others (e.g., all geometry related calls) this is not possible. + +class AbstractSplit() = AbstractChild(), AbstractParent(): + pass diff --git a/Lib/lib-stdwin/HVSplit.py b/Lib/lib-stdwin/HVSplit.py new file mode 100644 index 00000000000..2ee18f288b7 --- /dev/null +++ b/Lib/lib-stdwin/HVSplit.py @@ -0,0 +1,52 @@ +# HVSplit contains generic code for HSplit and VSplit. +# HSplit and VSplit are specializations to either dimension. + +from Split import Split + +class HVSplit() = Split(): + # + def create(self, (parent, hv)): + # hv is 0 or 1 for HSplit or VSplit + self = Split.create(self, parent) + self.hv = hv + return self + # + def minsize(self, m): + hv, vh = self.hv, 1 - self.hv + size = [0, 0] + for c in self.children: + csize = c.minsize(m) + if csize[vh] > size[vh]: size[vh] = csize[vh] + size[hv] = size[hv] + csize[hv] + return size[0], size[1] + # + def getbounds(self): + return self.bounds + # + def setbounds(self, bounds): + self.bounds = bounds + hv, vh = self.hv, 1 - self.hv + mf = self.parent.beginmeasuring + size = self.minsize(mf()) + # XXX not yet used! Later for stretching + maxsize_hv = bounds[1][hv] - bounds[0][hv] + origin = [self.bounds[0][0], self.bounds[0][1]] + for c in self.children: + size = c.minsize(mf()) + corner = [0, 0] + corner[vh] = bounds[1][vh] + corner[hv] = origin[hv] + size[hv] + c.setbounds((origin[0], origin[1]), \ + (corner[0], corner[1])) + origin[hv] = corner[hv] + # XXX stretch + # XXX too-small + # + +class HSplit() = HVSplit(): + def create(self, parent): + return HVSplit.create(self, (parent, 0)) + +class VSplit() = HVSplit(): + def create(self, parent): + return HVSplit.create(self, (parent, 1)) diff --git a/Lib/lib-stdwin/Split.py b/Lib/lib-stdwin/Split.py new file mode 100644 index 00000000000..c442fe3ef0a --- /dev/null +++ b/Lib/lib-stdwin/Split.py @@ -0,0 +1,113 @@ +# Generic Split implementation. +# Use as a base class for other splits. + +Error = 'Split.Error' # Exception + +import rect +from util import remove + +class Split(): + # + # Calls from creator + # NB derived classes may add parameters to create() + # + def create(self, parent): + parent.addchild(self) + self.parent = parent + self.children = [] + self.mouse_interest = [] + self.timer_interest = [] + self.mouse_focus = 0 + return self + # + # Downcalls from parent to child + # + def destroy(self): + self.parent = 0 + for child in self.children: + child.destroy() + self.children[:] = [] + self.mouse_interest[:] = [] + self.timer_interest[:] = [] + self.mouse_focus = 0 + # + def minsize(self, m): return unimpl() + def getbounds(self): return unimpl() + def setbounds(self, bounds): unimpl() + def draw(self, args): + # (Could avoid calls to children outside the area) + for child in self.children: + child.draw(args) + # + # Downcalls only made after certain upcalls + # + def mouse_down(self, detail): + if self.mouse_focus: + self.mouse_focus.mouse_down(detail) + p = detail[0] + for child in self.mouse_interest: + if rect.pointinrect(p, child.getbounds()): + self.mouse_focus = child + child.mouse_down(detail) + def mouse_move(self, detail): + if self.mouse_focus: + self.mouse_focus.mouse_move(detail) + def mouse_up(self, detail): + if self.mouse_focus: + self.mouse_focus.mouse_up(detail) + self.mouse_focus = 0 + # + def timer(self): + for child in self.timer_interest: + child.timer() + # + # Upcalls from child to parent + # + def addchild(self, child): + if child in self.children: + raise Error, 'addchild: child already inlist' + self.children.append(child) + def delchild(self, child): + if child not in self.children: + raise Error, 'delchild: child not in list' + remove(child, self.children) + if child in self.mouse_interest: + remove(child, self.mouse_interest) + if child in self.timer_interest: + remove(child, self.timer_interest) + if child = self.mouse_focus: + self.mouse_focus = 0 + # + def need_mouse(self, child): + if child not in self.mouse_interest: + self.mouse_interest.append(child) + self.parent.need_mouse(self) + def no_mouse(self, child): + if child in self.mouse_interest: + remove(child, self.mouse_interest) + if not self.mouse_interest: + self.parent.no_mouse(self) + # + def need_timer(self, child): + if child not in self.timer_interest: + self.timer_interest.append(child) + self.parent.need_timer(self) + def no_timer(self, child): + if child in self.timer_interest: + remove(child, self.timer_interest) + if not self.timer_interest: + self.parent.no_timer(self) + # + # The rest are transparent: + # + def begindrawing(self): + return self.parent.begindrawing() + def beginmeasuring(self): + return self.parent.beginmeasuring() + # + def change(self, area): + self.parent.change(area) + def scroll(self, args): + self.parent.scroll(args) + def settimer(self, itimer): + self.parent.settimer(itimer) diff --git a/Lib/lib-stdwin/TransParent.py b/Lib/lib-stdwin/TransParent.py new file mode 100644 index 00000000000..8cee28318b3 --- /dev/null +++ b/Lib/lib-stdwin/TransParent.py @@ -0,0 +1,96 @@ +# A class that sits transparently between a parent and one child. +# First create the parent, then this thing, then the child. +# Use this as a base class for objects that are almost transparent. +# Don't use as a base class for parents with multiple children. + +Error = 'TransParent.Error' # Exception + +class ManageOneChild(): + # + # Upcalls shared with other single-child parents + # + def addchild(self, child): + if self.child: + raise Error, 'addchild: one child only' + if not child: + raise Error, 'addchild: bad child' + self.child = child + # + def delchild(self, child): + if not self.child: + raise Error, 'delchild: no child' + if child <> self.child: + raise Error, 'delchild: not my child' + self.child = 0 + +class TransParent() = ManageOneChild(): + # + # Calls from creator + # NB derived classes may add parameters to create() + # + def create(self, parent): + parent.addchild(self) + self.parent = parent + self.child = 0 # No child yet + # + # Downcalls from parent to child + # + def destroy(self): + del self.parent + if self.child: self.child.destroy() + del self.child + # + def minsize(self, m): + if not self.child: + return 0, 0 + else: + return self.child.minsize(m) + def getbounds(self, bounds): + if not self.child: + raise Error, 'getbounds w/o child' + else: + return self.child.getbounds() + def setbounds(self, bounds): + if not self.child: + raise Error, 'setbounds w/o child' + else: + self.child.setbounds(bounds) + def draw(self, args): + if self.child: + self.child.draw(args) + # + # Downcalls only made after certain upcalls + # + def mouse_down(self, detail): + if self.child: self.child.mouse_down(detail) + def mouse_move(self, detail): + if self.child: self.child.mouse_move(detail) + def mouse_up(self, detail): + if self.child: self.child.mouse_up(detail) + # + def timer(self): + if self.child: self.child.timer() + # + # Upcalls from child to parent + # + def need_mouse(self, child): + self.parent.need_mouse(self) + def no_mouse(self, child): + self.parent.no_mouse(self) + # + def need_timer(self, child): + self.parent.need_timer(self) + def no_timer(self, child): + self.parent.no_timer(self) + # + def begindrawing(self): + return self.parent.begindrawing() + def beginmeasuring(self): + return self.parent.beginmeasuring() + # + def change(self, area): + self.parent.change(area) + def scroll(self, args): + self.parent.scroll(args) + def settimer(self, itimer): + self.parent.settimer(itimer) diff --git a/Lib/lib-stdwin/WindowParent.py b/Lib/lib-stdwin/WindowParent.py new file mode 100644 index 00000000000..39838f78854 --- /dev/null +++ b/Lib/lib-stdwin/WindowParent.py @@ -0,0 +1,92 @@ +# A 'WindowParent' is the only module that uses real stdwin functionality. +# It is the root of the tree. +# It should have exactly one child when realized. + +import stdwin +from stdwinevents import * + +from TransParent import ManageOneChild + +Error = 'WindowParent.Error' # Exception + +class WindowParent() = ManageOneChild(): + # + def create(self, (title, size)): + self.title = title + self.size = size # (width, height) + self.child = 0 # i.e., no child yet + self.win = 0 # i.e., no window yet + self.itimer = 0 + self.do_mouse = 0 + self.do_timer = 0 + return self + # + def need_mouse(self, child): self.do_mouse = 1 + def no_mouse(self, child): self.do_mouse = 0 + # + def need_timer(self, child): self.do_timer = 1 + def no_timer(self, child): self.do_timer = 0 + # + def realize(self): + if self.win: + raise Error, 'realize(): called twice' + if not self.child: + raise Error, 'realize(): no child' + size = self.child.minsize(self.beginmeasuring()) + self.size = max(self.size[0], size[0]), \ + max(self.size[1], size[1]) + stdwin.setdefwinsize(self.size) + self.win = stdwin.open(self.title) + if self.itimer: + self.win.settimer(self.itimer) + bounds = (0, 0), self.win.getwinsize() + self.child.setbounds(bounds) + # + def beginmeasuring(self): + # Return something with which a child can measure text + if self.win: + return self.win.begindrawing() + else: + return stdwin + # + def begindrawing(self): + if self.win: + return self.win.begindrawing() + else: + raise Error, 'begindrawing(): not realized yet' + # + def change(self, area): + if self.win: + self.win.change(area) + # + def scroll(self, args): + if self.win: + self.win.scroll(args) + # + def settimer(self, itimer): + if self.win: + self.win.settimer(itimer) + else: + self.itimer = itimer + # + # Only call dispatch if we have a child + # + def dispatch(self, (type, win, detail)): + if win <> self.win: + return + elif type = WE_DRAW: + d = self.win.begindrawing() + self.child.draw(d, detail) + elif type = WE_MOUSE_DOWN: + if self.do_mouse: self.child.mouse_down(detail) + elif type = WE_MOUSE_MOVE: + if self.do_mouse: self.child.mouse_move(detail) + elif type = WE_MOUSE_UP: + if self.do_mouse: self.child.mouse_up(detail) + elif type = WE_TIMER: + if self.do_timer: self.child.timer() + elif type = WE_SIZE: + self.win.change((0, 0), (10000, 10000)) # XXX + bounds = (0, 0), self.win.getwinsize() + self.child.setbounds(bounds) + # diff --git a/Lib/stdwin/Abstract.py b/Lib/stdwin/Abstract.py new file mode 100755 index 00000000000..d6015271d9f --- /dev/null +++ b/Lib/stdwin/Abstract.py @@ -0,0 +1,53 @@ +# Abstract classes for parents and children. +# Do not use as base class -- this is for documentation only. +# Note that the tree must be built top down. + +class AbstractParent(): + # + # Upcalls from child to parent + # + def addchild(self, child): unimpl() + def delchild(self, child): unimpl() + # + def need_mouse(self, child): unimpl() + def no_mouse(self, child): unimpl() + # + def need_timer(self, child): unimpl() + def no_timer(self, child): unimpl() + # + # XXX need_kbd, no_kbd; focus??? + # + def begindrawing(self): return unimpl() + def beginmeasuring(self): return unimpl() + # + def change(self, area): unimpl() + def scroll(self, (area, (dh, dv))): unimpl() + def settimer(self, itimer): unimpl() + +class AbstractChild(): + # + # Downcalls from parent to child + # + def destroy(self): unimpl() + # + def minsize(self, m): return unimpl() + def getbounds(self): return unimpl() + def setbounds(self, bounds): unimpl() + def draw(self, (d, area)): unimpl() + # + # Downcalls only made after certain upcalls + # + def mouse_down(self, detail): unimpl() + def mouse_move(self, detail): unimpl() + def mouse_up(self, detail): unimpl() + # + def timer(self): unimpl() + +# A "Split" is a child that manages one or more children. +# (This terminology is due to DEC SRC, except for CSplits.) +# A child of a split may be another split, a button, a slider, etc. +# Certain upcalls and downcalls can be handled transparently, but +# for others (e.g., all geometry related calls) this is not possible. + +class AbstractSplit() = AbstractChild(), AbstractParent(): + pass diff --git a/Lib/stdwin/HVSplit.py b/Lib/stdwin/HVSplit.py new file mode 100755 index 00000000000..2ee18f288b7 --- /dev/null +++ b/Lib/stdwin/HVSplit.py @@ -0,0 +1,52 @@ +# HVSplit contains generic code for HSplit and VSplit. +# HSplit and VSplit are specializations to either dimension. + +from Split import Split + +class HVSplit() = Split(): + # + def create(self, (parent, hv)): + # hv is 0 or 1 for HSplit or VSplit + self = Split.create(self, parent) + self.hv = hv + return self + # + def minsize(self, m): + hv, vh = self.hv, 1 - self.hv + size = [0, 0] + for c in self.children: + csize = c.minsize(m) + if csize[vh] > size[vh]: size[vh] = csize[vh] + size[hv] = size[hv] + csize[hv] + return size[0], size[1] + # + def getbounds(self): + return self.bounds + # + def setbounds(self, bounds): + self.bounds = bounds + hv, vh = self.hv, 1 - self.hv + mf = self.parent.beginmeasuring + size = self.minsize(mf()) + # XXX not yet used! Later for stretching + maxsize_hv = bounds[1][hv] - bounds[0][hv] + origin = [self.bounds[0][0], self.bounds[0][1]] + for c in self.children: + size = c.minsize(mf()) + corner = [0, 0] + corner[vh] = bounds[1][vh] + corner[hv] = origin[hv] + size[hv] + c.setbounds((origin[0], origin[1]), \ + (corner[0], corner[1])) + origin[hv] = corner[hv] + # XXX stretch + # XXX too-small + # + +class HSplit() = HVSplit(): + def create(self, parent): + return HVSplit.create(self, (parent, 0)) + +class VSplit() = HVSplit(): + def create(self, parent): + return HVSplit.create(self, (parent, 1)) diff --git a/Lib/stdwin/Split.py b/Lib/stdwin/Split.py new file mode 100755 index 00000000000..c442fe3ef0a --- /dev/null +++ b/Lib/stdwin/Split.py @@ -0,0 +1,113 @@ +# Generic Split implementation. +# Use as a base class for other splits. + +Error = 'Split.Error' # Exception + +import rect +from util import remove + +class Split(): + # + # Calls from creator + # NB derived classes may add parameters to create() + # + def create(self, parent): + parent.addchild(self) + self.parent = parent + self.children = [] + self.mouse_interest = [] + self.timer_interest = [] + self.mouse_focus = 0 + return self + # + # Downcalls from parent to child + # + def destroy(self): + self.parent = 0 + for child in self.children: + child.destroy() + self.children[:] = [] + self.mouse_interest[:] = [] + self.timer_interest[:] = [] + self.mouse_focus = 0 + # + def minsize(self, m): return unimpl() + def getbounds(self): return unimpl() + def setbounds(self, bounds): unimpl() + def draw(self, args): + # (Could avoid calls to children outside the area) + for child in self.children: + child.draw(args) + # + # Downcalls only made after certain upcalls + # + def mouse_down(self, detail): + if self.mouse_focus: + self.mouse_focus.mouse_down(detail) + p = detail[0] + for child in self.mouse_interest: + if rect.pointinrect(p, child.getbounds()): + self.mouse_focus = child + child.mouse_down(detail) + def mouse_move(self, detail): + if self.mouse_focus: + self.mouse_focus.mouse_move(detail) + def mouse_up(self, detail): + if self.mouse_focus: + self.mouse_focus.mouse_up(detail) + self.mouse_focus = 0 + # + def timer(self): + for child in self.timer_interest: + child.timer() + # + # Upcalls from child to parent + # + def addchild(self, child): + if child in self.children: + raise Error, 'addchild: child already inlist' + self.children.append(child) + def delchild(self, child): + if child not in self.children: + raise Error, 'delchild: child not in list' + remove(child, self.children) + if child in self.mouse_interest: + remove(child, self.mouse_interest) + if child in self.timer_interest: + remove(child, self.timer_interest) + if child = self.mouse_focus: + self.mouse_focus = 0 + # + def need_mouse(self, child): + if child not in self.mouse_interest: + self.mouse_interest.append(child) + self.parent.need_mouse(self) + def no_mouse(self, child): + if child in self.mouse_interest: + remove(child, self.mouse_interest) + if not self.mouse_interest: + self.parent.no_mouse(self) + # + def need_timer(self, child): + if child not in self.timer_interest: + self.timer_interest.append(child) + self.parent.need_timer(self) + def no_timer(self, child): + if child in self.timer_interest: + remove(child, self.timer_interest) + if not self.timer_interest: + self.parent.no_timer(self) + # + # The rest are transparent: + # + def begindrawing(self): + return self.parent.begindrawing() + def beginmeasuring(self): + return self.parent.beginmeasuring() + # + def change(self, area): + self.parent.change(area) + def scroll(self, args): + self.parent.scroll(args) + def settimer(self, itimer): + self.parent.settimer(itimer) diff --git a/Lib/stdwin/TransParent.py b/Lib/stdwin/TransParent.py new file mode 100755 index 00000000000..8cee28318b3 --- /dev/null +++ b/Lib/stdwin/TransParent.py @@ -0,0 +1,96 @@ +# A class that sits transparently between a parent and one child. +# First create the parent, then this thing, then the child. +# Use this as a base class for objects that are almost transparent. +# Don't use as a base class for parents with multiple children. + +Error = 'TransParent.Error' # Exception + +class ManageOneChild(): + # + # Upcalls shared with other single-child parents + # + def addchild(self, child): + if self.child: + raise Error, 'addchild: one child only' + if not child: + raise Error, 'addchild: bad child' + self.child = child + # + def delchild(self, child): + if not self.child: + raise Error, 'delchild: no child' + if child <> self.child: + raise Error, 'delchild: not my child' + self.child = 0 + +class TransParent() = ManageOneChild(): + # + # Calls from creator + # NB derived classes may add parameters to create() + # + def create(self, parent): + parent.addchild(self) + self.parent = parent + self.child = 0 # No child yet + # + # Downcalls from parent to child + # + def destroy(self): + del self.parent + if self.child: self.child.destroy() + del self.child + # + def minsize(self, m): + if not self.child: + return 0, 0 + else: + return self.child.minsize(m) + def getbounds(self, bounds): + if not self.child: + raise Error, 'getbounds w/o child' + else: + return self.child.getbounds() + def setbounds(self, bounds): + if not self.child: + raise Error, 'setbounds w/o child' + else: + self.child.setbounds(bounds) + def draw(self, args): + if self.child: + self.child.draw(args) + # + # Downcalls only made after certain upcalls + # + def mouse_down(self, detail): + if self.child: self.child.mouse_down(detail) + def mouse_move(self, detail): + if self.child: self.child.mouse_move(detail) + def mouse_up(self, detail): + if self.child: self.child.mouse_up(detail) + # + def timer(self): + if self.child: self.child.timer() + # + # Upcalls from child to parent + # + def need_mouse(self, child): + self.parent.need_mouse(self) + def no_mouse(self, child): + self.parent.no_mouse(self) + # + def need_timer(self, child): + self.parent.need_timer(self) + def no_timer(self, child): + self.parent.no_timer(self) + # + def begindrawing(self): + return self.parent.begindrawing() + def beginmeasuring(self): + return self.parent.beginmeasuring() + # + def change(self, area): + self.parent.change(area) + def scroll(self, args): + self.parent.scroll(args) + def settimer(self, itimer): + self.parent.settimer(itimer) diff --git a/Lib/stdwin/WindowParent.py b/Lib/stdwin/WindowParent.py new file mode 100755 index 00000000000..39838f78854 --- /dev/null +++ b/Lib/stdwin/WindowParent.py @@ -0,0 +1,92 @@ +# A 'WindowParent' is the only module that uses real stdwin functionality. +# It is the root of the tree. +# It should have exactly one child when realized. + +import stdwin +from stdwinevents import * + +from TransParent import ManageOneChild + +Error = 'WindowParent.Error' # Exception + +class WindowParent() = ManageOneChild(): + # + def create(self, (title, size)): + self.title = title + self.size = size # (width, height) + self.child = 0 # i.e., no child yet + self.win = 0 # i.e., no window yet + self.itimer = 0 + self.do_mouse = 0 + self.do_timer = 0 + return self + # + def need_mouse(self, child): self.do_mouse = 1 + def no_mouse(self, child): self.do_mouse = 0 + # + def need_timer(self, child): self.do_timer = 1 + def no_timer(self, child): self.do_timer = 0 + # + def realize(self): + if self.win: + raise Error, 'realize(): called twice' + if not self.child: + raise Error, 'realize(): no child' + size = self.child.minsize(self.beginmeasuring()) + self.size = max(self.size[0], size[0]), \ + max(self.size[1], size[1]) + stdwin.setdefwinsize(self.size) + self.win = stdwin.open(self.title) + if self.itimer: + self.win.settimer(self.itimer) + bounds = (0, 0), self.win.getwinsize() + self.child.setbounds(bounds) + # + def beginmeasuring(self): + # Return something with which a child can measure text + if self.win: + return self.win.begindrawing() + else: + return stdwin + # + def begindrawing(self): + if self.win: + return self.win.begindrawing() + else: + raise Error, 'begindrawing(): not realized yet' + # + def change(self, area): + if self.win: + self.win.change(area) + # + def scroll(self, args): + if self.win: + self.win.scroll(args) + # + def settimer(self, itimer): + if self.win: + self.win.settimer(itimer) + else: + self.itimer = itimer + # + # Only call dispatch if we have a child + # + def dispatch(self, (type, win, detail)): + if win <> self.win: + return + elif type = WE_DRAW: + d = self.win.begindrawing() + self.child.draw(d, detail) + elif type = WE_MOUSE_DOWN: + if self.do_mouse: self.child.mouse_down(detail) + elif type = WE_MOUSE_MOVE: + if self.do_mouse: self.child.mouse_move(detail) + elif type = WE_MOUSE_UP: + if self.do_mouse: self.child.mouse_up(detail) + elif type = WE_TIMER: + if self.do_timer: self.child.timer() + elif type = WE_SIZE: + self.win.change((0, 0), (10000, 10000)) # XXX + bounds = (0, 0), self.win.getwinsize() + self.child.setbounds(bounds) + #