indexing description: "[ Polygon Editor Scene ]" date: "$Date$" revision: "$Revision$" class POLYGON_EDITOR_SCENE inherit EM_COMPONENT_SCENE redefine handle_key_down_event, handle_quit_event, handle_mouse_motion_event, handle_mouse_button_down_event, handle_mouse_button_up_event, handle_key_up_event, handle_update_event end EM_SHARED_BITMAP_FACTORY export {NONE} all end EM_SHARED_STANDARD_FONTS export {NONE} all end create make feature {NONE} -- Initialisation make is -- Initialise scene. local keyboard: EM_KEYBOARD do make_component_scene -- create top panel create menu_panel.make_from_dimension (1024, menu_hight) menu_panel.set_background_color (create {EM_COLOR}.make_with_rgb (200, 200, 200)) add_buttons -- create `scene_dropdown' create scene_dropdown.make_empty scene_dropdown.put (create {SCENE}.make) scene_dropdown.set_position (816, 5) scene_dropdown.set_dimension (200, scene_dropdown.optimal_height) scene_dropdown.set_to_string_agent (agent string_from_scene) scene_dropdown.set_selected_index (1) scene_dropdown.selection_changed_event.subscribe (agent change_scene) menu_panel.add_widget (scene_dropdown) add_component (menu_panel) -- create editing panel create editing_panel.make (1024, 736, scene) editing_panel.set_position (0, menu_hight) add_component (editing_panel) -- create tools initialize_tools -- start with vertex mode toggle_display_mode -- check if unicode is enabled create keyboard.make_snapshot -- TODO: on some computers setting this in the root class doesnt work. check if somewhere the setting gets reset or if is a problem of specific sdl librarys (or platforms) keyboard.enable_unicode_characters is_unicode_enabled := keyboard.is_unicode_characters_enabled editing_panel.mouse_entered_event.subscribe (agent handle_mouse_entered_editing_panel (True)) editing_panel.mouse_exited_event.subscribe (agent handle_mouse_entered_editing_panel (False)) end feature -- Access menu_panel: EM_PANEL -- Menu panel editing_panel: EDITING_PANEL -- Editing Panel scene_dropdown: EM_COMBOBOX [SCENE] -- list of open scenes scene: SCENE is -- the currently selected scene. do Result := scene_dropdown.selected_element end tool: TOOL -- currently selected tool save_button: EM_BUTTON -- save button undo_button: EM_BUTTON -- undo button redo_button: EM_BUTTON -- redo button display_button: EM_BUTTON -- display button menu_hight: INTEGER is 32 -- the hight of the button menu display_img1, display_img2: EM_BITMAP -- images of the display button feature -- Basic operations add_buttons is -- Add all buttons local button: EM_BUTTON position: INTEGER do -- create Buttons position := 1 -- add New Scene button bitmap_factory.create_bitmap_from_image ("image/new.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent new_scene) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("New scene") menu_panel.add_widget (button) position := position + 30 -- add Open button bitmap_factory.create_bitmap_from_image ("image/open.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent open_scene) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Open scene") menu_panel.add_widget (button) position := position + 30 -- add Save button bitmap_factory.create_bitmap_from_image ("image/save.gif") create button.make_from_image (bitmap_factory.last_bitmap) bitmap_factory.create_bitmap_from_image ("image/save_disabled.gif") button.set_disabled_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent save_scene) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Save scene") save_button := button menu_panel.add_widget (button) position := position + 30 -- add Save As button bitmap_factory.create_bitmap_from_image ("image/save_as.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent save_scene_as) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Save scene as") menu_panel.add_widget (button) position := position + 30 -- add Export button bitmap_factory.create_bitmap_from_image ("image/export.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent export_scene) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Export scene") menu_panel.add_widget (button) position := position + 30 -- add Import Image button bitmap_factory.create_bitmap_from_image ("image/import.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent import_image) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Import image") menu_panel.add_widget (button) position := position + 33 -- add Undo button bitmap_factory.create_bitmap_from_image ("image/undo.gif") create button.make_from_image (bitmap_factory.last_bitmap) bitmap_factory.create_bitmap_from_image ("image/undo_disabled.gif") button.set_disabled_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent undo) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Undo (ctrl-z)") button.disable undo_button := button menu_panel.add_widget (button) position := position + 30 -- add Redo button bitmap_factory.create_bitmap_from_image ("image/redo.gif") create button.make_from_image (bitmap_factory.last_bitmap) bitmap_factory.create_bitmap_from_image ("image/redo_disabled.gif") button.set_disabled_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent redo) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Redo (ctrl-shift-z)") button.disable redo_button := button menu_panel.add_widget (button) position := position + 33 -- add Cursor Tool button bitmap_factory.create_bitmap_from_image ("image/cursor.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent cursor_tool) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Cursor tool") menu_panel.add_widget (button) position := position + 30 -- add Pan button bitmap_factory.create_bitmap_from_image ("image/hand1.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent set_pan_tool) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Pan tool: press mouse button, to drag scene") menu_panel.add_widget (button) position := position + 30 -- add Zoom button bitmap_factory.create_bitmap_from_image ("image/magnifying.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent set_zoom_tool) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Zoom tool: left click to zoom in, right click to zoom out") menu_panel.add_widget (button) position := position + 30 -- add Toggle Grid button bitmap_factory.create_bitmap_from_image ("image/grid.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent toggle_grid) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Toggle grid on/off") menu_panel.add_widget (button) position := position + 30 -- add Toggle Display Mode button bitmap_factory.create_bitmap_from_image ("image/object.png") display_img1 := bitmap_factory.last_bitmap bitmap_factory.create_bitmap_from_image ("image/vertex.png") display_img2 := bitmap_factory.last_bitmap create button.make_from_image (display_img1) button.clicked_event.subscribe (agent toggle_display_mode) button.set_dimension (30, 30) button.set_position (position, 1) display_button := button menu_panel.add_widget (button) position := position + 33 -- add Circle button bitmap_factory.create_bitmap_from_image ("image/circle.png") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent set_circle_tool) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Create circle tool") menu_panel.add_widget (button) position := position + 30 -- add Rectangle button bitmap_factory.create_bitmap_from_image ("image/rectangle.gif") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent set_rectangle_tool) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Create rectangle tool") menu_panel.add_widget (button) position := position + 30 -- add Polygon button bitmap_factory.create_bitmap_from_image ("image/polygon.png") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent set_polygon_tool) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Create polygon tool") menu_panel.add_widget (button) position := position + 30 -- add Edit Polygon button bitmap_factory.create_bitmap_from_image ("image/edit_polygon.png") create button.make_from_image (bitmap_factory.last_bitmap) button.clicked_event.subscribe (agent set_polygon_edit_tool) button.set_dimension (30, 30) button.set_position (position, 1) button.set_tooltip ("Edit Polygon Tool - add vertex (left click), remove vertex (right click), split polygon (left click on vertex), remove split (left click on splitting line)") menu_panel.add_widget (button) position := position + 30 end feature {NONE} -- Event Handling handle_quit_event (a_quit_event: EM_QUIT_EVENT) is -- Handle quit event. do quit_prompt end handle_update_event is -- Handle forced redraws. do Precursor {EM_COMPONENT_SCENE} -- blinking redraw of `editing_scene' if editing_panel.blinking_status /= ((time.ticks) \\ (editing_panel.selection_border_blink * 2) > editing_panel.selection_border_blink) then editing_panel.set_blinking_status (not editing_panel.blinking_status) editing_panel.draw end end handle_key_down_event (event: EM_KEYBOARD_EVENT) is -- Handle Key presses. local inserted_character: CHARACTER do Precursor {EM_COMPONENT_SCENE} (event) if is_unicode_enabled then if event.unicode_character.code > 0 then inserted_character := event.unicode_character end else inserted_character := event.character end if event.key = event.sdlk_escape then -- escape was pressed quit_prompt elseif inserted_character.code = 26 or inserted_character.is_equal ('z') then if event.is_control_pressed then if event.is_shift_pressed then -- redo if scene.history.can_redo then scene.history.redo ([]) end else -- undo if scene.history.can_undo then scene.history.undo ([]) end end end end tool.handle_key_down_event (event) update_scene end handle_key_up_event (event: EM_KEYBOARD_EVENT) is -- Handle Key releases. do Precursor {EM_COMPONENT_SCENE} (event) tool.handle_key_up_event (event) update_scene end handle_mouse_motion_event (event: EM_MOUSEMOTION_EVENT) is -- Handle mouse motion event. do Precursor {EM_COMPONENT_SCENE} (event) tool.handle_mouse_motion_event (event) editing_panel.draw update_cursor end handle_mouse_button_up_event (event: EM_MOUSEBUTTON_EVENT) is -- Handle mouse up event. do Precursor {EM_COMPONENT_SCENE} (event) tool.handle_mouse_button_up_event (event) update_cursor if scene.focus_on_scene then update_scene end editing_panel.set_changed end handle_mouse_button_down_event (event: EM_MOUSEBUTTON_EVENT) is -- Handle mouse down event. do Precursor {EM_COMPONENT_SCENE} (event) tool.handle_mouse_button_down_event (event) update_cursor if scene.focus_on_scene then update_scene end editing_panel.set_changed end handle_mouse_entered_editing_panel (b: BOOLEAN) is -- do scene.set_focus_on_scene (b) update_cursor if scene.focus_on_scene then update_scene end editing_panel.set_changed end handle_file_dialog_button_clicked (a_file_dialog: EM_FILE_DIALOG) is -- Handle click of a button on 'a_file_dialog'. do if not a_file_dialog.was_cancel_clicked and a_file_dialog.was_ok_clicked then if not a_file_dialog.filename.is_equal ("") then scene.save_as (a_file_dialog.directory, a_file_dialog.filename) handle_save_errors (a_file_dialog.directory, a_file_dialog.filename) scene_dropdown.set_changed end end end handle_export_file_dialog_button_clicked (a_file_dialog: EM_FILE_DIALOG; exp: EXPORTER) is -- Handle click of a button on 'a_file_dialog'. require a_file_dialog_not_void: a_file_dialog /= Void local saver: SCENE_SAVER dialog: EM_MESSAGE_DIALOG i: INTEGER do if not a_file_dialog.was_cancel_clicked and a_file_dialog.was_ok_clicked then if not a_file_dialog.filename.is_equal ("") then create saver.make (scene, a_file_dialog.directory, a_file_dialog.filename) i := saver.is_file_valid if i = 0 then error_message ("The given path is not valid!") elseif i = 1 then -- ok, the file can be created export_overwrite (a_file_dialog.directory, a_file_dialog.filename, exp) elseif i = 2 or i = 3 then -- prompt for overwrite create dialog.make_from_question ("Do you really want to overwrite the file "+a_file_dialog.filename+"?") dialog.set_modal (True) dialog.yes_button.clicked_event.subscribe (agent export_overwrite (a_file_dialog.directory, a_file_dialog.filename, exp)) dialog.show end end end end export_overwrite (a_path, a_file: STRING; exp: EXPORTER) is -- overwrite/write to the given file with export type `integer' local saver: SCENE_SAVER do create saver.make (scene, a_path, a_file) saver.export_overwrite (exp) end handle_file_dialog_button_clicked_to_open (a_file_dialog: EM_FILE_DIALOG) is -- Handle click of a button on 'a_file_dialog'. local a_scene: SCENE do if not a_file_dialog.was_cancel_clicked and a_file_dialog.was_ok_clicked then if a_file_dialog.is_file_selected then create a_scene.make a_scene.open (a_file_dialog.absolute_filename) if scene.open_error = 0 then -- no errors a_scene.set_file (a_file_dialog.directory, a_file_dialog.filename) tool.set_scene (a_scene) editing_panel.set_scene (a_scene) editing_panel.set_changed scene_dropdown.put (a_scene) scene_dropdown.set_selected_element (a_scene) elseif scene.open_error = 1 then error_message ("The format of the file is not valid!") elseif scene.open_error = 2 then error_message ("The file is not readable!") else error_message ("The file was not found!") end end end end handle_import_image_dialog_button_clicked (a_file_dialog: EM_FILE_DIALOG) is -- Handle click of a button on 'a_file_dialog'. local tuple: TUPLE [HEAP_PRIORITY_QUEUE_WALKABLE [IMAGE_PANE], STRING, DOUBLE] success: BOOLEAN do if not a_file_dialog.was_cancel_clicked and a_file_dialog.was_ok_clicked then if a_file_dialog.is_file_selected then create tuple tuple.put (scene.image_panes, 1) tuple.put (a_file_dialog.absolute_filename, 2) tuple.put (scene.scale, 3) scene.history.execute (create {IMPORT_IMAGE}.make, tuple) scene.set_changed if scene.history.execute_successful then -- the image has been loaded successfully success := True change_scene (scene) editing_panel.set_changed elseif scene.history.error_code = 1 then -- file not found error_message ("The file was not found") elseif scene.history.error_code = 3 then -- Capacity of image panes reached error_message ("You may add no more than "+scene.image_capacity.out+" image panes") else -- invalid image error_message ("The file was not a supported image file") end end end end feature {NONE} -- Dialogs quit_prompt is -- shows a prompt, to quit the application. local dialog: EM_MESSAGE_DIALOG do create dialog.make_from_question ("Do you really want to quit?") dialog.set_modal (True) dialog.yes_button.clicked_event.subscribe (agent quit) dialog.show end handle_save_errors (a_path, a_file: STRING) is -- scene.save has been called. If errors have occurred, fix them. require a_path_not_void: a_path /= Void a_file_not_void: a_file /= Void local dialog: EM_MESSAGE_DIALOG do if scene.save_error = 2 then -- prompt for overwrite create dialog.make_from_question ("Do you really want to overwrite the file "+a_file+"?") dialog.set_modal (True) dialog.yes_button.clicked_event.subscribe (agent save_overwrite (a_path, a_file)) dialog.show elseif scene.save_error = 1 then -- something went wrong - display error window error_message ("The file could not be saved") end scene_dropdown.set_changed save_button.set_enabled (not scene.is_saved) end error_message (s: STRING) is -- display an error message require s_not_void: s /= Void s_not_empty: not s.is_empty local dialog: EM_MESSAGE_DIALOG do create dialog.make_from_error (s) dialog.show dialog.set_modal (True) end feature {NONE} -- Button Press features new_scene is -- Adds a new empty scene. do scene_dropdown.put (create {SCENE}.make) end open_scene is -- Open a saved scene local file_dialog: EM_FILE_DIALOG do create file_dialog.make file_dialog.hide_close_button file_dialog.show file_dialog.button_clicked_event.subscribe (agent handle_file_dialog_button_clicked_to_open (file_dialog)) end save_scene is -- Saves the scene. do if not scene.is_saved then if scene.file = Void or else scene.file.is_equal ("") then save_scene_as else scene.save handle_save_errors (scene.path, scene.file) end end end save_scene_as is -- Saves the scene as. local file_dialog: EM_FILE_DIALOG do create file_dialog.make file_dialog.hide_close_button file_dialog.show file_dialog.button_clicked_event.subscribe (agent handle_file_dialog_button_clicked (file_dialog)) end save_overwrite (a_path, a_file: STRING) is -- -- saves and overwrites the set file. require a_path_not_void: a_path /= Void a_file_not_void: a_file /= Void do scene.set_file (a_path, a_file) scene.save_overwrite scene_dropdown.set_changed save_button.set_enabled (not scene.is_saved) end export_scene is -- export scene with the desired format. local dialog: EXPORT_DIALOG do create dialog.make (create {SCENE_SAVER}.make_empty) dialog.set_modal (True) dialog.yes_button.clicked_event.subscribe (agent handle_export_yes (dialog)) dialog.show end handle_export_yes (a_dialog: EXPORT_DIALOG) is -- export the scene with the selected option. -- pick file local file_dialog: EM_FILE_DIALOG do create file_dialog.make file_dialog.hide_close_button file_dialog.show file_dialog.button_clicked_event.subscribe (agent handle_export_file_dialog_button_clicked (file_dialog, a_dialog.list.selected_element)) end import_image is -- Adds an image to the scene. local file_dialog: EM_FILE_DIALOG do create file_dialog.make file_dialog.hide_close_button file_dialog.show file_dialog.button_clicked_event.subscribe (agent handle_import_image_dialog_button_clicked (file_dialog)) end undo is -- undo a step. do scene.history.undo ([]) scene.set_changed update_scene end redo is -- redo a step. do scene.history.redo ([]) scene.set_changed update_scene end cursor_tool is -- set selection tool. do if (not scene.vertex_mode) then tool.set_toolchanged tool := selection_tool elseif scene.vertex_mode then tool.set_toolchanged tool := vertex_selection_tool end tool.set_scene (scene) update_cursor end set_zoom_tool is -- set zoom tool. do tool.set_toolchanged tool := zoom_tool tool.set_scene (scene) update_cursor ensure tool_set: tool = zoom_tool end toggle_grid is -- turns the grid on and off. do scene.set_grid (not scene.grid) end toggle_display_mode is -- turns the grid on and off. do scene.set_vertex_mode (not scene.vertex_mode) tool.set_toolchanged if scene.vertex_mode then -- we are in vertex mode display_button.set_tooltip ("Set to Object View mode") display_button.set_image (display_img2) tool := vertex_selection_tool else display_button.set_tooltip ("Set to Vertex View mode") display_button.set_image (display_img1) tool := selection_tool end tool.set_scene (scene) update_cursor end set_pan_tool is -- set pan tool. do tool.set_toolchanged tool := pan_tool tool.set_scene (scene) update_cursor ensure tool_set: tool = pan_tool end set_polygon_tool is -- set polygon tool. do tool.set_toolchanged tool := create_polygon_tool tool.set_scene (scene) update_cursor ensure tool_set: tool = create_polygon_tool end set_circle_tool is -- set circle tool. do tool.set_toolchanged tool := create_circle_tool tool.set_scene (scene) update_cursor ensure tool_set: tool = create_circle_tool end set_rectangle_tool is -- set rectangle tool. do tool.set_toolchanged tool := create_rectangle_tool tool.set_scene (scene) update_cursor ensure tool_set: tool = create_rectangle_tool end set_polygon_edit_tool is -- set polygon edit tool. do if not scene.vertex_mode then toggle_display_mode end tool.set_toolchanged tool := polygon_edit_tool tool.set_scene (scene) update_cursor ensure tool_set: tool = polygon_edit_tool end update_cursor is -- update cursor. local cursor: EM_CURSOR do if last_cursor_id /= tool.cursor.id then -- do update, cursor has changed create cursor.make_from_surface (tool.cursor.bitmap, tool.cursor.offset_x, tool.cursor.offset_y) cursor.show last_cursor_id := tool.cursor.id end end last_cursor_id: INTEGER -- saves the last known cursor string_from_scene (a_scene: SCENE): STRING is -- String element from tuple as STRING. do Result := a_scene.name end change_scene (s: SCENE) is -- change the current scene. (triggered by dropdown selection) require s_not_void: s /= Void do -- update scene_dropdown scene_dropdown.set_changed update_scene end update_scene is -- updates the scenes do -- update disabled buttons save_button.set_enabled (not scene.is_saved) undo_button.set_enabled (scene.history.can_undo) redo_button.set_enabled (scene.history.can_redo) if scene.vertex_mode then -- we are in vertex mode display_button.set_tooltip ("Set to Object View mode") display_button.set_image (display_img2) else display_button.set_tooltip ("Set to Vertex View mode") display_button.set_image (display_img1) end -- update panel editing_panel.set_scene (scene) editing_panel.set_changed -- update tool if tool.scene /= scene then tool.set_toolchanged end tool.set_scene (scene) end feature {NONE} -- tools initialize_tools is -- creates all tools do create selection_tool.make (scene) create vertex_selection_tool.make (scene) create pan_tool.make (scene) create zoom_tool.make (scene) create create_circle_tool.make (scene) create create_rectangle_tool.make (scene) create create_polygon_tool.make (scene) create polygon_edit_tool.make (scene) tool := selection_tool end selection_tool: SELECTION_TOOL -- selection tool (default) vertex_selection_tool: VERTEX_SELECTION_TOOL -- vertex selection tool (same as selection tool, just in vertex mode) pan_tool: PAN_TOOL -- pan tool zoom_tool: ZOOM_TOOL -- zoom tool create_circle_tool: CREATE_CIRCLE_TOOL -- create circle tool create_rectangle_tool: CREATE_RECTANGLE_TOOL -- create rectangle tool create_polygon_tool: CREATE_POLYGON_TOOL -- create polygon tool polygon_edit_tool: POLYGON_EDIT_TOOL -- polygon edit tool is_unicode_enabled: BOOLEAN -- is unicode enabled? invariant tool_not_void: tool /= Void scene_not_void: scene /= Void end