Inkscape.org
Creating New Extensions Add Selection as symbol extn
  1. #1
    RuaridhW RuaridhW @RuaridhW

    I was hoping to make a very basic extn to do the same as the plus button action in the symbol library. Initially so i can create a keyboard shortcut for this action, but with the cunning plan to make it a batch process to add multiple selected objects individually; rather than have them all grouped and added as a single symbol.

    I'm sure i'm doing something embarrassingly simple wrong as well as misunderstanding this https://inkscape.gitlab.io/extensions/documentation/source/inkex.elements._use.html?highlight=symbol#inkex.elements._use.Symbol 

    Have tried and failed with a large variety of different approaches, but the basic approach has been along the lines of:

    import inkex
    class addasymbol(inkex.EffectExtension):

        Use(self.svg.selection)
        
    if __name__ == "__main__":
        addasymbol().run()
     

  2. #2
    inklinea inklinea @inklinea⛰️
    from inkex import Symbol
    selection_list = self.svg.selected
    
    if len(selection_list) < 1:
        inkex.errormsg('Nothing Selected')
        return
    
    svg_defs = self.svg.defs
    
    new_symbol = Symbol()
    
    for selected_object in selection_list:
        new_symbol.append(selected_object)
    
    svg_defs.append(new_symbol)

     

  3. #3
    RuaridhW RuaridhW @RuaridhW

    Oh wow thank you so much!

  4. #4
    RuaridhW RuaridhW @RuaridhW
    *

    Thank you again for the steer. I feel i'm nearly there applying the add_symbol action for each selected object, however, I am hitting a wall on how to create the symbol title element.
    The closest i've gotten is appending a group to the symbol element, but the title name doesn't migrate to the symbol library; I'm assuming that the dialogue looks for the title element:
    This is what i've gotten it down to, but no dice:

        old_title = getattr(selected_object,'title')
        svg_defs.makeelement('Title')
        new_title = Title()
        new_title_id = get_ids('title')
        new_title.set(new_title_id,old_title)
        new_symbol.append(new_title)

    This is the group code that runs but doesn't work as hoped:
      

        old_title = getattr(selected_object,'title')
        new_title = Group()
        new_title.set('title',old_title)
        new_symbol.append(new_title)
        svg_defs.append(new_symbol)

    Full code is:        

            selection_list = self.svg.selected
    
            if len(selection_list) < 1:
                inkex.errormsg('Nothing Selected')
                return
            else:
                
            svg_defs = self.svg.defs
            svg_toplevel = self.svg
    
            for selected_object in selection_list:
                new_symbol = Symbol()
                new_symbol.append(selected_object)
    
    
                old_title = getattr(selected_object,'title')
                svg_defs.makeelement('Title')
                new_title = Title()
                new_title_id = get_ids('title')
                new_title.set(new_title_id,old_title)
                new_symbol.append(new_title)
                svg_defs.append(new_symbol)
    
                new_use = Use()
                new_use_href = f'#'+str(new_symbol.get_id())
                new_use.set('xlink:href', new_use_href)
                svg_toplevel.append(new_use)

    Any advice would be most aprreciated, as i've obvously bitten off more than i can chew!

  5. #5
    inklinea inklinea @inklinea⛰️

    title is an attribute of the symbol tag.

    All that is needed is 

    new_symbol.set('title', 'hello')

    to destroy an attribute you can use: 

    new_symbol.set('title', None)

    You should not need to use getattr at the object level. 

    If you want to add the object to the symbol library without deleting the object you can simply use ( for any object )

    dupe_object = object.duplicate()

    Then make the symbol from either the original or the dupe.

     

  6. #6
    RuaridhW RuaridhW @RuaridhW

    First off wow thx for the uber rapid reply. But unfortunately that method just alters the symbol element title not add a separate element; the latter seems to be required by the symbols dialogue. see attached

    this is the code i used just in case i've done something idiotic:

    new_symbol = Symbol()
    new_symbol.append(selected_object)
    old_title = getattr(selected_object,'title')
    new_symbol.set('title', "squirrel")
    svg_defs.append(new_symbol)

     

    Symbol Xml2
  7. #7
    inklinea inklinea @inklinea⛰️

    I'm not 100% sure what you want to do. 

    If you have created a symbol, when you drag it to the canvas, Inkscape creates a <use> element.  https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use

    The <use> element references another node in the document ( in this case the symbol in question ) 

    The ID assigned to the <use> element is determined by Inkscape. 

    If you want to have symbols dragged to the canvas have a custom ID or any other custom attribute, then it can be done but would require writing a dynamic extension GUI using GTK3

    Unless I have understood the question incorrectly ? 

     

  8. #8
    RuaridhW RuaridhW @RuaridhW
    *

    Hi there, sorry so overall i am trying to make a workaround for the following 2 features of the GUI add-symbol functionality:

    -If you drag a selection of multiple objects into the symbol window they are grouped and added as a single symbol.

    -There is no shortcut verb available for add-symbol

    this means that when I am considering making a number of symbol libraries each with 2/400 objects drag and drop, or select and click'+' one by one is not really something i can face; yes i realise that i'll have spent way longer making an extension than it would have taken to do it that way but i could could get it to work i'm sure others would find it useful in the future.

    Also once i have it working i'd then know enough to monkey about with the code and force the library to display the symbols in some sort of order, e.g. alphabetical or coordinate, rather than only in added order.

    Sorry if you were referring to my last post then the GUI add_symbol changes XML seems to apply a symbol() and a use() referencing that symbol...

    but it also inserts an additional element <title id>  into the symbol element that is a duplicate of the subordinate object/path's <title id>  but at the object/path level.

    The importance of this is that the symbol label in the GUI library shows the symbol ID by default unless this object level title id is present; new_symbol.set('title', 'display_label') works but doesn't supersede symbol_id in the library. I can use my current code and then duplicate the object's title_id node and unindent it once and then when the saved and reopened the doc has the correct label in the library:

      <defs id.............
        <symbol id="symbol5">
          <path id="path4" .....>
            <title id="title4">BlueBox1</title>
          </path>
          <title id="title5">BlueBox1</title>
        </symbol>
      <use xlink:href="#symbol5" id="use5" />

    Currently method only get this:

        <defs id.............
        <symbol title="test title" id="symbol5">
          <path id="path4" .....>
            <title id="title4">BlueBox1</title>
          </path>
        </symbol>
      <use xlink:href="#symbol5" id="use5" />

    BTW i really appreciate you taking the time to even look at all of this, let alone trying to help me resolve issue i should be able to sort myself.

  9. #9
    RuaridhW RuaridhW @RuaridhW

    Ok so finally worked out what i was doing wrong and the answer was predictably painfully simple.

    So for anyone wanting a bulk add symbol extension that adds each selected object individually and can then create a keyboard short cut for... have at it

    """ This functions the same as the gui add_symbol action v1.3"""
    """ but also adds each selected object individually rather than grouped as a single symbol"""
    """ and allows you to create a keyboard shortcut to extension to action add_symbol"""
    """ will need to create an associated .inx to add to extensions menu"""
    
    import inkex
    from inkex import Symbol, Use, Title
    
    class addasymbol(inkex.EffectExtension):
    
        def effect(self):
            selection_list = self.svg.selected
    
            if len(selection_list) < 1:
                inkex.errormsg('Nothing Selected')
                return
                
            svg_defs = self.svg.defs
            svg_toplevel = self.svg
            
            """Cycles through each selected object"""
            for selected_object in selection_list:
                """sets up selected_object a symbol"""
                new_symbol = Symbol()
                new_symbol.append(selected_object)
    
                """Retrieves the title from original object and adds as symbol title/label"""
                """will default to symbol ID if no title found"""
                old_title = getattr(selected_object,'title')
                if old_title !=None:
                    new_title = Title(old_title)
                    new_symbol.append(new_title)
    
                """ adds symbol to Defs"""
                svg_defs.append(new_symbol)
    
                """ creates Use element and links to new symbol"""
                new_use = Use()
                new_use_href = f'#'+str(new_symbol.get_id())
                new_use.set('xlink:href', new_use_href)
                svg_toplevel.append(new_use)
                
            
    if __name__ == "__main__":
        addasymbol().run()