class EL_WINDOW_DRAG

(source code)

description

Allows any EV_WIDGET to be used as handle to drag a window to a new position

note
	description: "Allows any ${EV_WIDGET} to be used as handle to drag a window to a new position"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2024-01-20 19:18:25 GMT (Saturday 20th January 2024)"
	revision: "14"

class
	EL_WINDOW_DRAG

inherit
	ANY

	EL_MODULE_ACTION; EL_MODULE_SCREEN

	EL_SHARED_DEFAULT_PIXMAPS

create
	make

feature {NONE} -- Initialization

	make (a_window: EV_WINDOW; a_title_bar: EV_WIDGET)
		do
			window := a_window; title_bar := a_title_bar

			title_bar.pointer_button_press_actions.extend (agent on_pointer_button_press)
			title_bar.pointer_motion_actions.extend (agent on_pointer_motion)
			title_bar.pointer_button_release_actions.extend (agent on_pointer_button_release)
			title_bar.pointer_leave_actions.extend (agent on_pointer_leave)
		end

feature -- Status query

	is_active: BOOLEAN

feature -- Event handling

	on_pointer_button_press (
		x_pos, y_pos, button: INTEGER; x_tilt, y_tilt, pressure: DOUBLE; a_screen_x, a_screen_y: INTEGER
	)
		do
			if button = 1 and not is_active then
				is_active := True
				old_x := window.screen_x; old_y := window.screen_y
				anchor_x := a_screen_x; anchor_y := a_screen_y
				anchor_y := title_bar.screen_y + title_bar.height // 5
				Screen.set_pointer_position (anchor_x, anchor_y)

				title_bar.set_pointer_style (Pixmaps.Hyperlink_cursor)
			end
		end

	on_pointer_button_release (
		x_pos, y_pos, button: INTEGER; x_tilt, y_tilt, pressure: DOUBLE; a_screen_x, a_screen_y: INTEGER
	)
		do
			if button = 1 and is_active  then
				is_active := False
				title_bar.set_pointer_style (Pixmaps.Standard_cursor)
			end
		end

	on_pointer_leave
		local
			i: INTEGER
		do
			if is_active then
				from i := 1 until i > 3 loop
					Action.do_later (i * 100, agent move_window_to_pointer)
					i := i + 1
				end
			end
		end

	on_pointer_motion (a_x, a_y: INTEGER; a_x_tilt, a_y_tilt, a_pressure: DOUBLE; a_screen_x, a_screen_y: INTEGER)
		do
			if is_active then
				window.set_position (old_x + (a_screen_x - anchor_x), old_y + (a_screen_y - anchor_y))
			end
		end

feature {NONE} -- Implementation

	move_window_to_pointer
		do
			if attached Screen.pointer_position as p then
				on_pointer_motion (0, 0, 0, 0, 0, p.x, p.y)
			end
		end

feature {NONE} -- Internal attributes

	anchor_x: INTEGER

	anchor_y: INTEGER

	old_x: INTEGER

	old_y: INTEGER

	title_bar: EV_WIDGET

	window: EV_WINDOW

end