initial release
This commit is contained in:
410
cosmic rage/lua/movewindow.lua
Normal file
410
cosmic rage/lua/movewindow.lua
Normal file
@@ -0,0 +1,410 @@
|
||||
-- movewindow.lua
|
||||
|
||||
--[[
|
||||
|
||||
Miniwindow drag-to-move functions.
|
||||
|
||||
Author: Nick Gammon
|
||||
Date: 15th July 2009
|
||||
Modified: 16th November 2010 to add preprocessing
|
||||
Modified: 29th November 2010 by Fiendish to improve dragging offscreen
|
||||
Modified: 8th February 2018 by Nick to remember the flags setting (eg. absolute position)
|
||||
|
||||
This module is intended to make it easier to add drag handlers for miniwindows.
|
||||
|
||||
It implements the following:
|
||||
|
||||
-- find previous location
|
||||
nocheck: if true, don't check if offscreen (boolean)
|
||||
friends: other windows to move with this one (table)
|
||||
preprocess: preprocessing for mousedown, mouseup etc. (table)
|
||||
|
||||
Handler names for preprocess table:
|
||||
|
||||
mousedown
|
||||
mouseup
|
||||
mouseover
|
||||
cancelmouseover
|
||||
cancelmousedown
|
||||
dragmove
|
||||
dragrelease
|
||||
|
||||
If any preprocess handler returns true (that is, neither nil nor false) then the default handler
|
||||
in this module is not used. (The miniwindow name is the third argument)
|
||||
|
||||
function mousedown (flags, id, win)
|
||||
if bit.band (flags, miniwin.hotspot_got_rh_mouse) then
|
||||
-- do something different here
|
||||
return true
|
||||
end -- if
|
||||
|
||||
return false -- take normal movewindow behaviour
|
||||
end -- mousedown
|
||||
|
||||
windowinfo = movewindow.install (win, default_position, default_flags, nocheck, friends, preprocess)
|
||||
|
||||
movewindow.add_drag_handler (win, left, top, right, bottom, cursor) -- add a drag handler for the nominated rectangle
|
||||
|
||||
movewindow.save_state (win) -- saves the miniwindow location to the appropriate variables
|
||||
|
||||
It also installs a position-checker that moves the miniwindow into view after 5 seconds, in case
|
||||
you resize the main world window, and the window is no longer visible. The 5 seconds are to give
|
||||
the main world window's position and size time to stabilize. (Unless nocheck is true)
|
||||
|
||||
|
||||
Example of use:
|
||||
|
||||
require "movewindow" -- pull in this module
|
||||
|
||||
|
||||
-- CREATE WINDOW in OnPluginInstall
|
||||
|
||||
win = GetPluginID () -- miniwindow ID
|
||||
|
||||
windowinfo = movewindow.install (win, miniwin.pos_center_right, 0) -- default position / flags
|
||||
|
||||
-- make miniwindow (use locations returned from last time we saved the state)
|
||||
-- note that the width and height are not part of the window position info, and can thus change as required
|
||||
|
||||
WindowCreate (win,
|
||||
windowinfo.window_left,
|
||||
windowinfo.window_top,
|
||||
WINDOW_WIDTH,
|
||||
WINDOW_HEIGHT,
|
||||
windowinfo.window_mode,
|
||||
windowinfo.window_flags,
|
||||
ColourNameToRGB "slategray")
|
||||
|
||||
|
||||
|
||||
-- INSTALL DRAG HANDLER when required (eg. when drawing stuff to window)
|
||||
-- in this case we use 0,0,0,0 as the rectangle (ie. the whole window)
|
||||
-- typically the height would be the size of the title bar
|
||||
|
||||
movewindow.add_drag_handler (win, 0, 0, 0, 0, miniwin.cursor_both_arrow)
|
||||
|
||||
-- SAVE STATE in OnPluginSaveState
|
||||
|
||||
movewindow.save_state (win)
|
||||
|
||||
|
||||
The module makes one global variable (table) when installed. This is named:
|
||||
|
||||
mw_<window_id>_movewindow_info
|
||||
|
||||
|
||||
This contains handler functions (the table is an upvalue to the functions)
|
||||
|
||||
"check_map_position"=function: 023D9368 -- the position checker
|
||||
"dragmove"=function: 01AD1158 -- the dragmove handler
|
||||
"dragrelease"=function: 023E4238 -- the dragrelease handler
|
||||
"margin"=20 -- margin for dragging offscreen
|
||||
"mousedown"=function: 01AD1108 -- the mousedown handler
|
||||
"origx"=648 -- used during dragging
|
||||
"origy"=39
|
||||
"startx"=88
|
||||
"starty"=8
|
||||
"win"="23c3c91af0a26790c625f5d1" -- the supplied window ID
|
||||
"window_flags"=2 -- flags (eg. 2, absolute position)
|
||||
"window_left"=652 -- current left location
|
||||
"window_mode"=0 -- window mode
|
||||
"window_top"=31 -- current top location
|
||||
|
||||
|
||||
This table is returned from movewindow.install so you can find where to put the
|
||||
window the first time it is created.
|
||||
|
||||
--]]
|
||||
|
||||
movewindow = {} -- table to hold functions like movewindow.install
|
||||
|
||||
-- make a mouse-down handler with the movement information as an upvalue
|
||||
|
||||
local function make_mousedown_handler (mwi)
|
||||
|
||||
return function (flags, hotspot_id)
|
||||
|
||||
local win = mwi.win
|
||||
|
||||
-- see if other action wanted
|
||||
if mwi.preprocess.mousedown then
|
||||
if mwi.preprocess.mousedown (flags, hotspot_id, win) then
|
||||
return
|
||||
end -- if handled already
|
||||
end -- if handler
|
||||
|
||||
-- find where mouse is so we can adjust window relative to mouse
|
||||
mwi.startx = WindowInfo (win, 14)
|
||||
mwi.starty = WindowInfo (win, 15)
|
||||
|
||||
-- find where window is in case we drag it offscreen
|
||||
mwi.origx = WindowInfo (win, 10)
|
||||
mwi.origy = WindowInfo (win, 11)
|
||||
|
||||
-- find where the friends are relative to the window
|
||||
for i, v in ipairs (mwi.window_friends) do
|
||||
if v then
|
||||
mwi.window_friend_deltas [i] =
|
||||
{
|
||||
WindowInfo (v, 10) - mwi.origx,
|
||||
WindowInfo (v, 11) - mwi.origy
|
||||
}
|
||||
end -- if
|
||||
end -- for
|
||||
|
||||
end -- mousedown
|
||||
|
||||
end -- make_mousedown_handler
|
||||
|
||||
-- make a mouse drag-move handler with the movement information as an upvalue
|
||||
|
||||
local function make_dragmove_handler (mwi)
|
||||
|
||||
return function (flags, hotspot_id)
|
||||
|
||||
local win = mwi.win
|
||||
|
||||
-- see if other action wanted
|
||||
if mwi.preprocess.dragmove then
|
||||
if mwi.preprocess.dragmove (flags, hotspot_id, win) then
|
||||
return
|
||||
end -- if handled already
|
||||
end -- if handler
|
||||
|
||||
-- find where it is now
|
||||
local posx, posy = WindowInfo (win, 17) - mwi.startx,
|
||||
WindowInfo (win, 18) - mwi.starty
|
||||
|
||||
-- change the mouse cursor shape appropriately
|
||||
if posx < 0 or
|
||||
posx > GetInfo (281) - mwi.margin or
|
||||
posy < 0 or -- don't drag title out of view
|
||||
posy > GetInfo (280) - mwi.margin then
|
||||
SetCursor (miniwin.cursor_x) -- X cursor
|
||||
else
|
||||
SetCursor (miniwin.cursor_hand) -- hand cursor
|
||||
end -- if
|
||||
|
||||
if posx < 0 then
|
||||
posx = 0
|
||||
elseif posx > GetInfo (281) - mwi.margin then
|
||||
posx = GetInfo(281) - mwi.margin
|
||||
end
|
||||
if posy < 0 then
|
||||
posy = 0
|
||||
elseif posy > GetInfo(280) - mwi.margin then
|
||||
posy = GetInfo(280) - mwi.margin
|
||||
end
|
||||
|
||||
-- move the window to the new location - offset by how far mouse was into window
|
||||
WindowPosition(win, posx, posy, 0, miniwin.create_absolute_location);
|
||||
|
||||
-- move the friends if they still exist
|
||||
for i, v in ipairs(mwi.window_friends) do
|
||||
if v then
|
||||
WindowPosition (v, posx + mwi.window_friend_deltas [i] [1],
|
||||
posy + mwi.window_friend_deltas [i] [2],
|
||||
0,
|
||||
WindowInfo (v, 8))
|
||||
end -- if
|
||||
end -- for
|
||||
|
||||
mwi.window_left = posx -- remember for saving state
|
||||
mwi.window_top = posy
|
||||
mwi.window_mode = 0
|
||||
mwi.window_flags = miniwin.create_absolute_location -- absolute position
|
||||
|
||||
end -- dragmove
|
||||
|
||||
end -- make_dragmove_handler
|
||||
|
||||
-- make a mouse drag-release handler with the movement information as an upvalue
|
||||
|
||||
local function make_dragrelease_handler (mwi)
|
||||
|
||||
return function (flags, hotspot_id)
|
||||
|
||||
local win = mwi.win
|
||||
|
||||
-- see if other action wanted
|
||||
if mwi.preprocess.dragrelease then
|
||||
if mwi.preprocess.dragrelease (flags, hotspot_id, win) then
|
||||
return
|
||||
end -- if handled already
|
||||
end -- if handler
|
||||
|
||||
Repaint () -- update window location
|
||||
|
||||
end -- dragrelease
|
||||
|
||||
end -- make_dragrelease_handler
|
||||
|
||||
-- make other handler with the movement information as an upvalue
|
||||
|
||||
local function make_other_handler (mwi, name)
|
||||
|
||||
return function (flags, hotspot_id)
|
||||
|
||||
-- send to supplied handler
|
||||
if mwi.preprocess [name] then
|
||||
mwi.preprocess [name] (flags, hotspot_id, mwi.win)
|
||||
end -- if handler
|
||||
|
||||
end -- other
|
||||
|
||||
end -- make_other_handler
|
||||
|
||||
-- make a mouse position-checking function with the movement information as an upvalue
|
||||
|
||||
local function make_check_map_position_handler (mwi)
|
||||
|
||||
return function ()
|
||||
|
||||
local win = mwi.win
|
||||
|
||||
if not WindowInfo (win, 1) then
|
||||
ColourNote ("white", "red", "Error in make_check_map_position_handler: no window named: " .. win)
|
||||
return
|
||||
end -- no such window
|
||||
|
||||
-- check miniwindow visible
|
||||
if mwi.window_left < 0 or
|
||||
mwi.window_left > GetInfo (281) - mwi.margin or
|
||||
mwi.window_top < 0 or -- don't drag title out of view
|
||||
mwi.window_top > GetInfo (280) - mwi.margin then
|
||||
mwi.window_mode = miniwin.pos_center_right
|
||||
mwi.window_flags = 0
|
||||
end -- if not visible
|
||||
|
||||
WindowPosition (win,
|
||||
mwi.window_left,
|
||||
mwi.window_top,
|
||||
mwi.window_mode,
|
||||
mwi.window_flags)
|
||||
|
||||
end -- check_map_position
|
||||
|
||||
end -- make_check_map_position_handler
|
||||
|
||||
-- call movewindow.install in OnPluginInstall to find the position of the window, before creating it
|
||||
-- - it also creates the handler functions ready for use later
|
||||
|
||||
function movewindow.install (win, default_position, default_flags, nocheck, friends, preprocess, start_position)
|
||||
|
||||
win = win or GetPluginID () -- default to current plugin ID
|
||||
|
||||
assert (not string.match (win, "[^A-Za-z0-9_]"), "Invalid window name in movewindow.install: " .. win)
|
||||
|
||||
default_position = default_position or miniwin.pos_center_right -- on right, center top/bottom
|
||||
default_flags = default_flags or 0
|
||||
|
||||
-- set up handlers and where window should be shown (from saved state, if any)
|
||||
local movewindow_info = {
|
||||
win = win, -- save window ID
|
||||
|
||||
-- save current position in table (obtained from state file)
|
||||
window_left = tonumber (GetVariable ("mw_" .. win .. "_windowx")) or (start_position and start_position.x) or 0,
|
||||
window_top = tonumber (GetVariable ("mw_" .. win .. "_windowy")) or (start_position and start_position.y) or 0,
|
||||
window_mode = default_position,
|
||||
window_flags = tonumber (GetVariable ("mw_" .. win .. "_windowflags")) or default_flags,
|
||||
window_friends = friends or {},
|
||||
window_friend_deltas = {},
|
||||
margin = 20, -- how close we can put to the edge of the window
|
||||
preprocess = preprocess or {},
|
||||
}
|
||||
|
||||
-- check valid
|
||||
for k, v in pairs (movewindow_info.preprocess) do
|
||||
assert (type (v) == "function", "Handler '" .. k .. "' is not a function")
|
||||
end -- for
|
||||
|
||||
-- handler to reposition window
|
||||
movewindow_info.check_map_position = make_check_map_position_handler (movewindow_info) -- for startup
|
||||
|
||||
-- mouse handlers
|
||||
movewindow_info.mousedown = make_mousedown_handler (movewindow_info)
|
||||
movewindow_info.mouseup = make_other_handler (movewindow_info, "mouseup")
|
||||
movewindow_info.mouseover = make_other_handler (movewindow_info, "mouseover")
|
||||
movewindow_info.cancelmouseover = make_other_handler (movewindow_info, "cancelmouseover")
|
||||
movewindow_info.cancelmousedown = make_other_handler (movewindow_info, "cancelmousedown")
|
||||
movewindow_info.dragmove = make_dragmove_handler (movewindow_info)
|
||||
movewindow_info.dragrelease = make_dragrelease_handler (movewindow_info)
|
||||
|
||||
-- save table in global namespace
|
||||
_G ["mw_" .. win .. "_movewindow_info"] = movewindow_info
|
||||
|
||||
|
||||
-- give main world window time to stabilize its size and position
|
||||
-- eg. this might be: mw_23c3c91af0a26790c625f5d1_movewindow_info.check_map_position ()
|
||||
|
||||
if not nocheck then -- if wanted
|
||||
DoAfterSpecial (5, "mw_" .. win .. "_movewindow_info.check_map_position ()" , sendto.script)
|
||||
end -- if
|
||||
|
||||
return movewindow_info -- the caller might appreciate access to this table
|
||||
end -- movewindow.install
|
||||
|
||||
-- call movewindow.add_drag_handler after creating the window, and after deleting hotspots where applicable
|
||||
-- to add a drag hotspot
|
||||
|
||||
function movewindow.add_drag_handler (win, left, top, right, bottom, cursor)
|
||||
|
||||
win = win or GetPluginID () -- default to current plugin ID
|
||||
|
||||
-- the zz puts it under other hotspots on the drag area
|
||||
local hotspot_id = "zz_mw_" .. win .. "_movewindow_hotspot"
|
||||
|
||||
if not WindowInfo (win, 1) then
|
||||
ColourNote ("white", "red", "Error in movewindow.add_drag_handler: no window named: " .. win)
|
||||
return
|
||||
end -- no such window
|
||||
|
||||
-- make a hotspot
|
||||
WindowAddHotspot(win, hotspot_id,
|
||||
left or 0, top or 0, right or 0, bottom or 0, -- rectangle
|
||||
"mw_" .. win .. "_movewindow_info.mouseover", -- MouseOver
|
||||
"mw_" .. win .. "_movewindow_info.cancelmouseover", -- CancelMouseOver
|
||||
"mw_" .. win .. "_movewindow_info.mousedown", -- MouseDown
|
||||
"mw_" .. win .. "_movewindow_info.cancelmousedown", -- CancelMouseDown
|
||||
"mw_" .. win .. "_movewindow_info.mouseup", -- MouseUp
|
||||
"Drag to move window", -- tooltip text
|
||||
cursor or miniwin.cursor_hand, -- cursor
|
||||
0) -- flags
|
||||
|
||||
WindowDragHandler (win, hotspot_id,
|
||||
"mw_" .. win .. "_movewindow_info.dragmove",
|
||||
"mw_" .. win .. "_movewindow_info.dragrelease",
|
||||
0) -- flags
|
||||
|
||||
end -- movewindow.add_drag_handler
|
||||
|
||||
-- call movewindow.save_state in OnPluginSaveState
|
||||
|
||||
function movewindow.save_state (win)
|
||||
|
||||
win = win or GetPluginID () -- default to current plugin ID
|
||||
|
||||
-- get movewindow variable from global namespace
|
||||
local mwi = _G ["mw_" .. win .. "_movewindow_info"]
|
||||
|
||||
if not mwi then
|
||||
ColourNote ("white", "red", "Error in movewindow.save_state: no window movement info for: " .. win)
|
||||
return
|
||||
end -- no such window
|
||||
|
||||
-- remember where the window was
|
||||
|
||||
-- use actual last specified position, not where we happen to think it is, in case another plugin moves it
|
||||
-- suggested by Fiendish, 27 August 2012.
|
||||
if WindowInfo (win, 1) then
|
||||
mwi.window_left = WindowInfo(win, 1)
|
||||
end
|
||||
if WindowInfo (win, 2) then
|
||||
mwi.window_top = WindowInfo(win, 2)
|
||||
end
|
||||
|
||||
SetVariable ("mw_" .. win .. "_windowx", mwi.window_left)
|
||||
SetVariable ("mw_" .. win .. "_windowy", mwi.window_top)
|
||||
SetVariable ("mw_" .. win .. "_windowflags", mwi.window_flags)
|
||||
|
||||
end -- movewindow.save_state
|
||||
Reference in New Issue
Block a user