diff --git a/space_clip_editor_autotracker.py b/space_clip_editor_autotracker.py
index 1b9df0cf43518e0b9cd3f0b3af4f967f58c3d4d9..cd00f2e75463b2a162b027d8ada10453bdf1d9d3 100644
--- a/space_clip_editor_autotracker.py
+++ b/space_clip_editor_autotracker.py
@@ -2,7 +2,7 @@
 #
 #  This program is free software; you can redistribute it and/or
 #  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 3
+#  as published by the Free Software Foundation; either version 2
 #  of the License, or (at your option) any later version.
 #
 #  This program is distributed in the hope that it will be useful,
@@ -11,304 +11,544 @@
 #  GNU General Public License for more details.
 #
 #  You should have received a copy of the GNU General Public License
-#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 #
 # ##### END GPL LICENSE BLOCK #####
 
 bl_info = {
     "name": "Autotrack",
-    "author": "Miika Puustinen, Matti Kaihola",
-    "version": (0, 0, 95),
+    "author": "Miika Puustinen, Matti Kaihola, Stephen Leger",
+    "version": (0, 0, 99),
     "blender": (2, 78, 0),
     "location": "Movie clip Editor > Tools Panel > Autotrack",
     "description": "Motion Tracking with automatic feature detection.",
     "warning": "",
-    "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Motion_Tracking/Auto_Track",
+    "wiki_url": "https://github.com/miikapuustinen/blender_autotracker",
     "category": "Motion Tracking",
     }
 
-
 import bpy
+import bgl
+import blf
 import math
-
-
-class AutotrackerOperator(bpy.types.Operator):
+from mathutils import Vector
+from bpy.types import Operator, Panel, PropertyGroup, WindowManager
+from bpy.props import BoolProperty, FloatProperty, IntProperty, EnumProperty, PointerProperty
+
+# for debug purpose
+import time
+
+# http://blenderscripting.blogspot.ch/2011/07/bgl-drawing-with-opengl-onto-blender-25.html
+class GlDrawOnScreen():
+    black = (0.0, 0.0, 0.0, 0.7)
+    white = (1.0, 1.0, 1.0, 0.5)
+    progress_colour = (0.2, 0.7, 0.2, 0.5)
+    def String(self, text, x, y, size, colour):
+        ''' my_string : the text we want to print
+            pos_x, pos_y : coordinates in integer values
+            size : font height.
+            colour : used for definining the colour'''
+        dpi, font_id = 72, 0 # dirty fast assignment
+        bgl.glColor4f(*colour)
+        blf.position(font_id, x, y, 0)
+        blf.size(font_id, size, dpi)
+        blf.draw(font_id, text)
+    def _end(self):
+        bgl.glEnd()
+        bgl.glPopAttrib()
+        bgl.glLineWidth(1)
+        bgl.glDisable(bgl.GL_BLEND)
+        bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
+    def _start_line(self, colour, width=2, style=bgl.GL_LINE_STIPPLE):
+        bgl.glPushAttrib(bgl.GL_ENABLE_BIT)
+        bgl.glLineStipple(1, 0x9999)
+        bgl.glEnable(style)
+        bgl.glEnable(bgl.GL_BLEND)
+        bgl.glColor4f(*colour)
+        bgl.glLineWidth(width)
+        bgl.glBegin(bgl.GL_LINE_STRIP)
+    def Rectangle(self, x0, y0, x1, y1, colour, width=2, style=bgl.GL_LINE):
+        self._start_line(colour, width, style) 
+        bgl.glVertex2i(x0, y0)
+        bgl.glVertex2i(x1, y0)
+        bgl.glVertex2i(x1, y1)
+        bgl.glVertex2i(x0, y1)
+        bgl.glVertex2i(x0, y0)
+        self._end()
+    def Polygon(self, pts, colour):
+        bgl.glPushAttrib(bgl.GL_ENABLE_BIT)
+        bgl.glEnable(bgl.GL_BLEND)
+        bgl.glColor4f(*colour)    
+        bgl.glBegin(bgl.GL_POLYGON)
+        for pt in pts:
+            x, y = pt
+            bgl.glVertex2f(x, y)  
+        self._end()
+    def ProgressBar(self, x, y, width, height, start, percent):
+        x1, y1 = x+width, y+height
+        # progress from current point to either start or end
+        xs = x+(x1-x) * float(start)
+        if percent > 0:
+            # going forward
+            xi = xs+(x1-xs) * float(percent)
+        else:
+            # going backward
+            xi = xs-(x-xs) * float(percent)
+        self.Polygon([(xs, y), (xs, y1), (xi, y1), (xi, y)], self.progress_colour)
+        self.Rectangle(x, y, x1, y1, self.white, width=1)
+        
+def draw_callback(self, context):
+    #print("draw_callback : %s" % (self.progress))
+    self.gl.ProgressBar(10, 24, 200, 16, self.start, self.progress)
+    self.gl.String(str(int(100*abs(self.progress)))+"% ESC to Cancel", 14, 28, 10, self.gl.white)
+    
+class OP_Tracking_auto_tracker(Operator):
     """Autotrack. Esc to cancel."""
-    bl_idname = "wm.modal_timer_operator"
-    bl_label = "Modal Timer Operator"
+    bl_idname = "tracking.auto_track"
+    bl_label = "AutoTracking"
 
-    limits = bpy.props.IntProperty(default=0)
     _timer = None
-
-    def active_clip(self):
-        area = [i for i in bpy.context.screen.areas if i.type == 'CLIP_EDITOR'][0]
-        clip = area.spaces.active.clip.name
-        return clip
-
+    _draw_handler = None
+    
+    gl = GlDrawOnScreen()
+    progress = 0
+    limits = 0
+    t = 0
+    
+    def find_track_start(self, track):
+        for m in track.markers:
+            if not m.mute:
+                return m.frame
+        return track.markers[0].frame
+        
+    def find_track_end(self, track):
+        for m in reversed(track.markers):
+            if not m.mute:
+                return m.frame
+        return track.markers[-1].frame-1
+        
+    def find_track_length(self, track):
+        tstart = self.find_track_start(track)
+        tend   = self.find_track_end(track)
+        return tend-tstart
+    
+    def show_tracks(self, context):
+        scene = context.scene
+        clip  = context.area.spaces.active.clip
+        tracks = clip.tracking.tracks
+        for track in tracks:
+            track.hide = False
+        
+    def get_vars_from_context(self, context):    
+        scene = context.scene
+        props = context.window_manager.autotracker_props
+        clip  = context.area.spaces.active.clip
+        tracks = clip.tracking.tracks
+        current_frame = scene.frame_current
+        clip_end   = clip.frame_start+clip.frame_duration
+        clip_start = clip.frame_start
+        if props.track_backwards:
+            last_frame = min(clip_end, current_frame+props.frame_separation)
+        else:
+            last_frame = max(clip_start, current_frame-props.frame_separation)
+        return scene, props, clip, tracks, current_frame, last_frame
+    
+    def delete_tracks(self, to_delete):
+        bpy.ops.clip.select_all(action='DESELECT')
+        for track in to_delete:
+            track.select = True
+        bpy.ops.clip.delete_track()
+        
     # DETECT FEATURES
-    def auto_features(self, delete_threshold, limits):
-        tracks = []
+    def auto_features(self, context):
+        """
+            Detect features 
+        """
+        t = time.time()
+        
+        scene, props, clip, tracks, current_frame, last_frame = self.get_vars_from_context(context)
+        
         selected = []
         old = []
         to_delete = []
-
+        width = clip.size[0]
+        delete_threshold = float(props.delete_threshold)/100.0
+        
         bpy.ops.clip.select_all(action='DESELECT')
-
+        
         # Detect Features
         bpy.ops.clip.detect_features(
-            threshold=bpy.context.scene.autotracker_props.df_threshold,
-            min_distance=bpy.context.scene.autotracker_props.df_distance,
-            margin=bpy.context.scene.autotracker_props.df_margin,
-            placement=bpy.context.scene.autotracker_props.placement_list
+            threshold=props.df_threshold,
+            min_distance=props.df_distance/100.0*width,
+            margin=props.df_margin/100.0*width,
+            placement=props.placement_list
             )
-
-        current_frame = bpy.context.scene.frame_current
-
-        tracks = bpy.data.movieclips[self.active_clip()].tracking.tracks
+            
+        # filter new and old tracks
         for track in tracks:
-            if track.markers.find_frame(current_frame) is not None:
-                if track.select is not True and track.hide is False and track.markers.find_frame(current_frame).mute is False:
+            if track.hide or track.lock:
+                continue
+            marker = track.markers.find_frame(current_frame)
+            if marker is not None:
+                if (not track.select) and (not marker.mute):
                     old.append(track)
-                if track.select is True:
+                if track.select:
                     selected.append(track)
-
+        
+        added_tracks = len(selected)
+        
         # Select overlapping new markers
-        for i in selected:
-            for j in old:
-                i_marker = i.markers.find_frame(current_frame)
-                j_marker = j.markers.find_frame(current_frame)
-                distance = math.sqrt(((i_marker.co[0] - j_marker.co[0])**2) + ((i_marker.co[1] - j_marker.co[1])**2))
-
+        for track_new in selected:
+            marker0 = track_new.markers.find_frame(current_frame)
+            for track_old in old:
+                marker1 = track_old.markers.find_frame(current_frame)
+                distance = (marker1.co-marker0.co).length
                 if distance < delete_threshold:
-                    to_delete.append(i)
+                    to_delete.append(track_new)
+                    added_tracks -= 1
                     break
-
-        # delete short tracks
-        for track in tracks:
-            muted = []
-            active = []
-            # print(track)
-            for marker in track.markers:
-                if marker.mute is True:
-                    muted.append(marker)
-                else:
-                    active.append(marker)
-            if len(muted) > 3 and len(active) < 1:
-                to_delete.append(track)
-
-            if len(track.markers) > 1 and len(active) == 0:
-                to_delete.append(track)
-
+        
         # Delete Overlapping Markers
-        bpy.ops.clip.select_all(action='DESELECT')
-        for track in tracks:
-            if track in to_delete:
-                track.select = True
-
-        bpy.ops.clip.delete_track()
-
-        print(str(len(selected)) + "/" + str(len(tracks)) + " tracks tracking.")
-
+        self.delete_tracks(to_delete)
+        print("auto_features %.4f seconds add:%s tracks." % (time.time()-t, added_tracks))
+    
     # AUTOTRACK FRAMES
     def track_frames_backward(self):
-        bpy.ops.clip.track_markers(backwards=True, sequence=False)
-
+        # INVOKE_DEFAULT to show progress and take account of frame_limit
+        t = time.time()
+        res = bpy.ops.clip.track_markers('INVOKE_DEFAULT', backwards=True, sequence=True)
+        print("track_frames_backward %.2f seconds %s" % (time.time()-t, res))
+        
     def track_frames_forward(self):
-        bpy.ops.clip.track_markers(backwards=False, sequence=False)
-
-    # REMOVE BAD MARKERS
-    def remove_extra(self, jump_cut, track_backwards):
-        trackers = []
-
-        if track_backwards is True:
-            one_frame = -1
-            two_frames = -2
+        # INVOKE_DEFAULT to show progress and take account of frame_limit
+        t = time.time()
+        res = bpy.ops.clip.track_markers('INVOKE_DEFAULT', backwards=False, sequence=True)
+        print("track_frames_forward %.2f seconds %s" % (time.time()-t, res))
+    
+    def get_active_tracks(self, context):
+        scene, props, clip, tracks, current_frame, last_frame = self.get_vars_from_context(context)
+        # Select active trackers for tracking
+        #bpy.ops.clip.select_all(action='DESELECT')
+        active_tracks = []
+        for track in tracks:
+            if track.hide or track.lock:
+                continue
+            if len(track.markers) < 2:
+                active_tracks.append(track)
+            else:
+                marker = track.markers.find_frame(current_frame)
+                if (marker is not None) and (not marker.mute):
+                    active_tracks.append(track) 
+        return active_tracks
+    
+    def select_active_tracks(self, context):
+        t = time.time()
+        scene, props, clip, tracks, current_frame, last_frame = self.get_vars_from_context(context)
+        # Select active trackers for tracking
+        bpy.ops.clip.select_all(action='DESELECT')
+        selected = self.get_active_tracks(context)
+        for track in selected:
+            track.select = True
+        print("select_active_tracks %.2f seconds selected:%s" % (time.time()-t, len(selected)))
+        return selected
+        
+    def estimate_motion(self, context, last, frame):
+        """
+            compute mean pixel motion for current frame
+            TODO: use statistic here to make filtering more efficient
+            last : last frame number
+            frame: current frame number
+            return mean pixel distance error
+        """
+        scene, props, clip, tracks, current_frame, last_frame = self.get_vars_from_context(context)
+        nbtracks = 0
+        distance = 0.0
+        for track in tracks:
+            if track.hide or track.lock:
+                continue
+            marker0 = track.markers.find_frame(frame)
+            marker1 = track.markers.find_frame(last)
+            if marker0 is not None and marker1 is not None:
+                d = (marker0.co-marker1.co).length
+                # skip fixed tracks
+                if d > 0:
+                    distance += d
+                    nbtracks += 1
+        if nbtracks > 0:
+            mean = distance / nbtracks
         else:
-            one_frame = 1
-            two_frames = 2
-
-        if self.limits >= 3:
-            trackers = bpy.data.movieclips[self.active_clip()].tracking.tracks
-
-            for i in trackers:
-                if len(i.markers) > 5:
-                    current_frame = bpy.context.scene.frame_current
-
-                    if (i.markers.find_frame(current_frame) is not None and
-                        i.markers.find_frame(current_frame - one_frame) is not None and
-                       i.markers.find_frame(current_frame - two_frames) is not None):
-
-                        key_frame = i.markers.find_frame(current_frame).co
-                        prev_frame = i.markers.find_frame(current_frame - one_frame).co
-                        distance = math.sqrt(((key_frame[0] - prev_frame[0])**2) + ((key_frame[1] - prev_frame[1])**2))
-                        # Jump Cut threshold
-                        if distance > jump_cut:
-                            if (i.markers.find_frame(current_frame) is not None and
-                               i.markers.find_frame(current_frame - one_frame) is not None):
-
-                                # create new track to new pos
-                                new_track = \
-                                    bpy.data.movieclips[self.active_clip()].tracking.tracks.new(frame=current_frame)
-                                new_track.markers[0].co = i.markers.find_frame(current_frame).co
-                                i.markers.find_frame(current_frame).mute = True
-                                i.markers.find_frame(current_frame - one_frame).mute = True
-
+            # arbitrary set to prevent division by 0 error
+            mean = 10
+        
+        return mean
+    
+    # REMOVE SMALL TRACKS
+    def remove_small(self, context):
+        t = time.time()
+        scene, props, clip, tracks, current_frame, last_frame = self.get_vars_from_context(context)
+        to_delete = []
+        bpy.ops.clip.select_all(action='DESELECT')
+        for track in tracks:
+            if track.hide or track.lock:
+                continue
+            if len(track.markers) > 1:
+                marker = track.markers.find_frame(current_frame)
+                if marker is None and self.find_track_length(track) < props.small_tracks:
+                    to_delete.append(track)
+        deleted_tracks = len(to_delete)
+        self.delete_tracks(to_delete)
+        print("remove_small %.4f seconds %s tracks deleted." % (time.time()-t, deleted_tracks))
+    
+    def split_track(self, context, track, split_frame, skip=0):
+        scene, props, clip, tracks, current_frame, last_frame = self.get_vars_from_context(context)
+        if props.track_backwards:
+            end = scene.frame_start
+            step = -1
+        else:
+            end = scene.frame_end
+            step = 1
+        new_track = \
+            tracks.new(frame=split_frame)
+        for frame in range(split_frame, end, step):
+            marker = track.markers.find_frame(frame)
+            if marker is None:
+                return
+            # add new marker on new track for frame    
+            if abs(frame - split_frame) >= skip:    
+                new_marker = new_track.markers.find_frame(frame)
+                if new_marker is None:
+                    new_marker = new_track.markers.insert_frame(frame)
+                new_marker.co = marker.co
+            # remove marker on track for frame
+            if frame == split_frame:
+                track.hide = True
+            else:
+                track.markers.delete_frame(frame)
+            marker.mute = True
+                    
+    # REMOVE JUMPING MARKERS
+    def remove_jumping(self, context):
+        
+        t = time.time()
+        
+        scene, props, clip, tracks, current_frame, last_frame = self.get_vars_from_context(context)
+        
+        if props.track_backwards:
+            step = -1
+        else:
+            step = 1
+        
+        to_split = [None for track in tracks]
+        for frame in range(last_frame, current_frame, step):
+            
+            last = frame - step
+            
+            # mean motion (normalized [0-1]) distance for tracks between last and current frame
+            mean = self.estimate_motion(context, last, frame)
+            
+            # how much a track is allowed to move 
+            allowed = mean * props.jump_cut
+        
+            for i, track in enumerate(tracks):
+                if track.hide or track.lock:
+                    continue
+                marker0 = track.markers.find_frame(frame)
+                marker1 = track.markers.find_frame(last)
+                if marker0 is not None and marker1 is not None:
+                    distance = (marker0.co-marker1.co).length
+                    # Jump Cut threshold
+                    if distance > allowed:
+                        if to_split[i] is None:
+                            to_split[i] = [frame, frame]
+                        else:
+                            to_split[i][1] = frame 
+        
+        jumping = 0
+        for i, split in enumerate(to_split):
+            if split is not None:
+                self.split_track(context, tracks[i], split[0], abs(split[0]-split[1]))
+                jumping += 1
+                    
+        print("remove_jumping :%.4f seconds %s tracks cut." % (time.time()-t, jumping))  
+    
+    def get_frame_range(self, context):
+        """
+            get tracking frames range
+            use clip limits when clip shorter than scene 
+            else use scene limits
+        """
+        scene, props, clip, tracks, current_frame, last_frame = self.get_vars_from_context(context)
+        frame_start = max(scene.frame_start, clip.frame_start)
+        frame_end = min(scene.frame_end, clip.frame_start+clip.frame_duration)
+        frame_duration = frame_end - frame_start
+        return frame_start, frame_end, frame_duration
+        
     def modal(self, context, event):
-        scene = bpy.context.scene
-        if (event.type in {'ESC'} or scene.frame_current == scene.frame_end + 1 or
-           scene.frame_current == scene.frame_start - 1):
-            self.limits = 0
+        
+        if event.type in {'ESC'}:
+            print("Cancelling")
             self.cancel(context)
             return {'FINISHED'}
-
-        if event.type == 'TIMER':
-
-            # PROP VARIABLES
-            delete_threshold = bpy.context.scene.autotracker_props.delete_threshold
-            endframe = bpy.context.scene.frame_end
-            start_frame = bpy.context.scene.frame_start
-            frame_separate = bpy.context.scene.autotracker_props.frame_separation
-            margin = bpy.context.scene.autotracker_props.df_margin
-            distance = bpy.context.scene.autotracker_props.df_distance
-            threshold = bpy.context.scene.autotracker_props.df_threshold
-            jump_cut = bpy.context.scene.autotracker_props.jump_cut
-            track_backwards = bpy.context.scene.autotracker_props.track_backwards
-
-            # Auto features every frame separate step
-            if bpy.context.scene.frame_current % frame_separate == 0 or self.limits == 0:
-                limits = self.limits
-                self.auto_features(delete_threshold, limits)
-
-            # Select all trackers for tracking
-            select_all = bpy.ops.clip.select_all(action='SELECT')
-            tracks = bpy.data.movieclips[self.active_clip()].tracking.tracks
-            active_tracks = []
-            for track in tracks:
-                if track.lock is True:
-                    track.select = False
-                else:
-                    active_tracks.append(track)
-
-            # Forwards or backwards tracking
-            if track_backwards is True:
-                if len(active_tracks) == 0:
-                    print("No new tracks created. Doing nothing.")
-                    self.limits = 0
-                    self.cancel(context)
-                    return {'FINISHED'}
-                else:
-                    self.track_frames_backward()
-            else:
-                if len(active_tracks) == 0:
-                    print("No new tracks created. Doing nothing.")
-                    self.limits = 0
-                    self.cancel(context)
-                    return {'FINISHED'}
-                else:
-                    self.track_frames_forward()
-
-            # Remove bad tracks
-            self.remove_extra(jump_cut, track_backwards)
-
-            self.limits += 1
-
-        return {'PASS_THROUGH'}
-
-    def execute(self, context):
-        wm = context.window_manager
-        self._timer = wm.event_timer_add(time_step=0.5, window=context.window)
-        wm.modal_handler_add(self)
+        
+        scene, props, clip, tracks, current_frame, last_frame = self.get_vars_from_context(context)
+        frame_start, frame_end, frame_duration = self.get_frame_range(context)
+        
+        if (((not props.track_backwards) and current_frame >= frame_end) or
+            (props.track_backwards and current_frame <= frame_start)):
+            print("Reached clip end")
+            self.cancel(context)
+            return {'FINISHED'}
+        
+        # dont run this modal while tracking operator runs
+        # Known issue, youll have to keep ESC pressed
+        if event.type not in {'TIMER'} or context.scene.frame_current != self.next_frame:
+            return {'PASS_THROUGH'}
+        
+        # prevent own TIMER event while running
+        self.stop_timer(context)
+        
+        if props.track_backwards:
+            self.next_frame = scene.frame_current - props.frame_separation
+            total = self.start_frame - frame_start
+        else:
+            self.next_frame = scene.frame_current + props.frame_separation
+            total = frame_end - self.start_frame
+        
+        if total > 0:
+            self.progress = (current_frame-self.start_frame)/total
+        else:
+            self.progress = 0
+            
+        print("Tracking frame %s" % (scene.frame_current))
+        
+        # Remove bad tracks before adding new ones
+        self.remove_small(context)
+        self.remove_jumping(context)
+    
+        # add new tracks
+        self.auto_features(context)
+
+        # Select active trackers for tracking
+        active_tracks = self.select_active_tracks(context)
+        
+        # finish if there is nothing to track
+        if len(active_tracks) == 0:
+            print("No new tracks created. Doing nothing.")
+            self.cancel(context)
+            return {'FINISHED'}
+        
+        # setup frame_limit on tracks
+        for track in active_tracks:
+            track.frames_limit = 0
+        active_tracks[0].frames_limit = props.frame_separation
+        
+        # Forwards or backwards tracking
+        if props.track_backwards:
+            self.track_frames_backward()
+        else:
+            self.track_frames_forward()
+            
+        # setup a timer to broadcast a TIMER event to force modal to re-run as fast as possible (not waiting for any mouse or keyboard event) 
+        self.start_timer(context)
+        
+        return {'RUNNING_MODAL'}
+      
+    def invoke(self, context, event):
+        scene = context.scene
+        frame_start, frame_end, frame_duration = self.get_frame_range(context)
+        
+        if scene.frame_current > frame_end:
+            scene.frame_current = frame_end
+        elif scene.frame_current < frame_start:
+            scene.frame_current = frame_start
+        
+        self.start_frame = scene.frame_current
+        self.start = (scene.frame_current-frame_start) / (frame_duration)
+        self.progress = 0
+        
+        # keep track of frame at witch we should detect new features and filter tracks
+        self.next_frame = scene.frame_current
+        
+        # draw progress
+        args = (self, context)
+        self._draw_handler = bpy.types.SpaceClipEditor.draw_handler_add(draw_callback, args, 'WINDOW', 'POST_PIXEL')
+
+        self.start_timer(context)
+        context.window_manager.modal_handler_add(self)
         return {'RUNNING_MODAL'}
+    
+    def __init__(self):
+        self.t = time.time()
 
+    def __del__(self):
+        print("AutoTrack %.2f seconds" % (time.time()-self.t))
+        
+    def execute(self, context):
+        print("execute")
+        return {'FINISHED'}
+        
+    def stop_timer(self, context):
+        context.window_manager.event_timer_remove(self._timer)
+    
+    def start_timer(self, context):
+        self._timer = context.window_manager.event_timer_add(time_step=0.1, window=context.window)
+        
     def cancel(self, context):
-        wm = context.window_manager
-        wm.event_timer_remove(self._timer)
-
-
-# UI CREATION #
-
-class Autotracker_UI(bpy.types.Panel):
-    """Creates a Panel in the Render Layer properties window"""
-    bl_label = "Autotrack"
-    bl_idname = "autotrack"
-    bl_space_type = 'CLIP_EDITOR'
-    bl_region_type = 'TOOLS'
-    bl_category = "Track"
-
-    # Draw UI
-    def draw(self, context):
-        layout = self.layout
-
-        row = layout.row(align=True)
-        row.scale_y = 1.5
-
-        props = row.operator("wm.modal_timer_operator", text="Autotrack!     ", icon='PLAY')
-
-        row = layout.row(align=True)
-        row.prop(context.scene.autotracker_props, "track_backwards")
-
-        row = layout.row(align=True)  # make next row
-        row.prop(context.scene.autotracker_props, "delete_threshold")
-
-        row = layout.row(align=True)
-        row.prop(context.scene.autotracker_props, "frame_separation", text="Frame Separation")
-
-        row = layout.row(align=True)
-        row.prop(context.scene.autotracker_props, "jump_cut", text="Jump Threshold")
-
-        row = layout.row(align=True)
-        row.label(text="Detect Features Settings:")
-
-        row = layout.row(align=True)
-        row.prop(context.scene.autotracker_props, "df_margin", text="Margin:")
-
-        row = layout.row(align=True)
-        row.prop(context.scene.autotracker_props, "df_threshold", text="Threshold:")
-
-        row = layout.row(align=True)
-        row.prop(context.scene.autotracker_props, "df_distance", text="Distance:")
-
-        row = layout.row(align=True)
-        row.label(text="Feature Placement:")
-
-        row = layout.row(align=True)
-        row.prop(context.scene.autotracker_props, "placement_list")
-
-
-class AutotrackerSettings(bpy.types.PropertyGroup):
+        self.stop_timer(context)
+        self.show_tracks(context)  
+        bpy.types.SpaceClipEditor.draw_handler_remove(self._draw_handler, 'WINDOW')
+    
+    @classmethod
+    def poll(cls, context):
+        return (context.area.spaces.active.clip is not None) 
+    
+class AutotrackerSettings(PropertyGroup):
     """Create properties"""
-    df_margin = bpy.props.IntProperty(
+    df_margin = FloatProperty(
             name="Detect Features Margin",
             description="Only features further margin pixels from the image edges are considered.",
-            default=16,
+            subtype='PERCENTAGE',
+            default=5,
             min=0,
-            max=2000
+            max=100
             )
-    df_threshold = bpy.props.FloatProperty(
+            
+    df_threshold = FloatProperty(
             name="Detect Features Threshold",
             description="Threshold level to concider feature good enough for tracking.",
-            default=0.01,
+            default=0.3,
             min=0.0,
             max=1.0
             )
-
-    df_distance = bpy.props.IntProperty(
+    # Note: merge this one with delete_threshold        
+    df_distance = FloatProperty(
             name="Detect Features Distance",
             description="Minimal distance accepted between two features.",
-            default=64,
+            subtype='PERCENTAGE',
+            default=8,
             min=1,
-            max=300
+            max=100
             )
 
-    delete_threshold = bpy.props.FloatProperty(
+    delete_threshold = FloatProperty(
             name="New Marker Threshold",
             description="Threshold how near new features can appear during autotracking.",
-            default=0.1,
-            min=0.0,
-            max=1.0
+            subtype='PERCENTAGE',
+            default=8,
+            min=1,
+            max=100
             )
-
-    frame_separation = bpy.props.IntProperty(
+            
+    small_tracks = IntProperty(
+            name="Minimum track length",
+            description="Delete tracks shortest than this number of frames (set to 0 to keep all tracks).",
+            default=50,
+            min=1,
+            max=1000
+            )
+            
+    frame_separation = IntProperty(
             name="Frame Separation",
             description="How often new features are generated.",
             default=5,
@@ -316,20 +556,20 @@ class AutotrackerSettings(bpy.types.PropertyGroup):
             max=100
             )
 
-    jump_cut = bpy.props.FloatProperty(
+    jump_cut = FloatProperty(
             name="Jump Cut",
             description="Distance how much a marker can travel before it is considered "
-                        "to be a bad track and cut. A new track is added.",
-            default=0.1,
+                        "to be a bad track and cut. A new track is added. (factor relative to mean motion)",
+            default=5.0,
             min=0.0,
-            max=1.0
-    )
+            max=50.0
+            )
 
-    track_backwards = bpy.props.BoolProperty(
+    track_backwards = BoolProperty(
             name="AutoTrack Backwards",
             description="Autotrack backwards.",
             default=False
-    )
+            )
 
     # Dropdown menu
     list_items = [
@@ -338,28 +578,80 @@ class AutotrackerSettings(bpy.types.PropertyGroup):
         ("OUTSIDE_GPENCIL", "Outside Grease Pencil", "", 3),
     ]
 
-    placement_list = bpy.props.EnumProperty(
+    placement_list = EnumProperty(
             name="",
-            description="Feaure Placement",
+            description="Feature Placement",
             items=list_items
             )
+    
+"""
+    NOTE:
+    All size properties are in percent of clip size, so presets does not depends on clip size
+"""
+class AutotrackerPanel(Panel):
+    """Creates a Panel in the Render Layer properties window"""
+    bl_label = "Autotrack"
+    bl_idname = "autotrack"
+    bl_space_type = 'CLIP_EDITOR'
+    bl_region_type = 'TOOLS'
+    bl_category = "Track"
+    
+    @classmethod
+    def poll(cls, context):
+        return (context.area.spaces.active.clip is not None) 
+    
+    # Draw UI
+    def draw(self, context):
+        layout = self.layout
+        wm = context.window_manager
+        row = layout.row(align=True)
+        row.scale_y = 1.5
 
+        props = row.operator("tracking.auto_track", text="Autotrack!     ", icon='PLAY')
 
-# REGISTER BLOCK #
-def register():
-    bpy.utils.register_class(AutotrackerOperator)
-    bpy.utils.register_class(Autotracker_UI)
-    bpy.utils.register_class(AutotrackerSettings)
+        row = layout.row(align=True)
+        row.prop(wm.autotracker_props, "track_backwards")
 
-    bpy.types.Scene.autotracker_props = \
-        bpy.props.PointerProperty(type=AutotrackerSettings)
+        row = layout.row(align=True)  # make next row
+        row.prop(wm.autotracker_props, "delete_threshold")
+        
+        row = layout.row(align=True)  # make next row
+        row.prop(wm.autotracker_props, "small_tracks")
 
+        row = layout.row(align=True)
+        row.prop(wm.autotracker_props, "frame_separation", text="Frame Separation")
+
+        row = layout.row(align=True)
+        row.prop(wm.autotracker_props, "jump_cut", text="Jump Threshold")
+
+        row = layout.row(align=True)
+        row.label(text="Detect Features Settings:")
+
+        row = layout.row(align=True)
+        row.prop(wm.autotracker_props, "df_margin", text="Margin:")
+
+        row = layout.row(align=True)
+        row.prop(wm.autotracker_props, "df_threshold", text="Threshold:")
 
+        row = layout.row(align=True)
+        row.prop(wm.autotracker_props, "df_distance", text="Distance:")
+
+        row = layout.row(align=True)
+        row.label(text="Feature Placement:")
+
+        row = layout.row(align=True)
+        row.prop(wm.autotracker_props, "placement_list")
+                    
+def register():
+    bpy.utils.register_class(AutotrackerSettings)
+    WindowManager.autotracker_props = \
+        PointerProperty(type=AutotrackerSettings)
+    bpy.utils.register_module(__name__)  
+    
 def unregister():
-    bpy.utils.unregister_class(AutotrackerOperator)
-    bpy.utils.unregister_class(Autotracker_UI)
     bpy.utils.unregister_class(AutotrackerSettings)
-
+    bpy.utils.unregister_module(__name__)   
+    del WindowManager.autotracker_props
 
 if __name__ == "__main__":
     register()