Help optimize this simple material file browser!

This is a simple .skm material file management browser that runs on windows.
The principle of implementation is to read the user’s stored .skm folder, generate menus and display .skm thumbnails.
Users can click on the thumbnail to apply the material to the scene object.

The customization part of this plugin:
TMP_THUMBNAIL_BASE_DIR = “D:/_iFile/tem” #Thumbnail storage location
map5 = [“D:/_iFile/Maps”] # Directory of .skm files

The current interactive experience is not very good, there are mainly the following problems:
1、Only display the first level menu , can not support multi-level menu .
2, a menu menu display content for the current menu contains all the contents of the sub-folder , can not be good at all levels of the menu to display their own content.

I look forward to understanding the optimization of friends to help

require 'sketchup.rb'
require 'extensions.rb'

 # Attempt to load the rubyzip library
begin
  require 'zip'
rescue LoadError # If loading fails, try installing the rubyzip library
  puts "The rubyzip library is not installed, trying to install..."
  system("gem install rubyzip")
  require 'zip'
end

class Lite_maplib
  TMP_THUMBNAIL_BASE_DIR = "D:/_iFile/tem" #Thumbnail storage location
  IMAGE_EXTENSIONS = ['.jpg', '.png', '.skm']

  def initialize
    @count = 0
  end

  def maplib
    model = Sketchup.active_model
    map = []
    map5 = ["D:/_iFile/Maps"] # Directory of .skm files
    map5.each do |hmn|
      map << hmn.rstrip if File.exist?(hmn.rstrip)
    end
    map_path2 = []
    map.each do |path|
      Dir.glob("#{path}/*").select { |dir| File.directory?(dir) }.each do |subfolder|
        all = load_images_and_skm_files(subfolder)
        map_path2 << [all, File.basename(subfolder), subfolder] if all.any?
        @count += all.size
      end
    end
    menu, pic = generate_html_content(map_path2)
    html = generate_html(menu, pic)
    show_dialog(html)
    setup_callbacks
  end

  def load_images_and_skm_files(subfolder)
    all1 = Dir.glob("#{subfolder}/**/*.jpg")
    all2 = Dir.glob("#{subfolder}/**/*.png")
    allskm = Dir.glob("#{subfolder}/*.skm")
    all1 + all2 + allskm
  end

  def generate_html_content(map_path2)
    menu = ""
    pic = ""

    map_path2.each_with_index do |folder, index|
      menu << %(<li onclick="showFolderContents('#{index}')"><a href="#"> #{folder[1]} </a></li>\n)
      pic << %(<div class="xl-box" id="folder-#{index}" style="display:#{index == 0 ? 'block' : 'none'}">\n)

      folder[0].each do |image|
        pic << generate_image_html(image)
      end

      pic << %(</div>\n)
    end

    [menu, pic]
  end

  def generate_image_html(image)
    file_type = File.extname(image)
    absolute_path = File.expand_path(image) # Get absolute path
    if [".jpg", ".png"].include?(file_type)
      %(<input type="image" id="#{absolute_path}" src="#{absolute_path}" title="#{File.basename(image)}" width="80" height="80" onclick="return getid(this.id)" value="#{absolute_path}">\n)
    elsif file_type == ".skm"
      thumbnails = extract_skm(image)
      if thumbnails.any?
        %(<input type="image" src="#{thumbnails[0]}" title="#{File.basename(image)}"width="80" height="80" onclick="return applyMaterial('#{absolute_path}')">\n)
      else
        puts "Thumbnail not found: #{image}"
        ""
      end
    else
      ""
    end
  end

  def generate_html(menu, pic)
    %Q[
<!DOCTYPE html>
<html>
<head>
<title>maplib</title>
<meta charset="utf-8">
</head>
    <style>
      * {}
      a {text-decoration: none;color:#ccc;}
      body, html {margin: 0;padding: 0;height: 100%;background-color: #444;}
      .container {display: flex;height: 100%;}
      .nav {width: 150px;padding: 10px;box-sizing: border-box;background-color: #515151;}
      .main {flex: 1;padding: 20px;box-sizing: border-box;}
      ul {padding-inline-start: 5px;font-family: "YaHei", "Microsoft YaHei", sans-serif;}
      li {height: 30px;box-sizing: border-box;list-style: none;}
      ul li a{display:block;width:100%;}
      ul li a:hover{color:#fff;}
      .xl-box {display: none;}
  </style>
<body>
  <div class="container">
    <div class="nav">
      <ul class="ul">
        #{menu}
      </ul>
    </div>
  <div class="main">
    <div>
      #{pic}
    </div>
  </div>
</div>
<script>
  function getid(id) {
   var user_input1 = document.getElementById(id);
   sketchup.getUserInput01(user_input1.value);
  }

  function applyMaterial(skm_path) {
   console.log("Applying material from: " + skm_path); // 输出路径
   var skm_name = skm_path.split('/').pop();
   sketchup.applyMaterial(skm_path); // 传递绝对路径
  }

  function showFolderContents(folderIndex) {
   var boxes = document.getElementsByClassName("xl-box");
   for (var i = 0; i < boxes.length; i++) {
       boxes[i].style.display = "none";
     }
     var activeBox = document.getElementById("folder-" + folderIndex);
     if (activeBox) {
         activeBox.style.display = "block";
       }
       }

       document.addEventListener("DOMContentLoaded", function() {
                                   showFolderContents(0);
       });
    </script>
  </body>
</html>
       ]
   end

   def show_dialog(html)
     $dlg = UI::HtmlDialog.new({
                                 dialog_title: "Lite maplib (AllSKM#{@count})",
                                 preferences_key: "Cgmg_map_dlg",
                                 scrollable: true,
                                 resizable: true,
                                 width: 600,
                                 height: 600,
                                 style: UI::HtmlDialog::STYLE_DIALOG
     })

     $dlg.set_html(html)
     $dlg.show
     $dlg.bring_to_front
   end

   def setup_callbacks
     $dlg.add_action_callback("getUserInput01") { |action_context, user_input1|
       maplib_Paint = File.basename(user_input1, File.extname(user_input1))
       model = Sketchup.active_model
       materials = model.materials
       unless materials[maplib_Paint]
         material = materials.add(maplib_Paint)
         material.texture = user_input1
       end
       materials.current = materials[maplib_Paint]
       Sketchup.send_action('selectPaintTool:')
     }

     $dlg.add_action_callback("applyMaterial") { |action_context, skm_path|
       skm_path = File.expand_path(skm_path)
       puts "Received skm path: #{skm_path}" # Output received path
       load_skm_material(skm_path)
     }
   end

   def load_skm_material(skm_path)
     model = Sketchup.active_model
     materials = model.materials
     skm_name = File.basename(skm_path, File.extname(skm_path))

     puts "Path to the material file to try to load: #{skm_path}"

     if File.exist?(skm_path)
       begin
         load_file(skm_path, "Loading material")
       rescue => e
         puts "Failed to load material file: #{e.message}"
         return
       end

       material = materials[skm_name]
       if material
         materials.current = material
         Sketchup.send_action('selectPaintTool:')
         puts "Applied Materials: #{skm_name}"
       else
         puts "Material does not exist: #{skm_name}"
       end
     else
       puts "File does not exist: #{skm_path}"
     end
   end

def extract_skm(skm_path)
  skm_dir = File.dirname(skm_path)
  skm_name = File.basename(skm_path, '.skm')
  thumbnail_dir = File.join(TMP_THUMBNAIL_BASE_DIR, skm_name)
  Dir.mkdir(thumbnail_dir) unless Dir.exist?(thumbnail_dir)

  thumbnail_path = File.join(thumbnail_dir, "doc_thumbnail.png")

  # 检查缩略图是否已经存在
  if File.exist?(thumbnail_path)
    puts "Thumbnail already exists: #{thumbnail_path}"
    return [thumbnail_path]
  else
    thumbnails = []
    Zip::File.open(skm_path) do |zip_file|
      zip_file.each do |entry|
        if entry.name == "doc_thumbnail.png"
          File.delete(thumbnail_path) if File.exist?(thumbnail_path)
          entry.extract(thumbnail_path)
          thumbnails << thumbnail_path
          puts "Extracted successfully: #{thumbnail_path}"
        end
      end
    end
    thumbnails
  end
end

   def load_file(path, _status)
     model = Sketchup.active_model
     material = model.materials.load(path)
     model.materials.current = material
     UI.start_timer(0.1) { Sketchup.send_action("selectPaintTool:") }
   end
 end

 menu = UI.menu('Extensions')
 menu.add_item("lite map lib") { Lite_maplib.new.maplib }

In your forum profile you mentioned “License Type: Free Plan” “SketchUp Version: 2022”.
There is no free version of SU2022, are you using the cracked version?

1 Like

Each extension’s code should be totally within a unique namespace module (and usually within a submodule of your author namespace module,)

This is what the native Materials inspector panel does.

How would your interface be any different?