indexing description: "[ This is an important interface in the EiffelMedia library. Anything that can be drawn through an EM_SURFACE should implement EM_DRAWABLE. ]" date: "$Date$" revision: "$Revision$" deferred class EM_DRAWABLE inherit EM_CONSTANTS export {NONE} all end feature -- Drawing draw (a_surface: EM_SURFACE) is -- Draw `Current' onto `a_surface'. require a_surface_not_void: a_surface /= Void deferred end draw_part (a_rect: EM_RECT; a_surface: EM_SURFACE) is -- Draw rectangular part of `Current' defined by `a_rect' to `a_surface'. -- (Subclasses could redefine this feature for providing an implementation -- with better performance, otherwise its just done per default by -- transforming and clipping coordinates on `a_surface' before calling `draw'). require a_surface_not_void: a_surface /= Void a_rect_not_void: a_rect /= Void local clipping_area, old_clipping: EM_ORTHOGONAL_RECTANGLE translation: EM_VECTOR_2D do if is_visible then -- Default implementation, just set up coordinate transformation and clipping -- accordingly and draw `Current' as usual. -- Clip all drawings to `a_rect' at `x', `y'. old_clipping := a_surface.coordinate_area create clipping_area.make_from_coordinates (x, y, a_rect.width + x, a_rect.height + y) a_surface.clip_coordinates (clipping_area.intersection (old_clipping)) -- Translate all drawings to have point (a_rect.x, a_rect.y) at (x, y). create translation.make (a_rect.x, a_rect.y) a_surface.translate_coordinates (- translation) -- Draw `Current' to `drawing_interface'. draw (a_surface) -- Reset coordinate system and clipping area. a_surface.translate_coordinates (translation) a_surface.clip_coordinates (old_clipping) end end feature -- Status report width: INTEGER is -- Width of `Current' in pixels deferred ensure result_not_negative: Result >= 0 end height: INTEGER is -- Height of `Current' in pixels deferred ensure result_not_negative: Result >= 0 end is_visible: BOOLEAN -- is `Current' visible? x: INTEGER -- Horizontal position, distance in pixels from left y: INTEGER -- Vertical position, distance in pixels from top is_size_fixed: BOOLEAN -- Should `Current' not scale when drawed? -- `True' means that the object will be drawed unscaled -- but its position (`reference_point') will still be transformed correctly -- if drawed on a transformed scaled coordinate system -- (This is handled accordingly by `draw_object' of EM_SURFACE) feature -- Queries bounding_box: EM_ORTHOGONAL_RECTANGLE is -- Orthogonal rectangle surrounding `Current'; (i.e. usefull -- for visibility testing if it intersects with -- `coordinate_area' of EM_SURFACE) do create Result.make_from_coordinates (x, y, x + width, y + height) ensure result_not_void: Result /= Void end reference_point: EM_VECTOR_2D is -- Reference point of `Current' relative to which it should be positioned. -- (i.e. important when drawn on a scaled coordinate system and `is_size_fixed' is `True') do Result := bounding_box.center ensure result_not_void: Result /= Void end feature -- Status setting set_x (x_position: INTEGER) is -- Set `x' to `x_position'. do set_x_y (x_position, y) ensure x_set: x = x_position end set_y (y_position: INTEGER) is -- Set `y' to `y_position'. do set_x_y (x, y_position) ensure y_set: y = y_position end set_x_y (an_x, a_y: INTEGER) is -- Set `x' to `an_x' and `y' to `a_y'. do x := an_x y := a_y ensure x_set: x = an_x y_set: y = a_y end set_size_fixed (a_boolean: BOOLEAN) is -- Set `is_size_fixed' to `a_boolean'. do is_size_fixed := a_boolean ensure size_fixed_set: is_size_fixed = a_boolean end set_visible (a_boolean: BOOLEAN) is -- Set `visible' to `a_boolean' do is_visible := a_boolean ensure visible_set : is_visible = a_boolean end feature -- Mouse events initialize_events is -- Event initialization. -- Needs to be called before subscribing for events. require not_yet_initialized: not events_initialized do create mouse_button_down_event create mouse_button_up_event create mouse_motion_event events_initialized := True ensure events_initialized: events_initialized mouse_button_down_event_initialized: mouse_button_down_event /= Void mouse_button_up_event_initialized: mouse_button_up_event /= Void mouse_motion_event_initialized: mouse_motion_event /= Void end events_initialized: BOOLEAN -- Have events been initialized? publish_mouse_event (a_mouse_event: EM_MOUSE_EVENT) is -- Publish mouse event when `a_mouse_event' occured on `Current'. -- Descendants should redefine this feature -- for only catching and publishing their mouse events when mouse pointer -- is realy inside object or for -- distributing mouse events to child objects. require a_mouse_event_not_void: a_mouse_event /= Void do if bounding_box.has (a_mouse_event.proportional_position) then dispatch_mouse_event (a_mouse_event) a_mouse_event.set_caught (True) end end mouse_button_down_event: EM_EVENT_CHANNEL [TUPLE [EM_MOUSE_EVENT]] -- Mouse button down event, -- gets published when the mouse button is pressed over `Current', -- an EM_MOUSEBUTTON_EVENT is passed as argument mouse_button_up_event: EM_EVENT_CHANNEL [TUPLE [EM_MOUSE_EVENT]] -- Mouse button up event, -- gets published when the mouse button is released over `Current', -- an EM_MOUSEBUTTON_EVENT is passed as argument mouse_motion_event: EM_EVENT_CHANNEL [TUPLE [EM_MOUSE_EVENT]] -- Mouse button up event, -- gets published when the mouse button is released over `Current', -- an EM_MOUSEMOTION_EVENT is passed as argument feature {NONE} -- Implementation dispatch_mouse_event (a_mouse_event: EM_MOUSE_EVENT) is -- Publish appropriate mouse event. do -- Only dispatch when events are initialized. if events_initialized then inspect a_mouse_event.type when Em_mousemotion_event then mouse_motion_event.publish ([a_mouse_event]) when Em_mouse_button_down_event then mouse_button_down_event.publish ([a_mouse_event]) when Em_mouse_button_up_event then mouse_button_up_event.publish ([a_mouse_event]) end end end invariant mouse_button_down_event_initialized: events_initialized implies mouse_button_down_event /= Void mouse_button_up_event_initialized: events_initialized implies mouse_button_up_event /= Void mouse_motion_event_initialized: events_initialized implies mouse_motion_event /= Void end