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

    How toget a Settings Menu to communicate with a Main Menu?

    Scheduled Pinned Locked Moved Developers' Forum
    18 Posts 3 Posters 1.1k Views 3 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.
    • Dan RathbunD Offline
      Dan Rathbun
      last edited by

      @tomot said:

      I have added a Settings sub menu with the 5 listed options: successfully. However when I "#" comment out the original 5 listed options in the main script, the new Settings menu is unable to communicate the default values to the main script.

      Ok ... this "main script" term.. implies you are attempting plugin "file spanning" without using namespaces (modules.)

      You MUST use a namespace.

      FYI.. the Ruby keywords module and class do not mean "define" (That is reserved for methods, ie, def, and also means "redefine this method.")
      The keywords module and class mean "open for editing".

      SO.. your plugin code, can be in 100 different files if you wish (although that would be extreme.)

      But the code in each file must evaluate within the same namespace !!

      Ex:

      # file; 'tomot/fancydoor/doorwidget_main.rb'
      # ------------------------------------
      module Tomot; end
      module Tomot;;FancyDoorWidget
      
        # declare module vars and constants first
      
        # require other parts of this plugin;
        require('tomot/fancydoor/common_opts.rb')
        require('tomot/fancydoor/lefthand_doors.rb')
        require('tomot/fancydoor/righthand_doors.rb')
      
        # main plugin script, menu items, etc.
      
      end
      
      # file; 'tomot/fancydoor/common_opts.rb'
      # ------------------------------------
      module Tomot;;FancyDoorWidget
      
        # method(s) to control common door options
      
      end # module
      
      # file; 'tomot/fancydoor/lefthand_doors.rb'
      # ------------------------------------
      module Tomot;;FancyDoorWidget
      
        # methods to work with lefthand doors
      
      end # module
      

      ... etc.

      (A poor example... but each author has his/her own way of splitting up there code for ease of maintenance.)

      I usually put all plugin options handling (saving, restoring, changing, etc.) in one file with a "_opt.rb" suffix.
      .. and usually all menu, command and toolbar setup in another, with a "_mnu.rb" suffix.
      The main plugin methods and code, (ie, the "engine",) I put in a file with a "_eng.rb" suffix.
      If I have a bunch of misc. methods, I may put them in a separate file, with a "_lib.rb" suffix.

      I personally find it easier with Notepad++, to switch file tabs, or left-right edit panes, rather than scroll WAY up, and WAY back down within a single file.
      It all depends on whether the plugin is simple or complex.
      A very simple, single menu item "macro" I'll do all in one file.

      I'm not here much anymore.

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

        Oh.. another reason to break up your plugin code into multiple files.. is debugging.

        If the code that creates the menus, menuitems and toolbars, is all in one file. Once that is loaded, (assuming you pointed the menuitems, and toolbar buttons at methods in your module...,) that particular file does not need to be reloaded during debugging.

        If you are debugging, and tweaking options handling, in a separate file... after a tweak and save, you need only reload that specific file to redefine the methods you fixed.

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • thomthomT Offline
          thomthom
          last edited by

          @tomot said:

          I have added a Settings sub menu with the 5 listed options: successfully. However when I "#" comment out the original 5 listed options in the main script, the new Settings menu is unable to communicate the default values to the main script.

          I think we need to see some sample code here. Because all we know is the concept of what you want to do - which should be doable - but clearly there is something in the implementation that's not correct.

          Thomas Thomassen β€” SketchUp Monkey & Coding addict
          List of my plugins and link to the CookieWare fund

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

            @thomthom said:

            I think we need to see some sample code here. Because all we know is the concept of what you want to do - which should be doable - but clearly there is something in the implementation that's not correct.

            I want to avoid, attaching code because I know its asking to much and goes against the bounds of the help you guys are already willing to provide, I will chew through Dan's contribution, and get the module stuff in place first. I also ran across Housebuilder by: Steve Hurlbut which I had forgotten uses a settings menu, ....oy vey!... that code should be fun to look at.

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

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

              @dan rathbun said:

              So are you talking about menus or dialog boxes ???


              I picture is still worth a 1000 words: πŸ˜„


              bifold5.jpg

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

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

                OK.. your talking dialogs.
                (It does not matter how the dialog box is opened... via a menu choice, a toolbar button click, a press of a hotkey, or a command typed at the console,.. it's all the same. The variables and options, are NOT on the menu.. they are in dialog boxes.)

                You are pointing at a list of instance variables, not constants. (Constants begin with an uppercase letter if they are a class or Module, otherwise they are all CAPSLIKETHIS.)

                Follow what I said.

                Paste those instance vars into the Module vars section, and add another @ to the front of them. (Editor search and replace within selection "@" with "@@".) Do the same else where in the code, whenever they are accessed.

                If you want to save all those options between settings more easily, then:
                You might as well change @dstyle to @@opts[:dstyle], @drail to @@opts[:drail], etc.

                I'm not here much anymore.

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

                  @tomot said:

                  I hear your Module reference loud and clear πŸ˜„ Nevertheless this by itself will not ....

                  Come on.. stop making excuses. Listen to me!

                  Here's an updated template ... with empty Lefthand, Righthand, and Common Door Setting dialog methods.

                  Just cut and paste your code into a copy of the template.

                  • Put any public module functions that you will allow outside access to in the MODULE FUNCTIONS section. (They must be qualified by def self.methodname )
                  • Put any private methods that you want only internal plugin access to, within the private section of the proxy class block. (They are NOT qualified. Just defined as def methodname )

                  Notice how they can be called like instance methods from anywhere within the module, without qualification? That's because the proxy IS a singleton instance of an anonymous class, linked to self (which is the module itself.) Ruby assumes an implied " self" for all method calls that have no qualification.

                  • Declare all module vars before use, as nil, or an initial value, or an empty string, or an empty array or hash, etc., in the MODULE VARIABLE section (Which is always outside the proxy class, but they CAN be accessed from within it.)
                  module Tomot; end
                   
                  module Tomot;;FancyDoorWidget
                   
                    unless defined?(REGKEY)
                      #{#  CONSTANTS
                      #
                          REGKEY  = 'Plugin_'<<Module.nesting[0].name.split(';;').join('_')
                          TOPMENU = Sketchup.read_default(REGKEY,'TopMenu','Plugins')
                          SUBMENU = Sketchup.read_default(REGKEY,'SubMenu','')
                      #
                      #}#
                   
                      #{# MODULE VARIABLES
                      #
                   
                        @@menu      = nil
                        @@menuitem  = []
                        @@menuvalid = [MF_ENABLED,MF_ENABLED,MF_ENABLED,MF_ENABLED,MF_ENABLED]
                       
                        @@opts = {
                          ;TopMenu => 'Plugins',
                          ;SubMenu => '',
                        }
                      #
                      #}#
                    end # unless defined?(REGKEY)
                   
                    #{# MODULE METHODS
                    #
                      public
                   
                      #{ widget_1()
                      #
                      #  Use a fancy Door Widget tool 1.
                      #
                      def self.widget_1()
                        #
                        # code goes here
                        #
                      end#}
                   
                      #{ widget_2()
                      #
                      #  Use a fancy Door Widget tool 2.
                      #
                      def self.widget_2()
                        #
                        # code goes here
                        #
                      end#}
                    #
                    #}#
                   
                    #{# PROXY CLASS
                    #
                    class << self
                   
                      private
                   
                      #  get_saved_opts()
                      #
                      def get_saved_opts()
                        saved = {}
                        @@opts.each_key {|attr|
                          val = Sketchup.read_default( REGKEY, attr.to_s, 'blank' )
                          next if val == 'blank' # was never set, use literal @@opts
                          saved[attr]= val
                        }
                        if saved.empty? # first run. opts were never saved.
                          set_saved_opts()
                        else
                          @@opts.update(saved) # in-place call, same as; merge!
                        end
                      end#def get_saved_opts()
                     
                      #  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.gsub(34.chr,92.chr<<34.chr) )
                          else
                            Sketchup.write_default( REGKEY, attr.to_s, val )
                          end
                        }
                      end#def set_saved_opts()
                  
                  
                      ### --- DIALOG INPUTBOX METHODS <<---<<<<<<<<<<<<<<<<<<<<<
                  
                  
                      #{ common_door_settings()
                      #
                      #  Accesses the Common Door settings.
                      #
                      def common_door_settings()
                        #
                        # Call a inputbox here that sets common door
                        #   settings values in the @@opts hash.
                        #
                        # If any values change, call set_saved_opts()
                        #
                      end #}
                   
                      #{ lefthand_door_settings()
                      #
                      #  Accesses the Lefthand Door settings.
                      #
                      def lefthand_door_settings()
                        #
                        # Call a inputbox here that sets lefthand door
                        #   settings values in the @@opts hash.
                        #
                        # If any values change, call set_saved_opts()
                        #
                      end #}
                   
                      #{ righthand_door_settings()
                      #
                      #  Accesses the Common Door settings.
                      #
                      def righthand_door_settings()
                        #
                        # Call a inputbox here that sets righthand door
                        #   settings values in the @@opts hash.
                        #
                        # If any values change, call set_saved_opts()
                        #
                      end #}
                  
                  
                    end # proxy class
                    #
                    #}#
                   
                    #{# RUN ONCE
                    #
                    unless file_loaded?( File.basename(__FILE__) )
                   
                      # Init the plugin settings
                      get_saved_opts()
                     
                      # Add commands to the menu
                      if SUBMENU.empty?
                        add_separator_to_menu(TOPMENU)
                        @@menu = UI.menu(TOPMENU)
                      else
                        @@menu = UI.menu(TOPMENU).add_submenu(SUBMENU)
                      end
                     
                      @@menuitem[0] = @@menu.add_item("Fancy Door Task 1") { self.widget_1 }
                      @@menu.set_validation_proc(@@menuitem[0]) { @@menuvalid[0] }
                   
                      @@menuitem[1] = @@menu.add_item("Fancy Door Task 2") { self.widget_2 }
                      @@menu.set_validation_proc(@@menuitem[1]) { @@menuvalid[1] }
                      
                      @@menu.add_separator()
                      
                      @@menuitem[2] = @@menu.add_item("Set Common Door Options") {
                        @@menuvalid[2]= MF_GRAYED
                        common_door_settings()
                        @@menuvalid[2]= MF_ENABLED
                      }
                      @@menu.set_validation_proc(@@menuitem[2]) { @@menuvalid[2] }
                      
                      @@menuitem[3] = @@menu.add_item("Set Lefthand Door Options") {
                        @@menuvalid[3]= MF_GRAYED
                        lefthand_door_settings()
                        @@menuvalid[3]= MF_ENABLED
                      }
                      @@menu.set_validation_proc(@@menuitem[3]) { @@menuvalid[3] }
                  
                      @@menuitem[4] = @@menu.add_item("Set Righthand Door Options") {
                        @@menuvalid[4]= MF_GRAYED
                        righthand_door_settings()
                        @@menuvalid[4]= MF_ENABLED
                      }
                      @@menu.set_validation_proc(@@menuitem[4]) { @@menuvalid[4] }
                      
                   
                      file_loaded( File.basename(__FILE__) )
                   
                    end
                    #
                    #}#
                   
                  end # module
                  

                  I'm not here much anymore.

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

                    Whats really needed, from the old programming days of the past is a simple GOTO statement.
                    I hope my attached picture illustrates a simplified flow of my ruby. Presently if I # comment the @stylewidth variable under Dialog 1 the entity cannot be draw. However with a GOTO statement the program would be directed to the value to the @stylewidth variable under Dialog 2 and then be directed back to draw the entity.

                    p.s. interesting if one Google's Goto Ruby, you get people commenting on either side of this issue.


                    visual.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:

                      Whats really needed, from the old programming days of the past is a simple GOTO statement.

                      ABSOLUTELY TOTALLY UNTRUE !!

                      @tomot said:

                      I hope my attached picture illustrates a simplified flow of my ruby.

                      All it does, is show, that you still suffer from linear thinking.

                      Your simple example BookShelf plugin also indicates your "linear affliction", where you have all of the executable code within ONE single method.

                      You need to break away from that kind of thinking, in today's world of GUI programming where anything can happen, at any time, depending upon what the user's actions are.

                      Take two "Procedural, Event-Driven" pills and call me in the morning... πŸ˜†

                      Ruby has everything you need, now. And there is no reason why if you are properly using scoped variables, that dialog #2 cannot access them.

                      If it cannot, then you are doing something to hide the variable from dialog #2.

                      Your pic cannot tell us what it is that you are doing wrong. We need a code example.

                      I'm not here much anymore.

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

                        Let me also say that you really need to break up your code into methods.

                        A method call IS THE GOTO STATEMENT that you think you need.

                        So all of dialog #1 code should be within a method of it's own.

                        So all of dialog #2 code should be within a method of it's own.

                        The draw routine should be all within a method of it's own.

                        etc.. etc...

                        You can also create a getter method to get the value of a variable from anywhere within your module:

                        module Author;;SomePlugin
                        
                          @@stylewidth = 3.inches
                        
                          class << self
                        
                            def stylewidth()
                              @@stylewidth
                            end
                        
                          end # proxy class
                        
                        end # module
                        

                        But that is unneeded, as the module var can be accessed modulewide.

                        Remember I told you that the difference between @ instance vars and @@ module vars in modules, was subtle.
                        This is where the subtleness comes into play... The attr_accessor methods that create instance vars and getter and setter methods, are for mixin modules, that will be mixed into classes.

                        This is why I was encouraging you to use @@ module vars instead of @ instance vars in your modules. (But it looks like you copied someone else's use of instance vars in modules.)

                        I'm not here much anymore.

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

                          I didn't mean to open the Goto can of worms! it was a deja vu moment from the past, I realize that Goto can easily be satisfied using if. My current Ruby already contains some 20 if statements, which are goto's. I should be able link via another if statement the sharing of the stored registry value of the @stylwidth in Dialog 1 and Dialog 2.....Hopefully πŸ˜’

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

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

                            Your totally missing the point...

                            Anyway... I took a walk and thought about it a bit.. and I think I realize what your problem may be.

                            You need to define (as in declare, for those coming from other programming langauges,) ALL those variables, that you wish to be accessible throughout your module, at the top of the module BEFORE and OUTSIDE of ALL methods.

                            Did you examine the module template I posted further up the topic ??

                            Look at the sentence just above the code box:

                            @dan rathbun said:

                            • Declare all module vars before use, as nil, or an initial value, or an empty string, or an empty array or hash, etc., in the MODULE VARIABLE section (Which is always outside the proxy class, but they CAN be accessed from within it.)

                            Now, look near the bottom of the template, in the RUN ONCE section.
                            What is the FIRST thing I did ??

                            I called a method to get the user's saved options from the registry (which will update certain module vars with the user's values, saved from the previous session.)

                            From that point on... whenever ANY method gets the values that those module variables point to... the values will be the latest values. ANY method may change them, and ANY method can access their values. (It's just up to you to decide when to save any changes to the values back into the registry.)

                            I'm not here much anymore.

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

                              @tomot said:

                              ..., I realize that Goto can easily be satisfied using if.

                              No it cannot.

                              @tomot said:

                              My current Ruby already contains some 20 if statements, which are goto's.

                              No they are not branching statements, they are conditional statements.

                              But you CAN make them branch off to some other part of your code, by making method calls, in response to the boolean evaluation of the conditional expressions.
                              if condition_is_true then call_method_one() else call_method_two();

                              @tomot said:

                              I should be able link via another if statement the sharing of the stored registry value of the @stylewidth in Dialog 1 and Dialog 2..

                              Again... in a procedural language, a method call (aka procedure call,) takes the place of the old goto from the old sequential linear languages like Fortran and GW-BASIC.

                              Whenever you identify a particular place in your code, that you need to "goto" (usually repeatedly,)... then THAT is the spot where you need to begin a method.

                              I'm not here much anymore.

                              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