indexing description: "[ An EM_DRAWABLE_CONTAINER is a DS_LINKED_LIST of EM_DRAWABLE. The EM_DRAWABLE_CONTAINER itself is an EM_DRAWABLE. If an EM_DRAWABLE_CONTAINER is drawn to an EM_SURFACE all containing EM_DRAWABLEs are drawn to the surface. First element in the LIST is drawn first, last element is drawn last. An EM_DRAWABLE_CONTAINER is a new coordinate system for all its elements. All the contained elements are drawn to an EM_SURFACE relative to the x and y position of the EM_DRAWABLE_CONTAINER and clipped to its `width' and `height' which is calculated from contained objects such as to enclose them. ]" date: "$Date$" revision: "$Revision$" class EM_DRAWABLE_CONTAINER [G -> EM_DRAWABLE] inherit EM_DRAWABLE undefine copy, is_equal redefine publish_mouse_event, initialize_events end DS_BILINKED_LIST [G] rename put_last as extend, extend as extend_with_list redefine make end EM_SHARED_BITMAP_FACTORY export {NONE} all undefine default_create, is_equal, copy end create make feature {NONE} -- Initialization make is -- Create an empty drawable container. do Precursor create part_rect.make (0, 0, 0, 0) initialize_events set_visible (True) ensure then is_visible: is_visible end initialize_events is -- Initialize all events. do Precursor create mouse_motion_on_item_event create mouse_button_up_on_item_event create mouse_button_down_on_item_event end feature -- Commands draw (a_surface: EM_SURFACE) is -- Draw `Current' to `a_surface' local cursor: DS_LINKED_LIST_CURSOR [G] translation: EM_VECTOR_2D old_clipping_area, clipping_area: EM_RECTANGLE do if is_visible then -- Translate coordinate system for drawing all contained objects. create translation.make (x, y) a_surface.translate_coordinates (translation) -- Change clipping area to clip all objects to container boundaries. old_clipping_area := a_surface.coordinate_area create clipping_area.make_from_coordinates (0, 0, width, height) clipping_area := clipping_area.intersection (old_clipping_area) a_surface.clip_coordinates (clipping_area) -- Draw all contained objects. cursor := new_cursor from cursor.start until cursor.off loop a_surface.draw_object (cursor.item) cursor.forth end -- Reset coordinate system. a_surface.clip_coordinates (old_clipping_area) a_surface.translate_coordinates (- translation) end end feature -- Status height: INTEGER is -- Height of `Current' local cursor: DS_LINKED_LIST_CURSOR [G] do create cursor.make (current) from cursor.start until cursor.off loop if cursor.item.y + cursor.item.height > result then result := cursor.item.y + cursor.item.height end cursor.forth end end width: INTEGER is -- Width of `Current' local cursor: DS_LINKED_LIST_CURSOR [G] do create cursor.make (current) from cursor.start until cursor.off loop if cursor.item.x + cursor.item.width > result then result := cursor.item.x + cursor.item.width end cursor.forth end end feature -- Mouse Events 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 publishing their mouse events when mouse pointer -- is realy inside object or for -- distributing mouse events to child objects. local cursor: DS_BILINKED_LIST_CURSOR [G] transformed_mouse_event: EM_MOUSE_EVENT translation: EM_VECTOR_2D do if bounding_box.has (a_mouse_event.proportional_position) then -- Transform `a_mouse_event' into `Current' coordinate system. transformed_mouse_event := a_mouse_event.twin transformed_mouse_event.set_caught (False) create translation.make (x, y) transformed_mouse_event.set_proportional_position (a_mouse_event.proportional_position - translation) -- First publish mouse events of `Current'. dispatch_mouse_event (transformed_mouse_event) -- Publish `transformed_mouse_event' to all children. -- (in top to bottom order until `caught') cursor := new_cursor from cursor.finish until cursor.before or transformed_mouse_event.caught loop cursor.item.publish_mouse_event (transformed_mouse_event) cursor.back end -- Publish item mouse event with drawable object that caught the event. if transformed_mouse_event.caught then cursor.forth dispatch_mouse_on_item_event (cursor.item, transformed_mouse_event) -- Propagate to caller if event was caught. a_mouse_event.set_caught (True) end end end mouse_button_down_on_item_event: EM_EVENT_CHANNEL [TUPLE [G]] -- Mouse button down on item event, -- gets published when the mouse button event -- is caught by an item inside `Current', -- item is passed as first argument to subscribers, -- an EM_MOUSEBUTTON_EVENT is passed -- as optional second argument mouse_button_up_on_item_event: EM_EVENT_CHANNEL [TUPLE [G]] -- Mouse button up on item event, -- gets published when the mouse button event -- is caught by an item inside `Current', -- item is passed as first argument to subscribers, -- an EM_MOUSEBUTTON_EVENT is passed -- as optional second argument mouse_motion_on_item_event: EM_EVENT_CHANNEL [TUPLE [G]] -- Mouse motion on item event, -- gets published when the mouse motion event -- is caught by an item inside `Current', -- item is passed as first argument to subscribers, -- an EM_MOUSEBUTTON_EVENT is passed -- as optional second argument feature {NONE} -- implementation dispatch_mouse_on_item_event (an_item: G; a_mouse_event: EM_MOUSE_EVENT) is -- Dispatch mouse on item event. require an_item_not_void: an_item /= Void a_mouse_event_not_void: a_mouse_event /= Void do -- Only dispatch when events are initialized. if events_initialized then inspect a_mouse_event.type when Em_mousemotion_event then mouse_motion_on_item_event.publish ([an_item, a_mouse_event]) when Em_mouse_button_down_event then mouse_button_down_on_item_event.publish ([an_item, a_mouse_event]) when Em_mouse_button_up_event then mouse_button_up_on_item_event.publish ([an_item, a_mouse_event]) end end end part_rect: EM_BLITTING_RECTANGLE -- The rectangular part to be drawed end