note
	description: "This class represents a MS_IMPmulti-line text editor without scrollbar"
	legal: "See notice at end of class.";
	status: "See notice at end of class.";
	date: "$Date$";
	revision: "$Revision$"

class
	TEXT_IMP

inherit
	PRIMITIVE_IMP
		redefine
			set_foreground_color,
			set_background_color,
			on_right_button_down,
			on_right_button_up,
			realize,
			unrealize
		end

	TEXT_I

	WEL_RICH_EDIT
		rename
			make as wel_make,
			move as wel_move,
			item as wel_item,
			show as wel_show,
			hide as wel_hide,
			destroy as wel_destroy,
			x as wel_x,
			y as wel_y,
			width as wel_width,
			height as wel_height,
			set_x as wel_set_x,
			set_y as wel_set_y,
			set_width as wel_set_width,
			set_height as wel_set_height,
			shown as wel_shown,
			set_focus as wel_set_focus,
			set_capture as wel_set_capture, 
			release_capture as wel_release_capture,
			parent as wel_parent,
			text as wel_text,
			count as wel_count,
			foreground_color as wel_foreground_color,
			background_color as wel_background_color,
			set_background_color as wel_set_background_color,
			text_length as wel_text_length,
			set_text as wel_set_text,
			clear as wel_clear,
			set_selection as wel_set_selection,
			font as wel_font,
			set_font as wel_set_font,
			clear_selection as wel_clear_selection,
			set_read_only as wel_set_read_only,
			set_read_write as wel_set_read_write,
			style as wel_style
		undefine
			on_show,
			on_hide,
			on_size,
			on_move,
			on_right_button_up,
			on_left_button_down,
			on_left_button_up,
			on_right_button_down,
			on_mouse_move,
			on_destroy,
			on_set_cursor,
			on_key_up,
			on_key_down,
			background_brush
		redefine
			default_style,
			on_en_change,
			on_char,
			hide_selection,
			show_selection
		end

	SIZEABLE_WINDOWS

create
	make,make_word_wrapped

feature -- Initialization

	make,make_word_wrapped (a_text: TEXT; man: BOOLEAN; oui_parent: COMPOSITE)
			-- Create the text_windows
		do
			create private_text.make (0)
			create private_attributes;
			init_common_controls_dll
			init_rich_edit_dll
			a_text.set_font_imp (Current)
			parent ?= oui_parent.implementation
			managed := man
			is_multi_line_mode := true
		end

	init_rich_edit_dll
			-- Load the rich edit control DLL.
		local
			rich_edit_dll: WEL_RICH_EDIT_DLL
		once
			create rich_edit_dll.make
			rich_edit_dll.set_shared
		end

	realize
			-- Realize current widget
		local
			fw: FONT_IMP
			wc: WEL_COMPOSITE_WINDOW
		do
			if not realized then
				resize_for_shell
				wc ?= parent
				wel_make (wc, text, x, y, width, height, id_default)
				enable_standard_notifications

				if private_background_color /= Void then
					set_background_color (private_background_color)
				end

				if private_font /= Void then
					set_font (private_font)
				end

				if private_attributes.height = 0 then
					fw ?= font.implementation
					set_height (fw.string_height (Current, "I") * 7 // 4)
				end

				if private_attributes.width = 0 then
					set_width (200)
				end

				set_text (private_text)

				if maximum_size > 0 then
					set_maximum_size (maximum_size)
				end

				set_cursor_position (private_cursor_position)

				if margin_width + margin_height > 0 then
					set_margins (margin_width, margin_height)
				end

				if is_multi_line_mode then
					set_top_character_position (private_top_character_position)
				end

				if not managed then
					wel_hide
				elseif parent.shown then
					shown := true
				end

				if private_is_read_only then
					set_read_only
				end
			end
		end

feature -- Access

	margin_height : INTEGER
			-- Distance between top edge of text window and current text,
			-- and between bottom edge of text window and current text.

	margin_width: INTEGER
			-- Distance between left edge of text window and current text,
			-- and between right edge of text window and current text.

	maximum_size: INTEGER
			-- Maximum number of characters in current
			-- text field

	rows: INTEGER
			-- Height of Current widget measured in character heights.
		local
			f: FONT
		do
			if height /= 0 then
				if private_font /= Void then
					f := private_font
				else
					f := font
				end
				Result := height // (f.font_ascent + f.font_descent)
			end
		end

feature -- Status report

	begin_of_selection: INTEGER
			-- Position of the beginning of the current highlighted selection
		do
			if exists then
				Result := selection_start
			else
				Result := private_begin_selection
			end
		end

	end_of_selection: INTEGER
			-- Position of the end of the current selection highlightened
		do
			if exists then
				Result := selection_end
			else
				Result := private_end_selection
			end
		end

	is_selection_visible: BOOLEAN
			-- Is the selection visible?

	hide_selection
		do
			Precursor {WEL_RICH_EDIT}
			is_selection_visible := False
		end

	show_selection
		do
			Precursor {WEL_RICH_EDIT}
			is_selection_visible := True
		end

	count: INTEGER
			-- Number of characters in current text area
		do
			if exists then
				Result := wel_count
			else
				Result := private_text.count
			end
		end

	cursor_position: INTEGER
			-- Current position of the text cursor (it indicates the position
			-- where the next character pressed by the user will be inserted)
		do
			if exists then
				Result := caret_position
			else
				Result := private_cursor_position
			end
		end

	is_any_resizable: BOOLEAN
			-- Is width and height of current text resizable?
		do
			Result := is_height_resizable and is_width_resizable
		end

	is_height_resizable: BOOLEAN
			-- Is height of current text resizable?
		do
			Result := private_is_height_resizable
		end

	is_in_a_verification_callback: BOOLEAN
			-- Is the program in a `motion' or `modify' action ?
		do
		end

	is_bell_enabled: BOOLEAN
			-- Is the bell enabled when an action is forbidden
		do
		end

	is_read_only: BOOLEAN
			-- Is current text in read only mode?
		do
			Result := private_is_read_only
		end

	is_selection_active: BOOLEAN
			-- Is there a selection currently active ?
		do
			Result := has_selection
		end

	is_width_resizable: BOOLEAN
			-- Is width of current text resizable?
		do
			Result := private_is_width_resizable
		end

	is_word_wrap_mode: BOOLEAN
			-- Is specified that lines are to be broken at word breaks?
		do
			Result := private_is_word_wrap_mode
		end

	text: STRING
			-- Value of current text field
		do
			if exists then
				Result := wel_text
			else
				Result := private_text
			end
		end

	coordinate (char_pos: INTEGER): COORD_XY
			-- Coordinate relative to the upper left corner
			-- of Current text widget at character position `char_pos'.
		local
			win_point: WEL_POINT
		do
			win_point := position_from_character_index (char_pos)
			create Result
			Result.set (win_point.x, win_point.y)
		end

	x_coordinate (char_pos: INTEGER): INTEGER
			-- X coordinate relative to upper left corner
			-- of current text widget at character position `char_pos'
		do
			if exists then
				Result := position_from_character_index (char_pos).x
			end
		end

	y_coordinate (char_pos: INTEGER): INTEGER
			-- Y coordinate relative to upper left corner
			-- of current text widget at character position `char_pos'
		do
			if exists then
				Result := position_from_character_index (char_pos).y
			end
		end

	character_position (cx, cy : INTEGER) : INTEGER
			-- character position at position `cx' and `cy'.
		do
			if exists then
				Result := character_index_from_position (cx, cy)
			end
		end

	top_character_position: INTEGER
			-- Character position of first character displayed
		do
			if exists then
				Result := line_index (first_visible_line)
			end
		end

	is_multi_line_mode: BOOLEAN
			-- Is Current editing a multiline text?

	is_cursor_position_visible: BOOLEAN
			-- Is the insert cursor position marked
			-- by a blinking text cursor?
		do
		end

feature -- Status setting

	set_foreground_color (c: COLOR)
			-- Set the foreground color of current widget.
		local
			char_format: WEL_CHARACTER_FORMAT
			windows_color: WEL_COLOR_REF
			text_count: INTEGER
		do
			private_foreground_color := c
			if exists then
				if has_selection then
					unselect
				end
				windows_color ?= c.implementation
				create char_format.make
				char_format.set_text_color (windows_color)
				text_count := text.count
				if text_count > 1 then
					set_selection (0, text_count - 1)
					set_character_format_selection (char_format)
					unselect
					set_cursor_position (text_count)
					set_character_format_selection (char_format)
				else
					set_character_format_selection (char_format)
				end
			end
		end

	set_background_color (a_color: COLOR)
			-- Set the background color to `a_color'
			-- We may need a call to UpdateWindow
		local
			win_color: WEL_COLOR_REF
		do
			private_background_color := a_color
			if exists then
				win_color ?= a_color.implementation
				wel_set_background_color (win_color)
			end
		end

	unrealize
			-- Unrealize current widget
		do
			update_private_text (text)
			wel_destroy
		end

	set_margins (a_width, a_height: INTEGER)
			-- Set margins for text.
		do
		end

	allow_action
			-- Allow the cursor to move or the text to be modified
			-- during a `motion' or a `modify' action.
		do
		end

	clear
			-- Clear current text field.
		do
			set_text ("")
		end

	clear_selection
			-- Clear a selection
		do
			private_begin_selection := 0
			private_end_selection := 0
			if exists then
				unselect
			end
		end

	disable_resize
			-- Disable that current text widget attempts to resize its width and
			-- height to accommodate all the text contained.
		do
			private_is_width_resizable := False
			private_is_height_resizable := False
		end

	disable_resize_height
			-- Disable that current text widget attempts to resize its height
			-- to accommodate all the text contained.
		do
			private_is_height_resizable := False
		end

	disable_resize_width
			-- Disable that current text widget attempts to resize its width
			-- to accommodate all the text contained.
		do
			private_is_width_resizable := False
		end

	disable_verify_bell
			-- Disable the bell when an action is forbidden
		do
		end

	enable_resize
			-- Enable that current text widget attempts to resize its width and
			-- height to accommodate all the text contained.
		do
			private_is_width_resizable := True
			private_is_height_resizable := True
		end

	enable_resize_height
			-- Enable that current text widget attempts to resize its height to
			-- accommodate all the text contained.
		do
			private_is_height_resizable := True
		end

	enable_resize_width
			-- Enable that current text widget attempts to resize its width to
			-- accommodate all the text contained.
		do
			private_is_width_resizable := True
		end

	enable_verify_bell
			-- Enable the bell when an action is forbidden
		do
		end

	forbid_action
			-- Forbid the cursor to move or the text to be modified
			-- during a `motion' or a `modify' action.
		do
			if can_undo then	
				undo
			end
		end

	set_cursor_position (pos: INTEGER)
			-- Set cursor_position to pos.
		do
			private_cursor_position := pos
			if exists then
				if not has_selection then
					set_selection (pos, pos)
					move_to_selection
				else
					set_caret_position (pos)
				end
			end
		end

	set_editable
			-- Set the text in editable mode
		do
			if exists then
				wel_set_read_write
			end
			private_is_read_only := False
		end

	set_margin_height (new_height: INTEGER)
			-- Set `margin_height' to `new_height'.
		do
			if exists then
				set_margins (margin_width, new_height)
			end
			margin_height := new_height
		end

	set_margin_width (new_width: INTEGER)
			-- Set `margin_width' to `new_width'.
		do
			if exists then
				set_margins (new_width, margin_height)
			end
			margin_width := new_width
		end

	set_maximum_size (a_max: INTEGER)
			-- Set maximum_size to `a_max'.
		do
			maximum_size := a_max
			if exists then
				set_text_limit (a_max)
			end
		end

	set_read_only
			-- Set the text in read_only mode
		do
			if exists then
				wel_set_read_only
			end
			private_is_read_only := True
		end

	set_selection (first, last: INTEGER)
			-- Highlight the substring between `first' and `last' positions
			-- leave the caret at `first'
		local
			size: INTEGER
			last_line_position: INTEGER
			number_line_to_scroll: INTEGER
		do
			private_begin_selection := first
			private_end_selection := last
			
			if exists then
					-- We will always begin the selection at the end to the
					-- beginning in order to make visible the beginning of
					-- the selection for the user

				wel_set_selection (last, first)

				if is_selection_visible then
						--| If we need to show the selection we will try to show
						--| it in the best way
						--| If the text can fit in the window, it will be fit by
						--| using a scrolling of the selection
						--| If the text is bigger than the window, the beginning
						--| of the text will be on the first line of the window
						--| only if the beginning of the text is not already in
						--| the first quarter of the window
					size := y_coordinate (last) - y_coordinate (first)
	
					if
						y_coordinate (first) >= height or else
						size > height and then
						y_coordinate (first) > 1 * height // 4
					then
						set_top_character_position (first)
					elseif size < height and then y_coordinate (last) > height then
						last_line_position := character_index_from_position (0, height)
						number_line_to_scroll := line_from_char(last) - line_from_char (last_line_position - 1)
						scroll (0, number_line_to_scroll.min (line_from_char (first) - first_visible_line))
					end
				end
			end
		end

	set_text (a_text: STRING)
			-- Set window text to `a_text'
		do
			update_private_text (a_text)
			if exists then
				wel_set_text (a_text)
			end
		end

	set_top_character_position (char_pos: INTEGER)
			-- Set first character displayed to `char_pos'.
		do
			private_top_character_position := char_pos
			if exists then
				scroll (0, line_from_char (char_pos) - first_visible_line)
			end
		end

	set_single_line_mode
			-- Set editing for single line text.
		do
			is_multi_line_mode := false
		end

	set_rows (i: INTEGER)
			-- Set the character height of Current widget to `i'.
		local
			f: FONT
		do
			if private_font /= Void then
				f := private_font
			else
				f := font
			end
			set_height (i * (f.font_ascent + f.font_descent))
		end

	set_cursor_position_visible (flag: BOOLEAN)
			-- Set is_cursor_position_visible to flag.
		do
		end

	set_multi_line_mode
			-- Set editing for multiline text.
		do
			is_multi_line_mode := true
		end

feature -- Element change

	add_activate_action (a_command: COMMAND; argument: ANY)
                        -- Add `a_command' to the list of action to be executed when
			-- an activate event occurs.
                        -- `argument' will be passed to `a_command' whenever it is
			-- invoked as a callback.
		do
			activate_actions.add (Current, a_command, argument)
		end

	add_modify_action (a_command: COMMAND; arg: ANY)
			-- Add `a_command' to the list of action to execute before
			-- text is deleted from or inserted in current text widget.
		do
			modify_actions.add (Current, a_command, arg)
		end

	add_motion_action (a_command: COMMAND; arg: ANY)
			-- Add `a_command' to the list of action to execute before insert
			-- cursor is moved to a new position.
		do
			motion_actions.add (Current, a_command, arg)
		end

	append (s: STRING)
                        -- Append `s' at the end of current text.
		do
			if exists then
				if has_selection then
					unselect
				end
				set_caret_position (text.count)
				replace_selection (s)
			else
				text.append (s)
			end
		end

	insert (s: STRING; a_position: INTEGER)
                        -- Insert `s' in current text field at `a_position'.
                        -- Same as `replace (a_position, a_position, s)'.
		do
			if exists then
				if has_selection then
					unselect
				end
				set_caret_position (a_position)
				replace_selection (s)
			else
				if a_position = text.count then
					text.append (s)
				else
					text.insert_string (s, a_position + 1)
				end
			end
		end

	replace (from_position, to_position: INTEGER; s: STRING)
                        -- Replace text from `from_position' to `to_position' by `s'.
		do
			if exists then
				if has_selection then
					unselect
				end
				if from_position = to_position then
					set_caret_position (from_position)
					replace_selection (s)
				else
					set_selection (from_position, to_position)
					replace_selection (s)
				end
			else
				if from_position = to_position then
					text.insert_string (s, from_position + 1)
				else
					text.replace_substring (s, from_position + 1, to_position)
				end
			end
		end

feature -- Removal

	remove_activate_action (a_command: COMMAND; argument: ANY)
                        -- Remove `a_command' from the list of action to execute when the
			-- an activate event occurs.
		do
			activate_actions.remove (Current, a_command, argument)
		end

	remove_modify_action (a_command: COMMAND; arg : ANY)
			-- Remove `a_command' from the list of action to execute before
			-- text is deleted from or inserted in current text widget.
		do
			modify_actions.remove (Current, a_command, arg)
		end

	remove_motion_action (a_command: COMMAND; arg : ANY)
			-- Remove `a_command' from the list of action to execute before
			-- insert cursor is moved to a new position.
		do
			motion_actions.remove (Current, a_command, arg)
		end

feature {NONE} -- Notifications

	on_en_change
		do
			modify_actions.execute (Current, Void)
		end

	on_char (virtual_key, key_data: INTEGER)
			-- Wm_char message
		local
			kw: KEYBOARD_WINDOWS
			kpd: KYPRESS_DATA
		do
			create kw.make_from_key_state
			create kpd.make (owner, virtual_key, virtual_keys @ virtual_key, kw) 
			if virtual_key = vk_return or virtual_key = vk_tab then
				activate_actions.execute (Current, kpd)
			end
		end

	on_right_button_down (keys, a_x, a_y: INTEGER)
			-- Wm_rbuttondown message
			-- See class WEL_MK_CONSTANTS for `keys' value
		do
			Precursor {PRIMITIVE_IMP} (keys, a_x, a_y)
			disable_default_processing
		end

	on_right_button_up (keys, a_x, a_y: INTEGER)
			-- Wm_rbuttonup message
			-- See class WEL_MK_CONSTANTS for `keys' value
		do
			Precursor {PRIMITIVE_IMP} (keys, a_x, a_y)
			disable_default_processing
		end

feature {NONE} -- Implementation

	default_style: INTEGER
			-- Default style for window control;
		do
			Result := Precursor {WEL_RICH_EDIT} + Es_left + Es_autovscroll
			if not is_word_wrap_mode then
				Result := Result + Es_autohscroll
			end

			if not is_multi_line_mode then
				Result := Result - Ws_hscroll - Ws_vscroll - Es_multiline
			end
		end

	update_private_text (a_text: STRING)
			-- Update the private text and rebuild the
		do
			private_text := a_text
		end

	private_top_character_position: INTEGER
			-- Fist visible line containing character position.

	private_begin_selection: INTEGER
			-- Current place selection is to start

	private_cursor_position: INTEGER
			-- Current position of the text cursor (it indicates the position
			-- where the next character pressed by the user will be inserted)

	private_end_selection: INTEGER
			-- Current place selection ends

	private_is_height_resizable: BOOLEAN
			-- Is height of current text resizable?

	private_is_read_only: BOOLEAN
			-- Is current text in read only mode?

	private_is_width_resizable: BOOLEAN
			-- Is width of current text resizable?

	private_is_word_wrap_mode: BOOLEAN
			-- Is specified that lines are to be broken at word breaks?

	private_text: STRING;
			-- Value of current text field

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




end -- class TEXT_IMP