19928/jj_vision/interface/views/view.e
2024-06-19 08:36:35 +02:00

751 lines
20 KiB
Plaintext

note
description: "[
Used as common ancestor to all "windows" in a system built using the
"jj_vision" cluster. It provides a way through feature `draw_views'
for updating all the views which contain that `target'.
Alternatively, the view
can force the redraw of views containing any of several objects by passing
a set of changed objects to feature `draw_views_with_set'.
The class should be an ancestor ancestor along with
some effected EV_WIDGET.
NOTE: Views which are `is_destroyed' are removed from the global `views' set
in feature `draw_views'.
]"
date: "18 Jul 03"
author: "Jimmy J. Johnson"
copyright: "Copyright 2012, Jimmy J. Johnson"
license: "Eiffel Forum License v2 (see forum.txt)"
URL: "$URL: file:///F:/eiffel_repositories/jj_vision/trunk/interface/views/view.e $"
date: "$Date: 2015-10-24 07:32:40 -0700 (Sat, 24 Oct 2015) $"
revision: "$Revision: 23 $"
deferred class
VIEW
inherit
DIMABLE
undefine
default_create
redefine
set_dimming_level
end
SHARED
undefine
default_create
end
PIXEL_BUFFERS
undefine
default_create
end
--create
-- make
feature {NONE} -- Initialization
make (a_target: like target)
-- Create a new view to display `a_target'
do
-- This assignment is required to avoid violating a
-- precondition "not_empty" later when calling
-- feature `create_interface_objects".
target_imp := a_target
-- `default_create from:
-- 1) {EV_ANY} calls `create_interface_objects', later `initialize'
-- 2) {EV_MODEL calls only `create_interface_objects'
default_create
set_target (a_target) -- calls `draw'
-- draw
ensure
target_imp /= Void
end
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.
-- Called by `default_create' from {EV_ANY} or {EV_MODEL}
require
not_interface_objects_created: not is_interface_objects_created
do
create pixmap.make_with_pixel_buffer (Icon_new_class_color_buffer)
is_interface_objects_created := true
ensure
interface_objects_created: is_interface_objects_created
end
initialize
-- Initialize the view and insert it into a global list of views.
require
view_not_initialized: not is_view_initialized
do
-- initialize_dimable
dimming_level := Dim
previous_dimming_level := Dimmer
add_actions
is_view_initialized := True
ensure
initialized: is_view_initialized
end
add_actions
-- Add any actions to Current.
require
not_initialized: not is_view_initialized
do
pointer_button_press_actions.extend (agent on_prepick_right_click)
pick_actions.extend (agent on_picked)
pointer_motion_actions.extend (agent on_postput_move)
end
feature -- Status report
is_interface_objects_created: BOOLEAN
-- Has `create_interface_objects' been called?
is_view_initialized: BOOLEAN
-- Has `initialize' been called?
is_pick_notifiable: BOOLEAN
-- Should Current be notified by other views (normally
-- a view contained in Current) that some event has
-- occurred?
-- Feature `set_parent_view' must have been called on
-- the child view for this to take effect.
has_parent_view: BOOLEAN
-- Does Current know the view in which it resides?
do
Result := attached parent_view_imp
end
feature -- Access
application: JJ_APPLICATION
-- The application in which Current resides.
do
check attached {JJ_APPLICATION} (create {EV_ENVIRONMENT}).application as app then
-- because this class is for use in a {JJ_APPLICATION}.
Result := app
end
end
pixmap: EV_PIXMAP
-- The pixmap associated with this view
-- application: JJ_APPLICATION is
-- -- Convience feature for obtaining the current application.
-- local
-- app: JJ_APPLICATION
-- once
-- app ?= (create {EV_ENVIRONMENT}).application
-- check
-- jj_application_exists: app /= Void
-- -- Because VIEWs are used in JJ_APPLICATIONs.
-- end
-- ensure
-- result_exists: Result /= Void
-- end
-- command_manager: COMMAND_MANAGER is
-- -- Manages the COMMAND's called by the system to allow undo/redo capabilities.
-- -- (This is a handle to the `command_manager' from a JJ_APPLICATION; putting it
-- -- here instead of in SHARED allows redefinition of the `command_manager' in
-- -- descendents of JJ_APPLICATION.
-- once
-- Result := application.command_manager
-- end
frozen target: attached like target_imp
-- The primary target in this view. This feature along with
-- `set_target' allows the view to handle one target specially.
require
not_empty: not is_view_empty
do
check attached target_imp as t then
Result := t
end
end
parent_window: JJ_MAIN_WINDOW
-- The {JJ_MAIN_WINDOW} if any which contains this view.
-- Must redefine to change type.
do
check attached {EV_CONTAINABLE} Current as c then
Result := recursive_parent_window (c)
end
ensure
valid_result: Result /= Void
end
parent_tool: detachable TOOL
-- The TOOL, if any, in which Current resides.
local
con: detachable EV_CONTAINER
do
from con := parent
until Result /= Void or else con = Void
loop
if attached {TOOL} con as t then
Result := t
else
con := con.parent
end
end
end
parent_view: attached like parent_view_imp
-- The view in which Current resides.
-- Provides a way for a model view to notify a parent
-- container of changes
require
has_parent_view: has_parent_view
do
check attached parent_view_imp as p then
Result := p
end
end
parent: detachable EV_CONTAINER
-- Parent of the current view.
-- To be effected by joining with an EV_ class
deferred
end
state: VIEW_STATE
-- A snapshot of the current look of the view
do
create Result.make (Current)
end
feature -- Element change
set_target (a_target: like target)
-- Change the value of `target' and realign the table or list
-- of views in which `a_target' is displayed.
do
-- print ("VIEW.set_target: a_target = " + target.out + "%N")
-- Remove the old association
if attached target_imp and then target /= a_target then
check
has_associated_view: views_table.has (target)
-- because `target_imp' not Void and `make'
end
views_table.prune (Current)
target_imp := Void
end
if target_imp = Void then
-- the expected case, except of initial creation
-- print ("VIEW.set_target: if statement target_imp = Void %N")
target_imp := a_target
views_table.extend (Current)
elseif not views_table.has_view (Current) then
-- print ("VIEW.set_target: not views_table.has (Current) %N")
check
same_object: target_imp = a_target
-- because of assignment statement in `make'
end
views_table.extend (Current)
end
draw
ensure
has_target: has_target (a_target)
target_imp /= Void
end
set_parent_view (a_view: VIEW)
-- Set `parent_view' to `a_view', allowing Current to
-- notify `a_view' of some event (e.g. right click).
do
parent_view_imp := a_view
end
set_dimming_level (a_level: like dimming_level)
-- Change the `dimming_level'
do
Precursor (a_level)
-- paint
end
feature -- Basic operations
-- paint
-- -- Draw the current view when some property like
-- -- background color changes
-- do
-- end
draw
-- Draw the current view.
-- Default does nothing
require
view_is_drawable: not is_draw_disabled
do
end
draw_other_views (a_target: ANY)
-- Draw all views that contain `a_target' except Current
-- This also cleans any "destroyed" views from the `views' set.
require
target_exists: a_target /= Void
local
b: BOOLEAN
do
b := is_draw_disabled
disable_drawing
draw_views (a_target)
if not b then
enable_drawing
end
end
draw_views (a_target: ANY)
-- Draw the views which contain `a_target'.
local
lin: LINEAR [VIEW]
marks: LINKED_SET [VIEW] -- Views marked for removal.
v: VIEW
do
create marks.make
lin := views_table.linear (a_target)
from lin.start
until lin.after
loop
v := lin.item
if v.is_destroyed then
marks.extend (v)
elseif not v.is_draw_disabled then
v.draw
end
lin.forth
end
-- Clean out any views that are no longer usable.
from marks.start
until marks.exhausted
loop
views_table.prune (marks.item)
marks.forth
end
end
draw_views_with_set (a_set: LINEAR [ANY])
-- Draw the views which contain any of the objects in `a_set'.
-- This also cleans any "destroyed" views from the `views' set.
require
set_exists: a_set /= Void
local
lin: LINEAR [VIEW]
marks: LINKED_SET [VIEW] -- Views marked for removal.
v: VIEW
do
create marks.make
lin := views_table.linear_with_set (a_set)
from lin.start
until lin.after
loop
v := lin.item
if v.is_destroyed then
marks.extend (v)
elseif not v.is_draw_disabled then
v.draw
end
lin.forth
end
-- Clean out any views that are no longer usable.
from marks.start
until marks.exhausted
loop
views_table.prune (marks.item)
marks.forth
end
end
draw_all_views
-- Draw *all* the views in the system.
-- Also cleans any "destroyed" views for the `views' set.
local
lin: LINEAR [VIEW]
marks: LINKED_SET [VIEW] -- Views marked for removal.
v: VIEW
do
create marks.make
lin := views_table.linear_representation
from lin.start
until lin.after
loop
v := lin.item
if v.is_destroyed then
marks.extend (v)
elseif not v.is_draw_disabled then
v.draw
end
lin.forth
end
-- Clean out any views that are no longer usable.
from marks.start
until marks.exhausted
loop
views_table.prune (marks.item)
marks.forth
end
end
feature -- Status report
is_in_default_state: BOOLEAN = true
-- Is `Current' in its default state?
-- The intent of this class is to be joined with an EV_WIDGET.
-- The default state of a descendent is most likely not the same
-- as the default state of the parent EV_WIDGET (after all, a
-- new type widget is being defined that, by definition looks
-- different from the parent.)
-- This silly feature is the post-condition of `default_create'
-- from EV_WIDGET, which required a choice--either redefine this
-- feature in every EV_WIDGET descendant or, as chosen here, use
-- this version (the EV_WIDGET version is irrelavent anyway) and
-- undefine it in the inherit class of the EV_WIDGET parent.
is_destroyed: BOOLEAN
-- Has the view been destroyed?
-- This will be joined with an EV_WIDGET feature
deferred
end
is_view_empty: BOOLEAN
-- Are there no objects in this VIEW?
do
Result := target_imp = Void
end
is_draw_disabled: BOOLEAN
-- Can the view be drawn using 'draw'?
feature -- Status setting
disable_drawing
-- Block the view from being redrawn by calling draw.
-- Used to reduce number of calls to draw.
do
is_draw_disabled := True
ensure
drawing_not_allowed: is_draw_disabled
end
enable_drawing
-- Allow the view to be redrawn on a call to draw.
do
is_draw_disabled := False
ensure
drawing_allowed: not is_draw_disabled
end
feature -- Query
has_target (a_target: like target): BOOLEAN
-- Does Current contain `a_target'?
do
Result := target_imp = a_target
end
display_name (a_object: ANY): STRING
-- An identifying "out" value corresponding to `a_object'.
require
object_exists: a_object /= Void
do
if attached {EDITABLE} a_object as e then
Result := e.display_name
else
Result := "fix me"
print ("VIEW.display_name -- get from once table?")
end
ensure
result_exists: Result /= Void
end
yes_cursor (a_target: ANY): EV_POINTER_STYLE
-- Cursor for `a_target'.
do
create Result.make_with_pixel_buffer (Icon_new_class_color_buffer, 0, 0)
end
no_cursor (a_target: ANY): EV_CURSOR
-- Cursor for `a_target'.
do
create Result
end
linear (a_object: ANY): LINEAR [VIEW]
-- List of views in which `a_object' is displayed. The
-- resulting list could be empty.
do
Result := views_table.linear (a_object)
end
linear_with_set (a_set: LINEAR [ANY]): LINEAR [VIEW]
-- List of views in which any of the objects in `a_set'
-- is displayed.
do
Result := views_table.linear_with_set (a_set)
end
frozen post_pick_move_agent: PROCEDURE [TUPLE [a_x, a_y: INTEGER;
a_x_tilt, a_y_tilt, a_pressure: DOUBLE;
a_screen_x, a_screen_y: INTEGER]]
-- Creates an agent out of `on_postput_move' which is added to
-- the `pointer_motion_actions' of *ALL* views when a pick occurs
-- (see `on_picked'). Holding on to this agent as a once feature
-- allows `on_postput_move' to remove this agent from *ALL* the
-- views after the pick has ended and the mouse is moved [in one
-- of the views].
once
Result := agent on_postput_move
end
feature -- Basic operations
target_changed_operations
-- This feature is called by `notify_views' to perform
-- actions when that view's `target' was modified.
do
print ("{VIEW}.target_changed_operations %N")
end
pick_notified_operations (a_target: ANY)
-- React to the pick of `a_target' from some view
do
print ("{VIEW}.pick_notified_operations on {" + generating_type.name + "}%N")
end
pick_ended_operations
-- React to the end of a pick and drop operation
do
print ("{VIEW}.pick_ended_operations on {" + generating_type.name + "} %N")
end
feature {NONE} -- Agents and support (actions)
frozen on_prepick_right_click (x, y, button: INTEGER;
x_tilt, y_tilt, pressure: DOUBLE;
screen_x, screen_y: INTEGER)
-- Notify the parent of all views that contain `target'
-- that a pick event occurred involving `target'.
local
lin: LINEAR [VIEW]
marks: LINKED_SET [VIEW] -- Views marked for removal.
v: VIEW
do
-- is_picking.set_item (true)
create marks.make
lin := views_table.linear (target)
from lin.start
until lin.after
loop
v := lin.item
if v.is_destroyed then
marks.extend (v)
elseif v.has_parent_view then
-- Notifiy the parent view of the pick
v.parent_view.pick_notified_operations (target)
-- Save the view for notification when pick ends
pick_notified_views.extend (v.parent_view)
end
lin.forth
end
-- Clean out any views that are no longer usable.
from marks.start
until marks.exhausted
loop
views_table.prune (marks.item)
marks.forth
end
end
frozen on_picked (a_x, a_y: INTEGER)
-- Notify the parent of all views that contain `target'
-- that a pick event occurred involving `target'.
local
lin: LINEAR [VIEW]
marks: LINKED_SET [VIEW] -- Views marked for removal.
v: VIEW
do
is_picking.set_item (true)
-- create marks.make
-- lin := views_table.linear (target)
-- from lin.start
-- until lin.after
-- loop
-- v := lin.item
-- if v.is_destroyed then
-- marks.extend (v)
-- elseif v.has_parent_view then
-- -- Notifiy the parent view of the pick
-- v.parent_view.pick_notified_operations (target)
-- -- Save the view for notification when pick ends
-- pick_notified_views.extend (v.parent_view)
-- end
-- lin.forth
-- end
-- -- Clean out any views that are no longer usable.
-- from marks.start
-- until marks.exhausted
-- loop
-- views_table.prune (marks.item)
-- marks.forth
-- end
end
frozen on_postput_move (a_x, a_y: INTEGER;
a_x_tilt, a_y_tilt, a_pressure: DOUBLE;
a_screen_x, a_screen_y: INTEGER)
-- Feature added as agent to `pointer_motion_actions'
-- to react after a pnp operations has ended. It calls
-- feature `postput_operations'.
-- Redefine `postput_operations' to clean up any operations
-- that occurred in `do_prepick_operations'.
-- See index clause for information on pick-and-put.
local
v: VIEW
do
print ("{VIEW}.on_postput_move on " + generating_type.name + "%N")
-- Notify views when a transport has ended.
if is_picking.item and then not application.transport_in_progress then
print ("%T `is_picking and not transport_in_progress pick_notified_views.count = " + pick_notified_views.count.out + "%N")
is_picking.set_item (false)
-- Inform any parent views that the pick has ended
from pick_notified_views.start
until pick_notified_views.after
loop
v := pick_notified_views.item
v.pick_ended_operations
pick_notified_views.forth
end
pick_notified_views.wipe_out
end
end
notify_changed (a_target: ANY)
-- Inform the views that have `a_target' that `a_target'
-- has changed (i.e. call `on_target_changed' for those
-- views).
-- This also cleans any "destroyed" views from the `views' set.
local
lin: LINEAR [VIEW]
marks: LINKED_SET [VIEW] -- Views marked for removal.
v: VIEW
do
create marks.make
lin := views_table.linear (a_target)
from lin.start
until lin.after
loop
v := lin.item
if v.is_destroyed then
marks.extend (v)
elseif not v.is_draw_disabled then
v.target_changed_operations
end
lin.forth
end
-- Clean out any views that are no longer usable.
from marks.start
until marks.exhausted
loop
views_table.prune (marks.item)
marks.forth
end
end
frozen is_picking: BOOLEAN_REF
-- Is a pick-and-put (PNP) operation in progress?
-- It seems the PNP operations intercepts events system-
-- wide, so this is a global reference.
-- See index clause for information on pick-and-put.
once
create Result
end
pick_notified_views: LINKED_SET [VIEW]
-- List of views that were notfied by `on_picked'
once
create Result.make
end
feature -- Action sequences
pointer_button_press_actions: EV_POINTER_BUTTON_ACTION_SEQUENCE
-- Actions to be performed when screen pointer button is pressed.
-- Defined here as place-holder to be undefined (i.e. joined) to
-- the version from {EV_WIDGET} or {EV_MODEL}.
-- See index clause for information on pick-and-put.
deferred
end
pointer_motion_actions: EV_POINTER_MOTION_ACTION_SEQUENCE
-- Actions to be performed when screen pointer moves.
-- Defined here as place-holder to be undefined (i.e. joined) to
-- the version from {EV_WIDGET} or {EV_MODEL}.
-- See index clause for information on pick-and-put.
deferred
end
pick_actions: EV_PND_START_ACTION_SEQUENCE
-- Actions to be performed when `pebble' is picked up.
-- Defined here as place-holder to be undefined by some
-- {EV_WIDGET} or {EV_MODEL}.
deferred
end
drop_actions: EV_PND_ACTION_SEQUENCE --EV_PND_START_ACTION_SEQUENCE
-- Actions to be performed when a pebble is dropped here.
deferred
end
feature {NONE} -- Implementation
recursive_parent_window (a_containable: EV_CONTAINABLE): JJ_MAIN_WINDOW
-- The {JJ_MAIN_WINDOW} which contains this tool.
-- This procedure was provided by Julian Rodgers from the Eiffel
-- users group.
do
check attached {EV_CONTAINER} a_containable.parent as cur_parent then
-- because parent of EV_CONTAINABLE must be an EV_CONTAINER
if attached {JJ_MAIN_WINDOW} cur_parent as w then
Result := w
else
check attached {EV_CONTAINABLE} cur_parent as con_parent then
-- because, if `cur_parent' is not a {JJ_MAIN_WINDOW} it must be EV_CONTAINABLE
Result := recursive_parent_window (con_parent)
end
end
end
ensure
result_exists: Result /= Void
end
feature {NONE} -- Implemetation
target_imp: detachable ANY
-- Detachable implementation of `target' for void safety
views_table: VIEW_TARGET_TABLE
-- Global table associating objects to views
once
create Result
end
parent_view_imp: detachable VIEW
-- Detachable implementation of `parent_view'
invariant
-- not_empty: target_imp /= Void
end