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

