note
	description: "EiffelVision drawing area. Mswindows implementation."
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date: "$Date$"
	revision: "$Revision$"

class
	EV_DRAWING_AREA_IMP

inherit
	EV_DRAWING_AREA_I
		redefine
			interface
		end

	EV_DRAWABLE_IMP
		redefine
			make, interface, destroy, get_dc, release_dc
		end

	EV_PRIMITIVE_IMP
		undefine
			set_background_color,
			set_foreground_color,
			background_color_internal,
			foreground_color_internal
		redefine
			interface, make, on_left_button_down,
			on_middle_button_down, on_right_button_down,
			destroy
		end

	EV_WEL_CONTROL_WINDOW
		undefine
			on_sys_key_down,
			wel_set_font,
			wel_font,
			on_getdlgcode,
			on_wm_dropfiles
		redefine
			on_erase_background,
			class_background,
			default_style,
			class_style
		end

	WEL_CS_CONSTANTS
		export
			{NONE} all
		end

create
	make

feature {NONE} -- Initialization

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

	make
			-- Initialize `Current'.
			-- Set up action sequence connections
			-- and `Precursor' initialization.
		do
			wel_make (default_parent, "Drawing area")

			Precursor {EV_PRIMITIVE_IMP}

			create screen_dc.make (Current)
			internal_paint_dc := screen_dc
			internal_paint_dc.get

			Precursor {EV_DRAWABLE_IMP}

			disable_tabable_from
		end

feature -- Access

	dc: WEL_DC
			-- The device context of the control.
		do
			check internal_paint_dc /= Void then end
			Result := internal_paint_dc
		end

feature {NONE} -- Implementation

	in_paint: BOOLEAN
			-- Are we inside an onPaint event?

	release_dc
			-- Release the dc if not already released
		do
			if not in_paint then
				check internal_paint_dc /= Void then end
				if internal_paint_dc.exists then
					internal_paint_dc.release
				end

				internal_initialized_font := False
				internal_initialized_text_color := False
			end
		end

	get_dc
			-- Get the dc if not already get.
		do
			if not in_paint then
				check internal_paint_dc /= Void then end
				if not internal_paint_dc.exists then
					internal_paint_dc.get
					internal_paint_dc.set_background_transparent
					if attached internal_pen as l_internal_pen then
						internal_paint_dc.select_pen (l_internal_pen)
					else
						internal_paint_dc.select_pen (empty_pen)
					end

					if attached internal_brush as l_internal_brush then
						internal_paint_dc.select_brush (l_internal_brush)
					else
						internal_paint_dc.select_brush (empty_brush)
					end
					if valid_rop2_constant (wel_drawing_mode) then
						internal_paint_dc.set_rop2 (wel_drawing_mode)
					end
				end
			end
		end

	to_be_cleared: BOOLEAN
			-- Should the area be cleared?

	class_background: WEL_BRUSH
			-- Set the class background to NULL in order
			-- to have full control on the WM_ERASEBKG event
			-- (on_erase_background)
		once
			create Result.make_by_pointer (Default_pointer)
		end

	on_erase_background (paint_dc: WEL_PAINT_DC; invalid_rect: WEL_RECT)
			-- Process Wm_erasebkgnd message.
		do
			if to_be_cleared then
				to_be_cleared := False
				paint_dc.fill_rect(invalid_rect, our_background_brush)
			end

				-- Disable the default windows processing.
			disable_default_processing

				-- return a correct value to Windows, i.e. nonzero value
				-- to tell windows no to erase the background.
			set_message_return_value (to_lresult (1))
		end

	on_paint (paint_dc: WEL_PAINT_DC; invalid_rect: WEL_RECT)
			-- Wm_paint message.
			-- May be redefined to paint something on
			-- the `paint_dc'. `invalid_rect' defines
			-- the invalid rectangle of the client area that
			-- needs to be repainted.
		do
				-- Call registered onPaint actions
			if expose_actions_internal /= Void then
					-- Switch the dc from screen_dc to paint_dc.
				internal_paint_dc := paint_dc
				in_paint := True

					-- Initialise the device for painting.
				dc.set_background_transparent
				internal_initialized_pen := False
				internal_initialized_background_brush := False
				internal_initialized_brush := False
				internal_initialized_text_color := False

				expose_actions_internal.call ([
					invalid_rect.x,
					invalid_rect.y,
					invalid_rect.width,
					invalid_rect.height
					])

					-- Switch back the dc from paint_dc to screen_dc.
				check screen_dc /= Void then end
				internal_paint_dc := screen_dc
				in_paint := False

					-- Without disabling it looks like we will not be getting all
					-- the WM_PAINT messages we expected to receive (leaving some
					-- unrefresh part on the drawing area).
				disable_default_processing
			end
		end

	on_left_button_down (keys, x_pos, y_pos: INTEGER)
			-- Executed when the left button is pressed.
			-- Redefined as the button press does not set the
			-- focus automatically.
		do
			mouse_button_down
			Precursor {EV_PRIMITIVE_IMP} (keys, x_pos, y_pos)
		end

	on_middle_button_down (keys, x_pos, y_pos: INTEGER)
			-- Executed when the left button is pressed.
			-- Redefined as the button press does not set the
			-- focus automatically.
		do
			mouse_button_down
			Precursor {EV_PRIMITIVE_IMP} (keys, x_pos, y_pos)
		end

	on_right_button_down (keys, x_pos, y_pos: INTEGER)
			-- Executed when the left button is pressed.
			-- Redefined as the button press does not set the
			-- focus automatically.
		do
			mouse_button_down
			Precursor {EV_PRIMITIVE_IMP} (keys, x_pos, y_pos)
		end

	mouse_button_down
			-- Default handling for when a mouse button is pressed.
		do
			if not focus_on_press_disabled then
				set_focus
			end
		end

	clear_and_redraw_rectangle (x1, y1, a_width, a_height: INTEGER)
			-- Redraw the rectangle at (`x1',`y1') with width `a_width' and
			-- height `a_height'.
		do
				-- Set the rectangle to be cleared.
			to_be_cleared := True

				-- Ask windows to redraw the rectangle
				-- Windows will then call on_background_erase and
				-- then on_paint.
			wel_rect.set_rect (x1, y1, x1 + a_width, y1 + a_height)
			invalidate_rect (wel_rect, True)
		end

	clear_and_redraw
			-- Redraw the application screen
		do
				-- Set the rectangle to be cleared.
			to_be_cleared := True

				-- Ask windows to redraw the rectangle
				-- Windows will then call on_background_erase and
				-- then on_paint.
			invalidate
		end

	redraw_rectangle (x1, y1, a_width, a_height: INTEGER)
			-- Redraw the rectangle at (`x1',`y1') with width
			-- `a_width' and height and `a_height'.
		do
				-- Ask windows to redraw the rectangle
				-- Windows will then call on_paint.
			wel_rect.set_rect (x1, y1, x1 + a_width, y1 + a_height)
			invalidate_rect(wel_rect, False)
		end

	redraw
			-- Redraw the application screen
		do
				-- Ask windows to redraw the entire window
				-- Windows will call on_erase_background (which
				-- will do nothing since to_be_cleared = False)
				-- and then on_paint.
			invalidate
		end

	flush
			-- Update immediately the screen if needed.
		do
			update
		end

	default_style: INTEGER
			-- Default style that memories the drawings.
		do
			Result := Ws_child + Ws_visible + Ws_clipchildren + Ws_clipsiblings
		end

	class_style: INTEGER
   			-- Standard style used to create the window class.
   			-- Can be redefined to return a user-defined style.
   		once
			Result := cs_dblclks | cs_owndc
 		end

feature -- Commands.

	destroy
			-- Destroy `Current', but set the parent sensitive
			-- in case it was set insensitive by the child.
		do
			Precursor {EV_DRAWABLE_IMP}
			Precursor {EV_PRIMITIVE_IMP}
		end

feature {EV_ANY, EV_ANY_I} -- Implementation

	interface: detachable EV_DRAWING_AREA note option: stable attribute end

feature {EV_DRAWABLE_IMP} -- Internal datas.

	internal_paint_dc: detachable WEL_DC note option: stable attribute end
			-- dc we use when painting

	screen_dc: detachable WEL_CLIENT_DC note option: stable attribute end;
			-- dc we use when painting outside a WM_PAINT message

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