1343 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1343 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| note
 | |
| 	description	: "[
 | |
| 		This sets up buttons and menus for "selecting" multiple views and different
 | |
| 		formats for those views within a `cell'.  The `cell', `menu', and `bar' can
 | |
| 		then be added to your container as appropriate.
 | |
| 
 | |
| 		It manages the placement of VIEWs in a `cell', allowing nested
 | |
| 		split areas to be hidden/shown using buttons and/or menus.  The views are placed
 | |
| 		in `cell' which can be placed in an EV_CONTAINER.
 | |
| 
 | |
| 		Views are added to Current using `extend' or `extend_siblings'.  Class JJ_MAIN_WINDOW
 | |
| 		has a feature `split_manager' (inherited from VIEW) which allows the placement of
 | |
| 		multiple panes (e.g. VIEWs, TOOLs, etc) into the window.  The `split_manager'
 | |
| 		controls the layout of these VIEWs.  The `initialize' feature from a class descended
 | |
| 		from JJ_MAIN_WINDOW may look like this
 | |
| 
 | |
| 		feature initialize is
 | |
| 				-- Set up a window with three VIEWs.
 | |
| 			do
 | |
| 				Precursor {JJ_MAIN_WINDOW}
 | |
| 					-- Allow the user to choose if the children are displayed
 | |
| 					-- as tabs, multiple panes, or as a single cell.
 | |
| 				split_manager.enable_mode_changes
 | |
| 					-- Add two VIEWs to be displayed in an EV_VERTICAL_SPLIT_AREA (when
 | |
| 					-- the window mode `is_split_mode'.)
 | |
| 				split_manager.set_vertical
 | |
| 				split_manager.extend (view_one)
 | |
| 				split_manager.extend (view_two)
 | |
| 					-- Add a third view into an EV_HORIZONTAL_SPLIT_AREA with the
 | |
| 					-- previouse two views (contained in the EV_VERTICAL_SPLIT_AREA)
 | |
| 					-- below the new one
 | |
| 				split_manager.extend_siblings (view_three, split_manager.last_item)
 | |
| 					-- NOTE:  a tool bar and menu items are automatically added.
 | |
| 			end
 | |
| 
 | |
| 		If the number of views added to Current is at least two then the `bar' is filled
 | |
| 		with a set of buttons and 'menu' is built with menu items for selecting the
 | |
| 		"mode" of the `cell'.  When `is_in_split_mode' (the default mode) a number of
 | |
| 		views will be displayed in EV_SPLIT_AREAs, recursively, within `cell'.  When
 | |
| 		`is_maximized_mode' only the `selected_view' will be placed in `cell'.  Finally,
 | |
| 		when `is_notebook_mode' the views will be displayed as tabs in an EV_NOTEBOOK
 | |
| 		within `cell'.
 | |
| 
 | |
| 		Here is how the `bar' looks when `is_maximized_mode' or `is_notebook_mode'.
 | |
| 
 | |
| 			PB = `preferences_button'
 | |
| 			SB = `split_button'
 | |
| 			MB = `maximize_button'
 | |
| 			NB = `notebook_button'
 | |
| 			RB = an EV_TOOL_BAR_RADIO_BUTTON
 | |
| 
 | |
| 		  |---------------------- bar --------------------------------------|
 | |
| 		  | |--- mode_bar ---|  |--------------- radio bar -------------|   |
 | |
| 		  | |  |SB| |MB| |NB|   |  |  |RB| |RB| ... to number of views  |   |
 | |
| 		
 | |
| 		When one of the radio buttons is pressed the corresponding view is brought to
 | |
| 		the top.
 | |
| 
 | |
| 		When `is_split_mode' the radio buttons are replaced with EV_TOOL_BAR_TOGGLE_BUTTONs.
 | |
| 
 | |
| 			TB = an EV_TOOL_BAR_TOGGLE_BUTTON
 | |
| 
 | |
| 		  |------------------------------- bar ---------------------------|
 | |
| 		  | |--- mode_bar ---|  |-------------- toggle bar -----------|   |
 | |
| 		  | | |SB| |MB| |NB| |  |   |TB| |TB| ... to number of views  |   |
 | |
| 
 | |
| 		When a toggle button is selected the corresponding view becomes visible in a split
 | |
| 		area calculated on the fly.
 | |
| 
 | |
| 		The items in `menu' are kept in parallel with the buttons, allowing menu selection
 | |
| 		to accomplish the same things as the buttons.
 | |
| 		]"
 | |
| 	date: "12 Nov 07"
 | |
| 	author:		"Jimmy J. Johnson"
 | |
| 	copyright:	"Copyright 2012, Jimmy J. Johnson"
 | |
| 	license:	"Eiffel Forum License v2 (see forum.txt)"
 | |
| 	URL: 		"$URL: file:///F:/eiffel_repositories/jj_vision/trunk/interface/system/split_manager.e $"
 | |
| 	date:		"$Date: 2014-05-31 08:53:58 -0400 (Sat, 31 May 2014) $"
 | |
| 	revision:	"$Revision: 17 $"
 | |
| 
 | |
| class
 | |
| 	SPLIT_MANAGER
 | |
| 
 | |
| inherit
 | |
| 
 | |
| 	SHARED
 | |
| 		export
 | |
| 			{NONE} all
 | |
| 		redefine
 | |
| 			default_create
 | |
| 		end
 | |
| 
 | |
| 	S_TREE
 | |
| 		redefine
 | |
| 			default_create,
 | |
| 			root,
 | |
| 			set_root,
 | |
| 			extend,
 | |
| 			extend_siblings
 | |
| 		end
 | |
| 
 | |
| 	PIXEL_BUFFERS
 | |
| 		undefine
 | |
| 			default_create
 | |
| 		end
 | |
| 
 | |
| create
 | |
| 	default_create
 | |
| 
 | |
| feature {NONE} -- Initialization
 | |
| 
 | |
| 	default_create
 | |
| 			-- Initialize current
 | |
| 		do
 | |
| 			Precursor {S_TREE}
 | |
| 				-- create exported widgets
 | |
| 			create bar
 | |
| 			create menu
 | |
| 			create cell
 | |
| 
 | |
| --			create root.make (default_view)
 | |
| 			last_node := root
 | |
| 			selected_node := root
 | |
| --			view := default_view
 | |
| 				-- Assume split mode
 | |
| 			is_split_mode := True
 | |
| 				-- Only need these widgets if more than one view is added.
 | |
| 			create notebook
 | |
| 				-- create tool bars
 | |
| 			create toggle_bar
 | |
| 			create radio_bar
 | |
| 			create mode_bar
 | |
| 				-- create buttons and menus
 | |
| 			create single_mode_button
 | |
| 			create split_mode_button
 | |
| 			create notebook_mode_button
 | |
| 			create mode_menu
 | |
| 			create toggle_menu
 | |
| 			create radio_menu
 | |
| 			create single_mode_item
 | |
| 			create split_mode_item
 | |
| 			create notebook_mode_item
 | |
| 				-- Set widget attributes
 | |
| 			single_mode_button.set_pixmap (create {EV_PIXMAP}.make_with_pixel_buffer (Icon_format_text_color_buffer))
 | |
| 			single_mode_button.set_tooltip ("Single mode")
 | |
| 			split_mode_button.set_pixmap (create {EV_PIXMAP}.make_with_pixel_buffer (Icon_new_development_tool_color_buffer))
 | |
| 			split_mode_button.set_tooltip ("Split mode")
 | |
| 			notebook_mode_button.set_pixmap (create {EV_PIXMAP}.make_with_pixel_buffer (Icon_folders_color_buffer))
 | |
| 			notebook_mode_button.set_tooltip ("Tab mode")
 | |
| 				-- Set up the `mode_bar' and its buttons.
 | |
| --			mode_bar.extend (create {EV_TOOL_BAR_SEPARATOR})
 | |
| 			mode_bar.extend (single_mode_button)
 | |
| 			mode_bar.extend (split_mode_button)
 | |
| 			mode_bar.extend (notebook_mode_button)
 | |
| --			mode_bar.extend (create {EV_TOOL_BAR_SEPARATOR})
 | |
| 			split_mode_button.enable_select
 | |
| 				-- Set up menus which do not change
 | |
| 			menu.set_text ("Views")
 | |
| 			mode_menu.set_text ("Mode")
 | |
| 			radio_menu.set_text ("Select view")
 | |
| 			toggle_menu.set_text ("Select view")
 | |
| 			single_mode_item.set_text ("Maximize Mode")
 | |
| 			split_mode_item.set_text ("Split Mode")
 | |
| 			notebook_mode_item.set_text ("Notebook Mode")
 | |
| 			mode_menu.extend (single_mode_item)
 | |
| 			mode_menu.extend (split_mode_item)
 | |
| 			mode_menu.extend (notebook_mode_item)
 | |
| 			split_mode_item.enable_select
 | |
| 				-- Actions for `notebook'
 | |
| 			notebook.selection_actions.extend (agent on_tab_selected)
 | |
| 				-- Actions for buttons
 | |
| --			preferences_button.select_actions.extend (agent on_show_preferences_dialog)
 | |
| 			split_mode_button.select_actions.extend (agent set_split_mode)
 | |
| 			single_mode_button.select_actions.extend (agent set_single_mode)
 | |
| 			notebook_mode_button.select_actions.extend (agent set_notebook_mode)
 | |
| 				-- Actions for menu items
 | |
| --			preferences_item.select_actions.extend (agent on_show_preferences_dialog)
 | |
| 			single_mode_item.select_actions.extend (agent set_single_mode)
 | |
| 			split_mode_item.select_actions.extend (agent set_split_mode)
 | |
| 			notebook_mode_item.select_actions.extend (agent set_notebook_mode)
 | |
| 		end
 | |
| 
 | |
| feature -- Access
 | |
| 
 | |
| 	cell: EV_CELL
 | |
| 			-- The container which will be managed.  The views will be placed
 | |
| 			-- into `cell' based on the user's button, or menu selections.
 | |
| 			-- This should be extended into a widget.
 | |
| 
 | |
| 	menu: EV_MENU
 | |
| 			-- Menu of items to toggle views on and off.
 | |
| 			-- Can be inserted into window menu.
 | |
| 
 | |
| 	bar: EV_HORIZONTAL_BOX
 | |
| 			-- Bar of buttons used to manage views.
 | |
| 			-- Can be inserted into a toolbar.
 | |
| 
 | |
| 	selected_view: detachable VIEW
 | |
| 			-- The currently selected view.
 | |
| 		do
 | |
| 			if attached selected_node as sn then
 | |
| 				Result := sn.view
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	view_count: INTEGER
 | |
| 			-- The number of VIEWs contained in and managed by Current.
 | |
| 		do
 | |
| 			Result := descendents.count
 | |
| 		end
 | |
| 
 | |
| 	visible_count: INTEGER
 | |
| 			-- The number of VIEWs which are visible.
 | |
| 		local
 | |
| 			s: like leaf_nodes
 | |
| 			n: like root
 | |
| 		do
 | |
| 			s := leaf_nodes
 | |
| 			from s.start
 | |
| 			until s.exhausted
 | |
| 			loop
 | |
| 				n := s.item
 | |
| 				if n.is_visible then
 | |
| 					Result := Result + 1
 | |
| 				end
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	first_visible_view: VIEW
 | |
| 			-- The first view which is visible.
 | |
| 		local
 | |
| 			s: like leaf_nodes
 | |
| 			n: like root
 | |
| 			l_result: detachable VIEW
 | |
| 		do
 | |
| 			s := leaf_nodes
 | |
| 			from s.start
 | |
| 			until l_result /= Void or else s.exhausted
 | |
| 			loop
 | |
| 				n := s.item
 | |
| 				if n.is_visible then
 | |
| 					l_result := n.view
 | |
| 				end
 | |
| 				s.forth
 | |
| 			end
 | |
| 			if l_result = Void then
 | |
| 				Result := Default_view
 | |
| 			else
 | |
| 				Result := l_result
 | |
| 			end
 | |
| 		ensure
 | |
| 			result_exists: Result /= Void
 | |
| 		end
 | |
| 
 | |
| 	default_view: DEFAULT_VIEW
 | |
| 			-- Create an EV_LABEL as a place holder
 | |
| 		do
 | |
| 			create Result
 | |
| 			Result.set_pebble (Result)
 | |
| 			Result.set_text ("Empty:  no VIEW")
 | |
| 		end
 | |
| 
 | |
| 	state: SPLIT_MANAGER_STATE
 | |
| 			-- Create a structure representing the state of Current; to be used
 | |
| 			-- by `restore_state' during execution start.
 | |
| 		do
 | |
| 			save_split_positions
 | |
| 			create Result.make (Current)
 | |
| 		ensure
 | |
| 			result_exists: Result /= Void
 | |
| 		end
 | |
| 
 | |
| feature -- Element change
 | |
| 
 | |
| 	set_root (a_root: like root)
 | |
| 			-- Change `root' and resync the manager.
 | |
| 		do
 | |
| 			Precursor {S_TREE} (a_root)
 | |
| 			syncronize
 | |
| 		end
 | |
| 
 | |
| --	restore_with_state (a_state: SPLIT_MANAGER_STATE) is
 | |
| --			-- Restore Current to state as represented in `a_state'
 | |
| --		require
 | |
| --			state_exists: a_state /= Void
 | |
| --		local
 | |
| --			des: like descendents
 | |
| --			ns: SPLIT_MANAGER_NODE_STATE
 | |
| --		do
 | |
| --			if a_state.is_mode_frozen then
 | |
| --				disable_mode_changes
 | |
| --			else
 | |
| --				enable_mode_changes
 | |
| --			end
 | |
| --			if a_state.is_interface_frozen then
 | |
| --				disable_interface_changes
 | |
| --			else
 | |
| --				enable_interface_changes
 | |
| --			end
 | |
| --			if a_state.is_single_mode then
 | |
| --				set_single_mode
 | |
| --			elseif a_state.is_split_mode then
 | |
| --				set_split_mode
 | |
| --			elseif a_state.is_notebook_mode then
 | |
| --				set_notebook_mode
 | |
| --			else
 | |
| --				check
 | |
| --					should_not_happen: False
 | |
| --						-- because there are only three modes.
 | |
| --				end
 | |
| --			end
 | |
| --				-- Restore each node's state
 | |
| --			des := root.descendents
 | |
| --			check
 | |
| --				same_count: des.count = a_state.node_states.count
 | |
| --					-- The saved node states should have the same form as the
 | |
| --					-- node tree in the current window.
 | |
| --			end
 | |
| --			from
 | |
| --				a_state.node_states.start
 | |
| --				des.start
 | |
| --			until a_state.node_states.exhausted or else des.exhausted
 | |
| --			loop
 | |
| --				ns := a_state.node_states.item
 | |
| --				des.item.restore_with_state (ns)
 | |
| --				a_state.node_states.forth
 | |
| --				des.forth
 | |
| --			end
 | |
| --			syncronize
 | |
| --		end
 | |
| 
 | |
| feature -- Basic operations
 | |
| 
 | |
| 	extend (a_item: VIEW)
 | |
| 			-- Add `a_item' as a sibling to the previously added item.
 | |
| 		do
 | |
| 			Precursor {S_TREE} (a_item)
 | |
| 			if selected_node = Void then
 | |
| 				selected_node := corresponding_node (a_item)
 | |
| 			end
 | |
| 			add_agents (corresponding_node (a_item))
 | |
| 			syncronize
 | |
| 		end
 | |
| 
 | |
| 	extend_siblings (a_first, a_second: VIEW)
 | |
| 			-- Searching from `root', find the nodes containing `a_first', and/or
 | |
| 			-- `a_second' or, if not finding them, create new nodes containing
 | |
| 			-- `a_first', and `a_second' and make them children of a new node.
 | |
| 			--  Make `root' reference the new node.
 | |
| 		local
 | |
| 			n: like root
 | |
| 			had_first, had_second: BOOLEAN
 | |
| 		do
 | |
| 				-- Prevent agents from being added twice if the tree already has the item.
 | |
| 			if has (a_first) then
 | |
| 				had_first := True
 | |
| 			end
 | |
| 			if has (a_second) then
 | |
| 				had_second := True
 | |
| 			end
 | |
| 			Precursor {S_TREE} (a_first, a_second)
 | |
| 			n := corresponding_node (a_first)
 | |
| 			if selected_node = Void then
 | |
| 				selected_node := n
 | |
| 			end
 | |
| 			if n.is_view and then not had_first then
 | |
| 				add_agents (n)
 | |
| 			end
 | |
| 			n := corresponding_node (a_second)
 | |
| 			if n.is_view and then not had_second then
 | |
| 				add_agents (n)
 | |
| 			end
 | |
| 			syncronize
 | |
| 		end
 | |
| 
 | |
| 	wipe_out_views
 | |
| 			-- Clean out all the views in preperation for rebuilding.
 | |
| 		do
 | |
| 				-- Wipe out the containers
 | |
| 			notebook.wipe_out
 | |
| 				-- Wipe out the EV_CONTAINERs
 | |
| 			toggle_bar.wipe_out
 | |
| 			radio_bar.wipe_out
 | |
| 			toggle_menu.wipe_out
 | |
| 			radio_menu.wipe_out
 | |
| 				-- Reset the view to default state
 | |
| 			selected_node := root
 | |
| --			build_bars
 | |
| 		end
 | |
| 
 | |
| 	select_view (a_view: VIEW)
 | |
| 			-- Make `a_view' the `selected_view'
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 			has_view: has_view (a_view)
 | |
| 		do
 | |
| 			check attached corresponding_node (a_view) as n then
 | |
| 				n.show
 | |
| 				selected_node := n
 | |
| 			end
 | |
| 			syncronize
 | |
| 		ensure
 | |
| 			view_was_selected: selected_view = a_view
 | |
| 		end
 | |
| 
 | |
| 	toggle_view (a_view: VIEW)
 | |
| 			-- If `a_view' is hidden then show it; if it is shown hide it.
 | |
| 			-- The effect from this will show up in split mode.
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 			has_view: has_view (a_view)
 | |
| 		local
 | |
| 			n: like root
 | |
| 		do
 | |
| 			n := corresponding_node (a_view)
 | |
| 			check
 | |
| 				is_view: n.is_view
 | |
| 					-- Because if `has_view' then `n' must be a view.
 | |
| 			end
 | |
| 			if n.is_hidden then
 | |
| 				n.show
 | |
| 				selected_node := n
 | |
| 			else
 | |
| 				if visible_count > 1 then
 | |
| 					save_split_positions
 | |
| 					n.hide
 | |
| 				end
 | |
| 			end
 | |
| 			syncronize
 | |
| 		end
 | |
| 
 | |
| 	show_all_views
 | |
| 			-- Make all the views visible
 | |
| 		local
 | |
| 			s: like leaf_nodes
 | |
| 		do
 | |
| 			s := leaf_nodes
 | |
| 			from s.start
 | |
| 			until s.exhausted
 | |
| 			loop
 | |
| 				s.item.show
 | |
| 				s.forth
 | |
| 			end
 | |
| 			syncronize
 | |
| 		end
 | |
| 
 | |
| 	show_view (a_view: VIEW)
 | |
| 			-- Make `a_view' visible
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 			has_view: has_view (a_view)
 | |
| 		local
 | |
| 			n: like root
 | |
| 		do
 | |
| 			n := corresponding_node (a_view)
 | |
| 			if not n.is_visible then
 | |
| 				n.show
 | |
| 				restore_split_positions
 | |
| 			end
 | |
| 			select_view (a_view)
 | |
| 		ensure
 | |
| 			view_visible: corresponding_node (a_view).is_visible
 | |
| 			view_selected: selected_view = a_view
 | |
| 		end
 | |
| 
 | |
| 	hide_view (a_view: VIEW)
 | |
| 			-- React to a request to hide `a_view'
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 			has_view: has_view (a_view)
 | |
| 			is_in_split_mode: is_split_mode
 | |
| 		local
 | |
| 			n: like root
 | |
| 		do
 | |
| 			if visible_count > 1 then
 | |
| 				save_split_positions
 | |
| 				n := corresponding_node (a_view)
 | |
| 				n.hide
 | |
| 				if selected_view = a_view then
 | |
| 						-- Must select another
 | |
| 					select_view (first_visible_view)
 | |
| 				end
 | |
| 				syncronize
 | |
| 			end
 | |
| 		ensure
 | |
| 			view_not_visible: old visible_count > 1 implies not corresponding_node (a_view).is_visible
 | |
| 		end
 | |
| 
 | |
| 	disable_view (a_view: VIEW)
 | |
| 			-- Prevent `a_view' from appearing and also remove the
 | |
| 			-- buttons and menus which will allow it to be shown.
 | |
| 			-- Use `enable_view' to restore it to normal.
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 			has_view: has_view (a_view)
 | |
| 		do
 | |
| 			save_split_positions
 | |
| 			corresponding_node (a_view).disable
 | |
| --			build_bars
 | |
| --			build_cell
 | |
| 			syncronize
 | |
| 		ensure
 | |
| 			is_in_disabled_views: corresponding_node (a_view).is_disabled
 | |
| 		end
 | |
| 
 | |
| 	enable_view (a_view: VIEW)
 | |
| 			-- Sets the view handling for `a_view' back to normal
 | |
| 			-- by restoring the corresponding buttons and menues.
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 			has_view: has_view (a_view)
 | |
| 		do
 | |
| 			corresponding_node (a_view).enable
 | |
| --			build_bars
 | |
| --			build_cell
 | |
| 			restore_split_positions
 | |
| 			syncronize
 | |
| 		ensure
 | |
| 			view_not_disabled: not corresponding_node (a_view).is_disabled
 | |
| 		end
 | |
| 
 | |
| 	set_single_mode_view (a_view: VIEW)
 | |
| 			-- Set to single mode with `a_view' visible, filling the `cell'.
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 			has_view: has_view (a_view)
 | |
| --			mode_is_changable: is_mode_changable
 | |
| 		do
 | |
| 			set_single_mode
 | |
| 			if selected_view /= a_view then
 | |
| 				select_view (a_view)
 | |
| 			end
 | |
| 		ensure
 | |
| 			is_single_mode: is_single_mode
 | |
| 			correct_view_selected: selected_view = a_view
 | |
| 		end
 | |
| 
 | |
| 	set_split_mode_view (a_view: VIEW)
 | |
| 			-- Multiple views can be visible within `cell'.
 | |
| 			-- Ensure `a_view' is the selected view.
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 			has_view: has_view (a_view)
 | |
| --			mode_is_changable: is_mode_changable
 | |
| 		do
 | |
| 			set_split_mode
 | |
| 			if selected_view /= a_view then
 | |
| 				select_view (a_view)
 | |
| 			end
 | |
| 		ensure
 | |
| 			is_split_mode: is_split_mode
 | |
| 			correct_view_selected: selected_view = a_view
 | |
| 		end
 | |
| 
 | |
| 	set_notebook_mode_view (a_view: VIEW)
 | |
| 			-- Change to notebook style with `a_view' on top.
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 			has_view: has_view (a_view)
 | |
| --			mode_is_changable: is_mode_changable
 | |
| 		do
 | |
| 			set_notebook_mode
 | |
| 			if selected_view /= a_view then
 | |
| 				select_view (a_view)
 | |
| 			end
 | |
| 		ensure
 | |
| 			is_notebook_mode: is_notebook_mode
 | |
| 			correct_view_selected: selected_view = a_view
 | |
| 		end
 | |
| 
 | |
| feature -- Status report
 | |
| 
 | |
| 	is_interface_frozen: BOOLEAN
 | |
| 			-- Is the set of visible views frozen (i.e. can the user toggle a view
 | |
| 			-- on or off)?  (Assuming there is more than one view.)
 | |
| 			-- This affects the interface, not the programmers ability to change.
 | |
| 
 | |
| 	is_mode_frozen: BOOLEAN
 | |
| 			-- Is the "mode" frozen (i.e. if `is_single_mode' always single mode)?
 | |
| 			-- This affects the interface, not the programmers ability to change.
 | |
| 			-- See `enable_mode_changes' and `disable_mode_changes'.
 | |
| 
 | |
| 	is_single_mode: BOOLEAN
 | |
| 			-- Is only one view in `cell'?
 | |
| 
 | |
| 	is_split_mode: BOOLEAN
 | |
| 			-- Is the view in split mode (multiple views showing)?
 | |
| 
 | |
| 	is_notebook_mode: BOOLEAN
 | |
| 			-- Is the view in notebook mode (multiple views in an EV_NOTEBOOK)?
 | |
| 
 | |
| feature -- Status setting
 | |
| 
 | |
| 	enable_mode_changes
 | |
| 			-- Allow the *user* (not to be confused with *programer*) to change
 | |
| 			-- the way the contained views (if there is more than one view) are
 | |
| 			-- presented in `cell' by setting `is_mode_frozen' to True.
 | |
| 			-- If more than one view is present and `is_interface_frozen' then
 | |
| 			-- buttons and menus for changing the mode will be made available to
 | |
| 			-- the programmer in `bar' and `menu' which can then be presented to
 | |
| 			-- the user.
 | |
| 		do
 | |
| 			is_mode_frozen := False
 | |
| 			if not is_empty and then view_count >= 2 then
 | |
| 				build_bars
 | |
| 			end
 | |
| 			build_cell
 | |
| 		ensure
 | |
| 			mode_is_changable: not is_mode_frozen
 | |
| 		end
 | |
| 
 | |
| 	disable_mode_changes
 | |
| 			-- Prevent *user* changes to the "mode" by setting `is_mode_changable'
 | |
| 			-- to False.  The user will see what ever appearance has been set
 | |
| 			-- by the programmer using the `set_..._mode' features.
 | |
| 			-- See `set_split_mode', `set_single_mode',and `set_notebook_mode'.
 | |
| 		do
 | |
| 			is_mode_frozen := True
 | |
| 		ensure
 | |
| 			mode_is_not_changable: is_mode_frozen
 | |
| 		end
 | |
| 
 | |
| 	enable_interface_changes
 | |
| 			-- Allow the *user* to toggle the visible views.
 | |
| 			-- Used to add the buttons and menues from `bar'.
 | |
| 		do
 | |
| 			is_interface_frozen := False
 | |
| 		ensure
 | |
| 			views_are_changable: not is_interface_frozen
 | |
| 		end
 | |
| 
 | |
| 	disable_interface_changes
 | |
| 			-- Prevent the *user* from toggling the visible views.
 | |
| 			-- Used to hide or remove the buttons and menues from `bar'.
 | |
| 		do
 | |
| 			is_interface_frozen := True
 | |
| 		ensure
 | |
| 			views_not_changable: is_interface_frozen
 | |
| 		end
 | |
| 
 | |
| 	set_single_mode
 | |
| 			-- Make the `cell' hold only one widget, either the `selected_view' or,
 | |
| 			-- if there are no views, a `default_view'.
 | |
| --		require
 | |
| --			mode_is_changable: is_mode_changable
 | |
| 		do
 | |
| 			if not is_single_mode then
 | |
| 				if is_split_mode then
 | |
| 					save_split_positions
 | |
| 				end
 | |
| 				is_single_mode := True
 | |
| 				is_split_mode := False
 | |
| 				is_notebook_mode := False
 | |
| 				syncronize
 | |
| 			end
 | |
| --			select_view (selected_view)
 | |
| 		ensure
 | |
| 			is_single_mode: is_single_mode
 | |
| 		end
 | |
| 
 | |
| 	set_split_mode
 | |
| 			-- Make the `cell' hold the views recursively in EV_SPLIT_AREAs.
 | |
| 			-- If there are no views then `cell' contains a `default_view'.
 | |
| 		require
 | |
| 			is_mode_changable: not is_mode_frozen
 | |
| 		local
 | |
| 			d: like descendents
 | |
| 		do
 | |
| 			if not is_split_mode then
 | |
| 				is_split_mode := True
 | |
| 				is_single_mode := False
 | |
| 				is_notebook_mode := False
 | |
| 				restore_split_positions
 | |
| 				syncronize
 | |
| 			end
 | |
| 			if not attached selected_view or else (
 | |
| 					attached selected_view as v and then not has (v)) then
 | |
| 				d := descendents
 | |
| 				if not d.is_empty then
 | |
| 					selected_node := descendents.first
 | |
| 				end
 | |
| 			end
 | |
| 			check attached selected_view as v then
 | |
| 				select_view (v)
 | |
| 			end
 | |
| 		ensure
 | |
| 			is_split_mode: is_split_mode
 | |
| 		end
 | |
| 
 | |
| 	set_notebook_mode
 | |
| 			-- Make `cell' hold the views in an EV_NOTEBOOK.
 | |
| 			-- If there are no views then `cell' contains a `default_view'.
 | |
| --		require
 | |
| --			is_mode_changable: is_mode_changable
 | |
| 		do
 | |
| 			if not is_notebook_mode then
 | |
| 				if is_split_mode then
 | |
| 					save_split_positions
 | |
| 				end
 | |
| 				is_notebook_mode := True
 | |
| 				is_single_mode := False
 | |
| 				is_split_mode := False
 | |
| 				syncronize
 | |
| 			end
 | |
| --			select_view (selected_view)
 | |
| 		ensure
 | |
| 			is_notebook_mode: is_notebook_mode
 | |
| 		end
 | |
| 
 | |
| feature -- Query
 | |
| 
 | |
| 	is_visible (a_view: VIEW): BOOLEAN
 | |
| 			-- Is `a_view' visible?  (I.e. should it be added to `cell'?)
 | |
| 		do
 | |
| 			Result := has (a_view) and then corresponding_node (a_view).is_visible
 | |
| 		end
 | |
| 
 | |
| 	is_disabled (a_view: VIEW): BOOLEAN
 | |
| 			-- Is `a_view' able to be shown?
 | |
| 		do
 | |
| 			Result := has (a_view) and then corresponding_node (a_view).is_disabled
 | |
| 		end
 | |
| 
 | |
| 	has_split (a_split_area: EV_SPLIT_AREA): BOOLEAN
 | |
| 			-- Does Current contain/manage `a_split_area'?
 | |
| 		require
 | |
| 			split_exists: a_split_area /= Void
 | |
| 		local
 | |
| 			s: like internal_nodes
 | |
| 		do
 | |
| 			s := internal_nodes
 | |
| 			from s.start
 | |
| 			until Result or else s.exhausted
 | |
| 			loop
 | |
| 				Result := s.item.view = a_split_area
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	has_view (a_view: VIEW): BOOLEAN
 | |
| 			-- Does Current contain/manage `a_view'?
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 		local
 | |
| 			s: like leaf_nodes
 | |
| 		do
 | |
| 			s := leaf_nodes
 | |
| 			from s.start
 | |
| 			until Result or else s.exhausted
 | |
| 			loop
 | |
| 				Result := s.item.view = a_view
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	is_conforming_type (a_view: ANY): BOOLEAN
 | |
| 			-- Does `a_view' conform to VIEW or EV_SPLIT_AREA?
 | |
| 			-- Would have preferred for `a_view' to be an EV_WIDGET but that caused
 | |
| 			-- too many name clashes in decendents of VIEW.
 | |
| 		require
 | |
| 			view_exists: a_view /= Void
 | |
| 		do
 | |
| 			Result := a_view.conforms_to ({VIEW}) or else a_view.conforms_to ({EV_SPLIT_AREA})
 | |
| 		ensure
 | |
| 			definition: Result implies a_view.conforms_to ({VIEW}) or else a_view.conforms_to ({EV_SPLIT_AREA})
 | |
| 		end
 | |
| 
 | |
| feature {SPLIT_MANAGER_STATE} -- Implementation (Query)
 | |
| 
 | |
| 	root: detachable SPLIT_MANAGER_NODE
 | |
| 			-- Root node of the tree.
 | |
| 
 | |
| 	selected_node: like root
 | |
| 			-- The node corresponding the the view last selected by the user.
 | |
| 
 | |
| feature {NONE} -- Implementation (Basic operations)
 | |
| 
 | |
| 	add_agents (a_node: attached like root)
 | |
| 			-- Add agents to toggle/raise/minimize the widget
 | |
| 			-- (a VIEW) in `a_node'.
 | |
| 		require
 | |
| 			node_exists: a_node /= Void
 | |
| 			is_view: a_node.is_view
 | |
| 			has_view: has_node (a_node)
 | |
| 		do
 | |
| 			a_node.toggle_button.select_actions.extend (agent toggle_view (a_node.view))
 | |
| 			a_node.radio_button.select_actions.extend (agent select_view (a_node.view))
 | |
| 			a_node.toggle_item.select_actions.extend (agent toggle_view (a_node.view))
 | |
| 			a_node.radio_item.select_actions.extend (agent select_view (a_node.view))
 | |
| 				-- Add actions to the buttons of `a_view' if it is a TOOL
 | |
| 			if attached {TOOL} a_node.view as t then
 | |
| 					-- This item is a tool and therefore has buttons.
 | |
| 				t.maximize_actions.extend (agent set_single_mode_view (a_node.view))
 | |
| 				t.restore_actions.extend (agent set_split_mode_view (a_node.view))
 | |
| 				t.close_actions.extend (agent hide_view (a_node.view))
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	save_split_positions
 | |
| 			-- Save the position of splitters for restoration later.
 | |
| 		local
 | |
| 			n: SPLIT_MANAGER_NODE
 | |
| 			s: like internal_nodes
 | |
| 		do
 | |
| 			s := internal_nodes
 | |
| 			from s.start
 | |
| 			until s.exhausted
 | |
| 			loop
 | |
| 				n := s.item
 | |
| 				check
 | |
| 					node_holds_split_area: n.is_split
 | |
| 						-- Because only EV_SPLIT_AREA widgets are added to the nodes in `splits'.
 | |
| 				end
 | |
| 				n.save_split_position
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	restore_split_positions
 | |
| 			-- Set the split position of each visible split area to what it was
 | |
| 			-- when it was last visible.
 | |
| 		local
 | |
| 			n: SPLIT_MANAGER_NODE
 | |
| 			s: like internal_nodes
 | |
| 		do
 | |
| 			s := internal_nodes
 | |
| 			from s.start
 | |
| 			until s.exhausted
 | |
| 			loop
 | |
| 				n := s.item
 | |
| 				check
 | |
| 					node_holds_split_area: n.is_split
 | |
| 						-- Because only EV_SPLIT_AREA widgets are added to the nodes in `splits'.
 | |
| 				end
 | |
| 				n.restore_split_position
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	syncronize
 | |
| 			-- Rebuild all the externally accessed widgets such as `cell', `menu',
 | |
| 			-- and `button_bar' reflect the state of the buttons.
 | |
| 			-- Also ensure that at least one view is visible if there are any views.
 | |
| 			-- and update button and menu states.
 | |
| 		do
 | |
| 			build_cell
 | |
| 			if visible_count >= 1 then
 | |
| 				syncronize_tools
 | |
| 					-- Make sure the radio items and buttons for the `selected_node' are set to
 | |
| 					-- the correct state.  This must be called after the radio buttons are added
 | |
| 					-- to the bar because the radio buttons for all the views must work together
 | |
| 					-- (when one selected the other turn off.)
 | |
| 				restore_split_positions
 | |
| --				syncronize_view_selection_items
 | |
| 			end
 | |
| 			if view_count >= 2 then
 | |
| 				build_bars
 | |
| 				syncronize_mode_selection_items
 | |
| 				check attached selected_node as sn then
 | |
| 					sn.syncronize_buttons
 | |
| 				end
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	syncronize_tools
 | |
| 			-- Make sure any TOOLs handled by the manager are in the correct
 | |
| 			-- state, either maximized or normal.
 | |
| 		local
 | |
| 			s: like leaf_nodes
 | |
| 		do
 | |
| 			s := leaf_nodes
 | |
| 			from s.start
 | |
| 			until s.exhausted
 | |
| 			loop
 | |
| 				if attached {TOOL} s.item.view as t then
 | |
| 					if s.count <= 1 then
 | |
| 						t.disable_resize
 | |
| 					else
 | |
| 						t.enable_resize
 | |
| 					end
 | |
| 					if is_single_mode then
 | |
| 						if t.is_resizable then
 | |
| 							t.maximize
 | |
| 						end
 | |
| 					else
 | |
| 						if t.is_resizable then
 | |
| 							t.restore
 | |
| 						end
 | |
| 					end
 | |
| 					if is_split_mode then
 | |
| 						t.close_button.enable_sensitive
 | |
| 						t.maximize_button.enable_sensitive
 | |
| 						t.restore_button.enable_sensitive
 | |
| 					else
 | |
| 						t.close_button.disable_sensitive
 | |
| 						t.maximize_button.disable_sensitive
 | |
| --						t.restore_button.disable_sensitive
 | |
| 					end
 | |
| 				end
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| --	syncronize_view_selection_items is
 | |
| --			-- Make sure the state of the radio and toggle reflect the value
 | |
| --			-- of `selected_view' and visible views.
 | |
| --		local
 | |
| --			n: like root
 | |
| --		do
 | |
| --					-- Fix the radio items
 | |
| --			
 | |
| --			i := views.index_of (selected_view, 1)
 | |
| --			rb := radio_buttons.i_th (i)
 | |
| --			ri := radio_items.i_th (i)
 | |
| --			ri.select_actions.block
 | |
| --			ri.enable_select
 | |
| --			ri.select_actions.resume
 | |
| --			rb.select_actions.block
 | |
| --			rb.enable_select
 | |
| --			rb.select_actions.resume
 | |
| --					-- Fix the toggle items
 | |
| --			from views.start
 | |
| --			until views.exhausted
 | |
| --			loop
 | |
| --				i := views.index
 | |
| --				wv := views.item
 | |
| --				if not disabled_views.has (wv) then
 | |
| --					tb := toggle_buttons.i_th (i)
 | |
| --					ti := toggle_items.i_th (i)
 | |
| --					ti.select_actions.block
 | |
| --					tb.select_actions.block
 | |
| --					if visible_views.has (wv) then
 | |
| --						ti.enable_select
 | |
| --						tb.enable_select
 | |
| --					else
 | |
| --						ti.disable_select
 | |
| --						tb.disable_select
 | |
| --					end
 | |
| --					ti.select_actions.resume
 | |
| --					tb.select_actions.resume
 | |
| --				end
 | |
| --				views.forth
 | |
| --			end
 | |
| --		ensure
 | |
| --			selected_view_unchanged: selected_view = old selected_view
 | |
| --			toggle_items_agree: toggles_agree_with_visible_items
 | |
| --			radio_items_agree: radios_agree_with_selected_view
 | |
| --		end
 | |
| 
 | |
| 	syncronize_mode_selection_items
 | |
| 			-- Set the button states
 | |
| 		require
 | |
| 			at_least_two_views: view_count >= 2
 | |
| 		do
 | |
| 			single_mode_button.select_actions.block
 | |
| 			split_mode_button.select_actions.block
 | |
| 			notebook_mode_button.select_actions.block
 | |
| 			single_mode_item.select_actions.block
 | |
| 			split_mode_item.select_actions.block
 | |
| 			notebook_mode_item.select_actions.block
 | |
| 			if is_split_mode then
 | |
| 				split_mode_button.enable_select
 | |
| 				split_mode_item.enable_select
 | |
| 			elseif is_notebook_mode then
 | |
| 				notebook_mode_button.enable_select
 | |
| 				notebook_mode_item.enable_select
 | |
| 			elseif is_single_mode then
 | |
| 				single_mode_button.enable_select
 | |
| 				single_mode_item.enable_select
 | |
| 			else
 | |
| 				check
 | |
| 					no_mode_should_not_happen: False
 | |
| 				end
 | |
| 			end
 | |
| 			single_mode_button.select_actions.resume
 | |
| 			split_mode_button.select_actions.resume
 | |
| 			notebook_mode_button.select_actions.resume
 | |
| 			single_mode_item.select_actions.resume
 | |
| 			split_mode_item.select_actions.resume
 | |
| 			notebook_mode_item.select_actions.resume
 | |
| 				-- for testing only
 | |
| 			if is_split_mode then
 | |
| 				check
 | |
| --					one:   split_mode_button.is_selected
 | |
| --					two:   split_mode_item.is_selected
 | |
| --					three: not notebook_mode_button.is_selected
 | |
| --					four:  not notebook_mode_item.is_selected
 | |
| --					five:  not single_mode_button.is_selected
 | |
| --					six:   not single_mode_item.is_selected
 | |
| 				end
 | |
| 
 | |
| 			end
 | |
| 		ensure
 | |
| --			split_mode_implication: is_split_mode implies
 | |
| --				split_mode_button.is_selected and split_mode_item.is_selected and
 | |
| --				not notebook_mode_button.is_selected and not notebook_mode_item.is_selected and
 | |
| --				not single_mode_button.is_selected and not single_mode_item.is_selected
 | |
| --			notebook_mode_implication: is_notebook_mode implies
 | |
| --				notebook_mode_button.is_selected and notebook_mode_item.is_selected and
 | |
| --				not single_mode_button.is_selected and not single_mode_item.is_selected and
 | |
| --				not split_mode_button.is_selected and not split_mode_item.is_selected
 | |
| --			single_mode_implication: is_single_mode implies
 | |
| --				single_mode_button.is_selected and single_mode_item.is_selected and
 | |
| --				not notebook_mode_button.is_selected and not notebook_mode_item.is_selected and
 | |
| --				not split_mode_button.is_selected and not split_mode_item.is_selected
 | |
| 		end
 | |
| 
 | |
| 	block_leaf_actions
 | |
| 			-- Removing and adding radio widgets to the `radio_bar' or `radio_menu' causes
 | |
| 			-- problems if the select actions fire, therefore block all those actions.
 | |
| 			-- The leaf nodes only should have any corresponding button for selections.
 | |
| 		local
 | |
| 			s: like leaf_nodes
 | |
| 		do
 | |
| 			s := leaf_nodes
 | |
| 			from s.start
 | |
| 			until s.exhausted
 | |
| 			loop
 | |
| 				s.item.block_radio_actions
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	resume_leaf_actions
 | |
| 			-- Resume actions for leaf node widgets (see `block_leaf_actions')
 | |
| 		local
 | |
| 			s: like leaf_nodes
 | |
| 		do
 | |
| 			s := leaf_nodes
 | |
| 			from s.start
 | |
| 			until s.exhausted
 | |
| 			loop
 | |
| 				s.item.resume_radio_actions
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	build_bars
 | |
| 			-- Put the correct buttons in the `bar' and the correct
 | |
| 			-- menu items into `menu'.  Make sure the button and menu
 | |
| 			-- states agree with the state of Current.
 | |
| 		require
 | |
| 			at_least_two_views: view_count >= 2
 | |
| 		local
 | |
| 			n: SPLIT_MANAGER_NODE
 | |
| 			s: like leaf_nodes
 | |
| 		do
 | |
| --			toggle_bar.disable_sensitive
 | |
| --			radio_bar.disable_sensitive
 | |
| --			toggle_menu.disable_sensitive
 | |
| --			radio_menu.disable_sensitive
 | |
| 				-- Build the `radio_bar', `toggle_bar', `toggle_menu', and `radio_menu'
 | |
| 				-- Calling `wipeout' on an EV_TOGGLE_BUTTON or EV_TOGGLE_ITEM caused one
 | |
| 				-- of the other buttons or items in the group to be selected.  This calls
 | |
| 				-- the select actions on that widget, one of which is to select a view.
 | |
| 				-- This will eventually lead to a call to `synchronize' and then back
 | |
| 				-- to this feature.  This is undesirable, so to prevent the callback,
 | |
| 				-- we must block the select actions for each of the radio widgets.
 | |
| 			block_leaf_actions
 | |
| 			toggle_bar.wipe_out
 | |
| 			radio_bar.wipe_out
 | |
| 			toggle_menu.wipe_out
 | |
| 			radio_menu.wipe_out
 | |
| 			s := leaf_nodes
 | |
| 			from s.start
 | |
| 			until s.exhausted
 | |
| 			loop
 | |
| 				n := s.item
 | |
| 				if not n.is_disabled then
 | |
| 					toggle_bar.extend (n.toggle_button)
 | |
| 					radio_bar.extend (n.radio_button)
 | |
| 					toggle_menu.extend (n.toggle_item)
 | |
| --					radio_menu.extend (n.radio_item)
 | |
| 				end
 | |
| 				s.forth
 | |
| 			end
 | |
| 				-- Un-block the actions on any selectable widgets in the bar or menu
 | |
| 			from radio_bar.start
 | |
| 			until radio_bar.exhausted
 | |
| 			loop
 | |
| 				check attached {EV_TOOL_BAR_RADIO_BUTTON} radio_bar.item as b then
 | |
| 					b.select_actions.resume
 | |
| 				end
 | |
| 				radio_bar.forth
 | |
| 			end
 | |
| 			from radio_menu.start
 | |
| 			until radio_menu.exhausted
 | |
| 			loop
 | |
| 				check attached {EV_RADIO_MENU_ITEM} radio_menu.item as ri then
 | |
| 					ri.select_actions.resume
 | |
| 				end
 | |
| 				radio_menu.forth
 | |
| 			end
 | |
| 				--  Build the bar
 | |
| 			bar.wipe_out
 | |
| 			if leaf_nodes.count >= 2 then
 | |
| 				if not is_mode_frozen then
 | |
| 					bar.extend (mode_bar)
 | |
| 					bar.disable_item_expand (mode_bar)
 | |
| 				end
 | |
| 				if not is_interface_frozen then
 | |
| 					if is_single_mode or else is_notebook_mode then
 | |
| 						bar.extend (radio_bar)
 | |
| 						bar.disable_item_expand (radio_bar)
 | |
| 					elseif is_split_mode then
 | |
| 						bar.extend (toggle_bar)
 | |
| 						bar.disable_item_expand (toggle_bar)
 | |
| 					end
 | |
| 				end
 | |
| 			end
 | |
| 				-- Build the menu
 | |
| 			menu.wipe_out
 | |
| 			if not is_mode_frozen then
 | |
| 				menu.extend (mode_menu)
 | |
| 			end
 | |
| 			if not is_interface_frozen then
 | |
| 				if is_single_mode or else is_notebook_mode then
 | |
| 					menu.extend (radio_menu)
 | |
| 				elseif is_split_mode then
 | |
| 					menu.extend (toggle_menu)
 | |
| 				end
 | |
| 			end
 | |
| --			if visible_count >= 2 then
 | |
| 			if view_count >= 2 then
 | |
| 				toggle_bar.enable_sensitive
 | |
| 				mode_menu.enable_sensitive
 | |
| 				radio_menu.enable_sensitive
 | |
| 				toggle_menu.enable_sensitive
 | |
| 			else
 | |
| 				toggle_bar.disable_sensitive
 | |
| 				mode_menu.disable_sensitive
 | |
| 				radio_menu.disable_sensitive
 | |
| 				toggle_menu.disable_sensitive
 | |
| 			end
 | |
| 			resume_leaf_actions
 | |
| 		end
 | |
| 
 | |
| 	build_cell
 | |
| 			-- Put the appropriate EV_SPLIT_AREA or VIEW into `cell' based on user
 | |
| 			-- button or menu selections.  This must be done whenever the list
 | |
| 			-- of visible_views changes or when a view is disabled.
 | |
| 		local
 | |
| 			s: like leaf_nodes
 | |
| 			n: detachable like root
 | |
| 			v: VIEW
 | |
| --			b: EV_TOOL_BAR_RADIO_BUTTON
 | |
| 		do
 | |
| 				-- Must wipeout all the containers to prevent putting a view into
 | |
| 				-- more than one container at a time.
 | |
| 				-- This requires building the notebook here if `is_notebook_mode'
 | |
| 			cell.wipe_out
 | |
| 			if notebook /= Void then
 | |
| 				notebook.selection_actions.block
 | |
| 				notebook.wipe_out
 | |
| 			end
 | |
| 			wipeout_splits
 | |
| 			if view_count >= 1 then
 | |
| 				if is_single_mode or else view_count < 2 then
 | |
| 					check attached {EV_WIDGET} selected_view as ev_w then
 | |
| 							-- because all managed `views' should be EV_WIDGETS
 | |
| 						cell.extend (ev_w)
 | |
| 					end
 | |
| 				elseif is_notebook_mode then
 | |
| 					s := leaf_nodes
 | |
| 					from s.start
 | |
| 					until s.exhausted
 | |
| 					loop
 | |
| 						check
 | |
| 							s.item.is_view
 | |
| 								-- Because `views' should hold only nodes that contain a VIEW in `widget'.
 | |
| 							end
 | |
| 						n := s.item
 | |
| 						if not n.is_disabled then
 | |
| 							check attached {EV_WIDGET} n.view as ev_w then
 | |
| 									-- because all managed `views' should be EV_WIDGETS
 | |
| 								notebook.extend (ev_w)
 | |
| 								notebook.set_item_text (ev_w, ev_w.generating_type)
 | |
| 							end
 | |
| 						end
 | |
| 						s.forth
 | |
| 					end
 | |
| 					if n /= Void then
 | |
| 						check attached {EV_WIDGET} n.view as ev_w then
 | |
| 								-- because all managed `views' should be EV_WIDGETS
 | |
| 							notebook.select_item (ev_w)
 | |
| 						end
 | |
| 					end
 | |
| 					cell.extend (notebook)
 | |
| 					notebook.selection_actions.resume
 | |
| 				else
 | |
| 					check
 | |
| 						is_split_mode: is_split_mode
 | |
| 								-- because only mode left
 | |
| 					end
 | |
| 					if attached root as r then
 | |
| 						cell.extend (r.visible_widget)
 | |
| 					end
 | |
| 					restore_split_positions
 | |
| 				end
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	wipeout_splits
 | |
| 			-- Clean out all the split areas.
 | |
| 		local
 | |
| 			s: like internal_nodes
 | |
| 		do
 | |
| 			s := internal_nodes
 | |
| 			from s.start
 | |
| 			until s.exhausted
 | |
| 			loop
 | |
| 				check
 | |
| 					is_split: s.item.is_split
 | |
| 						-- Because splits hold only nodes containing EV_SPLIT_AREA is `widget'.
 | |
| 				end
 | |
| 				s.item.split_area.wipe_out
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| feature {NONE} -- Implementation (Actions)
 | |
| 
 | |
| 	on_mode_change
 | |
| 			-- The "mode" has changed, so rebuild the `bar' and `menu'
 | |
| 			-- and syncronize other items.
 | |
| 		do
 | |
| 			save_split_positions
 | |
| 			syncronize
 | |
| 		end
 | |
| 
 | |
| 	on_tab_selected
 | |
| 			-- React to a request from the `notebook' to select `a_view'
 | |
| 		require
 | |
| 			is_notebook_mode: is_notebook_mode
 | |
| 		do
 | |
| 			check attached {VIEW} notebook.selected_item as v then
 | |
| 				select_view (v)
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| feature {NONE} -- Implementation
 | |
| 
 | |
| 	has_invalid_leaf_type: BOOLEAN
 | |
| 			-- Used by invariant to make sure all leaf nodes contain VIEWs.
 | |
| 		local
 | |
| 			s: like leaf_nodes
 | |
| 			n: like root
 | |
| 		do
 | |
| 			s := leaf_nodes
 | |
| 			from s.start
 | |
| 			until Result or else s.exhausted
 | |
| 			loop
 | |
| 				n := s.item
 | |
| 				Result := not n.is_view
 | |
| 				if not n.is_view then
 | |
| 					Result := True
 | |
| 				end
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| 	has_invalid_internal_type: BOOLEAN
 | |
| 			-- Used by invariant to make sure all internal nodes contain EV_SPLIT_AREAs.
 | |
| 		local
 | |
| 			s: like internal_nodes
 | |
| 			n: like root
 | |
| 		do
 | |
| 			s := internal_nodes
 | |
| 			from s.start
 | |
| 			until Result or else s.exhausted
 | |
| 			loop
 | |
| 				n := s.item
 | |
| 				Result := not n.is_split
 | |
| 				s.forth
 | |
| 			end
 | |
| 		end
 | |
| 
 | |
| feature {NONE} -- Implementation (tool bars and buttons)
 | |
| 
 | |
| 	notebook: EV_NOTEBOOK
 | |
| 			-- Used internally to build `cell' when `notebook_mode_button' is selected.
 | |
| 
 | |
| 	mode_bar: EV_TOOL_BAR
 | |
| 			-- Holds the view mode buttons (`single_mode_button',
 | |
| 			-- `normal_mode_button', and `notebook_mode_button'.
 | |
| 
 | |
| 	toggle_bar: EV_TOOL_BAR
 | |
| 			-- Holds buttons which toggle multiple views on and off.
 | |
| 
 | |
| 	radio_bar: EV_TOOL_BAR
 | |
| 			-- Holds buttons used to select one of several views.
 | |
| 
 | |
| 	single_mode_button: EV_TOOL_BAR_RADIO_BUTTON
 | |
| 			-- Used to put the views into a maximized state
 | |
| 
 | |
| 	split_mode_button: EV_TOOL_BAR_RADIO_BUTTON
 | |
| 			-- Puts the manager into normal view mode (all selected views are visible).
 | |
| 
 | |
| 	notebook_mode_button: EV_TOOL_BAR_RADIO_BUTTON
 | |
| 			-- Puts the manager into a mode in which the views are
 | |
| 			-- placed withing an EV_NOTEBOOK.
 | |
| 
 | |
| feature {NONE} -- Implementation (menus and items)
 | |
| 
 | |
| 	mode_menu: EV_MENU
 | |
| 			-- Holds menu items for changing the mode
 | |
| 
 | |
| 	toggle_menu: EV_MENU
 | |
| 			-- Holds menu items used when not `is_maximized' and not `is_builder_mode'
 | |
| 			-- to toggle views on and off or to `maximize' the views.
 | |
| 
 | |
| 	radio_menu: EV_MENU
 | |
| 			-- Holds menu items used when `is_maximized' and not `is_builder_mode'
 | |
| 			-- to select one of several views or to `restore' the views.
 | |
| 
 | |
| 	single_mode_item: EV_RADIO_MENU_ITEM
 | |
| 			-- Maximizes the `selected_view'
 | |
| 
 | |
| 	split_mode_item: EV_RADIO_MENU_ITEM
 | |
| 			-- Reverts to `is_split_mode'
 | |
| 
 | |
| 	notebook_mode_item: EV_RADIO_MENU_ITEM
 | |
| 			-- Changes to notebook mode
 | |
| 
 | |
| invariant
 | |
| 
 | |
| 	cell_exists: cell /= Void
 | |
| 	not_has_invalid_leaf_type: not has_invalid_leaf_type
 | |
| 	not_has_invalid_internal_type: not has_invalid_internal_type
 | |
| 
 | |
| --	one_view_implies_root_exists: count >= 1 implies root /= Void
 | |
| --	one_view_implies_selected_node_exists: count >= 1 implies selected_node /= Void
 | |
| --	two_views_implies_exported_widgets_exist: count >= 2 implies (menu /= Void and bar /= Void)
 | |
| --	two_views_implies_widgets_exist: count >= 2 implies
 | |
| --		(notebook /= Void and mode_bar /= Void and toggle_bar /= Void and radio_bar /= Void and
 | |
| --		single_mode_button /= Void and split_mode_button /= Void and notebook_mode_button /= Void and
 | |
| --		mode_menu /= Void and toggle_menu /= Void and radio_menu /= Void and
 | |
| --		single_mode_item /= Void and split_mode_item /= Void and notebook_mode_item /= Void)
 | |
| 
 | |
| end
 | |
| 
 | 
