/**
 * $Id:
 *
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef WIN32
#include "BLI_winstuff.h"
#ifndef snprintf
#define snprintf _snprintf
#endif
#endif

#include "MEM_guardedalloc.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"

#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_effect_types.h"
#include "DNA_group_types.h"
#include "DNA_ika_types.h"
#include "DNA_image_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_radio_types.h"
#include "DNA_screen_types.h"
#include "DNA_sound_types.h"
#include "DNA_texture_types.h"
#include "DNA_userdef_types.h"
#include "DNA_vfont_types.h"
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
#include "DNA_packedFile_types.h"

#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_library.h"
#include "BKE_packedFile.h"

#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_vfontdata.h"
#include "BLI_editVert.h"

#include "BSE_filesel.h"

#include "BIF_gl.h"
#include "BIF_editarmature.h"
#include "BIF_editconstraint.h"
#include "BIF_editdeform.h"
#include "BIF_editfont.h"
#include "BIF_editmesh.h"
#include "BIF_editsound.h"
#include "BIF_interface.h"
#include "BIF_meshtools.h"
#include "BIF_mywindow.h"
#include "BIF_renderwin.h"
#include "BIF_resources.h"
#include "BIF_screen.h"
#include "BIF_scrarea.h"
#include "BIF_space.h"
#include "BIF_toets.h"
#include "BIF_toolbox.h"
#include "BIF_previewrender.h"
#include "BIF_butspace.h"

#include "mydevice.h"
#include "blendef.h"

#include "BKE_action.h"
#include "BKE_anim.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_font.h"
#include "BKE_ika.h"
#include "BKE_image.h"
#include "BKE_ipo.h"
#include "BKE_lattice.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_sound.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"

#include "BDR_drawobject.h"
#include "BDR_editcurve.h"
#include "BDR_editface.h"
#include "BDR_editobject.h"
#include "BDR_vpaint.h"
#include "BDR_unwrapper.h"

#include "BSE_drawview.h"
#include "BSE_editipo.h"
#include "BSE_edit.h"
#include "BSE_filesel.h"
#include "BSE_headerbuttons.h"
#include "BSE_trans_types.h"
#include "BSE_view.h"
#include "BSE_buttons.h"
#include "BSE_seqaudio.h"

#include "LOD_DependKludge.h"
#include "LOD_decimation.h"

#include "butspace.h" // own module

static int decim_faces=0;
static short degr= 90, step= 9, turn= 1;
static float extr_offs= 1.0;
static float editbutweight=1.0;
short editbutflag= 1;
float doublimit= 0.001, editbutvweight=1, editbutsize=0.1;
float uv_calc_radius= 1.0, uv_calc_cubesize= 1.0;
short uv_calc_mapdir= 1, uv_calc_mapalign= 1, facesel_draw_edges= 0;

extern ListBase editNurb;

/* *************************** MESH DECIMATE ******************************** */

/* should be removed from this c file (ton) */

static int decimate_count_tria(Object *ob)
{
	int tottria;
	MFace *mface;
	Mesh *me;
	int a;

	me= ob->data;

	/* count number of trias, since decimator doesnt allow quads */
	tottria= 0;
	mface= me->mface;
	for(a=0; a<me->totface; a++, mface++) {
		if(mface->v4) tottria++;
		if(mface->v3) tottria++;
	}

	return tottria;
}

static void decimate_faces(void)
{
	Object *ob;
	Mesh *me;
	MVert *mvert;
	MFace *mface;
	LOD_Decimation_Info lod;
	float *vb=NULL;
	float *vnb=NULL;
	int *tib=NULL;
	int a, tottria;

	/* we assume the active object being decimated */
	ob= OBACT;
	if(ob==NULL || ob->type!=OB_MESH) return;
	me= ob->data;

	/* add warning for vertex col and tfaces */
	if(me->tface || me->mcol || me->dvert || me->medge) {
		if(okee("This will remove UV coordinates, vertexcolors, deform weights and edge data")==0) return;
		if(me->tface) MEM_freeN(me->tface);
		if(me->mcol) MEM_freeN(me->mcol);
		if(me->dvert) free_dverts(me->dvert, me->totvert);
		me->tface= NULL;
		me->mcol= NULL;
		me->dvert= NULL;
	}

	/* count number of trias, since decimator doesnt allow quads */
	tottria= decimate_count_tria(ob);

	if(tottria<3) {
		error("You must have more than 3 input faces selected.");
		return;
	}
	/* allocate and init */
	lod.vertex_buffer= MEM_mallocN(3*sizeof(float)*me->totvert, "vertices");
	lod.vertex_normal_buffer= MEM_mallocN(3*sizeof(float)*me->totvert, "normals");
	lod.triangle_index_buffer= MEM_mallocN(3*sizeof(int)*tottria, "trias");
	lod.vertex_num= me->totvert;
	lod.face_num= tottria;

	/* fill vertex buffer */
	vb= lod.vertex_buffer;
	vnb= lod.vertex_normal_buffer;
	mvert= me->mvert;
	for(a=0; a<me->totvert; a++, mvert++, vb+=3, vnb+=3) {
		VECCOPY(vb, mvert->co);
		VECCOPY(vnb, mvert->no);
		Normalise(vnb);
	}

	/* fill index buffer */
	mface= me->mface;
	tib= lod.triangle_index_buffer;
	for(a=0; a<me->totface; a++, mface++) {
		if(mface->v4) {
			tib[0]= mface->v1;
			tib[1]= mface->v3;
			tib[2]= mface->v4;
			tib+= 3;
		}
		if(mface->v3) {
			tib[0]= mface->v1;
			tib[1]= mface->v2;
			tib[2]= mface->v3;
			tib+= 3;
		}
	}

	if(LOD_LoadMesh(&lod) ) {
		if( LOD_PreprocessMesh(&lod) ) {
			DispList *dl;
			DispListMesh *dlm;
			MFace *mfaceint;

			/* we assume the decim_faces tells how much to reduce */

			while(lod.face_num > decim_faces) {
				if( LOD_CollapseEdge(&lod)==0) break;
			}

			/* ok, put back the stuff in a displist */
			freedisplist(&(ob->disp));
			dl= MEM_callocN(sizeof(DispList), "disp");
			BLI_addtail(&ob->disp, dl);
			dl->type= DL_MESH;
			dlm=dl->mesh= MEM_callocN(sizeof(DispListMesh), "dispmesh");
			dlm->mvert= MEM_callocN(lod.vertex_num*sizeof(MVert), "mvert");
			dlm->mface= MEM_callocN(lod.face_num*sizeof(MFace), "mface");
			dlm->totvert= lod.vertex_num;
			dlm->totface= lod.face_num;

			mvert= dlm->mvert;
			vb= lod.vertex_buffer;
			for(a=0; a<lod.vertex_num; a++, vb+=3, mvert++) {
				VECCOPY(mvert->co, vb);
			}

			mfaceint= dlm->mface;
			tib= lod.triangle_index_buffer;
			for(a=0; a<lod.face_num; a++, mfaceint++, tib+=3) {
				mfaceint->v1= tib[0];
				mfaceint->v2= tib[1];
				mfaceint->v3= tib[2];
			}
		}
		else error("No memory");

		LOD_FreeDecimationData(&lod);
	}
	else error("No manifold Mesh");

	MEM_freeN(lod.vertex_buffer);
	MEM_freeN(lod.vertex_normal_buffer);
	MEM_freeN(lod.triangle_index_buffer);

	allqueue(REDRAWVIEW3D, 0);
}



static void decimate_cancel(void)
{
	Object *ob;

	ob= OBACT;
	if(ob) {
		freedisplist(&ob->disp);
		makeDispList(ob);
	}
	allqueue(REDRAWVIEW3D, 0);
}

static void decimate_apply(void)
{
	Object *ob;
	DispList *dl;
	DispListMesh *dlm;
	Mesh *me;
	MFace *mface;
	MFace *mfaceint;
	int a;

	if(G.obedit) return;

	ob= OBACT;
	if(ob) {
		dl= ob->disp.first;
		if(dl && dl->mesh) {
			dlm= dl->mesh;
			me= ob->data;

			// vertices
			if(me->mvert) MEM_freeN(me->mvert);
			me->mvert= dlm->mvert;
			dlm->mvert= NULL;
			me->totvert= dlm->totvert;

			// edges
			if(me->medge) MEM_freeN(me->medge);
			me->medge = NULL;
			me->totedge = 0;

			// faces
			if(me->mface) MEM_freeN(me->mface);
			me->mface= MEM_callocN(dlm->totface*sizeof(MFace), "mface");
			me->totface= dlm->totface;
			mface= me->mface;
			mfaceint= dlm->mface;
			for(a=0; a<me->totface; a++, mface++, mfaceint++) {
				mface->v1= mfaceint->v1;
				mface->v2= mfaceint->v2;
				mface->v3= mfaceint->v3;
				test_index_mface(mface, 3);
			}

			freedisplist(&ob->disp);

			G.obedit= ob;
			make_editMesh();
			load_editMesh();
			free_editMesh(G.editMesh);
			G.obedit= NULL;
			tex_space_mesh(me);

			if (mesh_uses_displist(me)) {
				makeDispList(ob);
			}
			BIF_undo_push("Apply decimation");
		}
		else error("Not a decimated Mesh");
	}
}

/* *************** */

void do_common_editbuts(unsigned short event) // old name, is a mix of object and editing events.... 
{
	EditMesh *em = G.editMesh;
	EditFace *efa;
	Base *base;
	Object *ob;
	Mesh *me;
	Nurb *nu;
	Curve *cu;
	BezTriple *bezt;
	BPoint *bp;
	unsigned int local;
	int a, bit, index= -1;

	switch(event) {
		
	case B_MATWICH:
		if(G.obedit && G.obedit->actcol>0) {
			if(G.obedit->type == OB_MESH) {
				efa= em->faces.first;
				while(efa) {
					if(efa->f & SELECT) {
						if(index== -1) index= efa->mat_nr;
						else if(index!=efa->mat_nr) {
							error("Mixed colors");
							return;
						}
					}
					efa= efa->next;
				}
			}
			else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
				nu= editNurb.first;
				while(nu) {
					if( isNurbsel(nu) ) {
						if(index== -1) index= nu->mat_nr;
						else if(index!=nu->mat_nr) {
							error("Mixed colors");
							return;
						}
					}
					nu= nu->next;
				}				
			}
			if(index>=0) {
				G.obedit->actcol= index+1;
				scrarea_queue_winredraw(curarea);
			}
		}
		break;
	case B_MATNEW:
		new_material_to_objectdata((G.scene->basact) ? (G.scene->basact->object) : 0);
		scrarea_queue_winredraw(curarea);
		BIF_undo_push("New material");
		allqueue(REDRAWVIEW3D_Z, 0);
		allqueue(REDRAWOOPS, 0);
		break;
	case B_MATDEL:
		delete_material_index();
		scrarea_queue_winredraw(curarea);
		BIF_undo_push("Delete material index");
		allqueue(REDRAWVIEW3D_Z, 0);
		allqueue(REDRAWOOPS, 0);
		break;
	case B_MATASS:
		if(G.obedit && G.obedit->actcol>0) {
			if(G.obedit->type == OB_MESH) {
				efa= em->faces.first;
				while(efa) {
					if(efa->f & SELECT)
						efa->mat_nr= G.obedit->actcol-1;
					efa= efa->next;
				}
			}
			else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
				nu= editNurb.first;
				while(nu) {
					if( isNurbsel(nu) )
						nu->mat_nr= G.obedit->actcol-1;
					nu= nu->next;
				}
			}
			allqueue(REDRAWVIEW3D_Z, 0);
			makeDispList(G.obedit);
			BIF_undo_push("Assign material index");
		}
		break;
	case B_MATSEL:
	case B_MATDESEL:
		if(G.obedit) {
			if(G.obedit->type == OB_MESH) {
				if (event==B_MATSEL) {
					editmesh_select_by_material(G.obedit->actcol-1);
				} else {
					editmesh_deselect_by_material(G.obedit->actcol-1);
				}
				allqueue(REDRAWVIEW3D, 0);
			}
			else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
				nu= editNurb.first;
				while(nu) {
					if(nu->mat_nr==G.obedit->actcol-1) {
						if(nu->bezt) {
							a= nu->pntsu;
							bezt= nu->bezt;
							while(a--) {
								if(bezt->hide==0) {
									if(event==B_MATSEL) {
										bezt->f1 |= 1;
										bezt->f2 |= 1;
										bezt->f3 |= 1;
									}
									else {
										bezt->f1 &= ~1;
										bezt->f2 &= ~1;
										bezt->f3 &= ~1;
									}
								}
								bezt++;
							}
						}
						else if(nu->bp) {
							a= nu->pntsu*nu->pntsv;
							bp= nu->bp;
							while(a--) {
								if(bp->hide==0) {
									if(event==B_MATSEL) bp->f1 |= 1;
									else bp->f1 &= ~1;
								}
								bp++;
							}
						}
					}
					nu= nu->next;
				}
				BIF_undo_push("Select material index");
				allqueue(REDRAWVIEW3D, 0);
			}
		}
		break;
	case B_HIDE:
		if(G.obedit) {
			if(G.obedit->type == OB_MESH) hide_mesh(0);
			else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) hideNurb(0);
		}
		break;
	case B_REVEAL:
		if(G.obedit) {
			if(G.obedit->type == OB_MESH) reveal_mesh();
			else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) revealNurb();
		}
		else if(G.f & G_FACESELECT) reveal_tface();
		
		break;
	case B_SELSWAP:
		if(G.obedit) {
			if(G.obedit->type == OB_MESH) selectswap_mesh();
			else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) selectswapNurb();
		}
		break;
	case B_AUTOTEX:
		ob= OBACT;
		if(ob && G.obedit==0) {
			if(ob->type==OB_MESH) tex_space_mesh(ob->data);
			else if(ob->type==OB_MBALL) ;
			else tex_space_curve(ob->data);
		}
		break;
	case B_DOCENTRE:
		docentre(0);
		break;
	case B_DOCENTRENEW:
		docentre_new();
		break;
	case B_DOCENTRECURSOR:
		docentre_cursor();
		break;
	case B_SETSMOOTH:
	case B_SETSOLID:
		if(G.obedit) {
			if(G.obedit->type == OB_MESH) {
				efa= em->faces.first;
				while(efa) {
					if(efa->f & SELECT) {
						if(event==B_SETSMOOTH) efa->flag |= ME_SMOOTH;
						else efa->flag &= ~ME_SMOOTH;
					}
					efa= efa->next;
				}
			}
			else {
				nu= editNurb.first;
				while(nu) {
					if(isNurbsel(nu)) {
						if(event==B_SETSMOOTH) nu->flag |= CU_SMOOTH;
						else nu->flag &= ~CU_SMOOTH;
					}
					nu= nu->next;
				}
			}
			makeDispList(G.obedit);
			allqueue(REDRAWVIEW3D, 0);
		}
		else {
			base= FIRSTBASE;
			while(base) {
				if(TESTBASELIB(base)) {
					if(base->object->type==OB_MESH) {
						me= base->object->data;
						mesh_set_smooth_flag(me, (event==B_SETSMOOTH));
						makeDispList(base->object);
					}
					else if ELEM(base->object->type, OB_SURF, OB_CURVE) {
						cu= base->object->data;
						nu= cu->nurb.first;
						while(nu) {
							if(event==B_SETSMOOTH) nu->flag |= ME_SMOOTH;
							else nu->flag &= ~ME_SMOOTH;
							nu= nu->next;
						}
						makeDispList(base->object);
					}
				}
				base= base->next;
			}
			allqueue(REDRAWVIEW3D, 0);
		}
		if(event == B_SETSMOOTH) BIF_undo_push("Set Smooth");
		else BIF_undo_push("Set Solid");

		break;

	default:
		if(event>=B_OBLAY && event<=B_OBLAY+31) {
			local= BASACT->lay & 0xFF000000;
			BASACT->lay -= local;
			if(BASACT->lay==0 || (G.qual & LR_SHIFTKEY)==0) {
				bit= event-B_OBLAY;
				BASACT->lay= 1<<bit;
				scrarea_queue_winredraw(curarea);
			}
			BASACT->lay += local;
			/* optimal redraw */
			if( (OBACT->lay & G.vd->lay) && (BASACT->lay & G.vd->lay) );
			else if( (OBACT->lay & G.vd->lay)==0 && (BASACT->lay & G.vd->lay)==0 );
			else allqueue(REDRAWVIEW3D, 0);
			
			OBACT->lay= BASACT->lay;
		}
	}

}

/* *************************** MESH  ******************************** */


static void editing_panel_mesh_type(Object *ob, Mesh *me)
{
	uiBlock *block;
	float val;
	/* Hope to support more than two subsurf algorithms */
	char subsurfmenu[]="Subsurf Type%t|Catmull-Clark%x0|Simple Subdiv.%x1";

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_type", UI_EMBOSS, UI_HELV, curarea->win);
	if( uiNewPanel(curarea, block, "Mesh", "Editing", 320, 0, 318, 204)==0) return;

	uiBlockBeginAlign(block);
	uiDefButS(block, TOG|BIT|5, REDRAWVIEW3D, "Auto Smooth",10,180,154,19, &me->flag, 0, 0, 0, 0, "Treats all set-smoothed faces with angles less than Degr: as 'smooth' during render");
	uiDefButS(block, NUM, B_DIFF, "Degr:",				10,160,154,19, &me->smoothresh, 1, 80, 0, 0, "Defines maximum angle between face normals that 'Auto Smooth' will operate on");

	uiBlockBeginAlign(block);
	uiBlockSetCol(block, TH_BUT_SETTING1);
	uiDefButS(block, TOG|BIT|7, B_MAKEDISP, "SubSurf",	10,134,70,19, &me->flag, 0, 0, 0, 0, "Treats the active object as a Subdivision Surface");
	uiDefButS(block, MENU, B_MAKEDISP, subsurfmenu,		80,134,84,19, &(me->subsurftype), 0, 0, 0, 0, "Selects type of Subsurf algorithm.");
	uiBlockSetCol(block, TH_AUTO);
	uiDefButS(block, NUM, B_MAKEDISP, "Subdiv:",		10, 114,110,19, &me->subdiv, 0, 6, 0, 0, "Defines the level of subdivision to display in real time interactively");
	uiDefButS(block, NUM, B_DIFF, "",				120,114, 44, 19, &me->subdivr, 0, 6, 0, 0, "Defines the level of subdivision to apply during rendering");
	uiDefButS(block, TOG|BIT|8, B_MAKEDISP, "Optimal",	10, 94,154,19, &me->flag, 0, 0, 0, 0, "Only draws optimal wireframe");

	uiBlockBeginAlign(block);

	if(me->medge) val= 1.0; else val= 0.0;
	uiDefBut(block, LABEL, 0, "Edges", 					10,70,70,20, 0, val, 0, 0, 0, "");
	if(me->medge==NULL) {
		uiDefBut(block, BUT, B_MAKEEDGES, "Make",		80,70,84,19, 0, 0, 0, 0, 0, "Adds edges data to active Mesh object, enables creases/seams and faster wireframe draw");
	}
	else uiDefBut(block, BUT, B_DELEDGES, "Delete", 	80,70,84,19, 0, 0, 0, 0, 0, "Deletes edges data from active Mesh object");

	if(me->mcol) val= 1.0; else val= 0.0;
	uiDefBut(block, LABEL, 0, "VertCol", 				10,50,70,20, 0, val, 0, 0, 0, "");
	if(me->mcol==NULL) {
		uiDefBut(block, BUT, B_MAKEVERTCOL, "Make",		80,50,84,19, 0, 0, 0, 0, 0, "Enables vertex colour painting on active object");
	}
	else uiDefBut(block, BUT, B_DELVERTCOL, "Delete", 	80,50,84,19, 0, 0, 0, 0, 0, "Deletes vertex colours on active object");

	if(me->tface) val= 1.0; else val= 0.0;
	uiDefBut(block, LABEL, 0, "TexFace", 				10,30,70,20, 0, val, 0, 0, 0, "");
	if(me->tface==NULL) {
		uiDefBut(block, BUT, B_MAKE_TFACES, "Make",		80,30,84,19, 0, 0, 0, 0, 0, "Enables the active object's faces for UV coordinate mapping");
	}
	else uiDefBut(block, BUT, B_DEL_TFACES, "Delete", 	80,30,84,19, 0, 0, 0, 0, 0, "Deletes UV coordinates for active object's faces");

	if(me->msticky) val= 1.0; else val= 0.0;
	uiDefBut(block, LABEL, 0, "Sticky", 				10,10,70,20, 0, val, 0, 0, 0, "");
	if(me->msticky==NULL) {
		uiDefBut(block, BUT, B_MAKESTICKY, "Make",		80,10,84,19, 0, 0, 0, 0, 0, "Creates Sticky coordinates for the active object from the current camera view background picture");
	}
	else uiDefBut(block, BUT, B_DELSTICKY, "Delete", 	80,10,84,19, 0, 0, 0, 0, 0, "Deletes Sticky texture coordinates");

	uiBlockEndAlign(block);

	/* decimator */
	if(G.obedit==NULL) {
		int tottria= decimate_count_tria(ob);
		DispList *dl;

		// wacko, wait for new displist system (ton)
		if( (dl=ob->disp.first) && dl->mesh);
		else decim_faces= tottria;

		uiBlockBeginAlign(block);
		uiBlockSetCol(block, TH_BUT_SETTING1);
		uiDefButI(block, NUM,B_DECIM_FACES, "Decimator:",	175,180,230,19, &decim_faces, 4.0, tottria, 10, 10, "Defines the number of triangular faces to decimate the active Mesh object to");
		uiBlockSetCol(block, TH_AUTO);
		uiDefBut(block, BUT,B_DECIM_APPLY, "Apply",		175,160,110,19, 0, 0, 0, 0, 0, "Applies the decimation to the active Mesh object");
		uiDefBut(block, BUT,B_DECIM_CANCEL, "Cancel",	285,160,120,19, 0, 0, 0, 0, 0, "Restores the Mesh to its original number of faces");
		uiBlockEndAlign(block);
	}


	uiDefIDPoinBut(block, test_meshpoin_but, 0, "TexMesh: ",	175,124,230,19, &me->texcomesh, "Enter the name of a Meshblock");

	if(me->key) {
		uiBlockBeginAlign(block);
		uiDefButS(block, NUM, B_DIFF, "Slurph:",				175,95,95,19, &(me->key->slurph), -500.0, 500.0, 0, 0, "");
		uiDefButS(block, TOG, B_RELKEY, "Relative Keys",		175,75,95,19, &me->key->type, 0, 0, 0, 0, "");
	}

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT, B_SLOWERDRAW,"SlowerDraw",			175,30,95,19, 0, 0, 0, 0, 0, "Displays the active object with all possible edges shown");
	uiDefBut(block, BUT, B_FASTERDRAW,"FasterDraw",			175,10,95,19, 0, 0, 0, 0, 0, "Displays the active object faster by omitting some edges when drawing");

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT,B_DOCENTRE, "Centre",					275, 95, 130, 19, 0, 0, 0, 0, 0, "Shifts object data to be centered about object's origin");
	uiDefBut(block, BUT,B_DOCENTRENEW, "Centre New",			275, 75, 130, 19, 0, 0, 0, 0, 0, "Shifts object's origin to center of object data");
	uiDefBut(block, BUT,B_DOCENTRECURSOR, "Centre Cursor",		275, 55, 130, 19, 0, 0, 0, 0, 0, "Shifts object's origin to cursor location");

	uiBlockBeginAlign(block);
	uiDefButS(block, TOG|BIT|2, REDRAWVIEW3D, "Double Sided",	275,30,130,19, &me->flag, 0, 0, 0, 0, "Toggles selected faces as doublesided or single-sided");
	uiDefButS(block, TOG|BIT|1, REDRAWVIEW3D, "No V.Normal Flip",275,10,130,19, &me->flag, 0, 0, 0, 0, "Disables flipping of vertexnormals during render");
	uiBlockEndAlign(block);

}



/* *************************** FONT ******************************** */

static short give_vfontnr(VFont *vfont)
{
	VFont *vf;
	short nr= 1;

	vf= G.main->vfont.first;
	while(vf) {
		if(vf==vfont) return nr;
		nr++;
		vf= vf->id.next;
	}
	return -1;
}

static VFont *give_vfontpointer(int nr)	/* nr= button */
{
	VFont *vf;
	short tel= 1;

	vf= G.main->vfont.first;
	while(vf) {
		if(tel==nr) return vf;
		tel++;
		vf= vf->id.next;
	}
	return G.main->vfont.first;
}

static VFont *exist_vfont(char *str)
{
	VFont *vf;

	vf= G.main->vfont.first;
	while(vf) {
		if(strcmp(vf->name, str)==0) return vf;
		vf= vf->id.next;
	}
	return 0;
}

static char *give_vfontbutstr(void)
{
	VFont *vf;
	int len= 0;
	char *str, di[FILE_MAXDIR], fi[FILE_MAXFILE];

	vf= G.main->vfont.first;
	while(vf) {
		strcpy(di, vf->name);
		BLI_splitdirstring(di, fi);
		len+= strlen(fi)+4;
		vf= vf->id.next;
	}

	str= MEM_callocN(len+21, "vfontbutstr");
	strcpy(str, "FONTS %t");
	vf= G.main->vfont.first;
	while(vf) {

		if(vf->id.us==0) strcat(str, "|0 ");
		else strcat(str, "|   ");

		strcpy(di, vf->name);
		BLI_splitdirstring(di, fi);

		strcat(str, fi);
		vf= vf->id.next;
	}
	return str;
}

static void load_buts_vfont(char *name)
{
	VFont *vf;
	Curve *cu;

	if(OBACT && OBACT->type==OB_FONT) cu= OBACT->data;
	else return;

	vf= exist_vfont(name);
	if(vf==0) {
		vf= load_vfont(name);
		if(vf==0) return;
	}
	else id_us_plus((ID *)vf);

	if(cu->vfont) cu->vfont->id.us--;
	cu->vfont= vf;

	text_to_curve(OBACT, 0);
	makeDispList(OBACT);
	BIF_undo_push("Load vector font");
	allqueue(REDRAWVIEW3D, 0);
	allqueue(REDRAWBUTSEDIT, 0);
}

void do_fontbuts(unsigned short event)
{
	Curve *cu;
	VFont *vf;
	Object *ob;
	ScrArea *sa;
	char str[80];

	ob= OBACT;

	switch(event) {
	case B_MAKEFONT:
		text_to_curve(ob, 0);
		makeDispList(ob);
		allqueue(REDRAWVIEW3D, 0);
		break;
	case B_TOUPPER:
		to_upper();
		break;
	case B_LOADFONT:
		vf= give_vfontpointer(G.buts->texnr);
		if(vf && vf->id.prev!=vf->id.next) strcpy(str, vf->name);
		else strcpy(str, U.fontdir);

		sa= closest_bigger_area();
		areawinset(sa->win);

		activate_fileselect(FILE_SPECIAL, "SELECT FONT", str, load_buts_vfont);

		break;
	case B_PACKFONT:
		if (ob) {
			cu= ob->data;
			if(cu && cu->vfont) {
				if (cu->vfont->packedfile) {
					if (G.fileflags & G_AUTOPACK) {
						if (okee("Disable AutoPack ?")) {
							G.fileflags &= ~G_AUTOPACK;
						}
					}

					if ((G.fileflags & G_AUTOPACK) == 0) {
						if (unpackVFont(cu->vfont, PF_ASK) == RET_OK) {
							text_to_curve(ob, 0);
							makeDispList(ob);
							allqueue(REDRAWVIEW3D, 0);
						}
					}
				} else {
					cu->vfont->packedfile = newPackedFile(cu->vfont->name);
				}
			}
		}
		allqueue(REDRAWHEADERS, 0);
		allqueue(REDRAWBUTSEDIT, 0);
		break;

	case B_SETFONT:
		if(ob) {
			cu= ob->data;

			vf= give_vfontpointer(G.buts->texnr);
			if(vf) {
				id_us_plus((ID *)vf);
				cu->vfont->id.us--;
				cu->vfont= vf;
				text_to_curve(ob, 0);
				makeDispList(ob);
				BIF_undo_push("Set vector font");
				allqueue(REDRAWVIEW3D, 0);
				allqueue(REDRAWBUTSEDIT, 0);
			}
		}
		break;
	case B_TEXTONCURVE:
		if(ob) {
			cu= ob->data;
			if(cu->textoncurve && cu->textoncurve->type!=OB_CURVE) {
				error("Only Curve Objects");
				cu->textoncurve= 0;
				allqueue(REDRAWBUTSEDIT, 0);
			}
			text_to_curve(ob, 0);
			makeDispList(ob);
		}
	}
}

static void editing_panel_font_type(Object *ob, Curve *cu)
{
	uiBlock *block;
	char *strp;
	static int packdummy = 0;
	VFontData *vfd;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_font_type", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Font", "Editing", 640, 0, 318, 204)==0) return;

	G.buts->texnr= give_vfontnr(cu->vfont);
	strp= give_vfontbutstr();
	vfd= cu->vfont->data;

	uiDefBut(block, BUT,B_LOADFONT, "Load",	480,188,68,20, 0, 0, 0, 0, 0, "Load a new font");
	uiDefButS(block, MENU, B_SETFONT, strp, 550,188,220,20, &G.buts->texnr, 0, 0, 0, 0, "Change font for object");

	if (cu->vfont->packedfile) {
		packdummy = 1;
	} else {
		packdummy = 0;
	}
	uiDefIconButI(block, TOG|BIT|0, B_PACKFONT, ICON_PACKAGE,	772,188,20,20, &packdummy, 0, 0, 0, 0, "Pack/Unpack this font");
	uiDefBut(block, LABEL, 0, vfd->name,  480, 165,314,20, 0, 0, 0, 0, 0, "Postscript name of the font");

	MEM_freeN(strp);

	uiBlockBeginAlign(block);
	uiDefButS(block, ROW,B_MAKEFONT, "Left",		480,135,53,20, &cu->spacemode, 0.0,0.0, 0, 0, "Left align the text from the object centre");
	uiDefButS(block, ROW,B_MAKEFONT, "Middle",		535,135,55,20, &cu->spacemode, 0.0,1.0, 0, 0, "Middle align the text from the object centre");
	uiDefButS(block, ROW,B_MAKEFONT, "Right",		592,135,53,20, &cu->spacemode, 0.0,2.0, 0, 0, "Right align the text from the object centre");
	uiDefButS(block, ROW,B_MAKEFONT, "Flush",		647,135,53,20, &cu->spacemode, 0.0,3.0, 0, 0, "Fill characters to maximum linewidth. (Multiple lines required)");
	uiDefBut(block, BUT, B_TOUPPER, "ToUpper",		715,135,78,20, 0, 0, 0, 0, 0, "Toggle between upper and lower case in editmode");
	uiBlockEndAlign(block);

	uiDefIDPoinBut(block, test_obpoin_but, B_TEXTONCURVE, "TextOnCurve:",	480,105,220,19, &cu->textoncurve, "Apply a deforming curve to the text");
	uiDefBut(block, TEX,REDRAWVIEW3D, "Ob Family:",	480,84,220,19, cu->family, 0.0, 20.0, 0, 0, "Blender uses font from selfmade objects");

	uiBlockBeginAlign(block);
	uiDefButF(block, NUM,B_MAKEFONT, "Size:",		480,56,155,20, &cu->fsize, 0.1,10.0, 10, 0, "Size of the text");
	uiDefButF(block, NUM,B_MAKEFONT, "Linedist:",	640,56,155,20, &cu->linedist, 0.0,10.0, 10, 0, "Distance between text lines");
	uiDefButF(block, NUM,B_MAKEFONT, "Spacing:",	480,34,155,20, &cu->spacing, 0.0,10.0, 10, 0, "Spacing of individual characters");
	uiDefButF(block, NUM,B_MAKEFONT, "X offset:",	640,34,155,20, &cu->xof, -50.0,50.0, 10, 0, "Horizontal position from object centre");
	uiDefButF(block, NUM,B_MAKEFONT, "Shear:",		480,12,155,20, &cu->shear, -1.0,1.0, 10, 0, "Italic angle of the characters");
	uiDefButF(block, NUM,B_MAKEFONT, "Y offset:",	640,12,155,20, &cu->yof, -50.0,50.0, 10, 0, "Vertical position from object centre");
	uiBlockEndAlign(block);
}


/* *************************** CURVE ******************************** */


void do_curvebuts(unsigned short event)
{
	extern Nurb *lastnu;
	extern ListBase editNurb;  /* from editcurve */
	Base *base;
	Object *ob;
	Curve *cu;
	Nurb *nu;

	ob= OBACT;
	if(ob==0) return;

	switch(event) {

	case B_CONVERTPOLY:
	case B_CONVERTBEZ:
	case B_CONVERTBSPL:
	case B_CONVERTCARD:
	case B_CONVERTNURB:
		if(G.obedit) {
			setsplinetype(event-B_CONVERTPOLY);
			makeDispList(G.obedit);
			allqueue(REDRAWVIEW3D, 0);
		}
		break;
	case B_UNIFU:
	case B_ENDPU:
	case B_BEZU:
	case B_UNIFV:
	case B_ENDPV:
	case B_BEZV:
		if(G.obedit) {
			nu= editNurb.first;
			while(nu) {
				if(isNurbsel(nu)) {
					if((nu->type & 7)==CU_NURBS) {
						if(event<B_UNIFV) {
							nu->flagu &= 1;
							nu->flagu += ((event-B_UNIFU)<<1);
							makeknots(nu, 1, nu->flagu>>1);
						}
						else if(nu->pntsv>1) {
							nu->flagv &= 1;
							nu->flagv += ((event-B_UNIFV)<<1);
							makeknots(nu, 2, nu->flagv>>1);
						}
					}
				}
				nu= nu->next;
			}
			makeDispList(G.obedit);
			allqueue(REDRAWVIEW3D, 0);
		}
		break;
	case B_SETWEIGHT:
		if(G.obedit) {
			weightflagNurb(1, editbutweight, 0);
			makeDispList(G.obedit);
			allqueue(REDRAWVIEW3D, 0);
		}
		break;
	case B_SETW1:
		editbutweight= 1.0;
		scrarea_queue_winredraw(curarea);
		break;
	case B_SETW2:
		editbutweight= sqrt(2.0)/4.0;
		scrarea_queue_winredraw(curarea);
		break;
	case B_SETW3:
		editbutweight= 0.25;
		scrarea_queue_winredraw(curarea);
		break;
	case B_SETW4:
		editbutweight= sqrt(0.5);
		scrarea_queue_winredraw(curarea);
		break;
	case B_SETORDER:
		if(G.obedit) {
			nu= lastnu;
			if(nu && (nu->type & 7)==CU_NURBS ) {
				if(nu->orderu>nu->pntsu) {
					nu->orderu= nu->pntsu;
					scrarea_queue_winredraw(curarea);
				}
				makeknots(nu, 1, nu->flagu>>1);
				if(nu->orderv>nu->pntsv) {
					nu->orderv= nu->pntsv;
					scrarea_queue_winredraw(curarea);
				}
				makeknots(nu, 2, nu->flagv>>1);
			}
			makeDispList(G.obedit);
			allqueue(REDRAWVIEW3D, 0);
		}
		break;
	case B_MAKEDISP:
		if(ob->type==OB_FONT) text_to_curve(ob, 0);
		makeDispList(ob);
		if(ob!=G.obedit) { // subsurf with linked dupli will crash
			/* we need signal to send to other users of same data to recalc... */
			base= FIRSTBASE;
			while(base) {
				if(base->lay & G.vd->lay) {
					if(base->object->data==ob->data && base->object!=ob)
						makeDispList(base->object);
				}
				base= base->next;
			}
		}
		allqueue(REDRAWVIEW3D, 0);
		allqueue(REDRAWINFO, 1); 	/* 1, because header->win==0! */
		break;

	case B_SUBDIVCURVE:
		subdivideNurb();
		break;
	case B_SPINNURB:
		/* bad bad bad!!! use brackets!!! In case you wondered:
		  {==,!=} goes before & goes before || */
		if( (G.obedit==0) ||
		    (G.obedit->type!=OB_SURF) ||
			((G.obedit->lay & G.vd->lay) == 0) ) return;
		spinNurb(0, 0);
		countall();
		makeDispList(G.obedit);
		allqueue(REDRAWVIEW3D, 0);
		break;
	case B_CU3D:	    /* allow 3D curve */
		if(G.obedit) {
			cu= G.obedit->data;
			nu= editNurb.first;
			while(nu) {
				nu->type &= ~CU_2D;
				if((cu->flag & CU_3D)==0) nu->type |= CU_2D;
				test2DNurb(nu);
				nu= nu->next;
			}
		}
		if(ob->type==OB_CURVE) {
			cu= ob->data;
			nu= cu->nurb.first;
			while(nu) {
				nu->type &= ~CU_2D;
				if((cu->flag & CU_3D)==0) nu->type |= CU_2D;
				test2DNurb(nu);
				nu= nu->next;
			}
		}
		makeDispList(G.obedit);
		allqueue(REDRAWVIEW3D, 0);
		break;
	case B_SETRESOLU:
		if(ob->type==OB_CURVE) {
			cu= ob->data;
			if(ob==G.obedit) nu= editNurb.first;
			else nu= cu->nurb.first;

			while(nu) {
				nu->resolu= cu->resolu;
				nu= nu->next;
			}
		}
		else if(ob->type==OB_FONT) text_to_curve(ob, 0);

		makeDispList(ob);
		allqueue(REDRAWVIEW3D, 0);

		break;
	}
}

static void editing_panel_curve_tools(Object *ob, Curve *cu)
{
	Nurb *nu;
	extern ListBase editNurb;  /* from editcurve */
	extern Nurb *lastnu;
	uiBlock *block;
	short *sp;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_curve_tools", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Curve Tools", "Editing", 640, 0, 318, 204)==0) return;

	uiDefBut(block, LABEL, 0, "Make Knots",562,173,102, 18, 0, 0, 0, 0, 0, "");

	if(ob->type==OB_CURVE) {
		uiDefBut(block, LABEL, 0, "Convert",	463,173,72, 18, 0, 0, 0, 0, 0, "");
		uiBlockBeginAlign(block);
		uiDefBut(block, BUT,B_CONVERTPOLY,"Poly",		467,152,72, 18, 0, 0, 0, 0, 0, "Converts selected into regular Polygon vertices");
		uiDefBut(block, BUT,B_CONVERTBEZ,"Bezier",		467,132,72, 18, 0, 0, 0, 0, 0, "Converts selected to Bezier triples");
		uiDefBut(block, BUT,B_CONVERTNURB,"Nurb",		467,112,72, 18, 0, 0, 0, 0, 0, "Converts selected to Nurbs Points");
	}
	uiBlockBeginAlign(block);
	uiDefBut(block, BUT,B_UNIFU,"Uniform U",	565,152,102, 18, 0, 0, 0, 0, 0, "Nurbs only; interpolated result doesn't go to end points in U");
	uiDefBut(block, BUT,B_UNIFV,"V",			670,152,50, 18, 0, 0, 0, 0, 0, "Nurbs only; interpolated result doesn't go to end points in V");
	uiDefBut(block, BUT,B_ENDPU,"Endpoint U",	565,132,102, 18, 0, 0, 0, 0, 0, "Nurbs only; interpolated result is forced to end points in U");
	uiDefBut(block, BUT,B_ENDPV,"V",			670,132,50, 18, 0, 0, 0, 0, 0, "Nurbs only; interpolated result is forced to end points in V");
	uiDefBut(block, BUT,B_BEZU,"Bezier U",		565,112,102, 18, 0, 0, 0, 0, 0, "Nurbs only; make knots array mimic a Bezier in U");
	uiDefBut(block, BUT,B_BEZV,"V",				670,112,50, 18, 0, 0, 0, 0, 0, "Nurbs only; make knots array mimic a Bezier in V");
	uiBlockEndAlign(block);

	uiDefBut(block, BUT,B_SETWEIGHT,"Set Weight",	465,11,95,49, 0, 0, 0, 0, 0, "Nurbs only; set weight for select points");

	uiBlockBeginAlign(block);
	uiDefButF(block, NUM,0,"Weight:",		565,36,102,22, &editbutweight, 0.01, 100.0, 10, 0, "The weight you can assign");
	uiDefBut(block, BUT,B_SETW1,"1.0",		670,36,50,22, 0, 0, 0, 0, 0, "");
	uiDefBut(block, BUT,B_SETW2,"sqrt(2)/4",565,11,55,20, 0, 0, 0, 0, 0, "");
	uiDefBut(block, BUT,B_SETW3,"0.25",		620,11,45,20, 0, 0, 0, 0, 0, "");
	uiDefBut(block, BUT,B_SETW4,"sqrt(0.5)",665,11,55,20, 0, 0, 0, 0, 0, "");
	uiBlockEndAlign(block);

	if(ob==G.obedit) {
		nu= lastnu;
		if(nu==NULL) nu= editNurb.first;
		if(nu) {
			uiBlockBeginAlign(block);
			sp= &(nu->orderu);
			uiDefButS(block, NUM, B_SETORDER, "Order U:", 565,90,102, 19, sp, 2.0, 6.0, 0, 0, "Nurbs only; the amount of control points involved");
			sp= &(nu->orderv);
			uiDefButS(block, NUM, B_SETORDER, "V:",	 	670,90,50, 19, sp, 2.0, 6.0, 0, 0, "Nurbs only; the amount of control points involved");
			sp= &(nu->resolu);
			uiDefButS(block, NUM, B_MAKEDISP, "Resol U:", 565,70,102, 19, sp, 1.0, 128.0, 0, 0, "The amount of new points interpolated per control vertex pair");
			sp= &(nu->resolv);
			uiDefButS(block, NUM, B_MAKEDISP, "V:", 	670,70,50, 19, sp, 1.0, 128.0, 0, 0, "The amount of new points interpolated per control vertex pair");
		}
	}


}

static void editing_panel_curve_tools1(Object *ob, Curve *cu)
{
	uiBlock *block;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_curve_tools1", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Curve Tools1", "Editing", 960, 0, 318, 204)==0) return;

	uiDefBut(block, BUT, B_SUBDIVCURVE, "Subdivide", 400,180,150,20, 0, 0, 0, 0, 0, "Subdivide selected");
	if(ob->type==OB_SURF) {
		uiDefBut(block, BUT, B_SPINNURB, "Spin",	 400,160,150,20, 0, 0, 0, 0, 0, "Spin selected 360 degrees");
	}
	uiBlockBeginAlign(block);
	uiDefBut(block, BUT,B_HIDE,		"Hide",			400,120,150,18, 0, 0, 0, 0, 0, "Hides selected faces");
	uiDefBut(block, BUT,B_REVEAL,	"Reveal",		400,100,150,18, 0, 0, 0, 0, 0, "Reveals selected faces");
	uiDefBut(block, BUT,B_SELSWAP,	"Select Swap",	400,80,150,18, 0, 0, 0, 0, 0, "Selects unselected faces, and deselects selected faces");
	uiBlockEndAlign(block);

	uiDefButF(block, NUM,	REDRAWVIEW3D, "NSize:",	400, 40, 150, 19, &editbutsize, 0.001, 1.0, 10, 0, "Normal size for drawing");
}

/* for curve, surf and font! */
static void editing_panel_curve_type(Object *ob, Curve *cu)
{
	uiBlock *block;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_curve_type", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Curve and Surface", "Editing", 320, 0, 318, 204)==0) return;

	uiDefButS(block, TOG|BIT|5, 0, "UV Orco",					600,160,150,19, &cu->flag, 0, 0, 0, 0, "Forces to use UV coordinates for texture mapping 'orco'");
	if(ob->type==OB_SURF)
		uiDefButS(block, TOG|BIT|6, REDRAWVIEW3D, "No Puno Flip",	600,140,150,19, &cu->flag, 0, 0, 0, 0, "Don't flip vertex normals while render");

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT,B_DOCENTRE, "Centre",					600, 115, 150, 19, 0, 0, 0, 0, 0, "Shifts object data to be centered about object's origin");
	uiDefBut(block, BUT,B_DOCENTRENEW, "Centre New",			600, 95, 150, 19, 0, 0, 0, 0, 0, "Shifts object's origin to center of object data");
	uiDefBut(block, BUT,B_DOCENTRECURSOR, "Centre Cursor",		600, 75, 150, 19, 0, 0, 0, 0, 0, "Shifts object's origin to cursor location");
	uiBlockEndAlign(block);

	if(ob->type==OB_SURF) {
		if(cu->key) {
			/* uiDefButS(block, NUM, B_DIFF, "Slurph:",			600,25,140,19, &(cu->key->slurph), -500.0, 500.0,0,0); ,""*/
			uiDefButS(block, TOG, B_RELKEY, "Relative Keys",	600,45,140,19, &cu->key->type, 0, 0, 0, 0, "");
		}
	}

	if(ob->type!=OB_SURF) {
	
		if(ob->type==OB_CURVE) {
			extern float prlen;		// buttons_object.c, should be moved....
			char str[32];
			uiBlockBeginAlign(block);
			uiDefButS(block, NUM, B_RECALCPATH, "PathLen:",			600,50,150,19, &cu->pathlen, 1.0, 9000.0, 0, 0, "If no speed Ipo was set, the amount of frames of the path");
			uiDefButS(block, TOG|BIT|3, B_RECALCPATH, "CurvePath",	600,30,75,19 , &cu->flag, 0, 0, 0, 0, "Enables curve to become translation path");
			uiDefButS(block, TOG|BIT|4, REDRAWVIEW3D, "CurveFollow",675,30,75,19, &cu->flag, 0, 0, 0, 0, "Makes curve path children to rotate along path");
			uiDefButS(block, TOG|BIT|7, B_CURVECHECK, "CurveStretch", 600,10,150,19, &cu->flag, 0, 0, 0, 0, "Option for curve-deform: makes deformed child to stretch along entire path");

			uiBlockEndAlign(block);
			sprintf(str, "%.4f", prlen);
			uiDefBut(block, BUT, B_PRINTLEN,		"PrintLen",	600,-10,75,19, 0, 0, 0, 0, 0, "");
			uiDefBut(block, LABEL, 0, str,						675,-10,75,19, 0, 1.0, 0, 0, 0, "");
		}

		uiBlockBeginAlign(block);
		uiDefButS(block, NUM, B_MAKEDISP, "DefResolU:",	760,160,120,19, &cu->resolu, 1.0, 128.0, 0, 0, "Default resolution");
		uiDefBut(block, BUT, B_SETRESOLU, "Set",		880,160,30,19, 0, 0, 0, 0, 0, "Set resolution for interpolation");

		uiBlockBeginAlign(block);
		uiDefButF(block, NUM, B_MAKEDISP, "Width:",		760,90,150,19, &cu->width, 0.0, 2.0, 1, 0, "Make interpolated result thinner or fatter");
		uiDefButF(block, NUM, B_MAKEDISP, "Ext1:",		760,70,150,19, &cu->ext1, 0.0, 5.0, 10, 0, "Extrude depth");
		uiDefButF(block, NUM, B_MAKEDISP, "Ext2:",		760,50,150,19, &cu->ext2, 0.0, 2.0, 1, 0, "Extrude beveling depth");
		uiDefButS(block, NUM, B_MAKEDISP, "BevResol:",	760,30,150,19, &cu->bevresol, 0.0, 10.0, 0, 0, "Amount of bevels");
		uiDefIDPoinBut(block, test_obcurpoin_but, B_MAKEDISP, "BevOb:",		760,10,150,19, &cu->bevobj, "Curve object name that defines the bevel shape");
		uiDefIDPoinBut(block, test_obcurpoin_but, B_MAKEDISP, "TaperOb:",		760,-10,150,19, &cu->taperobj, "Curve object name that defines the taper (width)");

		uiBlockBeginAlign(block);
		uiBlockSetCol(block, TH_BUT_SETTING1);
		uiDefButS(block, TOG|BIT|2, B_MAKEDISP, "Back",	760,130,50,19, &cu->flag, 0, 0, 0, 0, "Draw filled back for curves");
		uiDefButS(block, TOG|BIT|1, B_MAKEDISP, "Front",810,130,50,19, &cu->flag, 0, 0, 0, 0, "Draw filled front for curves");
		uiDefButS(block, TOG|BIT|0, B_CU3D, "3D",		860,130,50,19, &cu->flag, 0, 0, 0, 0, "Allow Curve Object to be 3d, it doesn't fill then");


	}

}


/* *************************** CAMERA ******************************** */


static void editing_panel_camera_type(Object *ob, Camera *cam)
{
	uiBlock *block;
	float grid=0.0;

	if(G.vd) grid= G.vd->grid;
	if(grid<1.0) grid= 1.0;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_camera_type", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Camera", "Editing", 320, 0, 318, 204)==0) return;

	uiDefButF(block, NUM,REDRAWVIEW3D, "Lens:", 470,178,160,20, &cam->lens, 1.0, 250.0, 100, 0, "Specify the lens of the camera");

	uiBlockBeginAlign(block);
	uiDefButF(block, NUM,REDRAWVIEW3D, "ClipSta:", 470,147,160,20, &cam->clipsta, 0.001*grid, 100.0*grid, 10, 0, "Specify the startvalue of the the field of view");
	uiDefButF(block, NUM,REDRAWVIEW3D, "ClipEnd:", 470,125,160,20, &cam->clipend, 1.0, 5000.0*grid, 100, 0, "Specify the endvalue of the the field of view");
	uiBlockEndAlign(block);

	uiDefButF(block, NUM,REDRAWVIEW3D, "DrawSize:", 470,90,160,20, &cam->drawsize, 0.1*grid, 10.0, 10, 0, "Specify the drawsize of the camera");

	uiDefButS(block, TOG, REDRAWVIEW3D, "Ortho", 470,49,61,40, &cam->type, 0, 0, 0, 0, "Render orthogonally");
	uiBlockBeginAlign(block);
	uiDefButS(block, TOG|BIT|0,REDRAWVIEW3D, "ShowLimits", 533,69,97,20, &cam->flag, 0, 0, 0, 0, "Draw the field of view");
	uiDefButS(block, TOG|BIT|1,REDRAWVIEW3D, "Show Mist", 533,49,97,20, &cam->flag, 0, 0, 0, 0, "Draw a line that indicates the mist area");
	uiBlockEndAlign(block);
}

/* yafray: extra camera panel to set Depth-of-Field parameters */
static void editing_panel_camera_yafraydof(Object *ob, Camera *cam)
{
	uiBlock *block;
	char *mst1, *mst2;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_camera_yafraydof", UI_EMBOSS, UI_HELV, curarea->win);
	uiNewPanelTabbed("Camera", "Editing");
	if(uiNewPanel(curarea, block, "Yafray DoF", "Editing", 320, 0, 318, 204)==0) return;

	uiDefButF(block, NUM, REDRAWVIEW3D, "DoFDist:", 10, 147, 180, 20, &cam->YF_dofdist, 0.0, 5000.0, 50, 0, "Sets distance to point of focus (use camera 'ShowLimits' to make visible in 3Dview)");
	uiDefButF(block, NUM, B_DIFF, "Aperture:", 10, 125, 180, 20, &cam->YF_aperture, 0.0, 2.0, 1, 0, "Sets lens aperture, the larger, the more blur (use small values, 0 is no DoF)");

	uiDefButS(block, TOG|BIT|2, B_DIFF, "Random sampling", 10, 90, 180, 20, &cam->flag, 0, 0, 0, 0, "Use noisy random Lens sampling instead of QMC");

	uiDefBut(block, LABEL, 0, "Bokeh", 10, 60, 180, 19, 0, 0.0, 0.0, 0, 0, "");
	mst1 = "Bokeh Type%t|Disk1%x0|Disk2%x1|Triangle%x2|Square%x3|Pentagon%x4|Hexagon%x5|Ring%x6";
	uiDefButS(block, MENU, B_REDR, mst1, 10, 40, 89, 20, &cam->YF_bkhtype, 0.0, 0.0, 0, 0, "Sets Bokeh type");
	
	if ((cam->YF_bkhtype!=0) && (cam->YF_bkhtype!=6)) {
		mst2 = "Bokeh Bias%t|Uniform%x0|Center%x1|Edge%x2";
		uiDefButS(block, MENU, B_REDR, mst2, 100, 40, 90, 20, &cam->YF_bkhbias, 0.0, 0.0, 0, 0, "Sets Bokeh bias");
		if (cam->YF_bkhtype>1)
			uiDefButF(block, NUM, B_DIFF, "Rotation:", 10, 15, 180, 20, &cam->YF_bkhrot, 0.0, 360.0, 100, 0, "Shape rotation amount in degrees");
	}

}


/* *************************** MBALL ******************************** */

void do_mballbuts(unsigned short event)
{
	switch(event) {
	case B_RECALCMBALL:
		makeDispList(OBACT);
		allqueue(REDRAWVIEW3D, 0);
		break;
	}
}

static void editing_panel_mball_type(Object *ob, MetaBall *mb)
{
	uiBlock *block;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_mball_type", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "MetaBall", "Editing", 320, 0, 318, 204)==0) return;

	ob= find_basis_mball(ob);
	mb= ob->data;

	uiBlockBeginAlign(block);
	uiDefButF(block, NUMSLI, B_RECALCMBALL, "Wiresize:",	470,178,250,19, &mb->wiresize, 0.05, 1.0, 0, 0, "Polygonization resolution in 3d window");
	uiDefButF(block, NUMSLI, 0, "Rendersize:",			470,158,250,19, &mb->rendersize, 0.05, 1.0, 0, 0, "Polygonization resolution in rendering");
	uiDefButF(block, NUMSLI, B_RECALCMBALL, "Threshold:", 470,138,250,19, &mb->thresh, 0.0001, 5.0, 0, 0, "Defines influence of meta elements");

	uiBlockBeginAlign(block);
	uiBlockSetCol(block, TH_BUT_SETTING1);
	uiDefBut(block, LABEL, 0, "Update:",		471,108,120,19, 0, 0, 0, 0, 0, "");
	uiDefButS(block, ROW, B_DIFF, "Always",	471, 85, 120, 19, &mb->flag, 0.0, 0.0, 0, 0, "While editing, always updates");
	uiDefButS(block, ROW, B_DIFF, "Half Res",	471, 65, 120, 19, &mb->flag, 0.0, 1.0, 0, 0, "While editing, updates in half resolution");
	uiDefButS(block, ROW, B_DIFF, "Fast",		471, 45, 120, 19, &mb->flag, 0.0, 2.0, 0, 0, "While editing, updates without polygonization");
	uiDefButS(block, ROW, B_DIFF, "Never",		471, 25, 120, 19, &mb->flag, 0.0, 3.0, 0, 0, "While editing, doesn't update");

}

static void editing_panel_mball_tools(Object *ob, MetaBall *mb)
{
	extern MetaElem *lastelem;
	uiBlock *block;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_mball_tools", UI_EMBOSS, UI_HELV, curarea->win);
	if( uiNewPanel(curarea, block, "MetaBall tools", "Editing", 640, 0, 318, 204)==0) return;

	if(ob==G.obedit && lastelem) {
		uiBlockBeginAlign(block);
		uiDefButF(block, NUMSLI, B_RECALCMBALL, "Stiffness:", 750,178,250,19, &lastelem->s, 0.0, 10.0, 0, 0, "Stiffness for active meta");
		if(lastelem->type!=MB_BALL)
		uiDefButF(block, NUMSLI, B_RECALCMBALL, "dx:",		750,158,250,19, &lastelem->expx, 0.0, 20.0, 0, 0, "X size for active meta");
		if((lastelem->type!=MB_BALL)&&(lastelem->type!=MB_TUBE))
		uiDefButF(block, NUMSLI, B_RECALCMBALL, "dy:",		750,138,250,19, &lastelem->expy, 0.0, 20.0, 0, 0, "Y size for active meta");

		if((lastelem->type==MB_CUBE)||(lastelem->type==MB_ELIPSOID))
		uiDefButF(block, NUMSLI, B_RECALCMBALL, "dz:",		750,118,250,19, &lastelem->expz, 0.0, 20.0, 0, 0, "Z size for active meta");
		uiBlockEndAlign(block);

		uiDefButS(block, ROW, B_RECALCMBALL, "Ball",			753,83,60,19, &lastelem->type, 1.0, 0.0, 0, 0, "Draw active meta as Ball");
		uiBlockBeginAlign(block);
		uiDefButS(block, ROW, B_RECALCMBALL, "Tube",			753,62,60,19, &lastelem->type, 1.0, 4.0, 0, 0, "Draw active meta as Ball");
		uiDefButS(block, ROW, B_RECALCMBALL, "Plane",			814,62,60,19, &lastelem->type, 1.0, 5.0, 0, 0, "Draw active meta as Plane");
		uiDefButS(block, ROW, B_RECALCMBALL, "Elipsoid",		876,62,60,19, &lastelem->type, 1.0, 6.0, 0, 0, "Draw active meta as Ellipsoid");
		uiDefButS(block, ROW, B_RECALCMBALL, "Cube",			938,62,60,19, &lastelem->type, 1.0, 7.0, 0, 0, "Draw active meta as Cube");
		uiBlockEndAlign(block);

		uiDefButS(block, TOG|BIT|1, B_RECALCMBALL, "Negative",753,16,60,19, &lastelem->flag, 0, 0, 0, 0, "Make active meta creating holes");

	}

}


/* *************************** LATTICE ******************************** */

void do_latticebuts(unsigned short event)
{
	Object *ob;
	Lattice *lt;

	ob= OBACT;
	if(ob->type!=OB_LATTICE) return;

	switch(event) {
	case B_RESIZELAT:
		if(ob) {
			if(ob==G.obedit) resizelattice(editLatt);
			else resizelattice(ob->data);
		}
		allqueue(REDRAWVIEW3D, 0);
		break;
	case B_DRAWLAT:
		if(ob==G.obedit) calc_lattverts_ext();
		allqueue(REDRAWVIEW3D, 0);
		break;
	case B_LATTCHANGED:

		lt= ob->data;
		if(lt->flag & LT_OUTSIDE) outside_lattice(lt);

		make_displists_by_parent(ob);

		allqueue(REDRAWVIEW3D, 0);

		break;
	}
}

static void editing_panel_lattice_type(Object *ob, Lattice *lt)
{
	uiBlock *block;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_lattice_type", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Latice", "Editing", 320, 0, 318, 204)==0) return;


	uiSetButLock(lt->key!=0, "Not with VertexKeys");
	uiSetButLock(ob==G.obedit, "Unable to perform function in EditMode");

	uiBlockBeginAlign(block);

	uiDefButS(block, NUM, B_RESIZELAT,	"U:",				469, 178,100,19, &lt->pntsu, 1.0, 64.0, 0, 0, "Points in U direction");
	uiDefButC(block, ROW, B_LATTCHANGED,		"Lin",		572, 178, 40, 19, &lt->typeu, 1.0, (float)KEY_LINEAR, 0, 0, "Set Linear interpolation");
	uiDefButC(block, ROW, B_LATTCHANGED,		"Card",		613, 178, 40, 19, &lt->typeu, 1.0, (float)KEY_CARDINAL, 0, 0, "Set Cardinal interpolation");
	uiDefButC(block, ROW, B_LATTCHANGED,		"B",		652, 178, 40, 19, &lt->typeu, 1.0, (float)KEY_BSPLINE, 0, 0, "Set B-spline interpolation");

	uiDefButS(block, NUM, B_RESIZELAT,	"V:",				469, 156,100,19, &lt->pntsv, 1.0, 64.0, 0, 0, "Points in V direction");
	uiDefButC(block, ROW, B_LATTCHANGED,		"Lin",		572, 156, 40, 19, &lt->typev, 2.0, (float)KEY_LINEAR, 0, 0, "Set Linear interpolation");
	uiDefButC(block, ROW, B_LATTCHANGED,		"Card",		613, 156, 40, 19, &lt->typev, 2.0, (float)KEY_CARDINAL, 0, 0, "Set Cardinal interpolation");
	uiDefButC(block, ROW, B_LATTCHANGED,		"B",		652, 156, 40, 19, &lt->typev, 2.0, (float)KEY_BSPLINE, 0, 0, "Set B-spline interpolation");

	uiDefButS(block, NUM, B_RESIZELAT,	"W:",				469, 134,100,19, &lt->pntsw, 1.0, 64.0, 0, 0, "Points in W direction");
	uiDefButC(block, ROW, B_LATTCHANGED,		"Lin",		572, 134, 40, 19, &lt->typew, 3.0, (float)KEY_LINEAR, 0, 0, "Set Linear interpolation");
	uiDefButC(block, ROW, B_LATTCHANGED,		"Card",		613, 134, 40, 19, &lt->typew, 3.0, (float)KEY_CARDINAL, 0, 0, "Set Cardinal interpolation");
	uiDefButC(block, ROW, B_LATTCHANGED,		"B",		652, 134, 40, 19, &lt->typew, 3.0, (float)KEY_BSPLINE, 0, 0, "Set B-spline interpolation");

	uiBlockEndAlign(block);

	uiDefBut(block, BUT, B_RESIZELAT,	"Make Regular",		469,98,102,31, 0, 0, 0, 0, 0, "Make Lattice regular");

	uiClearButLock();
	uiDefButS(block, TOG|BIT|1, B_LATTCHANGED, "Outside",	571,98,122,31, &lt->flag, 0, 0, 0, 0, "Only draw, and take into account, the outer vertices");

	if(lt->key) {
		uiDefButS(block, NUM, B_DIFF, "Slurph:",			469,60,120,19, &(lt->key->slurph), -500.0, 500.0, 0, 0, "Set time value to denote 'slurph' (sequential delay) vertices with key framing");
		uiDefButS(block, TOG, B_RELKEY, "Relative Keys",	469,40,120,19, &lt->key->type, 0, 0, 0, 0, "Use relative keys (instead of absolute)");
	}

}

/* *************************** ARMATURE ******************************** */



static int editbone_to_parnr (EditBone *bone)
{
	EditBone *ebone;
	int	index;

	for (ebone=G.edbo.first, index=0; ebone; ebone=ebone->next, index++){
		if (ebone==bone)
			return index;
	}

	return -1;
}

static void parnr_to_editbone(EditBone *bone)
{
	if (bone->parNr == -1){
		bone->parent = NULL;
		bone->flag &= ~BONE_IK_TOPARENT;
	}
	else{
		bone->parent = BLI_findlink(&G.edbo, bone->parNr);
		attach_bone_to_parent(bone);
	}
}

static void parnr_to_editbone_cb(void *bonev, void *arg2_unused)
{
	EditBone *curBone= bonev;
	parnr_to_editbone(curBone);
}

static void build_bonestring (char *string, EditBone *bone)
{
	EditBone *curBone;
	EditBone *pBone;
	int		skip=0;
	int		index, numbones, i;
	char (*qsort_ptr)[32] = NULL;

	sprintf (string, "Parent%%t| %%x%d", -1);	/* That space is there
												 * for a reason
												 */

	numbones = BLI_countlist(&G.edbo);

	/*
	 * This will hold the bone names temporarily so we can sort them
	 */
	if (numbones > 0)
		qsort_ptr = MEM_callocN (numbones * sizeof (qsort_ptr[0]),
								 "qsort_ptr");

	numbones = 0;
	for (curBone = G.edbo.first, index=0; curBone;
		 curBone=curBone->next, index++){
		/* Make sure this is a valid child */
		if (curBone != bone){
			skip=0;
			for (pBone=curBone->parent; pBone; pBone=pBone->parent){
				if (pBone==bone){
					skip=1;
					break;
				}
			}

			if (skip)
				continue;

			sprintf (qsort_ptr[numbones], "|%s%%x%d", curBone->name, index);
			numbones++;
		}
	}
	qsort (qsort_ptr, numbones, sizeof (qsort_ptr[0]),
		   ( int (*)(const void *, const void *) ) strcmp);

	for (i=0; i < numbones; ++i) {
		sprintf (string, "%s%s", string, qsort_ptr[i]);
	}

	if (qsort_ptr)
		MEM_freeN(qsort_ptr);
}

static void constraint_ebone_name_fix(ListBase *conlist, EditBone *eBone)
{

	bConstraint *curcon;
	char *subtarget;

	for (curcon = conlist->first; curcon; curcon=curcon->next){
		subtarget = get_con_subtarget_name(curcon, G.obedit);
		if (subtarget)
			if (!strcmp(subtarget,eBone->oldname) )
				strcpy(subtarget, eBone->name);
	}
}

// called in outliner too...
void validate_editbonebutton(EditBone *eBone)
{
	EditBone	*prev;
	bAction		*act=NULL;
	bActionChannel *chan;
	Base *base;
	bPose        *pose;
	bPoseChannel *pchan;

	/* Separate the bone from the G.edbo */
	prev=eBone->prev;
	BLI_remlink (&G.edbo, eBone);

	/*	Validate the name */
	unique_editbone_name (eBone->name);

	/* Re-insert the bone */
	if (prev)
		BLI_insertlink(&G.edbo, prev, eBone);
	else
		BLI_addhead (&G.edbo, eBone);

	/* Rename *action* channel if necessary */
	if (G.obedit)
		act = G.obedit->action;

	if (act && !act->id.lib){
		/*	Find the appropriate channel
		 */
		for (chan = act->chanbase.first; chan; chan=chan->next){
			if (!strcmp (chan->name, eBone->oldname)){
				strcpy (chan->name, eBone->name);
			}
		}
		allqueue(REDRAWACTION, 0);
	}

	/* Rename the *pose* channel, if it exists (thus making sure
	 * that the constraints are still valid)
	 */
	pose = G.obedit->pose;
	if (pose) {
		pchan = get_pose_channel(pose, eBone->oldname);
		if (pchan) {
			strcpy (pchan->name, eBone->name);
		}
	}

	/* Update the parenting info of any users */
	/*	Yes, I know this is the worst thing you have ever seen. */

	for (base = G.scene->base.first; base; base=base->next){
		Object *ob = base->object;
		ListBase *conlist;

		/* See if an object is parented to this armature */
		if (ob->parent && ob->partype==PARBONE &&
			(ob->parent->type==OB_ARMATURE) &&
			(ob->parent->data == G.obedit->data)){
			if (!strcmp(ob->parsubstr, eBone->oldname))
				strcpy(ob->parsubstr, eBone->name);
		}

		/* Update any constraints to use the new bone name */
		conlist = &ob->constraints;
		constraint_ebone_name_fix(conlist, eBone);

		switch (ob->type){
			case OB_ARMATURE:
				if (ob->pose){
					for (pchan = ob->pose->chanbase.first; pchan;
						 pchan=pchan->next){
						conlist = &pchan->constraints;
						constraint_ebone_name_fix(conlist, eBone);
					}
				}
				break;
			default:
				break;
        }

	}

	exit_editmode(0);	/* To ensure new names make it to the edit armature */

}

static void validate_editbonebutton_cb(void *bonev, void *arg2_unused)
{
	EditBone *curBone= bonev;
	validate_editbonebutton(curBone);
}

/* called from outliner now, can be used for buttons in posemode too */
/* current Armature should be active Object */
/* after this function, the Bones in Armature are re-allocced! */
void rename_bone_ext(char *oldname, char *newname)
{
	EditBone *ebone;
	int temp_editmode= 0;

	/* since the naming functions work only on editArmature, we have to... */
	if(G.obedit!=OBACT) exit_editmode(2);
	if(G.obedit==NULL) {
		G.obedit= OBACT;
		make_editArmature();
		temp_editmode= 1;
	}
	
	/* now find the eBone with oldname */
	for(ebone= G.edbo.first; ebone; ebone= ebone->next)
		if(strcmp(ebone->name, oldname)==0) break;

	if(ebone) {
		strcpy(ebone->oldname, oldname);
		strcpy(ebone->name, newname);
		validate_editbonebutton(ebone); // does exit_editmode... tsk, so armature bones pointers are invalid now
	}
	if(temp_editmode) exit_editmode(2);
	
}


static void armature_rest_pos_func(void *notused1, void *notused2) 
{
	clear_object_constraint_status(OBACT);
	make_displists_by_armature(OBACT);
}

static void editing_panel_armature_type(Object *ob, bArmature *arm)
{
	uiBlock		*block;
	uiBut       *but;
	int			bx=148, by=100;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_armature_type", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Armature", "Editing", 320, 0, 318, 204)==0) return;

	but = uiDefButI(block, TOG|BIT|ARM_RESTPOSBIT,REDRAWVIEW3D,
					"Rest Pos", bx,by,97,20, &arm->flag, 0, 0, 0, 0,
					"Disable all animation for this object");
	uiButSetFunc(but, armature_rest_pos_func, NULL, NULL);

	uiBlockBeginAlign(block);
	uiDefButI(block, TOG|BIT|ARM_DRAWAXESBIT,REDRAWVIEW3D, "Draw Axes", bx,by-46,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone axes");
	uiDefButI(block, TOG|BIT|ARM_DRAWNAMESBIT,REDRAWVIEW3D, "Draw Names", bx,by-69,97,20, &arm->flag, 0, 0, 0, 0, "Draw bone names");
	uiDefButI(block, TOG|BIT|ARM_DRAWXRAYBIT,REDRAWVIEW3D, "X-Ray", bx,by-92,97,20, &arm->flag, 0, 0, 0, 0, "Draw armature in front of shaded objects");
	uiDefButI(block, TOG|BIT|ARM_DELAYBIT,REDRAWVIEW3D,
			  "Delay Deform", bx,by-115,97,20, &arm->flag, 0, 0, 0, 0,
			  "Don't deform children when manipulating bones in pose mode");
}

static void editing_panel_armature_bones(Object *ob, bArmature *arm)
{
	uiBlock		*block;
	uiBut		*but;
	EditBone	*curBone;
	char		*boneString=NULL;
	int			bx=148, by=180;
	int			index;

	/* Draw the bone name block */

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_armature_bones", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Armature Bones", "Editing", 640, 0, 318, 204)==0) return;

	/* this is a variable height panel, newpanel doesnt force new size on existing panels */
	/* so first we make it default height */
	uiNewPanelHeight(block, 204);


	uiDefBut(block, LABEL, 0, "Selected Bones", bx,by,158,18, 0, 0, 0, 0, 0, "Only show in Armature Editmode");
	by-=20;
	for (curBone=G.edbo.first, index=0; curBone; curBone=curBone->next, index++){
		if (curBone->flag & (BONE_SELECTED)) {

			/* Hide in posemode flag */
			uiDefButI(block, TOG|BIT|BONE_HIDDENBIT, REDRAWVIEW3D, "Hide", bx-55,by,45,18, &curBone->flag, 0, 0, 0, 0, "Toggles display of this bone in posemode");

			/*	Bone naming button */
			strcpy (curBone->oldname, curBone->name);
			but=uiDefBut(block, TEX, REDRAWVIEW3D, "BO:", bx-10,by,117,18, &curBone->name, 0, 24, 0, 0, "Change the bone name");
			uiButSetFunc(but, validate_editbonebutton_cb, curBone, NULL);

			uiDefBut(block, LABEL, 0, "child of", bx+107,by,73,18, NULL, 0.0, 0.0, 0.0, 0.0, "");

			boneString = malloc((BLI_countlist(&G.edbo) * 64)+64);
			build_bonestring (boneString, curBone);

			curBone->parNr = editbone_to_parnr(curBone->parent);
			but = uiDefButI(block, MENU,REDRAWVIEW3D, boneString, bx+180,by,120,18, &curBone->parNr, 0.0, 0.0, 0.0, 0.0, "Parent");
			uiButSetFunc(but, parnr_to_editbone_cb, curBone, NULL);

			free(boneString);

			/* IK to parent flag */
			if (curBone->parent){
				but=uiDefButI(block, TOG|BIT|BONE_IK_TOPARENTBIT, REDRAWVIEW3D, "IK", bx+300,by,32,18, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "IK link to parent");
				uiButSetFunc(but, attach_bone_to_parent_cb, curBone, NULL);
			}

			/* Dist and weight buttons */
			uiBlockBeginAlign(block);
			but=uiDefButS(block, MENU, REDRAWVIEW3D,
							"Skinnable %x0|" "Unskinnable %x1|" "Head %x2|"
							"Neck %x3|" "Back %x4|" "Shoulder %x5|" "Arm %x6|"
							"Hand %x7|" "Finger %x8|" "Thumb %x9|" "Pelvis %x10|"
							"Leg %x11|" "Foot %x12|" "Toe %x13|" "Tentacle %x14",
							bx-10,by-19,117,18, &curBone->boneclass, 0.0, 0.0, 0.0, 0.0,
							"Classification of armature element");

			/* Dist and weight buttons */
			uiDefButF(block, NUM,REDRAWVIEW3D, "Dist:", bx+110, by-19,
						105, 18, &curBone->dist, 0.0, 1000.0, 10.0, 0.0,
						"Bone deformation distance");
			uiDefButF(block, NUM,REDRAWVIEW3D, "Weight:", bx+223, by-19,
						110, 18, &curBone->weight, 0.0F, 1000.0F,
						10.0F, 0.0F, "Bone deformation weight");

			uiBlockEndAlign(block);
			by-=42;
		}
	}

	if(by<0) {
		uiNewPanelHeight(block, 204 - by);
	}

}


/* *************************** MESH ******************************** */

void do_meshbuts(unsigned short event)
{
	Object *ob;
	Mesh *me;
	float fac;
	short randfac;

	ob= OBACT;
	if(ob && ob->type==OB_MESH) {

		me= get_mesh(ob);
		if(me==0) return;

		switch(event) {
		case B_AUTOVGROUP:
			if (!get_armature(ob->parent)){
				error ("Mesh must be the child of an armature");
				break;
			}
				/* Verify that there are vertex groups for bones in armature */
				/* Remove selected vertices from all defgroups */
				/* Perform assignment for selected vertices */

			allqueue (REDRAWVIEW3D, 1);
			break;
		case B_NEWVGROUP:
			add_defgroup (G.obedit);
			scrarea_queue_winredraw(curarea);
			break;
		case B_DELVGROUP:
			del_defgroup (G.obedit);
			allqueue (REDRAWVIEW3D, 1);
			BIF_undo_push("Delete vertex group");
			break;
		case B_ASSIGNVGROUP:
			assign_verts_defgroup ();
			allqueue (REDRAWVIEW3D, 1);
			BIF_undo_push("Assign to vertex group");
			break;
		case B_REMOVEVGROUP:
			remove_verts_defgroup (0);
			allqueue (REDRAWVIEW3D, 1);
			BIF_undo_push("Remove from vertex group");
			break;
		case B_SELVGROUP:
			sel_verts_defgroup(1);
			allqueue (REDRAWVIEW3D, 1);
			break;
		case B_DESELVGROUP:
			sel_verts_defgroup(0);
			allqueue (REDRAWVIEW3D, 1);
			break;
		case B_DELSTICKY:

			if(me->msticky) MEM_freeN(me->msticky);
			me->msticky= NULL;
			allqueue(REDRAWBUTSEDIT, 0);
			break;
		case B_MAKESTICKY:
			make_sticky();
			break;
		
		case B_MAKEEDGES:
			/* in editmode we only have to set edge pointer */
			if(ob==G.obedit) {
				me->medge= MEM_callocN(sizeof(MEdge), "fake mesh edge");
				me->totedge= 1;
			}
			else make_edges(me);
			allqueue(REDRAWBUTSEDIT, 0);
			break;
		case B_DELEDGES:
			if(me->medge) MEM_freeN(me->medge);
			me->medge= NULL;
			me->totedge= 0;
			makeDispList(ob);
			allqueue(REDRAWBUTSEDIT, 0);
			allqueue(REDRAWVIEW3D, 0);
			break;
			
		case B_MAKEVERTCOL:
			make_vertexcol();
			break;
		case B_DELVERTCOL:
			if(me->mcol) MEM_freeN(me->mcol);
			me->mcol= NULL;
			G.f &= ~G_VERTEXPAINT;
			freedisplist(&(ob->disp));
			allqueue(REDRAWBUTSEDIT, 0);
			allqueue(REDRAWVIEW3D, 0);
			break;

		case B_MAKE_TFACES:
			make_tfaces(me);
			allqueue(REDRAWBUTSEDIT, 0);
			break;

		case B_DEL_TFACES:
			if(me->tface) MEM_freeN(me->tface);
			me->tface= 0;
			G.f &= ~G_FACESELECT;
			allqueue(REDRAWBUTSEDIT, 0);
			allqueue(REDRAWVIEW3D, 0);
			allqueue(REDRAWIMAGE, 0);
			break;

		case B_FLIPNORM:
			if(G.obedit) {
				flip_editnormals();
			}
			else flipnorm_mesh( get_mesh(ob) );

			allqueue(REDRAWVIEW3D, 0);
			break;

		case B_DECIM_FACES:
			decimate_faces();
			break;
		case B_DECIM_CANCEL:
			decimate_cancel();
			break;
		case B_DECIM_APPLY:
			decimate_apply();
			break;

		case B_SLOWERDRAW:
			slowerdraw();
			break;
		case B_FASTERDRAW:
			fasterdraw();
			break;
		}
	}

	if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return;

	switch(event) {
	case B_SPIN:
		if( select_area(SPACE_VIEW3D)) spin_mesh(step, degr, 0, 0);
		break;
	case B_SPINDUP:
		if( select_area(SPACE_VIEW3D)) spin_mesh(step, degr, 0, 1);
		break;
	case B_EXTR:
		G.f |= G_DISABLE_OK;
		if( select_area(SPACE_VIEW3D)) extrude_mesh();
		G.f -= G_DISABLE_OK;
		break;
	case B_SCREW:
		if( select_area(SPACE_VIEW3D)) screw_mesh(step, turn);
		break;
	case B_EXTREP:
		if( select_area(SPACE_VIEW3D)) extrude_repeat_mesh(step, extr_offs);
		break;
	case B_SPLIT:
		G.f |= G_DISABLE_OK;
		split_mesh();
		G.f -= G_DISABLE_OK;
		break;
	case B_REMDOUB:
		notice("Removed: %d", removedoublesflag(1, doublimit));
		allqueue(REDRAWVIEW3D, 0);
		BIF_undo_push("Rem Doubles");
		break;
	case B_SUBDIV:
		waitcursor(1);
		subdivideflag(1, 0.0, editbutflag & B_BEAUTY);
		countall();
		waitcursor(0);
		allqueue(REDRAWVIEW3D, 0);
		BIF_undo_push("Subdivide");
		break;
	case B_FRACSUBDIV:
		randfac= 10;
		if(button(&randfac, 1, 100, "Rand fac:")==0) return;
		waitcursor(1);
		fac= -( (float)randfac )/100;
		subdivideflag(1, fac, editbutflag & B_BEAUTY);
		countall();
		waitcursor(0);
		allqueue(REDRAWVIEW3D, 0);
		BIF_undo_push("Fractal Subdivide");
		break;
	case B_XSORT:
		if( select_area(SPACE_VIEW3D)) xsortvert_flag(1);
		break;
	case B_HASH:
		hashvert_flag(1);
		break;
	case B_TOSPHERE:
		vertices_to_sphere();
		break;
	case B_VERTEXNOISE:
		vertexnoise();
		break;
	case B_VERTEXSMOOTH:
		vertexsmooth();
		break;
	case B_DRAWEDGES:
		G.f &= ~G_DRAWCREASES;
		allqueue(REDRAWBUTSEDIT, 0);
		allqueue(REDRAWVIEW3D, 0);
		break;
	case B_DRAWCREASES:
		G.f &= ~G_DRAWEDGES;
		allqueue(REDRAWBUTSEDIT, 0);
		allqueue(REDRAWVIEW3D, 0);
		break;
	}
	/* WATCH IT: previous events only in editmode! */
}

static void editing_panel_mesh_tools(Object *ob, Mesh *me)
{
	uiBlock *block;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_tools", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Mesh Tools", "Editing", 640, 0, 318, 204)==0) return;

	uiBlockBeginAlign(block);
	uiDefButS(block, TOG|BIT|2, 0, "Beauty",		10,195,80,19, &editbutflag, 0, 0, 0, 0, "Causes 'Subdivide' to split faces in halves instead of quarters");
	uiDefBut(block, BUT,B_SUBDIV,"Subdivide",		90,195,80,19, 0, 0, 0, 0, 0, "Splits selected faces into halves or quarters");
	uiDefBut(block, BUT,B_FRACSUBDIV, "Fract Subd",	170,195,85,19, 0, 0, 0, 0, 0, "Subdivides selected faces with a random factor");

	uiDefBut(block, BUT,B_VERTEXNOISE,"Noise",		10,175,80,19, 0, 0, 0, 0, 0, "Use vertex coordinate as texture coordinate");
	uiDefBut(block, BUT,B_HASH,"Hash",				90,175,80,19, 0, 0, 0, 0, 0, "Randomizes selected vertice sequence data");
	uiDefBut(block, BUT,B_XSORT,"Xsort",			170,175,85,19, 0, 0, 0, 0, 0, "Sorts selected vertice data in the X direction");

	uiDefBut(block, BUT,B_TOSPHERE,"To Sphere",		10,155,80,19, 0, 0, 0, 0, 0, "Moves selected vertices outwards into a spherical shape");
	uiDefBut(block, BUT,B_VERTEXSMOOTH,"Smooth",	90,155,80,19, 0, 0, 0, 0, 0, "Flattens angles of selected faces");
	uiDefBut(block, BUT,B_SPLIT,"Split",			170,155,85,19, 0, 0, 0, 0, 0, "Splits selected verts to separate sub-mesh.");

	uiDefBut(block, BUT,B_FLIPNORM,"Flip Normals",	10,135,80,19, 0, 0, 0, 0, 0, "Toggles the direction of the selected face's normals");
	uiDefBut(block, BUT,B_REMDOUB,"Rem Doubles",	90,135,80,19, 0, 0, 0, 0, 0, "Removes duplicates from selected vertices");
	uiDefButF(block, NUM, B_DIFF, "Limit:",			170,135,85,19, &doublimit, 0.0001, 1.0, 10, 0, "Specifies the max distance 'Rem Doubles' will consider vertices as 'doubled'");
	uiBlockEndAlign(block);

	uiDefBut(block, BUT,B_EXTR,"Extrude",			10,105,245,24, 0, 0, 0, 0, 0, "Converts selected edges to faces and selects the new vertices");

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT,B_SCREW,"Screw",			10,75,80,24, 0, 0, 0, 0, 0, "Activates the screw tool");  // Bish - This could use some more definition
	uiDefBut(block, BUT,B_SPIN, "Spin",				90,75,80,24, 0, 0, 0, 0, 0, "Extrudes the selected vertices in a circle around the cursor in the indicated viewport");
	uiDefBut(block, BUT,B_SPINDUP,"Spin Dup",		170,75,85,24, 0, 0, 0, 0, 0, "Creates copies of the selected vertices in a circle around the cursor in the indicated viewport");

	uiDefButS(block, NUM, B_DIFF, "Degr:",			10,55,80,19, &degr,10.0,360.0, 0, 0, "Specifies the number of degrees 'Spin' revolves");
	uiDefButS(block, NUM, B_DIFF, "Steps:",			90,55,80,19, &step,1.0,180.0, 0, 0, "Specifies the total number of 'Spin' slices");
	uiDefButS(block, NUM, B_DIFF, "Turns:",			170,55,85,19, &turn,1.0,360.0, 0, 0, "Specifies the number of revolutions the screw turns");
	uiDefButS(block, TOG|BIT|1, B_DIFF, "Keep Original",10,35,160,19, &editbutflag, 0, 0, 0, 0, "Keeps a copy of the original vertices and faces after executing tools");
	uiDefButS(block, TOG|BIT|0, B_DIFF, "Clockwise",	170,35,85,19, &editbutflag, 0, 0, 0, 0, "Specifies the direction for 'Screw' and 'Spin'");

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT,B_EXTREP, "Extrude Dup",	10,10,120,19, 0, 0, 0, 0, 0, "Creates copies of the selected vertices in a straight line away from the current viewport");
	uiDefButF(block, NUM, B_DIFF, "Offset:",		130,10,125,19, &extr_offs, 0.01, 100.0, 100, 0, "Sets the distance between each copy for 'Extrude Dup'");
	uiBlockEndAlign(block);
}

static void verify_vertexgroup_name_func(void *datav, void *data2_unused)
{
	unique_vertexgroup_name((bDeformGroup*)datav, OBACT);
}



static void editing_panel_mesh_tools1(Object *ob, Mesh *me)
{
	uiBlock *block;


	block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_tools1", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Mesh Tools 1", "Editing", 960, 0, 318, 204)==0) return;

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT,B_DOCENTRE, "Centre",		1091, 200, 166, 19, 0, 0, 0, 0, 0, "Shifts object data to be centered about object's origin");
	uiDefBut(block, BUT,B_HIDE,		"Hide",			1091, 180,  77, 19, 0, 0, 0, 0, 0, "Hides selected faces");
	uiDefBut(block, BUT,B_REVEAL,	"Reveal",		1171, 180,  86, 19, 0, 0, 0, 0, 0, "Reveals selected faces");
	uiDefBut(block, BUT,B_SELSWAP,	"Select Swap",	1091, 160, 166, 19, 0, 0, 0, 0, 0, "Selects unselected faces, and deselects selected faces");
	uiBlockEndAlign(block);

	uiBlockBeginAlign(block);
	uiDefButF(block, NUM,		  REDRAWVIEW3D, "NSize:",		1090, 131, 166, 19, &editbutsize, 0.001, 2.0, 10, 0, "Sets the length to use when displaying face normals");
	uiDefButI(block, TOG|BIT|6, REDRAWVIEW3D, "Draw Normals",	1090,110,166,19, &G.f, 0, 0, 0, 0, "Displays face normals as lines");
	uiDefButI(block, TOG|BIT|7, REDRAWVIEW3D, "Draw Faces",		1090,88,166,19, &G.f, 0, 0, 0, 0, "Displays all faces as shades");
	uiDefButI(block, TOG|BIT|18, B_DRAWEDGES, "Draw Edges", 	1090,66,166,19, &G.f, 0, 0, 0, 0, "Displays selected edges using hilights");
	uiDefButI(block, TOG|BIT|19, B_DRAWCREASES, "Draw Creases",	1090,44,166,19, &G.f, 0, 0, 0, 0, "Displays creased edges using hilights");
	uiDefButI(block, TOG|BIT|20, REDRAWVIEW3D, "Draw Seams",	1090,22,166,19, &G.f, 0, 0, 0, 0, "Displays UV unwrapping seams");
	uiDefButI(block, TOG|BIT|11, 0, "All Edges",				1090, 0,166,19, &G.f, 0, 0, 0, 0, "Displays all edges in object mode without optimization");
	uiBlockEndAlign(block);

}

static void editing_panel_links(Object *ob)
{
	uiBlock *block;
	ID *id, *idfrom;
	int *poin, xco=143;
	float min;
	Material *ma;
	char str[64];
	uiBut *but;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_links", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Link and Materials", "Editing", 0, 0, 318, 204)==0) return;

	buttons_active_id(&id, &idfrom);

	if(id) {
		int alone= 0;
		int local= 0;
		int browse= B_EDITBROWSE;

		if(ob->type==OB_MESH) {
			browse= B_MESHBROWSE;
			alone= B_MESHALONE;
			local= B_MESHLOCAL;
			uiSetButLock(G.obedit!=0, "Unable to perform function in EditMode");
		}
		else if(ob->type==OB_MBALL) {
			alone= B_MBALLALONE;
			local= B_MBALLLOCAL;
		}
		else if ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF) {
			alone= B_CURVEALONE;
			local= B_CURVELOCAL;
		}
		else if(ob->type==OB_CAMERA) {
			alone= B_CAMERAALONE;
			local= B_CAMERALOCAL;
		}
		else if(ob->type==OB_LAMP) {
			alone= B_LAMPALONE;
			local= B_LAMPLOCAL;
		}
		else if (ob->type==OB_ARMATURE){
			alone = B_ARMALONE;
			local = B_ARMLOCAL;
		}
		else if(ob->type==OB_LATTICE) {
			alone= B_LATTALONE;
			local= B_LATTLOCAL;
		}
		uiBlockSetCol(block, TH_BUT_SETTING2);
		xco= std_libbuttons(block, 143, 180, 0, NULL, browse, id, idfrom, &(G.buts->menunr), alone, local, 0, 0, B_KEEPDATA);
		uiBlockSetCol(block, TH_AUTO);
	}
	if(ob) {
		but = uiDefBut(block, TEX, B_IDNAME, "OB:",	xco, 180, 454-xco, YIC, ob->id.name+2, 0.0, 19.0, 0, 0, "Displays Active Object name. Click to change.");
		uiButSetFunc(but, test_idbutton_cb, ob->id.name, NULL);
	}



	/* to be sure */
	if ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL);
	else return;


	if(ob->type==OB_MESH) poin= &( ((Mesh *)ob->data)->texflag );
	else if(ob->type==OB_MBALL) poin= &( ((MetaBall *)ob->data)->texflag );
	else poin= &( ((Curve *)ob->data)->texflag );
	uiDefButI(block, TOG|BIT|0, B_AUTOTEX, "AutoTexSpace",	143,15,140,19, poin, 0, 0, 0, 0, "Adjusts active object's texture space automatically when transforming object");

	sprintf(str,"%d Mat:", ob->totcol);
	if(ob->totcol) min= 1.0; else min= 0.0;
	ma= give_current_material(ob, ob->actcol);

	if(ma) uiDefBut(block, LABEL, 0, ma->id.name+2, 318,153, 103, 20, 0, 0, 0, 0, 0, "");

	uiBlockBeginAlign(block);
	if(ma) uiDefButF(block, COL, B_REDR, "",			292,123,31,30, &(ma->r), 0, 0, 0, 0, "");
	uiDefButC(block, NUM, B_REDR,	str,		324,123,100,30, &ob->actcol, min, (float)(ob->totcol), 0, 0, "Displays total number of material indices and the current index");
	uiDefBut(block, BUT,B_MATWICH,	"?",		424,123,30,30, 0, 0, 0, 0, 0, "In EditMode, sets the active material index from selected faces");

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT,B_MATNEW,	"New",		292,98,80,20, 0, 0, 0, 0, 0, "Adds a new Material index");
	uiDefBut(block, BUT,B_MATDEL,	"Delete",	374,98,80,20, 0, 0, 0, 0, 0, "Deletes this Material index");
	uiDefBut(block, BUT,B_MATSEL,	"Select",	292,76,80,20, 0, 0, 0, 0, 0, "In EditMode, selects faces that have the active index");
	uiDefBut(block, BUT,B_MATDESEL,	"Deselect",	374,76,80,20, 0, 0, 0, 0, 0, "Deselects everything with current indexnumber");
	uiDefBut(block, BUT,B_MATASS,	"Assign",	292,47,162,26, 0, 0, 0, 0, 0, "In EditMode, assigns the active index to selected faces");

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT,B_SETSMOOTH,"Set Smooth",	291,15,80,20, 0, 0, 0, 0, 0, "In EditMode, sets 'smooth' rendering of selected faces");
	uiDefBut(block, BUT,B_SETSOLID,	"Set Solid",	373,15,80,20, 0, 0, 0, 0, 0, "In EditMode, sets 'solid' rendering of selected faces");
	uiBlockEndAlign(block);

	/* vertex group... partially editmode... */
	if(ob->type==OB_MESH) {
		uiBut *but;
		int	defCount;
		bDeformGroup	*defGroup;
		char *s, *menustr;
		bDeformGroup *dg;
		int min, index;
		char (*qsort_ptr)[32] = NULL;

		uiDefBut(block, LABEL,0,"Vertex Groups",
				 143,153,130,20, 0, 0, 0, 0, 0, "");

		defCount=BLI_countlist(&ob->defbase);

		if (!defCount) min=0;
		else min=1;

		if (defCount > 0) {
			/*
			 * This will hold the group names temporarily
			 * so we can sort them
			 */
			qsort_ptr = MEM_callocN (defCount * sizeof (qsort_ptr[0]),
									 "qsort_ptr");
			for (index = 1, dg = ob->defbase.first; dg; index++, dg=dg->next) {
				snprintf (qsort_ptr[index - 1], sizeof (qsort_ptr[0]),
						  "%s%%x%d|", dg->name, index);
			}

			qsort (qsort_ptr, defCount, sizeof (qsort_ptr[0]),
				   ( int (*)(const void *, const void *) ) strcmp);
		}

		s= menustr = MEM_callocN((32 * defCount)+20, "menustr");
		for (index = 0; index < defCount; index++) {
			int cnt= sprintf (s, "%s", qsort_ptr[index]);
			if (cnt>0) s+= cnt;
		}

		if (qsort_ptr)
		  MEM_freeN (qsort_ptr);

		uiBlockBeginAlign(block);
		if (defCount)
			uiDefButS(block, MENU, REDRAWBUTSEDIT, menustr,
					  143, 132,18,21, &ob->actdef, min, defCount, 0, 0,
					  "Browses available vertex groups");

		MEM_freeN (menustr);

		if (ob->actdef){
			defGroup = BLI_findlink(&ob->defbase, ob->actdef-1);
			but= uiDefBut(block, TEX,REDRAWBUTSEDIT,"",		161,132,140-18,21, defGroup->name, 0, 32, 0, 0, "Displays current vertex group name. Click to change. (Match bone name for deformation.)");
			uiButSetFunc(but, verify_vertexgroup_name_func, defGroup, NULL);

			uiDefButF(block, NUM, REDRAWVIEW3D, "Weight:",		143, 111, 140, 21, &editbutvweight, 0, 1, 10, 0, "Sets the current vertex group's bone deformation strength");
		}
		uiBlockEndAlign(block);

		if (G.obedit && G.obedit==ob){
			uiBlockBeginAlign(block);
	/*		uiDefBut(block, BUT,B_AUTOVGROUP,"Auto Weight",			740,by-=22,93,18, 0, 0, 0, 0, 0, "Automatically assigns deformation groups"); */
			uiDefBut(block, BUT,B_NEWVGROUP,"New",			143,90,70,21, 0, 0, 0, 0, 0, "Creates a new vertex group");
			uiDefBut(block, BUT,B_DELVGROUP,"Delete",		213,90,70,21, 0, 0, 0, 0, 0, "Removes the current vertex group");

			uiDefBut(block, BUT,B_ASSIGNVGROUP,"Assign",	143,69,70,21, 0, 0, 0, 0, 0, "Assigns selected vertices to the current vertex group");
			uiDefBut(block, BUT,B_REMOVEVGROUP,"Remove",	213,69,70,21, 0, 0, 0, 0, 0, "Removes selected vertices from the current vertex group");

			uiDefBut(block, BUT,B_SELVGROUP,"Select",		143,48,70,21, 0, 0, 0, 0, 0, "Selects vertices belonging to the current vertex group");
			uiDefBut(block, BUT,B_DESELVGROUP,"Desel.",		213,48,70,21, 0, 0, 0, 0, 0, "Deselects vertices belonging to the current vertex group");
			uiBlockEndAlign(block);
		}
	}


}

/* *************************** FACE/PAINT *************************** */

void do_fpaintbuts(unsigned short event)
{
	Mesh *me;
	Object *ob;
	extern TFace *lasttface; /* caches info on tface bookkeeping ?*/

	ob= OBACT;
	if(ob==0) return;

	switch(event) {

	case B_VPGAMMA:
		vpaint_dogamma();
		break;
	case B_COPY_TF_MODE:
	case B_COPY_TF_UV:
	case B_COPY_TF_COL:
	case B_COPY_TF_TEX:
		me= get_mesh(ob);
		if(me && me->tface) {
/*  			extern TFace *lasttface; */
			TFace *tface= me->tface;
			int a= me->totface;

			set_lasttface();
			if(lasttface) {

				while(a--) {
					if(tface!=lasttface && (tface->flag & TF_SELECT)) {
						if(event==B_COPY_TF_MODE) {
							tface->mode= lasttface->mode;
							tface->transp= lasttface->transp;
						}
						else if(event==B_COPY_TF_UV) {
							memcpy(tface->uv, lasttface->uv, sizeof(tface->uv));
							tface->tpage= lasttface->tpage;
							tface->tile= lasttface->tile;

							if(lasttface->mode & TF_TILES) tface->mode |= TF_TILES;
							else tface->mode &= ~TF_TILES;

						}
						else if(event==B_COPY_TF_TEX) {
							tface->tpage= lasttface->tpage;
							tface->tile= lasttface->tile;

							if(lasttface->mode & TF_TILES) tface->mode |= TF_TILES;
							else tface->mode &= ~TF_TILES;
						}
						else if(event==B_COPY_TF_COL) memcpy(tface->col, lasttface->col, sizeof(tface->col));
					}
					tface++;
				}
			}
			do_shared_vertexcol(me);
			allqueue(REDRAWVIEW3D, 0);
			allqueue(REDRAWIMAGE, 0);
		}
		break;
	case B_SET_VCOL:
		clear_vpaint_selectedfaces();
		break;
	case B_REDR_3D_IMA:
		allqueue(REDRAWVIEW3D, 0);
		allqueue(REDRAWIMAGE, 0);
		break;
	case B_ASSIGNMESH:

		test_object_materials(ob->data);
		allqueue(REDRAWVIEW3D, 0);
		allqueue(REDRAWBUTSEDIT, 0);
		break;

	case B_TFACE_HALO:
		set_lasttface();
		if(lasttface) {
			lasttface->mode &= ~TF_BILLBOARD2;
			allqueue(REDRAWBUTSEDIT, 0);
		}
		break;

	case B_TFACE_BILLB:
		set_lasttface();
		if(lasttface) {
			lasttface->mode &= ~TF_BILLBOARD;
			allqueue(REDRAWBUTSEDIT, 0);
		}
		break;
	}
}


/* -------------------- MODE: vpaint faceselect ------------------- */

static void editing_panel_mesh_paint(void)
{
	extern VPaint Gvp;         /* from vpaint */
	uiBlock *block;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_paint", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Paint", "Editing", 640, 0, 318, 204)==0) return;

    uiBlockBeginAlign(block);
	uiDefButF(block, NUMSLI, 0, "R ",			979,160,194,19, &Gvp.r, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of red used for painting");
	uiDefButF(block, NUMSLI, 0, "G ",			979,140,194,19, &Gvp.g, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of green used for painting");
	uiDefButF(block, NUMSLI, 0, "B ",			979,120,194,19, &Gvp.b, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of blue used for painting");
	uiBlockEndAlign(block);

	uiDefButF(block, NUMSLI, 0, "Opacity ",		979,100,194,19, &Gvp.a, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
	uiDefButF(block, NUMSLI, 0, "Size ",		979,80,194,19, &Gvp.size, 2.0, 64.0, 0, 0, "The size of the brush");

	uiDefButF(block, COL, B_REDR, "",		1176,99,28,80, &(Gvp.r), 0, 0, 0, B_VPCOLSLI, "");
	uiBlockBeginAlign(block);
	uiDefButS(block, ROW, B_DIFF, "Mix",			1212,160,63,19, &Gvp.mode, 1.0, 0.0, 0, 0, "Mix the vertex colours");
	uiDefButS(block, ROW, B_DIFF, "Add",			1212,140,63,19, &Gvp.mode, 1.0, 1.0, 0, 0, "Add the vertex colour");
	uiDefButS(block, ROW, B_DIFF, "Sub",			1212, 120,63,19, &Gvp.mode, 1.0, 2.0, 0, 0, "Subtract from the vertex colour");
	uiDefButS(block, ROW, B_DIFF, "Mul",			1212, 100,63,19, &Gvp.mode, 1.0, 3.0, 0, 0, "Multiply the vertex colour");
	uiDefButS(block, ROW, B_DIFF, "Filter",		1212, 80,63,19, &Gvp.mode, 1.0, 4.0, 0, 0, "Mix the colours with an alpha factor");

	uiBlockBeginAlign(block);
	uiDefButS(block, TOG|BIT|1, 0, "Area", 		979,50,81,19, &Gvp.flag, 0, 0, 0, 0, "Vertex paint evaluates the area of the face the brush covers (otherwise vertices only)");
	uiDefButS(block, TOG|BIT|2, 0, "Soft", 		1061,50,112,19, &Gvp.flag, 0, 0, 0, 0, "Use a soft brush");
	uiDefButS(block, TOG|BIT|3, 0, "Normals", 	1174,50,102,19, &Gvp.flag, 0, 0, 0, 0, "Vertex paint applies the vertex normal before painting");

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT, B_VPGAMMA, "Set", 	979,30,81,19, 0, 0, 0, 0, 0, "Apply Mul and Gamma to vertex colours");
	uiDefButF(block, NUM, B_DIFF, "Mul:", 		1061,30,112,19, &Gvp.mul, 0.1, 50.0, 10, 0, "Set the number to multiply vertex colours with");
	uiDefButF(block, NUM, B_DIFF, "Gamma:", 	1174,30,102,19, &Gvp.gamma, 0.1, 5.0, 10, 0, "Change the clarity of the vertex colours");
	uiBlockEndAlign(block);

	uiDefBut(block, BUT, B_SET_VCOL, "Set VertCol",	979,5,81,20, 0, 0, 0, 0, 0, "Set Vertex colour of selection to current (Shift+K)");

}

static void editing_panel_mesh_texface(void)
{
	uiBlock *block;
	extern TFace *lasttface;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_texface", UI_EMBOSS, UI_HELV, curarea->win);
	if(uiNewPanel(curarea, block, "Texture face", "Editing", 960, 0, 318, 204)==0) return;

	set_lasttface();	// checks for ob type
	if(lasttface) {

		uiBlockBeginAlign(block);
		uiDefButS(block, TOG|BIT|2, B_REDR_3D_IMA, "Tex",	600,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Render face with texture");
		uiDefButS(block, TOG|BIT|7, B_REDR_3D_IMA, "Tiles",	660,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Use tilemode for face");
		uiDefButS(block, TOG|BIT|4, REDRAWVIEW3D, "Light",	720,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Use light for face");
		uiDefButS(block, TOG|BIT|10, REDRAWVIEW3D, "Invisible",780,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Make face invisible");
		uiDefButS(block, TOG|BIT|0, REDRAWVIEW3D, "Collision", 840,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Use face for collision detection");

		uiBlockBeginAlign(block);
		uiDefButS(block, TOG|BIT|6, REDRAWVIEW3D, "Shared",	600,135,60,19, &lasttface->mode, 0, 0, 0, 0, "Blend vertex colours across face when vertices are shared");
		uiDefButS(block, TOG|BIT|9, REDRAWVIEW3D, "Twoside",660,135,60,19, &lasttface->mode, 0, 0, 0, 0, "Render face twosided");
		uiDefButS(block, TOG|BIT|11, REDRAWVIEW3D, "ObColor",720,135,60,19, &lasttface->mode, 0, 0, 0, 0, "Use ObColor instead of vertex colours");

		uiBlockBeginAlign(block);
		uiDefButS(block, TOG|BIT|8, B_TFACE_HALO, "Halo",	600,110,60,19, &lasttface->mode, 0, 0, 0, 0, "Screen aligned billboard");
		uiDefButS(block, TOG|BIT|12, B_TFACE_BILLB, "Billboard",660,110,60,19, &lasttface->mode, 0, 0, 0, 0, "Billboard with Z-axis constraint");
		uiDefButS(block, TOG|BIT|13, REDRAWVIEW3D, "Shadow", 720,110,60,19, &lasttface->mode, 0, 0, 0, 0, "Face is used for shadow");
		uiDefButS(block, TOG|BIT|14, REDRAWVIEW3D, "Text", 780,110,60,19, &lasttface->mode, 0, 0, 0, 0, "Enable bitmap text on face");

		uiBlockBeginAlign(block);
		uiBlockSetCol(block, TH_BUT_SETTING1);
		uiDefButC(block, ROW, REDRAWVIEW3D, "Opaque",	600,80,60,19, &lasttface->transp, 2.0, 0.0, 0, 0, "Render colour of textured face as colour");
		uiDefButC(block, ROW, REDRAWVIEW3D, "Add",		660,80,60,19, &lasttface->transp, 2.0, 1.0, 0, 0, "Render face transparent and add colour of face");
		uiDefButC(block, ROW, REDRAWVIEW3D, "Alpha",	720,80,60,19, &lasttface->transp, 2.0, 2.0, 0, 0, "Render polygon transparent, depending on alpha channel of the texture");

		uiBlockSetCol(block, TH_AUTO);
		uiBlockBeginAlign(block);
		uiDefBut(block, BUT, B_COPY_TF_MODE, "Copy DrawMode", 600,7,117,28, 0, 0, 0, 0, 0, "Copy the drawmode from active face to selected faces");
		uiDefBut(block, BUT, B_COPY_TF_UV, "Copy UV+tex",	  721,7,85,28, 0, 0, 0, 0, 0, "Copy UV information and textures from active face to selected faces");
		uiDefBut(block, BUT, B_COPY_TF_COL, "Copy VertCol",	  809,7,103,28, 0, 0, 0, 0, 0, "Copy vertex colours from active face to selected faces");
	}

}

void do_uvautocalculationbuts(unsigned short event)
{
	switch(event) {
	case B_UVAUTO_STD1:
	case B_UVAUTO_STD2:
	case B_UVAUTO_STD4:
	case B_UVAUTO_STD8:
	case B_UVAUTO_CUBE:
		calculate_uv_map(event);
		break;
	case B_UVAUTO_BOUNDS1:
	case B_UVAUTO_BOUNDS2:
	case B_UVAUTO_BOUNDS4:
	case B_UVAUTO_BOUNDS8:
	case B_UVAUTO_SPHERE:
	case B_UVAUTO_CYLINDER:
	case B_UVAUTO_WINDOW:
		if(select_area(SPACE_VIEW3D)) calculate_uv_map(event);
		break;
	case B_UVAUTO_LSCM:
		unwrap_lscm();
		break;
	}
}

static void editing_panel_mesh_uvautocalculation(void)
{
	uiBlock *block;
	int butH= 19, butHB= 20, row= 180, butS= 10;

	block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_uvautocalculation", UI_EMBOSS, UI_HELV, curarea->win);
	/* make this a tab of "Texture face" to save screen space*/
	uiNewPanelTabbed("Texture face", "Editing");
	if(uiNewPanel(curarea, block, "UV Calculation", "Editing", 960, 0, 318, 204)==0)
		return;

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT, B_UVAUTO_LSCM,"LSCM Unwrap",100,row,200,butH, 0, 0, 0, 0, 0, "Applies conformal UV mapping, preserving local angles");
	uiBlockEndAlign(block);
	row-= butHB+butS;

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT, B_UVAUTO_STD1,"Standard",100,row,100,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping");
	uiDefBut(block, BUT, B_UVAUTO_STD2,"/2",200,row,33,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/2");
	uiDefBut(block, BUT, B_UVAUTO_STD4,"/4",233,row,34,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/4");
	uiDefBut(block, BUT, B_UVAUTO_STD8,"/8",267,row,33,butH, 0, 0, 0, 0, 0, "Applies standard UV mapping 1/8");
	uiBlockEndAlign(block);
	row-= butHB+butS;

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT, B_UVAUTO_BOUNDS1,"Bounds",100,row,100,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/1");
	uiDefBut(block, BUT, B_UVAUTO_BOUNDS2,"/2",200,row,33,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/2");
	uiDefBut(block, BUT, B_UVAUTO_BOUNDS4,"/4",233,row,34,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/4");
	uiDefBut(block, BUT, B_UVAUTO_BOUNDS8,"/8",267,row,33,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping with bounds 1/8");
	uiDefBut(block, BUT, B_UVAUTO_WINDOW,"From Window",100,row-butH,200,butH, 0, 0, 0, 0, 0, "Applies planar UV mapping from window");
	uiBlockEndAlign(block);
	row-= 2*butHB+butS;

	uiBlockBeginAlign(block);
	uiDefButI(block, TOG|BIT|7, REDRAWVIEW3D, "Draw Faces",	100,row,200,butH, &G.f, 0, 0, 0, 0, "Displays all faces as shades");
	uiDefButI(block,TOG|BIT|18,REDRAWVIEW3D,"Draw Edges",100,row-butHB,200,butH,&G.f, 2.0, 0, 0, 0,  "Displays edges of visible faces");
 	uiDefButI(block,TOG|BIT|21,REDRAWVIEW3D,"Draw Hidden Edges",100,row-2*butHB,200,butH,&G.f, 2.0, 1.0, 0, 0,  "Displays edges of hidden faces");
	uiDefButI(block,TOG|BIT|20,REDRAWVIEW3D,"Draw Seams",100,row-3*butHB,200,butH,&G.f, 2.0, 2.0, 0, 0,  "Displays UV unwrapping seams");
	uiBlockEndAlign(block);
	row-= 4*butHB+butS;

	row= 180;

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT, B_UVAUTO_CUBE,"Cube",315,row,200,butH, 0, 0, 0, 0, 0, "Applies cube UV mapping");
	uiDefButF(block, NUM,B_UVAUTO_CUBESIZE ,"Size:",315,row-butHB,200,butH, &uv_calc_cubesize, 0.0001, 100.0, 10, 0, "Defines the cubemap size");
	uiBlockEndAlign(block);
	row-= 2*butHB+butS;

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT, B_UVAUTO_SPHERE,"Sphere",315,row,200,butH, 0, 0, 0, 0, 0, "Applies spherical UV mapping");
	uiBlockEndAlign(block);
	row-= butHB+butS;

	uiBlockBeginAlign(block);
	uiDefBut(block, BUT, B_UVAUTO_CYLINDER,"Cylinder",315,row,200,butH, 0, 0, 0, 0, 0, "Applies cylindrical UV mapping");
	uiDefButF(block, NUM,B_UVAUTO_CYLRADIUS ,"Radius:",315,row-butHB,200,butH, &uv_calc_radius, 0.1, 100.0, 10, 0, "Defines the radius of the UV mapping cylinder");
	uiBlockEndAlign(block);
	row-= 2*butHB+butS;


	uiBlockBeginAlign(block);
	uiDefButS(block, ROW,B_UVAUTO_FACE,"View Aligns Face",315,row,200,butH, &uv_calc_mapdir,2.0, 1.0, 0.0,0.0, "View is on equator for cylindrical and spherical UV mapping");
	uiDefButS(block, ROW,B_UVAUTO_TOP,"VA Top",315,row-butHB,100,butH, &uv_calc_mapdir,2.0, 0.0, 0.0,0.0, "View is on poles for cylindrical and spherical UV mapping");
	uiDefButS(block, ROW,B_UVAUTO_TOP,"Al Obj",415,row-butHB,100,butH, &uv_calc_mapdir,2.0, 2.0, 0.0,0.0, "Align to object for cylindrical and spherical UV mapping");
	uiBlockEndAlign(block);
	row-= 2*butHB+butS;

	uiBlockBeginAlign(block);
	uiDefButS(block, ROW,B_UVAUTO_ALIGNX,"Polar ZX",315,row,100,butH, &uv_calc_mapalign,2.0, 0.0, 0.0,0.0, "Polar 0 is X for cylindrical and spherical UV mapping");
	uiDefButS(block, ROW,B_UVAUTO_ALIGNY,"Polar ZY",415,row,100,butH, &uv_calc_mapalign,2.0, 1.0, 0.0,0.0, "Polar 0 is Y for cylindrical and spherical UV mapping");
	uiBlockEndAlign(block);
}

/* this is a mode context sensitive system */

void editing_panels()
{
	Object *ob;
	Curve *cu;
	MetaBall *mb;
	Lattice *lt;
	bArmature *arm;
	Camera *cam;

	ob= OBACT;
	if(ob==NULL) return;

	switch(ob->type) {
	case OB_MESH:
		editing_panel_links(ob); // no editmode!
		editing_panel_mesh_type(ob, ob->data);	// no editmode!
		/* modes */
		if(G.obedit) {
			editing_panel_mesh_tools(ob, ob->data); // no editmode!
			editing_panel_mesh_tools1(ob, ob->data); // no editmode!
		}
		else {
			if(G.f & G_FACESELECT) {
				editing_panel_mesh_texface();
				editing_panel_mesh_uvautocalculation();
			}
			if(G.f & (G_VERTEXPAINT | G_TEXTUREPAINT | G_WEIGHTPAINT) ) {
				editing_panel_mesh_paint();
			}
		}
		break;

	case OB_CURVE:
	case OB_SURF:
		cu= ob->data;
		editing_panel_links(ob); // no editmode!
		editing_panel_curve_type(ob, cu);
		if(G.obedit) {
			editing_panel_curve_tools(ob, cu);
			editing_panel_curve_tools1(ob, cu);
		}
		break;

	case OB_MBALL:
		mb= ob->data;
		editing_panel_links(ob); // no editmode!
		editing_panel_mball_type(ob, mb);
		if(G.obedit) {
			editing_panel_mball_tools(ob, mb);
		}
		break;

	case OB_FONT:
		cu= ob->data;
		editing_panel_links(ob); // no editmode!
		editing_panel_curve_type(ob, cu);
		editing_panel_font_type(ob, cu);
		break;

	case OB_LATTICE:
		lt= ob->data;
		editing_panel_links(ob); // no editmode!
		editing_panel_lattice_type(ob, lt);
		break;

	case OB_LAMP:
		editing_panel_links(ob); // no editmode!
		break;

	case OB_EMPTY:
		editing_panel_links(ob); // no editmode!
		break;

	case OB_CAMERA:
		cam= ob->data;
		editing_panel_links(ob); // no editmode!
		editing_panel_camera_type(ob, cam);
		/* yafray: extra panel for dof parameters */
		if (G.scene->r.renderer==R_YAFRAY) editing_panel_camera_yafraydof(ob, cam);
		break;

	case OB_ARMATURE:
		arm= ob->data;
		editing_panel_links(ob); // no editmode!
		editing_panel_armature_type(ob, arm);
		if(G.obedit) {
			editing_panel_armature_bones(ob, arm);
		}
		break;
	}

}
