note
	description: "Objects that represent an EiffelVision header control. Mswin Implementation."
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date: "$Date$"
	revision: "$Revision$"

class
	EV_HEADER_IMP

inherit
	EV_HEADER_I
		redefine
			interface
		end

	EV_ITEM_LIST_IMP [EV_HEADER_ITEM, EV_HEADER_ITEM_IMP]
		redefine
			interface,
			make
		end

	EV_PRIMITIVE_IMP
		undefine
			escape_pnd, pnd_press, on_right_button_double_click, on_middle_button_double_click,
			on_left_button_double_click, on_left_button_up,
			on_right_button_down, on_left_button_down, on_middle_button_down
		redefine
			interface,
			make,
			destroy,
			on_mouse_move,
			on_set_cursor
		end

	EV_FONTABLE_IMP
		redefine
			interface
		end

	WEL_HEADER_CONTROL
		rename
			make as wel_make,
			parent as wel_parent,
			set_parent as wel_set_parent,
			shown as is_displayed,
			destroy as wel_destroy,
			item as wel_item,
			enabled as is_sensitive,
			width as wel_width,
			height as wel_height,
			x as x_position,
			y as y_position,
			move as wel_move,
			resize as wel_resize,
			move_and_resize as wel_move_and_resize,
			text as wel_text,
			set_text as wel_set_text,
			font as wel_font,
			set_font as wel_set_font,
			has_capture as wel_has_capture
		undefine
			set_width,
			set_height,
			on_left_button_down,
			on_middle_button_down,
			on_right_button_down,
			on_left_button_up,
			on_middle_button_up,
			on_right_button_up,
			on_left_button_double_click,
			on_middle_button_double_click,
			on_right_button_double_click,
			on_erase_background,
			on_mouse_move,
			on_mouse_wheel,
			on_set_focus,
			on_desactivate,
			on_kill_focus,
			on_key_down,
			on_key_up,
			on_char,
			on_set_cursor,
			on_size,
			show,
			hide,
			x_position,
			y_position,
			on_sys_key_down,
			on_sys_key_up,
			default_process_message,
			on_getdlgcode,
			on_wm_dropfiles
		redefine
			on_hdn_begin_track,
			on_hdn_track,
			on_hdn_end_track,
			on_hdn_item_changed,
			on_hdn_item_changing,
			default_style
		end

	EV_SHARED_IMAGE_LIST_IMP
		export
			{NONE} all
		end

	EV_PICK_AND_DROPABLE_ITEM_HOLDER_IMP
		export
			{NONE} all
		redefine
			interface
		end

	WEL_HHT_CONSTANTS
		export
			{NONE} all
		end

create
	make

feature -- Initialization

	old_make (an_interface: attached like interface)
			-- Create `Current' with interface `an_interface'.
		do
			assign_interface (an_interface)
		end

	make
			-- Initialize `Current'.
		local
			l_rect: WEL_RECT
		do
			wel_make (default_parent, 0, 0, 0, 0, 0)
			create ev_children.make (2)
			initialize_pixmaps
			Precursor {EV_ITEM_LIST_IMP}

			disable_tabable_from
			disable_tabable_to

			set_default_font

			create l_rect.make (0, 0, 0, 0)

			retrieve_and_set_windows_pos (l_rect)



			Precursor {EV_PRIMITIVE_IMP}
		end

	default_style: INTEGER
			-- Default style used to create the control
		do
			Result := Ws_child | Hds_Buttons | Hds_horz | Ws_visible
		end

feature -- Status report

	ev_children: ARRAYED_LIST [EV_HEADER_ITEM_IMP]
			-- List of the children.

feature -- Status setting

	refresh_item (item_imp: EV_HEADER_ITEM_IMP)
			-- Refresh `item_imp'.
		require
			item_not_void: item_imp /= Void
		do
				-- Note that one is subtracted as the wel index is zero based.
			set_header_item (ev_children.index_of (item_imp, 1) - 1, item_imp)
		end

feature -- Element change

	insert_item (item_imp: EV_HEADER_ITEM_IMP; an_index: INTEGER)
			-- Insert `item_imp' at `an_index'.
		do
			insert_header_item (item_imp, an_index - 1)
			item_imp.set_pixmap_in_parent
		end

feature -- Removal

	remove_item (item_imp: EV_HEADER_ITEM_IMP)
			-- Remove `item' from the list
		local
			an_index: INTEGER
		do
			an_index := ev_children.index_of (item_imp, 1) - 1
			delete_header_item (an_index)
		end

feature -- Miscellaneous

	find_item_at_position (x_pos, y_pos: INTEGER): detachable EV_HEADER_ITEM_IMP
			-- `Result' is list item at pixel position `x_pos', `y_pos'.
		local
			hd_hit_test_info: WEL_HD_HIT_TEST_INFO
		do
			hd_hit_test_info := item_info_from_point (create {WEL_POINT}.make (x_pos, y_pos))
			if hd_hit_test_info /= Void and hd_hit_test_info.index /= - 1 then
				Result := ev_children @ (hd_hit_test_info.index + 1)
			end
		end

feature {EV_ANY, EV_ANY_I} -- Implementation

	interface: detachable EV_HEADER note option: stable attribute end

feature {EV_HEADER_ITEM_IMP} -- Implementation

	image_list: detachable EV_IMAGE_LIST_IMP
		-- Image list associated with `Current'.
		-- `Void' if none.

	setup_image_list
			-- Create the image list and associate it
			-- to `Current' if not already associated.
		do
			image_list := get_imagelist_with_size (pixmaps_width, pixmaps_height)
			set_image_list (image_list)
		ensure then
			image_list_not_void: image_list /= Void
		end

	pixmaps_size_changed
			-- The size of the displayed pixmaps has just
			-- changed.
		local
			l_cursor: CURSOR
			l_item: EV_HEADER_ITEM_IMP
		do
			if image_list /= Void then
				set_image_list (Void)
				image_list := Void
			end
			l_cursor := ev_children.cursor
			from
				ev_children.start
			until
				ev_children.off
			loop
				l_item := ev_children.item
				l_item.set_pixmap_in_parent
				ev_children.forth
			end
			ev_children.go_to (l_cursor)
		end

	resize_item_to_content (header_item: EV_HEADER_ITEM_IMP)
			-- Resize `header_item' width to fully display both `pixmap' and `text'.
		require
			header_item_not_void: header_item /= Void
			header_item_parented_in_current: header_item.parent_imp = Current
		local
			desired_width: INTEGER
			l_text: STRING_32
			font_imp: detachable EV_FONT_IMP
			margin: INTEGER
		do
			margin := {WEL_API}.send_message_result_integer (wel_item, hdm_get_bitmap_margin, cwel_integer_to_pointer (0), cwel_integer_to_pointer (0))
			l_text := header_item.text
			if not l_text.is_empty then
				if attached private_font as l_private_font then
					font_imp ?= l_private_font.implementation
					check
						font_not_void: font_imp /= Void then
					end
					desired_width := font_imp.string_width (l_text)
				elseif attached private_wel_font as l_private_wel_font then
					desired_width := l_private_wel_font.string_width (l_text)
				else
					check False end
				end
			end

			if header_item.pixmap_imp /= Void then
				if l_text.is_empty then
					desired_width := desired_width + pixmaps_width
				else
					desired_width := desired_width + pixmaps_width + margin * 2
				end
			end
			desired_width := desired_width + 18
				-- Restrict `desired_width' to dimensions permitted by `resize_item_to_content'.
			desired_width := desired_width.min (header_item.maximum_width)
			desired_width := desired_width.max (header_item.minimum_width)

			header_item.set_width (desired_width)
		end

	pointed_divider_index: INTEGER
			-- Index of divider currently beneath the mouse pointer, or
			-- 0 if none.
		local
			hit_test_info: WEL_HD_HIT_TEST_INFO
			wel_point: WEL_POINT
		do
			create wel_point.make (0, 0)
			wel_point.set_cursor_position
			wel_point.set_x (wel_point.x - absolute_x - 1)
			wel_point.set_y (wel_point.y - absolute_y - 1)
			hit_test_info := item_info_from_point (wel_point)
			if flag_set (hit_test_info.flags, Hht_on_divider) or flag_set (hit_test_info.flags, hht_on_div_open) then
				Result := hit_test_info.index + 1
			else
				Result := 0
			end
		end

feature {NONE} -- Implementation

	destroy
			-- Destroy `Current'.
		do
			attached_interface.wipe_out
			Precursor {EV_PRIMITIVE_IMP}
		end

	on_hdn_begin_track (info: WEL_HD_NOTIFY)
			-- The user has begun dragging a divider in the control
			-- (that is, the user has pressed the left mouse button while
			-- the mouse cursor is on a divider in the header control).
		local
			header_item: EV_HEADER_ITEM_IMP
		do
			header_item := ev_children @ (info.item_index + 1)
			if item_resize_start_actions_internal /= Void then
				item_resize_start_actions_internal.call ([header_item.attached_interface])
			end
			if not header_item.user_can_resize then
					-- Prevent the item from resizing if not `user_can_resize'.
				set_message_return_value (to_lresult (1))
			end
		end

	on_hdn_track (info: WEL_HD_NOTIFY)
			-- The user is dragging a divider in the header control.
		local
			header_item: EV_HEADER_ITEM_IMP
			desired_width: INTEGER
		do
			header_item := ev_children.i_th (info.item_index + 1)
			if flag_set (hdi_width, info.header_item.mask) then
				desired_width := info.header_item.width
				desired_width := desired_width.min (header_item.maximum_width).max (header_item.minimum_width)
				if header_item.width /= desired_width then
					header_item.set_width (desired_width)
				end
			end
			if item_resize_actions_internal /= Void then
				header_item := ev_children @ (info.item_index + 1)
				item_resize_actions_internal.call ([header_item.attached_interface])
			end
		end

	on_hdn_end_track (info: WEL_HD_NOTIFY)
			-- The user has finished dragging a divider.
		local
			header_item: EV_HEADER_ITEM_IMP
		do
			if item_resize_end_actions_internal /= Void then
				header_item := ev_children @ (info.item_index + 1)
				item_resize_end_actions_internal.call ([header_item.attached_interface])
			end
		end

	on_hdn_item_changing (info: WEL_HD_NOTIFY)
			-- The attributes of a header are changing.
			-- (from WEL_HEADER_CONTROL)
		local
			header_item: EV_HEADER_ITEM_IMP
			desired_width: INTEGER
		do
			header_item := ev_children @ (info.item_index + 1)
			desired_width := info.header_item.width
			if desired_width < header_item.minimum_width or desired_width > header_item.maximum_width then
				set_message_return_value (to_lresult (1))
			end
		end

	on_hdn_item_changed (info: WEL_HD_NOTIFY)
			-- The attributes of a header item have changed.
			-- (from WEL_HEADER_CONTROL)
		do
		end

	internal_propagate_pointer_press (keys, x_pos, y_pos, button: INTEGER)
			-- Propagate `keys', `x_pos' and `y_pos' to the appropriate
			-- item event. Called on a pointer button press.
		local
			pt: WEL_POINT
			l_pointed_divider_index: INTEGER
			l_item_imp: detachable EV_HEADER_ITEM_IMP
			l_item: detachable EV_HEADER_ITEM
			l_x_offset: INTEGER
		do
			pt := client_to_screen (x_pos, y_pos)
			l_pointed_divider_index := pointed_divider_index
			l_x_offset := x_pos
			l_item_imp := find_item_at_position (x_pos, y_pos)
			if transport_executing then
				if l_item_imp /= Void and then l_item_imp.is_transport_enabled and then
					not parent_is_pnd_source and then l_item_imp.parent /= Void
				then
					l_item_imp.pnd_press (x_pos, y_pos, button, pt.x, pt.y)
					if l_item_imp.motion_action = ev_pnd_execute then
						disable_default_processing
					end
				elseif attached pnd_item_source as l_pnd_item_source then
					l_pnd_item_source.pnd_press (x_pos, y_pos, button, pt.x, pt.y)
				end
				if item_is_pnd_source_at_entry = item_is_pnd_source then
					pnd_press (x_pos, y_pos, button, pt.x, pt.y)
					if motion_action = ev_pnd_execute then
						disable_default_processing
					end
				end
			else
				if l_pointed_divider_index = 0 then
						-- Clicking on the divider should not register as an item button click.
					if l_item_imp /= Void then
						l_item := l_item_imp.attached_interface
						l_x_offset := l_x_offset - item_x_offset (l_item)
						if l_item_imp.pointer_button_press_actions_internal /= Void then
							l_item_imp.pointer_button_press_actions.call (
								[l_x_offset, y_pos, button, 0.0, 0.0, 0.0, pt.x, pt.y])
						end
					end
					if item_pointer_button_press_actions_internal /= Void then
						item_pointer_button_press_actions_internal.call (
							[l_item, l_x_offset, y_pos, button]
						)
					end
				end
				if not press_actions_called and call_press_event then
					attached_interface.pointer_button_press_actions.call
						([x_pos, y_pos, button, 0.0, 0.0, 0.0, pt.x, pt.y])
				end
			end

				-- Reset `call_press_event'.
			keep_press_event
		end

	internal_propagate_pointer_double_press
		(keys, x_pos, y_pos, button: INTEGER)
			-- Propagate `keys', `x_pos' and `y_pos' to the appropriate
			-- item event. Called on a pointer button double press.
		local
			l_item_imp: detachable EV_HEADER_ITEM_IMP
			pt: WEL_POINT
			l_x_offset: INTEGER
			l_item: detachable EV_HEADER_ITEM
		do
			if pointed_divider_index = 0 then
					-- Clicking on the divider should not register as an item button click.
				l_item_imp := find_item_at_position (x_pos, y_pos)
				l_x_offset := x_pos
				if l_item_imp /= Void then
					l_item := l_item_imp.attached_interface
					l_x_offset := l_x_offset - item_x_offset (l_item)
					pt := client_to_screen (x_pos, y_pos)
					if l_item_imp.pointer_double_press_actions_internal /= Void then
						l_item_imp.pointer_double_press_actions.call
								([l_x_offset, y_pos, button, 0.0, 0.0, 0.0, pt.x, pt.y])
					end
				end

				if item_pointer_double_press_actions_internal /= Void then
					item_pointer_double_press_actions_internal.call (
						[l_item,
						l_x_offset,
						y_pos, button]
					)
				end
			end
		end

	on_mouse_move (keys, x_pos, y_pos: INTEGER)
			-- Executed when the mouse move.
		local
			it: detachable EV_HEADER_ITEM_IMP
			pt: WEL_POINT
		do
			it := find_item_at_position (x_pos, y_pos)
			pt := client_to_screen (x_pos, y_pos)
			if it /= Void then
				if it.pointer_motion_actions_internal /= Void then
					it.pointer_motion_actions.call ([x_pos - item_x_offset (it.attached_interface), y_pos, 0.0, 0.0, 0.0, pt.x, pt.y])
				end
			end
			if attached pnd_item_source as l_pnd_item_source then
				l_pnd_item_source.pnd_motion (x_pos, y_pos, pt.x, pt.y)
			end
			Precursor {EV_PRIMITIVE_IMP} (keys, x_pos, y_pos)
		end

	on_erase_background (paint_dc: WEL_PAINT_DC; invalid_rect: WEL_RECT)
			-- <Precursor>
		local
			bk_brush: detachable WEL_BRUSH
			i, nb: INTEGER
			l_x: INTEGER
		do
			if Application_imp.themes_active then
					-- It seems that the theme is handling the redraw on the WM_PAINT message
					-- properly.
				disable_default_processing
				set_message_return_value (to_lresult (1))
			else
					-- To avoid a flickering that occurs when resizing the top level window
					-- and refreshing the content at the same time, we only erase the part
					-- at the right of the last column if any.
				create bk_brush.make_solid (wel_background_color)
				nb := count
				if nb > 0 then
						-- Compute the `x' coordinates at the right of the last column.
					from
						i := 1
						l_x := x_position
					until
						i > nb
					loop
						if attached i_th (i) as l_item then
							l_x := l_x + l_item.width
						end
						i := i + 1
					end
				end
					-- We shrink the invalidation rect as it seems the border is drawn on the WM_PAINT
					-- message by the control.
				invalid_rect.set_left (l_x + 1)
				invalid_rect.set_top (invalid_rect.top + 1)
				invalid_rect.set_bottom (invalid_rect.bottom - 2)
				paint_dc.fill_rect (invalid_rect, bk_brush)
				bk_brush.delete
					--| Disable the default windows processing and return correct
					--| value to Windows, i.e. nonzero value.
				disable_default_processing
				set_message_return_value (to_lresult (1))
			end
		end

	on_set_cursor (hit_code: INTEGER)
			-- Called when a `Wm_setcursor' message is received.
			-- See class WEL_HT_CONSTANTS for valid `hit_code' values.
		local
			l_pointed_divider_index: INTEGER
		do
			l_pointed_divider_index := pointed_divider_index
			if l_pointed_divider_index > 1 and then not (ev_children @ l_pointed_divider_index).user_can_resize then
				disable_default_processing
			end
		end

note
	copyright: "Copyright (c) 1984-2018, 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