sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    PdScript-interpreter for GUI Scripting in SketchUp-Ruby

    Scheduled Pinned Locked Moved Developers' Forum
    14 Posts 2 Posters 5.7k Views 2 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      HPW
      last edited by

      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:

      
      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

      1 Reply Last reply Reply Quote 0
      • Dan RathbunD Offline
        Dan Rathbun
        last edited by

        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.

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • Dan RathbunD Offline
          Dan Rathbun
          last edited by

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

          @@extension.version = "1.0.1" or whatever....

          I'm not here much anymore.

          1 Reply Last reply Reply Quote 0
          • H Offline
            HPW
            last edited by

            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:

            
            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

            1 Reply Last reply Reply Quote 0
            • H Offline
              HPW
              last edited by

              I think I have now the correct format but it still does not work.

              
              "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

              1 Reply Last reply Reply Quote 0
              • Dan RathbunD Offline
                Dan Rathbun
                last edited by

                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.

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • Dan RathbunD Offline
                  Dan Rathbun
                  last edited by

                  @hpw said:

                  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

                  I'm not here much anymore.

                  1 Reply Last reply Reply Quote 0
                  • Dan RathbunD Offline
                    Dan Rathbun
                    last edited by

                    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:
                    %(#800080)["pdScript/lang"]
                    that has various string files, like:
                    %(#800080)[pdScript_menu.en] %(#008000)[# English]
                    %(#800080)[pdScript_menu.de] %(#008000)[# German]
                    %(#800080)[pdScript_menu.fr] %(#008000)[# 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'

                    #
                    # 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'

                    
                    #
                    # 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
                    
                    

                    I'm not here much anymore.

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      HPW
                      last edited by

                      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

                      1 Reply Last reply Reply Quote 0
                      • H Offline
                        HPW
                        last edited by

                        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

                        1 Reply Last reply Reply Quote 0
                        • H Offline
                          HPW
                          last edited by

                          Hello,

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

                          Hans-Peter

                          1 Reply Last reply Reply Quote 0
                          • 1 / 1
                          • First post
                            Last post
                          Buy SketchPlus
                          Buy SUbD
                          Buy WrapR
                          Buy eBook
                          Buy Modelur
                          Buy Vertex Tools
                          Buy SketchCuisine
                          Buy FormFonts

                          Advertisement