Old 02-12-2017, 04:04 PM   #1
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default API: Getting coordinates with multiple monitors

I'm having trouble getting a window to open at the mouse cursor when the user has two monitors; it always opens on the main screen, regardless of which one the mouse is on.

My current code looks roughly like:
Code:
x, y, w, h = Window dimensions and offset from the cursor

Get the screen size:
__, __, scr_w, scr_h = reaper.my_getViewport(x, y, x + w, y + h, x, y, x + w, y + h, 1)

Get the mouse position:
ax, ay = reaper.GetMousePosition()

Center the window to the mouse:
x, y = ax + x - (w / 2), ay + y - (h / 2)

Make sure every edge of the window would be on-screen:
l, t, r, b = x, y, x + w, y + h
	
if l < 0 then x = 0 end
if r > scr_w then x = (scr_w - w - 16) end
if t < 0 then y = 0 end
if b > scr_h then y = (scr_h - h - 40) end

return x, y
I suspect the issue lies with reaper.my_getViewport - since there's zero documentation for it, the values I'm using are complete guesses that have happened to work up until this point.

Any insight would be appreciated.

(Note that I'm handling the "make sure we're completely on-screen" adjustments myself because reaper.EnsureNotCompletelyOffscreen() is suffering from a lack of documentation AND a lack of parameters to be given)
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate

Last edited by Lokasenna; 02-12-2017 at 04:13 PM.
Lokasenna is offline   Reply With Quote
Old 12-30-2019, 05:30 AM   #2
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

Any news about this?

On Win 8.1, when setting wantWorkArea to "true", the window's toolbar size is subtracted from return values.

Code:
reaper.my_getViewport(numberr.left, numberr.top, numberr.right, numberr.bot, number sr.left, number sr.top, number sr.right, number sr.bot, boolean wantWorkArea)
Code:
local left, top, right, bottom = reaper.my_getViewport(0, 0, 0, 0, 0, 0, 0, 0, true)

And this related function...
Code:
Lua: gfx.dock(v[,wx,wy,ww,wh])

Call with v=-1 to query docked state, otherwise v>=0 to set docked state. State is &1 if docked, second byte is docker index (or last docker index if undocked). If wx-wh specified, additional values will be returned with the undocked window position/size
... what does gfx.dock(-1,0,0,0,0) return on multi-monitor setup? Is wy flipped on macOS?
spk77 is offline   Reply With Quote
Old 12-30-2019, 08:27 AM   #3
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

Quote:
Originally Posted by spk77 View Post
And this related function...
Code:
Lua: gfx.dock(v[,wx,wy,ww,wh])

Call with v=-1 to query docked state, otherwise v>=0 to set docked state. State is &1 if docked, second byte is docker index (or last docker index if undocked). If wx-wh specified, additional values will be returned with the undocked window position/size
... what does gfx.dock(-1,0,0,0,0) return on multi-monitor setup? Is wy flipped on macOS?
So, it seems that gfx.dock really returns y-position relative to the bottom-left corner of screen on macOS...This is really confusing:

(see the green text "Window_top" in the gif)
https://forum.cockos.com/showpost.ph...&postcount=221
spk77 is offline   Reply With Quote
Old 12-30-2019, 09:13 AM   #4
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
Default

About the flipped coordinates on Mac, this may be helpful?
https://forum.cockos.com/showpost.ph...&postcount=289
nofish is offline   Reply With Quote
Old 12-30-2019, 01:39 PM   #5
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

Quote:
Originally Posted by nofish View Post
About the flipped coordinates on Mac, this may be helpful?
https://forum.cockos.com/showpost.ph...&postcount=289
Thanks!
This is still a bit unclear:
On macOS, does gfx.dock(-1,0,0,0,0) return the y-position as "the bottom edge of a script window"?

Do I need to do something like this:
Code:
  local left, top, right, bottom = reaper.my_getViewport(0, 0, 0, 0, 0, 0, 0, 0, true)
  local dock, window_left, window_top, window_w, window_h = gfx.dock(-1,0,0,0,0)
  if OS == "OSX32" or OS == "OSX64" then
    window_top = bottom-window_h-window_top
  end

Here's a script for testing it. I would be very happy if someone could test it on macOS
Code:
local reaper = reaper
local abs = math.abs
local OS = reaper.GetOS()


local GUI = {}
GUI.dock = 0
GUI.win_x, GUI.win_y, GUI.win_w, GUI.win_h = 0, 0, 0, 0

GUI.drag = false

-- window moving is triggered when lmb is down and cursor is moved by this many pixels:
GUI.drag_start_offset = 40


local script = {title = "Get window and mouse positions"}

local mouse = {
                cap = 0,
                last_cap = 0,
                x = -1,
                y = -1,
                last_x = -1,
                last_y = -1,
                x_screen = -1,
                y_screen = -1,
                last_x_screen = -1,
                last_y_screen = -1,
                
                ctrl = false,
                shift = false,
                alt = false,
                
                lmb_down = false,
                lmb_down_time = 0,  
                rmb_down = false,
                rmb_down_time = 0,
                lmb_up_time = 0,
                rmb_up_time = 0,
                wheel = 0,
                
                ox = -1,
                oy = -1,
                ox_screen = -1,
                oy_screen = -1     
              }


-----------------------------------------------------------------------
------------------------------------------------------------
function on_lmb_down()
  if mouse.last_cap&1 == 0 then
    local curr_time = os.clock()
    mouse.lmb_down_time = curr_time
    mouse.ox, mouse.oy = mouse.x, mouse.y -- click position on script window
    mouse.ox_screen, mouse.oy_screen = mouse.x_screen, mouse.y_screen -- click position on screen
    _, GUI.win_x, GUI.win_y, GUI.win_w, GUI.win_h = gfx.dock(-1,0,0,0,0)
  elseif mouse.moved and (mouse.x_screen ~= mouse.ox_screen or mouse.y_screen ~= mouse.oy_screen) then

    if not GUI.drag and(abs(mouse.x_screen - mouse.ox_screen) > GUI.drag_start_offset or
                        abs(mouse.y_screen - mouse.oy_screen) > GUI.drag_start_offset) then
      GUI.drag = true
      -- update mouse click positions (to prevent the window from jumping by "GUI.drag_start_offset" pixels)
      mouse.ox_screen = mouse.x_screen
      mouse.oy_screen = mouse.y_screen
    end
    if GUI.drag then
      if gfx.dock(-1)&1 == 1 then
        gfx.dock(0) -- ...undock it
        -- move the undocked window to mouse position (centered to mouse cursor)
        GUI.win_x, GUI.win_y = mouse.x_screen-0.5*GUI.win_w, mouse.y_screen-0.5*GUI.win_h
        gfx.init("", GUI.win_w, GUI.win_h, 0, GUI.win_x, GUI.win_y) -- move window to new position
      elseif gfx.dock(-1)&1 == 0 then
        -- calculate new window position
        local new_x = GUI.win_x-mouse.ox_screen+mouse.x_screen
        local new_y = GUI.win_y-mouse.oy_screen+mouse.y_screen
        gfx.init("", GUI.win_w, GUI.win_h, 0, new_x, new_y) -- move window to new position
        -- move_window(mouse.x_screen, mouse.y_screen) -- needs JS reascript API
      end
    end
  end
end

-----------------------------------------------------------------------
function on_lmb_up()
  mouse.lmb_up_time = os.clock()
  if GUI.drag then
    GUI.drag = false
  end
end

-----------------------------------------------------------------------
function get_mod_keys()
  mouse.ctrl = mouse.cap&4==4
  mouse.shift = mouse.cap&8==8
  mouse.alt = mouse.cap&16==16
end

-----------------------------------------------------------------------
function get_mouse_btn_states()
  get_mod_keys()
  --     left btn down   right btn down  middle btn down
  return mouse.cap&1==1, mouse.cap&2==2, mouse.cap&64==64
end

------------------------------------------------------------
function get_mouse_state()
  mouse.x, mouse.y = gfx.mouse_x, gfx.mouse_y
  mouse.wheel = gfx.mouse_wheel
  mouse.x_screen, mouse.y_screen = reaper.GetMousePosition()
  mouse.moved = mouse.x_screen ~= mouse.last_x_screen or mouse.y_screen ~= mouse.last_y_screen
  mouse.cap = gfx.mouse_cap
  mouse.lmb_down, mouse.rmb_down = get_mouse_btn_states()
  if mouse.lmb_down then
    on_lmb_down()
  elseif mouse.last_cap&1 == 1 then
    on_lmb_up()
  end
end

-----------------------------------------------------------------------
function get_all_script_window_handles()
  --if gfx.dock(-1)&1 == 0 then
    local hWnd_array = reaper.new_array({}, 20)
    local num_script_windows = reaper.JS_Window_ArrayFind(script.title, true, hWnd_array)
    local handles = hWnd_array.table()
  --end
  return handles
end

------------------------------------------------------------
function init()
  gfx.init(script.title, 800, 600)
  --GUI.x, GUI.y, GUI.w, GUI.h = 0, 0, gfx.w, gfx.h

  gfx.set(1,1,1,1)
  gfx.setfont(1, "Arial", 20)
end

------------------------------------------------------------
function main()
  get_mouse_state() -- update mouse table
  gfx.x = 10
  gfx.y = 10
  gfx.set(1,1,1,1)
  for k,v in pairs(mouse) do
    if gfx.mouse_cap&1 == 1 then
      if k == "x" or k == "y" or k == "ox" or k == "oy"
                  or k == "ox_screen" or k == "oy_screen"
                  or k == "x_screen" or k == "y_screen" or k == "oy_screen"
                  or k == "lmb_down_time" or k == "rmb_down_time" or k == "oy_screen"
                  then gfx.set(0,1,1,1)

      elseif mouse[tostring(k)] == false then
        gfx.set(1,0,0,1)
      else 
        gfx.set(0,1,0,1)
      end
    end
    gfx.drawstr("mouse." .. tostring(k) .. " = " .. tostring(v))
    gfx.x = 10
    gfx.y = gfx.y+gfx.texth
  end
  gfx.x = 350
  gfx.y = 10
  gfx.set(1,1,1,1)
  for k,v in pairs(GUI) do
    if gfx.mouse_cap&1 == 1 and k == "drag" then
      if GUI.drag then 
        gfx.set(0,1,0,1)
      else
        gfx.set(1,0,0,1)
      end
    else
      gfx.set(1,1,1,1)
    end
    gfx.drawstr("GUI." .. tostring(k) .. " = " .. tostring(v))
    gfx.x = 350
    gfx.y = gfx.y+gfx.texth
  end
  local left, top, right, bottom = reaper.my_getViewport(0, 0, 0, 0, 0, 0, 0, 0, true)
  local dock, window_left, window_top, window_w, window_h = gfx.dock(-1,0,0,0,0)
  if OS == "OSX32" or OS == "OSX64" then
    window_top = bottom-window_h-window_top
  end
  gfx.set(0,1,0,1)
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  gfx.drawstr("dock: " .. tostring(dock))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  gfx.drawstr("window_left: " .. tostring(window_left))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  gfx.drawstr("window_top: " .. tostring(window_top))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  gfx.drawstr("window_w: " .. tostring(window_w))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  gfx.drawstr("window_h: " .. tostring(window_h))
  
  gfx.set(0,1,1,1)
  gfx.x = 350
  gfx.y = gfx.y+2*gfx.texth
  
  gfx.drawstr("reaper.my_getViewport left: " .. tostring(left))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  gfx.drawstr("reaper.my_getViewport top: " .. tostring(top))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  gfx.drawstr("reaper.my_getViewport right: " .. tostring(right))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  gfx.drawstr("reaper.my_getViewport bottom: " .. tostring(bottom))
  
  gfx.set(0,1,1,1)
  gfx.x = 350
  gfx.y = gfx.y+2*gfx.texth
  local is_at_right = window_left + window_w >= right
  if not is_at_right then
    gfx.set(1,0,0,1)
  else 
    gfx.set(0,1,0,1)
  end
  gfx.drawstr("Right edge >= screen right: " .. tostring(is_at_right))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  local is_at_top = window_top <= top
  if not is_at_top then
    gfx.set(1,0,0,1)
  else 
    gfx.set(0,1,0,1)
  end
  gfx.drawstr("Top edge <= screen top: " .. tostring(is_at_top))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  local is_at_left = window_left <= left
  if not is_at_left then
    gfx.set(1,0,0,1)
  else 
    gfx.set(0,1,0,1)
  end
  gfx.drawstr("Left edge <= screen left: " .. tostring(is_at_left))
  gfx.x = 350
  gfx.y = gfx.y+gfx.texth
  --gfx.drawstr("Bottom edge >= screen left: " .. tostring(window_top + window_h >= bottom))

  mouse.last_cap = mouse.cap
  mouse.last_x = mouse.x
  mouse.last_y = mouse.y
  mouse.last_x_screen = mouse.x_screen
  mouse.last_y_screen = mouse.y_screen
  if char~=-1 then reaper.defer(main) end
  gfx.update()
end

init()
main()

There's a red text - "Top edge <= screen top: false" that should turn green when the script window is at the top of the screen, like this:
spk77 is offline   Reply With Quote
Old 12-30-2019, 05:49 PM   #6
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
Default

I can't make ""Top edge <= screen top: false" turn green here, if that helps.

nofish is offline   Reply With Quote
Old 12-31-2019, 02:00 AM   #7
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

@nofish
Thanks for testing it! I see that the code is working correctly ("window_top" gets lower values when moving the window upwards)

So, it isn't possible to drag script windows past the bottom edge of reaper's titlebar on macOS?
That's why "Top edge <= screen top" is never true...

I'm using the same code for "drag'n'drop docking" -feature in Track Tags and I really like it, but I don't know if I'll ever get it working on macOS:
  1. drag from the title bar: window can be positioned freely
  2. drag from the client area: certain positions "trigger" gfx.dock -function when lmb is released
spk77 is offline   Reply With Quote
Old 12-31-2019, 09:49 AM   #8
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,096
Default

Quote:
Originally Posted by spk77 View Post
So, it isn't possible to drag script windows past the bottom edge of reaper's titlebar on macOS?
Admittedly that screencap was done on a virtual machine I'm firing up rather rarely (mostly for development purposes) so I'm not that familiar with macOS either, but apparently no, not possible to to drag script windows past the bottom edge of Reaper's titlebar. As can be seen in the gif, it's a bit different on Mac, the application's title bar sort of becomes the 'system' title bar and attaches to top even when an application isn't fully maximised.
nofish is offline   Reply With Quote
Old 12-31-2019, 09:57 AM   #9
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

Quote:
Originally Posted by nofish View Post
Admittedly that screencap was done on a virtual machine I'm firing up rather rarely (mostly for development purposes) so I'm not that familiar with macOS either, but apparently no, not possible to to drag script windows past the bottom edge of Reaper's titlebar. As can be seen in the gif, it's a bit different on Mac, the application's title bar sort of becomes the 'system' title bar and attaches to top even when an application isn't fully maximised.
Thanks!
I guess it would be better to use reaper's client area edges as "trigger" points for the docking feature in Track Tags. Getting client area should be possible with Js_ReaScriptAPI extension.
spk77 is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 11:54 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.