In our tool management class ToolManager, there is a lot of duplication in the code for creating toolbars. Each toolbar button is created through the following steps
- Loading tool class
- Creating Tool Objects
- Create Tool Activation Command Objects
- Add Tool Activation Command to Toolbar
Creating tools to activate command objects can be complex, such as setting icons, prompt text, status bar text, etc.
If these operations are categorized simply, the creation tool activation command object can be extracted and put into each tool to do, including creating command object, setting icons and so on. Because each tool should know what buttons it should represent, which belongs to the "individual" content. Tool management objects don't need to pay attention to these. They only deal with the toolbars with what names they create and where they should be added to the toolbars, which belongs to the "group" content. Therefore, we can modify the tool class and tool management class to make it more convenient and flexible to add tools.
Tool class
The transformation of tool class mainly involves two parts:
- Create Tool Activation Command Objects
- Personalized icons and prompt text
Tool management class should only focus on the command objects created by tools. In order to deal with them uniformly, we should add a common interface to the tools to obtain the command objects of tools. This can be achieved by ruby's blending module or class inheritance. For flexibility, we use the way of blending module here. First, you need to define a module for tool commands, in which you implement a method to create tool activation command objects.
# Tool Command Module module ToolCommand # Get the SketchUp command def command cmd = UI::Command.new('Tool name') do Sketchup.active_model.select_tool(self) end end end
Then mix this module into each tool so that each tool has a command method to create commands that activate itself.
require 'free_wall/tool/tool_command' class DrawWallTool include ToolCommand ...
For a complete plug-in, tools should have their own icons, prompt text and other personalized information, so we should set up these information when creating commands, and these information should be defined in each tool.
class DrawWallTool include ToolCommand def initialize @menu_text = 'Wall Painting Tool' @large_icon = File.join(File.dirname(__dir__), 'resource/img/draw_wall_tool.jpg') @small_icon = File.join(File.dirname(__dir__), 'resource/img/draw_wall_tool.jpg') @status_bar_text = 'Wall Painting Tool' @tooltip = 'Draw lines to create a wall' end ...
This information is then applied uniformly when creating commands
def command menu_text = @menu_text ? @menu_text : 'Unnamed Tools' cmd = UI::Command.new(menu_text) do Sketchup.active_model.select_tool(self) end cmd.large_icon = @large_icon if @large_icon cmd.small_icon = @small_icon if @small_icon cmd.status_bar_text = @status_bar_text if @status_bar_text cmd.tooltip = @tooltip if @tooltip cmd end
In this way, we can create personalized commands for tools, and when added to the toolbar, we can see that different tools have different display effects.
Tool Management Class
Load definition
The first step in the tool management class is to load the definition of the tool class. Since our tools are all defined in the tool directory, we can actually traverse the directory to load all ruby files.
tool_dir = File.join(__dir__, 'tool') Dir.entries(tool_dir).each { |file| file_path = File.join(tool_dir, file) next unless File.file?(file_path) require(file_path) }
After that, we should define the name of the toolbar we created and how the toolbar should lay out the specific tools, which can actually be defined by a hash table.
TOOLBAR_LIST = { 'Wall toolbar' => [DrawWallTool, CreateHoleTool] }.freeze
key is the name of the toolbar and value is the list of tools. This allows you to create all the tools through a single traversal.
Special elements can also be added to the list of tools to mark them as separators, such as adding a nil element between the two tools and creating a separator if nil elements are encountered while traversing the create tool button.
# Create toolbars def create_toolbar TOOLBAR_LIST.each { |name, tools_klass| tool_bar = UI::Toolbar.new(name) tools_klass.each { |tool_klass| if tool_klass tool = tool_klass.new tool_bar.add_item(tool.command) else tool_bar.add_separator end } } end
If you want to control the action of clicking the button when creating the toolbar, you can also replace the command of activating the tool when creating the toolbar with the execution of the block, and add the specific behavior when creating the toolbar to obtain the tool command.
... cmd = UI::Command.new(menu_text) do yield end ... ... cmd = tool.command { Sketchup.active_model.select_tool(tool) } ...
After such modification, when adding a new tool, you only need to add the class definition of the new tool to the specific location of the toolbar in TOOLBAR_LIST. And even with the same tool, we can add to different toolbars, and the behavior in each toolbar can be controlled.