19928/jj_vision/interface/controls/control.e
Jocelyn Fiat 6dde6425c2 init
2024-06-17 09:09:33 +02:00

456 lines
13 KiB
Plaintext

note
description: "[
Used with {EDITOR} classes to make EV_WIDGETs for displaying and
editting an object. It is composed of an EV_TEXT_FIELD, `display'
and an optional EV_LABEL, `label' which can be positioned to the
top, left, right, or bottom of the `display'.
A {CONTROL} can be created normally with `default_create' or using
`create_from_field'. Feature `create_from_field' is used to allow
creation of controls from a {SCHEMA} (a list of {FIELD}) for placement
in an {DIALOG_EDITOR_VIEW} (a form maker). Features from `field' can
then be used to determine placement, size, etc for the {CONTROL}.
The object to be editted is placed into the control with feature
`set_data' and is stored in `data' from ANY. The current `value'
of the object can be obtained if `is_display_valid'. Feature
`is_display_valid' is True when the string displayed in the `text'
field of `display' can be converted into an object of the correct
type. This convertion is ultimately done by feature `string_to_type'
from class FIELD through `field'.
]"
instructions: "[
To allow the editting of objects of types other than STRING, redefine
`default_field', or create an heir of {FIELD}, redefine `type'.
Feature `draw' takes care of checking the `values' type and putting
into `display' the appropriate string if the type of the `value'
does not conform to the control, or if there is no data, etc. If
the data is good then `draw_display' is called to show the actual
data. Therefore, do not redefine `draw'; redefine `draw_data'.
]"
date: "5 Mar 03"
author: "Jimmy J. Johnson"
copyright: "Copyright 2009, Jimmy J. Johnson"
license: "Eiffel Forum License v2 (see forum.txt)"
URL: "$URL: file:///F:/eiffel_repositories/jj_vision/trunk/interface/controls/control.e $"
date: "$Date: 2012-03-16 14:05:07 -0400 (Fri, 16 Mar 2012) $"
revision: "$Revision: 7 $"
deferred class
CONTROL
inherit
EV_STOCK_COLORS
rename
implementation as colors_implementation
export
{NONE} all
undefine
default_create,
copy,
is_equal
end
-- Current must be an EV_WIDGET of some sort in order to be placed into
-- and EV_CONTAINER. That's the whole point; do not delete EV_FIXED
-- without adding some other widget.
EV_FIXED
redefine
set_data,
initialize,
create_interface_objects,
destroy,
is_destroyed,
is_in_default_state
-- enable_sensitive,
-- disable_sensitive,
-- is_sensitive
end
feature {NONE} -- Initialization
create_interface_objects
-- Create objects to be used by `Current' in `initialize'
-- Implemented by descendants to create attached objects
-- in order to adhere to void-safety due to the implementation bridge pattern.
do
Precursor {EV_FIXED}
create valid_change_actions
create select_actions
create label
create display
field := Default_field
end
initialize
-- Set up the control
do
Precursor {EV_FIXED}
label.set_minimum_width (1)
label.set_minimum_height (1)
display.set_minimum_height (20)
display.set_minimum_width (50)
extend (label)
extend (display)
-- descendents must create the `display'
-- and set_actions for display.
label_position := Label_top
label.set_pebble_function (agent get_field)
-- label.set_drag_and_drop_mode
set_actions
field.control_list.extend (Current)
end
make_from_field (a_field: like field)
-- Create a control using the values in `a_field'.
do
default_create
field := a_field
field.control_list.extend (Current)
end
set_actions
-- Add actions to the controls of Current.
do
display.change_actions.extend (agent on_display_changed)
label.pointer_button_press_actions.extend (agent on_control_selected)
display.pointer_button_press_actions.extend (agent on_control_selected)
end
feature -- Access
value: ANY
-- A new object created from the `text' in `display'.
-- Normally only redefine to change the result type by using an
-- assignment attempt on Precursor. This is to to preserve
-- the "definition" post-condition.
require
display_is_valid: is_display_valid
do
Result := field.string_to_type (display.text)
ensure
valid_result: Result /= Void
definition: equal (Result, field.string_to_type (display.text))
end
field: like Default_field
-- Dictates appearanced of current Control
-- Redefine `Default_field' to change the type.
valid_change_actions: EV_NOTIFY_ACTION_SEQUENCE
-- Actions to be called when this control changes to a valid value.
select_actions: EV_NOTIFY_ACTION_SEQUENCE
-- Actions to be called when this control is selected
feature -- Element change
frozen set_data (a_data: ANY)
-- Pass in any type of object and display the string representation
-- of it by calling `refresh'.
-- The argument can be Void as it will be checked on `refresh' and
-- the control will so indicate.
do
Precursor {EV_FIXED} (a_data)
refresh
end
set_label_top
-- Make the 'label' appear to the top of the `display'
do
label_position := Label_top
ensure
label_position_correct: label_position = Label_top
end
set_label_bottom
-- Make the 'label' appear to the bottom of the `display'
do
label_position := Label_bottom
ensure
label_position_correct: label_position = Label_bottom
end
set_label_left
-- Make the `label' appear to the left of the `display'.
do
label_position := Label_left
ensure
label_position_correct: label_position = Label_left
end
set_label_right
-- Make the 'label' appear to the right of the `display'
do
label_position := Label_right
ensure
label_position_correct: label_position = Label_right
end
set_label_none
-- Make the 'label' not appear at all. Make a labelless control.
do
label_position := Label_none
ensure
label_position_correct: label_position = Label_none
end
feature -- Basic operations
destroy
-- Remove Current from the `control_list' in `field' when
-- the underlying graphical object is destroyed.
do
Precursor {EV_FIXED}
field.control_list.prune (Current)
ensure then
control_not_in_list: not field.control_list.has (Current)
end
build
-- Position and size the `label' and `display' based on
-- values in `field'.
local
fh: INTEGER
f: EV_FONT
s_size: TUPLE [INTEGER, INTEGER]
do
label.set_text (field.label)
set_item_height (label, (label.font.height).max (label.minimum_height))
set_item_width (label, (label.font.string_width (label.text)).max (label.minimum_width))
-- set_item_height (display, field.height.item.max (display.minimum_height))
set_item_width (display, field.width.item.max (display.minimum_width))
-- Set the height of the font in `display'.
fh := field.height.item
f := display.font.twin
f.set_height (fh.max (1)) -- `max' to meet precondition h > 0
display.set_font (f)
-- Use any string because all I need is the height a string
-- would be if it were displayed in that font. I can't use
-- display.text because when the control is first built there
-- may not be any text in it.
s_size := f.string_size ("This is a STRING.")
check attached {INTEGER_REF} s_size.item (2) as dh then
-- because result of `string_size' is a TUPLE [INTEGER, INTEGER]
set_item_height (display, dh.item.max (display.minimum_height))
end
-- Place the label in the correct possition.
inspect
label_position
when Label_left then
set_item_position (label, 0, 0)
set_item_position (display, label.x_position + label.width, 0)
set_minimum_width (label.width + display.width)
set_minimum_height ((display.height).max (label.height))
when Label_top then
set_item_position (label, 0, 0)
set_item_position (display, 0, label.font.height)
set_minimum_width ((display.width).max (label.width))
set_minimum_height (display.height + label.height)
when Label_right then
set_item_position (label, field.width.item.max (display.minimum_width), 0)
set_item_position (display, 0, 0)
set_minimum_width (label.width + display.width)
set_minimum_height ((display.height).max (label.height))
when Label_bottom then
set_item_position (label, 0, field.height.item.max (display.minimum_height))
set_item_position (display, 0, 0)
set_minimum_width ((display.width).max (label.width))
set_minimum_height (display.height + label.height)
when Label_none then
set_item_height (label, label.minimum_height)
set_item_width (label, label.minimum_width)
set_item_position (label, 0, 0)
set_minimum_width (display.width)
set_minimum_height (display.height)
else
check
should_not_happen: False
end
end
end
frozen refresh
-- Displays the string representation of `data'.
-- Normally do not redefine; redefine `load_display' instead.
do
display.change_actions.block
-- change_actions.block
if field.is_calculated then
-- display.disable_sensitive
else
display.enable_sensitive
end
if field.is_calculated then
display.set_text ("{CONTROL}.refresh -- fix me")
-- display.set_text (field.function_result_as_string)
elseif attached data as d then
display.set_text (field.type_to_string (d))
else
display.set_text ("Void")
end
build_colors
-- change_actions.resume
display.change_actions.resume
end
feature -- Query
is_display_valid: BOOLEAN
-- Is the representation in `display' valid for
-- object of `Type' based on `field'?
-- Default is True because assumes `Type' is an ANY.
do
Result := not equal (display.text, Void_representation) and then
field.is_valid_data (display.text)
end
feature -- Status report
is_in_default_state: BOOLEAN = True
-- redefined to make it get past the Eiffel Vision2
-- post condition of `default create'.
is_destroyed: BOOLEAN
-- Is current usable as a widget?
do
Result := Precursor {EV_FIXED} and not field.control_list.has (Current)
end
-- is_sensitive: BOOLEAN is
-- -- Is the object sensitive to user input?
-- do
-- Result := display.is_sensitive
-- end
--
--feature -- Status setting
--
-- enable_sensitive is
-- -- Make the `display' sensitive to user input.
-- do
-- display.enable_sensitive
-- end
--
-- disable_sensitive is
-- -- Make the `display' unresponsive to user input.
-- do
-- display.disable_sensitive
-- end
feature {NONE} -- Implementation
load_display (a_value: STRING)
-- Put `a_value' into `display'.
-- This feature should be called when redefining.
-- require
-- value_exists: a_value /= Void
do
display.set_text (a_value.out)
end
build_colors
-- Change display to red if the `text' in `display'
-- (not necessarilly the same `data' that is in
-- Current) is not valid.
do
if is_display_valid then
display.set_foreground_color (Black)
else
display.set_foreground_color (Red)
end
end
get_field: like field
-- Getter function for `field' so can use `set_pebble_function'.
-- `set_pebble_function' cannot take an attribute such as
-- `field' as a parameter; it must be a function.
do
Result := field
end
refresh_dependent_controls
-- Refresh all other controls which are dependent on
-- this one. Called when display changes.
local
c_list: LINKED_LIST [CONTROL]
c: CONTROL
do
c_list := field.controls_dependent
from c_list.start
until c_list.exhausted
loop
c := c_list.item
if c /= Current then
c.refresh
end
c_list.forth
end
end
on_display_changed
-- Update because something was done in the control
do
build_colors
refresh_dependent_controls
if is_display_valid then
valid_change_actions.call ([Current])
end
end
on_control_selected (a_x, a_y, button: INTEGER;
a_x_tilt, a_y_tilt, a_pressure: DOUBLE;
a_screen_x, a_screen_y: INTEGER)
-- Execute the agents in `select_actions'
-- The parameters are ignored but are needed to match the
-- signature of the `pointer_button_press_actions' of `display'.
-- EV_ACTION_SEQUENCE [TUPLE [x, y, button: INTEGER; x_tilt, y_tilt, pressure: DOUBLE; screen_x, screen_y: INTEGER]]
do
select_actions.call ([Current])
end
feature {FIELD_EDITOR_VIEW} -- Implementation
label: EV_LABEL
-- Displays the name (`key') if `is_label_shown'
display: EV_TEXT_FIELD
-- Displays the `value'.
label_position: INTEGER
-- Where is the label displayed? (top,
-- bottom, left, or right of the `display'.
Label_top, Label_bottom, Label_left, Label_right, Label_none: INTEGER = unique
-- Position of `label' in relation to display
default_field: FIELD
-- Create a field to be used if Current was `default_create'd.
-- The anchor for `field'.
deferred
end
Void_representation: STRING_32
-- A string with the value "Void".
once
create Result.make_from_string ("Void")
ensure
definition: equal (Result, ("Void").as_string_32)
end
invariant
field_exists: field /= Void
label_exists: label /= Void
display_exists: display /= Void
select_actions_exists: select_actions /= Void
valid_change_actions_exists: valid_change_actions /= Void
in_control_list_if_not_destroyed: not is_destroyed implies field.control_list.has (Current)
not_in_control_list_if_destroyed: is_destroyed implies not field.control_list.has (Current)
is_sensitive_definition: is_sensitive implies display.is_sensitive
end