How to add all SU materials in our list?

Dear friends,
As you know we can have a materials name list by using the following codes.

my_mat_names = []
Sketchup.active_model.materials.each do |mt|
  my_mat_names << mt.name
end
mat_list = my_mat_names.join('|')
prompts = ["Material"]
defaults = ["white"]
list = [mat_list]
title = "Material"
choice = UI.inputbox( prompts, defaults, list, title )

It is the list of materials that we used in our model, not complete SU materials. Of course, by using the following code we can add materials from SU.

my_mat = nil
filename = 'Materials/.../Mat_Name.skm'
path = Sketchup.find_support_file(filename)
materials = Sketchup.active_model.materials
my_mat = materials.load(path)

Adding materials one by one is so difficult also different SU’s have different materials.
1- How can we add all of the materials in SU to our list?
2- How can we add a special material in our plugin and will be available in all SU’s?
Your help will be highly appreciated.

You will have to use the Ruby core Dir class to walk all the material folders.

However, the names as displayed in SketchUp’s material browser may not be exactly the same as the SKM filenames.

1 Like

Can you give me more information?

Dir.chdir("C:/ProgramData/SketchUp/SketchUp 2021/SketchUp")
Dir.each_child("Materials") {|mt_dir|  
  Dir.each_child(Sketchup.find_support_file "Materials/"+ mt_dir) {|mt| 
    puts "Got #{mt}" 
  }
}

We can have the list of directories also we can find all materials but I have to use material directory address completely and it depends on SU version. If I use (Sketchup.find_support_file “Materials”, “”) directory address will be “C:/Users/Majid PC/AppData/Roaming/SketchUp/SketchUp 2021/SketchUp/Materials”.

Instead of …

Dir.chdir("C:/ProgramData/SketchUp/SketchUp 2021/SketchUp")

… use the block form of #chdir so that after the block, the previous working directory is automatically restored.

Here is an example:

NOTE: The #each_child loops are not needed because Dir::glob can recursively “walk” the subdirectories if ** is used as a pattern prefix.

module AuthorNamspace
  module SomeExtension

    extend self

    WIN = Sketchup.platform == :platform_win
    MAC = !WIN

    MATL_FILENAMES = []

    USER_MATL_DIR = Sketchup.find_support_file("Materials")
    USER_DIR = File.dirname(USER_MATL_DIR)

    if WIN
      PROG_MATL_DIR = USER_MATL_DIR.gsub(
        ENV["APPDATA"].gsub(/\\\\|\\/,'/'),
        ENV["PROGRAMDATA"].gsub(/\\\\|\\/,'/')
      )
    else # Mac uses the user path
      PROG_MATL_DIR = USER_MATL_DIR.dup
    end

    def get_material_filenames
      Dir.chdir(PROG_MATL_DIR) do
        # Recursively list all SKM files in subdirectories:
        MATL_FILENAMES << Dir.glob("**/*.{skm,SKM}")
      end
      if WIN
        Dir.chdir(USER_MATL_DIR) do
          # Recursively list all SKM files in subdirectories:
          MATL_FILENAMES << Dir.glob("**/*.{skm,SKM}")
        end
      end
      MATL_FILENAMES.flatten!
    end

  end
end

Referring to the example above, your plugin must create a plugin directory in the user materials folder path. In the example … USER_MATL_DIR.

Then you copy SKM files from your plugin’s directory to the new materials subdirectory. (Ie, your RBZ will have a “matls” distribution subfolder beneath the extension’s folder.)

The user may need to restart SketchUp for the new materials to be listed in the Materials inspector. (Or your extension can try to call the UI.refresh_inspectors method.)

1 Like

Thank you for the codes and information. When I run the upper code, I received the following warning…

:72: warning: already initialized constant MajidMahmoudi::MajInterior::MajInterior::WIN :72: warning: previous definition of WIN was here

is it normal?

As an alternative idea (workaround):
You can create a e.g. maj_mat.skp file with your special materials in it. You can include it in your extension folder beside of your main .rb file, then load it to the model then remove something like:

model = Sketchup.active_model
path = File.join(File.dirname(__FILE__), "maj_mat.skp")
comp = model.definitions.load( path )
model.definitions.remove(comp)

Note: The last code line with: DefinitionList#remove instance_method introduced in SU2018, therefore you have to use other method to purge the “unnecessary” component def in earlier version of SU e.g.

model.definitions.remove(comp) if Sketchup.version.to_i >= 18
#Before SU2018 #remove(definition) does not exist, use purge_unused instead
#Be careful, because it could/will remove unused what created by 'others' too...
model.definitions.purge_unused if Sketchup.version.to_i < 18
2 Likes

More precisely: When I load the upper code in a second time, I received the following warning…

Normally a ruby file of the extension loaded once when SU starts, and the constants are defined only once. During testing, when you are reloading a file the constants will be defined again, that is the reason you get the warning.

A constant is a type of variable which always starts with a capital letter . Constants are used for values that aren’t supposed to change, but Ruby doesn’t prevent you from changing them, but you will see this warning message.
You can find more for example here.Everything You Need to Know About Ruby Constants

During testing, let say Yes it is. But you have to be care to not define the constants e.g. in your methods again. Leave your constants definitions on top of the code outside of the methods…

You can check this topic:

1 Like

Dear Dan,
Following codes load all materials for me. I wish to know if it works for different SU versions and different OS also. Can you confirm it?

win = Sketchup.platform == :platform_win
mt_dir = Sketchup.find_support_file("Materials")
if win
  prog_mt_dir = mt_dir.gsub(
    ENV["APPDATA"].gsub(/\\\\|\\/,'/'),
    ENV["PROGRAMDATA"].gsub(/\\\\|\\/,'/')
  )
else
  prog_mt_dir = mt_dir.dup
end
materials = Sketchup.active_model.materials
Dir.chdir(prog_mt_dir) do
  Dir.glob("**/*.{skm,SKM}") do |mt|
    materials.load(Sketchup.find_support_file "Materials/" + mt)
  end
end
if win
  Dir.chdir(mt_dir) do
    Dir.glob("**/*.{skm,SKM}") do |mt|
      materials.load(Sketchup.find_support_file "Materials/" + mt)
    end
  end
end     

Thank you so much Dezmo. After long time I used constant variables and it is why I confused.

In your snippet you have defined mt_dir, but then do not use it later when you do …

    materials.load(Sketchup.find_support_file "Materials/" + mt)

Why not use this …

    materials.load(File.join(mt_dir, mt))

?

No. I do not have a Mac. And you will need to do your own testing.


All this aside …

WHO in the whole WORLD would want to BLOAT their model file with HUNDREDS of materials ?

The answer is NO ONE.

2 Likes

You may find this useful:
https://sketchucation.com/plugin/2365-material_browser

I did not checked too deeply but, probably e.g. the skm.rb in it, worth to see… :wink:

1 Like