Script to Standalone app

  • Hey there!

    I'm attempting to make a standalone app with a drawbot script using py2app and drawBot as a module. I'm having a lot of trouble with the Variable menu, the error I'm having so far is raise DrawBotError("There is no document open") when the script gets to Variable(menuElements, globals()) I'm speculating about how to solve it, Do I need to assign a document to the class or something like that?

  • admin

    Some parts of drawBots api don't work automatically outside the application, mainly parts where an UI is involved.

    But first why building an app?

    I would recommend UI parts to build separately. Build a window with vanilla, add some sliders and callback whenever that slider will change.

    DrawBot has a drawBot package, so drawBot code can be shared without looking a complex script folder structure:

  • @frederik sweet, I’ll give the package a try, I thought about using the app because it needs to be an executable and avoid the run part of the workflow.

  • Is there a way to execute the Run command using shell or applescript?

  • admin

    If drawBot is installed as a module you can access it anywhere!

    If Variable(..) is a key thing in your script, use a drawBot package, where you can set a main script that gets executed when the file is opened in

  • @frederik thanks!!! I just got curious about it. I'm having a problem with the package, it doesn't open the script when I open it in DrawBot, this is the tree I have

    ├── info.plist
    └── lib
        ├── resources
        │   └── fonts
        │       ├── VF.ttf
        │       └── Logo.otf

    When I open main by itself it runs

  • admin

    this should work!


    You can open the debugger in drawBot by hitten alt with the help menu open.

  • Debugger shows the problem now:

    Traceback (most recent call last):
      File "", line 45, in <module>
      File "drawBot/drawBotDrawingTools.pyc", line 2548, in Variable
    drawBot.misc.DrawBotError: There is no document open

    It works if I run does it need to open a window first and then run Variable? 🤔

  • @eduairet I tried this and now opens the script and it's not giving me errors but it still doesn't run entirely:

    openWindows = Quartz.CGWindowListCopyWindowInfo(
        Quartz.kCGWindowListOptionOnScreenOnly | Quartz.kCGWindowListExcludeDesktopElements, Quartz.kCGNullWindowID
    openWindows = [window.get('kCGWindowName', u'Unknown').encode('ascii','ignore') for window in openWindows if window['kCGWindowOwnerName'] == 'DrawBot']
    if b'' not in openWindows:
        os.system(f'open -a DrawBot {__file__}')

  • admin

    that is way to complex 🙂

    Variable works fine with the UI of drawBot... dont use it outside a drawBot document 😉

    You will have more control when you build it with vanilla and use this in a drawBot packages.

    import vanilla
    class MyController:
        def __init__(self):
            self.w = vanilla.Window((150, 40), "My Tool Name")
            self.w.slider = vanilla.Slider((10, 10, -10, 22), callback=self.sliderCallback)
        def sliderCallback(self, sender):        
            x = sender.get()
            fill(random(), random(), random())
            oval(x, 0, 1000, 1000)

    this script wrapped in a .drawBot package

  • Thanks Frederik 🙂 you've helped me a lot!!!

  • Hi @eduairet I stumpled upon your thread as I am currently working on something similar. I need to share some code for someone else to work with and the package seems to be a perfect fit.

    I just have a problem that my font is not loaded from the resource directory. Everytime I set text it uses standard fallback font.
    Looking at your tree file I see that you use a varFont as well located within resource. Is there a trick to get it working?

    Would be a bummer if the user needs to input a path to the font file. 😕

  • admin

    If you use a path in font(filePath) then the path is relative to the current directory (which is not always the the directory of the python file)

    DrawBot the app set the current directory to the .py file directory. When used as module this does not happen.

    So either set the a correct current directory or get a absolute path from the .py file: os.path.join(os.path.basename(__file__), "font.otf")

  • The hint with __file__ was just what I needed and got me on the right track.
    Using os.path.join(os.path.dirname(__file__), 'resource', 'font.otf') within the now gives me the ability to pull content from the resource directory. Perfect!

    Thank you so much @frederik, as always 🙂