Old 05-26-2023, 05:05 AM   #1
AudioBabble
Human being with feelings
 
AudioBabble's Avatar
 
Join Date: Dec 2021
Posts: 313
Default Packaging a python script as extension?

Is it possible to make an extension from a python script so that it would work for all users, regardless of if they have python installed?
AudioBabble is offline   Reply With Quote
Old 05-26-2023, 06:14 AM   #2
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 12,842
Default

When you make it an extension, you'd have to compile the code for each OS. I'm not sure whether it will work for ReaScript, but you can compile Python code, for example using this tool: https://cython.org/

Maybe it would be easier to rewrite the script to Lua instead?
__________________
DonateSoundCloudAll the REAPER names
vitalker is offline   Reply With Quote
Old 05-26-2023, 06:32 AM   #3
AudioBabble
Human being with feelings
 
AudioBabble's Avatar
 
Join Date: Dec 2021
Posts: 313
Default

Quote:
Originally Posted by vitalker View Post
When you make it an extension, you'd have to compile the code for each OS. I'm not sure whether it will work for ReaScript, but you can compile Python code, for example using this tool: https://cython.org/

Maybe it would be easier to rewrite the script to Lua instead?
I see... unfortunately what I'm doing involves gui data like mouse position and defining co-ordinates on a plugin window that I'm pretty sure is beyond what lua can do.

I guess I'll go down the compilation route, although at first will probably be a "windows" only script... much as I would like to be inclusive.
AudioBabble is offline   Reply With Quote
Old 05-26-2023, 06:46 AM   #4
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 3,556
Default

99.9% sure it can do that, and if you give us little sneak peak maybe we can help
Sexan is offline   Reply With Quote
Old 05-26-2023, 07:00 AM   #5
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 12,842
Default

Quote:
Originally Posted by Sexan View Post
99.9% sure it can do that, and if you give us little sneak peak maybe we can help
Yep, there is a native GFX + a couple of custom GUI libraries.
__________________
DonateSoundCloudAll the REAPER names
vitalker is offline   Reply With Quote
Old 05-26-2023, 07:52 AM   #6
AudioBabble
Human being with feelings
 
AudioBabble's Avatar
 
Join Date: Dec 2021
Posts: 313
Default

Thanks... I will post back with a sneak peak once I have it in some semblance of order -- at the moment, it's a bunch of snippets which I need to tie together into one script!
AudioBabble is offline   Reply With Quote
Old 05-26-2023, 10:15 AM   #7
AudioBabble
Human being with feelings
 
AudioBabble's Avatar
 
Join Date: Dec 2021
Posts: 313
Default

OK... here's a bit of it in python 3:

Code:
import wx
import tkinter as tk
from tkinter import *
from tkinter import ttk

def callback():
    global selectionOffset, selectionSize

    selectionOffset = ""
    selectionSize = ""

    class SelectableFrame(wx.Frame):

        c1 = None
        c2 = None

        def __init__(self, parent=None, id=wx.ID_ANY, title=""):
            wx.Frame.__init__(self, parent, id, title, size=(800,400))
            self.menubar = wx.MenuBar(wx.MB_DOCKABLE)
            self.filem = wx.Menu()
            self.filem.Append(wx.ID_EXIT, '&Transparency')
            self.menubar.Append(self.filem, '&File')
            self.SetMenuBar(self.menubar)
            self.Bind(wx.EVT_MOTION, self.OnMouseMove)
            self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
            self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
            self.Bind(wx.EVT_PAINT, self.OnPaint)
            self.Bind(wx.EVT_MENU, self.OnTrans)

            self.SetCursor(wx.Cursor(wx.CURSOR_CROSS))
            self.Show()
            self.transp = False
            wx.CallLater(250, self.OnTrans, None)

        def OnTrans(self, event):
            if self.transp == False:
                self.SetTransparent(180)
                self.transp = True
            else:
                self.SetTransparent(255)
                self.transp = False

        def OnMouseMove(self, event):
            if event.Dragging() and event.LeftIsDown():
                self.c2 = event.GetPosition()
                self.Refresh()

        def OnMouseDown(self, event):
            self.c1 = event.GetPosition()

        def OnMouseUp(self, event):
            self.SetCursor(wx.Cursor(wx.CURSOR_ARROW))
            self.Destroy()

        def OnPaint(self, event):
            global selectionOffset, selectionSize, top_left, bottom_right
            if self.c1 is None or self.c2 is None: return

            dc = wx.PaintDC(self)
            dc.SetPen(wx.Pen('red', 1))
            dc.SetBrush(wx.Brush(wx.Colour(0, 0, 0), wx.TRANSPARENT))

            dc.DrawRectangle(self.c1.x, self.c1.y, self.c2.x - self.c1.x, self.c2.y - self.c1.y)
            selectionOffset = str(self.c1.x) + "x" + str(self.c1.y)
            selectionSize = str(abs(self.c2.x - self.c1.x)) + "x" + str(abs(self.c2.y - self.c1.y))
            top_left = (self.c1.x, self.c1.y)
            bottom_right = (self.c2.x - self.c1.x, self.c2.y - self.c1.y)
        def PrintPosition(self, pos):
            return str(pos.x) + "x" + str(pos.y)


    class MyApp(wx.App):

        def OnInit(self):
            frame = SelectableFrame()

            return True


    app = MyApp(redirect=False)

    app.MainLoop()
    print(f"SELECTION:\n ^[    ]  Top Left (x, y):\t {top_left} \n\t^ Bottom Right (x, y):\t {bottom_right}")

# root window
root = tk.Tk()
root.geometry('300x200')
root.resizable(False, False)
root.title('Preset Sleuth')

# capture button
exit_button = ttk.Button(
    root,
    text='Draw Capture Area',
    command=callback
)

exit_button.pack(
    ipadx=5,
    ipady=5,
    expand=True
)

root.mainloop()
I'm sure it's a bit clunky to use wxPython for one window and tkinter for another, but I'm very much new to programming and still very reliant on other people's code snippets.

Basically, this bit allows the user to draw a rectangle and the program then spits out the top-left and bottom-right co-ords.

Would be interested to know about if GFX or any custom GUI libs can do this.. I was probably too quick to assume it wasn't possible!
AudioBabble is offline   Reply With Quote
Old 05-26-2023, 10:46 AM   #8
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 3,556
Default

Yes JS_API can do that, from my Area51 script which utilizes drawing over reaper with it:





Could you post a gif what it does so I can help you get started with small lua script?

Last edited by Sexan; 05-26-2023 at 10:52 AM.
Sexan is offline   Reply With Quote
Old 05-26-2023, 12:34 PM   #9
AudioBabble
Human being with feelings
 
AudioBabble's Avatar
 
Join Date: Dec 2021
Posts: 313
Default

very rough mock-up:


you can guess what I'm trying to do -- the idea is to define an area of the plugin window that contains the plugin name. Those co-ords can then be fed to a freeware program called capture2text which does a pretty nifty job of capturing, doing OCR then putting the scanned text value into memory buffer to be pasted elsewhere. I can do this programmatically in python provided the user has Capture2text running in the background... to do the actual capture and OCR in Python is very much possible but seemed like re-inventing the wheel.

Needing the translucent overlay window to get the drawn rectangle is possibly superfluous, but as a novice programmer, it was my best shot at achieving the aim.
AudioBabble is offline   Reply With Quote
Old 05-26-2023, 01:52 PM   #10
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 12,842
Default

Here is a script that taking a screenshot of a whole GUI:
https://forum.cockos.com/showpost.ph...79&postcount=2

Perhaps it's possible to make it work as your script.
__________________
DonateSoundCloudAll the REAPER names
vitalker is offline   Reply With Quote
Old 05-26-2023, 01:56 PM   #11
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 3,556
Default



If that little ocr program supports command line you can then do everything from the script

It looks bit scary because I've just copy pasted Mouse module script in it (you can use it as separate script and just call it with require) but the Main() is whole code for drawing etc.

98% of the code is just copy paste of this, but you dont need to worry about that at all its just handling mouse stuff for you:
https://github.com/GoranKovac/ReaScr...a_51_mouse.lua

Hope this will get you where you want
Attached Files
File Type: lua A_Draw.lua (4.7 KB, 4 views)
Sexan is offline   Reply With Quote
Old 05-26-2023, 03:04 PM   #12
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 3,556
Default

Here is alternative version with ImGui:



Assign it to some shortcut key, hold down that key and drag away. Once you release it the script will stop

Only downside with this one is that Option "Ignore FX CHAIN keyboard shorcut..." needs to be checked (this is because the key-hold voodoo but we can remove that and make it normal script)

Code:
local r = reaper

START_TIME = reaper.time_precise()
CUR_PREF = reaper.SNM_GetIntConfigVar("alwaysallowkb", 1)

local key_state = reaper.JS_VKeys_GetState(START_TIME - 2)
for i = 1, 255 do
    if key_state:byte(i) ~= 0 then
        reaper.JS_VKeys_Intercept(i, 1);
        KEY = i
    end
end
if not KEY then return end

local function Key_held() return r.JS_VKeys_GetState(START_TIME - 2):byte(KEY) == 1 end

local function Release()
    if not KEY then return end
    r.JS_VKeys_Intercept(KEY, -1)
    r.SNM_SetIntConfigVar("alwaysallowkb", CUR_PREF)
end

local ctx = r.ImGui_CreateContext("GUI DRAW")
local DL =  r.ImGui_GetWindowDrawList( ctx )

local start_x, start_y = r.ImGui_PointConvertNative(ctx, r.GetMousePosition())

function Main()
  if not Key_held() then return end
  
  local x,y = r.ImGui_PointConvertNative(ctx, r.GetMousePosition())
  r.ImGui_SetNextWindowPos( ctx, start_x - 200 , start_y - 200 )    
  r.ImGui_SetNextWindowSize(ctx, 1000, 1000)
  if reaper.ImGui_Begin(ctx, 'ALPHA', false, r.ImGui_WindowFlags_NoBackground() | r.ImGui_WindowFlags_NoDecoration() | r.ImGui_WindowFlags_AlwaysAutoResize() | r.ImGui_WindowFlags_NoMove()) then
     r.ImGui_SetNextWindowPos( ctx, start_x - 500 , start_y )  
     r.ImGui_SetNextWindowSizeConstraints( ctx, 200, 50, 200, 50 )
     
     if reaper.ImGui_Begin(ctx, 'START', false) then
        reaper.ImGui_Text(ctx, "START DRAGING WITH MOUSE")
        r.ImGui_End(ctx)
     end
     
     if r.ImGui_IsMouseDown(ctx, 0) then
        if not SX then
          SX, SY = x, y
        end
        r.ImGui_DrawList_AddRectFilled( DL, SX, SY, x, y, 0x2222AA55 )
     end
     
     if r.ImGui_IsMouseReleased(ctx, 0) then
        r.ShowConsoleMsg(("X : %d , Y : %d, XE : %d, YE : %d"):format(SX, SY, x, y) .. '\n')
     end
     
     r.ImGui_End(ctx)
  end
  
  r.defer(function() xpcall(Main, Release) end)
end
  
r.atexit(Release)
r.defer(Main)
Needs ReaImgui for drawing and JS_API for intercepting shortcut key
Sexan is offline   Reply With Quote
Old 05-26-2023, 06:05 PM   #13
AudioBabble
Human being with feelings
 
AudioBabble's Avatar
 
Join Date: Dec 2021
Posts: 313
Default

Thank you both, brilliant stuff. Keen to check out these methods.
Yes, the Capture2Text has a CLI version, although it's windows only.

Long-run, if I get something working the way I hope, I could always look into doing the OCR in lua as well -- tesseract looks like a good bet? https://tesseract.wiki/w/Tesseract:L...rary_functions
AudioBabble 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:28 PM.


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