From 558876b305a19e31f5fa143773f1e6ab58afbb31 Mon Sep 17 00:00:00 2001
From: Ivica Ico Bukvic <ico@vt.edu>
Date: Mon, 4 Apr 2011 00:47:00 -0400
Subject: [PATCH] Pd-0.42.5-extended-l2ork-dev-20110403.tar.bz2

---
 src/g_all_guis.h          |   8 ++
 src/g_bang.c              | 150 ++++++++++++++++++++++++++++++++++++--
 src/g_canvas.c            |  31 +++++++-
 src/g_canvas.h            |  14 ++++
 src/g_editor.c            |  51 +++++++------
 src/g_graph.c             |   6 +-
 src/g_hdial.c             | 149 +++++++++++++++++++++++++++++++++++--
 src/g_hslider.c           | 148 +++++++++++++++++++++++++++++++++++--
 src/g_mycanvas.c          | 148 +++++++++++++++++++++++++++++++++++--
 src/g_numbox.c            | 150 ++++++++++++++++++++++++++++++++++++--
 src/g_toggle.c            | 150 ++++++++++++++++++++++++++++++++++++--
 src/g_vdial.c             | 149 +++++++++++++++++++++++++++++++++++--
 src/g_vslider.c           | 149 +++++++++++++++++++++++++++++++++++--
 src/g_vumeter.c           | 148 +++++++++++++++++++++++++++++++++++--
 src/m_memory.c            |   5 ++
 src/m_pd.c                |  64 ++++++++++++++++
 src/m_pd.h                |   2 +-
 src/makefile.dependencies |   5 +-
 src/pd.tk                 |  12 ++-
 src/s_inter.c             |  18 +++++
 20 files changed, 1459 insertions(+), 98 deletions(-)

diff --git a/src/g_all_guis.h b/src/g_all_guis.h
index 6899cad29..c478950b0 100644
--- a/src/g_all_guis.h
+++ b/src/g_all_guis.h
@@ -124,6 +124,9 @@
 #define SCALEHANDLE_WIDTH   5
 #define SCALEHANDLE_HEIGHT  5
 
+#define LABELHANDLE_WIDTH	5
+#define LABELHANDLE_HEIGHT	5
+
 typedef struct _iem_fstyle_flags
 {
     unsigned int x_font_style:6;
@@ -166,6 +169,7 @@ typedef struct _scalehandle
     t_pd       h_pd;
     t_gobj    *h_master;
     t_symbol  *h_bindsym;
+	int		   h_scale;
     char       h_pathname[64];
     char       h_outlinetag[64];
     int        h_dragon;
@@ -204,6 +208,10 @@ typedef struct _iemgui
 	int 			   scale_offset_x;
 	int				   scale_offset_y;
 	int				   scale_vis;
+	t_pd			   *x_lhandle;
+	int				   label_offset_x;
+	int				   label_offset_y;
+	int				   label_vis;
 } t_iemgui;
 
 typedef struct _iemguidummy
diff --git a/src/g_bang.c b/src/g_bang.c
index aebd1d832..79aa1d2c1 100644
--- a/src/g_bang.c
+++ b/src/g_bang.c
@@ -53,6 +53,9 @@ void bng_draw_new(t_bng *x, t_glist *glist)
 	t_scalehandle *sh = (t_scalehandle *)x->x_gui.x_handle;
 	sprintf(sh->h_pathname, ".x%x.h%x", (int)canvas, (int)sh);
 
+	t_scalehandle *lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	sprintf(lh->h_pathname, ".x%x.h%x", (int)canvas, (int)lh);
+
 	//if (glist_isvisible(canvas)) {
 
 		t_gobj *y = (t_gobj *)x;
@@ -152,6 +155,8 @@ void bng_draw_erase(t_bng* x, t_glist* glist)
 	if (x->x_gui.x_fsf.x_selected) {
 		t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
 		sys_vgui("destroy %s\n", sh->h_pathname);
+		t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
+		sys_vgui("destroy %s\n", lh->h_pathname);
 	}
 /*
     sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x);
@@ -224,6 +229,7 @@ void bng_draw_select(t_bng* x, t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 	t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
+	t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
 
 	if (glist_isvisible(canvas)) {
 
@@ -239,8 +245,8 @@ void bng_draw_select(t_bng* x, t_glist* glist)
 			sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor bottom_right_corner\n",
 				 sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT);
 			sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxBNG}\n",
-				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w - SCALEHANDLE_WIDTH,
-				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT,
+				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w - SCALEHANDLE_WIDTH - 1,
+				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT - 1,
 				 SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT,
 				 sh->h_pathname, x, x);
 			sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
@@ -251,6 +257,27 @@ void bng_draw_select(t_bng* x, t_glist* glist)
 				 sh->h_pathname, sh->h_bindsym->s_name);
 			x->x_gui.scale_vis = 1;
 
+			if (strcmp(x->x_gui.x_lab->s_name, "empty") != 0)
+			{
+				if (x->x_gui.label_vis)
+					sys_vgui("destroy %s\n", lh->h_pathname);
+
+				sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor crosshair\n",
+					lh->h_pathname, LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT);
+				sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxLABEL %lxBNG}\n",
+					canvas, x->x_gui.x_obj.te_xpix+ x->x_gui.x_ldx - LABELHANDLE_WIDTH,
+					x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - LABELHANDLE_HEIGHT,
+					LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT,
+					lh->h_pathname, x, x);
+				sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 0 0 \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name); 
+				x->x_gui.label_vis = 1;
+			}
+
 			sys_vgui(".x%lx.c addtag selected withtag %lxBNG\n", canvas, x);
 		}
 		else
@@ -261,6 +288,8 @@ void bng_draw_select(t_bng* x, t_glist* glist)
 			sys_vgui(".x%lx.c dtag %lxBNG selected\n", canvas, x);
 			sys_vgui("destroy %s\n", sh->h_pathname);
 			x->x_gui.scale_vis = 0;
+			sys_vgui("destroy %s\n", lh->h_pathname);
+			x->x_gui.label_vis = 0;
 		}
 	}
 }
@@ -270,11 +299,17 @@ static void bng__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t_fl
 
 	t_bng *x = (t_bng *)(sh->h_master);
 
-	if (xxx) x->x_gui.scale_offset_x = xxx;
-	if (yyy) x->x_gui.scale_offset_y = yyy;
+ 	if (xxx) {
+ 		x->x_gui.scale_offset_x = xxx;
+ 		x->x_gui.label_offset_x = xxx;
+ 	}
+ 	if (yyy) {
+ 		x->x_gui.scale_offset_y = yyy;
+ 		x->x_gui.label_offset_y = yyy;
+ 	}
 
     int newstate = (int)f;
-    if (sh->h_dragon && newstate == 0)
+    if (sh->h_dragon && newstate == 0 && sh->h_scale)
     {
 		/* done dragging */
 
@@ -316,7 +351,7 @@ static void bng__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t_fl
 			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
 		}
     }
-    else if (!sh->h_dragon && newstate)
+    else if (!sh->h_dragon && newstate && sh->h_scale)
     {
 		/* dragging */
 		if (glist_isvisible(x->x_gui.x_glist))
@@ -332,13 +367,59 @@ static void bng__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t_fl
 		sh->h_dragx = 0;
 		sh->h_dragy = 0;
     }
+	else if (sh->h_dragon && newstate == 0 && !sh->h_scale)
+    {
+		/* done dragging */
+
+		/* first set up the undo apply */
+		canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
+
+		if (sh->h_dragx || sh->h_dragy) {
+
+			x->x_gui.x_ldx = x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x;
+			x->x_gui.x_ldy = x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y;
+
+			canvas_dirty(x->x_gui.x_glist, 1);
+		}
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			sys_vgui(".gfxstub%lx.dim.w_ent delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.dim.w_ent insert 0 %d\n", properties, x->x_gui.x_w);
+			//sys_vgui(".gfxstub%lx.dim.h_ent delete 0 end\n", properties);
+			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, x->x_gui.x_h);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist))
+		{
+			sys_vgui(".x%x.c delete %s\n", x->x_gui.x_glist, sh->h_outlinetag);
+			bng_draw_move(x, x->x_gui.x_glist);
+			sys_vgui("destroy %s\n", sh->h_pathname);
+			iemgui_select((t_gobj *)x, x->x_gui.x_glist, 1);
+			canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
+		}
+    }
+    else if (!sh->h_dragon && newstate && !sh->h_scale)
+    {
+		/* dragging */
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			sys_vgui("lower %s\n", sh->h_pathname);
+			t_scalehandle *othersh = (t_scalehandle *)x->x_gui.x_handle;
+			sys_vgui("lower .x%x.h%x\n", (int)glist_getcanvas(x->x_gui.x_glist), (int)othersh);
+		}
+
+		sh->h_dragx = 0;
+		sh->h_dragy = 0;
+    }
     sh->h_dragon = newstate;
 }
 
 static void bng__motionhook(t_scalehandle *sh,
 				    t_floatarg f1, t_floatarg f2)
 {
-    if (sh->h_dragon)
+    if (sh->h_dragon && sh->h_scale)
     {
 		t_bng *x = (t_bng *)(sh->h_master);
 		int dx = (int)f1, dy = (int)f2;
@@ -380,6 +461,38 @@ static void bng__motionhook(t_scalehandle *sh,
 			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, new_h);
 		}
     }
+	if (sh->h_dragon && !sh->h_scale)
+    {
+		t_bng *x = (t_bng *)(sh->h_master);
+		int dx = (int)f1, dy = (int)f2;
+		int newx, newy;
+		newx = x->x_gui.x_obj.te_xpix + x->x_gui.x_w - x->x_gui.scale_offset_x + dx;
+		newy = x->x_gui.x_obj.te_ypix + x->x_gui.x_h - x->x_gui.scale_offset_y + dy;
+
+		sh->h_dragx = dx;
+		sh->h_dragy = dy;
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			int new_x = x->x_gui.x_ldx - x->x_gui.label_offset_x + sh->h_dragx;
+			int new_y = x->x_gui.x_ldy - x->x_gui.label_offset_y + sh->h_dragy;
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, new_x);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, new_y);
+
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			int xpos=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		int ypos=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+			sys_vgui(".x%lx.c coords %lxLABEL %d %d\n",
+ 		    	canvas, x, xpos+x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x,
+ 		    	ypos+x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y);
+		}
+    }
 }
 
 void bng_draw(t_bng *x, t_glist *glist, int mode)
@@ -742,10 +855,26 @@ static void *bng_new(t_symbol *s, int argc, t_atom *argv)
     pd_bind(x->x_gui.x_handle, sh->h_bindsym = gensym(buf));
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
+	sh->h_scale = 1;
 	x->x_gui.scale_offset_x = 0;
 	x->x_gui.scale_offset_y = 0;
 	x->x_gui.scale_vis = 0;
 
+	/* label handle init */
+	t_scalehandle *lh;
+	char lhbuf[64];
+	x->x_gui.x_lhandle = pd_new(scalehandle_class);
+	lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	lh->h_master = (t_gobj*)x;
+	sprintf(lhbuf, "_h%x", (int)lh);
+	pd_bind(x->x_gui.x_lhandle, lh->h_bindsym = gensym(lhbuf));
+	sprintf(lh->h_outlinetag, "h%x", (int)lh);
+	lh->h_dragon = 0;
+	lh->h_scale = 0;
+	x->x_gui.label_offset_x = 0;
+	x->x_gui.label_offset_y = 0;
+	x->x_gui.label_vis = 0;
+
     return (x);
 }
 
@@ -764,6 +893,13 @@ static void bng_ff(t_bng *x)
 		pd_unbind(x->x_gui.x_handle, ((t_scalehandle *)x->x_gui.x_handle)->h_bindsym);
 		pd_free(x->x_gui.x_handle);
     }
+
+	/* label handle deconstructor */
+	if (x->x_gui.x_lhandle)
+	{
+		pd_unbind(x->x_gui.x_lhandle, ((t_scalehandle *)x->x_gui.x_lhandle)->h_bindsym);
+		pd_free(x->x_gui.x_lhandle);
+	}
 }
 
 void g_bang_setup(void)
diff --git a/src/g_canvas.c b/src/g_canvas.c
index 66591eb26..0847a0973 100644
--- a/src/g_canvas.c
+++ b/src/g_canvas.c
@@ -367,11 +367,39 @@ void glist_init(t_glist *x)
 }
 
     /* make a new glist.  It will either be a "root" canvas or else
-    it appears as a "text" object in another window (canvas_getcurrnet() 
+    it appears as a "text" object in another window (canvas_getcurrent() 
     tells us which.) */
 t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
 {
+	/*	first alloc one byte or redundant memory to prevent creation of objects with the same "name"
+		which leads to double-action invoked from every single action and eventually possible crashes
+
+		we keep a list of these redundant allocations and destroy them when pd quits */
+	//if (x->gl_owner && x->gl_env) {
+		t_redundant_mem *new_rm = (t_redundant_mem *)t_getbytes(sizeof(*new_rm));
+		new_rm->rm_what = (int)getbytes(1);
+		if (rm_start == NULL) {
+			//fprintf(stderr,"first allocation\n");
+			rm_start = new_rm;
+			rm_end = new_rm;
+		}
+		else if (rm_start == rm_end) {
+			//fprintf(stderr,"second allocation\n");
+			rm_end = new_rm;
+			rm_start->rm_next = rm_end;
+		}
+		else {
+			//fprintf(stderr,"allocation\n");
+			rm_end->rm_next = new_rm;
+			rm_end = new_rm;
+		}
+	//}
+
     t_canvas *x = (t_canvas *)pd_new(canvas_class);
+
+	/* now that we've created a new canvas, add canvas info to the new_rm */
+	new_rm->rm_canvas = x;
+
     t_canvas *owner = canvas_getcurrent();
     t_symbol *s = &s_;
     int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT;
@@ -463,6 +491,7 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
     x->gl_edit = !strncmp(x->gl_name->s_name, "Untitled", 8);
     x->gl_font = sys_nearestfontsize(font);
     pd_pushsym(&x->gl_pd);
+
     return(x);
 }
 
diff --git a/src/g_canvas.h b/src/g_canvas.h
index be574f249..24c2ac09e 100644
--- a/src/g_canvas.h
+++ b/src/g_canvas.h
@@ -40,6 +40,20 @@ in future releases.  The public (stable) API is in m_pd.h. */
 extern "C" {
 #endif
 
+/* 	redundant struct queue for maintaining a list of redundantly
+	allocated memory chunks to avoid double-entry bug. these are
+	instantiated inside canvas_new since the bug only affects new
+	canvases/abstractions rather than individual objects. the queue
+	is destructed in m_glob.c quit call (when pd exits) */
+typedef struct _redundant_mem
+{
+    int rm_what;
+	t_canvas *rm_canvas;
+    struct _redundant_mem *rm_next;
+} t_redundant_mem;
+
+t_redundant_mem *rm_start;
+t_redundant_mem *rm_end;
     
 /* --------------------- geometry ---------------------------- */
 #define IOWIDTH 7       /* width of an inlet/outlet in pixels */
diff --git a/src/g_editor.c b/src/g_editor.c
index e73bfbe97..b3e215337 100644
--- a/src/g_editor.c
+++ b/src/g_editor.c
@@ -2313,23 +2313,24 @@ static void canvas_doregion(t_canvas *x, int xpos, int ypos, int doit)
                 x->gl_editor->e_ywas, xpos, ypos);
 }
 
+/*
 static void canvas_mouseup_gop(t_canvas *x, t_gobj *g) {
 
-	/* simulate clearing and recreating object */
+	//simulate clearing and recreating object
 	gobj_activate(g, x, 1);
 	t_object *ob = pd_checkobject(&g->g_pd);
 	t_rtext *yyyy = glist_findrtext(x, (t_text *)&ob->ob_g);
-	/* copy current text */
+	//copy current text
     char *buf;
     int bufsize;
     rtext_gettext(yyyy, &buf, &bufsize);
 	//fprintf(stderr, ">%s<\n", buf);
 	rtext_key(yyyy, 127, NULL);
 
-	/* recreate object with no args */
+	//recreate object with no args
 	glist_deselect(x, g);
 
-	/* object was recreated, so now it is latest in the queue */
+	//object was recreated, so now it is latest in the queue
 	t_gobj *z = x->gl_list;
 
 	while (z->g_next) {
@@ -2341,7 +2342,7 @@ static void canvas_mouseup_gop(t_canvas *x, t_gobj *g) {
 	ob = pd_checkobject(&g->g_pd);
 	yyyy = glist_findrtext(x, (t_text *)&ob->ob_g);
 
-	/* redo the old text */
+	//redo the old text
 	int i;
 	for (i = 0; i < bufsize; i++) {
 		rtext_key(yyyy, (int)buf[i], NULL);
@@ -2349,6 +2350,7 @@ static void canvas_mouseup_gop(t_canvas *x, t_gobj *g) {
 	gobj_activate(z, x, 1);
 	x->gl_editor->e_textdirty = 1;
 }
+*/
 
 void canvas_mouseup(t_canvas *x,
     t_floatarg fxpos, t_floatarg fypos, t_floatarg fwhich)
@@ -2397,21 +2399,23 @@ void canvas_mouseup(t_canvas *x,
             }
             /* OK, activate it */
 
-			/* but before we do, check if this is GOP and adjust accordingly */
+			/*
+			// but before we do, check if this is GOP and adjust accordingly
 			//fprintf(stderr,"activate...");
 			if (pd_class(&g->g_pd) == canvas_class && 
 				((t_glist *)g)->gl_isgraph &&
 				canvas_isabstraction((t_glist *)g))
 			{
 				//fprintf(stderr,"gop...");
-				/* if mouse has not moved AND this object does not have its text hidden (otherwise we only translate the selection) */
+				// if mouse has not moved AND this object does not have its text hidden (otherwise we only translate the selection)
 				if (!(((t_glist *)g)->gl_hidetext) && !x->gl_editor->e_lastmoved) {
 					//fprintf(stderr,"yes\n");
 					canvas_mouseup_gop(x, x->gl_editor->e_selection->sel_what);
 				}
 				//else fprintf(stderr,"no\n");
 			}
-			/* else if it is a regular object */
+			// else if it is a regular object
+			*/
 			else {
 				//fprintf(stderr,"reg_obj\n");
 				gobj_activate(x->gl_editor->e_selection->sel_what, x, 1);
@@ -3029,11 +3033,11 @@ static t_binbuf *canvas_docopy(t_canvas *x)
     t_linetraverser t;
     t_outconnect *oc;
     t_binbuf *b = binbuf_new();
-	int c = 0;
+	//int c = 0;
     for (y = x->gl_list; y; y = y->g_next)
     {
         if (glist_isselected(x, y)) {
-			c++;
+			//c++;
 			//fprintf(stderr, "saving object num %d\n", c);
 			//fprintf(stderr, "saving object >.x%lx<\n", (t_int)y);
 			/* introduce redundant comment to avoid recreation of old abstractions
@@ -3042,28 +3046,28 @@ static t_binbuf *canvas_docopy(t_canvas *x)
 			   is yet another bug in tcl/tk which means that canvas tries to do some
 			   kind of caching behind the curtains resulting in objects not always
 			   having unique ids, contrary to tcl/tk's canvas man page */
-			if (c==1) {
+			/*if (c==1) {
             	binbuf_addv(b, "ssiis;", gensym("#X"), gensym("text"),
                 (int)((t_text *)y)->te_xpix-30, (int)((t_text *)y)->te_ypix-30, gensym("tcltksucks"));
-			}
+			}*/
             gobj_save(y, b);
 		}
     }
 	//fprintf(stderr,"done saving objects\n");
     linetraverser_start(&t, x);
-	c = 0;
+	//c = 0;
     while (oc = linetraverser_next(&t))
     {
         if (glist_isselected(x, &t.tr_ob->ob_g)
             && glist_isselected(x, &t.tr_ob2->ob_g))
         {
 			//fprintf(stderr, "lines need to be copied\n");
-			c = 1;
+			//c = 1;
             binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"),
-//                glist_selectionindex(x, &t.tr_ob->ob_g, 1), t.tr_outno,
-//                glist_selectionindex(x, &t.tr_ob2->ob_g, 1), t.tr_inno);
-                glist_selectionindex(x, &t.tr_ob->ob_g, 1)+1, t.tr_outno,
-                glist_selectionindex(x, &t.tr_ob2->ob_g, 1)+1, t.tr_inno);
+                glist_selectionindex(x, &t.tr_ob->ob_g, 1), t.tr_outno,
+                glist_selectionindex(x, &t.tr_ob2->ob_g, 1), t.tr_inno);
+//                glist_selectionindex(x, &t.tr_ob->ob_g, 1)+1, t.tr_outno,
+//                glist_selectionindex(x, &t.tr_ob2->ob_g, 1)+1, t.tr_inno);
         }
     }
 	//if (!c) fprintf(stderr, "no lines copied\n");
@@ -3188,7 +3192,8 @@ static void canvas_doclear(t_canvas *x)
     }
 restore:
     canvas_dirty(x, 1);
-	sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x);
+	canvas_redraw(x);
+	//sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x);
     canvas_resume_dsp(dspstate);
 }
 
@@ -3294,11 +3299,11 @@ static void canvas_dopaste(t_canvas *x, t_binbuf *b)
 
 	/* select newly created objects */
     for (g2 = x->gl_list, count = 0; g2; g2 = g2->g_next, count++)
-        if (count == nbox) {
-			/* delete bogus object we created in canvas_docopy in order to circumvent tcl/tk's failure
-			   to provide "unique" id to every new instance of an object */
+        /*if (count == nbox) {
+			// delete bogus object we created in canvas_docopy in order to circumvent tcl/tk's failure
+			//   to provide "unique" id to every new instance of an object
             glist_delete(x, g2);
-		} else if (count > nbox) {
+		} else*/ if (count >= nbox) {
             glist_select(x, g2);
 			//fprintf(stderr,"object=.x%lx glist_getcanvas(x)=.x%lx\n", (t_int)g2, (t_int)glist_getcanvas((t_glist*)g2) );
 		}
diff --git a/src/g_graph.c b/src/g_graph.c
index 4279cfa94..499c0742f 100644
--- a/src/g_graph.c
+++ b/src/g_graph.c
@@ -118,10 +118,6 @@ void glist_delete(t_glist *x, t_gobj *y)
     if (drawcommand)
         canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(
             glist_getcanvas(x)->gl_name)), 2);
-	//if(glist_isvisible(canvas)) {
-	//	gobj_select(y, x, 0);
-	//}
-    gobj_delete(y, x);
     if (glist_isvisible(canvas))
         gobj_vis(y, x, 0);
     if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
@@ -133,6 +129,7 @@ void glist_delete(t_glist *x, t_gobj *y)
         g->g_next = y->g_next;
         break;
     }
+    gobj_delete(y, x);
     pd_free(&y->g_pd);
     if (chkdsp) canvas_update_dsp();
     if (drawcommand)
@@ -140,7 +137,6 @@ void glist_delete(t_glist *x, t_gobj *y)
             glist_getcanvas(x)->gl_name)), 1);
     canvas_setdeleting(canvas, wasdeleting);
     x->gl_valid = ++glist_valid;
-	//canvas_redraw(x);
 }
 
     /* remove every object from a glist.  Experimental. */
diff --git a/src/g_hdial.c b/src/g_hdial.c
index 4fdc464aa..7669443a3 100644
--- a/src/g_hdial.c
+++ b/src/g_hdial.c
@@ -66,7 +66,8 @@ void hradio_draw_new(t_hradio *x, t_glist *glist)
 
 	t_scalehandle *sh = (t_scalehandle *)x->x_gui.x_handle;
 	sprintf(sh->h_pathname, ".x%x.h%x", (int)canvas, (int)sh);
-
+	t_scalehandle *lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	sprintf(lh->h_pathname, ".x%x.h%x", (int)canvas, (int)lh);
 
 	//if (glist_isvisible(canvas)) {
 
@@ -173,6 +174,8 @@ void hradio_draw_erase(t_hradio* x, t_glist* glist)
 	if (x->x_gui.x_fsf.x_selected) {
 		t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
 		sys_vgui("destroy %s\n", sh->h_pathname);
+		t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
+		sys_vgui("destroy %s\n", lh->h_pathname);
 	}
 /*
     for(i=0; i<n; i++)
@@ -256,6 +259,7 @@ void hradio_draw_select(t_hradio* x, t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 	t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
+	t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
     int n=x->x_number, i;
 
 	if (glist_isvisible(canvas)) {
@@ -274,8 +278,8 @@ void hradio_draw_select(t_hradio* x, t_glist* glist)
 			sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor bottom_right_corner\n",
 				 sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT);
 			sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxHRDO}\n",
-				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w * x->x_number - SCALEHANDLE_WIDTH,
-				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT,
+				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w * x->x_number - SCALEHANDLE_WIDTH - 1,
+				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT - 1,
 				 SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT,
 				 sh->h_pathname, x, x);
 			sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
@@ -285,6 +289,26 @@ void hradio_draw_select(t_hradio* x, t_glist* glist)
 			sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
 				 sh->h_pathname, sh->h_bindsym->s_name);
 			x->x_gui.scale_vis = 1;
+			if (strcmp(x->x_gui.x_lab->s_name, "empty") != 0)
+			{
+				if (x->x_gui.label_vis)
+					sys_vgui("destroy %s\n", lh->h_pathname);
+
+				sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor crosshair\n",
+					lh->h_pathname, LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT);
+				sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxLABEL %lxHRDO}\n",
+					canvas, x->x_gui.x_obj.te_xpix+ x->x_gui.x_ldx - LABELHANDLE_WIDTH,
+					x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - LABELHANDLE_HEIGHT,
+					LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT,
+					lh->h_pathname, x, x);
+				sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 0 0 \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name); 
+				x->x_gui.label_vis = 1;
+			}
 
 			sys_vgui(".x%lx.c addtag selected withtag %lxHRDO\n", canvas, x);
 		}
@@ -300,6 +324,8 @@ void hradio_draw_select(t_hradio* x, t_glist* glist)
 		             x->x_gui.x_lcol);
 			sys_vgui("destroy %s\n", sh->h_pathname);
 			x->x_gui.scale_vis = 0;
+			sys_vgui("destroy %s\n", lh->h_pathname);
+			x->x_gui.label_vis = 0;
 		}
 	}
 }
@@ -309,11 +335,17 @@ static void hradio__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t
 
 	t_hradio *x = (t_hradio *)(sh->h_master);
 
-	if (xxx) x->x_gui.scale_offset_x = xxx;
-	if (yyy) x->x_gui.scale_offset_y = yyy;
+ 	if (xxx) {
+ 		x->x_gui.scale_offset_x = xxx;
+ 		x->x_gui.label_offset_x = xxx;
+ 	}
+ 	if (yyy) {
+ 		x->x_gui.scale_offset_y = yyy;
+ 		x->x_gui.label_offset_y = yyy;
+ 	}
 
     int newstate = (int)f;
-    if (sh->h_dragon && newstate == 0)
+    if (sh->h_dragon && newstate == 0 && sh->h_scale)
     {
 		/* done dragging */
 
@@ -353,7 +385,7 @@ static void hradio__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t
 			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
 		}
     }
-    else if (!sh->h_dragon && newstate)
+    else if (!sh->h_dragon && newstate && sh->h_scale)
     {
 		/* dragging */
 		if (glist_isvisible(x->x_gui.x_glist))
@@ -369,13 +401,60 @@ static void hradio__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t
 		sh->h_dragx = 0;
 		sh->h_dragy = 0;
     }
+	else if (sh->h_dragon && newstate == 0 && !sh->h_scale)
+    {
+		/* done dragging */
+
+		/* first set up the undo apply */
+		canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
+
+		if (sh->h_dragx || sh->h_dragy) {
+
+			x->x_gui.x_ldx = x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x;
+			x->x_gui.x_ldy = x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y;
+
+			canvas_dirty(x->x_gui.x_glist, 1);
+		}
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			sys_vgui(".gfxstub%lx.dim.w_ent delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.dim.w_ent insert 0 %d\n", properties, x->x_gui.x_w);
+			//sys_vgui(".gfxstub%lx.dim.h_ent delete 0 end\n", properties);
+			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, x->x_gui.x_h);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist))
+		{
+			sys_vgui(".x%x.c delete %s\n", x->x_gui.x_glist, sh->h_outlinetag);
+			hradio_draw_move(x, x->x_gui.x_glist);
+			sys_vgui("destroy %s\n", sh->h_pathname);
+			iemgui_select((t_gobj *)x, x->x_gui.x_glist, 1);
+			canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
+		}
+    }
+    else if (!sh->h_dragon && newstate && !sh->h_scale)
+    {
+		/* started dragging label */
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			sys_vgui("lower %s\n", sh->h_pathname);
+			t_scalehandle *othersh = (t_scalehandle *)x->x_gui.x_handle;
+			sys_vgui("lower .x%x.h%x\n", (int)glist_getcanvas(x->x_gui.x_glist), (int)othersh);
+		}
+
+		sh->h_dragx = 0;
+		sh->h_dragy = 0;
+    }
+
     sh->h_dragon = newstate;
 }
 
 static void hradio__motionhook(t_scalehandle *sh,
 				    t_floatarg f1, t_floatarg f2)
 {
-    if (sh->h_dragon)
+    if (sh->h_dragon && sh->h_scale)
     {
 		t_hradio *x = (t_hradio *)(sh->h_master);
 		int dx = (int)f1, dy = (int)f2;
@@ -410,6 +489,37 @@ static void hradio__motionhook(t_scalehandle *sh,
 			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, new_h);
 		}
     }
+	else if (sh->h_dragon && !sh->h_scale)
+    {
+		t_bng *x = (t_bng *)(sh->h_master);
+		int dx = (int)f1, dy = (int)f2;
+		int newx, newy;
+		newx = x->x_gui.x_obj.te_xpix + x->x_gui.x_w - x->x_gui.scale_offset_x + dx;
+		newy = x->x_gui.x_obj.te_ypix + x->x_gui.x_h - x->x_gui.scale_offset_y + dy;
+
+		sh->h_dragx = dx;
+		sh->h_dragy = dy;
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			int new_x = x->x_gui.x_ldx - x->x_gui.label_offset_x + sh->h_dragx;
+			int new_y = x->x_gui.x_ldy - x->x_gui.label_offset_y + sh->h_dragy;
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, new_x);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, new_y);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			int xpos=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		int ypos=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+			sys_vgui(".x%lx.c coords %lxLABEL %d %d\n",
+ 		    	canvas, x, xpos+x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x,
+ 		    	ypos+x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y);
+		}
+    }
 }
 
 void hradio_draw(t_hradio *x, t_glist *glist, int mode)
@@ -846,10 +956,26 @@ static void *hradio_donew(t_symbol *s, int argc, t_atom *argv, int old)
     pd_bind(x->x_gui.x_handle, sh->h_bindsym = gensym(buf));
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
+	sh->h_scale = 1;
 	x->x_gui.scale_offset_x = 0;
 	x->x_gui.scale_offset_y = 0;
 	x->x_gui.scale_vis = 0;
 
+	/* label handle init */
+	t_scalehandle *lh;
+	char lhbuf[64];
+	x->x_gui.x_lhandle = pd_new(scalehandle_class);
+	lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	lh->h_master = (t_gobj*)x;
+	sprintf(lhbuf, "_h%x", (int)lh);
+	pd_bind(x->x_gui.x_lhandle, lh->h_bindsym = gensym(lhbuf));
+	sprintf(lh->h_outlinetag, "h%x", (int)lh);
+	lh->h_dragon = 0;
+	lh->h_scale = 0;
+	x->x_gui.label_offset_x = 0;
+	x->x_gui.label_offset_y = 0;
+	x->x_gui.label_vis = 0;
+
     return (x);
 }
 
@@ -875,6 +1001,13 @@ static void hradio_ff(t_hradio *x)
 		pd_unbind(x->x_gui.x_handle, ((t_scalehandle *)x->x_gui.x_handle)->h_bindsym);
 		pd_free(x->x_gui.x_handle);
     }
+
+	/* label handle deconstructor */
+	if (x->x_gui.x_lhandle)
+	{
+		pd_unbind(x->x_gui.x_lhandle, ((t_scalehandle *)x->x_gui.x_lhandle)->h_bindsym);
+		pd_free(x->x_gui.x_lhandle);
+	}
 }
 
 void g_hradio_setup(void)
diff --git a/src/g_hslider.c b/src/g_hslider.c
index 291735e8b..8193daf97 100644
--- a/src/g_hslider.c
+++ b/src/g_hslider.c
@@ -75,6 +75,8 @@ static void hslider_draw_new(t_hslider *x, t_glist *glist)
 
 	t_scalehandle *sh = (t_scalehandle *)x->x_gui.x_handle;
 	sprintf(sh->h_pathname, ".x%x.h%x", (int)canvas, (int)sh);
+	t_scalehandle *lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	sprintf(lh->h_pathname, ".x%x.h%x", (int)canvas, (int)lh);
 
 	//if (glist_isvisible(canvas)) {
 
@@ -173,6 +175,8 @@ static void hslider_draw_erase(t_hslider* x,t_glist* glist)
 	if (x->x_gui.x_fsf.x_selected) {
 		t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
 		sys_vgui("destroy %s\n", sh->h_pathname);
+		t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
+		sys_vgui("destroy %s\n", lh->h_pathname);
 	}
 /*
     sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x);
@@ -243,6 +247,7 @@ static void hslider_draw_select(t_hslider* x,t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 	t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
+	t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
 
 	if (glist_isvisible(canvas)) {
 
@@ -257,8 +262,8 @@ static void hslider_draw_select(t_hslider* x,t_glist* glist)
 			sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor bottom_right_corner\n",
 				 sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT);
 			sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxHSLDR}\n",
-				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w + 2 - SCALEHANDLE_WIDTH,
-				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT,
+				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w + 2 - SCALEHANDLE_WIDTH - 1,
+				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT - 1,
 				 SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT,
 				 sh->h_pathname, x, x);
 			sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
@@ -269,6 +274,27 @@ static void hslider_draw_select(t_hslider* x,t_glist* glist)
 				 sh->h_pathname, sh->h_bindsym->s_name);
 			x->x_gui.scale_vis = 1;
 
+			if (strcmp(x->x_gui.x_lab->s_name, "empty") != 0)
+			{
+				if (x->x_gui.label_vis)
+					sys_vgui("destroy %s\n", lh->h_pathname);
+
+				sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor crosshair\n",
+					lh->h_pathname, LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT);
+				sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxLABEL %lxHSLDR}\n",
+					canvas, x->x_gui.x_obj.te_xpix+ x->x_gui.x_ldx - LABELHANDLE_WIDTH,
+					x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - LABELHANDLE_HEIGHT,
+					LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT,
+					lh->h_pathname, x, x);
+				sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 0 0 \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name); 
+				x->x_gui.label_vis = 1;
+			}
+
 			sys_vgui(".x%lx.c addtag selected withtag %lxHSLDR\n", canvas, x);
 		}
 		else
@@ -278,6 +304,8 @@ static void hslider_draw_select(t_hslider* x,t_glist* glist)
 			sys_vgui(".x%lx.c dtag %lxHSLDR selected\n", canvas, x);
 			sys_vgui("destroy %s\n", sh->h_pathname);
 			x->x_gui.scale_vis = 0;
+			sys_vgui("destroy %s\n", lh->h_pathname);
+			x->x_gui.label_vis = 0;
 		}
 	}
 }
@@ -287,11 +315,17 @@ static void hslider__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx,
 
 	t_hslider *x = (t_hslider *)(sh->h_master);
 
-	if (xxx) x->x_gui.scale_offset_x = xxx;
-	if (yyy) x->x_gui.scale_offset_y = yyy;
+ 	if (xxx) {
+ 		x->x_gui.scale_offset_x = xxx;
+ 		x->x_gui.label_offset_x = xxx;
+ 	}
+ 	if (yyy) {
+ 		x->x_gui.scale_offset_y = yyy;
+ 		x->x_gui.label_offset_y = yyy;
+ 	}
 
     int newstate = (int)f;
-    if (sh->h_dragon && newstate == 0)
+    if (sh->h_dragon && newstate == 0 && sh->h_scale)
     {
 		/* done dragging */
 
@@ -329,7 +363,7 @@ static void hslider__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx,
 			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
 		}
     }
-    else if (!sh->h_dragon && newstate)
+    else if (!sh->h_dragon && newstate && sh->h_scale)
     {
 		/* dragging */
 		if (glist_isvisible(x->x_gui.x_glist))
@@ -345,13 +379,59 @@ static void hslider__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx,
 		sh->h_dragx = 0;
 		sh->h_dragy = 0;
     }
+	else if (sh->h_dragon && newstate == 0 && !sh->h_scale)
+    {
+		/* done dragging */
+
+		/* first set up the undo apply */
+		canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
+
+		if (sh->h_dragx || sh->h_dragy) {
+
+			x->x_gui.x_ldx = x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x;
+			x->x_gui.x_ldy = x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y;
+
+			canvas_dirty(x->x_gui.x_glist, 1);
+		}
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			sys_vgui(".gfxstub%lx.dim.w_ent delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.dim.w_ent insert 0 %d\n", properties, x->x_gui.x_w);
+			//sys_vgui(".gfxstub%lx.dim.h_ent delete 0 end\n", properties);
+			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, x->x_gui.x_h);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist))
+		{
+			sys_vgui(".x%x.c delete %s\n", x->x_gui.x_glist, sh->h_outlinetag);
+			hslider_draw_move(x, x->x_gui.x_glist);
+			sys_vgui("destroy %s\n", sh->h_pathname);
+			iemgui_select((t_gobj *)x, x->x_gui.x_glist, 1);
+			canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
+		}
+    }
+    else if (!sh->h_dragon && newstate && !sh->h_scale)
+    {
+		/* dragging */
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			sys_vgui("lower %s\n", sh->h_pathname);
+			t_scalehandle *othersh = (t_scalehandle *)x->x_gui.x_handle;
+			sys_vgui("lower .x%x.h%x\n", (int)glist_getcanvas(x->x_gui.x_glist), (int)othersh);
+		}
+
+		sh->h_dragx = 0;
+		sh->h_dragy = 0;
+    }
     sh->h_dragon = newstate;
 }
 
 static void hslider__motionhook(t_scalehandle *sh,
 				    t_floatarg f1, t_floatarg f2)
 {
-    if (sh->h_dragon)
+    if (sh->h_dragon && sh->h_scale)
     {
 		t_hslider *x = (t_hslider *)(sh->h_master);
 		int dx = (int)f1, dy = (int)f2;
@@ -383,6 +463,37 @@ static void hslider__motionhook(t_scalehandle *sh,
 			sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, new_h);
 		}
     }
+	if (sh->h_dragon && !sh->h_scale)
+    {
+		t_bng *x = (t_bng *)(sh->h_master);
+		int dx = (int)f1, dy = (int)f2;
+		int newx, newy;
+		newx = x->x_gui.x_obj.te_xpix + x->x_gui.x_w - x->x_gui.scale_offset_x + dx;
+		newy = x->x_gui.x_obj.te_ypix + x->x_gui.x_h - x->x_gui.scale_offset_y + dy;
+
+		sh->h_dragx = dx;
+		sh->h_dragy = dy;
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			int new_x = x->x_gui.x_ldx - x->x_gui.label_offset_x + sh->h_dragx;
+			int new_y = x->x_gui.x_ldy - x->x_gui.label_offset_y + sh->h_dragy;
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, new_x);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, new_y);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			int xpos=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		int ypos=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+			sys_vgui(".x%lx.c coords %lxLABEL %d %d\n",
+ 		    	canvas, x, xpos+x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x,
+ 		    	ypos+x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y);
+		}
+    }
 }
 
 
@@ -828,10 +939,26 @@ static void *hslider_new(t_symbol *s, int argc, t_atom *argv)
     pd_bind(x->x_gui.x_handle, sh->h_bindsym = gensym(buf));
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
+	sh->h_scale = 1;
 	x->x_gui.scale_offset_x = 0;
 	x->x_gui.scale_offset_y = 0;
 	x->x_gui.scale_vis = 0;
 
+	/* label handle init */
+	t_scalehandle *lh;
+	char lhbuf[64];
+	x->x_gui.x_lhandle = pd_new(scalehandle_class);
+	lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	lh->h_master = (t_gobj*)x;
+	sprintf(lhbuf, "_h%x", (int)lh);
+	pd_bind(x->x_gui.x_lhandle, lh->h_bindsym = gensym(lhbuf));
+	sprintf(lh->h_outlinetag, "h%x", (int)lh);
+	lh->h_dragon = 0;
+	lh->h_scale = 0;
+	x->x_gui.label_offset_x = 0;
+	x->x_gui.label_offset_y = 0;
+	x->x_gui.label_vis = 0;
+
     return (x);
 }
 
@@ -847,6 +974,13 @@ static void hslider_free(t_hslider *x)
 		pd_unbind(x->x_gui.x_handle, ((t_scalehandle *)x->x_gui.x_handle)->h_bindsym);
 		pd_free(x->x_gui.x_handle);
     }
+
+	/* label handle deconstructor */
+	if (x->x_gui.x_lhandle)
+	{
+		pd_unbind(x->x_gui.x_lhandle, ((t_scalehandle *)x->x_gui.x_lhandle)->h_bindsym);
+		pd_free(x->x_gui.x_lhandle);
+	}
 }
 
 void g_hslider_setup(void)
diff --git a/src/g_mycanvas.c b/src/g_mycanvas.c
index cb3193b79..1caaac710 100644
--- a/src/g_mycanvas.c
+++ b/src/g_mycanvas.c
@@ -44,6 +44,9 @@ void my_canvas_draw_new(t_my_canvas *x, t_glist *glist)
 	t_scalehandle *sh = (t_scalehandle *)x->x_gui.x_handle;
 	sprintf(sh->h_pathname, ".x%x.h%x", (int)canvas, (int)sh);
 
+	t_scalehandle *lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	sprintf(lh->h_pathname, ".x%x.h%x", (int)canvas, (int)lh);
+
 	//if (glist_isvisible(glist)) {
 
 		sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags {%lxRECT %lxMYCNV}\n",
@@ -96,6 +99,8 @@ void my_canvas_draw_erase(t_my_canvas* x, t_glist* glist)
 	if (x->x_gui.x_fsf.x_selected) {
 		t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
 		sys_vgui("destroy %s\n", sh->h_pathname);
+		t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
+		sys_vgui("destroy %s\n", lh->h_pathname);
 	}
     //sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x);
     //sys_vgui(".x%lx.c delete %lxRECT\n", canvas, x);
@@ -126,6 +131,7 @@ void my_canvas_draw_select(t_my_canvas* x, t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 	t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
+	t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
 
 	if (glist_isvisible(canvas)) {
 
@@ -139,8 +145,8 @@ void my_canvas_draw_select(t_my_canvas* x, t_glist* glist)
 			sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor bottom_right_corner\n",
 				 sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT);
 			sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxMYCNV}\n",
-				 canvas, x->x_gui.x_obj.te_xpix + x->x_vis_w - SCALEHANDLE_WIDTH,
-				 x->x_gui.x_obj.te_ypix + x->x_vis_h - SCALEHANDLE_HEIGHT,
+				 canvas, x->x_gui.x_obj.te_xpix + x->x_vis_w - SCALEHANDLE_WIDTH - 1,
+				 x->x_gui.x_obj.te_ypix + x->x_vis_h - SCALEHANDLE_HEIGHT - 1,
 				 SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT,
 				 sh->h_pathname, x, x);
 			sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
@@ -151,6 +157,27 @@ void my_canvas_draw_select(t_my_canvas* x, t_glist* glist)
 				 sh->h_pathname, sh->h_bindsym->s_name);
 			x->x_gui.scale_vis = 1;
 
+			if (strcmp(x->x_gui.x_lab->s_name, "empty") != 0)
+			{
+				if (x->x_gui.label_vis)
+					sys_vgui("destroy %s\n", lh->h_pathname);
+
+				sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor crosshair\n",
+					lh->h_pathname, LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT);
+				sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxLABEL %lxMYCNV}\n",
+					canvas, x->x_gui.x_obj.te_xpix+ x->x_gui.x_ldx - LABELHANDLE_WIDTH,
+					x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - LABELHANDLE_HEIGHT,
+					LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT,
+					lh->h_pathname, x, x);
+				sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 0 0 \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name); 
+				x->x_gui.label_vis = 1;
+			}
+
 			sys_vgui(".x%lx.c addtag selected withtag %lxMYCNV\n", canvas, x);
 		}
 		else
@@ -159,6 +186,8 @@ void my_canvas_draw_select(t_my_canvas* x, t_glist* glist)
 			sys_vgui(".x%lx.c dtag %lxMYCNV selected\n", canvas, x);
 			sys_vgui("destroy %s\n", sh->h_pathname);
 			x->x_gui.scale_vis = 0;
+			sys_vgui("destroy %s\n", lh->h_pathname);
+			x->x_gui.label_vis = 0;
 		}
 	}
 }
@@ -168,11 +197,17 @@ static void my_canvas__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx
 
 	t_my_canvas *x = (t_my_canvas *)(sh->h_master);
 
-	if (xxx) x->x_gui.scale_offset_x = xxx;
-	if (yyy) x->x_gui.scale_offset_y = yyy;
+	if (xxx) {
+		x->x_gui.scale_offset_x = xxx;
+		x->x_gui.label_offset_x = xxx;
+	}
+	if (yyy) {
+		x->x_gui.scale_offset_y = yyy;
+		x->x_gui.label_offset_y = yyy;
+	}
 
     int newstate = (int)f;
-    if (sh->h_dragon && newstate == 0)
+    if (sh->h_dragon && newstate == 0 && sh->h_scale)
     {
 		/* done dragging */
 
@@ -216,7 +251,7 @@ static void my_canvas__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx
 			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
 		}
     }
-    else if (!sh->h_dragon && newstate)
+    else if (!sh->h_dragon && newstate && sh->h_scale)
     {
 		/* dragging */
 		if (glist_isvisible(x->x_gui.x_glist))
@@ -232,13 +267,58 @@ static void my_canvas__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx
 		sh->h_dragx = 0;
 		sh->h_dragy = 0;
     }
+    else if (sh->h_dragon && newstate == 0 && !sh->h_scale)
+    {
+		/* done dragging */
+
+		/* first set up the undo apply */
+		canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
+
+		if (sh->h_dragx || sh->h_dragy) {
+
+			x->x_gui.x_ldx = x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x;
+			x->x_gui.x_ldy = x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y;
+
+			canvas_dirty(x->x_gui.x_glist, 1);
+		}
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, x->x_gui.x_ldx);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, x->x_gui.x_ldy);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist))
+		{
+			my_canvas_draw_move(x, x->x_gui.x_glist);
+			sys_vgui("destroy %s\n", sh->h_pathname);
+			iemgui_select((t_gobj *)x, x->x_gui.x_glist, 1);
+			canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
+		}
+    }
+    else if (!sh->h_dragon && newstate && !sh->h_scale)
+    {
+		/* dragging */
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			sys_vgui("lower %s\n", sh->h_pathname);
+			t_scalehandle *othersh = (t_scalehandle *)x->x_gui.x_handle;
+			sys_vgui("lower .x%x.h%x\n", (int)glist_getcanvas(x->x_gui.x_glist), (int)othersh);
+		}
+
+		sh->h_dragx = 0;
+		sh->h_dragy = 0;
+    }
     sh->h_dragon = newstate;
 }
 
 static void my_canvas__motionhook(t_scalehandle *sh,
 				    t_floatarg f1, t_floatarg f2)
 {
-    if (sh->h_dragon)
+    if (sh->h_dragon && sh->h_scale)
     {
 		t_my_canvas *x = (t_my_canvas *)(sh->h_master);
 		int dx = (int)f1, dy = (int)f2;
@@ -275,6 +355,37 @@ static void my_canvas__motionhook(t_scalehandle *sh,
 			}
 		}
     }
+	else if (sh->h_dragon && !sh->h_scale)
+	{
+		t_my_canvas *x = (t_my_canvas *)(sh->h_master);
+		int dx = (int)f1, dy = (int)f2;
+		int newx, newy;
+		newx = x->x_gui.x_obj.te_xpix + x->x_gui.x_ldx - x->x_gui.label_offset_x + dx;
+		newy = x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - x->x_gui.label_offset_y + dy;
+
+		sh->h_dragx = dx;
+		sh->h_dragy = dy;
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			int new_x = x->x_gui.x_ldx - x->x_gui.label_offset_x + sh->h_dragx;
+			int new_y = x->x_gui.x_ldy - x->x_gui.label_offset_y + sh->h_dragy;
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, new_x);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, new_y);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			int xpos=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		int ypos=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+			sys_vgui(".x%lx.c coords %lxLABEL %d %d\n",
+		    	canvas, x, xpos+x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x,
+		    	ypos+x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y);
+		}
+	}
 }
 
 void my_canvas_draw(t_my_canvas *x, t_glist *glist, int mode)
@@ -539,10 +650,26 @@ static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
     pd_bind(x->x_gui.x_handle, sh->h_bindsym = gensym(buf));
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
+	sh->h_scale = 1;
 	x->x_gui.scale_offset_x = 0;
 	x->x_gui.scale_offset_y = 0;
 	x->x_gui.scale_vis = 0;
 
+	/* label handle init */
+	t_scalehandle *lh;
+	char lhbuf[64];
+	x->x_gui.x_lhandle = pd_new(scalehandle_class);
+	lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	lh->h_master = (t_gobj*)x;
+	sprintf(lhbuf, "_h%x", (int)lh);
+	pd_bind(x->x_gui.x_lhandle, lh->h_bindsym = gensym(lhbuf));
+	sprintf(lh->h_outlinetag, "h%x", (int)lh);
+	lh->h_dragon = 0;
+	lh->h_scale = 0;
+	x->x_gui.label_offset_x = 0;
+	x->x_gui.label_offset_y = 0;
+	x->x_gui.label_vis = 0;
+
     return (x);
 }
 
@@ -558,6 +685,13 @@ static void my_canvas_ff(t_my_canvas *x)
 		pd_unbind(x->x_gui.x_handle, ((t_scalehandle *)x->x_gui.x_handle)->h_bindsym);
 		pd_free(x->x_gui.x_handle);
     }
+
+	/* label handle deconstructor */
+	if (x->x_gui.x_lhandle)
+	{
+		pd_unbind(x->x_gui.x_lhandle, ((t_scalehandle *)x->x_gui.x_lhandle)->h_bindsym);
+		pd_free(x->x_gui.x_lhandle);
+	}
 }
 
 void g_mycanvas_setup(void)
diff --git a/src/g_numbox.c b/src/g_numbox.c
index 69569f008..d99dc4b01 100644
--- a/src/g_numbox.c
+++ b/src/g_numbox.c
@@ -195,6 +195,9 @@ static void my_numbox_draw_new(t_my_numbox *x, t_glist *glist)
 	t_scalehandle *sh = (t_scalehandle *)x->x_gui.x_handle;
 	sprintf(sh->h_pathname, ".x%x.h%x", (int)canvas, (int)sh);
 
+	t_scalehandle *lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	sprintf(lh->h_pathname, ".x%x.h%x", (int)canvas, (int)lh);
+
 	//if (glist_isvisible(canvas)) {
 
 		t_gobj *y = (t_gobj *)x;
@@ -233,7 +236,7 @@ static void my_numbox_draw_new(t_my_numbox *x, t_glist *glist)
 		         x->x_gui.x_lcol, x, x);
 		my_numbox_ftoa(x);
 		sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \
-		    -font {{%s} %d %s} -fill #%6.6x -tags {%lxNUMBER %lxNUM noscroll}\n",
+		    -font {{%s} %d %s} -fill #%6.6x -tags {%lxNUMBER %lxNUM}\n",
 		    canvas, xpos+half+2, ypos+half+d,
 		    x->x_buf, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight,
 		    x->x_gui.x_fcol, x, x);
@@ -313,6 +316,8 @@ static void my_numbox_draw_erase(t_my_numbox* x,t_glist* glist)
 	if (x->x_gui.x_fsf.x_selected) {
 		t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
 		sys_vgui("destroy %s\n", sh->h_pathname);
+		t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
+		sys_vgui("destroy %s\n", lh->h_pathname);
 	}
 /*
     sys_vgui(".x%lx.c delete %lxBASE1\n", canvas, x);
@@ -399,6 +404,7 @@ static void my_numbox_draw_select(t_my_numbox *x, t_glist *glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 	t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
+	t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
 
 	if (glist_isvisible(canvas)) {
 
@@ -426,8 +432,8 @@ static void my_numbox_draw_select(t_my_numbox *x, t_glist *glist)
 			sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor bottom_right_corner\n",
 				 sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT);
 			sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxNUM}\n",
-				 canvas, x->x_gui.x_obj.te_xpix + x->x_numwidth - SCALEHANDLE_WIDTH,
-				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT,
+				 canvas, x->x_gui.x_obj.te_xpix + x->x_numwidth - SCALEHANDLE_WIDTH - 1,
+				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT - 1,
 				 SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT,
 				 sh->h_pathname, x, x);
 			sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
@@ -437,6 +443,26 @@ static void my_numbox_draw_select(t_my_numbox *x, t_glist *glist)
 			sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
 				 sh->h_pathname, sh->h_bindsym->s_name);
 			x->x_gui.scale_vis = 1;
+			if (strcmp(x->x_gui.x_lab->s_name, "empty") != 0)
+			{
+				if (x->x_gui.label_vis)
+					sys_vgui("destroy %s\n", lh->h_pathname);
+
+				sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor crosshair\n",
+					lh->h_pathname, LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT);
+				sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxLABEL %lxNUM}\n",
+					canvas, x->x_gui.x_obj.te_xpix+ x->x_gui.x_ldx - LABELHANDLE_WIDTH,
+					x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - LABELHANDLE_HEIGHT,
+					LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT,
+					lh->h_pathname, x, x);
+				sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 0 0 \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name); 
+				x->x_gui.label_vis = 1;
+			}
 
 			sys_vgui(".x%lx.c addtag selected withtag %lxNUM\n", canvas, x);
 		}
@@ -453,6 +479,8 @@ static void my_numbox_draw_select(t_my_numbox *x, t_glist *glist)
 		        canvas, x, x->x_gui.x_fcol);
 			sys_vgui("destroy %s\n", sh->h_pathname);
 			x->x_gui.scale_vis = 0;
+			sys_vgui("destroy %s\n", lh->h_pathname);
+			x->x_gui.label_vis = 0;
 		}
 	}
 }
@@ -462,11 +490,17 @@ static void my_numbox__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx
 
 	t_my_numbox *x = (t_my_numbox *)(sh->h_master);
 
-	if (xxx) x->x_gui.scale_offset_x = xxx;
-	if (yyy) x->x_gui.scale_offset_y = yyy;
+ 	if (xxx) {
+ 		x->x_gui.scale_offset_x = xxx;
+ 		x->x_gui.label_offset_x = xxx;
+ 	}
+ 	if (yyy) {
+ 		x->x_gui.scale_offset_y = yyy;
+ 		x->x_gui.label_offset_y = yyy;
+ 	}
 
     int newstate = (int)f;
-    if (sh->h_dragon && newstate == 0)
+    if (sh->h_dragon && newstate == 0 && sh->h_scale)
     {
 		/* done dragging */
 
@@ -507,7 +541,7 @@ static void my_numbox__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx
 			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
 		}
     }
-    else if (!sh->h_dragon && newstate)
+    else if (!sh->h_dragon && newstate && sh->h_scale)
     {
 		/* dragging */
 		if (glist_isvisible(x->x_gui.x_glist))
@@ -526,13 +560,59 @@ static void my_numbox__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx
 		sh->h_dragx = 0;
 		sh->h_dragy = 0;
     }
+	else if (sh->h_dragon && newstate == 0 && !sh->h_scale)
+    {
+		/* done dragging */
+
+		/* first set up the undo apply */
+		canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
+
+		if (sh->h_dragx || sh->h_dragy) {
+
+			x->x_gui.x_ldx = x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x;
+			x->x_gui.x_ldy = x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y;
+
+			canvas_dirty(x->x_gui.x_glist, 1);
+		}
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			sys_vgui(".gfxstub%lx.dim.w_ent delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.dim.w_ent insert 0 %d\n", properties, x->x_gui.x_w);
+			//sys_vgui(".gfxstub%lx.dim.h_ent delete 0 end\n", properties);
+			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, x->x_gui.x_h);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist))
+		{
+			sys_vgui(".x%x.c delete %s\n", x->x_gui.x_glist, sh->h_outlinetag);
+			my_numbox_draw_move(x, x->x_gui.x_glist);
+			sys_vgui("destroy %s\n", sh->h_pathname);
+			iemgui_select((t_gobj *)x, x->x_gui.x_glist, 1);
+			canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
+		}
+    }
+    else if (!sh->h_dragon && newstate && !sh->h_scale)
+    {
+		/* dragging */
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			sys_vgui("lower %s\n", sh->h_pathname);
+			t_scalehandle *othersh = (t_scalehandle *)x->x_gui.x_handle;
+			sys_vgui("lower .x%x.h%x\n", (int)glist_getcanvas(x->x_gui.x_glist), (int)othersh);
+		}
+
+		sh->h_dragx = 0;
+		sh->h_dragy = 0;
+    }
     sh->h_dragon = newstate;
 }
 
 static void my_numbox__motionhook(t_scalehandle *sh,
 				    t_floatarg f1, t_floatarg f2)
 {
-    if (sh->h_dragon)
+    if (sh->h_dragon && sh->h_scale)
     {
 		t_my_numbox *x = (t_my_numbox *)(sh->h_master);
 		int dx = (int)f1, dy = (int)f2;
@@ -588,6 +668,37 @@ static void my_numbox__motionhook(t_scalehandle *sh,
 			sys_vgui(".gfxstub%lx.label.fontsize_entry insert 0 %d\n", properties, x->x_tmpfontsize);
 		}
     }
+	if (sh->h_dragon && !sh->h_scale)
+    {
+		t_bng *x = (t_bng *)(sh->h_master);
+		int dx = (int)f1, dy = (int)f2;
+		int newx, newy;
+		newx = x->x_gui.x_obj.te_xpix + x->x_gui.x_w - x->x_gui.scale_offset_x + dx;
+		newy = x->x_gui.x_obj.te_ypix + x->x_gui.x_h - x->x_gui.scale_offset_y + dy;
+
+		sh->h_dragx = dx;
+		sh->h_dragy = dy;
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			int new_x = x->x_gui.x_ldx - x->x_gui.label_offset_x + sh->h_dragx;
+			int new_y = x->x_gui.x_ldy - x->x_gui.label_offset_y + sh->h_dragy;
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, new_x);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, new_y);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			int xpos=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		int ypos=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+			sys_vgui(".x%lx.c coords %lxLABEL %d %d\n",
+ 		    	canvas, x, xpos+x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x,
+ 		    	ypos+x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y);
+		}
+    }
 }
 
 void my_numbox_draw(t_my_numbox *x, t_glist *glist, int mode)
@@ -1100,9 +1211,25 @@ static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
     pd_bind(x->x_gui.x_handle, sh->h_bindsym = gensym(buf));
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
+	sh->h_scale = 1;
 	x->x_gui.scale_offset_x = 0;
 	x->x_gui.scale_offset_y = 0;
 	x->x_gui.scale_vis = 0;
+
+	/* label handle init */
+	t_scalehandle *lh;
+	char lhbuf[64];
+	x->x_gui.x_lhandle = pd_new(scalehandle_class);
+	lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	lh->h_master = (t_gobj*)x;
+	sprintf(lhbuf, "_h%x", (int)lh);
+	pd_bind(x->x_gui.x_lhandle, lh->h_bindsym = gensym(lhbuf));
+	sprintf(lh->h_outlinetag, "h%x", (int)lh);
+	lh->h_dragon = 0;
+	lh->h_scale = 0;
+	x->x_gui.label_offset_x = 0;
+	x->x_gui.label_offset_y = 0;
+	x->x_gui.label_vis = 0;
 	
 	x->x_scalewidth = 0;
 	x->x_scaleheight = 0;
@@ -1125,6 +1252,13 @@ static void my_numbox_free(t_my_numbox *x)
 		pd_unbind(x->x_gui.x_handle, ((t_scalehandle *)x->x_gui.x_handle)->h_bindsym);
 		pd_free(x->x_gui.x_handle);
     }
+
+	/* label handle deconstructor */
+	if (x->x_gui.x_lhandle)
+	{
+		pd_unbind(x->x_gui.x_lhandle, ((t_scalehandle *)x->x_gui.x_lhandle)->h_bindsym);
+		pd_free(x->x_gui.x_lhandle);
+	}
 }
 
 void g_numbox_setup(void)
diff --git a/src/g_toggle.c b/src/g_toggle.c
index be2122d4e..e339b5bcd 100644
--- a/src/g_toggle.c
+++ b/src/g_toggle.c
@@ -57,6 +57,9 @@ void toggle_draw_new(t_toggle *x, t_glist *glist)
 	t_scalehandle *sh = (t_scalehandle *)x->x_gui.x_handle;
 	sprintf(sh->h_pathname, ".x%x.h%x", (int)canvas, (int)sh);
 
+	t_scalehandle *lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	sprintf(lh->h_pathname, ".x%x.h%x", (int)canvas, (int)lh);
+
 	//if (glist_isvisible(canvas)) {
 
 		t_gobj *y = (t_gobj *)x;
@@ -157,6 +160,8 @@ void toggle_draw_erase(t_toggle* x, t_glist* glist)
 	if (x->x_gui.x_fsf.x_selected) {
 		t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
 		sys_vgui("destroy %s\n", sh->h_pathname);
+		t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
+		sys_vgui("destroy %s\n", lh->h_pathname);
 	}
 /*
     sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x);
@@ -233,6 +238,7 @@ void toggle_draw_select(t_toggle* x, t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 	t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
+	t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
 
 	if (glist_isvisible(canvas)) {
 
@@ -247,8 +253,8 @@ void toggle_draw_select(t_toggle* x, t_glist* glist)
 			sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor bottom_right_corner\n",
 				 sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT);
 			sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxTGL}\n",
-				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w - SCALEHANDLE_WIDTH,
-				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT,
+				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w - SCALEHANDLE_WIDTH - 1,
+				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h - SCALEHANDLE_HEIGHT - 1,
 				 SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT,
 				 sh->h_pathname, x, x);
 			sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
@@ -259,6 +265,27 @@ void toggle_draw_select(t_toggle* x, t_glist* glist)
 				 sh->h_pathname, sh->h_bindsym->s_name);
 			x->x_gui.scale_vis = 1;
 
+			if (strcmp(x->x_gui.x_lab->s_name, "empty") != 0)
+			{
+				if (x->x_gui.label_vis)
+					sys_vgui("destroy %s\n", lh->h_pathname);
+
+				sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor crosshair\n",
+					lh->h_pathname, LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT);
+				sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxLABEL %lxTGL}\n",
+					canvas, x->x_gui.x_obj.te_xpix+ x->x_gui.x_ldx - LABELHANDLE_WIDTH,
+					x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - LABELHANDLE_HEIGHT,
+					LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT,
+					lh->h_pathname, x, x);
+				sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 0 0 \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name); 
+				x->x_gui.label_vis = 1;
+			}
+
 			sys_vgui(".x%lx.c addtag selected withtag %lxTGL\n", canvas, x);
 		}
 		else
@@ -268,6 +295,8 @@ void toggle_draw_select(t_toggle* x, t_glist* glist)
 			sys_vgui(".x%lx.c dtag %lxTGL selected\n", canvas, x);
 			sys_vgui("destroy %s\n", sh->h_pathname);
 			x->x_gui.scale_vis = 0;
+			sys_vgui("destroy %s\n", lh->h_pathname);
+			x->x_gui.label_vis = 0;
 		}
 	}
 }
@@ -277,11 +306,17 @@ static void toggle__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t
 
 	t_toggle *x = (t_toggle *)(sh->h_master);
 
-	if (xxx) x->x_gui.scale_offset_x = xxx;
-	if (yyy) x->x_gui.scale_offset_y = yyy;
+	if (xxx) {
+		x->x_gui.scale_offset_x = xxx;
+		x->x_gui.label_offset_x = xxx;
+	}
+	if (yyy) {
+		x->x_gui.scale_offset_y = yyy;
+		x->x_gui.label_offset_y = yyy;
+	}
 
     int newstate = (int)f;
-    if (sh->h_dragon && newstate == 0)
+    if (sh->h_dragon && newstate == 0 && sh->h_scale)
     {
 		/* done dragging */
 
@@ -323,7 +358,7 @@ static void toggle__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t
 			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
 		}
     }
-    else if (!sh->h_dragon && newstate)
+    else if (!sh->h_dragon && newstate && sh->h_scale)
     {
 		/* dragging */
 		if (glist_isvisible(x->x_gui.x_glist))
@@ -339,13 +374,60 @@ static void toggle__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t
 		sh->h_dragx = 0;
 		sh->h_dragy = 0;
     }
+	else if (sh->h_dragon && !newstate && !sh->h_scale)
+	{
+		/* done dragging */
+
+		/* first set up the undo apply */
+		canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
+
+		if (sh->h_dragx || sh->h_dragy) {
+
+			x->x_gui.x_ldx = x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x;
+			x->x_gui.x_ldy = x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y;
+
+			canvas_dirty(x->x_gui.x_glist, 1);
+		}
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			sys_vgui(".gfxstub%lx.dim.w_ent delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.dim.w_ent insert 0 %d\n", properties, x->x_gui.x_w);
+			//sys_vgui(".gfxstub%lx.dim.h_ent delete 0 end\n", properties);
+			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, x->x_gui.x_h);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist))
+		{
+			sys_vgui(".x%x.c delete %s\n", x->x_gui.x_glist, sh->h_outlinetag);
+			toggle_draw_move(x, x->x_gui.x_glist);
+			sys_vgui("destroy %s\n", sh->h_pathname);
+			iemgui_select((t_gobj *)x, x->x_gui.x_glist, 1);
+			canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
+		}
+	}
+	else if(!sh->h_dragon && newstate && !sh->h_scale)
+	{
+		/* dragging */
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			sys_vgui("lower %s\n", sh->h_pathname);
+			t_scalehandle *othersh = (t_scalehandle *)x->x_gui.x_handle;
+			sys_vgui("lower .x%x.h%x\n", (int)glist_getcanvas(x->x_gui.x_glist), (int)othersh);
+		}
+
+		sh->h_dragx = 0;
+		sh->h_dragy = 0;
+	}
+
     sh->h_dragon = newstate;
 }
 
 static void toggle__motionhook(t_scalehandle *sh,
 				    t_floatarg f1, t_floatarg f2)
 {
-    if (sh->h_dragon)
+    if (sh->h_dragon && sh->h_scale)
     {
 		t_toggle *x = (t_toggle *)(sh->h_master);
 		int dx = (int)f1, dy = (int)f2;
@@ -387,6 +469,37 @@ static void toggle__motionhook(t_scalehandle *sh,
 			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, new_h);
 		}
     }
+	else if (sh->h_dragon && !sh->h_scale)
+	{
+		t_bng *x = (t_bng *)(sh->h_master);
+		int dx = (int)f1, dy = (int)f2;
+		int newx, newy;
+		newx = x->x_gui.x_obj.te_xpix + x->x_gui.x_w - x->x_gui.scale_offset_x + dx;
+		newy = x->x_gui.x_obj.te_ypix + x->x_gui.x_h - x->x_gui.scale_offset_y + dy;
+
+		sh->h_dragx = dx;
+		sh->h_dragy = dy;
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			int new_x = x->x_gui.x_ldx - x->x_gui.label_offset_x + sh->h_dragx;
+			int new_y = x->x_gui.x_ldy - x->x_gui.label_offset_y + sh->h_dragy;
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, new_x);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, new_y);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			int xpos=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		int ypos=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+			sys_vgui(".x%lx.c coords %lxLABEL %d %d\n",
+ 		    	canvas, x, xpos+x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x,
+ 		    	ypos+x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y);
+		}
+	}
 }
 
 
@@ -669,10 +782,26 @@ static void *toggle_new(t_symbol *s, int argc, t_atom *argv)
     pd_bind(x->x_gui.x_handle, sh->h_bindsym = gensym(buf));
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
+	sh->h_scale = 1;
 	x->x_gui.scale_offset_x = 0;
 	x->x_gui.scale_offset_y = 0;
 	x->x_gui.scale_vis = 0;
 
+	/* label handle init */
+	t_scalehandle *lh;
+	char lhbuf[64];
+	x->x_gui.x_lhandle = pd_new(scalehandle_class);
+	lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	lh->h_master = (t_gobj*)x;
+	sprintf(lhbuf, "_h%x", (int)lh);
+	pd_bind(x->x_gui.x_lhandle, lh->h_bindsym = gensym(lhbuf));
+	sprintf(lh->h_outlinetag, "h%x", (int)lh);
+	lh->h_dragon = 0;
+	lh->h_scale = 0;
+	x->x_gui.label_offset_x = 0;
+	x->x_gui.label_offset_y = 0;
+	x->x_gui.label_vis = 0;
+
     return (x);
 }
 
@@ -688,6 +817,13 @@ static void toggle_ff(t_toggle *x)
 		pd_unbind(x->x_gui.x_handle, ((t_scalehandle *)x->x_gui.x_handle)->h_bindsym);
 		pd_free(x->x_gui.x_handle);
     }
+
+	/* label handle deconstructor */
+	if (x->x_gui.x_lhandle)
+	{
+		pd_unbind(x->x_gui.x_lhandle, ((t_scalehandle *)x->x_gui.x_lhandle)->h_bindsym);
+		pd_free(x->x_gui.x_lhandle);
+	}
 }
 
 void g_toggle_setup(void)
diff --git a/src/g_vdial.c b/src/g_vdial.c
index 4fd5679bb..b92bcd285 100644
--- a/src/g_vdial.c
+++ b/src/g_vdial.c
@@ -64,6 +64,8 @@ void vradio_draw_new(t_vradio *x, t_glist *glist)
 
 	t_scalehandle *sh = (t_scalehandle *)x->x_gui.x_handle;
 	sprintf(sh->h_pathname, ".x%x.h%x", (int)canvas, (int)sh);
+	t_scalehandle *lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	sprintf(lh->h_pathname, ".x%x.h%x", (int)canvas, (int)lh);
 
 	//if (glist_isvisible(canvas)) {
 
@@ -170,6 +172,8 @@ void vradio_draw_erase(t_vradio* x, t_glist* glist)
 	if (x->x_gui.x_fsf.x_selected) {
 		t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
 		sys_vgui("destroy %s\n", sh->h_pathname);
+		t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
+		sys_vgui("destroy %s\n", lh->h_pathname);
 	}
 
 /*
@@ -254,6 +258,7 @@ void vradio_draw_select(t_vradio* x, t_glist* glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 	t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
+	t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
     int n=x->x_number, i;
 
 	if (glist_isvisible(canvas)) {
@@ -272,8 +277,8 @@ void vradio_draw_select(t_vradio* x, t_glist* glist)
 			sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor bottom_right_corner\n",
 				 sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT);
 			sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxVRDO}\n",
-				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w - SCALEHANDLE_WIDTH,
-				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h * x->x_number - SCALEHANDLE_HEIGHT,
+				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w - SCALEHANDLE_WIDTH - 1,
+				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h * x->x_number - SCALEHANDLE_HEIGHT - 1,
 				 SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT,
 				 sh->h_pathname, x, x);
 			sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
@@ -284,6 +289,27 @@ void vradio_draw_select(t_vradio* x, t_glist* glist)
 				 sh->h_pathname, sh->h_bindsym->s_name);
 			x->x_gui.scale_vis = 1;
 
+			if (strcmp(x->x_gui.x_lab->s_name, "empty") != 0)
+			{
+				if (x->x_gui.label_vis)
+					sys_vgui("destroy %s\n", lh->h_pathname);
+
+				sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor crosshair\n",
+					lh->h_pathname, LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT);
+				sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxLABEL %lxVDRO}\n",
+					canvas, x->x_gui.x_obj.te_xpix+ x->x_gui.x_ldx - LABELHANDLE_WIDTH,
+					x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - LABELHANDLE_HEIGHT,
+					LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT,
+					lh->h_pathname, x, x);
+				sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 0 0 \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name); 
+				x->x_gui.label_vis = 1;
+			}
+
 			sys_vgui(".x%lx.c addtag selected withtag %lxVRDO\n", canvas, x);
 		}
 		else
@@ -298,6 +324,8 @@ void vradio_draw_select(t_vradio* x, t_glist* glist)
 		             x->x_gui.x_lcol);
 			sys_vgui("destroy %s\n", sh->h_pathname);
 			x->x_gui.scale_vis = 0;
+			sys_vgui("destroy %s\n", lh->h_pathname);
+			x->x_gui.scale_vis = 0;
 		}
 	}
 }
@@ -307,11 +335,17 @@ static void vradio__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t
 
 	t_vradio *x = (t_vradio *)(sh->h_master);
 
-	if (xxx) x->x_gui.scale_offset_x = xxx;
-	if (yyy) x->x_gui.scale_offset_y = yyy;
+ 	if (xxx) {
+ 		x->x_gui.scale_offset_x = xxx;
+ 		x->x_gui.label_offset_x = xxx;
+ 	}
+ 	if (yyy) {
+ 		x->x_gui.scale_offset_y = yyy;
+ 		x->x_gui.label_offset_y = yyy;
+ 	}
 
     int newstate = (int)f;
-    if (sh->h_dragon && newstate == 0)
+    if (sh->h_dragon && newstate == 0 && sh->h_scale)
     {
 		/* done dragging */
 
@@ -351,7 +385,7 @@ static void vradio__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t
 			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
 		}
     }
-    else if (!sh->h_dragon && newstate)
+    else if (!sh->h_dragon && newstate && sh->h_scale)
     {
 		/* dragging */
 		if (glist_isvisible(x->x_gui.x_glist))
@@ -367,13 +401,60 @@ static void vradio__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t
 		sh->h_dragx = 0;
 		sh->h_dragy = 0;
     }
+	else if (sh->h_dragon && newstate == 0 && !sh->h_scale)
+    {
+		/* done dragging */
+
+		/* first set up the undo apply */
+		canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
+
+		if (sh->h_dragx || sh->h_dragy) {
+
+			x->x_gui.x_ldx = x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x;
+			x->x_gui.x_ldy = x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y;
+
+			canvas_dirty(x->x_gui.x_glist, 1);
+		}
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			sys_vgui(".gfxstub%lx.dim.w_ent delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.dim.w_ent insert 0 %d\n", properties, x->x_gui.x_w);
+			//sys_vgui(".gfxstub%lx.dim.h_ent delete 0 end\n", properties);
+			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, x->x_gui.x_h);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist))
+		{
+			sys_vgui(".x%x.c delete %s\n", x->x_gui.x_glist, sh->h_outlinetag);
+			vradio_draw_move(x, x->x_gui.x_glist);
+			sys_vgui("destroy %s\n", sh->h_pathname);
+			iemgui_select((t_gobj *)x, x->x_gui.x_glist, 1);
+			canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
+		}
+    }
+    else if (!sh->h_dragon && newstate && !sh->h_scale)
+    {
+		/* dragging */
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			sys_vgui("lower %s\n", sh->h_pathname);
+			t_scalehandle *othersh = (t_scalehandle *)x->x_gui.x_handle;
+			sys_vgui("lower .x%x.h%x\n", (int)glist_getcanvas(x->x_gui.x_glist), (int)othersh);
+		}
+
+		sh->h_dragx = 0;
+		sh->h_dragy = 0;
+    }
+
     sh->h_dragon = newstate;
 }
 
 static void vradio__motionhook(t_scalehandle *sh,
 				    t_floatarg f1, t_floatarg f2)
 {
-    if (sh->h_dragon)
+    if (sh->h_dragon && sh->h_scale)
     {
 		t_vradio *x = (t_vradio *)(sh->h_master);
 		int dx = (int)f1, dy = (int)f2;
@@ -408,6 +489,37 @@ static void vradio__motionhook(t_scalehandle *sh,
 			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, new_h);
 		}
     }
+	if (sh->h_dragon && !sh->h_scale)
+    {
+		t_bng *x = (t_bng *)(sh->h_master);
+		int dx = (int)f1, dy = (int)f2;
+		int newx, newy;
+		newx = x->x_gui.x_obj.te_xpix + x->x_gui.x_w - x->x_gui.scale_offset_x + dx;
+		newy = x->x_gui.x_obj.te_ypix + x->x_gui.x_h - x->x_gui.scale_offset_y + dy;
+
+		sh->h_dragx = dx;
+		sh->h_dragy = dy;
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			int new_x = x->x_gui.x_ldx - x->x_gui.label_offset_x + sh->h_dragx;
+			int new_y = x->x_gui.x_ldy - x->x_gui.label_offset_y + sh->h_dragy;
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, new_x);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, new_y);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			int xpos=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		int ypos=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+			sys_vgui(".x%lx.c coords %lxLABEL %d %d\n",
+ 		    	canvas, x, xpos+x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x,
+ 		    	ypos+x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y);
+		}
+    }
 }
 
 void vradio_draw(t_vradio *x, t_glist *glist, int mode)
@@ -846,10 +958,26 @@ static void *vradio_donew(t_symbol *s, int argc, t_atom *argv, int old)
     pd_bind(x->x_gui.x_handle, sh->h_bindsym = gensym(buf));
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
+	sh->h_scale = 1;
 	x->x_gui.scale_offset_x = 0;
 	x->x_gui.scale_offset_y = 0;
 	x->x_gui.scale_vis = 0;
 
+	/* label handle init */
+	t_scalehandle *lh;
+	char lhbuf[64];
+	x->x_gui.x_lhandle = pd_new(scalehandle_class);
+	lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	lh->h_master = (t_gobj*)x;
+	sprintf(lhbuf, "_h%x", (int)lh);
+	pd_bind(x->x_gui.x_lhandle, lh->h_bindsym = gensym(lhbuf));
+	sprintf(lh->h_outlinetag, "h%x", (int)lh);
+	lh->h_dragon = 0;
+	lh->h_scale = 0;
+	x->x_gui.label_offset_x = 0;
+	x->x_gui.label_offset_y = 0;
+	x->x_gui.label_vis = 0;
+
     return (x);
 }
 
@@ -875,6 +1003,13 @@ static void vradio_ff(t_vradio *x)
 		pd_unbind(x->x_gui.x_handle, ((t_scalehandle *)x->x_gui.x_handle)->h_bindsym);
 		pd_free(x->x_gui.x_handle);
     }
+
+	/* label handle deconstructor */
+	if (x->x_gui.x_lhandle)
+	{
+		pd_unbind(x->x_gui.x_lhandle, ((t_scalehandle *)x->x_gui.x_lhandle)->h_bindsym);
+		pd_free(x->x_gui.x_lhandle);
+	}
 }
 
 void g_vradio_setup(void)
diff --git a/src/g_vslider.c b/src/g_vslider.c
index 49eafb7c8..d766fc829 100644
--- a/src/g_vslider.c
+++ b/src/g_vslider.c
@@ -58,6 +58,8 @@ static void vslider_draw_new(t_vslider *x, t_glist *glist)
 
 	t_scalehandle *sh = (t_scalehandle *)x->x_gui.x_handle;
 	sprintf(sh->h_pathname, ".x%x.h%x", (int)canvas, (int)sh);
+	t_scalehandle *lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	sprintf(lh->h_pathname, ".x%x.h%x", (int)canvas, (int)lh);
 
 	//if (glist_isvisible(canvas)) {
 
@@ -159,6 +161,8 @@ static void vslider_draw_erase(t_vslider* x,t_glist* glist)
 	if (x->x_gui.x_fsf.x_selected) {
 		t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
 		sys_vgui("destroy %s\n", sh->h_pathname);
+		t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
+		sys_vgui("destroy %s\n", lh->h_pathname);
 	}
 /*
     sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x);
@@ -235,6 +239,7 @@ static void vslider_draw_select(t_vslider *x, t_glist *glist)
 {
     t_canvas *canvas=glist_getcanvas(glist);
 	t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
+	t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
 
 	if (glist_isvisible(canvas)) {
 
@@ -249,8 +254,8 @@ static void vslider_draw_select(t_vslider *x, t_glist *glist)
 			sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor bottom_right_corner\n",
 				 sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT);
 			sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxVSLDR}\n",
-				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w - SCALEHANDLE_WIDTH,
-				 x->x_gui.x_obj.te_ypix + 3 + x->x_gui.x_h - SCALEHANDLE_HEIGHT,
+				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w - SCALEHANDLE_WIDTH - 1,
+				 x->x_gui.x_obj.te_ypix + 3 + x->x_gui.x_h - SCALEHANDLE_HEIGHT - 1,
 				 SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT,
 				 sh->h_pathname, x, x);
 			sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
@@ -261,6 +266,27 @@ static void vslider_draw_select(t_vslider *x, t_glist *glist)
 				 sh->h_pathname, sh->h_bindsym->s_name);
 			x->x_gui.scale_vis = 1;
 
+			if (strcmp(x->x_gui.x_lab->s_name, "empty") != 0)
+			{
+				if (x->x_gui.label_vis)
+					sys_vgui("destroy %s\n", lh->h_pathname);
+
+				sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor crosshair\n",
+					lh->h_pathname, LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT);
+				sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxLABEL %lxVSLDR}\n",
+					canvas, x->x_gui.x_obj.te_xpix+ x->x_gui.x_ldx - LABELHANDLE_WIDTH,
+					x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - LABELHANDLE_HEIGHT,
+					LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT,
+					lh->h_pathname, x, x);
+				sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 0 0 \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name); 
+				x->x_gui.label_vis = 1;
+			}
+
 			sys_vgui(".x%lx.c addtag selected withtag %lxVSLDR\n", canvas, x);
 		}
 		else
@@ -270,6 +296,8 @@ static void vslider_draw_select(t_vslider *x, t_glist *glist)
 			sys_vgui(".x%lx.c dtag %lxVSLDR selected\n", canvas, x);
 			sys_vgui("destroy %s\n", sh->h_pathname);
 			x->x_gui.scale_vis = 0;
+			sys_vgui("destroy %s\n", lh->h_pathname);
+			x->x_gui.label_vis = 0;
 		}
 	}
 }
@@ -279,11 +307,17 @@ static void vslider__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx,
 
 	t_vslider *x = (t_vslider *)(sh->h_master);
 
-	if (xxx) x->x_gui.scale_offset_x = xxx;
-	if (yyy) x->x_gui.scale_offset_y = yyy;
+ 	if (xxx) {
+ 		x->x_gui.scale_offset_x = xxx;
+ 		x->x_gui.label_offset_x = xxx;
+ 	}
+ 	if (yyy) {
+ 		x->x_gui.scale_offset_y = yyy;
+ 		x->x_gui.label_offset_y = yyy;
+ 	}
 
     int newstate = (int)f;
-    if (sh->h_dragon && newstate == 0)
+    if (sh->h_dragon && newstate == 0 && sh->h_scale)
     {
 		/* done dragging */
 
@@ -321,7 +355,7 @@ static void vslider__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx,
 			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
 		}
     }
-    else if (!sh->h_dragon && newstate)
+    else if (!sh->h_dragon && newstate && sh->h_scale)
     {
 		/* dragging */
 		if (glist_isvisible(x->x_gui.x_glist))
@@ -337,13 +371,60 @@ static void vslider__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx,
 		sh->h_dragx = 0;
 		sh->h_dragy = 0;
     }
+	else if (sh->h_dragon && newstate == 0 && !sh->h_scale)
+    {
+		/* done dragging */
+
+		/* first set up the undo apply */
+		canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
+
+		if (sh->h_dragx || sh->h_dragy) {
+
+			x->x_gui.x_ldx = x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x;
+			x->x_gui.x_ldy = x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y;
+
+			canvas_dirty(x->x_gui.x_glist, 1);
+		}
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			sys_vgui(".gfxstub%lx.dim.w_ent delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.dim.w_ent insert 0 %d\n", properties, x->x_gui.x_w);
+			//sys_vgui(".gfxstub%lx.dim.h_ent delete 0 end\n", properties);
+			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, x->x_gui.x_h);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist))
+		{
+			sys_vgui(".x%x.c delete %s\n", x->x_gui.x_glist, sh->h_outlinetag);
+			vslider_draw_move(x, x->x_gui.x_glist);
+			sys_vgui("destroy %s\n", sh->h_pathname);
+			iemgui_select((t_gobj *)x, x->x_gui.x_glist, 1);
+			canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
+		}
+    }
+    else if (!sh->h_dragon && newstate && !sh->h_scale)
+    {
+		/* dragging */
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			sys_vgui("lower %s\n", sh->h_pathname);
+			t_scalehandle *othersh = (t_scalehandle *)x->x_gui.x_handle;
+			sys_vgui("lower .x%x.h%x\n", (int)glist_getcanvas(x->x_gui.x_glist), (int)othersh);
+		}
+
+		sh->h_dragx = 0;
+		sh->h_dragy = 0;
+    }
+
     sh->h_dragon = newstate;
 }
 
 static void vslider__motionhook(t_scalehandle *sh,
 				    t_floatarg f1, t_floatarg f2)
 {
-    if (sh->h_dragon)
+    if (sh->h_dragon && sh->h_scale)
     {
 		t_hslider *x = (t_hslider *)(sh->h_master);
 		int dx = (int)f1, dy = (int)f2;
@@ -375,6 +456,37 @@ static void vslider__motionhook(t_scalehandle *sh,
 			sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, new_h);
 		}
     }
+	if (sh->h_dragon && !sh->h_scale)
+    {
+		t_bng *x = (t_bng *)(sh->h_master);
+		int dx = (int)f1, dy = (int)f2;
+		int newx, newy;
+		newx = x->x_gui.x_obj.te_xpix + x->x_gui.x_w - x->x_gui.scale_offset_x + dx;
+		newy = x->x_gui.x_obj.te_ypix + x->x_gui.x_h - x->x_gui.scale_offset_y + dy;
+
+		sh->h_dragx = dx;
+		sh->h_dragy = dy;
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			int new_x = x->x_gui.x_ldx - x->x_gui.label_offset_x + sh->h_dragx;
+			int new_y = x->x_gui.x_ldy - x->x_gui.label_offset_y + sh->h_dragy;
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, new_x);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, new_y);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			int xpos=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		int ypos=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+			sys_vgui(".x%lx.c coords %lxLABEL %d %d\n",
+ 		    	canvas, x, xpos+x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x,
+ 		    	ypos+x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y);
+		}
+    }
 }
 
 
@@ -803,10 +915,26 @@ static void *vslider_new(t_symbol *s, int argc, t_atom *argv)
     pd_bind(x->x_gui.x_handle, sh->h_bindsym = gensym(buf));
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
+	sh->h_scale = 1;
 	x->x_gui.scale_offset_x = 0;
 	x->x_gui.scale_offset_y = 0;
 	x->x_gui.scale_vis = 0;
 
+	/* label handle init */
+	t_scalehandle *lh;
+	char lhbuf[64];
+	x->x_gui.x_lhandle = pd_new(scalehandle_class);
+	lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	lh->h_master = (t_gobj*)x;
+	sprintf(lhbuf, "_h%x", (int)lh);
+	pd_bind(x->x_gui.x_lhandle, lh->h_bindsym = gensym(lhbuf));
+	sprintf(lh->h_outlinetag, "h%x", (int)lh);
+	lh->h_dragon = 0;
+	lh->h_scale = 0;
+	x->x_gui.label_offset_x = 0;
+	x->x_gui.label_offset_y = 0;
+	x->x_gui.label_vis = 0;
+
     return (x);
 }
 
@@ -822,6 +950,13 @@ static void vslider_free(t_vslider *x)
 		pd_unbind(x->x_gui.x_handle, ((t_scalehandle *)x->x_gui.x_handle)->h_bindsym);
 		pd_free(x->x_gui.x_handle);
     }
+
+	/* label handle deconstructor */
+	if (x->x_gui.x_lhandle)
+	{
+		pd_unbind(x->x_gui.x_lhandle, ((t_scalehandle *)x->x_gui.x_lhandle)->h_bindsym);
+		pd_free(x->x_gui.x_lhandle);
+	}
 }
 
 void g_vslider_setup(void)
diff --git a/src/g_vumeter.c b/src/g_vumeter.c
index 3980f1bf2..49113b1c1 100644
--- a/src/g_vumeter.c
+++ b/src/g_vumeter.c
@@ -113,6 +113,8 @@ static void vu_draw_new(t_vu *x, t_glist *glist)
 
 	t_scalehandle *sh = (t_scalehandle *)x->x_gui.x_handle;
 	sprintf(sh->h_pathname, ".x%x.h%x", (int)canvas, (int)sh);
+	t_scalehandle *lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	sprintf(lh->h_pathname, ".x%x.h%x", (int)canvas, (int)lh);
 
 	//if (glist_isvisible(canvas)) {
 
@@ -289,6 +291,8 @@ static void vu_draw_erase(t_vu* x,t_glist* glist)
 	if (x->x_gui.x_fsf.x_selected) {
 		t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
 		sys_vgui("destroy %s\n", sh->h_pathname);
+		t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
+		sys_vgui("destroy %s\n", lh->h_pathname);
 	}
 
 /*
@@ -426,6 +430,7 @@ static void vu_draw_select(t_vu* x,t_glist* glist)
     int i;
     t_canvas *canvas=glist_getcanvas(glist);
 	t_scalehandle *sh = (t_scalehandle *)(x->x_gui.x_handle);
+	t_scalehandle *lh = (t_scalehandle *)(x->x_gui.x_lhandle);
 
 	if (glist_isvisible(canvas)) {
 
@@ -452,8 +457,8 @@ static void vu_draw_select(t_vu* x,t_glist* glist)
 			sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor bottom_right_corner\n",
 				 sh->h_pathname, SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT);
 			sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxSCALE %lxVU}\n",
-				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w + 1 - SCALEHANDLE_WIDTH,
-				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h + 2 - SCALEHANDLE_HEIGHT,
+				 canvas, x->x_gui.x_obj.te_xpix + x->x_gui.x_w + 1 - SCALEHANDLE_WIDTH - 1,
+				 x->x_gui.x_obj.te_ypix + x->x_gui.x_h + 2 - SCALEHANDLE_HEIGHT - 1,
 				 SCALEHANDLE_WIDTH, SCALEHANDLE_HEIGHT,
 				 sh->h_pathname, x, x);
 			sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
@@ -463,6 +468,26 @@ static void vu_draw_select(t_vu* x,t_glist* glist)
 			sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
 				 sh->h_pathname, sh->h_bindsym->s_name);
 			x->x_gui.scale_vis = 1;
+			if (strcmp(x->x_gui.x_lab->s_name, "empty") != 0)
+			{
+				if (x->x_gui.label_vis)
+					sys_vgui("destroy %s\n", lh->h_pathname);
+
+				sys_vgui("canvas %s -width %d -height %d -bg $select_color -bd 0 -cursor crosshair\n",
+					lh->h_pathname, LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT);
+				sys_vgui(".x%x.c create window %d %d -anchor nw -width %d -height %d -window %s -tags {%lxLABEL %lxVU}\n",
+					canvas, x->x_gui.x_obj.te_xpix+ x->x_gui.x_ldx - LABELHANDLE_WIDTH,
+					x->x_gui.x_obj.te_ypix + x->x_gui.x_ldy - LABELHANDLE_HEIGHT,
+					LABELHANDLE_WIDTH, LABELHANDLE_HEIGHT,
+					lh->h_pathname, x, x);
+				sys_vgui("bind %s <Button> {pd [concat %s _click 1 %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 0 0 \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name);
+				sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+					lh->h_pathname, lh->h_bindsym->s_name); 
+				x->x_gui.label_vis = 1;
+			}
 
 			sys_vgui(".x%lx.c addtag selected withtag %lxVU\n", canvas, x);
 		}
@@ -485,6 +510,8 @@ static void vu_draw_select(t_vu* x,t_glist* glist)
 		    sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
 			sys_vgui("destroy %s\n", sh->h_pathname);
 			x->x_gui.scale_vis = 0;
+			sys_vgui("destroy %s\n", lh->h_pathname);
+			x->x_gui.label_vis = 0;
 		}
 	}
 }
@@ -494,11 +521,17 @@ static void vu__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t_flo
 
 	t_vu *x = (t_vu *)(sh->h_master);
 
-	if (xxx) x->x_gui.scale_offset_x = xxx;
-	if (yyy) x->x_gui.scale_offset_y = yyy;
+ 	if (xxx) {
+ 		x->x_gui.scale_offset_x = xxx;
+ 		x->x_gui.label_offset_x = xxx;
+ 	}
+ 	if (yyy) {
+ 		x->x_gui.scale_offset_y = yyy;
+ 		x->x_gui.label_offset_y = yyy;
+ 	}
 
     int newstate = (int)f;
-    if (sh->h_dragon && newstate == 0)
+    if (sh->h_dragon && newstate == 0  && sh->h_scale)
     {
 		/* done dragging */
 
@@ -539,7 +572,7 @@ static void vu__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t_flo
 			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
 		}
     }
-    else if (!sh->h_dragon && newstate)
+    else if (!sh->h_dragon && newstate && sh->h_scale)
     {
 		/* dragging */
 		if (glist_isvisible(x->x_gui.x_glist))
@@ -555,13 +588,60 @@ static void vu__clickhook(t_scalehandle *sh, t_floatarg f, t_floatarg xxx, t_flo
 		sh->h_dragx = 0;
 		sh->h_dragy = 0;
     }
+	else if (sh->h_dragon && newstate == 0 && !sh->h_scale)
+    {
+		/* done dragging */
+
+		/* first set up the undo apply */
+		canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
+
+		if (sh->h_dragx || sh->h_dragy) {
+
+			x->x_gui.x_ldx = x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x;
+			x->x_gui.x_ldy = x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y;
+
+			canvas_dirty(x->x_gui.x_glist, 1);
+		}
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			sys_vgui(".gfxstub%lx.dim.w_ent delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.dim.w_ent insert 0 %d\n", properties, x->x_gui.x_w);
+			//sys_vgui(".gfxstub%lx.dim.h_ent delete 0 end\n", properties);
+			//sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, x->x_gui.x_h);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist))
+		{
+			sys_vgui(".x%x.c delete %s\n", x->x_gui.x_glist, sh->h_outlinetag);
+			vu_draw_move(x, x->x_gui.x_glist);
+			sys_vgui("destroy %s\n", sh->h_pathname);
+			iemgui_select((t_gobj *)x, x->x_gui.x_glist, 1);
+			canvas_fixlinesfor(x->x_gui.x_glist, (t_text *)x);
+			sys_vgui("pdtk_canvas_getscroll .x%lx.c\n", x->x_gui.x_glist);
+		}
+    }
+    else if (!sh->h_dragon && newstate && !sh->h_scale)
+    {
+		/* dragging */
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			sys_vgui("lower %s\n", sh->h_pathname);
+			t_scalehandle *othersh = (t_scalehandle *)x->x_gui.x_handle;
+			sys_vgui("lower .x%x.h%x\n", (int)glist_getcanvas(x->x_gui.x_glist), (int)othersh);
+		}
+
+		sh->h_dragx = 0;
+		sh->h_dragy = 0;
+    }
+
     sh->h_dragon = newstate;
 }
 
 static void vu__motionhook(t_scalehandle *sh,
 				    t_floatarg f1, t_floatarg f2)
 {
-    if (sh->h_dragon)
+    if (sh->h_dragon && sh->h_scale)
     {
 		t_vu *x = (t_vu *)(sh->h_master);
 		int dx = (int)f1, dy = (int)f2;
@@ -598,6 +678,37 @@ static void vu__motionhook(t_scalehandle *sh,
 			sys_vgui(".gfxstub%lx.dim.h_ent insert 0 %d\n", properties, new_h);
 		}
     }
+	if (sh->h_dragon && !sh->h_scale)
+    {
+		t_bng *x = (t_bng *)(sh->h_master);
+		int dx = (int)f1, dy = (int)f2;
+		int newx, newy;
+		newx = x->x_gui.x_obj.te_xpix + x->x_gui.x_w - x->x_gui.scale_offset_x + dx;
+		newy = x->x_gui.x_obj.te_ypix + x->x_gui.x_h - x->x_gui.scale_offset_y + dy;
+
+		sh->h_dragx = dx;
+		sh->h_dragy = dy;
+
+		int properties = gfxstub_haveproperties((void *)x);
+
+		if (properties) {
+			int new_x = x->x_gui.x_ldx - x->x_gui.label_offset_x + sh->h_dragx;
+			int new_y = x->x_gui.x_ldy - x->x_gui.label_offset_y + sh->h_dragy;
+			sys_vgui(".gfxstub%lx.label.xy.x_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.x_entry insert 0 %d\n", properties, new_x);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry delete 0 end\n", properties);
+			sys_vgui(".gfxstub%lx.label.xy.y_entry insert 0 %d\n", properties, new_y);
+		}
+
+		if (glist_isvisible(x->x_gui.x_glist)) {
+			int xpos=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		int ypos=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+    		t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+			sys_vgui(".x%lx.c coords %lxLABEL %d %d\n",
+ 		    	canvas, x, xpos+x->x_gui.x_ldx + sh->h_dragx - x->x_gui.label_offset_x,
+ 		    	ypos+x->x_gui.x_ldy + sh->h_dragy - x->x_gui.label_offset_y);
+		}
+    }
 }
 
 void vu_draw(t_vu *x, t_glist *glist, int mode)
@@ -933,10 +1044,26 @@ static void *vu_new(t_symbol *s, int argc, t_atom *argv)
     pd_bind(x->x_gui.x_handle, sh->h_bindsym = gensym(buf));
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
+	sh->h_scale = 1;
 	x->x_gui.scale_offset_x = 0;
 	x->x_gui.scale_offset_y = 0;
 	x->x_gui.scale_vis = 0;
 
+	/* label handle init */
+	t_scalehandle *lh;
+	char lhbuf[64];
+	x->x_gui.x_lhandle = pd_new(scalehandle_class);
+	lh = (t_scalehandle *)x->x_gui.x_lhandle;
+	lh->h_master = (t_gobj*)x;
+	sprintf(lhbuf, "_h%x", (int)lh);
+	pd_bind(x->x_gui.x_lhandle, lh->h_bindsym = gensym(lhbuf));
+	sprintf(lh->h_outlinetag, "h%x", (int)lh);
+	lh->h_dragon = 0;
+	lh->h_scale = 0;
+	x->x_gui.label_offset_x = 0;
+	x->x_gui.label_offset_y = 0;
+	x->x_gui.label_vis = 0;
+
     return (x);
 }
 
@@ -952,6 +1079,13 @@ static void vu_free(t_vu *x)
 		pd_unbind(x->x_gui.x_handle, ((t_scalehandle *)x->x_gui.x_handle)->h_bindsym);
 		pd_free(x->x_gui.x_handle);
     }
+
+	/* label handle deconstructor */
+	if (x->x_gui.x_lhandle)
+	{
+		pd_unbind(x->x_gui.x_lhandle, ((t_scalehandle *)x->x_gui.x_lhandle)->h_bindsym);
+		pd_free(x->x_gui.x_lhandle);
+	}
 }
 
 void g_vumeter_setup(void)
diff --git a/src/m_memory.c b/src/m_memory.c
index f598e4f8f..7e0de12cb 100644
--- a/src/m_memory.c
+++ b/src/m_memory.c
@@ -17,15 +17,20 @@
 static int totalmem = 0;
 #endif
 
+static int memoffset = 0;
+
 void *getbytes(size_t nbytes)
 {
     void *ret;
+
     if (nbytes < 1) nbytes = 1;
     ret = (void *)calloc(nbytes, 1);
+
 #ifdef LOUD
     fprintf(stderr, "new  %lx %d\n", (int)ret, nbytes);
 #endif /* LOUD */
 #ifdef DEBUGMEM
+	
     totalmem += nbytes;
 #endif
     if (!ret)
diff --git a/src/m_pd.c b/src/m_pd.c
index 211173369..7b5d8d2b3 100644
--- a/src/m_pd.c
+++ b/src/m_pd.c
@@ -6,6 +6,9 @@
 #include "m_pd.h"
 #include "m_imp.h"
 
+#include "g_canvas.h"
+#include <stdio.h>
+
     /* FIXME no out-of-memory testing yet! */
 
 t_pd *pd_new(t_class *c)
@@ -13,6 +16,67 @@ t_pd *pd_new(t_class *c)
     t_pd *x;
     if (!c) 
         bug ("pd_new: apparently called before setup routine");
+
+	/* 	here we make sure we do not create objects at the same memory address as before
+		to avoid double-entry bug that is invoked when this happens. why? no idea...
+		tcl/tk definitely sends only one command via socket, yet it is activated multiple
+		times inside c code. perhaps class_addmethod is never cleaned out (although this
+		makes no sense either as we use calloc which should zero everything out, yet even
+		that is not entirely guarranteed)
+
+		we do this by comparing the newly allocated address with preexisting list of
+		canvases that were created in the past.
+
+		if a duplicate is triggered, we deallocate memory and reallocate it assigning 
+		a random additional amount of memory and then resize allocation to the original
+		size
+
+		duplicate: -1 initial state
+					0 all is ok
+					1 found a duplicate
+	*/
+
+	int duplicate = -1;
+	int random_extra = 0;
+
+	while (duplicate != 0) {
+
+		if (duplicate == -1) {
+			//fprintf(stderr,"alloc %d %d\n", duplicate, (int)c->c_size);
+			x = (t_pd *)t_getbytes(c->c_size);
+		} else if (duplicate == 1) {
+			random_extra = rand () + 1;
+			//fprintf(stderr,"alloc %d %d %d\n", duplicate, (int)c->c_size, (int)c->c_size + random_extra);
+			x = (t_pd *)t_getbytes(c->c_size + random_extra);
+		}
+		duplicate = 0;
+
+		if (rm_start) {
+			t_redundant_mem *tmp = rm_start;
+			while (tmp->rm_next) {
+				if ((int)tmp->rm_canvas == (int)x) {
+					duplicate = 1;
+					break;
+				}
+				tmp = tmp->rm_next;
+			}
+			if (tmp && (int)tmp->rm_canvas == (int)x)
+				duplicate = 1;
+		}
+		//fprintf(stderr,"done alloc %d\n", duplicate);
+		if (duplicate == 1) {
+			//fprintf(stderr,"duplicate\n");
+			if (!random_extra)
+				t_freebytes(x, sizeof(c->c_size));
+			else
+				t_freebytes(x, sizeof(c->c_size+random_extra));
+		}
+
+		if (!duplicate && random_extra) {
+			x = (t_pd *)t_resizebytes(x, c->c_size+random_extra, c->c_size);
+		}
+	}
+
     x = (t_pd *)t_getbytes(c->c_size);
     *x = c;
     if (c->c_patchable)
diff --git a/src/m_pd.h b/src/m_pd.h
index b61e370a2..161aa95be 100644
--- a/src/m_pd.h
+++ b/src/m_pd.h
@@ -11,7 +11,7 @@ extern "C" {
 #define PD_MAJOR_VERSION 0
 #define PD_MINOR_VERSION 42
 #define PD_BUGFIX_VERSION 5
-#define PD_TEST_VERSION "extended-l2ork-20110326"
+#define PD_TEST_VERSION "extended-l2ork-20110403"
 
 /* old name for "MSW" flag -- we have to take it for the sake of many old
 "nmakefiles" for externs, which will define NT and not MSW */
diff --git a/src/makefile.dependencies b/src/makefile.dependencies
index 2f2d94308..438ce3f76 100644
--- a/src/makefile.dependencies
+++ b/src/makefile.dependencies
@@ -505,7 +505,10 @@ m_pd.o: m_pd.c /usr/include/stdlib.h /usr/include/features.h \
  /usr/include/sys/select.h /usr/include/bits/select.h \
  /usr/include/bits/sigset.h /usr/include/bits/time.h \
  /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
- /usr/include/alloca.h m_pd.h m_imp.h
+ /usr/include/alloca.h m_pd.h m_imp.h g_canvas.h /usr/include/stdio.h \
+ /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+ /usr/lib/gcc/i486-linux-gnu/4.4.1/include/stdarg.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
 m_class.o: m_class.c config.h m_pd.h \
  /usr/lib/gcc/i486-linux-gnu/4.4.1/include/stddef.h m_imp.h s_stuff.h \
  /usr/include/stdlib.h /usr/include/features.h \
diff --git a/src/pd.tk b/src/pd.tk
index 066472b38..119b6c85a 100644
--- a/src/pd.tk
+++ b/src/pd.tk
@@ -3079,10 +3079,18 @@ proc pdtk_canvas_ctrlkey {name key shift} {
 
 	#puts stderr $name
 
-	if {$name == "." || [string match .printout* $name] || [string match .controls* $name] || [string match .gfxstub* $name]  || [string match .help_browser* $name]} {
-		set ignore 1	
+	if {[string match *.c $name] || [info exists $name.c]} {
+		set ignore 0
+	} else {
+		set ignore 1
 	}
 
+	#puts stderr "$name $ignore"
+
+	#if {$name == "." || [string match .printout* $name] || [string match .controls* $name] || [string match .gfxstub* $name]  || [string match .help_browser* $name]} {
+	#	set ignore 1	
+	#}
+
 	if {!$ignore} {
 		if {$key == "1"} {menu_object $topname 1}
 		if {$key == "2"} {menu_message $topname 1}
diff --git a/src/s_inter.c b/src/s_inter.c
index 47eb6a530..40dc3ec41 100644
--- a/src/s_inter.c
+++ b/src/s_inter.c
@@ -1313,6 +1313,24 @@ void sys_bail(int n)
 
 void glob_quit(void *dummy)
 {
+	/* deallocate rendundant memory (see g_canvas.c canvas_new and g_canvas.h for struct declaration */
+	if (rm_start) {
+		while (rm_start->rm_next) {
+			t_redundant_mem *tmp = rm_start;
+			rm_start = rm_start->rm_next;
+			/* 	we can also explicitly look for deallocating per-canvas settings here, if such proves necessary 
+				to do so, look at rm_start->rm_canvas
+			*/
+			//fprintf(stderr,".x%lx\n", tmp->rm_canvas);
+			t_freebytes(tmp,  sizeof(*tmp));
+			//fprintf(stderr,"dealloc\n");
+		}
+		if (rm_start) {
+			t_freebytes(rm_start,  sizeof(*rm_start));
+			//fprintf(stderr,"last dealloc\n");
+		}
+	}
+
     sys_vgui("exit\n");
     if (!sys_nogui)
     {
-- 
GitLab