home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.cs.arizona.edu
/
ftp.cs.arizona.edu.tar
/
ftp.cs.arizona.edu
/
icon
/
historic
/
v941.tgz
/
icon.v941src.tar
/
icon.v941src
/
ipl
/
gprocs
/
vtext.icn
< prev
next >
Wrap
Text File
|
2000-07-29
|
13KB
|
479 lines
############################################################################
#
# File: vtext.icn
#
# Subject: Procedures for textual vidgets
#
# Authors: Jon Lipp and Gregg M. Townsend
#
# Date: July 22, 1997
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# Vidgets defined in this file:
# Vtext
#
############################################################################
#
# Requires: Version 9 graphics
#
############################################################################
#
# Includes: keysyms
#
############################################################################
#
# Links: vidgets
#
############################################################################
link vidgets
$include "keysyms.icn"
$ifndef _X_WINDOW_SYSTEM
$define Key_KP_Up Key_Up
$define Key_KP_Down Key_Down
$define Key_KP_Left Key_Left
$define Key_KP_Right Key_Right
$endif
############################################################################
# Vtext
############################################################################
record Vstd_text(draw_cursor, erase_cursor, draw_data, unblock, block,
DataPixelSize, MaxPixelSize, NumericData, CursorPos, DataLength,
OldCursorPos, CursorOn, ta, tb, dx, dy)
record Vtext_rec (win, s, callback, id, MaxChars, mask, data, uid,
ax, ay, aw, ah, T, P, V)
procedure Vtext(params[])
local frame, x, y, ins, self
static procs, type
initial {
procs := Vstd(event_Vtext, draw_Vtext,
outline_Vtext, resize_Vtext, inrange_Vpane, init_Vtext,
couplerset_Vtext,,,,, set_value_Vtext)
type := proc("type", 0) # protect attractive name
}
if ins := Vinsert_check(params) then {
frame := pop(params); x := pop(params); y:= pop(params)
}
self := Vtext_rec ! params[1:7|0]
Vwin_check(self.win, "Vtext()")
if (\self.MaxChars, not numeric(self.MaxChars) ) then
_Vbomb("invalid size parameter to Vtext()")
if type(\self.mask) ~== "cset" then
_Vbomb("invalid mask parameter to Vtext()")
if type(\self.s) ~== "string" & not numeric(self.s) then
_Vbomb("invalid prompt passed to Vtext()")
self.uid := Vget_uid()
self.V := procs
self.P := Vstd_pos()
self.T := Vstd_text(draw_cursor_Vtext, erase_cursor_Vtext,
draw_data_Vtext, unblock_Vtext, block_Vtext)
init_Vtext(self)
if \ins then VInsert(frame, self, x, y)
return self
end
#
# Initialization
#
procedure init_Vtext(self)
local p
/self.s := ""
/self.MaxChars := 18
self.s ? if self.s := tab(find("\\=")) then ="\\=" & self.data := tab(0)
/self.data := ""
if *self.data > self.MaxChars then self.data := self.data[1:self.MaxChars]
self.T.DataLength := *self.data
self.T.MaxPixelSize := WAttrib(self.win, "fwidth")*self.MaxChars
# /self.T.MaxPixelSize := 250
## check max length by pixel size.
# if TextWidth(self.win, self.data) > self.T.MaxPixelSize then {
# t := get_pos_Vtext(self, self.T.MaxPixelSize)
# self.data := self.data[1:t]
# }
# self.T.DataLength := *self.data
self.T.DataPixelSize := TextWidth(self.win, self.data)
## size by characters - taken out.
/self.mask := &cset
## initialize with cursor at end
self.T.ta := self.T.tb := self.T.CursorPos := self.T.DataLength + 1
## initialize with all data blocked out (selected)
# self.T.ta := 1
# self.T.tb := self.T.CursorPos := self.T.DataLength + 1
self.T.dx := TextWidth (self.win, self.s) + 6
self.aw := self.T.dx + self.T.MaxPixelSize + 4
self.ah := WAttrib(self.win, "fheight") + 6 # 4 for bevel, 2 for I-bar
self.T.dy := self.ah - 3 - WAttrib(self.win, "descent")
p := \self.callback
self.callback := Vcoupler()
add_clients_Vinit(self.callback, p, self)
end
#
# Reconfigure the text vidget.
#
procedure resize_Vtext(s, x, y, w, h)
s.T.dx := TextWidth (s.win, s.s) + 6
s.T.DataLength := *s.data
s.T.MaxPixelSize := WAttrib(s.win, "fwidth") * s.MaxChars
w := s.aw := s.T.dx + s.T.MaxPixelSize + 4
h := s.ah := WAttrib(s.win, "fheight") + 6
resize_Vidget(s, x, y, w, h)
end
#
# Draw the prompt, the data, outline the data area, then draw
# the cursor if it was already on previous to calling this
# procedure (happens with dialog boxes and resize events).
#
procedure draw_Vtext(self)
local t
t := self.T.CursorOn
self.T.CursorOn := &null
draw_prompt_Vtext(self)
draw_data_Vtext(self)
outline_Vtext(self)
if \t then draw_cursor_Vtext(self)
end
#
# Outline the data field.
#
procedure outline_Vtext(self)
BevelRectangle(self.win, self.ax+self.T.dx-4, self.ay,
self.aw-(self.T.dx-4), self.ah, -2)
end
#
# Draw the prompt.
#
procedure draw_prompt_Vtext(self)
GotoXY(self.win, self.ax, self.ay+self.T.dy)
writes(self.win, self.s)
return
end
#
# Since the cursor is drawn in "reverse" mode, erase it only if it
# is "on" upon entering this procedure.
#
procedure erase_cursor_Vtext(self)
local ocx, cy
if /self.T.CursorOn then fail
ocx := self.T.OldCursorPos
## bracket cursor
WAttrib(self.win, "drawop=reverse", "linewidth=1")
DrawSegment(self.win, \ocx-2, self.ay+2, ocx+2, self.ay+2,
ocx, self.ay+3, ocx, self.ay+self.ah-4,
ocx-2, self.ay+self.ah-3, ocx+2, self.ay+self.ah-3)
WAttrib(self.win, "drawop=copy")
self.T.CursorOn := &null
end
#
# Draw the cursor only if it was previously "off" at this location.
#
procedure draw_cursor_Vtext(self)
local ocx, cx, cy
if \self.T.CursorOn then fail
cx := self.ax+self.T.dx + get_pixel_pos_Vtext(self, self.T.CursorPos) - 1
## bracket cursor
WAttrib(self.win, "drawop=reverse", "linewidth=1")
DrawSegment(self.win, cx-2, self.ay+2, cx+2, self.ay+2,
cx, self.ay+3, cx, self.ay+self.ah-4,
cx-2, self.ay+self.ah-3, cx+2, self.ay+self.ah-3)
WAttrib(self.win, "drawop=copy")
self.T.OldCursorPos := cx
self.T.CursorOn := 1
end
#
# De-block the data (reset ta and tb to CursorPos).
#
procedure unblock_Vtext(self)
self.T.ta := self.T.CursorPos := self.T.tb
draw_data_Vtext(self)
end
#
# Block (select) all the data
#
procedure block_Vtext(self)
self.T.ta := 1
self.T.tb := self.T.CursorPos := self.T.DataLength + 1
draw_data_Vtext(self)
if self.T.DataLength = 0 then
draw_cursor_Vtext(self)
end
#
# Draw the data, reversing that text that lies between ta and tb
# fields.
#
procedure draw_data_Vtext(self)
# if self.T.ta = self.T.tb then return
erase_cursor_Vtext(self)
GotoXY(self.win, self.ax+self.T.dx, self.ay+self.T.dy)
if self.T.ta <= self.T.tb then {
writes(self.win, self.data[1:self.T.ta])
WAttrib(self.win, "reverse=on")
writes(self.win, self.data[self.T.ta:self.T.tb])
WAttrib(self.win, "reverse=off")
writes(self.win, self.data[self.T.tb:0])
}
else {
writes(self.win, self.data[1:self.T.tb])
WAttrib(self.win, "reverse=on")
writes(self.win, self.data[self.T.tb:self.T.ta])
WAttrib(self.win, "reverse=off")
writes(self.win, self.data[self.T.ta:0])
}
EraseArea(self.win, self.ax+self.T.dx+self.T.DataPixelSize, self.ay+2,
self.aw-(self.T.dx +self.T.DataPixelSize+1), self.ah-4)
return
end
#
# Wow. Mouse events, block out text, key presses, enter, delete
# etcetera stuff. Call callback if linefeed key or return key
# is pressed.
#
procedure event_Vtext(self, e, x, y)
static ota
local otb, rv
if \self.callback.locked then fail
/x := &x; /y := &y
self.T.DataLength := *self.data
if e === (&lpress|&mpress|&rpress) then {
WAttrib(self.win, "pointer=xterm")
otb := self.T.ta := self.T.tb := self.T.CursorPos :=
get_pos_Vtext(self, &x-(self.ax+self.T.dx))
if otb = self.T.DataLength+1 & otb = \ota then
self.T.ta := 1
draw_data_Vtext(self)
draw_cursor_Vtext(self)
until e === (&lrelease|&mrelease|&rrelease) do {
self.T.tb := get_pos_Vtext(self, &x-(self.ax+self.T.dx))
if otb ~= self.T.tb then {
draw_data_Vtext(self)
self.T.CursorPos := self.T.tb
draw_cursor_Vtext(self)
otb := self.T.tb
}
e := Event(self.win)
}
rv := &null
WAttrib(self.win, "pointer=top left arrow")
} ## end mouse event loop
else if (not &meta) & (not (integer(e) < 0)) then {
## it's a keypress
if rv := case e of {
"\^b" | Key_Left | Key_KP_Left: move_cursor_Vtext(self, -1)
"\^f" | Key_Right | Key_KP_Right: move_cursor_Vtext(self, 1)
"\b" | "\d": delete_left_Vtext(self)
"\^k" | "\^u" | "\^x": delete_line_Vtext(self)
(&shift & "\t") | Key_Up | Key_KP_Up: return V_PREVIOUS
"\t" | Key_Down | Key_KP_Down: return V_NEXT
"\r" | "\l": {
self.callback.V.set(self.callback, self, self.data)
V_NEXT
}
default: insert_char_Vtext(self, e)
}
then {
draw_data_Vtext(self)
draw_cursor_Vtext(self)
self.T.ta := self.T.tb := self.T.CursorPos
}
}
else
fail # not our event
ota := self.T.ta
return rv
end
# Move the cursor one way or another, determine if at bounds.
#
procedure move_cursor_Vtext(self, increment)
local t
t := self.T.CursorPos + increment
if t < 1 | t > self.T.DataLength+1 then fail
self.T.ta := self.T.tb := self.T.CursorPos := t
return
end
#
# Blank out the whole data field.
#
procedure delete_line_Vtext(self)
self.data := ""
self.T.DataLength := *self.data
self.T.DataPixelSize := 0
self.T.ta := self.T.tb := self.T.CursorPos := 1
return
end
#
# Get the character position based on mouse x coordinate.
#
procedure get_pos_Vtext(self, x)
local tp, c, i, j
c := 1
i := j := 0
while i < x do {
j := i
i +:= TextWidth(self.win, self.data[c])
if (c +:= 1) > self.T.DataLength then break
}
if x <= ((i + j) / 2) then
c -:= 1 # less than halfway into the char
if i < x then tp := self.T.DataLength+1
else tp := (1 <= c) | 1
return tp
end
#
# Get pixel position in data field based on character position.
#
procedure get_pixel_pos_Vtext(self, CursorPos)
local sum, i
sum := 1
every i := 1 to CursorPos-1 do sum +:= TextWidth(self.win, self.data[i])
return sum
end
#
# Insert a character; could replace blocked out text. Check if
# insertion will go over bounds.
#
procedure insert_char_Vtext(self, c)
c := c[1]
if TextWidth(self.win, c) == 0 then
fail # not displayable
if (self.T.DataLength - abs(self.T.ta-self.T.tb) + 1) > self.MaxChars |
not (c ? any(self.mask)) then fail
if self.T.ta ~= self.T.tb then
change_data_Vtext(self, c)
else
self.data := self.data[1:self.T.CursorPos] || c ||
self.data[self.T.CursorPos:0]
self.T.DataLength := *self.data
self.T.DataPixelSize := TextWidth(self.win, self.data)
self.T.CursorPos +:= 1
return
end
#
# Replace a character at current position.
#
procedure change_data_Vtext(self, c)
if self.T.tb < self.T.ta then {
self.data := self.data[1:self.T.tb] || (\c | "") ||
self.data[self.T.ta:0]
self.T.ta := self.T.CursorPos := self.T.tb
}
else {
self.data := self.data[1:self.T.ta] || (\c | "") ||
self.data[self.T.tb:0]
self.T.tb := self.T.CursorPos := self.T.ta
}
end
#
# Delete the character to the left of the cursor.
#
procedure delete_left_Vtext(self)
if self.T.ta ~= self.T.tb then {
change_data_Vtext(self)
self.T.DataPixelSize := TextWidth(self.win, self.data)
return
}
else
if self.T.CursorPos > 1 then {
self.data := self.data[1:self.T.CursorPos-1] ||
self.data[self.T.CursorPos:0]
self.T.DataPixelSize := TextWidth(self.win, self.data)
self.T.CursorPos -:= 1
return
}
end
#
# Set the data field to value passed in.
# NOTE: doesn't pass it through mask right now.
# Call callback if value if different from internal coupler's
# value.
#
procedure couplerset_Vtext(self, caller, value)
local data
data := string(\value) | ""
self.data := data
if *self.data > self.MaxChars then self.data := self.data[1:self.MaxChars]
self.T.DataLength := *self.data
self.T.DataPixelSize := TextWidth(self.win, self.data)
## initialize with cursor at end
self.T.ta := self.T.tb := self.T.CursorPos := self.T.DataLength + 1
## initialize with all data blocked out (selected)
# self.T.ta := 1
# self.T.tb := self.T.CursorPos := self.T.DataLength + 1
draw_data_Vtext(self)
if numeric(value) then {
if value = \self.T.NumericData then fail
self.T.NumericData := value
}
else if data === self.data then fail
self.callback.V.set(self.callback, caller, value)
# draw_cursor_Vtext(self)
end
#
# Call couplerset to set value.
#
procedure set_value_Vtext(self, value)
couplerset_Vtext(self, , value)
return
end