SketchUcation Plugin Store

 

 

pdScript-interpreter for GUI Scripting in SketchUp-Ruby

pdScript-interpreter for GUI Scripting in SketchUp-Ruby

Postby HPW » Sat Jan 21, 2012 6:29 pm

Hello,

Some times ago I ran across a pascal script scripting language from Precision.
Whats it makes special was the fact that it supports GUI scripting.
http://www.be-precision.com/products/pdScript/

After they build an optional engine as a DLL, its get interesting to call it from other enviroments.

Similar to my newLISP integration into Sketchup, I build a pdScript extension for Sketchup.
newLISP: viewtopic.php?f=180&t=18127&p=148708

A screenshot:
http://www.hpwsoft.de/SU_PDS.png

Windows only!

Interested who want to try it can download here:

http://www.hpwsoft.de/anmeldung/html1/s ... chup3.html

The ZIP contains 1 file at the toplevel:
pdScript_ext.rb

The rb is the extension which must be activated in the preferences.
The subfolder contains the DLL's and samples. Preserve the folder when you unpack the ZIP.
The extension adds a menu to the plugins menu with some demo.

The Win32API extension is needed from here:
viewtopic.php?f=323&t=42732#p380121

Regards

Hans-Peter
Last edited by HPW on Tue Jan 24, 2012 9:24 pm, edited 3 times in total.
HPW
 
Posts: 126
Joined: Sat Mar 28, 2009 9:19 am
Location: Germany

Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

Postby Dan Rathbun » Sat Jan 21, 2012 9:06 pm

    Here's the one stop place for Win32API.so (here at SCF.)

    [Plugin Library] Win32API and Win32OLE so files

    You need not distro any certain version, with your plugin.
    Just list a dependancy, and put the above link in any posting of a plugin.
    User avatar
    Dan Rathbun
    Top SketchUcator
     
    Posts: 4074
    Joined: Tue Oct 06, 2009 3:06 am
    Location: Florida, USA
    Name: Dan Rathbun
    Operating system: Windows
    SketchUp version: 8
    License type: Pro
    SketchUp use: education
    Level of SketchUp: Advanced

    Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

    Postby Dan Rathbun » Sat Jan 21, 2012 9:18 pm

    You should not need to create global variables if you wrap your code in a module of your own.

    Creating instance variables (@vars) at the top level (which is within Object,) is a very big no no !
    User avatar
    Dan Rathbun
    Top SketchUcator
     
    Posts: 4074
    Joined: Tue Oct 06, 2009 3:06 am
    Location: Florida, USA
    Name: Dan Rathbun
    Operating system: Windows
    SketchUp version: 8
    License type: Pro
    SketchUp use: education
    Level of SketchUp: Advanced

    Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

    Postby HPW » Sun Jan 22, 2012 9:04 am

    Hello Dan,

    Thanks for the suggestions.
    I will remove the Win32API from the zip.
    I had a look to module as you advised.
    Here my frist attempt:
    Code: Select all
    require 'sketchup.rb'
    module PdScript
      if not file_loaded?(File.basename(__FILE__))
        # UI.messagebox("pdScript loader startet")
        win32api_file = Sketchup.find_support_file "Plugins/Win32API.so", ""
        pdScriptapi_file = Sketchup.find_support_file "Plugins/pdScript/pdScriptE.dll", ""
        # UI.messagebox("pdScriptDll="+pdScriptapi_file)
        if (win32api_file)
          require 'Win32API'
          # UI.messagebox("Win32API loaded ")
          if File.exist? pdScriptapi_file
            @pdScript = Win32API.new(pdScriptapi_file, "pdScriptA", ['P','P','L'], 'I')
            @pdsFreeScript = Win32API.new(pdScriptapi_file, "pdsFreeScript", ['I'], 'I')
            @pdsExecuteFunction = Win32API.new(pdScriptapi_file, "pdsExecuteFunctionA", ['I','P','P','P'], 'I')
            @pdScriptScriptHandle = 0
            # puts "psScript_Result: "
            # puts @pdScript
            dll_file = Sketchup.find_support_file "Plugins/pdScript/RubyConnect.dll", ""
            if (dll_file)
              @FindConnectedWindow = Win32API.new(dll_file, "FindConnectedWindow", ['P','P'], 'P')
      #        UI.messagebox("FindConnectedWindow loaded")
               FindConnectedWindowSU = @FindConnectedWindow.Call("- SketchUp","")
      #        UI.messagebox("Return from FindConnectedWindow: "+FindConnectedWindowSU)
      #      else
      #        UI.messagebox("File RubyConnect.dll is missing in the pdScript-Plugins! pdScript loading fails!")
            end   # if
            # UI.messagebox("pdScript loaded")
            add_separator_to_menu("Plugins")
            $pdScriptMenuStrings = LanguageHandler.new("pdScript_menu.strings")
            pdScript_menu = UI.menu("Plugins").add_submenu($pdScriptMenuStrings.GetString("pdScript"))
            pdScript_menu.add_item($pdScriptMenuStrings.GetString("Start pdScript clock Dialog")) { PdScript.start_clock_dialog }
            pdScript_menu.add_item($pdScriptMenuStrings.GetString("Start pdScript MyDialog Dialog modal")) { PdScript.start_mydialog_dialog }
            pdScript_menu.add_item($pdScriptMenuStrings.GetString("Start pdScript MyDialog Dialog non-modal")) { PdScript.start_mydialog_nonmodal_dialog }
            pdScript_menu.add_item($pdScriptMenuStrings.GetString("Start pdScript FreeScript")) { PdScript.start_freescript }
          else
            UI.messagebox("Cannot find file pdScriptE.dll!")
          end      # if
        else
            UI.messagebox("File Win32API.so is missing in the SketchUp-Plugins-Directory! pdScript loading fails!")
        end   # if
      else
       puts "File "+File.basename(__FILE__)+" was yet loaded!"
      end   # if


      def PdScript.start_clock_dialog
        # UI.messagebox("Before clock Dialog")
        pdScriptclock_file = Sketchup.find_support_file "Plugins/pdScript/Clock.dpas", ""
        retval = @pdScript.Call(pdScriptclock_file,"",0)
        UI.messagebox("Return from Clock-Dialog: "+retval.to_s())
      end

      def PdScript.start_mydialog_dialog
        # UI.messagebox("Before clock Dialog")
        pdScriptMyDialog_file = Sketchup.find_support_file "Plugins/pdScript/MyDialog.dpas", ""
        retval = @pdScript.Call(pdScriptMyDialog_file,"/pds{hide-from-taskbar=true}",0)
        UI.messagebox("Return from Modal-Dialog: "+retval.to_s())
      end

      def PdScript.start_mydialog_nonmodal_dialog
        # UI.messagebox("Before clock Dialog")
        pdScriptMyDialog_file = Sketchup.find_support_file "Plugins/pdScript/MyDialogNon.dpas", ""
        @pdScriptScriptHandle = @pdScript.Call(pdScriptMyDialog_file,"/pds{hide-from-taskbar=true;keep-alive=true;host-app="+FindConnectedWindowSU+"}",0)
        # UI.messagebox("Return from NonModal-Dialog: "+@pdScriptScriptHandle.to_s())
      end

      def PdScript.start_freescript
        # UI.messagebox("Before clock Dialog")
        if @pdScriptScriptHandle > 0
         retval = @pdsFreeScript.Call(@pdScriptScriptHandle)
         @pdScriptScriptHandle = 0
        end
      #  UI.messagebox("Return from Freescript: "+retval.to_s())
      end

      def PdScript.ExecuteFunction(param1, param2, param3)
         # UI.messagebox("Before ExecuteFunction")
         retval = @pdsExecuteFunction.Call(@pdScriptScriptHandle, param1, param2, param3)
         UI.messagebox("Return from ExecuteFunction: "+retval.to_s())
      end

      file_loaded(File.basename(__FILE__))
     
      # Sample calls from RubyConsole to comunicate to open pdScriptdialog
      # PdScript.ExecuteFunction("ChangeEdit2","Value 2 from RubyCall","|")
      # PdScript.ExecuteFunction("ChangeEdit4","Value 4 from RubyCall","|")
      # PdScript.ExecuteFunction("ChangeEdits","Value 1 from RubyCall|Value 2 from RubyCall|Value 3 from RubyCall|Value 4 from RubyCall","|")
    end


    Seems to work.
    Is that the proper way to use a modul?
    Since my main-programming language is not ruby, it was my intention for posting here to hear from the experts, if I am doing something wrong.

    Regards

    Hans-Peter
    HPW
     
    Posts: 126
    Joined: Sat Mar 28, 2009 9:19 am
    Location: Germany

    Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

    Postby Dan Rathbun » Sun Jan 22, 2012 7:05 pm

      You are still using a global var $pdScriptMenuStrings, use a module var instead, like @@pdScriptMenuStrings, or since it will local to your module, an even simplier name, like: @@lang (see below.)

      Also:

      1. you did NOT supply the "pdScript.strings" file
      2. trying to use Google's LanguageHandler class is problematic, because it assumes that the string file is in the Resources subpath (which is difficult to install into.)
          Instead just have your own "lang" or "strings" subdir, with UTF8 encoded hash files. These files should have extensions that are equal to the user's local language code, thus:
          langcode = Sketchup.get_locale.split('-')[0]
          @@extpath = File.dirname(__FILE__)
          langdir = "lang"
          langfile = "pdScript_menu.#{langcode}"
          langpath = File.join(@@extpath,langdir,langfile)

      So you have a subdir:
      "pdScript/lang"
      that has various string files, like:
      pdScript_menu.en # English
      pdScript_menu.de # German
      pdScript_menu.fr # French
      etc. etc.
      A user can copy the english file and resave it with another langcode extension, then edit the values for their own language.
      Just be sure to test using File.exists?(langpath) and if it returns false, then use the english as a default.

      It is not really necessary to use a convoluted class like LanguageHandler, when a plain Ruby Hash works just as fine. See the "langhandler.rb" file in the "Tools" dir for the snippet that loads a strings file into a Hash. You can have the hash stored in a simple name like: @@lang and just access the values, like: @@lang["Start pdScript MyDialog Dialog modal"]

      BUT.. you must also wrap the extension registration script "pdScript_ext.rb" inside your module so that the @@lang var is local to YOUR module, and not Object (which would propagate into everyone else's classes and modules.)

      File: 'pdScript_ext.rb'
      Code: Select all
      #
      # File: 'pdScript_ext.rb'
      #
      # This extensions allows the intergration of pdScript into SketchUp
      # Additional info about pdScript at www.be-precision.com/products/pdScript/
      #-----------------------------------------------------------------------------
      require('sketchup.rb')
      require('extensions.rb')

      require('pdScript/langLoad.rb')

      module PdScript
       
        plugdir = Sketchup.find_support_file('Plugins')

        langcode = Sketchup.get_locale.split('-')[0]
        @@extdir = "pdScript"
        langdir  = "lang"
        langpath = File.join(plugdir,@@extdir,langdir,"pdScript_menu.#{langcode}")
        if not File.exists?(langpath)
          langcode = 'en'
          langpath = File.join(plugdir,@@extdir,langdir,"pdScript_menu.#{langcode}")
        end
        @@lang = parse_langfile(langpath) # create the language hash

        @@extension = SketchupExtension.new( @@lang["pdScript interpreter"], "pdScript/pdScript.rb")
        @@extension.description = @@lang["Adds pdScript interpreter to the ruby environment"]
        @@extension.name= "pdScript interpreter"
        @@extension.creator = "HPW/Precision"
        @@extension.copyright = "2012-01-22"
        @@extension.version = "1.0"

        Sketchup.register_extension( @@extension, false )

      end
      (PS: use Ruby standard date string format: YYYY-MM-DD)

      File: 'pdScript/langLoad.rb'
      Code: Select all
      #
      # Copyright 2005-2008, Google, Inc.
      #   code from "Tools/LangHandler.rb"
      #   Modified for use with PdScript module. 2012-JAN
      #   renamed to: 'pdScript/langLoad.rb'
      #
      # -----------------------------------------------------------------------------
      #
      # Permission to use, copy, modify, and distribute this software for
      # any purpose and without fee is hereby granted, provided that the above
      # copyright notice appear in all copies.
      #
      # THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
      # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
      # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
      # -----------------------------------------------------------------------------

      module PdScript

        class << self  # Proxy class bound to THIS module:

          @hash = ""
       
          #  parse_langfile( langpath )
          #
          #  Args:
          #
          #    langpath  :  a fullpath to a UTF8 encoded strings format file.
          #
          #  Returns a hash object loaded with the new strings, and english keys.
          #
          def parse_langfile(langpath)

            @hash = Hash.new {|hash,key| key }
            # for [] method, returns the arg if key does not exist in hash

            langFile = File.open(langpath, "r") { |file|

              entryString = ""
              inComment = false

              file.each do |line|
                #ignore simple comment lines - BIG assumption the whole line is a comment
                if !line.include?("//")
                  #also ignore comment blocks
                  if line.include?("/*")
                    inComment = true
                  end

                  if inComment==true
                    if line.include?("*/")
                      inComment=false
                    end
                  else
                    entryString += line
                  end
                end

                if entryString.include?(";")
                  #parse the string into key and value
                 
                  #remove the white space
                  entryString.strip!

                  #pull out the key
                  keyvalue = entryString.split("\"=\"")
                 
                  #strip the leading quotation out
                  key = keyvalue[0][(keyvalue[0].index("\"")+1)..(keyvalue[0].length+1)]

                  #pull out the value
                  keyvalue[1].gsub!(";", "")
                  value = keyvalue[1].gsub("\"", "")

                  #add to @strings
                  @hash[key]=value.chomp

                  entryString = ""
                end
              end # do each line
           
            } # end of File.open (File is closed automatically.)

            return @hash

          end # def
       
        end # proxy class

      end # module
      Last edited by Dan Rathbun on Mon Jan 23, 2012 5:28 am, edited 3 times in total.
      User avatar
      Dan Rathbun
      Top SketchUcator
       
      Posts: 4074
      Joined: Tue Oct 06, 2009 3:06 am
      Location: Florida, USA
      Name: Dan Rathbun
      Operating system: Windows
      SketchUp version: 8
      License type: Pro
      SketchUp use: education
      Level of SketchUp: Advanced

      Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

      Postby Dan Rathbun » Sun Jan 22, 2012 7:43 pm

        Changed File: 'pdScript/langLoad.rb', line 32 (and added comment.)

        Will set the hash so that 'key' will be returned, if it is not present as a key.
        User avatar
        Dan Rathbun
        Top SketchUcator
         
        Posts: 4074
        Joined: Tue Oct 06, 2009 3:06 am
        Location: Florida, USA
        Name: Dan Rathbun
        Operating system: Windows
        SketchUp version: 8
        License type: Pro
        SketchUp use: education
        Level of SketchUp: Advanced

        Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

        Postby Dan Rathbun » Sun Jan 22, 2012 7:47 pm

        Woops.. do not forget to change the version in the _ext file:

        @@extension.version = "1.0.1" or whatever....
        User avatar
        Dan Rathbun
        Top SketchUcator
         
        Posts: 4074
        Joined: Tue Oct 06, 2009 3:06 am
        Location: Florida, USA
        Name: Dan Rathbun
        Operating system: Windows
        SketchUp version: 8
        License type: Pro
        SketchUp use: education
        Level of SketchUp: Advanced

        Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

        Postby HPW » Sun Jan 22, 2012 11:51 pm

        Hello Dan,

        Thanks again for the advises and samples.
        I did what you say, but since you did not post the file format for the language file I tried to understand the source of the parse-function.

        My pdScript_menu.en is this:
        Code: Select all
        pdScript interpreter="pdScript interpreter"
        Adds pdScript interpreter to the ruby environment="Adds pdScript interpreter to the ruby environment!"
        pdScript="pdScript English"
        Start pdScript clock Dialog="Start pdScript clock Dialog English"
        Start pdScript MyDialog Dialog modal="Start pdScript MyDialog Dialog modal English"
        Start pdScript MyDialog Dialog non-modal="Start pdScript MyDialog Dialog non-modal English"
        Start pdScript FreeScript="Start pdScript FreeScript English"


        The function runs but I get always the key instead of the value.
        What did I miss?

        Regards

        Hans-Peter
        HPW
         
        Posts: 126
        Joined: Sat Mar 28, 2009 9:19 am
        Location: Germany

        Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

        Postby HPW » Mon Jan 23, 2012 12:33 am

        I think I have now the correct format but it still does not work.
        Code: Select all
        "pdScript interpreter"="pdScript interpreter";
        "Adds pdScript interpreter to the ruby environment"="Adds pdScript interpreter to the ruby environment!";
        "pdScript"="pdScript English";
        "Start pdScript clock Dialog"="Start pdScript clock Dialog English";
        "Start pdScript MyDialog Dialog modal"="Start pdScript MyDialog Dialog modal English";
        "Start pdScript MyDialog Dialog non-modal"="Start pdScript MyDialog Dialog non-modal English";
        "Start pdScript FreeScript"="Start pdScript FreeScript English";


        @@lang = parse_langfile(langpath) # create the language hash
        UI.messagebox(@@lang["pdScript interpreter"])

        does show an empty dialog.

        Hans-Peter
        HPW
         
        Posts: 126
        Joined: Sat Mar 28, 2009 9:19 am
        Location: Germany

        Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

        Postby Dan Rathbun » Mon Jan 23, 2012 2:32 am

        in File: 'pdScript/langLoad.rb'

        the hash var may be out of scope for the nested blocks. There is some difference between { ... } and do ... end

        I'll try to test later.

        And you can look at any of the strings files in your "Resources/de/" folder. You'll see they have English keys and German values.
        User avatar
        Dan Rathbun
        Top SketchUcator
         
        Posts: 4074
        Joined: Tue Oct 06, 2009 3:06 am
        Location: Florida, USA
        Name: Dan Rathbun
        Operating system: Windows
        SketchUp version: 8
        License type: Pro
        SketchUp use: education
        Level of SketchUp: Advanced

        Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

        Postby Dan Rathbun » Mon Jan 23, 2012 5:21 am

        HPW wrote:The function runs but I get always the key instead of the value.
        What did I miss?

        because:
        PdScript.module_eval "puts(@@lang.inspect)"
        returns:
        {"pdScript"=>nil, "Adds pdScript interpreter to the ruby environment"=>nil, "pdScript interpreter"=>nil, "Start pdScript clock Dialog"=>nil, "Start pdScript FreeScript"=>nil, "Start pdScript MyDialog Dialog modal"=>nil, "Start pdScript MyDialog Dialog non-modal"=>nil}

        and I created the Hash so that if the value was invalid, it would return the English key as a backup.
        Two problems
        line 74 was chomp! should be chomp

        also, easiest solution for scoping, was to use a instance @ var: @hash instead of hash

        In addition, the keys must be EXACT when you ask for the value, or else you just get the arg returned.

        I corrected the files above
        User avatar
        Dan Rathbun
        Top SketchUcator
         
        Posts: 4074
        Joined: Tue Oct 06, 2009 3:06 am
        Location: Florida, USA
        Name: Dan Rathbun
        Operating system: Windows
        SketchUp version: 8
        License type: Pro
        SketchUp use: education
        Level of SketchUp: Advanced

        Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

        Postby HPW » Mon Jan 23, 2012 7:12 am

        Hello Dan,

        Thanks again.
        I will add this at the evening.

        One question again: Is there a save way to gets sketchup's main window handle.
        I see some posts with winApi calls to search the window by title string.
        I have done the same in my Dll.
        Would be nice when Sketchup would publish this in a global var.

        Hans-Peter
        HPW
         
        Posts: 126
        Joined: Sat Mar 28, 2009 9:19 am
        Location: Germany

        Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

        Postby HPW » Mon Jan 23, 2012 7:50 pm

        Hello,

        Added all suggested changes and upload a 1.01 zip to the link above.
        Thanks again to Dan for the advises and code samples. Learned a lot.

        Hans-Peter
        HPW
         
        Posts: 126
        Joined: Sat Mar 28, 2009 9:19 am
        Location: Germany

        Re: pdScript-interpreter for GUI Scripting in SketchUp-Ruby

        Postby HPW » Tue Jan 24, 2012 10:08 pm

        Hello,

        I made a small page for the sketchup plugin on my website.
        I updated the above link for the download.

        Hans-Peter
        HPW
         
        Posts: 126
        Joined: Sat Mar 28, 2009 9:19 am
        Location: Germany

        SketchUcation One-Liner Adverts

        by Ad Machine » 5 minutes ago

        Not a Premium Member yet? Check out the great time-limited deal we are offering.

        Ad Machine
        Robot
         
        Posts: 2012


        Return to Developers' Forum

        Who is online

        Users browsing this forum: Chris Fullmer, interverne, Jesiah, Majestic-12 Bot, Renderiza and 5 guests