indexing description: "[ Selection tool (default tool). Selects and moves objects/image panes around ]" date: "$Date$" revision: "$Revision$" class SELECTION_TOOL inherit TOOL redefine make, set_toolchanged end create make feature -- Initialization make (a_scene: SCENE) is -- creation procedure do Precursor {TOOL} (a_scene) scene.set_selection_box (Void, Void) create selected_panes.make create selected_objects.make end feature -- Access cursor: MOUSE_CURSOR is -- appropriate cursor do if scene.focus_on_scene and (dragging_object or dragging_pane or (is_over_image_pane /= Void and then is_over_image_pane.is_selected) or (is_over_object /= Void and then is_over_object.count > 0 and is_over_object.first.is_selected)) then Result := move_cursor else Result := arrow_cursor end end feature -- Event Handling handle_mouse_button_down_event (event: EM_MOUSEBUTTON_EVENT) is -- Handle mouse button down event. do if scene.focus_on_scene and event.is_left_button then is_pressed := True select_drag_start_coords := scene.coordinates_from_screen_position (x, y) select_drag_start_screen_position := create {EM_VECTOR_2D}.make (x, y) if is_over_object /= Void and then is_over_object.count > 0 and then is_over_object.first.is_selected then dragging_object := True elseif is_over_image_pane /= Void and then is_over_image_pane.is_selected then -- start dragging the selected image panes dragging_pane := True end end end handle_mouse_button_up_event (event: EM_MOUSEBUTTON_EVENT) is -- Handle mouse button up event. local pane1, pane2: IMAGE_PANE v: EM_VECTOR_2D rect: EM_RECTANGLE_COLLIDABLE list: DS_LINKED_LIST [OBJECT] do if event.is_left_button then is_pressed := False end if scene.selection_box_top_left /= Void and scene.selection_box_bottom_right /= Void then -- a selectionbox was released, find objects create rect.make (select_drag_start_coords, scene.coordinates_from_screen_position (x, y)) set_toolchanged list := scene.collision_detector.objects_intersecting_rectangle (rect) if ctrl_is_pressed then add_selected_to_selected_objects (list) else new_selected_objects_list (list) end else -- something might have been dragged if select_drag_start_coords /= Void then if dragging_object then -- multiple objects have been dragged v := scene.coordinates_from_screen_position (x, y) - select_drag_start_coords scene.history.execute (create {MOVE_OBJECT}.make, [selected_objects, v]) if scene.history.execute_successful then scene.set_changed end elseif dragging_pane then -- a pane has been dragged v := scene.coordinates_from_screen_position (x, y) - select_drag_start_coords scene.history.execute (create {MOVE_IMAGE_PANE}.make, [selected_panes, v]) if scene.history.execute_successful then scene.set_changed end else -- select object or pane of mouse press and release list := mouse_is_over_objects if ctrl_is_pressed then -- add these elements, if any to the selected list add_selected_to_selected_objects (list) else new_selected_objects_list (list) if list.count = 0 then -- no objects were selected -> check image panes pane1 := image_pane_on_coords (select_drag_start_coords.x, select_drag_start_coords.y) pane2 := is_over_image_pane if pane1 /= Void and pane1 = pane2 then -- a pane was selected if not ctrl_is_pressed then unselect_all_selected pane1.set_selected (True) selected_panes.force_last (pane1) else if pane1.is_selected then -- if already selected and ctrl was pressed -> unselect pane1.set_selected (False) selected_panes.delete (pane1) else pane1.set_selected (True) selected_panes.force_last (pane1) end end else -- nothing was selected unselect_all_selected end end end end end end scene.set_selection_box (Void, Void) dragging_pane := False dragging_object := False select_drag_start_coords := Void select_drag_start_screen_position := Void end handle_mouse_motion_event (event: EM_MOUSEMOTION_EVENT) is -- Handle mouse motion event. local pane_cursor: DS_LINKED_LIST_CURSOR [IMAGE_PANE] obj_cursor: DS_LINKED_LIST_CURSOR [OBJECT] v: EM_VECTOR_2D do x := event.screen_x y := event.screen_y - 32 if is_pressed and event.button_state_left then -- the mouse is dragged over the scene v := scene.coordinates_from_screen_position (x, y) if dragging_object and select_drag_start_coords /= Void then create obj_cursor.make (selected_objects) from obj_cursor.start until obj_cursor.off loop obj_cursor.item.move_by (x - last_x, y - last_y) obj_cursor.item.set_changed obj_cursor.forth end elseif dragging_pane and select_drag_start_coords /= Void then create pane_cursor.make (selected_panes) from pane_cursor.start until pane_cursor.off loop pane_cursor.item.set_x_y (v.x + pane_cursor.item.true_x - select_drag_start_coords.x, v.y + pane_cursor.item.true_y - select_drag_start_coords.y) pane_cursor.forth end scene.set_changed else scene.set_selection_box (select_drag_start_screen_position, create {EM_VECTOR_2D}.make (x, y)) end end -- update `is_over_image_pane' and `is_over_object' if scene.focus_on_scene then is_over_object := mouse_is_over_objects if is_over_object.count = 0 then is_over_image_pane := mouse_is_over_pane else is_over_image_pane := Void end end last_x := x last_y := y end handle_key_down_event (event: EM_KEYBOARD_EVENT) is -- Handle key down event. do if event.key = event.sdlk_lctrl then lctrl_is_pressed := True elseif event.key = event.sdlk_rctrl then rctrl_is_pressed := True elseif event.key = event.sdlk_r then r_pressed := True elseif event.key = event.sdlk_t then t_pressed := True elseif event.key = event.sdlk_pageup then pgup_pressed := True elseif event.key = event.sdlk_pagedown then pgdown_pressed := True elseif event.key = event.sdlk_delete then delete_pressed := True end end handle_key_up_event (event: EM_KEYBOARD_EVENT) is -- Handle key up event. local c: CIRCLE p: POLYGON r: RECTANGLE do if event.key = event.sdlk_lctrl then lctrl_is_pressed := False elseif event.key = event.sdlk_rctrl then rctrl_is_pressed := False elseif event.key = event.sdlk_r and r_pressed then change_transparency_of_selected (True) r_pressed := False elseif event.key = event.sdlk_t and t_pressed then change_transparency_of_selected (False) t_pressed := False elseif event.key = event.sdlk_pageup and pgup_pressed then change_zindex_of_selected (+1) pgdown_pressed := False elseif event.key = event.sdlk_pagedown and pgdown_pressed then change_zindex_of_selected (-1) pgup_pressed := False elseif event.key = event.sdlk_delete and delete_pressed then if selected_objects /= Void and then selected_objects.count > 0 then from selected_objects.start until selected_objects.off loop c ?= selected_objects.item_for_iteration p ?= selected_objects.item_for_iteration r ?= selected_objects.item_for_iteration if c /= Void then scene.history.execute (create {REMOVE_OBJECT}.make, [scene.circles, c]) if scene.history.execute_successful then scene.set_changed end elseif r /= Void then scene.history.execute (create {REMOVE_OBJECT}.make, [scene.rectangles, r]) if scene.history.execute_successful then scene.set_changed end elseif p /= Void then scene.history.execute (create {REMOVE_OBJECT}.make, [scene.polygons, p]) if scene.history.execute_successful then scene.set_changed end end selected_objects.forth end elseif selected_panes /= Void and then selected_panes.count > 0 then from selected_panes.start until selected_panes.off loop scene.history.execute (create {REMOVE_PANE}.make, [scene.image_panes, selected_panes.item_for_iteration]) if scene.history.execute_successful then scene.set_changed end selected_panes.forth end end end end feature -- Element Change set_toolchanged is -- tool was changed, unselect all items do unselect_all_selected scene.set_selection_box (Void, Void) dragging_object := False dragging_pane := False is_over_image_pane := Void is_over_object := Void r_pressed := False t_pressed := False pgdown_pressed := False pgup_pressed := False lctrl_is_pressed := False rctrl_is_pressed := False ensure then selected_panes_wiped: selected_panes.count = 0 end feature {NONE} -- Implementation mouse_is_over_pane: IMAGE_PANE is -- returns what pane the mouse is currently over local coords: EM_VECTOR_2D do coords := scene.coordinates_from_screen_position (x, y) Result := image_pane_on_coords (coords.x, coords.y) end mouse_is_over_objects: DS_LINKED_LIST [OBJECT] is -- returns what objects the mouse is currently over local coords: EM_VECTOR_2D a_cursor: DS_LINKED_LIST_CURSOR [POLYGON] do coords := scene.coordinates_from_screen_position (x, y) Result := scene.collision_detector.objects_intersecting_point (coords) -- also check invalid polygons create a_cursor.make (scene.polygons) from a_cursor.start until a_cursor.off loop if not a_cursor.item.is_collidable_valid and then not Result.has (a_cursor.item) and then a_cursor.item.is_inside (coords) then Result.force_last (a_cursor.item) end a_cursor.forth end end image_pane_on_coords (an_x, a_y: DOUBLE): IMAGE_PANE is -- returns the top most image pane if there is one under the mouse, otherwise returns Void do -- loop through images starting with the top-most from scene.image_panes.finish until scene.image_panes.off or Result /= Void loop if scene.image_panes.item_for_iteration.is_coordinate_on_image (an_x, a_y) then Result := scene.image_panes.item_for_iteration end scene.image_panes.back end end unselect_all_selected is -- unselects all selected elements local pane_cursor: DS_LINKED_LIST_CURSOR [IMAGE_PANE] do -- unselect all panes create pane_cursor.make (selected_panes) from pane_cursor.start until pane_cursor.off loop pane_cursor.item.set_selected (False) pane_cursor.forth end selected_panes.wipe_out -- unselect all objects from selected_objects.start until selected_objects.off loop selected_objects.item_for_iteration.set_selected (False) selected_objects.forth end selected_objects.wipe_out end add_selected_to_selected_objects (list: DS_LINKED_LIST [OBJECT]) is -- adds `list' to `selected_objects'. (used if ctrl was pressed) require list_not_void: list /= Void do from list.start until list.off loop if not selected_objects.has (list.item_for_iteration) then list.item_for_iteration.set_selected (True) selected_objects.force_last (list.item_for_iteration) end list.forth end end new_selected_objects_list (list: DS_LINKED_LIST [OBJECT]) is -- adds `list' to `selected_objects'. (used if ctrl was pressed) require list_not_void: list /= Void do unselect_all_selected create selected_objects.make from list.start until list.off loop if not selected_objects.has (list.item_for_iteration) then list.item_for_iteration.set_selected (True) selected_objects.force_last (list.item_for_iteration) end list.forth end end change_zindex_of_selected (v: INTEGER) is -- change the z-index of the selected panes by `v' local pane_cursor: DS_LINKED_LIST_CURSOR [IMAGE_PANE] do -- unselect all panes if selected_panes /= Void then create pane_cursor.make (selected_panes) from pane_cursor.start until pane_cursor.off loop pane_cursor.item.set_z_index (pane_cursor.item.z_index + v) scene.image_panes.reorder (pane_cursor.item) pane_cursor.forth end end end change_transparency_of_selected (b: BOOLEAN) is -- change `transparency' of the selected image panes. -- b = true -> increase transparency local pane_cursor: DS_LINKED_LIST_CURSOR [IMAGE_PANE] do -- unselect all panes if selected_panes /= Void then create pane_cursor.make (selected_panes) from pane_cursor.start until pane_cursor.off loop if b and pane_cursor.item.transparency <= 255 - transparency_rate then pane_cursor.item.set_transparency (pane_cursor.item.transparency + transparency_rate) elseif not b and pane_cursor.item.transparency >= transparency_rate then pane_cursor.item.set_transparency (pane_cursor.item.transparency - transparency_rate) end pane_cursor.forth end end end select_drag_start_coords, select_drag_start_screen_position: EM_VECTOR_2D -- where the mouse started dragging selected_panes: DS_LINKED_LIST [IMAGE_PANE] -- currently selected image panes selected_objects: DS_LINKED_LIST [OBJECT] -- currently selected objects selected_vertices: DS_LINKED_LIST [EM_VECTOR_2D] -- currently selected vertices ctrl_is_pressed: BOOLEAN is -- is the ctrl button pressed? do Result := lctrl_is_pressed or rctrl_is_pressed end lctrl_is_pressed, rctrl_is_pressed: BOOLEAN -- is the left/right ctrl button pressed? r_pressed, t_pressed: BOOLEAN -- has the r or t button been pressed? pgup_pressed, pgdown_pressed: BOOLEAN -- has the page up or page down button been pressed? delete_pressed: BOOLEAN -- has the delete button been pressed? is_over_image_pane: IMAGE_PANE -- is the mouse currently over an image pane? is_over_object: DS_LINKED_LIST [OBJECT] -- is the mouse currently over an object? dragging_pane: BOOLEAN -- is the tool dragging the selected pane? dragging_object: BOOLEAN -- is the tool dragging an object? transparency_rate: INTEGER is 25 -- must be greater than 0 and smaller than 256 end