Source file scrollbar.icn |
# $Id: scrollbar.icn,v 1.1 2003-05-31 06:09:03 jeffery Exp $
$define MIN_BAR_SIZE 8
##
# This class provides horizontal and vertical scroll bars.
#
# There are two ways to use a scroll bar. The first way is to
# set a total_size (represented by the whole bar), a page_size
# (represented by the draggable button) and an increment_size
# (being the amount added/subtracted when the top/bottom
# button is pressed). The value will then range from zero to
# (total_size - page_size) inclusive. An initial value must
# be set with the {set_value()} method.
# @example
# @ vb := ScrollBar()
# @ vb$set_pos("85%", "25%")
# @ vb$set_size(20, "40%")
# @ vb$set_total_size(130)
# @ vb$set_page_size(30)
# @ vb$set_increment_size(1)
# @ vb$set_value(0)
# @ self$add(vb)
#
# Alternatively, a scroll bar can be used as a slider which
# ranges over a given range of values. In this case, the
# range is set with {set_range()}. It is still necessary to set
# the increment size and the initial value, as above, but
# page_size and total_size should not be set.
#
# Real numbers as opposed to integers can be used for the
# range settings if desired.
# @example
# @ vb := ScrollBar()
# @ vb$set_pos("85%", "25%")
# @ vb$set_size(20, "40%")
# @ vb$set_range(2, 25)
# @ vb$set_value(10)
# @ vb$set_increment_size(1)
# @ self$add(vb)
#
# An Event is returned whenever the buttons are pressed or the
# bar dragged; the value can be retrieved by get_value(). The
# event code (obtainable by {get_code()}) is 1 if the bar has
# been dragged, and 0 if either button has been pressed or the
# bar released after being dragged. This fact can be used to
# reduce the number of events which are processed by the
# user's program - just ignore events with code 1.
#
class ScrollBar : Component(
value,
page_size,
increment_size,
total_size,
hi,
lo,
bar_area_x,
bar_area_y,
bar_area_w,
bar_area_h,
bar_x,
bar_y,
bar_w,
bar_h,
bar_down,
bar_down_offset,
b1,
b2,
is_horizontal_flag,
bar_pos,
bar_size,
bar_area_pos,
bar_area_size,
is_range_flag
)
method final_setup(x, y)
self$Component.final_setup(x, y)
self.b1$final_setup(x, self)
self.b2$final_setup(x, self)
end
##
# Make the scroll bar horizontal (default is vertical).
#
method set_is_horizontal()
return self.is_horizontal_flag := 1
end
##
# Set the total size which the scroll bar area represents.
# @param x The total size
#
method set_total_size(x)
return self.total_size := x
end
##
# Return the total size.
#
method get_total_size()
return self.total_size
end
##
# Set the size which the bar in the scroll bar area represents.
# @param x The size.
#
method set_page_size(x)
return self.page_size := x
end
##
# Get the page size.
#
method get_page_size()
return self.page_size
end
##
# Get the value.
# @return The value
#
method get_value()
return self.value
end
##
# Set the value representing the top of the bar in the scroll
# bar. The value is forced into range if it is not in range already.
# @param x The value.
#
method set_value(x)
if \(\self.parent_Dialog).is_open then {
self$move_value(x)
self$set_pos_from_value()
self$refresh()
} else
self.value := x
return x
end
##
# Set the amount to increase the value by when one of the
# buttons is pressed.
# @param x The increment size.
#
method set_increment_size(x)
return self.increment_size := x
end
##
# Set the range of the scroll bar. The values may
# be integer or real.
# @param lo The lower bound
# @param hi The upper bound
#
method set_range(lo, hi)
self.is_range_flag := 1
self.lo := lo
self.hi := hi
end
method firstly()
self$Component.firstly()
self.b1$firstly()
self.b2$firstly()
end
method finally()
self$Component.finally()
b1$finally()
b2$finally()
end
method move_bar_pos(x)
self.bar_pos := x
self.bar_pos <:= self.bar_area_pos
self.bar_pos >:= self.bar_area_pos + self.bar_area_size - self.bar_size
if /self.is_horizontal_flag then
self.bar_y := self.bar_pos
else
self.bar_x := self.bar_pos
end
method move_value(x)
self.value := x
self.value <:= self.lo
self.value >:= self.hi
end
method set_pos_from_value()
if self.hi ~= self.lo then
self$move_bar_pos(self.bar_area_pos + integer(((self$get_value() - self.lo) * (self.bar_area_size - self.bar_size)) / (self.hi - self.lo)))
else
self$move_bar_pos(self.bar_area_pos)
end
method set_value_from_pos()
if self.bar_area_size ~= self.bar_size then
self$move_value(self.lo + ((self.hi - self.lo) * (self.bar_pos - self.bar_area_pos)) / (self.bar_area_size - self.bar_size))
else
self$move_value(self.lo)
end
method handle_notify(e)
if e$get_component() === b1 then {
#
# Button up clicked
#
self$move_value(self$get_value() - self.increment_size)
self$set_pos_from_value()
} else if e$get_component() === b2 then {
#
# Button down clicked
#
self$move_value(self$get_value() + self.increment_size)
self$set_pos_from_value()
}
#
# Re-draw bar
#
self$refresh()
self.parent_Component$handle_notify(_Event(EVENT_SCROLLED, self, 2))
end
method handle_event(e)
if b1$handle_event(e)$get_code() = 0 then {
#
# Button up clicked
#
self$move_value(self$get_value() - self.increment_size)
self$set_pos_from_value()
} else if b2$handle_event(e)$get_code() = 0 then {
#
# Button down clicked
#
self$move_value(self$get_value() + self.increment_size)
self$set_pos_from_value()
}
else if integer(e) = (&lpress | &rpress | &mpress) & (self.bar_x <= &x < self.bar_x + self.bar_w) & (self.bar_y <= &y < self.bar_y + self.bar_h) then {
#
# Click on bar; set flag and save offset between top of bar and pointer position
#
self.bar_down := 1
if /self.is_horizontal_flag then
self.bar_down_offset := &y - self.bar_y
else
self.bar_down_offset := &x - self.bar_x
} else if \self.bar_down & (integer(e) = (&lrelease | &rrelease | &mrelease)) then {
#
# Released; clear flag
#
self.bar_down := &null
} else if \self.bar_down & (integer(e) = (&ldrag | &rdrag | &mdrag)) then {
#
# Bar dragged; compute new position
#
if /self.is_horizontal_flag then
self$move_bar_pos(&y - self.bar_down_offset)
else
self$move_bar_pos(&x - self.bar_down_offset)
self$set_value_from_pos()
}
else if integer(e) = (&lpress | &rpress | &mpress) &
(self.bar_area_x <= &x < self.bar_area_x + self.bar_area_w) &
(self.bar_area_y <= &y < self.bar_area_y + self.bar_area_h) then {
#
# click outside bar; treat similar to pgup or pgdn
#
if /self.is_horizontal_flag then {
if &y < self.bar_y then {
self$move_bar_pos(self.bar_y-self.bar_h)
self$set_value_from_pos()
}
else if &y > self.bar_y+self.bar_h then {
self$move_bar_pos(self.bar_y+self.bar_h)
self$set_value_from_pos()
}
}
else {
if &x < self.bar_x then {
self$move_bar_pos(self.bar_x-self.bar_w)
self$set_value_from_pos()
}
else if &x > self.bar_x+self.bar_w then {
self$move_bar_pos(self.bar_x+self.bar_w)
self$set_value_from_pos()
}
}
} else
fail
#
# Re-draw bar
#
self$refresh()
return _Event(e, self, \self.bar_down | 0)
end
method display(buffer_flag)
W := if /buffer_flag then self.cwin else self.cbwin
EraseRectangle(W, self.x, self.y, self.w, self.h)
#
# Draw rectangle around area within which bar moves
#
if /self.is_horizontal_flag then
DrawRaisedRectangle(W, self.x, self.y + self.w, self.w, self.h - 2 * self.w,2)
else
DrawRaisedRectangle(W, self.x + self.h, self.y, self.w - 2 * self.h, self.h,2)
#
# Display two buttons
#
b1$display(buffer_flag)
b2$display(buffer_flag)
self$bar_to_win(W)
self$do_shading(W)
end
method refresh()
self$bar_to_win(self.cbwin)
self$do_shading(self.cbwin)
CopyArea(self.cbwin, self.cwin, self.bar_area_x, self.bar_area_y, self.bar_area_w, self.bar_area_h, self.bar_area_x, self.bar_area_y)
end
method bar_to_win(W)
EraseRectangle(W, self.bar_area_x, self.bar_area_y, self.bar_area_w, self.bar_area_h)
DrawRaisedRectangle(W, self.bar_x, self.bar_y, self.bar_w, self.bar_h,2)
end
method resize()
self$Component.resize()
if /self.is_range_flag then {
#
# Check total size and page size
#
if /self.total_size then
error("total size not set")
if /self.page_size then
error("page size not set")
if self.page_size <= 0 then
error("invalid page size")
}
else {
if \self.lo >= \self.hi then
error("invalid range")
}
#
# Check increment size, value
#
if /self.increment_size then
error("increment size not set")
if /self.value then
error("value not set")
if /self.is_horizontal_flag then {
#
# Compute bar area dimensions
#
self.bar_x := self.bar_area_x := self.x + BORDER_WIDTH + 2
self.bar_area_pos := self.bar_area_y := self.y + self.w + BORDER_WIDTH + 2
self.bar_w := self.bar_area_w := self.w - 2 * (BORDER_WIDTH + 2)
self.bar_area_size := self.bar_area_h := self.h - 2 * self.w - 2 * (BORDER_WIDTH + 2)
#
# Set button positions
#
b1$set_pos(0, 0)
b1$set_size(self.w, self.w)
b2$set_pos(0, self.h - self.w)
b2$set_size(self.w, self.w)
b1$set_img(img_style("arrow_up"))
b2$set_img(img_style("arrow_down"))
} else {
self.bar_area_pos := self.bar_area_x := self.x + self.h + BORDER_WIDTH + 2
self.bar_y := self.bar_area_y := self.y + BORDER_WIDTH + 2
self.bar_area_size := self.bar_area_w := self.w - 2 * self. h - 2 * (BORDER_WIDTH + 2)
self.bar_h := self.bar_area_h := self.h - 2 * (BORDER_WIDTH + 2)
b1$set_pos(0, 0)
b1$set_size(self.h, self.h)
b2$set_pos(self.w - self.h, 0)
b2$set_size(self.h, self.h)
b1$set_img(img_style("arrow_left"))
b2$set_img(img_style("arrow_right"))
}
if /self.is_range_flag then {
#
# Not a range; compute lo, hi and bar_size.
#
self.lo := 0
if self.total_size > self.page_size then {
self.hi := self.total_size - self.page_size
self.bar_size := integer((self.bar_area_size * self.page_size) / self.total_size)
} else {
#
# Total <= page; these settings produce an immovable full size bar.
#
self.hi := 0
self.bar_size := self.bar_area_size
}
} else {
#
# Range; set bar size proportional to button size, but leave room if bar_area_size is small.
#
self.bar_size := (b1.w_spec * 3) / 2
self.bar_size >:= self.bar_area_size - 8
}
#
# Ensure bar size in range not less than MIN_BAR_SIZE, but must be within
# bar_area_size.
#
self.bar_size <:= MIN_BAR_SIZE
self.bar_size >:= self.bar_area_size
#
# Set bar height/width according to orientation
#
if /self.is_horizontal_flag then
self.bar_h := self.bar_size
else
self.bar_w := self.bar_size
b1$resize()
b2$resize()
self$move_value(self.value)
self$set_pos_from_value()
return
end
initially(argv[])
self$Component.initially()
self.b1 := IconButton()
self.b1$toggle_draw_border()
self.b2 := IconButton()
self.b2$toggle_draw_border()
if *argv > 0 then set_fields(argv)
end
This page produced by UniDoc on 2021/04/15 @ 23:59:43.