Source file textfield.icn |
# $Id: textfield.icn,v 1.1 2003-05-31 06:09:04 jeffery Exp $
##
# A class for a single input line of text. The text can
# scroll within the area specified. By default, a border
# surrounds the text area; this can be turned of by using
# {toggle_draw_border()}.
#
# The horizontal size must be set by the {set_size()} method:
# there is no default (the vertical size will default, however).
#
# An event is generated when return is pressed (with code 0),
# and whenever the contents are changed (with code 1).
#
# @example
# @ t := TextField()
# @ t$set_pos(50, 250)
# @ # Vertical size will default
# @ t$set_size(100)
# @ t$set_contents("Initial string")
# @ self$add(t)
#
class TextField : Component(
filter, # Cset for filtering characters
printable, # The printable characters
contents,
cursor,
leftmost,
rightmost,
tx,
tw,
displaychar # char to print on screen
)
method set_displaychar(c)
displaychar := c
end
##
# Set a filter on the characters allowed to be input to the text field.
# @param c The cset of permissible characters.
# @example
# @ # Permit only hexadecimal characters as input
# @ set_filter('0987654321abcdefABCDEF')
#
method set_filter(c)
return self.filter := c ** printable
end
##
# Return the present contents of the text field.
#
method get_contents()
return self.contents
end
method resize()
if \self.draw_border_flag then
/self.h_spec := WAttrib(self.cwin, "fheight") + 2 * DEFAULT_TEXT_Y_SURROUND
else
/self.h_spec := WAttrib(self.cwin, "fheight")
self$Component.resize()
if \self.draw_border_flag then {
self.tx := self.x + DEFAULT_TEXT_X_SURROUND
self.tw := self.w - 2 * DEFAULT_TEXT_X_SURROUND
} else {
#
# Still want an offset for the text so that a click slightly to the left of
# the text itself is recognised. Therefore, just have a slightly smaller surround.
#
self.tx := self.x + (DEFAULT_TEXT_X_SURROUND - BORDER_WIDTH)
self.tw := self.w - 2 * (DEFAULT_TEXT_X_SURROUND - BORDER_WIDTH)
}
end
##
# Set the contents of the field. If not invoked then
# the initial content is the empty string.
# @param x The contents
#
method set_contents(x)
self.contents := string(x)
self.cursor := *self.contents + 1
self.leftmost := 1
self$redisplay()
return x
end
#
# Mouse click - compute new cursor position, re-display
#
method handle_press()
local startx, s
#
# Space at end for cursor at end of string
#
s := self.contents || " "
startx := self.tx
self.cursor := self.leftmost
while (startx + TextWidth(self.cwin, s[self.leftmost:self.cursor + 1]) <= &x) & (self.cursor + 1 < self.rightmost) do
self.cursor +:= 1
self$display()
end
#
# Delete
#
method handle_delete1(e)
if self.cursor > 1 then {
self.contents[self.cursor - 1] := ""
self.cursor -:= 1
self$display()
return _Event(e, self, 1)
}
end
method handle_return(e)
return _Event(e, self, 0)
end
method handle_key_right(e)
self.cursor := (*self.contents + 1 >= self.cursor + 1)
self$display()
end
method handle_key_left(e)
self.cursor := (0 < self.cursor - 1)
self$display()
end
method handle_delete_line(e)
self.contents := ""
self.cursor := 1
self$display()
return _Event(e, self, 1)
end
method handle_delete_2(e)
if self.cursor <= *self.contents then {
self.contents[self.cursor] := ""
self$display()
return _Event(e, self, 1)
}
end
method handle_start_of_line(e)
self.cursor := 1
self$display()
end
method handle_end_of_line(e)
self.cursor := *self.contents + 1
self$display()
end
method handle_default(e)
#
# Add any printable character at cursor position, and return
# event with code 1.
#
if type(e) == "string" & not(&control | &meta) & any(filter, e) then {
if self.cursor = 1 then
self.contents := e || self.contents
else
self.contents[self.cursor - 1] ||:= e
self.cursor +:= 1
self$display()
return _Event(e, self, 1)
}
end
method handle_event(e)
local code
return if self$in_region() & (integer(e) = (&lpress | &rpress | &mpress)) then
handle_press(e)
else if \self.has_focus then {
#
# Object has focus. Handle various key presses.
#
case e of {
"\b" : handle_delete1(e)
"\r" | "\l": handle_return(e)
"\^k" : handle_delete_line(e)
Key_Right : handle_key_right(e)
Key_Left : handle_key_left(e)
"\^a" : handle_start_of_line(e)
"\^e" : handle_end_of_line(e)
"\d" | "\^d" : handle_delete_2(e)
default : handle_default(e)
}
}
end
method display(buffer_flag)
local r, fh, spc, s, cp, cw
fh := WAttrib(self.cwin, "fheight")
spc := self.tw
#
# Space at end for cursor at end of string
#
if \displaychar then
s := repl("*", *(self.contents)) || " "
else
s := self.contents || " "
#
# Initialize left and right markers; only move leftmost if needed
#
self.leftmost >:= self.cursor
self.rightmost := self.cursor + 1
#
# Now pad out left and right markers to fill space
#
if TextWidth(self.cwin, s[self.leftmost:self.rightmost]) <= spc then {
while TextWidth(self.cwin, s[self.leftmost:self.rightmost + 1]) <= spc do
self.rightmost +:= 1
} else {
while TextWidth(self.cwin, s[self.leftmost:self.rightmost]) > spc do
self.leftmost +:= 1
}
#
# Clear rectangle, set s to string to display
#
EraseRectangle(self.cbwin, self.x, self.y, self.w, self.h)
s := s[self.leftmost:self.rightmost]
#
# Cursor position within s
#
cp := self.cursor - self.leftmost + 1
if \self.draw_border_flag then
DrawSunkenRectangle(self.cbwin, self.x, self.y, self.w, self.h,-2)
#
# Display s centred vertically in box
#
left_string(self.cbwin, self.tx, self.y + self.h / 2 , s)
#
# If has focus display box cursor, else display outline cursor
#
if \self.has_focus then {
FillRectangle(self.cbwin, self.tx + TextWidth(self.cwin, s[1:cp]), 1 + self.y + (self.h - fh) / 2, TextWidth(self.cwin, s[cp]), fh)
cw := Clone(self.cbwin, "drawop=reverse")
left_string(cw, self.tx + TextWidth(cw, s[1:cp]), self.y + self.h / 2 , s[cp])
Uncouple(cw)
} else
Rectangle(self.cbwin, self.tx + TextWidth(self.cwin, s[1:cp]), 1 + self.y + (self.h - fh) / 2, TextWidth(self.cwin, s[cp]), fh)
self$do_shading(self.cbwin)
if /buffer_flag then
CopyArea(self.cbwin, self.cwin, self.x, self.y, self.w, self.h, self.x, self.y)
end
initially(argv[])
self$Component.initially()
filter := printable := cset(&ascii[33:128])
self.accepts_tab_focus_flag := 1
self$set_contents("")
self.draw_border_flag := 1
if *argv > 0 then set_fields(argv)
end
This page produced by UniDoc on 2021/04/15 @ 23:59:43.