So after reading quite a bit, I’m still unable to figure out how to deal with the asynchronousity of ruby:
My extension builds a component on command and allows the user to place it in his model. If he repeats the command with the same dimensions, a second component is made by the same name but with the addition of ‘#1’, as you know.
I made a cleaning snippet that cleans those # components out if they are equal to the first one.It needs to wait after the placement of the component.
How to tell ruby to wait for it?
I’m not sure I understand exactly …
Actually it as happening if you are adding or loading new component definition to the DefinitionList with the same name.
(BTW: there is bug in SU2022, related to this, where this “numbering” will not happen )
Do you mean you want to watch when a new definition is added to the list?
If yes, there is an Sketchup::DefinitionsObserver for that purpose.
Or do you want to listen when the instance of specific definition added? Use Sketchup::DefinitionObserver
Or you check the DefinitionList if the definition with the specific name already exist in it and simple you will not create a new or load it again but use the existing.
This has been discussed before. I remember because I was involved in the discussion and posted several examples. See my old reply here …
Hum… I do not experience this bug here with place_component.
Thanks for the clues. Appreciated.
Yes, because
place_component
is placing an instance and does not affect the DefinitionList- You are using SU2021 (according to your profile)
ahg… I have been trying to update profile. still looking to find where.
I’m using 2022 on Mac M1.
Click on your Avatar top right of the browser window.
Click on the head and shoulders icon, then ‘Preferences’:
Then ‘Profile’ within ‘Preferences’, then the License Type and SketchUp Version entries, and reset them.
Thanks John, for some reason I was not seeing the ‘Profile’ option in the preferences. Too tired, I guess.
Back to the topic. I would really like place_component to not switch automaticaly to the Move tool. I often found that annoying while working and it seems to be causing trouble in coding also. Wonder if this what is preventing a normal resume of scripts from the GUI, after the component is put.
@john_mcclenahan and I have faced a similar problem in an extension we are working on, and in our case the behavior of place_component can actually lead to a SketchUp crash (multiple BugSplats submitted, no response yet from the developers). I think the core issue is that place_component in the Ruby API is badly conceived. I think that (like some other API calls such as send_action) it just queues up the action until Ruby relinquishes control to the GUI, rather than suspending the current Tool and reactivating it on completion. There are other native tools such as orbit and pan that suspend/resume the current Tool, so it seems this should have been possible…
Yes indeed, script not resuming is pretty hard on development.
code snippet
possible custom “place component” (concept, do not use at it is!)
(Assuming there is a definition already in a model, or you can create your own an pass it as argument)
module Dezmo
class MyPlaceCompTest
def initialize(definition)
@ip0 = Sketchup::InputPoint.new
@defi = definition
@instance = nil
end
def onCancel(reason, view)
puts "MyTool was canceled for reason ##{reason} "
@instance.erase! if @instance && @instance.valid?
#The pop_tool method is used to pop the last pushed tool on the tool stack.
Sketchup.active_model.tools.pop_tool() if reason == 0
view.invalidate
end
def deactivate(view)
puts "Your tool has been deactivated in view: #{view}"
@instance.erase! if @instance && @instance.valid?
view.invalidate
end
def add_instance(tr)
Sketchup.active_model.active_entities.add_instance(@defi, tr)
end
def onMouseMove(flags, x, y, view)
@ip0.pick(view, x, y)
tr = Geom::Transformation.translation(@ip0.position)
@instance = add_instance(tr) unless @instance
ti_inv = @instance.transformation.inverse
@instance.transform!(tr * ti_inv)
view.invalidate
end
def onLButtonDown(flags, x, y, view)
@instance = nil
view.invalidate
end
def draw(view)
@ip0.draw(view) if @ip0.display?
view.tooltip = @ip0.tooltip if @ip0.valid?
end
end #class
end #module
model = Sketchup.active_model
definition = model.definitions[0]
model.tools.push_tool(Dezmo::MyPlaceCompTest.new(definition))
The problem is that #place_component
also closes any open operation and creates a new operation.
It is not likely that this method will change as we discussed in the issue tracker. Rather a new method would need to be implemented. See:
-
Model#load_and_place_component · Issue #6 · SketchUp/api-issue-tracker · GitHub
-
place_component callback · Issue #279 · SketchUp/api-issue-tracker · GitHub
I also posted an example DragTool quite some time (4 years) ago …
Oh yes, It is certain that yours will handle a undo stack much better …
While mine just a finger exercise…
Both of your methods prove the point, I’d say.
A developper should not have to resort to work (hard) around, in this case.
I should post a request on GitHub API issue tracker. Or comment the ones already there.
Please comment in the existing issues.
You can “wait” for the placement with a temporary observer. The most robust way to catch the placement is to listen to the tool change from place_component
to move and use the fact that the selection will contain the placed instance. Something like:
module PlaceComponentTest2000
class PlaceComponentObserver
def initialize()
Sketchup.active_model.tools.add_observer(self)
end
def onActiveToolChanged(tools, tool_name, tool_id)
# Ignore orbit and place_component
return if [10508, 21013].include?(tool_id)
Sketchup.active_model.tools.remove_observer(self)
sel = Sketchup.active_model.selection
if sel.length == 1 && sel.first.is_a?(Sketchup::ComponentInstance)
PlaceComponentTest2000.post_placement(sel.first)
end
end
end
def self.post_placement(instance)
puts "The component is placed"
end
def self.main
Sketchup.active_model.place_component(Sketchup.active_model.definitions.first, false)
PlaceComponentObserver.new
# execution will resume in post_placement
end
main
end
Thanks Caul.
Interesting indeed. Studying.
update: That did the trick. Good intro to observers for me.
What appealed to me in that suggestion is that it did not seemed out of reach for my level of knowledge. Which is a little higher now, btw.