# \[code\] undoable place\_component() "MoveTool" clone

**URL:** <https://forums.sketchup.com/t/code-undoable-place-component-movetool-clone/27193>\
**Category:** Ruby API\
**Created:** [June 28, 2016, 10:58pm UTC](https://forums.sketchup.com/t/code-undoable-place-component-movetool-clone/27193 "2016-06-28T22:58:01Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [June 28, 2016, 10:58pm UTC](https://forums.sketchup.com/t/code-undoable-place-component-movetool-clone/27193/1 "2016-06-28T22:58:01Z")

</div>

Continuing the discussion from:

[Model.place\_component component\_definition, boolean cannot be undone?](http://forums.sketchup.com/t/model-place-component-component-definition-boolean-cannot-be-undone/17165):

Here is an **example** of a **single undoable** place component operation.

**It is not a tool, rather it is a command.**

It achieves the single undo, via 3 linked operations. The first is attached to the following **`model#place_component()`** operation, and the last is attached to it’s predecessor.

It can move both compound (groups, images and component instances,) and primitive objects.

[move\_selection\_set.rb](https://forums.sketchup.com/uploads/short-url/llfZG7k6oVZGf4L0mFjN4KAXWe3.rb) (1.9 KB)

* * *

```ruby
# encoding: UTF-8

module Author; end
module Author::SomePlugin

  extend self
  
  unless defined?(@@loaded)
    @@opname ||= "MoveObjects"
  end
  
  class DefSpy < Sketchup::DefinitionObserver
    OUTER = Module::nesting[1]
    def onComponentInstanceAdded(definition, instance)
      definition.remove_observer(self)
      UI.start_timer(1.0,false) {
        OUTER::remove_definition(definition, instance)
      }
    end
  end

  def move_selection_set(sel)
    #
    choice = UI::messagebox("Erase original selection ?",MB_YESNO)
    #
    return if choice == IDCANCEL
    #
    mod = sel.model
    ents = mod.active_entities
    mod.start_operation(@@opname,true,true)
      #
      cdef = mod.definitions[@@opname]
      if cdef
        cdef.clear! if cdef.entities.size > 0
        grp = cdef.entities.add_group(sel.to_a)
        t = grp.transformation
        grp.explode
        if choice != IDYES
          ents.add_instance(cdef,t)
        end
      else
        grp = ents.add_group(sel.to_a)
        ins = grp.to_component
        cdef = ins.definition
        cdef.name= @@opname
        if choice == IDYES
          ins.erase!
        else
          ins.explode
        end
      end
      #
    mod.commit_operation
    #
    cdef.add_observer(DefSpy::new)
    mod.place_component(cdef)
    #
  end ###

  def remove_definition(definition, instance)
    #
    mod = definition.model
    mod.start_operation(@@opname,true,false,true)
      #
      instance.explode rescue nil
      if mod.definitions.respond_to?(:remove)
        mod.definitions.remove(definition)
      else # pre-2018
        definition.entities.clear! rescue nil
      end
      #
    mod.commit_operation
    #
  end ###

  if !defined?(@@loaded)
    UI.add_context_menu_handler {|popup|
      sel = Sketchup.active_model.selection
      if !sel.empty?
        popup.add_item(@@opname) { move_selection_set(sel) }
      end
    }
    @@loaded = true
  end

end

```

* * *

Tested in SketchUp 2016.

[2021-JAN-19] Updated to use [`DefinitionList#remove`](https://ruby.sketchup.com/Sketchup/DefinitionList.html#remove-instance_method) in SketchUp version 2018+.

---

<div class="post-metadata">

**Author:** ![creators](https://avatars.discourse-cdn.com/v4/letter/c/db5fbb/32.png) [@creators](https://forums.sketchup.com/u/creators)\
**Post date:** [January 19, 2021, 3:27am UTC](https://forums.sketchup.com/t/code-undoable-place-component-movetool-clone/27193/2 "2021-01-19T03:27:34Z")

</div>

#1.Load model  
model = Sketchup.active\_model  
abc\_path = ‘C:\Users\jekye\Desktop\11.skp’  
abc\_def = model.definitions.load abc\_path  
model.place\_component(abc\_def)

#2.How can I explode the load model at the same time?  
Sketchup.active\_model.selection[0].explode

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [January 19, 2021, 12:54pm UTC](https://forums.sketchup.com/t/code-undoable-place-component-movetool-clone/27193/3 "2021-01-19T12:54:20Z")

</div>

Please fix your post …

- [[How to] Post correctly formatted and colorized code on the forum?](https://forums.sketchup.com/t/how-to-post-correctly-formatted-and-colorized-code-on-the-forum/46189)

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [January 19, 2021, 1:04pm UTC](https://forums.sketchup.com/t/code-undoable-place-component-movetool-clone/27193/4 "2021-01-19T13:04:23Z")

</div>

> [@creators](#):
>
> #2.How can I explode the load model at the same time?

You _might_ need to implement a `DefinitionObserver` as shown in the example above. After the instance is placed, in the `onComponentInstanceAdded` callback method you can start a timer that will explode the instance. The **tricky** part is that you should not do this until after SketchUp is done notifying **all** observers about the new instance object.

Also within the timer block you can purge the just loaded definition (`abc_def`) using the [`Sketchup::DefinitionsList#remove`](https://ruby.sketchup.com/Sketchup/DefinitionList.html#remove-instance_method) method that was added to the API since this example was posted.

---

<div class="post-metadata">

**Author:** ![creators](https://avatars.discourse-cdn.com/v4/letter/c/db5fbb/32.png) [@creators](https://forums.sketchup.com/u/creators)\
**Post date:** [March 7, 2021, 3:58am UTC](https://forums.sketchup.com/t/code-undoable-place-component-movetool-clone/27193/5 "2021-03-07T03:58:57Z")

</div>

I just learned, I don’t know how to write. Can you help me improve it and write it down? thank you!

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [March 8, 2021, 3:04pm UTC](https://forums.sketchup.com/t/code-undoable-place-component-movetool-clone/27193/6 "2021-03-08T15:04:18Z")

</div>

> [@creators](#):
>
> I just learned, I don’t know how to write.

If **you** would like to learn to **code** Ruby extensions, you can start here …

> [@Ruby Learning Resources \[WikiLists\]](https://forums.sketchup.com/t/ruby-learning-resources-wikilists/22861):
>
> All seven of the lists below are set as wikis. card_index INDEX [notebook PRIMERS & GUIDES](http://forums.sketchup.com/t/ruby-learning-resources/22861/2)[books BOOKS](http://forums.sketchup.com/t/ruby-learning-resources/22861/3)[mortar_board TUTORIALS](http://forums.sketchup.com/t/ruby-learning-resources/22861/4)[card_box REFERENCE](http://forums.sketchup.com/t/ruby-learning-resources/22861/5)[clipboard TEMPLATES](http://forums.sketchup.com/t/ruby-learning-resources/22861/6)[newspaper NEWS](http://forums.sketchup.com/t/ruby-learning-resources/22861/7)[bulb IDEAS](http://forums.sketchup.com/t/ruby-learning-resources/22861/8)

> [@creators](#):
>
> Can you help me improve it and write it down?

This topic thread and it’s **example** is written the way it is by design. It serves it’s purpose, as stated in the topic title.

Feel free to use it as a starting point. Modify it for your own use. (But I will not be modifying this example here in this topic thread.)

However, it uses operations and observers which are advanced API concepts. It will will take quite some time for a new coder to become familiar and confident in event-driven coding to use these concepts.

We ask here in this forum category that coders at least **try** to solve their own problems, and ask **specific** coding questions. It is **not appropriate** to ask others here in this category to do your work for you.

* * *

If you do not have the time or inclination to learn Ruby programming, then you can hire an experienced coder to do it for you. Please post such a request in the Commercial category:

- [Commercial and Collaborative Work - SketchUp Community](https://forums.sketchup.com/c/commercial-collaborative-work/33)
