Easy way to get rendering information option keys and its corresponding constants in Ruby?

Situation:
I would like to know if one of the rendering information of model changed, then exactly what it was and what it’s new value is.
(No specific goal, just for my own education.)

I’m not a (very) lazy man, so checked myself and get my solution. Easy! :slight_smile:
I can use Class: Sketchup::RenderingOptionsObserver and Class: Sketchup::RenderingOptions

#dirty
class MyROObserver < Sketchup::RenderingOptionsObserver
  def onRenderingOptionsChanged(rend_ops, type)
    #What is this key?
    # key = "BandColor"

    # just give an initial value to not get error with partly code 
    key = "?"
    if type == Sketchup::RenderingOptions::ROPSetBackgroundColor
      key = "BackgroundColor"
    elsif type == Sketchup::RenderingOptions::ROPDrawHiddenGeometry
      # Wrong in a docu:
      #key = "ROPDrawHiddenGeometry"
      key = "DrawHiddenGeometry"
    elsif type == Sketchup::RenderingOptions::ROPDrawHiddenObjects
      # Wrong in a docu:
      #key = "ROPDrawHiddenObjects"
      key = "DrawHiddenObjects"
    # +61 times elseif,...!?
    #elsif type == 
      
    end
    puts "Constant: #{type}"
    puts "#{key} : #{rend_ops[key]}"
  end
end

# Attach the observer.
model_rend_ops = Sketchup.active_model.rendering_options
my_ro_obsever = MyROObserver.new
model_rend_ops.add_observer(my_ro_obsever)

# do not forget
# model_rend_ops.remove_observer(my_ro_obsever)

Not really considering now the usual Ruby API documentation mistakes (two were mentioned in my code), I would like to know the followings:

  • Do other developers do the same or similar?
  • Do I really heve to go through all of the constant and try to figure out which one is related to what rendering information (option) key?
  • Don’t we have a “secret” method to do it more easy or at least a “cat hand written” doc about the key<>type pairs?
  • Why do we need a constant here? Wouldn’t it be easier to return the “key”? Is it a language/OS/version… specific thing?
  • What is Sketchup::RenderingOptions::ROPAssign good for?
  • What does “BandColor” key mean?
1 Like

If you find documentation errors, feel free to log them in our issue tracker.

No. There is an an other way…

class MyROObserver < Sketchup::RenderingOptionsObserver
  def initialize
    @ro_last = Sketchup.active_model.rendering_options.to_h
  end
  def onRenderingOptionsChanged(rend_ops, type)
    rend_ops.to_h.each{|k,v|
      next if @ro_last[k] == v
      puts "Constant: #{type}"
      puts "New: #{k} : #{v}"
      puts "Old: #{k} : #{@ro_last[k]}"
    }
    @ro_last = Sketchup.active_model.rendering_options.to_h
  end
end

# Attach the observer.
model_rend_ops = Sketchup.active_model.rendering_options
my_ro_obsever = MyROObserver.new
model_rend_ops.add_observer(my_ro_obsever)
# do not forget
# model_rend_ops.remove_observer(my_ro_obsever)

Thanks Christina, I know about that…For some reason, I don’t want to register to github yet. Sorry!
Please take it from here if you like to. Someone else can do it as well. :blush:

The return values are integer indexes that come from the C-side enumerations (structs).

It certainly would have been easier in many cases for Ruby-side coders if the hash keys were returned.

That is the dull color bands outside the view when the camera’s aspect ratio is certain values.

  • Sketchup::Camera#aspect_ratio=

    used to set the aspect ratio for a Camera. Changing this value will cause SketchUp to show gray bars over the screen to show the resulting view.

1 Like

Here’s my take on catching rendering options and list the changes.

module RenderingOptionTracker
  # Call this when setting up the extension.
  def self.backup_rendering_options
    @ro_backup = Sketchup.active_model.rendering_options.to_h
    
    nil
  end
  
  # Call this to list the rendering options that have changed,
  # e.g. from a RenderingOptionsObserver.
  #
  # @return [Hash]
  #   Old outdated values indexed by the RenderingOptions key.
  def self.rendering_options_diff
    previous_rendering_options = @ro_backup
    backup_rendering_options
    
    previous_rendering_options.reject do |key, old_value|
      Sketchup.active_model.rendering_options[key] == old_value
    end
  end
end

I let the returned hash contain the old, outdated value, as there is no other way to retrieve it. You use the key to look up the current value, or rewrite this design to return the new value directly if that makes the most sense.

EDIT: It seems you designed more or less the same thing as I was writing this.

1 Like

Yes, I ended up with the similar manner during our "parallel forum posting " above.
Thanks anyway since yours is more elegant! :+1:

I see. (however I know not much about C…).
I guess than, Sketchup::RenderingOptions::ROPAssign constant is also related to that. Or do we have any other use in Ruby side?

BTW Dan,
Maybe you would be so kind and add to #449 issue in github the [problem in a doc] :innocent:
image

Note that the rend_ops parameter is already the Sketchup.active_model.rendering_options object. So your last line of the callback can be …

    @ro_last = rend_ops.to_h

Also …

      puts "Constant: #{type}"

… does not list the constant, it lists it’s integer value.

I would do somethng like this …

class MyROObserver < Sketchup::RenderingOptionsObserver

  # Create a hash of Rendering Options constant names, indexed by their value:
  LOOKUP ||= Sketchup::RenderingOptions.constants.map {|c|
    [ Sketchup::RenderingOptions.const_get(c), c.to_s.delete_prefix('ROP') ]
  }.to_h

  def initialize
    @ro_last = Sketchup.active_model.rendering_options.to_h
  end

  def onRenderingOptionsChanged(rend_ops, type)
    rend_ops.to_h.each{|k,v|
      next if @ro_last[k] == v
      puts "Constant: #{LOOKUP[type]} (#{type})"
      puts "New: #{k} : #{v}"
      puts "Old: #{k} : #{@ro_last[k]}"
    }
    @ro_last = rend_ops.to_h
  end

end # class
2 Likes

I like this very much! Thanks! :+1:

Sure… :blush:

1 Like

What problem … that I already have not mentioned ?

I mean in the docu the two new option key added in SU2020 mentioned as

  • ROPDrawHiddenGeometry
  • ROPDrawHiddenObjects

But it must to be

  • DrawHiddenGeometry
  • DrawHiddenObjects
1 Like

Oh … yea okay I understand. They wrote the constant name rather than the options keys.


ADD: I’ve added the above errors to the GitHub issue.

2 Likes

Continuing the test (SU2021) using the following code snippet.

Code:
# Test on SU2021.0.339
# Dirty! Do not use it on "live" model!
module DezmoLessonsROO
  extend self

  LOOKUP ||= Sketchup::RenderingOptions.constants.map {|c|
    [ Sketchup::RenderingOptions.const_get(c), c.to_s.delete_prefix('ROP') ]
  }.to_h
  
  class MyROObserver < Sketchup::RenderingOptionsObserver
    
    def initialize
      @ro_last = Sketchup.active_model.rendering_options.to_h
    end
    
    def onRenderingOptionsChanged(rend_ops, type)
      rend_ops.to_h.each{|k,v|
        next if @ro_last[k] == v
        puts "Constant: #{LOOKUP[type]} (#{type})"
        puts "Old: #{k} : #{@ro_last[k]}"
        puts "New: #{k} : #{v}"
        puts
        DezmoLessonsROO.store(type, LOOKUP[type], k)
      }
      @ro_last = rend_ops.to_h
    end
    
  end #class

  def store(type, con, o_key)
    @to_print[type] = [con, o_key]
  end
  
  def fire_observer
    @to_print = {}
    model_rend_ops = Sketchup.active_model.rendering_options
    backup_ops = model_rend_ops.to_h
    my_ro_obsever = MyROObserver.new
    model_rend_ops.add_observer(my_ro_obsever)
    model_rend_ops.each { |key, value|
      puts "fire1>> #{key} : #{value}"
      ov = value
      case value
      when Integer
        model_rend_ops[key] = value + 1
      when Float
        model_rend_ops[key] = value + 0.1
      when TrueClass, FalseClass
        model_rend_ops[key] = !value
      when Sketchup::Color
        model_rend_ops[key] = value.blend(Sketchup::Color.new(1, 2, 3, 4), 0.5)
      end
      # fire again with original value
      puts "fire2>> #{key} : #{model_rend_ops[key]} << #{ov}"
      model_rend_ops[key] = ov
    }
    #restore rendering options, just for sure...
    model_rend_ops.remove_observer(my_ro_obsever)
    Sketchup.active_model.rendering_options.each { |key, value|
      Sketchup.active_model.rendering_options[key] = backup_ops[key]
    }
    pp @to_print.sort.to_h
    puts "#{@to_print.size} constants-ro.keys pairs found (out of theoretic: #{model_rend_ops.keys.size})"
    puts
    puts "Not included constants:"
    puts "(Does not have assigned key)"
    LOOKUP.sort.to_h.each_key{|ck|
      puts "#{ck}=>#{LOOKUP[ck]}" unless @to_print[ck]
    }
    puts
    puts "Not included ro.keys:"
    puts "(Does not cause observer fire.)"
    model_rend_ops.each_key{|key|
      puts "#{key}" unless @to_print.values.flatten.include?(key)
    }
  end
end #module
DezmoLessonsROO.fire_observer

Some experiences:

  1. I was able to identify: 53 constants-ro.keys pairs (out of theoretic: 63)
Constant<> ro key pairs
 1=>["SetRenderMode", "RenderMode"],
 3=>["SetTexture", "Texture"],
 4=>["SetEdgeDisplayMode", "EdgeDisplayMode"],
 5=>["SetEdgeColorMode", "EdgeColorMode"],
 6=>["SetJitterEdges", "JitterEdges"],
 9=>["SetProfileEdges", "DrawSilhouettes"],
 10=>["SetProfileWidth", "SilhouetteWidth"],
 11=>["SetDisplayInstanceAxes", "DisplayInstanceAxes"],
 12=>["SetBackgroundColor", "BackgroundColor"],
 13=>["SetForegroundColor", "ForegroundColor"],
 14=>["SetHighlightColor", "HighlightColor"],
 15=>["SetConstructionColor", "ConstructionColor"],
 16=>["SetDisplayColorByLayer", "DisplayColorByLayer"],
 18=>["SetExtendLines", "ExtendLines"],
 19=>["SetLineExtension", "LineExtension"],
 20=>["SetDisplayFog", "DisplayFog"],
 23=>["SetFogColor", "FogColor"],
 24=>["SetFogDist", "FogStartDist"],
 26=>["SetSectionDisplayMode", "DisplaySectionPlanes"],
 28=>["DrawHidden", "DrawHiddenObjects"],
 29=>["DrawHiddenGeometry", "DrawHiddenGeometry"],
 30=>["DrawHiddenObjects", "DrawHiddenObjects"],
 31=>["EditComponent", "InstanceHidden"],
 32=>["TransparencySortMethod", "TransparencySort"],
 33=>["SetDepthQueEdges", "DrawDepthQue"],
 34=>["SetLineEndEdges", "DrawLineEnds"],
 35=>["SetDepthQueWidth", "DepthQueWidth"],
 36=>["SetLineEndWidth", "LineEndWidth"],
 37=>["SetProfilesOnlyEdges", "DrawProfilesOnly"],
 38=>["SetLockedColor", "LockedColor"],
 39=>["SetDisplaySketchAxes", "DisplaySketchAxes"],
 40=>["SetFaceColor", "FaceFrontColor"],
 41=>["SetEdgeType", "EdgeType"],
 42=>["SetModelTransparency", "ModelTransparency"],
 43=>["SetMaterialTransparency", "MaterialTransparency"],
 44=>["SetSectionActiveColor", "SectionActiveColor"],
 45=>["SetSectionInactiveColor", "SectionInactiveColor"],
 46=>["SetSectionDefaultCutColor", "SectionDefaultCutColor"],
 47=>["SetSectionDefaultFillColor", "SectionDefaultFillColor"],
 48=>["SetSectionCutWidth", "SectionCutWidth"],
 49=>["SetSectionCutFilled", "SectionCutFilled"],
 50=>["SetHideConstructionGeometry", "HideConstructionGeometry"],
 51=>["SetSkyColor", "SkyColor"],
 52=>["SetGroundColor", "GroundColor"],
 53=>["SetDrawHorizon", "DrawHorizon"],
 54=>["SetDrawGround", "DrawGround"],
 55=>["SetDrawUnderground", "DrawUnderground"],
 56=>["SetGroundTransparency", "GroundTransparency"],
 57=>["SetDisplayText", "DisplayText"],
 58=>["SetDisplayDims", "DisplayDims"],
 59=>["SetFogUseBkColor", "FogUseBkColor"],
 60=>["SetDisplayWatermarks", "DisplayWatermarks"],
 62=>["SetDrawBackEdges", "DrawBackEdges"]
Not included constants (Does not have assigned key?):
0=>Assign
2=>SetTransparencyObsolete
7=>SetLineStyleEdges
8=>SetExtendEdges
25=>SetFogHint
27=>SectionDisplayTurnedOff
61=>SetXRayOpacity
63=>SetPhotomatchDrawBackground
64=>SetPhotomatchBackgroundOpacity
65=>SetPhotomatchDrawOverlay
66=>SetPhotomatchOverlayOpacity
9999=>SetFaceColorMode
Not included ro.keys (Does not cause observer fire):
BandColor
DisplaySectionCuts
FaceBackColor
FogEndDist
HorizonColor
InactiveFade
InactiveHidden
InstanceFade
SectionCutDrawEdges
ShowViewName
  1. Chaining values at some rendering information keys caused double ( “DrawHiddenGeometry”, “DrawHiddenObjects” ) or tripple ("DrawHidden") fire of the observer.
    @DanRathbun, This could be interesting for your GitHub case too.
Partly off-topic:

Thanks for @TIG for grammar :blush: correction. :+1: :grinning:

:innocent:

I have noted some weird happens in that issue.

1 Like

:blush: I just noticed that I had “reinvented the wheel” of @MSP_Greg: SketchUp_14_Constants_Guide.md#renderingoptionsobserver

However it is interesting to see how some constants are changed during the time…

Yes some of the observers fire only for manual GUI actions and not per API calls.
We open issue for them when they are found. Sometimes also the inspector panels do not update after API calls, and we are forced to call UI.refresh_inspectors.

Yes, It is similar for # Model.options . You have to force refresh in a same way to get effect e.g on an opened Model Info Measurement units.