19928/jj_vitp/Interface/views/board_view.e
Jocelyn Fiat 6dde6425c2 init
2024-06-17 09:09:33 +02:00

653 lines
19 KiB
Plaintext

note
description: "[
A {VIEW} that corresponds to the game board in Victory
In the Pacific (VITP). This view has widgets that hold
and allow control of game actions (e.g. movement, attacks,
repositions, etc) of game elements (e.g. ships, control
markers, ports, etc.)
]"
author: "Jimmy J. Johnson"
class
BOARD_VIEW
inherit
VITP_CELL_VIEW
redefine
create_interface_objects,
initialize,
add_actions,
set_target,
draw,
pick_notified_operations,
pick_ended_operations
end
FONT_AND_COLOR_CONSTANTS
export
{NONE}
all
undefine
default_create,
copy
end
POSITION_CONSTANTS
export
{NONE}
all
undefine
default_create,
copy
redefine
playing_area_ratio
end
create
make
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
print ("BOARD_VIEW.create_interface_objects %N")
Precursor {VITP_CELL_VIEW}
print ("%T BOARD_VIEW.create_interface_objects before creating widget_factory %N")
create widget_factory.make (game)
print ("%T BOARD_VIEW.create_interface_objects after creatingh widget_factory %N")
-- create dot
-- create bounding_figure
-- Create for Void safety
-- create mouse_offset
create last_mouse_position
-- create containers
create task_force_widgets.make (100)
create highlighted_widgets.make
-- create the corner points used to determine the scale factor
create top_left_dot
create bottom_right_dot
-- create container for the grid cells (rows, columns)
-- create cell_array.make (playing_area_height // cell_size,
end
initialize
-- Called after `Default_create'
do
Precursor {VITP_CELL_VIEW}
-- world.extend (dragging_arrow)
-- dragging_arrow.hide
-- -- create the `handle'
-- create handle
-- world.extend (handle)
build_border
-- Attack widgets go on top of all other widgets except the dots
-- build_corner_dots
-- Place the dots from {POSITION_CONSTANTS} into Current
-- The dots move based on scaling of the view, allowing
-- cell positions to be determined regardless of the
-- actual size of the view.
add_widgets
world.extend (top_left_dot)
world.extend (bottom_right_dot)
end
add_widgets
-- Add the sea areas, ports, and unit widgets to the `world',
-- hiding the unit widgets until needed
local
wf: like widget_factory
t: like widget_factory.widgets
w: VITP_WIDGET
do
wf := widget_factory
-- Add sea areas first
t := wf.sea_area_widgets
from t.start
until t.after
loop
-- world.extend (t.item_for_iteration)
add_model (t.item_for_iteration)
t.forth
end
-- Add ports
t := wf.port_widgets
from t.start
until t.after
loop
-- world.extend (t.item_for_iteration)
add_model (t.item_for_iteration)
t.forth
end
-- Add unit widgets
t := wf.attack_widgets
from t.start
until t.after
loop
w := t.item_for_iteration
print ("{BOARD_VIEW}.add_widgets: Adding " + w.target.name + " at (" + w.x.out + ", " + w.y.out + ") %N")
-- world.extend (w)
add_model (w)
-- w.hide
t.forth
end
end
build_corner_dots
-- Create the two dots that will mark the top-left and bottom-right corners of
-- the board. These aid calculation of the current scaling factor and scolling
do
top_left_dot.set_x_y (playing_area_left, playing_area_top)
bottom_right_dot.set_x_y (playing_area_right, playing_area_bottom)
top_left_dot.set_line_width (10)
bottom_right_dot.set_line_width (10)
world.extend (top_left_dot)
world.extend (bottom_right_dot)
end
add_actions
-- Add actions to the widgets
local
w: ATTACK_UNIT_WIDGET
do
-- Do not call precursor
-- asia_widget.pointer_button_press_actions.force_extend (agent toggle_land)
-- pointer_motion_actions.extend (agent on_pointer_moved)
-- pointer_button_release_actions.extend (agent on_button_released)
end
build_border
-- Put a border around the game board to hide some of the land overhangs
local
poly: EV_MODEL_POLYGON
s: INTEGER
bw, bh: INTEGER_32
c: EV_COLOR
do
s := 5
c := Medium_grey
bw := board_width
bh := board_height
-- top
create poly.default_create
poly.set_line_width (0)
poly.extend_point (create {EV_COORDINATE}.make (-s, -s))
poly.extend_point (create {EV_COORDINATE}.make (bw + s, -s))
poly.extend_point (create {EV_COORDINATE}.make (bw + s, 0))
poly.extend_point (create {EV_COORDINATE}.make (-s, 0))
poly.set_background_color (c)
poly.set_foreground_color (c)
world.extend (poly)
-- botton
create poly.default_create
poly.set_line_width (0)
poly.extend_point (create {EV_COORDINATE}.make (-s, bh))
poly.extend_point (create {EV_COORDINATE}.make (bw + s, bh))
poly.extend_point (create {EV_COORDINATE}.make (bw + s, bh + s))
poly.extend_point (create {EV_COORDINATE}.make (-s, bh + s))
poly.set_background_color (c)
poly.set_foreground_color (c)
world.extend (poly)
-- left
create poly.default_create
poly.set_line_width (0)
poly.extend_point (create {EV_COORDINATE}.make (-s, -s))
poly.extend_point (create {EV_COORDINATE}.make (0, -s))
poly.extend_point (create {EV_COORDINATE}.make (0, bh + s))
poly.extend_point (create {EV_COORDINATE}.make (-s, bh + s))
poly.set_background_color (c)
poly.set_foreground_color (c)
world.extend (poly)
-- right
create poly.default_create
poly.set_line_width (0)
poly.extend_point (create {EV_COORDINATE}.make (bw, -s))
poly.extend_point (create {EV_COORDINATE}.make (bw + s, -s))
poly.extend_point (create {EV_COORDINATE}.make (bw + s, bh + s))
poly.extend_point (create {EV_COORDINATE}.make (bw, bh + s))
poly.set_background_color (c)
poly.set_foreground_color (c)
world.extend (poly)
end
feature -- Basic operations
set_target (a_item: like game)
-- Associate `a_item' with Current.
do
Precursor (a_item)
-- Build a polygon that defines the boundary of current for which we
-- find the centerpoint, the `dot'. Other widgets can then be built
-- and if desired placed in Current relative to `dot'
widget_factory.set_game (game)
-- paint
-- set_pebble (a_item)
-- set_accept_cursor (sub_pixmap (bounding_box))
end
draw
-- Redraw the view
-- This means the game has changed in some way
-- (e.g. a ship was added).
do
if not is_view_empty then
-- update_attack_widgets
-- should be no need to draw the whole view unless the game
-- was changed.
end
end
feature -- Access
widget_factory: ALL_WIDGETS_FACTORY
-- Holds all the widgets on the board
playing_area_ratio: REAL_64
-- Ratio of the playing_area_width' to the [possibly]
-- scaled size of the `playing_area_width'. Default = one,
-- but redefined here to use the distance between the
-- two corner dots.
do
Result := playing_area_width / (bottom_right_dot.x - top_left_dot.x)
end
feature -- Query
cell_at (a_x, a_y: INTEGER_32): VITP_CELL
-- The cell at the screen coordinates `a_x', `a_y'
local
x, y: INTEGER_32
do
x := ((a_x * playing_area_ratio) / cell_size).truncated_to_integer + 1
y := ((a_y * playing_area_ratio) / cell_size).truncated_to_integer + 1
Result := game.cell (x, y)
end
screen_coordinates (a_cell: VITP_CELL): TUPLE [x, y: INTEGER_32]
-- The screen coordinates corresponding to `a_cell'
local
x, y: INTEGER_32
do
x := ((a_cell.index.x * cell_size) / playing_area_ratio).truncated_to_integer
y := ((a_cell.index.y * cell_size) / playing_area_ratio).truncated_to_integer
Result := [x, y]
end
feature -- Status report
is_forwarding: BOOLEAN
-- Has a widget been brought to the top?
is_dragging: BOOLEAN
-- Are we in the process of sliding a widget or a group of widgets?
-- is_picking: BOOLEAN
-- -- Are we in the process of a pick-and-put operation?
is_repositioning: BOOLEAN
-- Is a widget being repositioned?
is_moving: BOOLEAN
-- Is a unit being moved to a new location?
is_highlighting: BOOLEAN
-- Is a widget or group of widgets being emphasized?
is_highlighting_location: BOOLEAN
-- Is one or more port widgets being emphasized?
is_highlighting_units: BOOLEAN
-- Is one or more unit widgets being emphasized?
is_highlighting_task_force: BOOLEAN
-- Is one or more {TASK_FORCE_WIDGET}s being emphasized?
is_processing_task_force: BOOLEAN
-- A {TASK_FORCE_WIDGET} is being clicked/move/released
feature -- Actions
pick_notified_operations (a_target: ANY)
-- React to the pick of `a_target' from some view
local
sop: like game.sequence_of_play
set: LINKED_SET [PORT]
p: PORT
pw: PORT_WIDGET
do
Precursor (a_target)
print ("{BOARD_VIEW}.pick_notified_operations on {" + generating_type.name + "}%N")
sop := game.sequence_of_play
if sop.is_reinforcement_step and then attached {ATTACK_UNIT} a_target as t then
set := t.reinforceable_ports
print ("%T undimming " + set.count.out + " areas %N")
from set.start
until set.after
loop
p := set.item
print ("%T%T making " + p.name + " brighter %N")
pw := widget_factory.port_widgets.definite_item (p)
pw.set_dimming_level ({DIMABLE}.bright)
pw.activate_drop_action
highlighted_widgets.extend (pw)
set.forth
end
-- application.process_graphical_events
end
end
pick_ended_operations
-- React to the end of a pick and drop operation
do
Precursor
print ("{BOARD_VIEW}.pick_ended_operations on {" + generating_type.name + "} %N")
from highlighted_widgets.start
until highlighted_widgets.after
loop
highlighted_widgets.item.deactivate_drop_action
highlighted_widgets.item.restore_dimming_level
highlighted_widgets.forth
end
highlighted_widgets.wipe_out
end
on_pointer_enter (a_widget: VITP_WIDGET)
-- React to a pointer entering `a_widget'
local
tfw: TASK_FORCE_WIDGET
do
io.put_string ("BOARD_WORLD.on_pointer_enter: on " + a_widget.target.name + " %N")
-- if attached {ATTACK_UNIT_WIDGET} a_widget as w then
-- if w.unit.is_task_force then
-- tfw := task_force_widgets.widget (w.unit.task_force)
-- forward_widget_to_top (w, tfw)
-- end
-- end
end
on_pointer_leave (a_widget: VITP_WIDGET)
-- React to a pointer leaving a `a_widget'
do
io.put_string ("BOARD_WORLD.on_pointer_leave: on " + a_widget.target.name + " %N")
-- if is_forwarding then
-- restore_forwarded_widget
-- end
end
on_button_pressed (a_widget: VITP_WIDGET; ax: INTEGER; ay: INTEGER; a_button: INTEGER)
-- React to a pointer button pressed notification from `a_widget'
do
io.put_string ("BOARD_WORLD.on_button_pressed: button " + a_button.out +
" pressed at (" + ax.out + ", " + ay.out + ") on " + a_widget.target.name + " %N")
-- last_mouse_position.set_precise (ax, ay)
-- if is_forwarding then
-- restore_forwarded_widget
-- end
-- if a_button = 1 then
-- if attached {ATTACK_UNIT_WIDGET} a_widget as w then
-- highlight_unit (w.unit)
-- begin_widget_reposition (w, ax, ay)
-- elseif attached {LOCATION_WIDGET} a_widget as w then
-- highlight_location (w.location)
-- highlight_location_occupants (w.location)
-- end
-- end
end
on_button_double_pressed (a_widget: VITP_WIDGET; ax: INTEGER; ay: INTEGER; a_button: INTEGER)
-- React to a pointer button released notification from `a_widget'
do
io.put_string ("BOARD_WORLD.on_button_double_pressed: button " + a_button.out +
" double-pressed at (" + ax.out + ", " + ay.out + ") on " + a_widget.target.name + "%N")
if a_button = 1 then
if attached {TASK_FORCE_WIDGET} a_widget as w and then
not w.point_on_bounding_figure (ax, ay) then
if w.is_stacked then
w.tile
else
w.stack
end
-- Next lines to prevent undesired movement
is_repositioning := false
end
end
end
on_button_released (a_widget: VITP_WIDGET; ax: INTEGER; ay: INTEGER; a_button: INTEGER)
-- React to a pointer button released notification from `a_widget'
do
io.put_string ("BOARD_WORLD.on_button_released: button " + a_button.out + " pressed at (" + ax.out + ", " + ay.out + ") %N")
if is_highlighting_location then
normalize_locations
end
if is_highlighting_units then
normalize_units
end
if is_repositioning then
-- finish_widget_reposition
end
end
on_pointer_motion (a_widget: VITP_WIDGET; ax, ay: INTEGER)
-- React to a pointer move notification from `a_widget'
do
io.put_string ("BOARD_WORLD.on_notify_pointer_motion: at (" + ax.out + ", " + ay.out + ") %N")
-- if is_repositioning then
---- last_mouse_position.set_position (ax, ay)
-- -- Adjust for difference in the location of `active_widget' and `last_mouse_position'
---- if can_reposition (ax, ay) then
---- set_pointer_style (create {EV_POINTER_STYLE}.make_predefined ({EV_POINTER_STYLE_CONSTANTS}.Standard_cursor))
---- reposition_active_widget (ax, ay)
---- else
---- set_pointer_style (create {EV_POINTER_STYLE}.make_predefined ({EV_POINTER_STYLE_CONSTANTS}.No_cursor))
---- end
-- end
end
feature -- Basic operations
position_task_force_widget (a_widget: TASK_FORCE_WIDGET)
-- Place `a_widget' on the board so it does not overlap other
-- widgets, possibly moving other widgets.
do
end
position_widget (a_widget: ATTACK_UNIT_WIDGET)
-- Ensure each widget is postioned according to its position,
-- perhaps repositioning it to accomodate other widgets.
do
end
feature --{WIDGET_FACTORY} -- Basic operations
on_flip_widget (a_widget: SHIP_WIDGET)
-- Toggle the raiding status of `a_widget'
do
io.put_string ("on_flip_raider /n")
a_widget.flip
ensure
ship_status_toggled: a_widget.ship.is_raiding = not (old a_widget.ship.is_raiding)
end
board_coordinate_to_model_position (a_position: EV_COORDINATE): VITP_POSITION
-- `a_position' converted to the model's coordinate system
require
position_exists: a_position /= Void
local
brp, tlp: EV_COORDINATE
p: EV_COORDINATE
x_size, y_size: REAL_64
long, lat: REAL_64
do
p := a_position
brp := bottom_right_dot.point
tlp := top_left_dot.point
x_size := brp.x_precise - tlp.x_precise
y_size := brp.y_precise - tlp.y_precise
long := (p.x_precise - tlp.x_precise) * (board_right / x_size)
lat := (p.y_precise - tlp.y_precise) * (board_bottom / y_size)
create Result.set_xy (long.truncated_to_integer, lat.truncated_to_integer)
end
highlight_location (a_location: LOCATION)
-- Brighten the widget corresponding to `a_location'
require
location_exists: a_location /= Void
local
w: VITP_WIDGET
do
w := widget_factory.widgets.definite_item (a_location)
if world.has (w) then
w.set_dimming_level ({DIMABLE}.Bright)
w.paint
highlighted_widgets.extend (w)
is_highlighting_location := true
end
end
highlight_location_occupants (a_location: LOCATION)
-- Brighten the widgets corresponding to the occupants of `a_location'
require
location_exists: a_location /= Void
local
u_list: LINKED_SET [ATTACK_UNIT]
w: VITP_WIDGET
do
u_list := a_location.units
from u_list.start
until u_list.after
loop
w := widget_factory.widgets.definite_item (u_list.item)
w.set_dimming_level ({DIMABLE}.Bright)
w.paint
highlighted_widgets.extend (w)
u_list.forth
end
is_highlighting_units := true
end
highlight_unit (a_unit: ATTACK_UNIT)
-- Brighten the widget corresponding to `a_unit'
require
unit_exists: a_unit /= Void
local
tfw: TASK_FORCE_WIDGET
w: VITP_WIDGET
do
-- if a_unit.is_task_force then
-- tfw := task_force_widgets.widget (a_unit.task_force)
-- if tfw.is_stacked then
-- w := tfw
-- else
-- w := world.attack_widgets.widget (a_unit)
-- end
-- else
-- w := world.attack_widgets.widget (a_unit)
-- end
w := widget_factory.widgets.definite_item (a_unit)
w.set_dimming_level ({DIMABLE}.Bright)
w.paint
highlighted_widgets.extend (w)
is_highlighting_units := true
end
normalize_locations
-- Restor all location widgets to a normal brightness level
local
w: LOCATION_WIDGET
do
-- from world.location_widgets.start
-- until world.location_widgets.after
-- loop
-- w := world.location_widgets.item_for_iteration
-- w.set_dimming_level ({DIMABLE}.Normal)
-- w.paint
-- world.location_widgets.forth
-- end
-- is_highlighting_location := false
end
normalize_units
-- Restore all attack widgets to a normal brightness level
local
w: ATTACK_UNIT_WIDGET
do
-- from world.attack_widgets.start
-- until world.attack_widgets.after
-- loop
-- w := world.attack_widgets.item_for_iteration
-- w.set_dimming_level ({DIMABLE}.Normal)
-- w.paint
-- world.attack_widgets.forth
-- end
-- is_highlighting_units := false
end
feature --{VITP_WIDGET} -- Implementation
task_force_widgets: VITP_WIDGET_TABLE [TASK_FORCE_WIDGET, TASK_FORCE]
last_mouse_position: EV_COORDINATE
-- For possible restoration to the location where the reposition began
forwarded_widget: detachable ATTACK_UNIT_WIDGET
-- A widget that has been brought to the top of its owner
forwarded_widget_owner: detachable VITP_WIDGET
-- The widget in which `forwarded_widget' resides
highlighted_widgets: LINKED_SET [VITP_WIDGET]
-- The widgets with the focus
top_left_dot: EV_MODEL_DOT
-- A dot at top left of the board, that will scale and scroll with the view,
-- whose position when compared with `bottom_right_dot' provides a scale
-- factor used to position widgets
bottom_right_dot: EV_MODEL_DOT
-- See `top_left_dot'
feature {NONE} -- Implementation
-- X_stacking_increment: INTEGER
-- -- The distance in pixels to offset a stacked widget in the x direction
-- local
-- w: ATTACK_UNIT_WIDGET
-- do
-- -- Since we base this distance on the current size of a ship widget,
-- -- we must ensure we have a widget from which to calculate the value.
-- check not world.attack_widgets.is_empty then
-- w := world.attack_widgets.iteration_item (1)
---- Result := (w.tile_size / 10).rounded
-- Result := (w.tile_size / 10).rounded
-- end
-- end
-- Y_stacking_increment: INTEGER
-- -- The distance in pixels to offset a stacked widget in the x direction
-- local
-- w: ATTACK_UNIT_WIDGET
-- do
-- -- Since we base this distance on the current size of a ship widget,
-- -- we must ensure we have a widget from which to calculate the value.
-- check not world.attack_widgets.is_empty then
-- w := world.attack_widgets.iteration_item (1)
---- Result := (w.tile_size / 10).rounded
-- Result := (w.tile_size / 10).rounded
-- end
-- end
--feature {NONE} -- Implemetation
-- target_imp: detachable VITP_GAME
-- -- Detachable implementation of `target' for void safety
end