Example #1
0
 def delete_items(self, items, redraw=1, delete_single_atom=1):
     """deletes items and also makes cleaning of orphan bonds and atoms"""
     if not items:
         return items, []  # quick way to avoid costly evaluation
     deleted = copy.copy(items)
     for o in items:
         if o.object_type == 'atom':
             self.delete_atom(o)
         else:
             self.delete_bond(o)
     if self.atoms:
         # delete bonds that are not in connect anymore
         bonds_in_connect = set()
         for a in self.atoms:
             for (e, v) in a.get_neighbor_edge_pairs():
                 if v in self.atoms:
                     bonds_in_connect.add(e)
         deleted += [
             self.delete_bond(o) for o in (self.bonds - bonds_in_connect)
         ]
         # delete also orphan atoms
         if delete_single_atom:
             atms = [o for o in self.atoms if len(o.neighbors) == 0]
             deleted += [self.delete_atom(o) for o in atms]
         # recalculation of second line of double bond position, optimized to do it only when realy
         # necessary, because its pretty expensive
         # check_integrity should be called before redrawing, because it moves atoms and bonds
         # to new molecules when the molecule is spit and avoids working on non-connected graph
         offspring = self.check_integrity()
         if redraw:
             bonds_to_redraw = []
             for b in deleted:
                 if b.object_type == 'bond':
                     for a in b.atoms:
                         if a in self.atoms:
                             bonds_to_redraw.extend(a.neighbor_edges)
             [
                 o.redraw(recalc_side=1)
                 for o in misc.filter_unique(bonds_to_redraw)
                 if o.order == 2 and o.item
             ]
             [o.decide_pos() for o in self.atoms if isinstance(o, atom)]
             [o.redraw() for o in self.atoms]
     else:
         offspring = self.check_integrity()
         deleted += map(self.delete_bond, copy.copy(self.bonds))
     return deleted, offspring
Example #2
0
    def handle_overlap(self):
        "deletes one of overlaping atoms and updates the bonds"
        to_delete = []
        bonds_to_check = set(
        )  # this can speedup the following for b in bonds_to_check by factor of 10 for big mols
        for i in range(len(self.atoms)):
            for j in range(i + 1, len(self.atoms)):
                a = self.atoms[i]
                b = self.atoms[j]
                if (abs(a.x - b.x) < 4) and (abs(a.y - b.y) < 4):
                    if a not in to_delete:
                        for e, v in b.get_neighbor_edge_pairs():
                            e.change_atoms(b, a)
                            a.add_neighbor(v, e)
                            v.add_neighbor(a, e)
                            bonds_to_check.add(e)
                        to_delete.append(b)
        deleted = misc.filter_unique(to_delete)
        [self.delete_atom(o) for o in deleted]
        # after all is done, find and delete orphan bonds and update the others
        to_redraw = []
        bonds = set(self.bonds)
        for b in bonds_to_check:
            if not b in self.bonds:
                #print b, "not in self.bonds"
                continue
            recent_b = None
            for recent_b in self.gen_bonds_between(b.atom1, b.atom2):
                if recent_b != b:
                    break
            if recent_b and recent_b != b:
                self.delete_bond(b)
                deleted.append(b)
                to_redraw.append(recent_b)  # we redraw the ones that remained
            elif not recent_b:
                b.atom1.add_neighbor(b.atom2, b)
                b.atom2.add_neighbor(b.atom1, b)
                to_redraw.append(b)  # we redraw this also
        for b in to_redraw:
            b.redraw()

        return deleted
Example #3
0
  def handle_overlap( self):
    "deletes one of overlaping atoms and updates the bonds"
    to_delete = []
    bonds_to_check = set() # this can speedup the following for b in bonds_to_check by factor of 10 for big mols
    for i in range( len( self.atoms)):
      for j in range( i+1, len( self.atoms)):
        a = self.atoms[i]
        b = self.atoms[j]
        if (abs( a.x-b.x) < 4) and (abs( a.y-b.y) <4):
          if a not in to_delete:
            for e,v in b.get_neighbor_edge_pairs():
              e.change_atoms( b, a)
              a.add_neighbor( v, e)
              v.add_neighbor( a, e)
              bonds_to_check.add( e)
            to_delete.append( b)
    deleted = misc.filter_unique( to_delete)
    [self.delete_atom( o) for o in deleted]
    # after all is done, find and delete orphan bonds and update the others
    to_redraw = []
    bonds = set( self.bonds)
    for b in bonds_to_check:
      if not b in self.bonds:
        #print(b, "not in self.bonds")
        continue
      recent_b = None
      for recent_b in self.gen_bonds_between( b.atom1, b.atom2):
        if recent_b != b:
          break
      if recent_b and recent_b != b:
        self.delete_bond( b)
        deleted.append( b)
        to_redraw.append( recent_b) # we redraw the ones that remained
      elif not recent_b:
        b.atom1.add_neighbor( b.atom2, b)
        b.atom2.add_neighbor( b.atom1, b)
        to_redraw.append( b) # we redraw this also
    for b in to_redraw:
      b.redraw()

    return deleted
Example #4
0
 def delete_items( self, items, redraw=1, delete_single_atom=1):
   """deletes items and also makes cleaning of orphan bonds and atoms"""
   if not items:
     return items, []     # quick way to avoid costly evaluation
   deleted = copy.copy( items)
   for o in items:
     if o.object_type == 'atom':
       self.delete_atom( o)
     else:
       self.delete_bond( o)
   if self.atoms:
     # delete bonds that are not in connect anymore
     bonds_in_connect = set()
     for a in self.atoms:
       for (e,v) in a.get_neighbor_edge_pairs():
         if v in self.atoms:
           bonds_in_connect.add( e)
     deleted += [self.delete_bond( o) for o in (self.bonds - bonds_in_connect)]
     # delete also orphan atoms
     if delete_single_atom:
       atms = [o for o in self.atoms if len(o.neighbors) == 0]
       deleted += [self.delete_atom( o) for o in atms]
     # recalculation of second line of double bond position, optimized to do it only when realy
     # necessary, because its pretty expensive
     # check_integrity should be called before redrawing, because it moves atoms and bonds
     # to new molecules when the molecule is spit and avoids working on non-connected graph
     offspring = self.check_integrity()
     if redraw:
       bonds_to_redraw = []
       for b in deleted:
         if b.object_type == 'bond':
           for a in b.atoms:
             if a in self.atoms:
               bonds_to_redraw.extend( a.neighbor_edges)
       [o.redraw( recalc_side=1) for o in misc.filter_unique( bonds_to_redraw) if o.order == 2 and o.item]
       [o.decide_pos() for o in self.atoms if isinstance( o, atom)]
       [o.redraw() for o in self.atoms]
   else:
     offspring = self.check_integrity()
     deleted += map( self.delete_bond, copy.copy( self.bonds))
   return deleted, offspring
Example #5
0
    def __init__(self, parent, items):
        self.items = items
        self.changes_made = 0
        self.parent = parent
        self.dialog = Pmw.Dialog(parent,
                                 buttons=(_('OK'), _('Cancel')),
                                 defaultbutton=_('OK'),
                                 title=_('Configuration'),
                                 command=self.done,
                                 master='parent')
        #parent.bind_all( "<Button-1>", self.raise_me, add='+')
        self.pages = Pmw.NoteBook(self.dialog.interior())
        self.pages.pack(anchor='w', pady=0, padx=0, fill='both', expand=1)

        # create pages for different item types
        self.atom_page = None
        self.bond_page = None
        self.arrow_page = None
        self.text_page = None
        self.plus_page = None
        self.font_page = None
        self.common_page = None
        arrows = []
        for o in items:
            if o.object_type == 'point':
                items.remove(o)
                if o.arrow not in arrows:
                    arrows.append(o.arrow)
        items += arrows
        types = misc.filter_unique([o.object_type for o in items])

        if 'atom' in types:
            self.atom_page = self.pages.add(_('Atom'))
            # charge
            charges = misc.filter_unique(
                [o.charge for o in items if hasattr(o, 'charge')])
            if len(charges) == 1:
                charge = charges[0]
            else:
                charge = ''
            self.atom_charge = Pmw.Counter(self.atom_page,
                                           labelpos='w',
                                           label_text=_('Charge'),
                                           entryfield_value=charge,
                                           entryfield_validate={
                                               'validator': 'integer',
                                               'min': -4,
                                               'max': 4
                                           },
                                           entry_width=3,
                                           increment=1,
                                           datatype='integer')
            self.atom_charge.pack(anchor='nw', padx=10, pady=5)
            # show?
            shows = misc.filter_unique(
                [o.show for o in items if hasattr(o, 'show')])
            if len(shows) == 1:
                show = int(shows[0])
            else:
                show = 2  # means the show should be preserved as is
            self.atom_show = Pmw.OptionMenu(self.atom_page,
                                            labelpos='nw',
                                            label_text=_('Atom name'),
                                            items=(_("don't show"), _("show"),
                                                   u""),
                                            initialitem=show)
            self.atom_show.pack(anchor='nw')
            # positioning
            poss = misc.filter_unique(
                [o.pos for o in items if o.object_type == 'atom'])
            if not poss:
                pos = None
            elif len(poss) == 1 and poss[0]:
                pos = ['center-first', 'center-last'].index(poss[0])
            else:
                pos = 2  # means the centering should be preserved as is
            if pos == None:
                self.atom_pos = None
            else:
                self.atom_pos = Pmw.OptionMenu(
                    self.atom_page,
                    labelpos='nw',
                    label_text=_('Atom positioning'),
                    items=(_("center first letter"), _("center last letter"),
                           u""),
                    initialitem=pos)

                self.atom_pos.pack(anchor='nw')
            # show hydrogens
            shows = misc.filter_unique(
                [o.show_hydrogens for o in items if o.object_type == 'atom'])
            if len(shows) == 1:
                show = shows[0]
            else:
                show = 2  # means the show should be preserved as is
            self.atom_show_h = Pmw.OptionMenu(self.atom_page,
                                              labelpos='nw',
                                              label_text=_('Hydrogens'),
                                              items=(_("off"), _("on"), u""),
                                              initialitem=show)

            self.atom_show_h.pack(anchor='nw')

            # marks
            #self.marks = widgets.GraphicalAngleChooser( self.atom_page, 270)
            #self.marks.pack()

        # BOND
        if 'bond' in types:
            self.bond_page = self.pages.add(_('Bond'))
            # bond_widths (former distances)
            dists = misc.filter_unique(
                map(abs,
                    [o.bond_width for o in items if o.object_type == 'bond']))
            if len(dists) == 1:
                dist = dists[0]
            else:
                dist = ''
            if not misc.split_number_and_unit(dist)[1]:
                dist = str(dist) + 'px'
            self.bond_dist = widgets.WidthChooser(self.bond_page,
                                                  dist,
                                                  label=_('Bond width'))
            self.bond_dist.pack(anchor='ne', padx=10, pady=5)

            # wedge_widths
            dists = misc.filter_unique(
                map(abs,
                    [o.wedge_width for o in items if o.object_type == 'bond']))
            if len(dists) == 1:
                dist = dists[0]
            else:
                dist = ''
            if not misc.split_number_and_unit(dist)[1]:
                dist = str(dist) + 'px'
            self.wedge_width = widgets.WidthChooser(
                self.bond_page, dist, label=_('Wedge/Hatch width'))
            self.wedge_width.pack(anchor='ne', padx=10, pady=5)

            # double bond length ratio
            ratios = misc.filter_unique([
                o.double_length_ratio for o in items if o.object_type == 'bond'
            ])
            if len(ratios) == 1:
                ratio = ratios[0]
            else:
                ratio = ''
            self.double_length_ratio = widgets.RatioCounter(
                self.bond_page, ratio, label=_('Double-bond length ratio'))
            self.double_length_ratio.pack(anchor='nw', padx=10, pady=5)

        # ARROW
        if 'arrow' in types:
            self.arrow_page = self.pages.add(_('Arrow'))
            self.arrow_end_changed = 0
            self.arrow_start_changed = 0
            arrow_items = [o for o in items if o.object_type == 'arrow']

            # arrow start pins
            arrow_starts = misc.filter_unique(
                [o.get_pins()[0] for o in arrow_items])
            self.arrow_start = Tkinter.IntVar()
            if len(arrow_starts) == 1:
                self.arrow_start.set(arrow_starts[0])
            else:
                self.arrow_start.set(0)
            self.arrow_start_entry = Tkinter.Checkbutton(
                self.arrow_page,
                text=_('Arrow-head on start'),
                variable=self.arrow_start,
                command=self._arrow_start_changed)
            self.arrow_start_entry.pack(anchor='w')

            # arrow end pins
            arrow_ends = misc.filter_unique(
                [o.get_pins()[1] for o in arrow_items])
            self.arrow_end = Tkinter.IntVar()
            if len(arrow_ends) == 1:
                self.arrow_end.set(arrow_ends[0])
            else:
                self.arrow_end.set(0)
            self.arrow_end_entry = Tkinter.Checkbutton(
                self.arrow_page,
                text=_('Arrow-head on end'),
                variable=self.arrow_end,
                command=self._arrow_end_changed)
            self.arrow_end_entry.pack(anchor='w')

            # spline?
            splines = misc.filter_unique([o.spline for o in arrow_items])
            self.spline = Tkinter.IntVar()
            if len(splines) == 1:
                self.spline.set(splines[0])
            else:
                self.spline.set(0)
            self.spline_entry = Tkinter.Checkbutton(
                self.arrow_page,
                text=_('Spline arrow'),
                variable=self.spline,
                command=self._spline_changed)
            self.spline_changed = 0
            self.spline_entry.pack(anchor='w')

        # TEXTS

        # PLUS

        # FONT
        font_items = filter(lambda x: hasattr(x, 'font_family'), items)
        if font_items:
            self.font_page = self.pages.add(_('Font'))

            sizes = misc.filter_unique([o.font_size for o in font_items])
            if len(sizes) == 1:
                size = sizes[0]
            else:
                size = ''
            self.font_size = widgets.FontSizeChooser(self.font_page, size)
            self.font_size.pack(anchor='nw')

            used_families = misc.filter_unique(
                [o.font_family for o in font_items])
            if len(used_families) == 1:
                self.used_family = used_families[0]
            else:
                self.used_family = ''
            self.font_family = widgets.FontFamilyChooser(
                self.font_page, self.used_family)
            self.font_family.pack(anchor="nw", side='bottom')

        # COMMON
        self.common_page = self.pages.add(_('Common'))
        line_items = filter(lambda x: hasattr(x, 'line_width'), items)
        if line_items:
            widths = misc.filter_unique([o.line_width for o in line_items])
            if len(widths) == 1:
                width = widths[0]
            else:
                width = ''
            if not misc.split_number_and_unit(width)[1]:
                width = str(width) + 'px'
            self.line_width = widgets.WidthChooser(self.common_page,
                                                   width,
                                                   label=_('Line width'))
            self.line_width.pack(anchor='nw', padx=10, pady=5)

        line_color_items = filter(lambda x: hasattr(x, 'line_color'), items)
        if line_color_items:
            lines = misc.filter_unique(
                [o.line_color for o in line_color_items])
            if len(lines) == 1:
                line = lines[0]
            else:
                line = None
            self.line_color = widgets.ColorButtonWithTransparencyChecker(
                self.common_page, color=line, text=_("Line color"))
            self.line_color.pack(anchor='nw', padx=10, pady=10)

        area_color_items = filter(lambda x: hasattr(x, 'area_color'), items)
        if area_color_items:
            areas = misc.filter_unique(
                [o.area_color for o in area_color_items])
            if len(areas) == 1:
                area = areas[0]
            else:
                area = None
            self.area_color = widgets.ColorButtonWithTransparencyChecker(
                self.common_page, color=area, text=_("Area color"))
            self.area_color.pack(anchor='nw', padx=10, pady=5)

        # RUN IT ALL
        self.pages.setnaturalsize()
        self.dialog.activate(globalMode=0)
Example #6
0
  def __init__( self, parent, items):
    self.items = items
    self.changes_made = 0
    self.parent = parent
    self.dialog = Pmw.Dialog( parent,
                              buttons=(_('OK'), _('Cancel')),
                              defaultbutton=_('OK'),
                              title=_('Configuration'),
                              command=self.done,
                              master='parent')
    #parent.bind_all( "<Button-1>", self.raise_me, add='+')
    self.pages = Pmw.NoteBook( self.dialog.interior())
    self.pages.pack( anchor='w', pady=0, padx=0, fill='both', expand=1)

    # create pages for different item types
    self.atom_page = None
    self.bond_page = None
    self.arrow_page = None
    self.text_page = None
    self.plus_page = None
    self.font_page = None
    self.common_page = None
    arrows = []
    for o in items:
      if o.object_type == 'point':
        items.remove( o)
        if o.arrow not in arrows:
          arrows.append( o.arrow)
    items += arrows
    types = misc.filter_unique( [o.object_type for o in items])

    if 'atom' in types:
      self.atom_page = self.pages.add(_('Atom'))
      # charge
      charges = misc.filter_unique( [o.charge for o in items if hasattr( o, 'charge')])
      if len( charges) == 1:
        charge = charges[0]
      else:
        charge = ''
      self.atom_charge = Pmw.Counter( self.atom_page,
                                      labelpos = 'w',
                                      label_text = _('Charge'),
                                      entryfield_value = charge,
                                      entryfield_validate={ 'validator':'integer', 'min':-4, 'max':4},
                                      entry_width = 3,
                                      increment = 1,
                                      datatype = 'integer')
      self.atom_charge.pack( anchor='nw', padx=10, pady=5)
      # show?
      shows = misc.filter_unique( [o.show for o in items if hasattr( o, 'show')])
      if len( shows) == 1:
        show = int( shows[0])
      else:
        show = 2 # means the show should be preserved as is
      self.atom_show = Pmw.OptionMenu( self.atom_page,
                                       labelpos = 'nw',
                                       label_text = _('Atom name'),
                                       items = (_("don't show"), _("show"), ""),
                                       initialitem = show)
      self.atom_show.pack( anchor = 'nw')
      # positioning
      poss = misc.filter_unique( [o.pos for o in items if o.object_type == 'atom'])
      if not poss:
        pos = None
      elif len( poss) == 1 and poss[0]:
        pos = ['center-first', 'center-last'].index( poss[0])
      else:
        pos = 2 # means the centering should be preserved as is
      if pos == None:
        self.atom_pos = None
      else:
        self.atom_pos = Pmw.OptionMenu( self.atom_page,
                                        labelpos = 'nw',
                                        label_text = _('Atom positioning'),
                                        items = (_("center first letter"), _("center last letter"), ""),
                                        initialitem = pos)

        self.atom_pos.pack( anchor = 'nw')
      # show hydrogens
      shows = misc.filter_unique( [o.show_hydrogens for o in items if o.object_type == 'atom'])
      if len( shows) == 1:
        show = shows[0]
      else:
        show = 2 # means the show should be preserved as is
      self.atom_show_h = Pmw.OptionMenu( self.atom_page,
                                         labelpos = 'nw',
                                         label_text = _('Hydrogens'),
                                         items = (_("off"), _("on"), ""),
                                         initialitem = show)

      self.atom_show_h.pack( anchor = 'nw')

      # marks
      #self.marks = widgets.GraphicalAngleChooser( self.atom_page, 270)
      #self.marks.pack()

    # BOND
    if 'bond' in types:
      self.bond_page = self.pages.add(_('Bond'))
      # bond_widths (former distances)
      dists = misc.filter_unique( map( abs, [o.bond_width for o in items if o.object_type == 'bond']))
      if len( dists) == 1:
        dist = dists[0]
      else:
        dist = ''
      if not misc.split_number_and_unit( dist)[1]:
        dist = str( dist) + 'px'
      self.bond_dist = widgets.WidthChooser( self.bond_page, dist, label=_('Bond width'))
      self.bond_dist.pack( anchor='ne', padx=10, pady=5)

      # wedge_widths
      dists = misc.filter_unique( map( abs, [o.wedge_width for o in items if o.object_type == 'bond']))
      if len( dists) == 1:
        dist = dists[0]
      else:
        dist = ''
      if not misc.split_number_and_unit( dist)[1]:
        dist = str( dist) + 'px'
      self.wedge_width = widgets.WidthChooser( self.bond_page, dist, label=_('Wedge/Hatch width'))
      self.wedge_width.pack( anchor='ne', padx=10, pady=5)

      # double bond length ratio
      ratios = misc.filter_unique( [o.double_length_ratio for o in items if o.object_type == 'bond'])
      if len( ratios) == 1:
        ratio = ratios[0]
      else:
        ratio = ''
      self.double_length_ratio = widgets.RatioCounter( self.bond_page,
                                                       ratio,
                                                       label=_('Double-bond length ratio'))
      self.double_length_ratio.pack( anchor='nw', padx=10, pady=5)

    # ARROW
    if 'arrow' in types:
      self.arrow_page = self.pages.add(_('Arrow'))
      self.arrow_end_changed = 0
      self.arrow_start_changed = 0
      arrow_items = [o for o in items if o.object_type == 'arrow']

      # arrow start pins
      arrow_starts = misc.filter_unique( [o.get_pins()[0] for o in arrow_items])
      self.arrow_start = Tkinter.IntVar()
      if len( arrow_starts) == 1:
        self.arrow_start.set( arrow_starts[0])
      else:
        self.arrow_start.set( 0)
      self.arrow_start_entry = Tkinter.Checkbutton( self.arrow_page,
                                                    text=_('Arrow-head on start'),
                                                    variable = self.arrow_start,
                                                    command = self._arrow_start_changed)
      self.arrow_start_entry.pack( anchor='w')

      # arrow end pins
      arrow_ends = misc.filter_unique( [o.get_pins()[1] for o in arrow_items])
      self.arrow_end = Tkinter.IntVar()
      if len( arrow_ends) == 1:
        self.arrow_end.set( arrow_ends[0])
      else:
        self.arrow_end.set( 0)
      self.arrow_end_entry = Tkinter.Checkbutton( self.arrow_page,
                                                  text=_('Arrow-head on end'),
                                                  variable = self.arrow_end,
                                                  command = self._arrow_end_changed)
      self.arrow_end_entry.pack( anchor='w')

      # spline?
      splines = misc.filter_unique( [o.spline for o in arrow_items])
      self.spline = Tkinter.IntVar()
      if len( splines) == 1:
        self.spline.set( splines[0])
      else:
        self.spline.set( 0)
      self.spline_entry = Tkinter.Checkbutton( self.arrow_page,
                                               text=_('Spline arrow'),
                                               variable = self.spline,
                                               command = self._spline_changed)
      self.spline_changed = 0
      self.spline_entry.pack( anchor='w')

    # TEXTS

    # PLUS

    # FONT
    font_items = filter( lambda x: hasattr( x, 'font_family'), items)
    if font_items:
      self.font_page = self.pages.add(_('Font'))

      sizes = misc.filter_unique( [o.font_size for o in font_items])
      if len( sizes) == 1:
        size = sizes[0]
      else:
        size = ''
      self.font_size = widgets.FontSizeChooser( self.font_page, size)
      self.font_size.pack( anchor = 'nw')

      used_families = misc.filter_unique( [o.font_family for o in font_items])
      if len( used_families) == 1:
        self.used_family = used_families[0]
      else:
        self.used_family = ''
      self.font_family = widgets.FontFamilyChooser( self.font_page, self.used_family)
      self.font_family.pack( anchor="nw", side = 'bottom')

    # COMMON
    self.common_page = self.pages.add(_('Common'))
    line_items = filter( lambda x: hasattr( x, 'line_width'), items)
    if line_items:
      widths = misc.filter_unique( [o.line_width for o in line_items])
      if len( widths) == 1:
        width = widths[0]
      else:
        width = ''
      if not misc.split_number_and_unit( width)[1]:
        width = str( width) + 'px'
      self.line_width = widgets.WidthChooser( self.common_page, width, label=_('Line width'))
      self.line_width.pack( anchor='nw', padx=10, pady=5)

    line_color_items = filter( lambda x: hasattr( x, 'line_color'), items)
    if line_color_items:
      lines = misc.filter_unique( [o.line_color for o in line_color_items])
      if len( lines) == 1:
        line = lines[0]
      else:
        line = None
      self.line_color = widgets.ColorButtonWithTransparencyChecker( self.common_page, color=line, text=_("Line color"))
      self.line_color.pack( anchor='nw', padx=10, pady=10)

    area_color_items = filter( lambda x: hasattr( x, 'area_color'), items)
    if area_color_items:
      areas = misc.filter_unique( [o.area_color for o in area_color_items])
      if len( areas) == 1:
        area = areas[0]
      else:
        area = None
      self.area_color = widgets.ColorButtonWithTransparencyChecker( self.common_page, color=area, text=_("Area color"))
      self.area_color.pack( anchor='nw', padx=10, pady=5)


    # RUN IT ALL
    self.pages.setnaturalsize()
    self.dialog.activate( globalMode=0)