summaryrefslogtreecommitdiff
path: root/ipl/gprocs/vframe.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/gprocs/vframe.icn')
-rw-r--r--ipl/gprocs/vframe.icn355
1 files changed, 355 insertions, 0 deletions
diff --git a/ipl/gprocs/vframe.icn b/ipl/gprocs/vframe.icn
new file mode 100644
index 0000000..0ac2a1a
--- /dev/null
+++ b/ipl/gprocs/vframe.icn
@@ -0,0 +1,355 @@
+############################################################################
+#
+# File: vframe.icn
+#
+# Subject: Procedures for pane frame vidgets
+#
+# Author: Jon Lipp
+#
+# Date: May 2, 2001
+#
+############################################################################
+#
+# This file is in the public domain.
+#
+############################################################################
+#
+# Vidgets defined in this file:
+#
+# Vframe
+# Vroot_frame
+#
+# Utility procedures in this file:
+#
+# Vmin_frame_width()
+# Vmin_frame_height()
+#
+############################################################################
+#
+# Requires: Version 9 graphics
+#
+############################################################################
+#
+# Links: vidgets
+#
+############################################################################
+
+link vidgets
+
+############################################################################
+# frame vidget -
+# Keeps track of panes. Frames can contain
+# sub-frames in a hierarchy. Frames know their own absolute
+# coordinates and the relative sizes and positions of their
+# children (panes and sub-frames). They determine positioning
+# and size of each child, and route events.
+############################################################################
+
+record Vframe_rec(win, aw, ah, callback, id, lookup, draw, ax, ay,
+ uid, P, F, V)
+
+#
+# Creation procedure for a Vframe.
+# Specify its "own" utility procedures (V field).
+# Specify "special" procedures (format, in F field).
+# Get a unique id (uid).
+# check implicit insertion, insert if necessary.
+#
+procedure Vframe(params[])
+ local self, procs, spec_procs, frame, x, y, ins
+
+ procs := Vstd(event_Vframe, draw_Vframe, outline_Vidget,
+ resize_Vframe, inrange_Vpane, init_Vframe,
+ couplerset_Vpane, insert_Vframe, remove_Vframe,
+ lookup_Vframe, set_abs_Vframe)
+ spec_procs := Vstd_dialog( , , format_Vframe)
+
+ if ins := Vinsert_check(params) then {
+ frame := pop(params); x := pop(params); y:= pop(params)
+ }
+ self := Vframe_rec ! params[1:6|0]
+ Vwin_check(self.win, "Vframe()")
+ if (\self.aw, not numeric(self.aw) ) then
+ _Vbomb("invalid aw parameter to Vframe()")
+ if (\self.ah, not numeric(self.ah) ) then
+ _Vbomb("invalid ah parameter to Vframe()")
+
+ self.uid := Vget_uid()
+ self.V := procs
+ self.F := spec_procs
+ self.P := Vstd_pos()
+ self.V.init(self)
+ if \ins then VInsert(frame, self, x, y)
+ return self
+end
+
+#
+# Initialize procedure for Vframe. Other frame types call this.
+#
+procedure init_Vframe(s)
+ s.lookup := []
+ s.draw := []
+end
+
+#
+# draw the contents of the frame.
+#
+procedure draw_Vframe(s, erased)
+local p
+
+# PMIcon: fixed bug; drawig before resize.
+ if /s.aw | /s.ah then _Vbomb("frame not resized yet")
+ /erased & EraseArea(s.win, s.ax, s.ay, s.aw, s.ah)
+ every p := !s.draw do p.V.draw(p, "erased")
+ s.V.outline(s)
+end
+
+#
+# Set the absolute coordinates of everything on the draw list;
+# Don't do it for Vline, it is special.
+# It used to be that if the vidget is a Vpane,
+# a resize event was sent, so that it would notify its callback.
+# That "feature" has been commented out in the code below.
+#
+procedure resize_Vframe(s, x,y,wid,h)
+ local w, slots
+ static type
+
+ initial type := proc("type", 0) # protect attractive name
+
+ resize_Vidget(s, x, y, wid, h)
+ every w := !s.draw do {
+ if (type(w) == "Vline_rec") then
+ w.V.resize(s, w)
+ else s.V.set_abs(s, w)
+# if type(w) == "Vpane_rec" then
+# w.V.event(w, -10)
+ }
+end
+#
+# Determine the absolute coordinates of a vdiget based on its parent
+# frame's absolute coordinates, and the "virtual" coordinates passed
+# in upon creation.
+# Allows for the fact that a pane can have relative
+# position and size constraints intertwined with absolute.
+#
+procedure set_abs_Vframe(s, vid)
+local ax,ay,aw,ah, a, b, w, h, vx, vy, vw, vh
+ static type
+
+ initial type := proc("type", 0) # protect attractive name
+
+ w := s.aw; h := s.ah
+ vx := vid.P.x; vy := vid.P.y
+ vw := vid.P.w; vh := vid.P.h
+
+ ax := s.ax + ( (vx <= -1, w + vx - (\vid.aw | 0)) |
+ (type(vx) == "real",
+ (-1 <= vx < 0, w - vx*w) |
+ (0 < vx <= 1, vx*w) ) | vx )
+ ay := s.ay + ( (vy <= -1, h + vy - (\vid.ah | 0)) |
+ (type(vy) == "real",
+ (-1 <= vy < 0, h - vy*h) |
+ (0 < vy <= 1, vy*h) ) | vy )
+
+ aw := (\vw, (type(vw) == "real", 0 < vw <= 1, vw*w) |
+ vw) | \vid.aw | w
+ ah := (\vh, (type(vh) == "real", 0 < vh <= 1, vh*h) |
+ vh) | \vid.ah | h
+ aw := integer(aw)
+ ah := integer(ah)
+
+## don't let kid be bigger than the frame.
+ if (a := aw + ax) > (b := s.aw + s.ax) then aw -:= (a-b)
+ if (a := ah + ay) > (b := s.ah + s.ay) then ah -:= (a-b)
+ vid.V.resize(vid, ax, ay, aw, ah)
+end
+
+#
+# Don't erase the vidget if erase is non-&null.
+#
+procedure remove_Vframe(s, pane, erase)
+local new, k
+
+ new := []
+ every k := !s.lookup do if k ~=== pane then put(new,k)
+ s.lookup := new
+ new := []
+ every k := !s.draw do if k ~=== pane then put(new,k)
+ s.draw := new
+
+ if /erase then VErase(pane)
+end
+
+#
+# Insert a vidget into a frame.
+#
+procedure insert_Vframe(s, pane, x, y, w, h)
+local wc
+static image
+
+ initial image := proc("image", 0) # protet attractive name
+
+#defaults
+ /x := 0
+ /y := 0
+ /w := \pane.aw
+ /h := \pane.ah
+ pane.P.x := x
+ pane.P.y := y
+ pane.P.w := w
+ pane.P.h := h
+ put(s.draw, pane)
+ if not (image(pane.V.event) ? find("null_proc") ) then
+ put(s.lookup, pane)
+ if (\s.ax, \s.ay, \s.aw, s.ah) then { # is this frame sized yet
+ if (type(pane) == "Vline_rec") then
+ pane.V.resize(s, pane)
+ else
+ s.V.set_abs(s, pane)
+ }
+end
+
+#
+# Get events, lookup vidget based on (x, y), call its event loop.
+#
+procedure event_Vframe(s, e, x, y)
+local dest
+
+ if dest := s.V.lookup(s, x, y) then {
+ return dest.V.event(dest, e, x, y)
+ }
+end
+
+#
+# For every vidget on lookup list, check if (x, y) lie within its
+# boundaries. Doesn't address overlapping vidgets.
+#
+procedure lookup_Vframe(s, x, y)
+local w
+
+ every w := !s.lookup do
+ if w.V.inrange(w, x, y) then
+ return w
+end
+
+#
+# Determine and set the minimum bounding rectangle which encompasses
+# all vidgets within the frame. Restriction is that all vidgies must have
+# been inserted with absolute coordinates and sizes.
+#
+procedure format_Vframe(self)
+ resize_Vidget(self, , , Vmin_frame_width(self), Vmin_frame_height(self))
+end
+
+
+############################################################################
+# Vroot_frame -
+# Root of the X-Idol event window demultiplexing recordes.
+# The root_frame record serves as the root for windows that are
+# subdivided.
+############################################################################
+
+procedure Vroot_frame(params[])
+ local self
+ static procs, spec_procs
+
+ initial {
+ procs := Vstd(event_Vroot_frame, draw_Vframe, null_proc,
+ resize_Vroot_frame, inrange_Vpane, init_Vroot_frame,
+ couplerset_Vpane, insert_Vframe, remove_Vframe,
+ lookup_Vframe, set_abs_Vframe)
+ spec_procs := Vstd_dialog( , , format_Vframe)
+
+ VInit()
+ }
+
+ self := Vframe_rec ! params[1:2|0]
+ Vwin_check(self.win, "Vroot_frame()")
+ self.uid := Vget_uid()
+ self.V := procs
+ self.F := spec_procs
+ self.P := Vstd_pos()
+ self.V.init(self)
+ return self
+end
+
+procedure init_Vroot_frame(s)
+ s.ax := s.ay := 0
+ init_Vframe(s)
+end
+
+#
+# Process events (same as for a frame). Difference, is if we get a resize,
+# resize all vidgets within, and redraw screen (no lookup performed).
+#
+procedure event_Vroot_frame(s,e,x,y)
+local dest
+
+ if e === &resize then {
+ s.V.resize(s)
+ return &null
+ }
+ else {
+ if dest:= s.V.lookup(s,x,y) then
+ return dest.V.event(dest,e,x,y)
+ else fail
+ }
+end
+
+#
+# The window was resized! Well... reconfigure all the absolute
+# position and sizes for all panes. This benefits relative values
+# the most.
+#
+procedure resize_Vroot_frame(s)
+
+ s.aw := WAttrib(s.win, "width")
+ s.ah := WAttrib(s.win, "height")
+ resize_Vframe(s, s.ax, s.ay, s.aw, s.ah)
+ s.V.draw(s)
+end
+
+############################################################################
+# Utility procedures for frames.
+############################################################################
+
+#
+# Min--- returns the minimum size of the frame that will encase all
+# children. NOTE - this can only be determined if all the children
+# were inserted with absolute co-ords and sizes. I.e. positive and
+# integral x, y, w, & h.
+#
+procedure Vmin_frame_width(s)
+ local max, vid
+ static type
+
+ initial type := proc("type", 0) # protect attractive name
+
+ max := 2
+ every vid := (!s.draw) do
+ if (type(vid) ~== "Vline_rec") then {
+ if type(vid.P.x) == "real" | type(vid.P.w) == "real" |
+ vid.P.x < 0 | vid.P.w < 0 then
+ _Vbomb("attempt to format a frame with non-absolute sized and positioned children")
+ max <:= (vid.P.x + vid.P.w )
+ }
+ return max
+end
+
+procedure Vmin_frame_height(s)
+ local max, vid
+ static type
+
+ initial type := proc("type", 0) # protect attractive name
+
+ max := 2
+ every vid := (!s.draw) do
+ if (type(vid) ~== "Vline_rec") then {
+ if type(vid.P.y) == "real" | type(vid.P.h) == "real" |
+ vid.P.y < 0 | vid.P.h < 0 then
+ _Vbomb("attempt to format a frame with non-absolute sized and positioned children")
+ max <:= (vid.P.y + vid.P.h )
+ }
+ return max
+end