note description: "[ Root class for widgets in VITP where `item' represents some {VITP_ITEM}. This also has features for aligning a widget with another. ]" author: "Jimmy J. Johnson" deferred class VITP_WIDGET inherit -- EV_WIDGET JJ_MODEL_WORLD_VIEW -- See newgroup message 20398. Concrete descendants must -- re-implement `new_filled_list' (from ARRAYED_LIST) as: -- new_filled_list (n: INTEGER): like Current -- -- New list with `n' elements. -- do -- create Result.make (n) -- end -- undefine -- new_filled_list redefine create_interface_objects, initialize, set_target, set_dimming_level, target_imp, add_actions, new_filled_list -- Let's try redefining with an empty body; this feature -- may be inapplicable anyway. -- select -- default_create end -- DIMABLE -- rename -- default_create as initialize_dimable -- redefine -- set_dimming_level -- end FONT_AND_COLOR_CONSTANTS export {NONE} all undefine default_create end feature {NONE} -- Initialization create_interface_objects -- Initialize attributes require else not_initialized: not is_initialized local i: INTEGER c: EV_COORDINATE do accept_cursor := Default_accept_cursor deny_cursor := Default_accept_cursor foreground_color := Black create font create text_group create name_mt create dot Precursor {JJ_MODEL_WORLD_VIEW} end frozen initialize -- Set up the widgets in Current. require else not_initialized: not is_initialized do -- set_font (Default_font) -- initialize_defining_figure extend_widgets build_widgets set_fonts_and_colors position_widgets set_widget_order -- add_actions dot.set_line_width (10) -- The Precursor from {VIEW} calls `add_actions' Precursor {JJ_MODEL_WORLD_VIEW} set_pebble (target) is_initialized := True end extend_widgets -- Put widgets into Current. This cannot be done -- in `create_interface_object', because cannot call -- `extend' feature until all objects [in descendants] -- are also created. do extend (dot) extend (text_group) text_group.extend (name_mt) -- Cannot put `jj_defining_figure' in yet, because -- descendants may not have finished creation and -- `jj_defining_figure' is self-initializing. -- extend (jj_defining_figure) end build_widgets -- Now that widgets were created in `create_interface_objects' -- and added to Current in `extend_widgets', build up the -- widgets by adding internal structure to each widget. do end set_fonts_and_colors -- Set the default fonts for any text widgets and set -- the default colors for any contained widgets. do end position_widgets -- Move Current and contained widgets to correct -- location and set their sizes require not_initialized: not is_initialized do -- Center text on Current text_group.set_x_y (x, y) end set_widget_order -- Ensure the widgets are ordered properly -- (i.e. whose on top?) do bring_to_front (text_group) bring_to_front (dot) -- Next line is okay, I think extend (jj_defining_figure) bring_to_front (jj_defining_figure) end add_actions -- Add actions to Current do check not is_view_initialized then -- pointer_enter_actions.extend (agent on_pointer_enter) -- pointer_leave_actions.extend (agent on_pointer_leave) -- pointer_motion_actions.extend (agent on_pointer_motion) -- pointer_button_press_actions.extend (agent on_button_pressed) -- pointer_double_press_actions.extend (agent on_pointer_double_pressed) -- pointer_button_release_actions.extend (agent on_button_released) -- pointer_motion_actions.extend (agent on_pointer_motion) -- pointer_enter_actions.extend (agent on_pointer_enter) -- pointer_leave_actions.extend (agent on_pointer_leave) end Precursor {JJ_MODEL_WORLD_VIEW} end -- build_bounding_figure -- -- Add points to the `jj_bounding_figure'. -- -- The default builds a polygon from the `bounding_box'. -- require -- not_initialized: not is_initialized -- local -- bb: like bounding_box -- do -- jj_bounding_figure.set_point_count (4) -- bb := bounding_box -- jj_bounding_figure.set_i_th_point_position (1, bb.lower_left.x, bb.lower_left.y) -- jj_bounding_figure.set_i_th_point_position (2, bb.upper_left.x, bb.upper_left.y) -- jj_bounding_figure.set_i_th_point_position (3, bb.upper_right.x, bb.upper_right.y) -- jj_bounding_figure.set_i_th_point_position (4, bb.lower_right.x, bb.lower_right.y) -- bring_to_front (jj_bounding_figure) -- jj_bounding_figure.hide -- jj_bounding_figure.enable_closed -- ensure -- has_enough_points: jj_bounding_figure.point_count >= 1 -- has_bounding_figure: has (jj_bounding_figure) -- end set_initialized -- Make `is_initialized' do is_initialized := true end feature -- Access game: VITP_GAME -- The game for which this widget provides an interface. do Result := target.game end foreground_color: EV_COLOR -- Can be used to `paint' contained widgets -- background_color: EV_COLOR -- -- Can be used to `paint' contained widgets. -- defined in EV_MODEL_WORLD font: EV_FONT -- The base font from which the size, weight, etc -- of the fonts for any texts in Current can be based. dot: EV_MODEL_DOT -- A point on Current used for positioning child widgets jj_defining_figure: EV_MODEL_CLOSED -- A shape to mark the boundary of Current, used -- to determine if widgets overlap or depart an area. attribute create {EV_MODEL_RECTANGLE} Result.make_with_points (bounding_box.upper_left, bounding_box.lower_right) Result.set_line_width (5) end midpoint: EV_COORDINATE -- The point that is the center of the `jj_bounding_figure' -- relative to Current's containing group local p: EV_COORDINATE mid: EV_COORDINATE do p := point_relative mid := points_middle (min_values, max_values) create Result.make_precise (p.x + mid.x, p.y + mid.y) end feature -- Element change set_target (a_item: like target) -- Associate `a_item' with Current. local s, s1, s2: STRING pos: INTEGER do Precursor {JJ_MODEL_WORLD_VIEW} (a_item) -- Set text, handling a couple of {PORT} names specially if target = game.Pearl_harbor or target = game.Johnston_island or target = game.New_hebrides or target = game.dutch_harbor or target = game.Andaman_islands then -- split into two lines s := target.name pos := s.index_of (' ', 1) s1 := s.substring (1, pos - 1) s2 := s.substring (pos + 1, s.count) -- Add spaces to better center text on circles if target = game.pearl_harbor or target = game.dutch_harbor then s1 := " " + s1 elseif target = game.johnston_island then s2 := " " + s2 elseif target = game.new_hebrides then s1 := " " + s1 elseif target = game.andaman_islands then s2 := " " + s2 end name_mt.set_text (s1 + "%N" + s2) else name_mt.set_text (target.name) end -- Set the color of and draw the contained widgets paint end set_foreground_color (a_color: EV_COLOR) -- Change the color in which the text is drawn require color_exists: a_color /= Void do foreground_color := a_color paint end -- set_font (a_font: EV_FONT) -- -- Change the appearance of the `font' from which -- -- the fonts (height, weight, etc.) of any text -- -- widgets in Current can be based. -- do -- font := a_font -- name_mt.set_font (font) -- end feature -- Basic operations set_dimming_level (a_level: INTEGER) -- Change the `dimming_level' do Precursor {JJ_MODEL_WORLD_VIEW} (a_level) from start until exhausted loop if attached {VITP_WIDGET} item as v then -- io.put_string (" VITP_WIDGET.set_dimming_level - widget is a {" + v.generating_type + "} %N" ) v.set_dimming_level (a_level) end forth end paint end paint -- Set the color of items in this widget and hide/show figures do if is_defining_figure_shown then jj_defining_figure.show else jj_defining_figure.hide end name_mt.set_foreground_color (adjusted_color (foreground_color)) end -- center_on (a_x, a_y: INTEGER_32) -- -- Move Current so its center point is on (a_x, a_y). -- local -- bb: EV_RECTANGLE -- do -- bb := bounding_box -- set_x_y (a_x - (bb.x + bb.width // 2), a_y - (bb.y + bb.height // 2)) -- end center_on_point (a_point: EV_COORDINATE) -- Transform Current so its center point is on `a_point' require point_exists: a_point /= Void local t: EV_MODEL_TRANSFORMATION ax, ay: REAL_64 bb: EV_RECTANGLE do bb := bounding_box ax := a_point.x_precise - (bb.x + bb.width / 2) ay := a_point.y_precise - (bb.y + bb.height / 2) create t.make_id t.translate (ax, ay) transform (t) end center_on_dot (a_dot: EV_MODEL_DOT) -- Place the center of `a_widget' on `a_dot' require dot_exists: a_dot /= Void local bb: EV_RECTANGLE cx, cy: REAL_64 dif_x, dif_y: REAL_64 t: EV_MODEL_TRANSFORMATION do bb := bounding_box cx := bb.width / 2 cy := bb.height / 2 dif_x := (bb.x + cx) - a_dot.point.x_precise dif_y := (bb.y + cy) - a_dot.point.y_precise -- dif_x := (bb.x + cx) - dot.point_x -- dif_y := (bb.y + cy) - dot.point_y create t.make_zero t.translate (-dif_x, -dif_y) transform (t) end center_on_origin -- Place the center of the widget at (0,0) local t: EV_MODEL_TRANSFORMATION ax, ay: REAL_64 bb: EV_RECTANGLE do bb := bounding_box ax := bb.x + bb.width / 2 ay := bb.y + bb.height / 2 create t.make_id t.translate (-ax, -ay) transform (t) end center_widget_on_dot (a_widget: EV_MODEL; a_dot: EV_MODEL_DOT) -- Place the center of `a_widget' on `a_dot' local bb: EV_RECTANGLE cx, cy: REAL_64 dif_x, dif_y: REAL_64 t: EV_MODEL_TRANSFORMATION do bb := a_widget.bounding_box cx := bb.width / 2 cy := bb.height / 2 dif_x := (bb.x + cx) - dot.point.x_precise dif_y := (bb.y + cy) - dot.point.y_precise create t.make_zero t.translate (-dif_x, -dif_y) a_widget.transform (t) end center_widget_on_other (a_widget: EV_MODEL; a_other: EV_MODEL) -- Place the center of `a_widget' on `a_other' local bb, bb_other: EV_RECTANGLE bb_center_x, bb_center_y: REAL_64 bb_other_center_x, bb_other_center_y: REAL_64 cx, cy: REAL_64 dif_x, dif_y: REAL_64 t: EV_MODEL_TRANSFORMATION do bb := a_widget.bounding_box bb_other := a_other.bounding_box bb_center_x := bb.left + bb.width / 2 bb_center_y := bb.top + bb.height / 2 bb_other_center_x := bb_other.left + bb_other.width / 2 bb_other_center_y := bb_other.top + bb_other.height / 2 dif_x := bb_other_center_x - bb_center_x dif_y := bb_other_center_y - bb_center_y -- cx := bb.width / 2 -- cy := bb.height / 2 -- dif_x := (bb.x + cx) - dot.point.x_precise -- dif_y := (bb.y + cy) - dot.point.y_precise -- dif_x := (bb.x + cx) - a_other.point_array.item (0).x_precise -- dif_y := (bb.x + cx) - a_other.point_array.item (0).x_precise create t.make_zero t.translate (dif_x, dif_y) a_widget.transform (t) -- Check for identical centers bb := a_widget.bounding_box bb_other := a_other.bounding_box bb_center_x := bb.left + bb.width / 2 bb_center_y := bb.top + bb.height / 2 bb_other_center_x := bb_other.left + bb_other.width / 2 bb_other_center_y := bb_other.top + bb_other.height / 2 dif_x := bb_other_center_x - bb_center_x dif_y := bb_other_center_y - bb_center_y end translate_widget (a_widget: EV_MODEL; a_x, a_y: INTEGER_32) -- Move `a_widget' in x and y directions. local t: EV_MODEL_TRANSFORMATION do create t.make_zero t.translate (a_x, a_y) -- a_widget.transform (t) a_widget.set_x_y (a_widget.x + a_x, a_widget.y + a_y) end rotate_widget (a_widget: EV_MODEL; a_degrees: REAL_64) -- Rotate `a_widget' `a_degrees' clockwise. local rad: REAL_64 do rad := degrees_to_radians (a_degrees) a_widget.rotate (rad) end scale_widget (a_widget: EV_MODEL; a_scale: REAL_64) -- Resize `a_widget' by `a_scale' factor. do a_widget.scale (a_scale) end align_midpoints (a_other: VITP_WIDGET) -- Move Current so its `midpoint' is over the `midpoint' of `a_other' local t: EV_MODEL_TRANSFORMATION po: EV_COORDINATE do po := points_offset (midpoint, a_other.midpoint) create t.make_zero t.translate (po.x_precise, po.y_precise) transform (t) end align_midpoints_with_offset (a_other: VITP_WIDGET; a_x_offset, a_y_offset: REAL_64) -- Move Current so its `midpoint' is offset from the `midpoint' -- of `a_other' by the offsets (as percentages of the size of -- Current in that direction). local t: EV_MODEL_TRANSFORMATION s: EV_COORDINATE xx, yy: REAL_64 do s := a_other.size_values align_midpoints (a_other) xx := s.x_precise * a_x_offset yy := s.y_precise * a_y_offset create t.make_zero t.translate (xx, yy) transform (t) end align_vertical (a_other: VITP_WIDGET) -- Move Current horizontally until it's `midpoint.x' is aligned -- with the `midpoint.x' of `a_other'. local t: EV_MODEL_TRANSFORMATION po: EV_COORDINATE do po := points_offset (midpoint, a_other.midpoint) create t.make_zero t.translate (po.x_precise, 0.0) transform (t) end align_horizontal (a_other: VITP_WIDGET) -- Move Current vertically until it's `midpoint.y' is aligned -- with the `midpoint.y' of `a_other'. local t: EV_MODEL_TRANSFORMATION po: EV_COORDINATE do po := points_offset (midpoint, a_other.midpoint) create t.make_zero t.translate (0.0, po.y_precise) transform (t) end align_lefts (a_other: VITP_WIDGET) -- Move Current so its left side is aligned with -- the left side of `a_other' local t: EV_MODEL_TRANSFORMATION c, o: REAL_64 -- current's value; other's value do c := min_values.x o := a_other.min_values.x create t.make_zero t.translate (o - c, 0.0) transform (t) end align_rights (a_other: VITP_WIDGET) -- Move Current so its right side is aligned with -- the right side of `a_other' local t: EV_MODEL_TRANSFORMATION c, o: REAL_64 do c := max_values.x o := a_other.max_values.x create t.make_zero t.translate (o - c, 0.0) transform (t) end align_tops (a_other: VITP_WIDGET) -- Move Current so its top side is aligned with -- the top side of `a_other' local t: EV_MODEL_TRANSFORMATION c, o: REAL_64 do c := max_values.y o := a_other.max_values.y create t.make_zero t.translate (0.0, o - c) transform (t) end align_bottoms (a_other: VITP_WIDGET) -- Move Current so its bottom side is aligned with -- the bottom side of `a_other' local t: EV_MODEL_TRANSFORMATION c, o: REAL_64 do c := min_values.y o := a_other.min_values.y create t.make_zero t.translate (o - c, 0.0) transform (t) end align_left_to_others_right (a_other: VITP_WIDGET) -- Move Current so its left side is aligned with the -- left side of `a_other' local t: EV_MODEL_TRANSFORMATION o, c: REAL_64 do c := min_values.x o := a_other.max_values.x create t.make_zero t.translate (o - c, 0.0) transform (t) end align_right_to_others_left (a_other: VITP_WIDGET) -- Move Current so its right side is aligned with the -- left side of `a_other' local t: EV_MODEL_TRANSFORMATION c, o: REAL_64 do c := max_values.x o := a_other.min_values.x create t.make_zero t.translate (o - c, 0.0) transform (t) end align_top_to_others_bottom (a_other: VITP_WIDGET) -- Move Current so its top side is aligned with the -- bottom side of `a_other' local t: EV_MODEL_TRANSFORMATION c, o: REAL_64 do c := min_values.y o := a_other.max_values.y create t.make_zero t.translate (0.0, o - c) transform (t) end align_bottom_to_others_top (a_other: VITP_WIDGET) -- Move Current so its top side is aligned with the -- bottom side of `a_other' local t: EV_MODEL_TRANSFORMATION c, o: REAL_64 do c := min_values.y o := a_other.max_values.y create t.make_zero t.translate (o - c, 0.0) transform (t) end feature -- Actions -- timer: TIME -- on_pointer_enter -- -- React to the mouse pointer entering Current -- do -- io.put_string ("VITP_WIDGET.on_enter " + vitp_item.name + "%N") -- -- Start timer; after delay with no movement show status dialog -- end -- on_pointer_leave -- -- React to the mouse pointer leaving Current -- do -- io.put_string ("VITP_WIDGET.on_leave " + vitp_item.name + "%N") -- end -- on_pointer_motion (ax, ay: INTEGER; ax_tilt, ay_tilt, apressure: DOUBLE; -- a_screen_x, a_screen_y: INTEGER) -- -- React to the mouse moving within Current -- do -- io.put_string ("VITP_WIDGET.on_move " + vitp_item.name + "%N") -- end feature -- Status report is_initialized: BOOLEAN -- Has Curent been initialized? (I.e. all all widgets built?) -- Used to prevent calling `initialize' more than once. is_defining_figure_shown: BOOLEAN -- Can be used by descendants to determine if the `jj_bounding_figure' -- should be visible or not. feature -- Query contains_point (a_point: EV_COORDINATE): BOOLEAN -- Is `a_point' on or in Current's `jj_defining_figure'? local pts: SPECIAL [EV_COORDINATE] -- for convenience i, j: INTEGER do -- pts := jj_bounding_figure.point_array -- -- Remember SPECIAL is zero-based -- from -- i := 0 -- j := pts.count - 1 -- until i > pts.count - 1 -- loop -- if ( ((pts[i].y_precise >= a_point.y_precise) /= (pts[j].y_precise >= a_point.y_precise)) and -- (a_point.x_precise <= (pts[j].x_precise - pts[i].x_precise) * -- (a_point.y_precise - pts[i].y_precise) / -- (pts[j].y_precise - pts[i].y_precise) + pts[i].x_precise) ) then -- Result := not Result -- end -- j := i -- i := i + 1 -- end Result := jj_defining_figure.position_on_figure (a_point.x, a_point.y) end overlaps (a_other: VITP_WIDGET): BOOLEAN -- Does Current occupy any space occupied by a_other local pts: SPECIAL [EV_COORDINATE] i: INTEGER do if Current /= a_other then pts := jj_defining_figure.point_array -- Remember SPECIAL is zero-based from i := 0 until i > pts.count - 1 or Result loop Result := a_other.contains_point (pts[i]) i := i + 1 end -- Check the other way around if not Result then pts := a_other.jj_defining_figure.point_array from i := 0 until i > pts.count - 1 or Result loop Result := contains_point (pts[i]) i := i + 1 end end end end touches (a_other: VITP_WIDGET): BOOLEAN -- Does Current touch `a_other'? do end is_touched_by (a_other: VITP_WIDGET): BOOLEAN -- Is Current touched by `a_other'? do end contains (a_other: VITP_WIDGET): BOOLEAN -- Does Current contain *all* of `a_other'? do end is_contained_by (a_other: VITP_WIDGET): BOOLEAN -- Is *all* of Current within `a_other'? do end diverges_from (a_other: VITP_WIDGET): BOOLEAN -- Does Current `intersects' `a_other' while having any -- point outside `a_other' do end feature {NONE} -- Inapplicable new_filled_list (n: INTEGER): like Current -- Redefined to get past void-safety issues do check do_not_call: False then -- Because this was redefined to appease void-safety, nothing else. end end feature -- Actions activate_drop_action -- Allow Current to react to the drop of a unit, moving -- that unit to the `location' in Current. do drop_actions.extend (drop_unit_agent) end deactivate_drop_action -- Remove the agent added by `activate_drop_actions do drop_actions.start drop_actions.prune (drop_unit_agent) end frozen drop_unit_agent: PROCEDURE [TUPLE [ATTACK_UNIT]] -- Create an agent out of `on_drop_unit' which will be added -- to Current when a pick is started and the Sequence of Play -- allows for the unit to be dropped here. once ("OBJECT") Result := agent on_drop_unit end on_drop_unit (a_unit: ATTACK_UNIT) -- Move `a_unit' to `locaiton' do print ("{LOCATION_WIDGET}.on_drop_unit: dropped " + a_unit.name + " on " + target.name + "%N") end feature {NONE} -- Implementation (actions) on_button_pressed (ax: INTEGER; ay: INTEGER; a_button: INTEGER; x_tilt: DOUBLE; y_tilt: DOUBLE; pressure: DOUBLE; a_screen_x: INTEGER; a_screen_y: INTEGER) -- Notify `board_world' that Current was clicked -- This allows the `board_world' to handle the click *and* to know the -- widget on which the click occurred. do io.put_string ("VITP_WIDGET.on_button_pressed on " + target.name + "%N") -- if attached board_world as bw then -- bw.on_notify_button_pressed (Current, ax, ay, a_button) -- end end -- on_pointer_double_pressed (ax: INTEGER; ay: INTEGER; a_button: INTEGER; x_tilt: DOUBLE; y_tilt: DOUBLE; -- pressure: DOUBLE; a_screen_x: INTEGER; a_screen_y: INTEGER) -- -- Notify `board_world' that Current was double-clicked -- -- This allows the `board_world' to handle the click *and* to know the -- -- widget on which the click occurred. -- do -- if attached board_world as bw then -- bw.on_notify_button_double_pressed (Current, ax, ay, a_button) -- end -- end -- on_button_released (ax: INTEGER; ay: INTEGER; a_button: INTEGER; x_tilt: DOUBLE; y_tilt: DOUBLE; -- pressure: DOUBLE; a_screen_x: INTEGER; a_screen_y: INTEGER) -- -- Notify `board_world' that `a_button' was released on it -- do -- if attached board_world as bw then -- bw.on_notify_button_released (Current, ax, ay, a_button) -- end -- end -- on_pointer_motion (ax: INTEGER; ay: INTEGER; x_tilt: DOUBLE; y_tilt: DOUBLE; -- pressure: DOUBLE; a_screen_x: INTEGER; a_screen_y: INTEGER) -- -- Notify `board_world' that mouse was moved on Current -- local -- c: EV_COORDINATE -- do -- if attached board_world as bw then -- bw.on_notify_pointer_motion (Current, ax, ay) -- end -- end -- on_pointer_enter -- -- React to the mouse entering the `dot' -- do -- if attached board_world as bw then -- bw.on_notify_pointer_enter (Current) -- end -- end -- on_pointer_leave -- -- React to mouse leaving Current -- do -- if attached board_world as bw then -- bw.on_notify_pointer_leave (Current) -- end -- end feature {VITP_WIDGET} -- Implementation vitp_world: detachable WIDGET_FACTORY -- The VITP {WIDGET_FACTORY} if any in which Current recursively resides do if attached {WIDGET_FACTORY} world as w then Result := w elseif attached {WIDGET_FACTORY} group as w then Result := w elseif attached {VITP_WIDGET} group as g then Result := g.vitp_world end end size_values: EV_COORDINATE -- The difference between the min_values and max_values. -- The "width" and "height" of the `jj_defining_figure' as a tuple. local po: EV_COORDINATE do po := points_offset (max_values, min_values) create Result.make_precise (po.x_precise.abs, po.y_precise.abs) end min_values: EV_COORDINATE -- The smallest values of both the x & y coordinates of all -- the points in `jj_bounding_figure' local i: INTEGER xx, yy: REAL_64 c: EV_COORDINATE rect: EV_RECTANGLE do -- create c -- xx := {REAL_64}.Max_value -- yy := {REAL_64}.Max_value -- from i := 1 -- until i > jj_bounding_figure.point_count -- loop -- c.set_precise (jj_bounding_figure.i_th_point_x (i), jj_bounding_figure.i_th_point_y (i)) -- if c.x_precise < xx then -- xx := c.x_precise -- end -- if c.y_precise < yy then -- yy := c.y_precise -- end -- i := i + 1 -- end -- create Result.make_precise (xx, yy) create Result.make_precise (bounding_box.left, bounding_box.top) end max_values: EV_COORDINATE -- The largest values of both the x & y coordinates of all -- the points in `jj_bounding_figure' local i: INTEGER xx, yy: REAL_64 c: EV_COORDINATE do create c -- xx := {REAL_64}.Min_value -- yy := {REAL_64}.Min_value -- from i := 1 -- until i > jj_bounding_figure.point_count -- loop -- c.set_precise (jj_bounding_figure.i_th_point_x (i), jj_bounding_figure.i_th_point_y (i)) -- if c.x_precise > xx then -- xx := c.x_precise -- end -- if c.y_precise > yy then -- yy := c.y_precise -- end -- i := i + 1 -- end -- create Result.make_precise (xx, yy) create Result.make_precise (bounding_box.right, bounding_box.bottom) end points_middle (a_point, a_other_point: EV_COORDINATE): EV_COORDINATE -- The point midway between the two points local xx, yy: REAL_64 do xx := (a_other_point.x_precise - a_point.x_precise) / 2 yy := (a_other_point.y_precise - a_point.y_precise) / 2 create Result.make_precise (xx, yy) end points_offset (a_point, a_other_point: EV_COORDINATE): EV_COORDINATE -- The offset of `a_other_point' from `a_point' local xx, yy: REAL_64 do xx := a_other_point.x_precise - a_point.x_precise yy := a_other_point.y_precise - a_point.y_precise create Result.make_precise (xx, yy) end feature {NONE} -- Implementation degrees_to_radians (degrees: DOUBLE): DOUBLE -- Convert degrees to radians. -- Helper function for convienence if need to rotate the widget. require degrees_big_enough: degrees >= -360 degrees_small_enough: degrees <= 360 do Result := degrees * Pi / 180 ensure -- definition: very_close (Result, degrees * (2 * Pi) / 360) result_in_range: Result >= -2 * Pi and Result <= 2 * Pi end feature {VITP_WIDGET} -- Implementation name_mt: EV_MODEL_TEXT -- The name of the object in Current text_group: EV_MODEL_GROUP -- Hold any text widgets in Current so they can -- be positioned and resized as a group target_imp: detachable VITP_ITEM -- Detachable implementation of `target' for void safety invariant not_empty: target_imp /= Void end