Index: lib/matplotlib/cbook.py
===================================================================
--- lib/matplotlib/cbook.py	(revision 5797)
+++ lib/matplotlib/cbook.py	(working copy)
@@ -287,7 +287,7 @@
 
 def is_scalar(obj):
     'return true if *obj* is not string like and is not iterable'
-    return is_string_like(obj) or not iterable(obj)
+    return not is_string_like(obj) and not iterable(obj)
 
 def is_numlike(obj):
     'return true if *obj* looks like a number'
@@ -1154,6 +1154,46 @@
 
     return result
 
+def less_simple_linear_interpolation( x, y, xi, extrap=False ):
+    """
+    This function provides simple (but somewhat less so than
+    simple_linear_interpolation) linear interpolation.  This is very
+    inefficient linear interpolation meant to be used only for a small
+    number of points in relatively non-intensive use cases.
+
+    Call signature::
+
+    yi = less_simple_linear_interpolation(x,y,xi)
+    """
+    if is_scalar(xi): xi = [xi]
+
+    x = np.asarray(x)
+    y = np.asarray(y)
+    xi = np.asarray(xi)
+
+    s = list(y.shape)
+    s[0] = len(xi)
+    yi = np.tile( np.nan, s )
+
+    for ii,xx in enumerate(xi):
+        bb = x == xx
+        if np.any(bb):
+            jj, = np.nonzero(bb)
+            yi[ii] = y[jj[0]]
+        elif xx<x[0]:
+            if extrap:
+                yi[ii] = y[0]
+        elif xx>x[-1]:
+            if extrap:
+                yi[ii] = y[-1]
+        else:
+            jj, = np.nonzero(x<xx)
+            jj = max(jj)
+
+            yi[ii] = y[jj] + (xx-x[jj])/(x[jj+1]-x[jj]) * (y[jj+1]-y[jj])
+
+    return yi
+
 def recursive_remove(path):
     if os.path.isdir(path):
         for fname in glob.glob(os.path.join(path, '*')) + glob.glob(os.path.join(path, '.*')):
@@ -1246,7 +1286,76 @@
             margs[i] = x.filled()
     return margs
 
+def isvector(X):
+    """
+    Like the Matlab (TM) function with the same name, returns true if
+    the supplied numpy array or matrix looks like a vector, meaning it
+    has a one non-singleton axis (i.e., it can have multiple axes, but
+    all must have length 1, except for one of them).
 
+    If you just want to see if the array has 1 axis, use X.ndim==1
+
+    Call signature::
+    isvector(X)
+    """
+    return np.prod(X.shape)==np.max(X.shape)
+
+def vector_lengths( X, P=2., axis=None ):
+    """
+    Finds the length of a set of vectors in n dimensions.  This is
+    like the mlab.norm function for vectors, but has the ability to
+    work over a particular axis of the supplied array or matrix.
+
+    Call signature::
+
+    vector_lengths( X, P=2., axis=None )
+
+    Computes (sum((x_i)^P))^(1/P) for each {x_i} being the elements of X along
+    the given axis.  If *axis* is *None*, compute over all elements of X.
+    """
+    X = np.asarray(X)
+    return (np.sum(X**(P),axis=axis))**(1./P)
+
+def distances_along_curve( X ):
+    """
+    Computes the distance between a set of successive points in N dimensions.
+
+    Call signature::
+
+    distances_along_curve(X)
+
+    where X is an MxN array or matrix.  The distances between successive rows
+    is computed.  Distance is the standard Euclidean distance.
+    """
+    X = np.diff( X, axis=0 )
+    return vector_lengths(X,axis=1)
+
+def path_length(X):
+    """
+    Computes the distance travelled along a polygonal curve in N dimensions.
+
+    Call signature::
+
+    path_length(X)
+
+    where X is an MxN array or matrix.  Returns an array of length M consisting
+    of the distance along the curve at each point (i.e., the rows of X).
+    """
+    X = distances_along_curve(X)
+    return np.concatenate( (np.zeros(1), np.cumsum(X)) )
+
+def is_closed_polygon(X):
+    """
+    Tests whether first and last object in a sequence are the same.  These are
+    presumably coordinates on a polygonal curve, in which case this function
+    tests if that curve is closed.
+
+    Call signature::
+
+    is_closed_polygon(X)
+    """
+    return np.all(X[0] == X[-1])
+
 # a dict to cross-map linestyle arguments
 _linestyles = [('-', 'solid'),
     ('--', 'dashed'),
Index: lib/matplotlib/contour.py
===================================================================
--- lib/matplotlib/contour.py	(revision 5801)
+++ lib/matplotlib/contour.py	(working copy)
@@ -69,6 +69,12 @@
             controls whether the underlying contour is removed or
             not. Default is *True*.
 
+          *inline_spacing*:
+            space in pixels to leave on each side of label when
+            placing inline.  Defaults to 5.  This spacing will be
+            exact for labels at locations where the contour is
+            straight, less so for labels on curved contours.
+
           *fmt*:
             a format string for the label. Default is '%1.3f'
             Alternatively, this can be a dictionary matching contour
@@ -108,11 +114,12 @@
 
         fontsize = kwargs.get('fontsize', None)
         inline = kwargs.get('inline', 1)
-        self.fmt = kwargs.get('fmt', '%1.3f')
+        inline_spacing = kwargs.get('inline_spacing', 5)
+        self.labelFmt = kwargs.get('fmt', '%1.3f')
         _colors = kwargs.get('colors', None)
 
         # Detect if manual selection is desired and remove from argument list
-        self.manual_select=kwargs.get('manual',False)
+        self.labelManual=kwargs.get('manual',False)
 
         if len(args) == 0:
             levels = self.levels
@@ -131,50 +138,50 @@
                 raise ValueError(msg)
         else:
             raise TypeError("Illegal arguments to clabel, see help(clabel)")
-        self.label_levels = levels
-        self.label_indices = indices
+        self.labelLevelList = levels
+        self.labelIndiceList = indices
 
-        self.fp = font_manager.FontProperties()
+        self.labelFontProps = font_manager.FontProperties()
         if fontsize == None:
-            font_size = int(self.fp.get_size_in_points())
+            font_size = int(self.labelFontProps.get_size_in_points())
         else:
             if type(fontsize) not in [int, float, str]:
                 raise TypeError("Font size must be an integer number.")
                 # Can't it be floating point, as indicated in line above?
             else:
                 if type(fontsize) == str:
-                    font_size = int(self.fp.get_size_in_points())
+                    font_size = int(self.labelFontProps.get_size_in_points())
                 else:
-                    self.fp.set_size(fontsize)
+                    self.labelFontProps.set_size(fontsize)
                     font_size = fontsize
-        self.fslist = [font_size] * len(levels)
+        self.labelFontSizeList = [font_size] * len(levels)
 
         if _colors == None:
-            self.label_mappable = self
-            self.label_cvalues = np.take(self.cvalues, self.label_indices)
+            self.labelMappable = self
+            self.labelCValueList = np.take(self.cvalues, self.labelIndiceList)
         else:
-            cmap = colors.ListedColormap(_colors, N=len(self.label_levels))
-            self.label_cvalues = range(len(self.label_levels))
-            self.label_mappable = cm.ScalarMappable(cmap = cmap,
-                                                 norm = colors.NoNorm())
+            cmap = colors.ListedColormap(_colors, N=len(self.labelLevelList))
+            self.labelCValueList = range(len(self.labelLevelList))
+            self.labelMappable = cm.ScalarMappable(cmap = cmap,
+                                                   norm = colors.NoNorm())
 
-        #self.cl = []   # Initialized in ContourSet.__init__
-        #self.cl_cvalues = [] # same
-        self.cl_xy = []
+        #self.labelTexts = []   # Initialized in ContourSet.__init__
+        #self.labelCValues = [] # same
+        self.labelXYs = []
 
-        if self.manual_select:
+        if self.labelManual:
             print 'Select label locations manually using first mouse button.'
             print 'End manual selection with second mouse button.'
             if not inline:
                 print 'Remove last label by clicking third mouse button.'
 
             blocking_contour_labeler = BlockingContourLabeler(self)
-            blocking_contour_labeler(inline)
+            blocking_contour_labeler(inline,inline_spacing)
         else:
-            self.labels(inline)
+            self.labels(inline,inline_spacing)
 
-        self.label_list =  cbook.silent_list('text.Text', self.cl)
-        return self.label_list
+        self.labelTextsList =  cbook.silent_list('text.Text', self.labelTexts)
+        return self.labelTextsList
 
 
     def print_label(self, linecontour,labelwidth):
@@ -196,9 +203,9 @@
 
     def too_close(self, x,y, lw):
         "if there's a label already nearby, find a better place"
-        if self.cl_xy != []:
+        if self.labelXYs != []:
             dist = [np.sqrt((x-loc[0]) ** 2 + (y-loc[1]) ** 2)
-                    for loc in self.cl_xy]
+                    for loc in self.labelXYs]
             for d in dist:
                 if d < 1.2*lw:
                     return 1
@@ -237,12 +244,35 @@
 
         return lw
 
+    def get_real_label_width( self, lev, fmt, fsize ):
+        """
+        This computes actual onscreen label width.
+        This uses some black magic to determine onscreen extent of non-drawn
+        label.  This magic may not be very robust.
+        """
+        # Find middle of axes
+        xx = np.mean( np.asarray(self.ax.axis()).reshape(2,2), axis=1 )
 
+        # Temporarily create text object
+        t = text.Text( xx[0], xx[1] )
+        self.set_label_props( t, self.get_text(lev,fmt), 'k' )
+
+        # Some black magic to get onscreen extent
+        # NOTE: This will only work for already drawn figures, as the canvas
+        # does not have a renderer otherwise.  This is the reason this function
+        # can't be integrated into the rest of the code.
+        bbox = t.get_window_extent(renderer=self.ax.figure.canvas.renderer)
+
+        # difference in pixel extent of image
+        lw = np.diff(bbox.corners()[0::2,0])[0]
+
+        return np.round(lw)
+
     def set_label_props(self, label, text, color):
         "set the label properties - color, fontsize, text"
         label.set_text(text)
         label.set_color(color)
-        label.set_fontproperties(self.fp)
+        label.set_fontproperties(self.labelFontProps)
         label.set_clip_box(self.ax.bbox)
 
     def get_text(self, lev, fmt):
@@ -255,85 +285,6 @@
             else:
                 return fmt%lev
 
-    def break_linecontour(self, linecontour, rot, labelwidth, ind):
-        "break a contour in two contours at the location of the label"
-        lcsize = len(linecontour)
-        hlw = int(labelwidth/2)
-
-        #length of label in screen coords
-        ylabel = abs(hlw * np.sin(rot*np.pi/180))
-        xlabel = abs(hlw * np.cos(rot*np.pi/180))
-
-        trans = self.ax.transData
-
-        slc = trans.transform(linecontour)
-        x,y = slc[ind]
-        xx=slc[:,0].copy()
-        yy=slc[:,1].copy()
-
-        #indices which are under the label
-        inds, = np.nonzero(((xx < x+xlabel) & (xx > x-xlabel)) &
-                            ((yy < y+ylabel) & (yy > y-ylabel)))
-
-        if len(inds) >0:
-            #if the label happens to be over the beginning of the
-            #contour, the entire contour is removed, i.e.
-            #indices to be removed are
-            #inds= [0,1,2,3,305,306,307]
-            #should rewrite this in a better way
-            linds, = np.nonzero(inds[1:]- inds[:-1] != 1)
-            if inds[0] == 0 and len(linds) != 0:
-                ii = inds[linds[0]]
-                lc1 =linecontour[ii+1:inds[ii+1]]
-                lc2 = []
-
-            else:
-                lc1=linecontour[:inds[0]]
-                lc2= linecontour[inds[-1]+1:]
-
-        else:
-            lc1=linecontour[:ind]
-            lc2 = linecontour[ind+1:]
-
-
-        if rot <0:
-            new_x1, new_y1 = x-xlabel, y+ylabel
-            new_x2, new_y2 = x+xlabel, y-ylabel
-        else:
-            new_x1, new_y1 = x-xlabel, y-ylabel
-            new_x2, new_y2 = x+xlabel, y+ylabel
-
-        inverse = trans.inverted()
-        new_x1d, new_y1d = inverse.transform_point((new_x1, new_y1))
-        new_x2d, new_y2d = inverse.transform_point((new_x2, new_y2))
-        new_xy1 = np.array(((new_x1d, new_y1d),))
-        new_xy2 = np.array(((new_x2d, new_y2d),))
-
-
-        if rot > 0:
-            if (len(lc1) > 0 and (lc1[-1][0] <= new_x1d)
-                             and (lc1[-1][1] <= new_y1d)):
-                lc1 = np.concatenate((lc1, new_xy1))
-                #lc1.append((new_x1d, new_y1d))
-
-            if (len(lc2) > 0 and (lc2[0][0] >= new_x2d)
-                             and (lc2[0][1] >= new_y2d)):
-                lc2 = np.concatenate((new_xy2, lc2))
-                #lc2.insert(0, (new_x2d, new_y2d))
-        else:
-            if (len(lc1) > 0 and ((lc1[-1][0] <= new_x1d)
-                             and (lc1[-1][1] >= new_y1d))):
-                lc1 = np.concatenate((lc1, new_xy1))
-                #lc1.append((new_x1d, new_y1d))
-
-            if (len(lc2) > 0 and ((lc2[0][0] >= new_x2d)
-                             and (lc2[0][1] <= new_y2d))):
-                lc2 = np.concatenate((new_xy2, lc2))
-                #lc2.insert(0, (new_x2d, new_y2d))
-
-        return [lc1,lc2]
-
-
     def locate_label(self, linecontour, labelwidth):
         """find a good place to plot a label (relatively flat
         part of the contour) and the angle of rotation for the
@@ -362,12 +313,6 @@
         dist = np.add.reduce(([(abs(s)[i]/L[i]) for i in range(xsize)]),-1)
         x,y,ind = self.get_label_coords(dist, XX, YY, ysize, labelwidth)
         #print 'ind, x, y', ind, x, y
-        angle = np.arctan2(ylast - yfirst, xlast - xfirst).ravel()
-        rotation = angle[ind]*180/np.pi
-        if rotation > 90:
-            rotation = rotation -180
-        if rotation < -90:
-            rotation = 180 + rotation
 
         # There must be a more efficient way...
         lc = [tuple(l) for l in linecontour]
@@ -375,72 +320,176 @@
         #print 'dind', dind
         #dind = list(linecontour).index((x,y))
 
-        return x,y, rotation, dind
+        return x, y, dind
 
+    def calc_label_rot_and_inline( self, slc, ind, lw, lc=[], spacing=5 ):
+        """
+        This function calculates the appropriate label rotation given
+        the linecontour coordinates in screen units, the index of the
+        label location and the label width.
+
+        It will also break contour and calculate inlining if *lc* is
+        not empty.  *spacing* is the space around the label in pixels
+        to leave empty.
+
+        Do both of these tasks at once to avoid calling cbook.path_length
+        multiple times, which is relatively costly.
+
+        The method used here involves calculating the path length
+        along the contour in pixel coordinates and then looking
+        approximately label width / 2 away from central point to
+        determine rotation and then to break contour if desired.
+        """
+
+        # Half the label width
+        hlw = lw/2.0
+
+        # Check if closed and, if so, rotate contour so label is at edge
+        closed = cbook.is_closed_polygon(slc)
+        if closed:
+            slc = np.r_[ slc[ind:-1], slc[:ind+1] ]
+
+            if len(lc): # Rotate lc also if not empty
+                lc = np.r_[ lc[ind:-1], lc[:ind+1] ]
+
+            ind = 0
+
+        # Path length in pixel space
+        pl = cbook.path_length(slc)
+        pl = pl-pl[ind]
+
+        # Use linear interpolation to get points around label
+        xi = np.array( [ -hlw, hlw ] )
+        if closed: # Look at end also for closed contours
+            dp = np.array([pl[-1],0])
+        else:
+            dp = np.zeros_like(xi)
+
+        ll = cbook.less_simple_linear_interpolation( pl, slc, dp+xi,
+                                                     extrap=True )
+
+        # get vector in pixel space coordinates from one point to other
+        dd = np.diff( ll, axis=0 ).ravel()
+
+        # Get angle of vector - must be calculated in pixel space for
+        # text rotation to work correctly
+        if np.all(dd==0): # Must deal with case of zero length label
+            rotation = 0.0
+        else:
+            rotation = np.arctan2(dd[1], dd[0]) * 180.0 / np.pi
+
+        # Fix angle so text is never upside-down
+        if rotation > 90:
+            rotation = rotation - 180.0
+        if rotation < -90:
+            rotation = 180.0 + rotation
+
+        # Break contour if desired
+        nlc = []
+        if len(lc):
+            # Expand range by spacing
+            xi = dp + xi + np.array([-spacing,spacing])
+
+            # Get indices near points of interest
+            I = cbook.less_simple_linear_interpolation(
+                pl, np.arange(len(pl)), xi, extrap=False )
+
+            # If those indices aren't beyond contour edge, find x,y
+            if (not np.isnan(I[0])) and int(I[0])<>I[0]:
+                xy1 = cbook.less_simple_linear_interpolation(
+                    pl, lc, [ xi[0] ] )
+
+            if (not np.isnan(I[1])) and int(I[1])<>I[1]:
+                xy2 = cbook.less_simple_linear_interpolation(
+                    pl, lc, [ xi[1] ] )
+
+            # Make integer
+            I = [ np.floor(I[0]), np.ceil(I[1]) ]
+
+            # Actually break contours
+            if closed:
+                # This will remove contour if shorter than label
+                if np.all(~np.isnan(I)):
+                    nlc.append( np.r_[ xy2, lc[I[1]:I[0]+1], xy1 ] )
+            else:
+                # These will remove pieces of contour if they have length zero
+                if not np.isnan(I[0]):
+                    nlc.append( np.r_[ lc[:I[0]+1], xy1 ] )
+                if not np.isnan(I[1]):
+                    nlc.append( np.r_[ xy2, lc[I[1]:] ] )
+
+        return (rotation,nlc)
+
+
     def add_label(self,x,y,rotation,lev,cvalue):
         dx,dy = self.ax.transData.inverted().transform_point((x,y))
         t = text.Text(dx, dy, rotation = rotation,
                       horizontalalignment='center',
                       verticalalignment='center')
 
-        color = self.label_mappable.to_rgba(cvalue,alpha=self.alpha)
+        color = self.labelMappable.to_rgba(cvalue,alpha=self.alpha)
 
-        _text = self.get_text(lev,self.fmt)
+        _text = self.get_text(lev,self.labelFmt)
         self.set_label_props(t, _text, color)
-        self.cl.append(t)
-        self.cl_cvalues.append(cvalue)
-        self.cl_xy.append((x,y))
+        self.labelTexts.append(t)
+        self.labelCValues.append(cvalue)
+        self.labelXYs.append((x,y))
 
         # Add label to plot here - useful for manual mode label selection
         self.ax.add_artist(t)
 
     def pop_label(self,index=-1):
         '''Defaults to removing last label, but any index can be supplied'''
-        self.cl_cvalues.pop(index)
-        t = self.cl.pop(index)
+        self.labelCValues.pop(index)
+        t = self.labelTexts.pop(index)
         t.remove()
 
-    def labels(self, inline):
+    def labels(self, inline, inline_spacing):
         trans = self.ax.transData # A bit of shorthand
 
         for icon, lev, fsize, cvalue in zip(
-            self.label_indices, self.label_levels, self.fslist,
-            self.label_cvalues ):
+            self.labelIndiceList, self.labelLevelList, self.labelFontSizeList,
+            self.labelCValueList ):
 
             con = self.collections[icon]
-            lw = self.get_label_width(lev, self.fmt, fsize)
+            lw = self.get_label_width(lev, self.labelFmt, fsize)
             additions = []
             paths = con.get_paths()
             for segNum, linepath in enumerate(paths):
-                linecontour = linepath.vertices
-                # for closed contours add one more point to
-                # avoid division by zero
-                if np.all(linecontour[0] == linecontour[-1]):
-                    linecontour = np.concatenate((linecontour,
-                                                  linecontour[1][np.newaxis,:]))
-                    #linecontour.append(linecontour[1])
-                # transfer all data points to screen coordinates
-                slc = trans.transform(linecontour)
+                lc = linepath.vertices # Line contour
+                slc0 = trans.transform(lc) # Line contour in screen coords
+
+                # For closed polygons, add extra point to avoid division by
+                # zero in print_label and locate_label.  Other than these
+                # functions, this is not necessary and should probably be
+                # eventually removed.
+                if cbook.is_closed_polygon( lc ):
+                    slc = np.r_[ slc0, slc0[1:2,:] ]
+                else:
+                    slc = slc0
+
                 if self.print_label(slc,lw):
-                    x,y, rotation, ind  = self.locate_label(slc, lw)
+                    x,y,ind  = self.locate_label(slc, lw)
 
+                    rotation,new=self.calc_label_rot_and_inline(
+                        slc0, ind, lw, lc if inline else [],
+                        inline_spacing )
+
                     # Actually add the label
                     self.add_label(x,y,rotation,lev,cvalue)
 
-                    # Use break_linecontour to split contours for inlining
+                    # If inline, add new contours
                     if inline:
-                        new = self.break_linecontour(linecontour, rotation,
-                                                     lw, ind)
-                        if len(new[0]):
-                            paths[segNum] = path.Path(new[0])
-                        if len(new[1]):
-                            additions.append(path.Path(new[1]))
+                        for n in new:
+                            # Add path if not empty or single point
+                            if len(n)>1: additions.append( path.Path(n) )
 
-            # After looping over all segments on a contour, append
-            # new paths to existing
-            paths.extend(additions)
+            # After looping over all segments on a contour, remove old
+            # paths and add new ones if inlining
+            if inline:
+                del paths[:]
+                paths.extend(additions)
 
-
 class ContourSet(cm.ScalarMappable, ContourLabeler):
     """
     Create and store a set of contour lines or filled regions.
@@ -512,8 +561,8 @@
         else:
             self.collections = cbook.silent_list('collections.LineCollection')
         # label lists must be initialized here
-        self.cl = []
-        self.cl_cvalues = []
+        self.labelTexts = []
+        self.labelCValues = []
 
         kw = {'cmap': cmap}
         if norm is not None:
@@ -574,9 +623,9 @@
         for color, collection in zip(tcolors, self.collections):
             collection.set_alpha(self.alpha)
             collection.set_color(color)
-        for label, cv in zip(self.cl, self.cl_cvalues):
+        for label, cv in zip(self.labelTexts, self.labelCValues):
             label.set_alpha(self.alpha)
-            label.set_color(self.label_mappable.to_rgba(cv))
+            label.set_color(self.labelMappable.to_rgba(cv))
         # add label colors
         cm.ScalarMappable.changed(self)
 
Index: lib/matplotlib/blocking_input.py
===================================================================
--- lib/matplotlib/blocking_input.py	(revision 5799)
+++ lib/matplotlib/blocking_input.py	(working copy)
@@ -19,8 +19,9 @@
 
 import time
 import numpy as np
+
 from matplotlib import path, verbose
-from cbook import is_sequence_of_strings
+from matplotlib.cbook import is_sequence_of_strings
 
 class BlockingInput(object):
     """
@@ -267,47 +268,39 @@
 
         if event.inaxes == cs.ax:
             conmin,segmin,imin,xmin,ymin = cs.find_nearest_contour(
-                event.x, event.y, cs.label_indices)[:5]
+                event.x, event.y, cs.labelIndiceList)[:5]
 
             # Get index of nearest level in subset of levels used for labeling
-            lmin = cs.label_indices.index(conmin)
+            lmin = cs.labelIndiceList.index(conmin)
 
+            # Coordinates of contour
             paths = cs.collections[conmin].get_paths()
             lc = paths[segmin].vertices
 
-            # Figure out label rotation.  This is very cludgy.
-            # Ideally, there would be one method in ContourLabeler
-            # that would figure out the best rotation for a label at a
-            # point, but the way automatic label rotation is done is
-            # quite mysterious to me and doesn't seem easy to
-            # generalize to non-automatic label placement.  The method
-            # used below is not very robust!  It basically looks one
-            # point before and one point after label location on
-            # contour and takes mean of angles of two vectors formed.
-            # This produces "acceptable" results, but not nearly as
-            # nice as automatic method.
-            ll = lc[max(0,imin-1):imin+2] # Get points around point
-            dd = np.diff(ll,axis=0)
-            rotation = np.mean( np.arctan2(dd[:,1], dd[:,0]) ) * 180 / np.pi
-            if rotation > 90:
-                rotation = rotation -180
-            if rotation < -90:
-                rotation = 180 + rotation
+            # In pixel/screen space
+            slc = cs.ax.transData.transform(lc)
 
-            cs.add_label(xmin,ymin,rotation,cs.label_levels[lmin],
-                         cs.label_cvalues[lmin])
+            # Get label width for rotating labels and breaking contours
+            lw = cs.get_label_width(cs.labelLevelList[lmin],
+                                    cs.labelFmt, cs.labelFontSizeList[lmin])
 
+            # Figure out label rotation.
+            rotation,nlc = cs.calc_label_rot_and_inline(
+                slc, imin, lw, lc if self.inline else [],
+                self.inline_spacing )
+
+            cs.add_label(xmin,ymin,rotation,cs.labelLevelList[lmin],
+                         cs.labelCValueList[lmin])
+
             if self.inline:
-                # Get label width for breaking contours
-                lw = cs.get_label_width(cs.label_levels[lmin],
-                                        cs.fmt, cs.fslist[lmin])
-                # Break contour
-                new=cs.break_linecontour(lc,rotation,lw,imin)
-                if len(new[0]):
-                    paths[segmin] = path.Path(new[0])
-                if len(new[1]):
-                    paths.extend([path.Path(new[1])])
+                # Remove old, not looping over paths so we can do this up front
+                paths.pop(segmin)
 
+                # Add paths if not empty or single point
+                for n in nlc:
+                    if len(n)>1:
+                        paths.append( path.Path(n) )
+
             self.fig.canvas.draw()
         else: # Remove event if not valid
             BlockingInput.pop(self)
@@ -320,14 +313,21 @@
         broken contour - once humpty-dumpty is broken, he can't be put
         back together.  In inline mode, this does nothing.
         """
+        # Remove this last event - not too important for clabel use
+        # since clabel normally doesn't have a maximum number of
+        # events, but best for cleanliness sake.
+        BlockingInput.pop(self)
+
         if self.inline:
             pass
         else:
             self.cs.pop_label()
             self.cs.ax.figure.canvas.draw()
 
-    def __call__(self,inline,n=-1,timeout=-1):
+    def __call__(self,inline,inline_spacing=5,n=-1,timeout=-1):
         self.inline=inline
+        self.inline_spacing=inline_spacing
+
         BlockingMouseInput.__call__(self,n=n,timeout=timeout,
                                     show_clicks=False)
 
