I’m trying to figure out how to open up a group (change context) so that the user is presented with a group that is already active and then they can proceed to edit the geometry (lines and face) within this group.
I’m not seeing a way to do this with the API, but the documentation is so vast I’m sure I’m probably missing it. Can someone lead me in the right direction?
I’m working on the foundation plugin right now and I am trying to provide a means whereby the user can define a new outline for the (polygon) slab-on-grade foundation.
The simplest thing that comes to mind is push all of the points that define the outline/perimeter of the foundation to a group that contains the face constructed from these points. Then the user can modify this face/lines as much as they like and once they are satisfied they click the save settings button of the accompanying HTML menu which then activates the ruby code that grabs this newly edited face and its points and regens the foundation.
close_active will allow me to get back to the root of the model.
active_path will give me a way of checking whether I need to use the previous method to jump back to the root of the model.
Found this gem by Eneroth:
However I don’t see a way of passing a group or component to a method which will then allow me to open up that entity for editing. There has got to be a way to do this, otherwise this is a major hole in the API.
It is! It has been requested for years but apparently it’s quite hard to get it to work the way the backend is written. There are a few hacks like selecting a component and sending a virtual keystroke to enter through an OS API but then you have to implement it for Windows and MacOS separately and may need to update it if those OS APIs ever changes. I’m personally avoiding that kind of extra work.
######################
#
# Open Group for Editing (Windows Only)
if Sketchup.platform == :platform_win
ss = Sketchup.active_model.selection
ss.clear
ss.add(@maingroup)
if ss.length > 1
UI.messagebox "Selection must be limited to one (1) Foundation Assembly."
else
if ss.empty?
UI.messagebox "No Foundation Assembly Selected."
else
first_sel = ss[0]
if first_sel.respond_to?(:definition)
require "win32ole"
win32util = WIN32OLE.new('WScript.Shell')
win32util.SendKeys('{ENTER}')
end
end
end
else
# Mac Solution?
end
The only problem I’m having now is that right before I run this section of code I’m opening up an HTML menu so the focus is taken off of the main SU window. Now I just need to figure out how to bring the focus back to the main window, and also figure out a solution for MacOS.
Well the error message tells you exactly what you’re doing wrong. There is no Ruby constant (class or module) named WScript, ie yet defined within the Ruby ObjectSpace.
… which shows it is a server name (ie, a String object.)
This is a recent Ruby no-no … ie, most SketchUp versions using Ruby 2+.
So Ruby no longer allows the assignment (or reassignment) of constants from within methods.
Or at the least it is warning you, and soon will not be allowed in upcoming versions.
Another feature request “old as the hills” that has not yet been given us. Various hacks exist. (Opening a 1px x 1px webdialog offscreen, and then closing it returns focus to the main application window.)
I’ve been chatting with @john_drivenupthewall how to send an enter (or return) to mac. He uses a utility called “cliclick”.
If you are within your own tool, then you can exit your tool and reenter it, with a special state where you skip the deactivate() and activate(). You of course need to have the instance of your Tool class somewhere.
def open_group
######################
#
# Open Group for Editing (Windows Only)
if Sketchup.platform == :platform_win
ss = Sketchup.active_model.selection
ss.clear
ss.add(@maingroup)
if ss.length > 1
UI.messagebox "Selection must be limited to one (1) Foundation Assembly."
else
if ss.empty?
UI.messagebox "No Foundation Assembly Selected."
else
first_sel = ss[0]
if first_sel.respond_to?(:definition)
require "win32ole"
@win32util = WIN32OLE.new('WScript.Shell')
MedeekMethods.activate_window
@win32util.SendKeys('{ENTER}')
# Edit nested group (not working)
# ss.clear
# ss.add(@Temp_outline_group)
# @win32util.SendKeys('{ENTER}')
end
end
end
else
# Mac Solution?
end
UI.stop_timer(@opentimer)
end
def activate_window
caption = MedeekMethods.get_caption
@win32util.AppActivate caption
end
def get_caption
su_version = Sketchup.version.to_i
if Sketchup.active_model.path.empty? # new model
if Sketchup.is_pro?
if su_version == '17'
caption = "Untitled - SketchUp Pro 2017"
elsif su_version == '18'
caption = "Untitled - SketchUp Pro 2018"
elsif su_version == '19'
caption = "Untitled - SketchUp Pro 2019"
else
caption = "Untitled - SketchUp Pro"
end
else
caption = "Untitled - SketchUp Make 2017"
end
else
filename = File.basename(Sketchup.active_model.path)
if Sketchup.is_pro?
if su_version == '17'
caption = "#{filename} - SketchUp Pro 2017"
elsif su_version == '18'
caption = "#{filename} - SketchUp Pro 2018"
elsif su_version == '19'
caption = "#{filename} - SketchUp Pro 2019"
else
caption = "#{filename} - SketchUp Pro"
end
else
caption = "#{filename} - SketchUp Make 2017"
end
end
return caption
end
I have to call the open_group method with a timer because of the HTML dialog so after my dialog is launched I call this:
Note that I’m actually trying to edit a nested group with my main group. So I actually need to select the main group, open it then select the group inside and open it.
When I try to add the nested group to the selection set and then press enter it appears to jump me out of the editing of the main group so this is not working.
P.S. For now I’ve just commented out the logic that tries to open up the nested group. At least I can get one level deep. It is then up to the user to click into the nested group to edit it.
I think a quite big question is why you want to open a component. For e.g. a layer panel/outliner it is a required functionality, but perhaps your plugin can be designed to simply not do this.
Inside of this group is a face which defines the outline or perimeter of the slab-on-grade foundation. The user can edit this face to any geometry they like and then hit the update / commit button and the plugin will then utilize this updated face to regenerate the slab-on-grade foundation with the new perimeter.
Technically a user could just recreate their foundation from scratch with a new face (to define the outline) however people always want that parametric ability, so I have to provide it.
I’m also using this method to jump out of the possible nested scenarios prior to regenerating the foundation:
def move_to_root
path1 = (Sketchup.active_model.active_path || [])
instance1 = path1.last
if instance1 == @Temp_outline_group
Sketchup.active_model.close_active
path2 = (Sketchup.active_model.active_path || [])
instance2 = path2.last
if instance2 == @maingroup
Sketchup.active_model.close_active
end
elsif instance1 == @maingroup
Sketchup.active_model.close_active
end
end
This is pretty basic stuff when you have the right methods available to you. It would really be nice if there was a method available to open a group or component rather than having to try and make it work with a hack job.