note
	description: "[
		Widget which is a combination of an EV_TREE and an EV_MULTI_COLUMN_LIST.

		Item Insertion:

		The grid is an item holder for objects of type EV_GRID_ITEM and its descendents.  Each grid
		item may be inserted in to the grid at a specific column and row.  An item itself may be
		added to the grid via `set_item', which takes a column and row index.  Items be also added
		via the `set_item' routine of the row (EV_GRID_ROW) and column (EV_GRID_COLUMN) objects
		contained within `Current'.

		Items inserted may be Void if necessary, this may be useful to blank out any existing items
		set.

		If a grid contains no items and therefore has no rows or columns, inserting an item will
		dynamically resize and automatically create the columns and rows so that it can contain
		and display the newly inserted item. New columns and rows may also be added to the grid via
		`insert_new_column' and `insert_new_row' respectively.

		--------------------------------------------------------------------------------

		Dynamic Mode:

		There may be times where you have very large numbers of items you wish to
		display into the grid. Unfortunately, the overhead of building thousands and
		thousands of grid items and inserting them can take a considerable amount of
		which shows up as a delay to users of the system. To prevent this, the grid
		supports the use of a dynamic mode which permit you to specify how many items
		are contained and then as and when the grid requires access to one of these items
		for display purposes, an event is triggered requesting the item to be displayed.

		dynamic content is enabled via `enable_partial_dynamic_content'. In this mode
		whenever the grid attempts to draw an item that is `Void', it queries you for the
		item and then inserts it into the grid.

		The grid requests an item in the dynamic mode through the calling of the
		`dynamic_content_function' which may be set via a call to
		`set_dynamic_content_function'. This function has two integer arguments
		corresponding to the column and row index of the desired item and a return type
		of EV_GRID_ITEM.

		--------------------------------------------------------------------------------

		Size and Position:

		The grid is comprised of the following graphical elements:
		1. A header displayed at the top of `Current' which may be hidden/shown via
		`show_header' and hide_header'.
		2. A viewable area in which the contents of `Current' are displayed, displayed
		immediately below the header. The size of this
		area is given by `viewable_width' and `viewable_height' with its position
		relative to the top left corner of `Current' given by `viewable_x_offset',
		`viewable_y_offset'. Note that `viewable_y_offset' changes based on the visible
		state of the header.
		3. A horizontal scroll bar displayed below the viewable area, only shown if the
		virtual width of `Current' is greater than `viewable_width'.
		4. A vertical scroll bar displayed to the right of viewable area and header,
		only shown if the virtual height of `Current' is greater than `viewable_height'.

		You may supress the displaying of the scroll bars if required via calls to
		`hide_vertical_scroll_bar' and `hide_horizontal_scroll_bar' which ensure that
		the scroll bars are never displayed. This is useful for situations where you
		wish to control the virtual position of the grid via your own custom interface.

		The virtual size of the grid represents the complete screen area in pixels
		required to display the contents of `Current' and may be queried via
		`virtual_width' and `virtual_height'. If the contents of the grid are smaller
		than the viewable area, then the virtual size is equal to the viewable area,
		otherwise an area of the virtual size is displayed within viewable area, with
		the coordinates of this area (relative to the top left corner) within the
		virtual size given by `virtual_x' and `virtual_y'. As the scroll bars are moved,
		`virtual_x' and `virtual_y' are directly manipulated, although you may set the
		virtual position explicitly via calls to `set_virtual_x' and `set_virtual_y'.

		The maximum permitted virtual position of the grid is given by
		`maximum_virtual_x_position', `maximum_virtual_y_position' which is dependent on
		the following factors:
			The viewable area of the grid.
			The `virtual_width' and `virtual_height'.
			The `is_*_scrolling_per_item' properties.
			The `is_*_overscroll_enabled' properties.
		Changing one or more of these properties may immediately change the virtual width,
		height or maximum virtual positions, and possibly scroll the grid to ensure that the
		current virtual position is within the new bounds.

		The properties `is_vertical_overscroll_enabled' and `is_horizontal_overscroll_enabled'
		permit you to ensure the grid permits scrolling past the final item, ensuring that there
		is trailing space matching the viewable dimension of the grid less the dimension of
		the final item.

		You may query the virtual position of an item within the virtual area of
		`Current' via `virtual_x_position' and `virtual_y_position' directly on the
		item. You may also query the dimensions of an item via `width' and `height'. It
		is important to note that for an item that is part of a tree structure, the
		`width' may not be equal to `column.width' and the `virtual_x_position' may not
		be equal to `column.virtual_x_position'. This is because items in tree
		structures are indented to provide space for the expand/collapse icons as
		necessary. The number of pixels that the item is indented for this purpose may
		be queried directly from the item via a call
		to `horizontal_indent'.

		You may query the virtual y position of a row within `Current' via
		`virtual_y_position' directly on the row.
		You may query the virtual x position of a column within `Current' via
		`virtual_x_position' directly on the column.

		As items, columns or rows are added and removed from `Current', the virtual size
		may change. The virtual position may only change if in this situation, you are
		removing rows or columns that cause the virtual size to reduce and the virtual
		position is no longer valid. The grid will automatically adjust the virtua
		position so that the contents of the viewable area are completely contained
		within the new virtual position.

		The `height' of the rows displayed in `Current' is dependent on
		`is_row_height_fixed'. If `True',  then all rows are displayed at the same
		height, goverened by `row_height'. If `False', then the height of the row is
		goverened by its `height' property which may differ on an individual row basis.
		The width of columns is always unique and based on their `width' property.

		To determine if a particular item is located at a virtual position, use
		`item_at_virtual_position'. You may determine the first and last visible rows
		via `first_visible_row' and `last_visible_row', while `first_visible_column' and
		`last_visible_column' give the first and last columns visible in `Current'. For
		more precise information regarding exactly which rows and columns are displayed,
		you may query `visible_row_indexes' and `visible_column_indexes'. Note that if a
		tree is enabled via `enable_tree', then the contents of `visible_row_indexes'
		and `visible_column_indexes' may not be contiguous.

		To optimize performance, `Current'  only performs recomputation of the virtual
		positions of items as strictly necessary, which is normally once just before a
		redraw. As you may query virtual position information whenever you wish,
		`Current' may be forced to perform its recomputation of virtual positions as a
		result of your query. Each time that you modify something in the grid that may
		affect a virtual position of an item, the grid must recompute the virtual
		positions again as required. Therefore, for your code to be optimal, it may be
		necessary to take this into account. The worst possible case scenario is if you
		are to iterate from the start of the grid to the end of the grid and modify the
		state of each item or row during the iteration before querying a virtual position
		of an object in the grid past the current iteration position. In this situation,
		it is recommended that you perform a two-pass operation. First perform all of the
		modifications to the items and then perform all of the queries to virtual
		positions. The grid is optimized for additions in order so if you are repeatedly
		adding items and querying their virtual positions, then the performance is far
		better than if you are continuously inserting items at the start of the grid and
		querying their virtual positions. Although it is important to be aware of this
		behavior, you will find that in almost all cases, you have do perform no special
		optimizations to get good performance within `Current'. This also aplies to
		removal of rows. If you have many rows to remove, start with the final rows and
		iterate towards the first for increased performance.

		The re-drawing of `Current' is performed on idle, so if you are performing heavy
		computation and the grid is not updating, call `process_events' from
		EV_APPLICATION in order to force a re-draw.
		--------------------------------------------------------------------------------
		Appearance:

		Each of the items contained within the grid are sized based on the column and
		row that they occupy. If `is_row_height_fixed' is `True' then the height of the
		rows is dependent on `row_height' of `Current', otherwise it is dependent on
		`height' of the row and each row may occupy a different height. For the first
		non-`Void' item of each row, the position of the item is `item.horizontal_indent'
		pixels greater than the column in which it is contained. The appearance of each
		item is dependent on the actual type of the item, but there are a number of
		ways in which you may modify this at the grid level.

		`post_draw_overlay_function' is available, which permits you to draw directly on
		top of items immediately after they are dwan by the implementation. This is
		useful for adding custom borders to your items.
		`pre_draw_overlay_function' is available, which permits you to draw on top of the
		background of items, but before any features of that item have been drawn. For
		example, for grid label items, the background is cleared, then the function is
		called and then the `text' and `pixmap' are drawn. Note that for drawable items,
		which do not re-draw their background automatically, nothing is drawn before the
		`pre_draw_overlay_function' is called.

		When items are selected in a focused grid, they become highlighted in
		`focused_selection_color' and if the grid does not have the focus,
		`non_focused_selection_color' is used instead. It is recommended that you use
		these colors for your own drawable items to maintain consistency within the grid.
		The selection colors may be modified via `set_focused_selection_color' and
		`set_non_focused_selection_color'.

		Separators between items may be enabled on the grid via `enable_column_separators'
		and `enable_row_separators' which ensure a single line is drawn between each row
		and column in `separator_color'. Use `set_separator_color' to modify this color.

		The tree structure of `Current' is drawn using `expand_node_pixmap' and
		`collapse_node_pixmap' to illustrate the expanded state of rows with subrows. You
		may use your own pixmaps by calling `set_expand_node_pixmap' and
		`set_collapse_node_pixmap'. The indent applied to each subrow is based on the
		current width of the node pixmaps + `subrow_indent'. You may increase this indent
		by calling `set_subrow_indent'. The nodes in the tree are connected via lines drawn
		in the color `tree_node_connector_color' which may be modified via
		`set_tree_node_connector_color'. These connecting lines may also be hidden via a
		call to `hide_tree_node_connectors'.

		During a column resize in `Current', the contents of the grid are immediately
		refreshed. This behavior may be disabled via a call to `disable_column_resize_immedite'
		and may be necessary if running the grid on older systems as it is less processor
		intensive. When not `is_column_resize_immediate', the column resizing is only performed
		when the user completes the resize, but a divider may be shown in `Current' which indicates
		its new width during the resizing, by calling `enable_resizing_divider'. This divider
		may be solid or dashed, based on the state of `is_resizing_divider_solid', settable via
		`enable_resizing_divider_solid' or `disable_resizing_divider_solid'.

		If you wish to perform multiple updates to the grid, in most cases the graphical
		update is buffered until the system becomes idle, thereby reducing flicker.
		However, in some situations, it is possible that the system may become idle
		during the updates, which may lead to flicker. In situations such as these, you
		may use `lock_update' to prevent graphical updates from occurring in the grid
		until `unlock_update' is called. While the grid `is_locked', no graphical updates
		of any form are performed.

		--------------------------------------------------------------------------------

		Selection:

		The grid allows both single and multiple selection handling on an item or row level.
		When enable_single_item_selection is called, only an single item may be selected by the
		user when `Current' is on-screen.  Selection may occur either programmatically via the
		`enable_select' routine of either the item/column or row or on-screen via mouse or keyboard.
		This is accompanied with the query `is_selected'.  When a user attempts to select an item or
		row on-screen the grid attempts to make that item or row more visible to the user so that the
		text of the item may be read, this will not occur however if the item is currently activated.

		There are two main selection modes, item selection and row selection.  In item selection,
		single or multiple items may be selected depending on the current selection mode.  This can be
		set with `enable_single_item_selection' and `enable_multiple_item_selection' respectively.

		For each type of selection there are events.  Examples of such events are `item_select_actions',
		`row_select_actions' and `column_select_actions', these are fired in `Current', with the
		appropriate object being passed to the action sequence that is selected. `item_select_actions'
		will only get executed whilst in either single or multiple item selection mode. For handling selection
		events during single or multiple row selection modes, `row_select_actions' should be used.
		To keep track of deselected items, rows or columns, there is `item_deselect_actions',
		`row_deselect_actions' and `column_deselect_actions' respectively.

		Along with selecting items, they may also be deselected.  This can be done programatically
		via the `disable_select' routine of either the item/column or row.

		To query what objects are selected, the following queries are available in `Current',
		`selected_items', `selected_rows' and `selected_columns'.

		To turn off any default behavior the following queries are available, `disable_selection_key_handling'
		and `disable_selection_click_handling', this turns off the ability for the user of the grid
		to select items via the keyboard or mouse.

		The routine `enable_always_selected' makes sure that at least one item or row is selected depending
		on the mode after the initial selection.  This can be handy for implementing widgets that require an item
		be selected at all times.

		The selection of the grid may be removed with `remove_selection'.

		--------------------------------------------------------------------------------

		Item Activation:

		Activation allows for interactive editing of the contents of an item. By calling
		`activate' on an activatable item in response to a user event such as double clicking,
		the item allows for in-place user editing, for changing things such as text.  After
		changing the item, the user may complete the activation by pressing Enter on the
		keyboard or by causing the item itself to loose focus.

		To programmatically cancel any activation, each grid item has a `deactivate' routine
		that may be called during the activation.

		If an activation occurs during a user selection then the grid itself will not attempt to reposition
		the item so that it is more visible.

		When an item is activated, the `item_activate_actions' are fired, this can be used
		to customize the activation process of a certain item, `item_deactivate_actions' are
		fired when the item is deactivated.  When an item is deactivated, if the user hasn't
		cancelled the deactivation then the item's contents are updated.

		See EV_GRID_EDITABLE_ITEM and EV_GRID_COMBO_ITEM for examples of activatable items
		that allow for in place editing.

		--------------------------------------------------------------------------------
		Event Handling:

		The standard set of widget events are inherited from EV_CELL with an additional
		set of events that are applicable to both `Current' and the items contained are
		inherited from EV_GRID_ACTION_SEQUENCES. For example,
		`pointer_button_press_actions' is inherited from EV_CELL, while
		`pointer_button_press_item_actions' is inherited from EV_GRID_ACTION_SEQUENCES
		and has an EV_GRID_ITEM as event data specifying the applicable item (if any).
		The coordinates of the item specific versions use virtual coordinates of
		`Current' as their coordinate information, wheras those inherited from EV_CELL
		use client coordinates as for any other EV_WIDGET. The order of event execution
		for multiple action sequences that may be triggered by a single event are as
		follows:
		1. The standard inherited widget events are fired. i.e.
			"grid.pointer_button_press_actions" The x and y coordinate event data is
			relative to the upper left corner of `Current'.
		2. The grid item specific versions of these events are fired. i.e.
			"grid.pointer_button_press_item_actions" The x and y coordinate event data is
			relative to the upper left corner of the "item" area of `Current', in virtual
			grid coordinates. These events are only fired while the mouse pointer is above
			the "item" area (does not include header and scroll bars).
		3. The events are fired on the item themselves. i.e.
			"item.pointer_button_press_actions" The x and y coordinate event data is
			relative to the upper left corner of the item.

		The grid specific versions of particular events permit you to perform handling
		for all of your items in a common place and are always fired before the specific
		item versions. For example, if you connect to both EV_GRID.row_expand_actions
		and EV_GRID_ROW.expand_actions, the grid version is fired first, immediately by
		the row version. The action sequences are fired one immediately after the other
		and both are always fired even if you change states of the target object within
		the first action sequence.
		--------------------------------------------------------------------------------

		Color Handling:

		Colors applied to items within `Current' are determined on a three level basis.
		The base level is `Current' whose `foreground_color' and `background_color' may
		never be Void.
		The second level are the columns and rows of `Current' whose `foreground_color'
		and `background_color' are `Void' by default.
		The final level is comprised of the items of `Current' themselves whose
		`foreground_color' and `background_color' are `Void' by default.
		As `Current' performs a  re-draw of an item "cell" contained within, the
		following rules are applied in order to determine the displayed colors:
		1. If there is an item in the "cell" which has a non-Void `foreground_color' or
		`background_color' then these colors are applied to the contents of that "cell",
		otherwise, step 2 is applied.
		2. If the column or row at that position has non-Void `foreground_color' or
		`background_color' then these colors are applied to the contents of that "cell",
		otherwise step 3 is applied.
		3. As the colors of the item, row and column were all `Void', the `foreground'
		and `background_color' of `Current' is applied to the contents of that "cell".
		Note that for areas of an items "cell" that are not filled by item item itself,
		such as the area of a tree structure, step 1 is ignored and the color
		calculations begin at step 2.
			]"
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date: "$Date$"
	revision: "$Revision$"

class
	EV_GRID

inherit
	EV_CELL
		rename
			item as cell_item,
			wipe_out as cell_wipe_out,
			count as cell_count,
			full as cell_full,
			has as cell_has,
			prune as cell_prune,
			prune_all as cell_prune_all,
			extendible as cell_extendible,
			put as cell_put,
			replace as cell_replace,
			linear_representation as cell_linear_representation,
			is_empty as cell_is_empty,
			extend as cell_extend,
			fill as cell_fill,
			is_inserted as cell_is_inserted,
			empty as cell_empty,
			has_recursive as cell_has_recursive,
			may_contain as cell_may_contain,
			merge_radio_button_groups as cell_merge_radio_button_groups,
			unmerge_radio_button_groups as cell_unmerge_radio_button_groups,
			merged_radio_button_groups as cell_merged_radio_button_groups,
			items_unique as cell_items_unique,
			parent_of_items_is_current as cell_parent_of_items_is_current,
			background_color_propagated as cell_background_color_propagated,
			foreground_color_propagated as cell_foreground_color_propagated,
			all_radio_buttons_connected as cell_all_radio_buttons_connected,
			first_radio_button_selected as cell_first_radio_button_selected,
			is_parent_recursive as cell_is_parent_recursive,
			has_radio_button as cell_has_radio_button,
			has_selected_radio_button as cell_has_selected_radio_button,
			propagate_background_color as cell_propagate_background_color,
			propagate_foreground_color as cell_propagate_foreground_color,
			client_height as cell_client_height,
			client_width as cell_client_width,
			background_pixmap as cell_background_pixmap
		redefine
			implementation,
			create_implementation,
			prunable,
			readable,
			writable,
			is_in_default_state
		end

	EV_TOOLTIPABLE
		undefine
			copy, is_equal
		redefine
			implementation,
			is_in_default_state
		end

	EV_GRID_TYPES
		undefine
			copy, is_equal, default_create
		end

	EV_GRID_ACTION_SEQUENCES

	REFACTORING_HELPER
		undefine
			copy, is_equal, default_create
		end

feature -- Access

	row (a_row: INTEGER): EV_GRID_ROW
			-- Row at index `a_row'.
		require
			not_destroyed: not is_destroyed
			a_row_positive: a_row > 0
			a_row_not_greater_than_row_count: a_row <= row_count
		do
			Result := implementation.row (a_row)
		ensure
			row_not_void: Result /= Void
		end

	displayed_column (i: INTEGER): EV_GRID_COLUMN
			-- `i'-th displayed column. May not correspond
			-- to `column' if one or more columns have been
			--- hidden via `hide'.
		require
			not_destroyed: not is_destroyed
			i_positive: i > 0
			i_not_greater_than_displayed_column_count: i <= displayed_column_count
		do
			Result := implementation.displayed_column (i)
		ensure
			column_not_void: Result /= Void
		end

	column (a_column: INTEGER): EV_GRID_COLUMN
			-- Column at index `a_column'.
		require
			not_destroyed: not is_destroyed
			a_column_positive: a_column > 0
			a_column_not_greater_than_column_count: a_column <= column_count
		do
			Result := implementation.column (a_column)
		ensure
			column_not_void: Result /= Void
		end

	item (a_column: INTEGER; a_row: INTEGER): detachable EV_GRID_ITEM
			-- Cell at `a_row' and `a_column' position, Void if none.
		require
			not_destroyed: not is_destroyed
			a_column_positive: a_column > 0
			a_column_less_than_column_count: a_column <= column_count
			a_row_positive: a_row > 0
			a_row_less_than_row_count: a_row <= row_count
		do
			Result := implementation.item (a_column, a_row)
		end

	activated_item: detachable EV_GRID_ITEM
			-- Item that has currently been activated, if any.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.currently_active_item
		end

	item_at_virtual_position (a_virtual_x, a_virtual_y: INTEGER): detachable EV_GRID_ITEM
			-- Cell at virtual position `a_virtual_x', `a_virtual_y' or
			-- `Void' if none.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.item_at_virtual_position (a_virtual_x, a_virtual_y)
		end

	row_at_virtual_position (a_virtual_y: INTEGER; ignore_locked_rows: BOOLEAN): detachable EV_GRID_ROW
			-- Row at virtual y position `a_virtual_y'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.row_at_virtual_position (a_virtual_y, ignore_locked_rows)
		end

	column_at_virtual_position (a_virtual_x: INTEGER): detachable EV_GRID_COLUMN
			-- Column at virtual x position `a_virtual_x'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.column_at_virtual_position (a_virtual_x)
		end

	selected_columns: ARRAYED_LIST [EV_GRID_COLUMN]
			-- All columns selected in `Current'.
			-- Returned list is unsorted so no particular ordering is guaranteed.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.selected_columns
		ensure
			result_not_void: Result /= Void
		end

	selected_rows: ARRAYED_LIST [EV_GRID_ROW]
			-- All rows selected in `Current'.
			-- Returned list is unsorted so no particular ordering is guaranteed.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.selected_rows
		ensure
			result_not_void: Result /= Void
		end

	selected_items: ARRAYED_LIST [EV_GRID_ITEM]
			-- All items selected in `Current'.
			-- Returned list is unsorted so no particular ordering is guaranteed.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.selected_items
		ensure
			result_not_void: Result /= Void
		end

	remove_selection
			-- Ensure that `selected_items', `selected_rows' and `selected_columns' are empty.
		require
			not_destroyed: not is_destroyed
		do
			implementation.remove_selection
		ensure
			selected_items_empty: selected_items.is_empty
			selected_rows_empty: selected_rows.is_empty
			selected_columns_empty: selected_columns.is_empty
		end

	header: EV_GRID_HEADER
			-- Header control used for resizing columns of `Current'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.header
		ensure
			result_not_void: Result /= Void
		end

	horizontal_scroll_bar: EV_HORIZONTAL_SCROLL_BAR
			-- Horizontal scrollbar used for scrolling `Current'.
			-- Use `is_horizontal_scroll_bar_show_requested' to find out if scrollbar will be shown if
			-- needed (i.e. when `virtual_width' is greater than `viewable_width').
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.horizontal_scroll_bar
		ensure
			result_not_void: Result /= Void
		end

	vertical_scroll_bar: EV_VERTICAL_SCROLL_BAR
			-- Vertical scrollbar used for scrolling `Current'.
			-- Use `is_vertical_scroll_bar_show_requested' to find out if scrollbar will be shown if
			-- needed (i.e. when `virtual_height' is greater than `viewable_height').			
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.vertical_scroll_bar
		ensure
			result_not_void: Result /= Void
		end

	is_header_displayed: BOOLEAN
			-- Is the header displayed in `Current'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_header_displayed
		end

	is_resizing_divider_enabled: BOOLEAN
			-- Is a vertical divider displayed during column resizing?
			-- Note that if `is_column_resize_immediate' is `True', `Result'
			-- is ignored by `Current' and no resizing divider is displayed.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_resizing_divider_enabled
		end

	is_resizing_divider_solid: BOOLEAN
			-- Is resizing divider displayed during column resizing drawn as a solid line?
			-- If `False', a dashed line style is used.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_resizing_divider_solid
		end

	is_horizontal_scrolling_per_item: BOOLEAN
			-- Is horizontal scrolling performed on a per-item basis?
			-- If `True', each change of the horizontal scroll bar increments the horizontal
			-- offset by the current column width.
			-- If `False', the scrolling is smooth on a per-pixel basis.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_horizontal_scrolling_per_item
		end

	is_vertical_scrolling_per_item: BOOLEAN
			-- Is vertical scrolling performed on a per-item basis?
			-- If `True', each change of the vertical scroll bar increments the vertical
			-- offset by the current row height.
			-- If `False', the scrolling is smooth on a per-pixel basis.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_vertical_scrolling_per_item
		end

	is_vertical_overscroll_enabled: BOOLEAN
			-- Does the virtual height of `Current' include the
			-- position of the final row plus the `viewable_height'.
			-- If `True', this enables vertical scrolling until the last row
			-- is at the very top of the viewable area. If `False', scrolling
			-- may be performed until the last row is at the bottom of the viewable
			-- area.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_vertical_overscroll_enabled
		end

	is_horizontal_overscroll_enabled: BOOLEAN
			-- Does the virtual width of `Current' include the
			-- position of the final column plus the `viewable_width'.
			-- If `True', this enables horizontal scrolling until the last column
			-- is at the very left of the viewable area. If `False', scrolling
			-- may be performed until the last column is at the left of the viewable
			-- area.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_horizontal_overscroll_enabled
		end

	dynamic_content_function: detachable FUNCTION [TUPLE [col: INTEGER; row: INTEGER], EV_GRID_ITEM]
			-- Function which computes the item that resides in a particular position of the
			-- grid while `is_content_partially_dynamic'.
		require
			not_is_destroyed: not is_destroyed
		do
			Result := implementation.dynamic_content_function
		end

	is_content_partially_dynamic: BOOLEAN
			-- Is the content of `Current' partially dynamic? If `True' then
			-- whenever an item must be re-drawn and it is not already set within `Current',
			-- then it is queried via execution of `dynamic_content_function'. The returned item is added
			-- to `Current' so the query only occurs once.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_content_partially_dynamic
		end

	is_row_height_fixed: BOOLEAN
			-- Must all rows in `Current' have the same height?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_row_height_fixed
		end

	is_column_resize_immediate: BOOLEAN
			-- Is the user resizing of a column reflected immediately in `Current'?
			-- If `True', the column width is updated continuosly and the state of `is_resizing_divider_enabled'
			-- is ignored with no divider displayed.
			-- If `False', the column width is only updated upon completion of the resize.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_column_resize_immediate
		end

	row_height: INTEGER
			-- Height of all rows within `Current'. Only has an effect on `Current'
			-- while `is_row_height_fixed', otherwise the individual height of each
			-- row is used directly.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.row_height
		ensure
			result_non_negative: result >= 0
		end

	subrow_indent: INTEGER
			-- Number of pixels horizontally by which each subrow is indented
			-- from its `parent_row'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.subrow_indent
		ensure
			result_non_negative: result >= 0
		end

	expand_node_pixmap: EV_PIXMAP
			-- Pixmap displayed within tree structures when a row with one or more
			-- subrows is collapsed. Clicking the area occupied by this pixmap in `Current'
			-- expands the row.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.expand_node_pixmap
		ensure
			result_not_void: Result /= Void
		end

	collapse_node_pixmap: EV_PIXMAP
			-- Pixmap displayed within tree structures when a row with one or more
			-- subrows is expanded. Clicking the area occupied by this pixmap in `Current'
			-- collapses the row.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.collapse_node_pixmap
		ensure
			result_not_void: Result /= Void
		end

	are_tree_node_connectors_shown: BOOLEAN
			-- Are connectors between tree nodes shown in `Current'?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.are_tree_node_connectors_shown
		end

	virtual_x_position: INTEGER
			-- Horizontal offset of viewable area in relation to the left edge of
			-- the virtual area in pixels.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.virtual_x_position
		ensure
			valid_result: Result >= 0 and Result <= maximum_virtual_x_position
		end

	virtual_y_position: INTEGER
			-- Vertical offset of viewable area in relation to the top edge of
			-- the virtual area in pixels.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.virtual_y_position
		ensure
			valid_result: Result >= 0 and Result <= maximum_virtual_y_position
		end

	maximum_virtual_x_position: INTEGER
			-- Maximum permitted virtual x position based on current dimensions and properties.
			-- Properties that affect this value are `is_vertical_scrolling_per_item' and
			-- `is_vertical_overscroll_enabled'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.maximum_virtual_x_position
		ensure
			result_non_negative: Result >= 0
		end

	maximum_virtual_y_position: INTEGER
			-- Maximum permitted virtual y position based on current dimensions and properties.
			-- Properties that affect this value are `is_horizontal_scrolling_per_item' and
			-- `is_horizontal_overscroll_enabled'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.maximum_virtual_y_position
		ensure
			result_non_negative: Result >= 0
		end

	virtual_width: INTEGER
			-- Width of virtual area in pixels.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.virtual_width
		ensure
			result_non_negative: Result >= 0
		end

	virtual_height: INTEGER
			-- Height of virtual area in pixels.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.virtual_height
		ensure
			result_non_negative: Result >= 0
		end

	viewable_width: INTEGER
			-- Width of `Current' available to view displayed items. Does
			-- not include width of any displayed scroll bars.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.viewable_width
		ensure
			viewable_width_valid: is_displayed implies viewable_width >= 0 and viewable_width <= width
		end

	viewable_height: INTEGER
			-- Height of `Current' available to view displayed items. Does
			-- not include width of any displayed scroll bars and/or header if shown.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.viewable_height
		ensure
			viewable_height_valid: is_displayed implies viewable_height >= 0 and viewable_height <= height
		end

	viewable_x_offset: INTEGER
			-- Horizontal distance in pixels from the left edge of `Current' to
			-- the left edge of the viewable area (defined by `viewable_width', `viewable_height')
			-- in which all content is displayed.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.viewable_x_offset
		ensure
			viewable_x_offset_valid: Result >=0 and Result <= width
		end

	viewable_y_offset: INTEGER
			-- Vertical distance in pixels from the top edge of `Current' to
			-- the top edge of the viewable area (defined by `viewable_width', `viewable_height')
			-- in which all content is displayed.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.viewable_y_offset
		ensure
			viewable_y_offset_valid: Result >=0 and Result <= height
		end

	item_pebble_function: detachable FUNCTION [detachable EV_GRID_ITEM, detachable ANY]
			-- Returns data to be transported by pick and drop mechanism.
			-- It will be called once each time a pick on the item area of the grid occurs, the result
			-- will be assigned to `pebble' for the duration of transport.
			-- When a pick occurs on an item, the item itself is passed.
			-- If a pick occurs and no item is present, then Void is passed.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.item_pebble_function
		end

	item_veto_pebble_function: detachable FUNCTION [EV_GRID_ITEM, ANY, BOOLEAN]
			-- Function used to determine whether dropping is allowed on a particular item.
			-- When called during PND transport, the grid item currently under the pebble
			-- and the pebble itself are passed to the function.  A return value of True means
			-- that the pebble is allowed to be dropped onto the item, a return value of False
			-- disallows any PND transport.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.item_veto_pebble_function
		end

	item_accept_cursor_function: detachable FUNCTION [EV_GRID_ITEM, EV_POINTER_STYLE]
			-- Function used to retrieve the PND accept cursor for a particular item.
			-- Called directly after `item_pebble_function' has executed.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.item_accept_cursor_function
		end

	item_deny_cursor_function: detachable FUNCTION [EV_GRID_ITEM, EV_POINTER_STYLE]
			-- Function used to retrieve the PND deny cursor for a particular item.
			-- Called directly after `item_pebble_function' has executed.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.item_deny_cursor_function
		end

	are_column_separators_enabled: BOOLEAN
			-- Is a vertical separator displayed in color `separator_color' between each column?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.are_column_separators_enabled
		end

	are_row_separators_enabled: BOOLEAN
			-- Is a horizontal separator displayed in color `separator_color' between each row?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.are_row_separators_enabled
		end

	separator_color: EV_COLOR
			-- Color used to display column and row separators.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.separator_color
		ensure
			result_not_void: Result /= Void
		end

	focused_selection_color: EV_COLOR
			-- Color used to show selection within items while focused.
		require
			not_is_destroyed: not is_destroyed
		do
			Result := implementation.focused_selection_color
		ensure
			result_not_void: Result /= Void
		end

	non_focused_selection_color: EV_COLOR
			-- Color used to show selection within items while not focused.
		require
			not_is_destroyed: not is_destroyed
		do
			Result := implementation.non_focused_selection_color
		ensure
			result_not_void: Result /= Void
		end

	focused_selection_text_color: EV_COLOR
			-- Color used to for text of selected items while focused.
		require
			not_is_destroyed: not is_destroyed
		do
			Result := implementation.focused_selection_text_color
		ensure
			result_not_void: Result /= Void
		end

	non_focused_selection_text_color: EV_COLOR
			-- Color used for text of selected items while not focused.
		require
			not_is_destroyed: not is_destroyed
		do
			Result := implementation.non_focused_selection_text_color
		ensure
			result_not_void: Result /= Void
		end

	is_full_redraw_on_virtual_position_change_enabled: BOOLEAN
			-- Is complete client area invalidated as a result of virtual position changing?
			-- Note that enabling this causes a large performance penalty in redrawing during
			-- scrolling, but may be used to achieve effects not otherwise possible unless the
			-- entire client area is invalidated.
		require
			not_is_destroyed: not is_destroyed
		do
			Result := implementation.is_full_redraw_on_virtual_position_change_enabled
		end

	is_locked: BOOLEAN
			-- Are all graphical updates to `Current' suppressed until
			-- `unlock_update' is called.
		require
			not_is_destroyed: not is_destroyed
		do
			Result := implementation.is_locked
		end

	locked_rows: ARRAYED_LIST [EV_GRID_ROW]
			-- All rows locked within `Current' in order of locking.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.locked_rows
		ensure
			Result_not_void: Result /= Void
		end

	locked_columns: ARRAYED_LIST [EV_GRID_COLUMN]
			-- All columns locked within `Current' in order of locking.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.locked_columns
		ensure
			Result_not_void: Result /= Void
		end

feature -- Status setting

	set_item_veto_pebble_function (a_function: FUNCTION [EV_GRID_ITEM, ANY, BOOLEAN])
			-- Assign `a_function' to `item_veto_pebble_function'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.set_item_veto_pebble_function (a_function)
		ensure
			item_veto_pebble_function_set: item_veto_pebble_function = a_function
		end

	set_item_pebble_function (a_function: FUNCTION [detachable EV_GRID_ITEM, detachable ANY])
			-- Assign `a_function' to `item_pebble_function'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.set_item_pebble_function (a_function)
		ensure
			item_pebble_function_set: item_pebble_function = a_function
		end

	set_item_accept_cursor_function (a_function: FUNCTION [EV_GRID_ITEM, EV_POINTER_STYLE])
			-- Assign `a_function' to `item_accept_cursor_function'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.set_item_accept_cursor_function (a_function)
		ensure
			item_accept_cursor_function_set: item_accept_cursor_function = a_function
		end

	set_item_deny_cursor_function (a_function: FUNCTION [EV_GRID_ITEM, EV_POINTER_STYLE])
			-- Assign `a_function' to `item_deny_cursor_function'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.set_item_deny_cursor_function (a_function)
		ensure
			item_deny_cursor_function_set: item_deny_cursor_function = a_function
		end

	enable_tree
			-- Enable tree functionality for `Current'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_tree
		ensure
			tree_enabled: is_tree_enabled
		end

	disable_tree
			-- Disable tree functionality for `Current'.
			-- All subrows of rows contained are unparented,
			-- which flattens the tree structure.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_tree
		ensure
			tree_disabled: not is_tree_enabled
		end

	show_column (a_column: INTEGER)
			-- Ensure column `a_column' is visible in `Current'.
		require
			not_destroyed: not is_destroyed
			a_column_within_bounds: a_column > 0 and a_column <= column_count
		do
			implementation.show_column (a_column)
		ensure
			column_displayed: column_displayed (a_column)
		end

	hide_column (a_column: INTEGER)
			-- Ensure column `a_column' is not visible in `Current'.
		require
			not_destroyed: not is_destroyed
			a_column_within_bounds: a_column > 0 and a_column <= column_count
		do
			implementation.hide_column (a_column)
		ensure
			column_not_displayed: not column_displayed (a_column)
		end

	select_column (a_column: INTEGER)
			-- Ensure all items in `a_column' are selected.
		require
			not_destroyed: not is_destroyed
			a_column_within_bounds: a_column > 0 and a_column <= column_count
			column_displayed: column_displayed (a_column)
		do
			implementation.select_column (a_column)
		ensure
			column_selected: column (a_column).is_selected
		end

	select_row (a_row: INTEGER)
			-- Ensure all items in `a_row' are selected.
		require
			not_destroyed: not is_destroyed
			a_row_within_bounds: a_row > 0 and a_row <= row_count
		do
			implementation.select_row (a_row)
		ensure
			row_selected: row (a_row).is_selected
		end

	enable_selection_on_single_button_click
			-- Enable selection handling of items when clicked upon via mouse button `1'.
			-- This is useful when implementing Contextual Menus where the selection may need
			-- to remain unchanged when using mouse button `3' to handle the menu.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_selection_on_single_button_click
		ensure
			selection_on_single_click_enabled: is_selection_on_single_button_click_enabled and then is_selection_on_click_enabled
		end

	enable_selection_on_click
			-- Enable selection handling of items when clicked upon via mouse button.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_selection_on_click
		ensure
			selection_on_click_enabled:is_selection_on_click_enabled
			selection_on_single_click_disabled: not is_selection_on_single_button_click_enabled
		end

	disable_selection_on_click
			-- Disable selection handling when items are clicked upon.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_selection_on_click
		ensure
			selection_on_click_disabled: not is_selection_on_click_enabled and then not is_selection_on_single_button_click_enabled
		end

	enable_selection_key_handling
			-- Enable selection handling of items via the keyboard.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_selection_keyboard_handling
		ensure
			selection_key_handling_enabled: is_selection_keyboard_handling_enabled
		end

	disable_selection_key_handling
			-- Disable selection handling of items via the keyboard.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_selection_keyboard_handling
		ensure
			selection_key_handling_disabled: not is_selection_keyboard_handling_enabled
		end

	enable_single_row_selection
			-- Allow the user to select a single row via clicking or navigating using the keyboard arrow keys.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_single_row_selection
		ensure
			single_row_selection_enabled: is_single_row_selection_enabled
		end

	enable_multiple_row_selection
			-- Allow the user to select more than one row via clicking or navigating using the keyboard arrow keys.
			-- Multiple rows may be selected via Ctrl and Shift keys.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_multiple_row_selection
		ensure
			multiple_row_selection_enabled: is_multiple_row_selection_enabled
		end

	enable_single_item_selection
			-- Allow the user to select a single item via clicking or navigating using the keyboard arrow keys.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_single_item_selection
		ensure
			single_item_selection_enabled: is_single_item_selection_enabled
		end

	enable_multiple_item_selection
			-- Allow the user to select more than one item via clicking or navigating using the keyboard arrow keys.
			-- Multiple items may be selected via Ctrl and Shift keys.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_multiple_item_selection
		ensure
			multiple_item_selection_enabled: is_multiple_item_selection_enabled
		end

	enable_always_selected
			-- Ensure that the user may not completely remove the selection from `Current'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_always_selected
		ensure
			item_is_always_selected_enabled: is_always_selected
		end

	disable_always_selected
			-- Allow the user to completely remove the selection from `Current' via clicking on an item,
			-- clicking on a Void area or by Ctrl clicking the selected item itself.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_always_selected
		ensure
			not_is_item_always_selected_enabled: not is_always_selected
		end

	is_always_selected: BOOLEAN
			-- May the user completely remove the selection from the grid.
			-- If `True' then the user of the grid may only deselect items by selecting other items.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_always_selected
		end

	enable_item_tab_navigation
			-- Allow keyboard tab navigation to occur within current for items that return True for 'has_default_activation'.
			-- Tabbing in to the grid from a previous widget will select the first item.
			-- Shift/Tabbing in to the grid will select the most bottom/right default activable grid item.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_item_tab_navigation
		ensure
			tabbed_item_navigation_enabled: is_item_tab_navigation_enabled
		end

	disable_item_tab_navigation
			-- Disable tabbed item navigation so that tabbing loses focus from the grid by default.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_item_tab_navigation
		ensure
			tabbed_item_navigation_disabled: not is_item_tab_navigation_enabled
		end

	show_header
			-- Ensure header displayed.
		require
			not_destroyed: not is_destroyed
		do
			implementation.show_header
		ensure
			header_displayed: is_header_displayed
		end

	hide_header
			-- Ensure header is hidden.
		require
			not_destroyed: not is_destroyed
		do
			implementation.hide_header
		ensure
			header_not_displayed: not is_header_displayed
		end

	set_first_visible_row (a_row: INTEGER)
			-- Set `a_row' as the first row visible in `Current' as long
			-- as there are enough rows after `a_row' to fill the remainder of `Current'.
		require
			not_destroyed: not is_destroyed
			valid_row_index: a_row >= 1 and a_row <= row_count
		do
			implementation.set_first_visible_row (a_row)
		ensure
			to_implement_assertion ("EV_GRID.set_first_visible_row - Enough following rows implies `first_visible_row' = a_row, Can be calculated from `height' of `Current' and row heights.")
		end

	enable_resizing_divider
			-- Ensure a vertical divider is displayed during column resizing.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_resizing_divider
		ensure
			resizing_divider_enabled: is_resizing_divider_enabled
		end

	disable_resizing_divider
			-- Ensure no vertical divider is displayed during column resizing.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_resizing_divider
		ensure
			resizing_divider_disabled: not is_resizing_divider_enabled
		end

	enable_solid_resizing_divider
			-- Ensure resizing divider displayed during column resizing
			-- is displayed as a solid line.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_solid_resizing_divider
		ensure
			solid_resizing_divider: is_resizing_divider_solid
		end

	disable_solid_resizing_divider
			-- Ensure resizing divider displayed during column resizing
			-- is displayed as a dashed line.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_solid_resizing_divider
		ensure
			dashed_resizing_divider: not is_resizing_divider_solid
		end

	enable_horizontal_scrolling_per_item
			-- Ensure horizontal scrolling is performed on a per-item basis.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_horizontal_scrolling_per_item
		ensure
			horizontal_scrolling_performed_per_item: is_horizontal_scrolling_per_item
		end

	disable_horizontal_scrolling_per_item
			-- Ensure horizontal scrolling is performed on a per-pixel basis.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_horizontal_scrolling_per_item
		ensure
			horizontal_scrolling_performed_per_pixel: not is_horizontal_scrolling_per_item
		end

	enable_vertical_scrolling_per_item
			-- Ensure vertical scrolling is performed on a per-item basis.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_vertical_scrolling_per_item
		ensure
			vertical_scrolling_performed_per_item: is_vertical_scrolling_per_item
		end

	disable_vertical_scrolling_per_item
			-- Ensure vertical scrolling is performed on a per-pixel basis.
		require
			not_destroyed: not is_destroyed
			not_dynamic_content_enabled_with_row_height_variable:
				not (is_content_partially_dynamic and is_row_height_fixed = False)
		do
			implementation.disable_vertical_scrolling_per_item
		ensure
			vertical_scrolling_performed_per_pixel: not is_vertical_scrolling_per_item
		end

	enable_vertical_overscroll
			-- Ensure `is_vertical_overscroll_enabled' is `True'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_vertical_overscroll
		ensure
			is_vertical_overscroll_enabled: is_vertical_overscroll_enabled
		end

	disable_vertical_overscroll
			-- Ensure `is_vertical_overscroll_enabled' is `False'.
		require
			not_destroyed: not is_destroyed
			dynamic_content_not_enabled_with_variable_row_heights:
				not (is_content_partially_dynamic and not is_row_height_fixed)
		do
			implementation.disable_vertical_overscroll
		ensure
			not_is_vertical_overscroll_enabled: not is_vertical_overscroll_enabled
		end

	enable_horizontal_overscroll
			-- Ensure `is_horizontal_overscroll_enabled' is `True'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_horizontal_overscroll
		ensure
			is_horizontal_overscroll_enabled: is_horizontal_overscroll_enabled
		end

	disable_horizontal_overscroll
			-- Ensure `is_horizontal_overscroll_enabled' is `False'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_horizontal_overscroll
		ensure
			not_is_horizontal_overscroll_enabled: not is_horizontal_overscroll_enabled
		end

	set_row_height (a_row_height: INTEGER)
			-- Set height of all rows within `Current' to `a_row_height
			-- If not `is_row_height_fixed' then use the height individually per row instead.
		require
			not_destroyed: not is_destroyed
			a_row_height_positive: a_row_height >= 1
		do
			implementation.set_row_height (a_row_height)
		ensure
			row_height_set: row_height = a_row_height
		end

	enable_partial_dynamic_content
			-- Ensure contents of `Current' must be retrieved when required via execution of
			-- `dynamic_content_function' only if the item is not already set
			-- in `Current'.
		require
			not_destroyed: not is_destroyed
			not_row_height_variable_and_vertical_overscroll_enabled:
				not (not is_row_height_fixed and is_vertical_overscroll_enabled)
			not_row_height_variable_and_vertical_scrolling_per_pixel:
				not (not is_row_height_fixed and not is_vertical_scrolling_per_item)
		do
			implementation.enable_partial_dynamic_content
		ensure
			content_partially_dynamic: is_content_partially_dynamic
		end

	disable_dynamic_content
			-- Ensure contents of `Current' are not dynamic and are no longer retrieved as such.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_dynamic_content
		ensure
			content_not_dynamic: not is_content_partially_dynamic
		end

	enable_row_height_fixed
			-- Ensure all rows have the same height.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_row_height_fixed
		ensure
			row_height_fixed: is_row_height_fixed
		end

	disable_row_height_fixed
			-- Permit rows to have varying heights.
		require
			not_destroyed: not is_destroyed
			not_dynamic_content_enabled_with_height_not_bounded:
				not (is_content_partially_dynamic and is_vertical_overscroll_enabled = False)
		do
			implementation.disable_row_height_fixed
		ensure
			row_height_variable: not is_row_height_fixed
		end

	set_column_count_to (a_column_count: INTEGER)
			-- Resize `Current' to have `a_column_count' columns.
		require
			not_destroyed: not is_destroyed
			a_column_count_positive: a_column_count >= 0
		do
			implementation.set_column_count_to (a_column_count)
		ensure
			column_count_set: column_count = a_column_count
		end

	set_row_count_to (a_row_count: INTEGER)
			-- Resize `Current' to have `a_row_count' rows.
		require
			not_destroyed: not is_destroyed
			a_row_count_non_negative: a_row_count >= 0
		do
			implementation.set_row_count_to (a_row_count)
		ensure
			row_count_set: row_count = a_row_count
		end

	set_dynamic_content_function (a_function: FUNCTION [TUPLE [col: INTEGER; row: INTEGER], EV_GRID_ITEM])
			-- Function which computes the item that resides in a particular position of the
			-- grid while `is_content_partially_dynamic'.
		require
			not_destroyed: not is_destroyed
			a_function_not_void: a_function /= Void
		do
			implementation.set_dynamic_content_function (a_function)
		ensure
			dynamic_content_function_set: dynamic_content_function = a_function
		end

	set_subrow_indent (a_subrow_indent: INTEGER)
			-- Set `subrow_indent' to `a_subrow_indent'.
		require
			not_destroyed: not is_destroyed
			a_subrow_indent_non_negtive: a_subrow_indent >= 0
		do
			implementation.set_subrow_indent (a_subrow_indent)
		ensure
			subrow_indent_set: subrow_indent = a_subrow_indent
		end

	set_node_pixmaps (an_expand_node_pixmap, a_collapse_node_pixmap: EV_PIXMAP)
			-- Assign `an_expand_node_pixmap' to `expand_node_pixmap' and `a_collapse_node_pixmap'
			-- to `collapse_node_pixmap'. These pixmaps are used in rows containing subrows for
			-- expanding/collapsing the row.
		require
			not_destroyed: not is_destroyed
			pixmaps_not_void: an_expand_node_pixmap /= Void and a_collapse_node_pixmap /= Void
			pixmaps_dimensions_identical: an_expand_node_pixmap.width = a_collapse_node_pixmap.width and
				an_expand_node_pixmap.height = a_collapse_node_pixmap.height
		do
			implementation.set_node_pixmaps (an_expand_node_pixmap, a_collapse_node_pixmap)
		ensure
			pixmaps_set: expand_node_pixmap = an_expand_node_pixmap and collapse_node_pixmap = a_collapse_node_pixmap
		end

	show_tree_node_connectors
			-- Ensure connectors are displayed between nodes of tree structure in `Current'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.show_tree_node_connectors
		ensure
			tree_node_connectors_shown: are_tree_node_connectors_shown
		end

	hide_tree_node_connectors
			-- Ensure no connectors are displayed between nodes of tree structure in `Current'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.hide_tree_node_connectors
		ensure
			tree_node_connectors_hidden: not are_tree_node_connectors_shown
		end

	set_virtual_position (virtual_x, virtual_y: INTEGER)
			-- Move viewable area of `Current' to virtual position `virtual_x', `virtual_y'.
		require
			not_destroyed: not is_destroyed
			virtual_x_valid: virtual_x >= 0 and virtual_x <= maximum_virtual_x_position
			virtual_y_valid: virtual_y >= 0 and virtual_y <= maximum_virtual_y_position
		do
			implementation.set_virtual_position (virtual_x, virtual_y)
		ensure
			virtual_position_set: virtual_x_position = virtual_x and virtual_y_position = virtual_y
		end

	set_tree_node_connector_color (a_color: EV_COLOR)
			-- Set `a_color' as `tree_node_connector_color'.
		require
			not_destroyed: not is_destroyed
			a_color_not_void: a_color /= Void
		do
			implementation.set_tree_node_connector_color (a_color)
		ensure
			tree_node_connector_color_set: tree_node_connector_color = a_color
		end

	enable_columns_drawn_above_rows
			-- Ensure `are_columns_drawn_above_rows' is `True'.

		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_columns_drawn_above_rows
		ensure
			columns_drawn_above_rows: are_columns_drawn_above_rows
		end

	disable_columns_drawn_above_rows
			-- Ensure `are_columns_drawn_above_rows' is `False'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_columns_drawn_above_rows
		ensure
			columns_drawn_below_rows: not are_columns_drawn_above_rows
		end

	enable_column_resize_immediate
			-- Ensure `is_column_resize_immediate' is `True'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_column_resize_immediate
		ensure
			is_column_resize_immediate: is_column_resize_immediate
		end

	disable_column_resize_immediate
			-- Ensure `is_column_resize_immediate' is `False'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_column_resize_immediate
		ensure
			not_is_column_resize_immediate: not is_column_resize_immediate
		end

	enable_column_separators
			-- Ensure `are_column_separators_enabled' is `True'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_column_separators
		ensure
			column_separators_enabled: are_column_separators_enabled
		end

	disable_column_separators
			-- Ensure `are_column_separators_enabled' is `False'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_column_separators
		ensure
			column_separators_disabled: not are_column_separators_enabled
		end

	enable_row_separators
			-- Ensure `are_row_separators_enabled' is `True'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.enable_row_separators
		ensure
			row_separators_enabled: are_row_separators_enabled
		end

	disable_row_separators
			-- Ensure `are_row_separators_enabled' is `False'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.disable_row_separators
		ensure
			row_separators_disabled: not are_row_separators_enabled
		end

	set_separator_color (a_color: EV_COLOR)
			-- Set `a_color' as `separator_color'.
		require
			not_destroyed: not is_destroyed
			a_color_not_void: a_color /= Void
		do
			implementation.set_separator_color (a_color)
		ensure
			separator_color_set: separator_color = a_color
		end

	set_focused_selection_color (a_color: EV_COLOR)
			-- Assign `a_color' to `focused_selection_color'.
		require
			not_is_destroyed: not is_destroyed
			a_color_not_void: a_color /= Void
		do
			implementation.set_focused_selection_color (a_color)
		ensure
			focused_selection_color_set: focused_selection_color = a_color
		end

	set_non_focused_selection_color (a_color: EV_COLOR)
			-- Assign `a_color' to `non_focused_selection_color'.
		require
			not_is_destroyed: not is_destroyed
			a_color_not_void: a_color /= Void
		do
			implementation.set_non_focused_selection_color (a_color)
		ensure
			non_focused_selection_color_set: non_focused_selection_color = a_color
		end

	set_focused_selection_text_color (a_color: EV_COLOR)
			-- Assign `a_color' to `focused_selection_text_color'.
		require
			not_is_destroyed: not is_destroyed
			a_color_not_void: a_color /= Void
		do
			implementation.set_focused_selection_text_color (a_color)
		ensure
			focused_selection_text_color_set: focused_selection_text_color = a_color
		end

	set_non_focused_selection_text_color (a_color: EV_COLOR)
			-- Assign `a_color' to `non_focused_selection_text_color'.
		require
			not_is_destroyed: not is_destroyed
			a_color_not_void: a_color /= Void
		do
			implementation.set_non_focused_selection_text_color (a_color)
		ensure
			non_focused_selection_text_color_set: non_focused_selection_text_color = a_color
		end

	redraw
			-- Force `Current' to be re-drawn when next idle.
		require
			not_destroyed: not is_destroyed
		do
			implementation.redraw
		end

	enable_full_redraw_on_virtual_position_change
			-- Ensure `is_full_redraw_on_virtual_position_change_enabled' is `True'.
		require
			not_is_destroyed: not is_destroyed
		do
			implementation.enable_full_redraw_on_virtual_position_change
		ensure
			is_full_redraw_on_virtual_position_change_enabled: is_full_redraw_on_virtual_position_change_enabled
		end

	disable_full_redraw_on_virtual_position_change
			-- Ensure `is_full_redraw_on_virtual_position_change_enabled' is `False'.
		require
			not_is_destroyed: not is_destroyed
		do
			implementation.disable_full_redraw_on_virtual_position_change
		ensure
			not_is_full_redraw_on_virtual_position_change_enabled: not is_full_redraw_on_virtual_position_change_enabled
		end

	lock_update
			-- Ensure `is_locked' is `True', thereby preventing graphical
			-- updates until `unlock_update' is called.
		require
			not_is_destroyed: not is_destroyed
		do
			implementation.lock_update
		ensure
			is_locked: is_locked
		end

	unlock_update
			-- Ensure `is_locked' is `False', thereby ensuring graphical
			-- updates occur as normal. The complete client area
			-- is refreshed to synchronize the display with the contents.
		require
			not_is_destroyed: not is_destroyed
		do
			implementation.unlock_update
		ensure
			not_is_locked: not is_locked
		end

	hide_vertical_scroll_bar
			-- Ensure no vertical scroll bar is displayed in `Current'
			-- at any time.
		require
			not_is_destroyed: not is_destroyed
		do
			implementation.hide_vertical_scroll_bar
		ensure
			not_is_vertical_scroll_bar_show_requested: not is_vertical_scroll_bar_show_requested
		end

	show_vertical_scroll_bar
			-- Ensure a vertical scroll bar is displayed in `Current'
			-- when required. Note that this does not force the vertical
			-- scroll bar to be visible, simply ensures that when `virtual_height'
			-- is greater than `viewable_height', the scroll bar is displayed.
		require
			not_is_destroyed: not is_destroyed
		do
			implementation.show_vertical_scroll_bar
		ensure
			is_vertical_scroll_bar_show_requested: is_vertical_scroll_bar_show_requested
		end

	is_vertical_scroll_bar_show_requested: BOOLEAN
			-- Will a vertical scroll bar be displayed in `Current' when
			-- `virtual_height' exceeds `viewable_height'?
		require
			not_is_destroyed: not is_destroyed
		do
			Result := implementation.is_vertical_scroll_bar_show_requested
		end

	hide_horizontal_scroll_bar
			-- Ensure no horizontal scroll bar is displayed in `Current'
			-- at any time.
		require
			not_is_destroyed: not is_destroyed
		do
			implementation.hide_horizontal_scroll_bar
		ensure
			not_is_horizontal_scroll_bar_show_requested: not is_horizontal_scroll_bar_show_requested
		end

	show_horizontal_scroll_bar
			-- Ensure a horizontal scroll bar is displayed in `Current'
			-- when required. Note that this does not force the horizontal
			-- scroll bar to be visible, simply ensures that when `virtual_width'
			-- is greater than `viewable_width', the scroll bar is displayed.
		require
			not_is_destroyed: not is_destroyed
		do
			implementation.show_horizontal_scroll_bar
		ensure
			is_horizontal_scroll_bar_show_requested: is_horizontal_scroll_bar_show_requested
		end

	is_horizontal_scroll_bar_show_requested: BOOLEAN
			-- Will a horizontal scroll bar be displayed in `Current' when
			-- `virtual_width' exceeds `viewable_width'?
		require
			not_is_destroyed: not is_destroyed
		do
			Result := implementation.is_horizontal_scroll_bar_show_requested
		end

	enable_focus_on_press
			-- Enable focus handling when mouse button is pressed on grid excluding header and scrollbars.
		require
			not_destroyed: not is_destroyed
		do
			implementation.drawable.enable_focus_on_press
		end

	disable_focus_on_press
			-- Disable focus handling when mouse button is pressed on grid excluding header and scrollbars.
		require
			not_destroyed: not is_destroyed
		do
			implementation.drawable.disable_focus_on_press
		end

feature -- Status report

	prunable: BOOLEAN = False
			-- May items be removed?

	writable: BOOLEAN = False
			-- Is there a current item that may be modified?

	readable: BOOLEAN = False
			-- Is there a current item that may be accessed?

	is_tree_enabled: BOOLEAN
			-- Is tree functionality enabled?
			-- Must be `True' to perform any tree structure functions on `Current'.
			-- Use `enable_tree' and `disable_tree' to set this state.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_tree_enabled
		end

	column_displayed (a_column: INTEGER): BOOLEAN
			-- May column `a_column' be displayed when `Current' is?
			-- Will return False if `hide' has been called on column `a_column'.
			-- A value of True does not signify that column `a_column' is visible on screen at that particular time.
		require
			not_destroyed: not is_destroyed
			a_column_within_bounds: a_column > 0 and a_column <= column_count
		do
			Result := implementation.column_displayed (a_column)
		end

	is_single_row_selection_enabled: BOOLEAN
			-- Does clicking or keyboard navigating via arrow keys select the whole row, unselecting
			-- any previously rows?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_single_row_selection_enabled
		end

	is_multiple_row_selection_enabled: BOOLEAN
			-- Does clicking or keyboard navigating via arrow keys select the whole row, with multiple
			-- row selection permitted via the use of Ctrl and Shift keys?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_multiple_row_selection_enabled
		end

	is_single_item_selection_enabled: BOOLEAN
			-- Does clicking or keyboard navigating via arrow keys select an item, unselecting
			-- any previously selected items?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_single_item_selection_enabled
		end

	is_multiple_item_selection_enabled: BOOLEAN
			-- Does clicking or keyboard navigating via arrow keys select an item, with multiple
			-- item selection permitted via the use of Ctrl and Shift keys?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_multiple_item_selection_enabled
		end

	is_selection_on_click_enabled: BOOLEAN
			-- Will an item be selected if clicked upon?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_selection_on_click_enabled
		end

	is_selection_on_single_button_click_enabled: BOOLEAN
			-- Will an item be selected if clicked upon via mouse button `1' only?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_selection_on_single_button_click_enabled
		end

	is_selection_keyboard_handling_enabled: BOOLEAN
			-- May items be selected via the keyboard?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.is_selection_keyboard_handling_enabled
		end

	is_item_tab_navigation_enabled: BOOLEAN
			-- Is the tabbing mode for `Current' set so that keyboard tabbing moves to/from 'has_default_activation' grid items?
		do
			Result := implementation.is_item_tab_navigation_enabled
		end

	first_visible_row: detachable EV_GRID_ROW
			-- First row visible in `Current' or Void if `visible_row_count' = 0
			-- If `is_vertical_scrolling_per_item', the first visible row may be only partially visible.
		require
			not_destroyed: not is_destroyed
			is_displayed: is_displayed
		do
			Result := implementation.first_visible_row
		ensure
			has_rows_implies_result_not_void: visible_row_count > 0 implies result /= Void
			no_rows_implies_result_void: visible_row_count = 0 implies result = Void
		end

	first_visible_column: detachable EV_GRID_COLUMN
			-- First column visible in `Current' or Void if `column_count' = 0
			-- If `is_horizontal_scrolling_per_item', the first visible column may be only partially visible.
		require
			not_destroyed: not is_destroyed
			is_displayed: is_displayed
		do
			Result := implementation.first_visible_column
		ensure
			has_columns_implies_result_not_void: column_count > 0 implies result /= Void
			no_columns_implies_result_void: column_count = 0 implies result = Void
		end

	last_visible_row: detachable EV_GRID_ROW
			-- Last row visible in `Current' or Void if `visible_row_count' = 0
			-- The last visible row may be only partially visible.
		require
			not_destroyed: not is_destroyed
			is_displayed: is_displayed
		do
			Result := implementation.last_visible_row
		ensure
			has_rows_implies_result_not_void: visible_row_count > 0 implies result /= Void
			no_rows_implies_result_void: visible_row_count = 0 implies result = Void
		end

	last_visible_column: detachable EV_GRID_COLUMN
			-- Index of last column visible in `Current' or 0 if `column_count' = 0.
			-- The last visible column may be only partially visible.
		require
			not_destroyed: not is_destroyed
			is_displayed: is_displayed
		do
			Result := implementation.last_visible_column
		ensure
			has_columns_implies_result_not_void: column_count > 0 implies result /= Void
			no_columns_implies_result_void: column_count = 0 implies result = Void
		end

	visible_row_indexes: ARRAYED_LIST [INTEGER]
			-- Indexes of all rows that are currently visible in `Current'.
			-- `Result' may not be contiguous if `is_tree_enabled' and one or more of the
			-- visible rows have subrows and are not expanded.
		require
			not_destroyed: not is_destroyed
			is_displayed: is_displayed
		do
			Result := implementation.visible_row_indexes
		ensure
			result_not_void: Result /= Void
		end

	viewable_row_indexes: ARRAYED_LIST [INTEGER]
			-- Indexes of all rows that are currently viewable in the grid in its present state.
			-- For example, if the first node is a non expanded tree that has 10 subrows, the contents
			-- would be 1, 11, 12, 13, 14, ...
			-- This list only returns valid values if variable row heights, tree functionality or
			-- hidden nodes are enabled in the grid, otherwise the returned list is empty.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.viewable_row_indexes
		ensure
			result_not_void: Result /= Void
		end

	visible_column_indexes: ARRAYED_LIST [INTEGER]
			-- All columns that are currently visible in `Current'.
			-- `Result' may not be contiguous if one or more columns are hidden.
		require
			not_destroyed: not is_destroyed
			is_displayed: is_displayed
		do
			Result := implementation.visible_column_indexes
		ensure
			result_not_void: Result /= Void
		end

	tree_node_connector_color: EV_COLOR
			-- Color of connectors drawn between tree nodes within `Current'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.tree_node_connector_color
		ensure
			result_not_void: Result /= Void
		end

	are_columns_drawn_above_rows: BOOLEAN
			-- For drawing purposes, are columns drawn above rows?
			-- If `True', for all cells within `Current' whose `column' and `row' have non-Void
			-- foreground or background colors, the column colors are given priority.
			-- If `False', the colors of the row are given priority.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.are_columns_drawn_above_rows
		end

	depth_in_tree (a_row_index: INTEGER): INTEGER
			-- Depth in tree for `a_row'
		require
			valid_index: 0 < a_row_index and a_row_index <= row_count
		do
			Result := implementation.depth_in_tree (a_row_index)
		end

	find_next_item (a_row_index, a_column_index: INTEGER; look_left, a_is_tab_navigatable: BOOLEAN): detachable EV_GRID_ITEM
			-- Find the next item horizontally in `grid_row' starting at index `starting_index', if 'look_left' then the the item to the left/up is found, else it looks right/down.
			-- If `a_is_tab_navigatable' then Result must have 'is_tab_navigatable' set.
			-- Result is Void if no item is found.
		require
			a_row_index_valid: a_row_index > 0 and then a_row_index <= row_count
			a_column_index_valid: a_column_index > 0 and then a_column_index <= column_count
		do
			Result := implementation.find_next_item (a_row_index, a_column_index, look_left, a_is_tab_navigatable)
		end

	has_selected_row: BOOLEAN
			-- Has selected row?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.has_selected_row
		ensure
			Result_implies_selected_rows_not_empty: Result implies not selected_rows.is_empty
		end

	has_selected_column: BOOLEAN
			-- Has selected column?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.has_selected_column
		ensure
			Result_implies_selected_columns_not_empty: Result implies not selected_columns.is_empty
		end

	has_selected_item: BOOLEAN
			-- Has selected items?
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.has_selected_item
		ensure
			Result_implies_selected_items_not_empty: Result implies not selected_items.is_empty
		end

feature -- Element change

	insert_new_row (i: INTEGER)
			-- Insert a new row immediately before row at index `i'.
		require
			not_destroyed: not is_destroyed
			i_within_range: i > 0 and i <= row_count + 1
			not_inserting_within_existing_subrow_structure: i <= row_count implies row (i).parent_row = Void
		do
			implementation.insert_new_rows (1, i)
		ensure
			row_count_set: row_count = old row_count + 1
		end

	insert_new_rows (rows_to_insert, i: INTEGER)
			-- Insert `rows_to_insert' rows immediately before row at index `i'.
		require
			not_destroyed: not is_destroyed
			i_within_range: i > 0 and i <= row_count + 1
			rows_to_insert_positive: rows_to_insert >= 1
			not_inserting_within_existing_subrow_structure: i <= row_count implies row (i).parent_row = Void
		do
			implementation.insert_new_rows (rows_to_insert, i)
		ensure
			row_count_set: row_count = old row_count + rows_to_insert
		end

	insert_new_row_parented (i: INTEGER; a_parent_row: EV_GRID_ROW)
			-- Insert a new row immediately before row at index `i' and make that row a subnode of `a_parent_row'.
		require
			not_destroyed: not is_destroyed
			tree_enabled: is_tree_enabled
			i_positive: i > 0
			i_less_than_row_count: i <= row_count + 1
			a_parent_row_not_void: a_parent_row /= Void
			a_parent_row_in_current: a_parent_row.parent = Current
			i_valid_for_parent: i > a_parent_row.index and i <= a_parent_row.index + a_parent_row.subrow_count_recursive + 1
			not_inserting_within_existing_subrow_structure: i < a_parent_row.index + a_parent_row.subrow_count_recursive
				implies row (i).parent_row = a_parent_row
		do
			implementation.insert_new_rows_parented (1, i, a_parent_row)
		ensure
			row_count_set: row_count = old row_count + 1
			subrow_count_set: a_parent_row.subrow_count = old a_parent_row.subrow_count + 1
		end

	insert_new_rows_parented (rows_to_insert, i: INTEGER; a_parent_row: EV_GRID_ROW)
			-- Insert `rows_to_insert' new rows immediately before row at index `i'.
			-- Make these newly inserted rows subnodes of `a_parent_row'.
		require
			not_destroyed: not is_destroyed
			tree_enabled: is_tree_enabled
			i_positive: i > 0
			rows_to_insert_positive: rows_to_insert >= 1
			i_less_than_row_count: i <= row_count + 1
			a_parent_row_not_void: a_parent_row /= Void
			i_valid_for_parent: i > a_parent_row.index and i <= a_parent_row.index + a_parent_row.subrow_count_recursive + 1
			not_inserting_within_existing_subrow_structure: i < a_parent_row.index + a_parent_row.subrow_count_recursive
				implies row (i).parent_row = a_parent_row
		do
			implementation.insert_new_rows_parented (rows_to_insert, i, a_parent_row)
		ensure
			row_count_set: row_count = old row_count + rows_to_insert
			subrow_count_set: a_parent_row.subrow_count = old a_parent_row.subrow_count + rows_to_insert
		end

	insert_new_column (a_index: INTEGER)
			-- Insert a new column immediately before column at index `a_index'.
		require
			not_destroyed: not is_destroyed
			a_index_within_range: a_index > 0 and a_index <= column_count + 1
			new_column_insertable: a_index <= column_count implies column ((a_index - 1).max (1)).all_items_may_be_set
		do
			implementation.insert_new_column (a_index)
		ensure
			column_count_set: column_count = old column_count + 1
		end

	move_row (i, j: INTEGER)
			-- Move row at index `i' immediately before row at index `j'.
			-- If `j' = `row_count + 1' then row `i' is moved to the last index in the grid.
			-- Row `i' will be unparented if it has a `parent_row'.
		require
			not_destroyed: not is_destroyed
			i_valid: i > 0 and then i <= row_count
			j_valid: j > 0 and then j <= row_count + 1
			row_has_no_subrows: row (i).subrow_count = 0
			not_breaking_existing_subrow_structure:
				j = row_count + 1 or
				(j = i or (j = i + 1 and (i + 1 <= row_count)) and then row (i + 1).parent_row = Void) or
				row (j).parent_row = Void
		do
			implementation.move_rows_to_parent (i, j, 1, Void)
		ensure
			rows_moved:
				(j <= i implies row (j) = old row (i)) and
				(j > i implies row (j - 1) = old row (i)) and
				(j < i implies (row (i) = old row ((i - 1).max (1)))) and
				(j > i + 1 implies (row (i) = old row ((i + 1).min (row_count))))
			row_count_unchanged: row_count = old row_count
		end

	move_rows (i, j, n: INTEGER)
			-- Move `n' rows starting at index `i' immediately before row at index `j'.
			-- If `j' = `row_count + 1' the rows are moved to the very bottom of the grid.
			-- If `is_tree_enabled', all rows moved that share the same tree structure depth
			-- as row `i' are unparented and set as root rows within the grid tree.
			-- All parent rows within the rows moved that have a tree structure depth
			-- greater than that of row `i' are left parented.
		require
			not_destroyed: not is_destroyed
			i_valid: i > 0 and then i <= row_count
			j_valid: j > 0 and then j <= row_count + 1
			n_valid: n > 0 and then i + n <= row_count + 1
			move_not_overlapping: n > 1 implies (j <= i or else j >= i + n)
			rows_may_be_moved: rows_may_be_moved (i, n)
			not_breaking_existing_subrow_structure:
				j = row_count + 1 or
				(j = i or (j = i + n and (i + n <= row_count)) and then row (i + n).parent_row = Void) or
				row (j).parent_row = Void
		do
			implementation.move_rows_to_parent (i, j, n, Void)
		ensure
			rows_moved:
				(j <= i implies row (j) = old row (i) and then row (j + n - 1) = old row (i + n - 1)) and
				(j > i + n implies row (j - n) = old row (i) and then row (j - 1) = old row (i + n - 1))
			row_count_unchanged: row_count = old row_count
		end

	move_row_to_parent (i, j: INTEGER; a_parent_row: EV_GRID_ROW)
			-- Move row at index `i' immediately before row at index `j'.
			-- Row `i' is re-parented as a subrow of `a_parent_row'.
			-- If `j' = `row_count + 1' then row `i' is moved to the last index in the grid.
		require
			not_destroyed: not is_destroyed
			tree_enabled: is_tree_enabled
			i_valid: i > 0 and then i <= row_count
			j_valid: j > 0 and then j <= row_count + 1
			row_has_no_subrows: row (i).subrow_count = 0
			a_parent_row_not_void: a_parent_row /= Void
			j_valid_for_move_to_a_parent_row:
				(j = i + 1 implies (i > a_parent_row.index and i <= a_parent_row.index + a_parent_row.subrow_count_recursive + 1)) or
				(j > a_parent_row.index and j <= a_parent_row.index + a_parent_row.subrow_count_recursive + 1)
			rows_may_be_moved: rows_may_be_moved (i, 1)
			not_inserting_within_existing_subrow_structure: j < a_parent_row.index + a_parent_row.subrow_count_recursive
				implies row (j).parent_row = a_parent_row
		do
			implementation.move_rows_to_parent (i, j, 1, a_parent_row)
		ensure
			rows_moved:
				(j <= i implies row (j) = old row (i)) and
				(j > i implies row (j - 1) = old row (i)) and
				(j < i implies (row (i) = old row ((i - 1).max (1)))) and
				(j > i + 1 implies (row (i) = old row ((i + 1).min (row_count))))
			row_count_unchanged: row_count = old row_count
		end

	 move_rows_to_parent (i, j, n: INTEGER; a_parent_row: EV_GRID_ROW)
			-- Move `n' rows starting at index `i' immediately before row at index `j'.
			-- All rows moved that share the same tree structure depth
			-- as row `i' are reparented as a subrow of `a_parent_row'.
			-- All parent rows within the rows moved that have a tree structure depth
			-- greater than that of row `i' are left parented.
		require
			not_destroyed: not is_destroyed
			tree_enabled: is_tree_enabled
			i_valid: i > 0 and then i <= row_count
			j_valid: j > 0 and then j <= row_count + 1
			n_valid: n > 0 and then i + n <= row_count + 1
			move_not_overlapping: n > 1 implies (j <= i or else j >= i + n)
			rows_may_be_moved: rows_may_be_moved (i, n)
			a_parent_row_not_void: a_parent_row /= Void
			j_valid_for_move_to_a_parent_row:
					(j = i + n implies (i > a_parent_row.index and i <= a_parent_row.index + a_parent_row.subrow_count_recursive + 1)) or
					(j > a_parent_row.index and j <= a_parent_row.index + a_parent_row.subrow_count_recursive + 1)
			not_inserting_within_existing_subrow_structure:
				j <= a_parent_row.index + a_parent_row.subrow_count_recursive implies row (j).parent_row = a_parent_row
		do
			implementation.move_rows_to_parent (i, j, n, a_parent_row)
		ensure
			rows_moved:
				(j < i implies row (j) = old row (i) and then row (j + n - 1) = old row (i + n - 1)) and
				(j > i + n implies row (j - n) = old row (i) and then row (j - 1) = old row (i + n - 1))
			row_count_unchanged: row_count = old row_count
		end

	move_column (i, j: INTEGER)
			-- Move column at index `i' and insert immediately before column at index `j'.
			-- To move column `i' to the last index in the grid, use `j' = `column_count + 1'.
		require
			not_destroyed: not is_destroyed
			i_valid: i > 0 and then i <= column_count
			j_valid: j > 0 and then j <= column_count + 1
			column_i_moveable: column (i).all_items_may_be_removed
			column_j_settable: j <= column_count implies column (j).all_items_may_be_set
		do
			implementation.move_columns (i, j, 1)
		ensure
			columns_moved:
				(j <= i implies column (j) = old column (i)) and
				(j > i implies column (j - 1) = old column (i)) and
				(j < i implies (column (i) = old column ((i - 1).max (1)))) and
				(j > i + 1 implies (column (i) = old column ((i + 1).min (column_count))))
			column_count_unchanged: column_count = old column_count
		end

	move_columns (i, j, n: INTEGER)
			-- Move `n' columns starting at column `i' and insert immediately before column `j'.
		require
			not_destroyed: not is_destroyed
			i_valid: i > 0 and then i <= column_count
			j_valid: j > 0 and then j <= column_count + 1
			n_valid: n > 0 and then i + n <= column_count + 1
			move_not_overlapping: n > 1 implies (j <= i or else j >= i + n)
			columns_removable: are_columns_removable (i, n)
			column_j_settable: j <= column_count implies column (j).all_items_may_be_set
		do
			implementation.move_columns (i, j, n)
		ensure
			columns_moved:
				(j < i implies column (j) = old column (i) and then column (j + n - 1) = old column (i + n - 1)) and
				(j > i + n implies column (j - n) = old column (i) and then column (j - 1) = old column (i + n - 1))
			column_count_unchanged: column_count = old column_count
		end

	set_item (a_column, a_row: INTEGER; a_item: detachable EV_GRID_ITEM)
			-- Set grid item at position (`a_column', `a_row') to `a_item'.
			-- If `a_item' is `Void', the current item (if any) is removed.
		require
			not_destroyed: not is_destroyed
			a_item_not_parented: a_item /= Void implies a_item.parent = Void
			a_column_positive: a_column > 0
			a_row_positive: a_row > 0
			item_may_be_added_if_row_is_a_subrow: a_item /= Void and then a_row <= row_count and then row (a_row).is_part_of_tree_structure implies row (a_row).is_index_valid_for_item_setting_if_tree_node (a_column)
			item_may_be_removed_if_row_is_a_subrow: a_item = Void and then a_row <= row_count and then row (a_row).is_part_of_tree_structure implies row (a_row).is_index_valid_for_item_removal_if_tree_node (a_column)
		do
			implementation.set_item (a_column, a_row, a_item)
		ensure
			item_set: item (a_column, a_row) = a_item
		end

	remove_item (a_column, a_row: INTEGER)
			-- Remove grid item at position (`a_column', `a_row').
		require
			not_destroyed: not is_destroyed
			a_column_positive: a_column > 0
			a_row_positive: a_row > 0
			item_may_be_removed_if_row_is_a_subrow: row (a_row).is_part_of_tree_structure implies row (a_row).is_index_valid_for_item_removal_if_tree_node (a_column)
		do
			set_item (a_column, a_row, Void)
		ensure
			item_removed: item (a_column, a_row) = Void
		end

	clear
			-- Remove all items from `Current'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.clear
		ensure
			to_implement_assertion ("EV_GRID.clear - All items positions return `Void'.")
		end

	wipe_out
			-- Remove all columns and rows from `Current'.
		require
			not_destroyed: not is_destroyed
		do
			implementation.wipe_out
		ensure
			columns_removed: column_count = 0
			rows_removed: row_count = 0
		end

feature -- Removal

	remove_column (a_column: INTEGER)
			-- Remove column `a_column'.
		require
			not_destroyed: not is_destroyed
			a_column_positive: a_column > 0
			a_column_less_than_column_count: a_column <= column_count
			column_may_be_removed: column (a_column).all_items_may_be_removed
		do
			implementation.remove_column (a_column)
		ensure
			column_count_updated: column_count = old column_count - 1
			old_column_removed: (old column (a_column)).parent = Void
		end

	remove_row (a_row: INTEGER)
			-- Remove row `a_row' and all subrows recursively.
			-- If `row (a_row).subrow_count_recursive' is greater than 0 then
			-- all subrows of the row are also removed from `Current'.
		require
			not_destroyed: not is_destroyed
			a_row_positive: a_row > 0
			a_row_less_than_row_count: a_row <= row_count
		do
			implementation.remove_row (a_row)
		ensure
			row_count_updated: row_count = old row_count - (old row (a_row).subrow_count_recursive + 1)
			old_row_removed: (old row (a_row)).parent = Void
			to_implement_assertion ("EV_GRID.remove_row		All old recursive subrows removed.")
		end

	remove_rows (lower_index, upper_index: INTEGER)
			-- Remove all rows from `lower_index' to `upper_index' inclusive.
		require
			not_destroyed: not is_destroyed
			valid_lower_index: lower_index >= 1 and lower_index <= row_count
			valid_upper_index: upper_index >= lower_index and upper_index <= row_count
			valid_final_row_in_tree_structure: (is_tree_enabled and then
				attached highest_parent_row_within_bounds (lower_index, upper_index) as l_row implies
				upper_index = l_row.index + l_row.subrow_count_recursive) or
				            (is_tree_enabled and then highest_parent_row_within_bounds
				(lower_index, upper_index) = Void implies row (upper_index).subrow_count = 0)
			valid_final_row_in_tree_structure: (is_tree_enabled and then
				attached highest_parent_row_within_bounds (lower_index, upper_index) as l_row implies
				upper_index = l_row.index + l_row.subrow_count_recursive) or
				            (is_tree_enabled and then highest_parent_row_within_bounds
				(lower_index, upper_index) = Void implies row (upper_index).subrow_count = 0)
		do
			implementation.remove_rows (lower_index, upper_index)
		ensure
			row_count_consistent: row_count = (old row_count) - (upper_index - lower_index + 1)
			lower_row_removed: (old row (lower_index)).parent = Void
			upper_row_removed: (old row (upper_index)).parent = Void
			to_implement_assertion (once "middle_rows_removed from lower to upper all old rows parent = Void")
		end

feature -- Measurements

	column_count: INTEGER
			-- Number of columns in Current.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.column_count
		ensure
			result_not_negative: Result >= 0
		end

	displayed_column_count: INTEGER
			-- Number of non-hidden columns displayed in Current.
			-- Equal to `column_count' if no columns have been
			-- hidden via `hide'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.displayed_column_count
		ensure
			result_valid: Result >= 0 and Result <= column_count
		end

	row_count: INTEGER
			-- Number of rows in Current
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.row_count
		ensure
			result_not_negative: Result >= 0
		end

	visible_row_count: INTEGER
			-- Number of visible rows in `Current'. When `is_tree_enabled',
			-- a number of rows may be within a collapsed parent row, so these
			-- are ignored.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.visible_row_count
		ensure
			result_not_negative: Result >= 0
		end

	tree_node_spacing: INTEGER
			-- Spacing value used around the expand/collapse node of a
			-- subrow. For example, to determine the height available for the node image
			-- within a subrow, subtract 2 * tree_node_spacing from the `row_height'.
		require
			not_destroyed: not is_destroyed
		do
			Result := implementation.tree_node_spacing
		ensure
			result_positive: Result >= 1
		end

feature -- Activation Handling

	propagate_key_press (a_key: EV_KEY)
			-- Propagate key press for `a_key' to `Current'.
			-- Useful for handling custom navigation during item activation.
		require
			not_destroyed: not is_destroyed
		do
			implementation.key_press_received (a_key)
		end

feature -- Contract support

	are_columns_removable (a_index, n: INTEGER): BOOLEAN
			-- Are `n' columns starting at column index `a_index' removable from `Current'?
		require
			a_index_positive: a_index > 0
			n_positive: n > 0
			a_index_not_greater_than_column_count: a_index <= column_count
			n_valid: a_index + n <= column_count + 1
		local
			a_counter: INTEGER
		do
			from
				Result := True
				a_counter := a_index
			until
				a_counter = a_index + n or else not Result
			loop
				Result := column (a_counter).all_items_may_be_removed
				a_counter := a_counter + 1
			end
		end

	highest_parent_row_within_bounds (lower_index, upper_index: INTEGER): detachable EV_GRID_ROW
			-- Return the highest level `parent_row' recursively of row `upper_index'
			-- that has an index greater or equal to `lower_index'.
		require
			not_destroyed: not is_destroyed
			tree_enabled: is_tree_enabled
			valid_lower_index: lower_index >= 1 and lower_index <= row_count
			valid_upper_index: upper_index >= lower_index and upper_index <= row_count
		local
			l_row: EV_GRID_ROW
		do
			l_row := row (upper_index)
			from
			until
				l_row.parent_row = Void or l_row.index < lower_index
			loop
				if attached l_row.parent_row as l_parent_row then
					l_row := l_parent_row
					if l_row.index > lower_index then
						Result := l_row
					end
				end
			end
		end

	rows_may_be_moved (a_first_row_index, a_row_count: INTEGER): BOOLEAN
			-- Do rows from `a_first_row_index' to `a_first_row_index' + `a_row_count' - 1 represent a complete tree structure?
			-- and if row (`a_first_row_index') has a `parent_row', are all rows to be moved nested within that parent
			-- within the tree structure? If `Result' is `True', the rows may be moved without breaking an existing
			-- tree structure.
		require
			row_count_positive: a_row_count >= 1
			first_row_index_valid: a_first_row_index >= 1 and a_first_row_index + a_row_count - 1 <= row_count
		local
			counter: INTEGER
			current_row: EV_GRID_ROW
			parent_of_first_row: detachable  EV_GRID_ROW
		do
			Result := True
			parent_of_first_row := row (a_first_row_index).parent_row
			from
				counter := a_first_row_index
			until
				counter >= a_first_row_index + a_row_count or Result = False
			loop
				current_row := row (counter)
				if parent_of_first_row /= Void then
						-- Ensure that we have not moved up a level in the tree structure
						-- past the parent of row `a_first_row_index'.
					Result := current_row.parent_row = parent_of_first_row
				end
				if counter + 1 + current_row.subrow_count_recursive > a_first_row_index + a_row_count then
						-- Ensure that we are not splitting an existing structure.
					Result := False
				end
				counter := counter + 1 + current_row.subrow_count_recursive
			end
		end

feature {NONE} -- Contract support

	is_in_default_state: BOOLEAN
			-- Is `Current' in its default state?
		do
			Result := row_count = 0 and column_count = 0 and not is_horizontal_scrolling_per_item and
				is_vertical_scrolling_per_item and is_header_displayed and
				is_row_height_fixed and subrow_indent = 0 and is_single_item_selection_enabled and is_selection_on_click_enabled and
				are_tree_node_connectors_shown and are_columns_drawn_above_rows and not is_resizing_divider_enabled and
				is_column_resize_immediate and not is_full_redraw_on_virtual_position_change_enabled and
				not is_vertical_overscroll_enabled and not is_horizontal_overscroll_enabled and not is_locked and
				is_horizontal_scroll_bar_show_requested and is_vertical_scroll_bar_show_requested
		end

feature {EV_GRID_I} -- Implementation

	frozen new_row: like row_type
			-- Create a new row.
		do
			create Result
		end

	frozen new_column: like column_type
			-- Create a new column.
		do
			create Result
		end

feature {EV_ANY, EV_ANY_I} -- Implementation

	implementation: EV_GRID_I
		-- Responsible for interaction with native graphics toolkit.

feature {NONE} -- Implementation

	create_implementation
			-- See `{EV_ANY}.create_implementation'.
		do
			create {EV_GRID_IMP} implementation.make
		end

note
	copyright: "Copyright (c) 1984-2014, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
			Eiffel Software
			5949 Hollister Ave., Goleta, CA 93117 USA
			Telephone 805-685-1006, Fax 805-685-6869
			Website http://www.eiffel.com
			Customer support http://support.eiffel.com
		]"

end