19928/jj_vision/unfinished/left_aligned_scrollable_area.e

270 lines
8.6 KiB
Plaintext
Raw Normal View History

2024-06-17 07:09:33 +00:00
note
description: "[
Objects that represent a scrollable area in which the contents are always aligned with the top left while
smaller than client area.
When using this control, you must be careful of the following things:
An action sequence is connected to the idle_actions of the application from time to time. As it is removed,
it is the final agent contained, so if you must add to the idle actions, you should not add at the last position.
An agent is connected to the `resize_actions' of the widget inserted. If you clear this action sequence, `Current'
will not update as the widget size changes. Removing the widget via `remove_item' removes the final agent from
`resize_actions'.
None of the inherited features for addition and removal of widget does not work correctly. Use `add_item'
and `remove_item' only.
]"
author: "Julian Rogers"
date: "$Date: 2012-03-16 14:05:07 -0400 (Fri, 16 Mar 2012) $"
revision: "$Revision: 7 $"
class
LEFT_ALIGNED_SCROLLABLE_AREA
inherit
EV_VERTICAL_BOX
redefine
initialize,
is_in_default_state
end
feature {NONE} -- Creation
initialize
-- Initialize `Current'.
local
h_box: EV_HORIZONTAL_BOX
do
create cell
create viewport
create vertical_scroll_bar
vertical_scroll_bar.change_actions.extend (agent scroll_vertically)
create horizontal_scroll_bar
horizontal_scroll_bar.change_actions.extend (agent scroll_horizontally)
horizontal_scroll_bar.hide
vertical_scroll_bar.hide
create horizontal_box
extend (horizontal_box)
create main_fixed
viewport.extend (main_fixed)
create h_box
extend (h_box)
h_box.extend (horizontal_scroll_bar)
cell.set_minimum_size (vertical_scroll_bar.minimum_width, horizontal_scroll_bar.minimum_height)
h_box.extend (cell)
h_box.disable_item_expand (cell)
cell.hide
disable_item_expand (h_box)
horizontal_box.extend (viewport)
horizontal_box.extend (vertical_scroll_bar)
horizontal_box.disable_item_expand (vertical_scroll_bar)
resize_actions.extend (agent resized)
is_initialized := True
end
feature -- Access
add_item (an_item: EV_WIDGET)
-- Add `an_item' to `Current'.
require
an_item_not_void: an_item /= Void
do
main_fixed.extend (an_item)
main_fixed.set_item_position (an_item, 0, 0)
the_item := an_item
the_item.resize_actions.extend (agent item_resized)
resized (0, 0, 0, 0)
ensure
item_set: the_item = an_item
end
feature -- Status report
the_item: EV_WIDGET
-- Item currently contained.
feature -- Status setting
remove_item
-- Remove item from `Current'
do
if the_item /= Void then
main_fixed.wipe_out
the_item := Void
the_item.resize_actions.go_i_th (the_item.resize_actions.count)
the_item.resize_actions.remove
end
ensure
no_item_contained: the_item = Void
end
feature {NONE} -- Implementation
item_resized (an_x, a_y, a_width, a_height: INTEGER)
-- `the_item' has been resized, respond by updating `Current'.
do
resized (0, 0, width, height)
end
resized (an_x, a_y, a_width, a_height: INTEGER)
-- `Current' has been resized. Determine if the scroll bars must be updated, and if necessary
-- connect an idle action that executes `update_scroll_bars' if their visible status has changed.
-- The visible status of the scroll bars must not be updated via `show' or `hide' during execution of
-- this feature as it is called from within the resize. Resizing a Vision2 interface during a resize
-- event is dangerous in this situation. Hence we must connect `update_scroll_bars' to perform the update
-- when the resizing is completed from the idle actions.
do
clear_visibility_flags
if the_item /= Void then
if viewport.width < the_item.width then
if not horizontal_scroll_bar.is_show_requested then
show_horizontal := True
end
horizontal_scroll_bar.value_range.adapt (create {INTEGER_INTERVAL}.make (0, the_item.width - viewport.width))
horizontal_scroll_bar.set_leap (viewport.width.max (1))
elseif horizontal_scroll_bar.is_show_requested then
hide_horizontal := True
end
if viewport.height < the_item.height then
if not vertical_scroll_bar.is_show_requested then
show_vertical := True
end
vertical_scroll_bar.value_range.adapt (create {INTEGER_INTERVAL}.make (0, the_item.height - viewport.height))
vertical_scroll_bar.set_leap (viewport.height.max (1))
elseif vertical_scroll_bar.is_show_requested then
hide_vertical := True
end
-- Ensure that as `Current' is enlarged, if the scroll positions are non zero, the
-- item tends towards the zero position.
if viewport.y_offset > 0 and the_item.height - viewport.y_offset < viewport.height then
viewport.set_y_offset ((the_item.height - viewport.height).max (0))
end
if viewport.x_offset > 0 and the_item.width - viewport.x_offset < viewport.width then
viewport.set_x_offset ((the_item.width - viewport.width).max (0))
end
if show_horizontal or hide_horizontal or show_vertical or hide_vertical and not idle_actions_connected then
idle_actions_connected := True
application.idle_actions.extend (agent update_scroll_bars)
end
end
end
update_scroll_bars
-- Actually perform hiding and showing of scroll bars deferred from `resized'.
-- Note that we must recompute the scroll bar values, as the widgets may have been resized since we
-- originally flagged that there must be a change of visibility.
do
if show_vertical then
vertical_scroll_bar.show
end
if hide_vertical then
vertical_scroll_bar.hide
end
if show_horizontal then
horizontal_scroll_bar.show
end
if hide_horizontal then
horizontal_scroll_bar.hide
end
if horizontal_scroll_bar.is_show_requested and vertical_scroll_bar.is_show_requested then
cell.show
else
cell.hide
end
if show_vertical or show_horizontal or hide_horizontal or hide_vertical then
if vertical_scroll_bar.is_show_requested then
vertical_scroll_bar.value_range.adapt (create {INTEGER_INTERVAL}.make (0, the_item.height - viewport.height))
vertical_scroll_bar.set_leap (viewport.height.max (1))
end
if horizontal_scroll_bar.is_show_requested then
horizontal_scroll_bar.value_range.adapt (create {INTEGER_INTERVAL}.make (0, the_item.width - viewport.width))
horizontal_scroll_bar.set_leap (viewport.width.max (1))
end
end
-- Ensure that as `Current' is enlarged, if the scroll positions are non zero, the
-- item tends towards the zero position.
if viewport.y_offset > 0 and the_item.height - viewport.y_offset < viewport.height then
viewport.set_y_offset ((the_item.height - viewport.height).max (0))
end
if viewport.x_offset > 0 and the_item.width - viewport.x_offset < viewport.width then
viewport.set_x_offset ((the_item.width - viewport.width).max (0))
end
-- Remove the idle action as leaving it hogs the CPU.
application.idle_actions.go_i_th (application.idle_actions.count)
application.idle_actions.remove
idle_actions_connected := False
end
show_vertical, hide_vertical, show_horizontal, hide_horizontal, show_cell, hide_cell: BOOLEAN
-- Flags to determine if the visible state of widgets must be updated.
clear_visibility_flags
-- Clear visibility flags to False.
do
show_vertical := False
show_horizontal := False
hide_horizontal := False
hide_vertical := False
end
scroll_vertically (new_value: INTEGER)
-- Respond to a scrolling of `vertical_scroll_bar'.
do
viewport.set_y_offset (new_value)
end
scroll_horizontally (new_value: INTEGER)
-- Respond to a scrolling of `horizontal_scroll_bar'.
do
viewport.set_x_offset (new_value)
end
is_in_default_state: BOOLEAN = True
-- Is `Current' in its default state.
idle_actions_connected: BOOLEAN
-- Is the idle event for showing scroll bars already connected?
vertical_scroll_bar: EV_VERTICAL_SCROLL_BAR
-- Vertical scroll bar comprising `Current'.
horizontal_scroll_bar: EV_HORIZONTAL_SCROLL_BAR
-- Horizontal scroll bar comprising `Current'.
horizontal_box: EV_HORIZONTAL_BOX
-- Horizontal box comprising `Current'.
viewport: EV_VIEWPORT
-- Viewport comprising `Current'.
main_fixed: EV_FIXED
-- The Fixed required in `Current'.
cell: EV_CELL
-- A cell placed betwen the corners of the scroll bars.
application: EV_APPLICATION
-- Once access to EV_APPLICATION.
once
--((create {EV_ENVIRONMENT}).application).idle_actions.extend (agent update_scroll_bars)
Result := ((create {EV_ENVIRONMENT}).application)
end
end -- class LEFT_ALIGNED_SCROLLABLE_AREA