sketchucation logo sketchucation
    • Login
    πŸ€‘ SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    Storing last values used in the registry?

    Scheduled Pinned Locked Moved Developers' Forum
    13 Posts 4 Posters 1.2k Views 4 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.
    • T Offline
      tomot
      last edited by

      I've been digging through scripts, and while doing some module script incorporation, I'm of the opinion that using the Registry provides a cleaner less error prone way of dealing with this Subject: The following code is part of the 1st menu

       
      reg_key = "TNT;;Bookshelf" 
      prompts = ["Width", "Height", "Depth"]
      values = [2.feet, 2.feet, 1.feet]
      #---read registry values
      v = Sketchup.read_default(reg_key, "values")  
        unless v.nil?
          values = eval(v)
          values[0] = values[0].to_l
          values[1] = values[1].to_l
          values[2] = values[2].to_l
        end        
      

      Am I correct in assuming that a 2nd menu ALWAYS needs its own new Registry entry? (like the following which does work)

      
      reg_key = "TNT;;Bookshelf1" 
      prompts = [ "No. of shelves wide ", "No. of shelves high ", "shelf thickness"]
      values = [ 5, 5, 1.inch ]
      #---read registry values
      v = Sketchup.read_default(reg_key, "values")  
        unless v.nil?
          values = eval(v)
          values[0] = values[0].to_i 
          values[1] = values[1].to_i 
          values[2] = values[2].to_l 
        end        
      

      BTW: if I use only one registry entry for both menus and increment the values in the 2nd menu ie. values[4] etc. I get a console error

      [my plugins](http://thingsvirtual.blogspot.ca/)
      tomot

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

        You are confusing terms again.

        They are input dialog boxes, NOT menus.

        NO. Each one of your plugins should only use ONE registry key.

        • Please begin all your keys with "Plugin_"

        Reason.. this sets them apart from all other Sketchup subkeys, but still grouped together. And it follows the convention used by the WebDialog keys, which are always (automatically,) prefixed with "WebDialog_"

        • Whitespace (and '::') in keynames should be replaced with "_".
          like:
          REGKEY = 'Plugin_'<<Module.nesting[0].name.split('::').join('_')
          notice I use a constant (all caps,) because it will never change.
          It would produce for your example:
          'Plugin_TNT_Bookshelf'

        BUT ...
        Each "set" of values OR special setting has it's own ATTRIBUTE name (under the common plugin KEY.)
        "RightHandDoorParams"
        "LeftHandDoorParams"

        I'm not here much anymore.

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

          Next issue.

          I gave you a couple of basic saving and loading option methods, in this thread's code sample:
          http://forums.sketchucation.com/viewtopic.php?f=180&t=43673&p=390107#p389920

          What do you want to do differently ??

          We can tweak the process.

          For example.. if you still wanted to use unique @@ names, like @@lhd_width, @@lhd_height, @@lhd_style, etc., instead of @@opts[:lhd_width], etc. everywhere in your code ...
          ... you CAN do that and still use the @@opts hash of saving and restoring.

          The trick is to collect ALL module variables (also called class variables,) into a array of var name strings, using the standard method class_variables()
          then iterate that array thus:

          vars = class_variables()
          vars.each do |var|
            eval("@@opts[#{var.gsub('@@',';')}]= #{var}")
          end
          # Now we can save the opts hash; 
          set_saved_opts()
          

          The reverse, after calling get_saved_opts(), to distribute the saved settings back to your module variables:

          get_saved_opts()
          @@opts.each do |attr,val|
            eval("@@#{attr.to_s} = @@opts[#{attr}]")
          end
          

          I'm not here much anymore.

          1 Reply Last reply Reply Quote 0
          • T Offline
            tomot
            last edited by

            @dan rathbun said:

            You are confusing terms again.
            They are input dialog boxes, NOT menus.

            yes, menus my bad!... been a long day so far, could not sleep, I started coding at 3:30 am this morning, with good intentions trying your outline, finally had to sideline that effort, it in favor of a simpler older script of mine in need of a module. Regardless this small demonstration script, is a starting point, for going forward. πŸ˜„ using module & registry works!..........comments welcome!


            tnt_bookshelf.rb

            [my plugins](http://thingsvirtual.blogspot.ca/)
            tomot

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

              OK looking at it... and making a few quick changes.

              ADD: Here's version '1.1.1'
              Fixed line 65: forgot to paste in the new attribute name "BookshelfDimensions" .. sorry.


              TNT_1_1_1.zip


              I fixed it so there is only ONE key for the plugin, and each dialog has a separate attribute beneath that key.

              viz:
              Plugin_TNT_Bookshelf_REGKEY.png
              Also:

              • Put the plugin inside a plugin submodule: TNT::BookShelf.
              • Plugin now resides with the path "tnt/bookshelf/"
              • Added a VERSION constant.
              • Wrapped the undo operation in a begin ... rescue ... end block.
              • Moved the "BookShelf Details" dialog before the undo operation.
              • Moved the last line: file_loaded(*filepath*) inside the file_loaded? conditional block. (Just to be sure it only gets pushed into $loaded_files once. Although file_loaded() may test for this, there's no sense calling it if not needed to.)
              • Made note (in file header,) that on XP the REGKEY path differs from Win6+.

              I'm not here much anymore.

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

                Bumped: version '1.1.1'
                Fixed line 65: forgot to paste in the new attribute name "BookshelfDimensions" .. sorry.

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • T Offline
                  tomot
                  last edited by

                  Dan thanks for your patience! I'm going to digest your changes...tomorrow.
                  After 12 hrs of sitting,... my ass is developing flat spots πŸ˜„
                  In the next stage I will be tackling how the incorporating of therectangle.rb code
                  which is used in my doortool ruby works with the module & registry stuff I have learned to implement today.
                  ttyl!

                  [my plugins](http://thingsvirtual.blogspot.ca/)
                  tomot

                  1 Reply Last reply Reply Quote 0
                  • T Offline
                    tomot
                    last edited by

                    Looks great Dan! Now unless I'm missing something, (which happens quite often), does the storing of last used dialog values in the registry not make for a more elegant solution then using the @@ approach?

                    [my plugins](http://thingsvirtual.blogspot.ca/)
                    tomot

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

                      Firstly... the difference between @ vars and @@ vars in modules are subtle. (Save that issue for later.)

                      Elegant? Well your really doing the same thing ... but dialog by dialog, instead of the plugin's whole set of saved values.

                      Also you're doing it in a sort of brute force manner. You are accessing the stored values in the registry (whether you need to not,) and always saving them (without really testing if they are good values. Relying on the user to input values they wish to save.)
                      Also you are creating the literal strings for the inputboxes each time the 'main' method is called.
                      But that's OK for now... you can understand what's happening.

                      Later on you (when you're ready to get fancier,) you might move the defaults, prompts etc out of the method into module vars. But it's not that important for a really simple single command plugin module. As your plugins get more complex and bigger, you will want to centralize common functions like loading and saving defaults into one method ... rather than have them scattered throughout your code. (Easier maintenance!)

                      Ruby is multi-paradigm... "there is more that one way to skin a cat."


                      The BIG lessons you have learned, is module wrapping, using variables that have namespace scope, and saving default values.
                      Also take note of the operation block.


                      I have noticed problems with the API's read_default() on PC when it tries to read REG_SZ strings values. We need to store quotes with the value in the registry. Using the inspect() method is a good idea, because it will escape embedded ' or " if used for unit symbols.
                      If I try to read the "SnapLength" attribute in the "Preferences" key, I get nil, because it's set to 1" instead of '1"' or "1\""
                      Also it cannot see any keys with spaces in their names, and just returns nil.

                      I'm not here much anymore.

                      1 Reply Last reply Reply Quote 0
                      • T Offline
                        tomot
                        last edited by

                        Nice explanation! if I continue for now to go down the registry path
                        How does or can values accept strings ? such as door open, or door closed?


                        values.jpg

                        [my plugins](http://thingsvirtual.blogspot.ca/)
                        tomot

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

                          @tomot said:

                          Nice explanation! if I continue for now to go down the registry path
                          How does or can values accept strings ? such as door open, or door closed?

                          OK just tested a bit ... the write_default and read_default have no problems if you feed a string (or most simple class types,) to them. The write stores it so it can be read OK.

                          The problem arrises when there is more than one double quote char ( ") in sequence, AND they are not escaped.
                          Because write_default always surrounds a string argument, perhaps by calling inspect() internally to the method.

                          so this was wrong, on my part:

                              #  set_saved_opts()
                              #
                              def set_saved_opts()
                                @@opts.each_pair {|attr,val|
                                  if val.is_a?(String)
                                    Sketchup.write_default( REGKEY, attr.to_s, val.inspect )
                                  else
                                    Sketchup.write_default( REGKEY, attr.to_s, val )
                                  end
                                }
                              end#def set_saved_opts()
                          
                          

                          I knew we needed to handle strings specially, but I went the opposite way. (The inspect method adds quotes.)

                          We really do not want to ADD any more quotes chars...

                          ... we want to either strip them off of strings, or be sure they are escaped.

                          Let's go with option 2, and use the gsub method, to escape all internal double quotes, like:
                          gsub(34.chr,92.chr<<34.chr)

                              #  set_saved_opts()
                              #
                              def set_saved_opts()
                                @@opts.each_pair {|attr,val|
                                  if val.is_a?(String)
                                    Sketchup.write_default( REGKEY, attr.to_s, val.gsub(34.chr,92.chr<<34.chr) )
                                  else
                                    Sketchup.write_default( REGKEY, attr.to_s, val )
                                  end
                                }
                              end#def set_saved_opts()
                          
                          

                          In your case if you had a results array that had an embedded string:
                          [1, 2, "door closed", 2.54]
                          and you use inspect() on it, you get this:
                          "[1, 2, "door closed", 2.54]"
                          and read_default cannot eval it, so it returns nil
                          Also, you cannot double inspect it, because that will result in the whole registry value delimited by 2 double quotes:
                          [1, 2, "door closed", 2.54].inspect.inspect
                          puts this: %(#008000)[""[1, 2, \"door closed\", 2.54]""] into the registry, and read_default will poop out again, (returning nil.)

                          So... you need to use:
                          results.inspect.gsub(34.chr,92.chr<<34.chr)

                          You can try it at the console:
                          Sketchup.write_default("Plugin_TNT_Bookshelf", "Array", [1,2,"door closed",2.54].inspect.gsub(34.chr,92.chr<<34.chr))
                          and then to test retrieving it:
                          [ruby:3jpmcjqh]arr = Sketchup.read_default("Plugin_TNT_Bookshelf", "Array")[/ruby:3jpmcjqh]
                          which if all goes well, should return:
                          [ruby:3jpmcjqh]'[1,2,"door closed",2.54]'[/ruby:3jpmcjqh] which can be eval'd back into an array.

                          OK?

                          However... write_default and read_default can ALSO write and read arrays directly if you DON'T inspect them.
                          This is because the 'write' converts them to a string, before storing them in the registry,... and then the 'read' evals those strings back into an [ruby:3jpmcjqh]Array[/ruby:3jpmcjqh].

                          But.. to confuse the issue... they do not handle hashes well. We have to resort to the [ruby:3jpmcjqh].inspect.gsub(34.chr,92.chr<<34.chr)[/ruby:3jpmcjqh] treatment for any hash arguments to write_default, and eval the return strings from read_default.


                          Now.. (if your dizzy trying to absorb this,) perhaps, you'll understand why I like to write one method to get all this proper handling correct, and then reuse that method in multiple plugins. (Say via a mixin module.) Trying to remember all the quirky issues, when it comes time to write and read values, is a pain in the butt.


                          You don't run into this 'nested string' in hashes and arrays problem, if all your variables are saved into individual attributes in the registry.
                          (... And they are all single value types, ie, not arrays, hashes, structs, etc.)

                          def save_my_vars()
                            vars = instance_variables + class_variables
                            vars.each{|var| eval("Sketchup.write_default(#{REGKEY}, '#{var}', #{var}")
                          end
                          
                          def load_my_vars()
                            vars = instance_variables + class_variables
                            vars.each{|var| eval("#{var} = Sketchup.read_default(#{REGKEY}, '#{var}'")
                          end
                          
                          

                          But.. that will save ALL of your variables... even iterators, and ones you do not really need to save.

                          This is why I collect only the ones I wish to save, into an [ruby:3jpmcjqh]@@opts[/ruby:3jpmcjqh] hash, and then write only those values to the registry.

                          Example.. at the top of your Bookshelf module, where you define your instance [ruby:3jpmcjqh]@[/ruby:3jpmcjqh] variables... you could just as easily define them AND an [ruby:3jpmcjqh]@@opts[/ruby:3jpmcjqh] hash, all in one go:

                          # default bookshelf values used for script development
                          unless defined?(@@opts)
                            @@opts = {
                              ;height => @height = 2.feet, 
                              ;width  => @width = 2.feet,
                              ;depth  => @depth = 1.inch, 
                              ;ny     => @ny = 5,
                              ;nz     => @nz = 5,
                              ;dist   => @dist = 1.inch
                            }
                          end
                          
                          

                          Anyway... as long as the simple way works.. use it. When things get more complex... and you need to centralize your default value handling... you've got a topic thread here to mine for ideas.

                          I'm not here much anymore.

                          1 Reply Last reply Reply Quote 0
                          • K Offline
                            ktkoh
                            last edited by

                            I have been following this topic as I have in the past used a file to store variables between sessions and my question is does the registry storing of variables only work on Win based computers and not on the Apple OS?

                            Keith

                            1 Reply Last reply Reply Quote 0
                            • TIGT Offline
                              TIG Moderator
                              last edited by

                              The Sketchup.read_defaults and Sketchup.write_defaults use each PC's Sketchup 'Registry' entries OR a MAC's Sketchup 'plist' file entries... so they should work cross-platform.
                              The main issue with using the Registry is storing data restructured into a format that can be recovered and then converted back into the required 'class' later - e.g. a string/float/integer/length/boolean/array/hash etc will need some 'manipulation' before writing - but if you have been using a 'file' to store such things then you've been writing them as strings already - when you reread the file you presumably convert the strings back with say string.to_f to make the value a number etc... [like an 'ini' file].
                              The Registry data exists across sessions globally for Sketchup on each PC, not just the current SKP.
                              So if you want SKP specific data saving then it's best to use model-attributes to save things with the SKP [you can save attributes as most common data types directly - except a hash] - the data is thereby accessible to all uses on the network when you script reads the attributes as it runs, and later updates the attributes as it closes, this can all be done independent of each PC's Registry entries.

                              Horses for courses...

                              TIG

                              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