How to add all SU materials in our list?

No, incorrect ! This lists only the material objects that have already been loaded into the model’s materials collection. Not what is on disk in the various “Materials” directories.

It is already in the model’s memory at that point.

Only if the user has clicked the house icon, and is looking at the “In Model” materials collection.

Computer platforms differ. MS Windows and MacOS are different in their filesystems and where they organize user and program data files.

It is a situation that programmers must deal with.

And the location of material files is only 1 of many differences you will need to deal with as a SketchUp extension programmer.

No, it is not that simple. It depends upon whether the user wants to use a material that is already in the model, or is still on disk in one of the material repositories.

Listen, it is not the same for Ruby. You’ll just need to realize this. You did do the correct thing in having the API find the file …

  filename = 'Materials/Asphalt and Concrete/Blacktop Old 01.skm'
  path = Sketchup.find_support_file(filename)

This was shown you in the API documentation.

Yes, …

  # Within some method...
  filename = 'Materials/Asphalt and Concrete/Blacktop Old 01.skm'
  materials = Sketchup.active_model.materials
  matl_name = File.basename(filename,".skm")
  matl = materials["[#{matl_name}]"]
  if matl.nil? # not in model materials collection, load it:
    begin
      matl = materials.load(Sketchup.find_support_file(filename))
    rescue => err
      put err.inspect
    end
  end
  return unless matl

No … let the API give your code the file path as shown above. It is cross-platform.

I really love Sketchup. A big reason is a logical similarity between programing and normal usage.
About this topic.
When I say User Material List I mean the following picture.


This menu is all available materials that come from hard disks. SU doesn’t list only materials that users used before. When a user one of the materials just select and use it.
1- Is it possible for SU team to do the same way for programmers?
I believe the answer is “YES”.
2- Is it difficult?
I believe the answer is “NO”.
This is just a suggestion.

The answer is no. Because it would be a waste of time and effort.
As shown above a programmer can load any of the distributed materials.

If you wish to, it is rather easy to use the core Ruby Dir class to search through the material collections on disk and return the file path.

Example …

  # Returns the absolute path to a material name query,
  # or nil if the named material was not found.
  def get_material_path(matl_name)
    # Search User Materials first:
    user_path = Sketchup.find_support_file("Materials")
    found = search_materials(user_path, matl_name)
    if !found  # Search ProgramData Materials:
      matl_path = Sketchup.find_support_file("Materials/Colors")
      prog_path = File.dirname(matl_path)
      found = search_materials(prog_path, matl_name)
    end
    return found
  end

  # Recursively searches the material path given for the named material.
  # Do not include the .skm extension, just the name.
  def search_materials(matl_path, matl_name)
    skm = File.join("**", "*.skm")
    skm_files = []
    Dir.chdir(matl_path) { skm_files = Dir.glob(skm) }
    rel_path = skm_files.find do |file|
      File.basename(file,'.*') == matl_name
    end
    rel_path ? File.join(matl_path,rel_path) : nil
  end

So for example …

bamboo_path = get_material_path("Wood Bamboo")
#=> C:/ProgramData/SketchUp/SketchUp 2021/SketchUp/Materials/Wood/Wood Bamboo.skm
1 Like

:crystal_ball:
I took out my crystal ball, a little fuzzy, but I think I see something …
:stuck_out_tongue_winking_eye: :face_with_monocle:

:copyright: :registered: :tm: :stuck_out_tongue:

1 Like

Hello Mr. Dan,
This code doesn’t work on MAC. Can you help me with it?
I write following code in MAC

mt_dir = Sketchup.find_support_file("Materials")
p mt_dir
#"/Users/majidmahmoudi/Library/Application Support/SketchUp 2018/SketchUp/Materials"
prog_mt_dir = mt_dir.dup
p prog_mt_dir
#"/Users/majidmahmoudi/Library/Application Support/SketchUp 2018/SketchUp/Materials"
Dir.chdir(prog_mt_dir) do
# Directory change.
Dir.glob("**/*.{skm,SKM}") do |mt|
  p mt # This code never executed.
end
#

Also Following code…

mt_dir = Sketchup.find_support_file("Materials")
Dir.chdir(mt_dir.dup) 
p Dir.pwd
# "/Users/majidmahmoudi/Library/Application Support/SketchUp 2018/SketchUp/Materials"
files = Dir.glob("**/*.skm")
p files
#[]

First of all, I do not have a Mac, so I cannot help with strange Mac quirks.

Why are you using the Array#<< method and not assignment ?

And if it is because of a dynamic constant assignment error, then this should tell you that using a constant reference is likely the incorrect solution.

Try using a module @var instead.

The most likely reason you did not see the print filename statement get called is the materials directory folder is empty.
You can test the directory thus …
if Dir.exist?(prog_mt_dir) && !Dir.empty?(prog_mt_dir)

You can also insert a …
puts Dir.getwd
… statement inside the Dir.chdir block to test that the working directory has been changed.

Again shows that the user’s materials directory is empty.
This is normal if the user has not yet saved any custom materials locally to their account.


:question:

What is wrong with the example methods I gave you above ?

Hello.
If the directory is empty why following code works in MAC and material add in list? By using this method I can add any material. For sure directory is not empty and materials are there.

mat = Sketchup.active_model.materials
@f_mat = nil       
filename = 'Materials/Stone/Carrera Marble.skm'
mat_name = File.basename(filename,".skm")
@f_mat = mat["[#{mat_name}]"]
if @f_mat.nil?
  begin
    @f_mat = mat.load(Sketchup.find_support_file(filename))
  rescue => err
    @f_mat = "yellow"
  end
end           

Why is the version 2018 for Mac, but 2021 for Windows ?

What does …

Sketchup.find_support_file(filename)

… return for a path string on your Mac ?


@slbaumgartner Steve, are you having any problems with Dir::glob on Mac for SU2018 (Ruby 2.2.4) or other Ruby version ?

I don’t have 2018 installed on this Mac, but Dir.glob works for the other versions I have.

In the last example snippet @majid866 gave, it works because Sketchup.find_support_file finds the distribution material within the SketchUp app bundle, for example in SU 2021:

/Applications/SketchUp 2021/SketchUp.app/Contents/Resources/Content/Materials/Stone/Carrera Marble.skm

But that’s an entirely different location than the user materials folder in Application Support. Further, if the user has set a location via Preferences->Files, that’s yet a third place a skm could be, and find_support_file doesn’t probe it.

2 Likes

Thanks Steve. This is what I thought. And is why I did this …

… in the example methods above. Ie, I purposefully used a subfolder (“Colors”) that I knew would be in the Program Data path and then stripped that subfolder off in the next statement.

1 Like

I wish to test extensions in different SU versions and OS.

Thank you so much Mr. Dan and @slbaumgartner. It is working now.

            mat = Sketchup.active_model.materials
            mat_path = Sketchup.find_support_file("Materials/Colors")
            prog_path = File.dirname(mat_path)
            Dir.chdir(prog_path) do
              Dir.glob("**/*.{skm,SKM}") { |mt|
                mat.load(File.join(prog_path, mt))
              }
            end

Yes, but it will bloat model files. Have you checked the size before and after ?

Yes, I did. All materials loaded after code. It is interesting. Please see the following code.

mat_path = Sketchup.find_support_file("Materials")
p mat_path
# "/Users/majidmahmoudi/Library/Application Support/SketchUp 2018/SketchUp/Materials"
mat_path = Sketchup.find_support_file("Materials/Colors")
p mat_path
#/Applications/SketchUp 2018/SketchUp.app/Contents/Resources/Content/Materials/Color

And how much does this bloat the file?

File size before code 101KB
File size after code 5.8MB
I used an empty file.

I would call this bloat as the file is 58x larger and you haven’t even begun to draw geometry.

1 Like

I know. Also, I will inform users about it and let them make a choice to load materials or not.

:thinking: :bulb:Just an idea, if that matters to you in your present case…

It may not be necessary to load all materials.

If you use UI.openpanel method, the users can browse and select the one they want.

To get these “nice” thumbnails of materials, of course, assumes that the .skm file association is properly done to Sketchup… in an operating system level. At least on Windows. I 'have No idea about Mac.
The code snippet:

mat = Sketchup.active_model.materials
mat_path = Sketchup.find_support_file("Materials/Colors")
prog_path = File.dirname(mat_path)
chosen_material = UI.openpanel("Open Material File", prog_path, "Material Files|*.skm;*.SKM;||")
if chosen_material
 last_loaded_material = mat.load chosen_material
 puts last_loaded_material.name
  # do something with last_loaded_material 
else
  puts "No material selected."
  # do something else
end

matsel

1 Like