
----------------------------------------------------------------------------------------------------------
--Nuts & Bolts :: Creates detailed models of nuts and bolts 

--Supported on 3ds Max 2011 to 3ds Max 2019
--Free for any kind of use and modification. The script is being provided as is, with no guarantees or support.
--By Oormi Creations, http://oormi.in
--Version 0.3.2 May 2018
-----------------------------------------------------------------------------------------------------------
clearlistener()
try closerolloutfloater nabrf
catch()

(
--vars
bolt 			= undefined
nut 			= undefined
washer 		= undefined
	
mtext 		= undefined
alltext 		= undefined
addmark 	= undefined

washht		= undefined
washdia1	= undefined
washdia2	= undefined
washcham	= undefined
	
headht		= undefined
headdia		= undefined
boltht		= undefined
segs 			= undefined
nothreadht = undefined
threadht 	= undefined
threaddia 	= undefined
threadpitch = undefined
threaddepth = undefined
weldThreshold = undefined
threadchamfer = undefined

nutht			= undefined
nutdia1		= undefined
nutdia2		= undefined
nutsegs 		= undefined
nutthreadpitch = undefined
nutthreaddepth = undefined
nutweldThreshold = undefined
nutthreadchamfer = undefined
nutplay 		= undefined

prehead 	= undefined
prebolt 		= undefined
prenut 		= undefined
prewash		= undefined
preview		 = off

--------------------------------------------------------------------------------------------------------

fn cleanpreview =
(
	try
	(
		delete prehead
		delete prebolt
		delete prenut
		delete prewash
	)
	catch()
	prehead = undefined
	prebolt = undefined
	prenut = undefined
	prewash	= undefined
	preview = off
)
	
fn createwasher washpos wcol = 
(
	cy = Tube smooth:on sides:32 capsegs:1 heightsegs:1 radius1:(washdia1/2) radius2:(washdia2/2) height:washht name:(uniquename "Washer")
	hscale = washdia1/30.0
	
	pcy = convertToPoly(cy)
	pcy.EditablePoly.SetSelection #Edge #{4}
	pcy.EditablePoly.SelectEdgeLoop ()
	pcy.edgeChamferSegments = 4
	pcy.EditablePoly.chamferEdges (washcham*hscale)
	facecount = pcy.EditablePoly.getnumfaces()
	pcy.EditablePoly.SetSelection #Face #{1..facecount}
	pcy.autoSmoothThreshold = 25
	pcy.EditablePoly.autosmooth ()
	
	washer = pcy
	washer.pos = washpos - [0,0,washht]
	washer.wirecolor = wcol
	selectmore washer
)

fn createmark marktext markdia =
(
	toolMode.transformCenter()
	sz = markdia * 0.15
	start 	= 0
	sep 	= 20
	strht 	= markdia/100
	rad 	= markdia/4
	
	for i=1 to marktext.count do
	(
		ch 	= marktext[i]
		txt 	= text text:ch size:sz
		txt.pos = [0,0,headht]
		addmodifier txt (Extrude amount:strht)
		txt.pos.y = rad
		txt.rotation = (EulerAngles 0 0 (start+sep*i))
		ptxt = convertToPoly(txt)
		if i==1 then alltext = txt
		else polyop.attach alltext txt
	)
	toolMode.selectionCenter()
)


fn createnut1 nutpos wcol =
(
	--create the nut
	cy = Cylinder()
	cy.radius = (nutdia1/2)
	cy.height = nutht
	cy.heightsegs = 1
	cy.sides = 6
	cy.smooth = off
	hscale = nutdia1/100.0
	
	pcy = convertToPoly(cy)
	pcy.EditablePoly.SetSelection #Face #{7..8}
	pcy.EditablePoly.ConvertSelection #Face #Edge
	pcy.EditablePoly.chamferEdges (3.0*hscale)
	pcy.EditablePoly.SetSelection #Edge #{24,30}
	pcy.EditablePoly.SelectEdgeRing ()
	pcy.EditablePoly.chamferEdges (11.3*hscale)
	pcy.EditablePoly.chamferEdges (5.5*hscale)
	pcy.EditablePoly.SetSelection #Edge #{19..30, 91..102, 104, 111, 114, 117, 120, 123, 127, 130, 133, 136, 147, 152, 157..158, 161, 164, 167, 170, 175..176, 181, 183, 186, 189, 199..222}
	pcy.EditablePoly.chamferEdges (2.5*hscale)
	pcy.EditablePoly.SetSelection #Edge #{2, 4, 6, 9, 12, 15}
	pcy.EditablePoly.chamferEdges (1.0*hscale)
	pcy.EditablePoly.SetSelection #Face #{7..8}
	pcy.bevelFaces 0.0 (-20.0*hscale)
	facecount = pcy.EditablePoly.getnumfaces()
	pcy.EditablePoly.SetSelection #Face #{1..facecount}
	pcy.autoSmoothThreshold = 25
	pcy.EditablePoly.autosmooth ()

	if nutsegs<3 then nutsegs = 3
	if nutsegs>60 then nutsegs = 60
		
	rem = mod 360 nutsegs
	if rem>0 then
	(
		for i=1 to 360 do
		(
			nutsegs = nutsegs-1
			rem = mod 360 nutsegs
			if rem<1 then exit
		)
	)
	
	r2 = (nutdia2/2)--+nutplay
	r1 = r2-nutthreaddepth--+nutplay
	d1 = nutthreadpitch/2
	d2 = nutthreadpitch
	turns = (nutht/nutthreadpitch)+1
	density = 360/nutsegs

	ep = editable_mesh name:(uniquename "Thread")
	convertTo ep (Editable_Poly)

	for t=0 to turns*360 by density do
	(
		x	=	r1*cos(t)
		y	=	r1*sin(t)
		z	=	(d2*t/360.0)
		v1 = ep.createVertex [x,y,z]
		x2	=	r2*cos(t)
		y2	=	r2*sin(t)
		v2 = ep.createVertex [x2,y2,z+d1]
		v3 = ep.createVertex [x,y,z+d2]
		
		if t>0 then 
		(
			ep.createFace #(v1,v2,v2-3,v1-3)
			ep.createFace #(v2,v3,v2-2,v1-2)
		)
	)

	ep.weldThreshold = nutweldThreshold
	polyop.weldVertsByThreshold ep #{1..(getnumverts ep)}

	ep.EditablePoly.SetSelection #Edge #{2}
	ep.EditablePoly.SelectEdgeLoop ()
	ep.EditablePoly.chamferEdges nutthreadchamfer
	addmodifier ep (push Push_Value:nutplay)
	addmodifier ep (Cap_Holes ())
	addmodifier ep (smooth autosmooth:on THRESHOLD:30)
	convertTo ep PolyMeshObject

	--boolean
	ep.pos = [0,0,-nutthreadpitch]
	nut = pcy - ep
	delete ep
	convertToPoly (nut)
	nut.name = uniquename "Nut"
	move nut nutpos
	nut.wirecolor = wcol

	selectMore nut
	--show all
	max zoomext sel all

)

fn createnut2 nutpos wcol =
(
	--create the nut
	cy = Cylinder()
	cy.radius = (nutdia1/2)
	cy.height = nutht
	cy.heightsegs = 1
	cy.sides = 6
	cy.smooth = off
	hscale = nutdia1/100.0
	
	pcy = convertToPoly(cy)
	pcy.EditablePoly.SetSelection #Face #{1,8}
	pcy.EditablePoly.ConvertSelection #Face #Edge
	pcy.EditablePoly.chamferEdges (3.0*hscale)
	pcy.EditablePoly.SetSelection #Edge #{24,30}
	pcy.EditablePoly.SelectEdgeRing ()
	pcy.EditablePoly.chamferEdges (11.3*hscale)
	pcy.EditablePoly.chamferEdges (5.5*hscale)
	pcy.EditablePoly.SetSelection #Edge #{19..30, 91..102, 104, 111, 114, 117, 120, 123, 127, 130, 133, 136, 147, 152, 157..158, 161, 164, 167, 170, 175..176, 181, 183, 186, 189, 199..222}
	pcy.EditablePoly.chamferEdges (2.5*hscale)
	pcy.EditablePoly.SetSelection #Edge #{8..9, 11, 13, 15, 17}
	pcy.EditablePoly.chamferEdges (1.0*hscale)
	pcy.EditablePoly.SetSelection #Face #{1,8}
	pcy.bevelFaces 0.0 (-20.0*hscale)
	facecount = pcy.EditablePoly.getnumfaces()
	pcy.EditablePoly.SetSelection #Face #{1..facecount}
	pcy.autoSmoothThreshold = 25
	pcy.EditablePoly.autosmooth ()

	if nutsegs<3 then nutsegs = 3
	if nutsegs>60 then nutsegs = 60
		
	rem = mod 360 nutsegs
	if rem>0 then
	(
		for i=1 to 360 do
		(
			nutsegs = nutsegs-1
			rem = mod 360 nutsegs
			if rem<1 then exit
		)
	)
	
	r2 = (nutdia2/2)--+nutplay
	r1 = r2-nutthreaddepth--+nutplay
	d1 = nutthreadpitch/2
	d2 = nutthreadpitch
	turns = (nutht/nutthreadpitch)+1
	density = 360/nutsegs

	ep = editable_mesh name:(uniquename "Thread")
	convertTo ep (Editable_Poly)

	for t=0 to turns*360 by density do
	(
		x	=	r1*cos(t)
		y	=	r1*sin(t)
		z	=	(d2*t/360.0)
		v1 = ep.createVertex [x,y,z]
		x2	=	r2*cos(t)
		y2	=	r2*sin(t)
		v2 = ep.createVertex [x2,y2,z+d1]
		v3 = ep.createVertex [x,y,z+d2]
		
		if t>0 then 
		(
			ep.createFace #(v1,v2,v2-3,v1-3)
			ep.createFace #(v2,v3,v2-2,v1-2)
		)
	)

	ep.weldThreshold = nutweldThreshold
	polyop.weldVertsByThreshold ep #{1..(getnumverts ep)}

	ep.EditablePoly.SetSelection #Edge #{2}
	ep.EditablePoly.SelectEdgeLoop ()
	ep.EditablePoly.chamferEdges nutthreadchamfer
	addmodifier ep (push Push_Value:nutplay)
	addmodifier ep (Cap_Holes ())
	addmodifier ep (smooth autosmooth:on THRESHOLD:30)
	convertTo ep PolyMeshObject

	--boolean
	ep.pos = [0,0,-nutthreadpitch]
	nut = pcy - ep
	delete ep
	convertToPoly (nut)
	nut.name = uniquename "Nut"
	move nut nutpos
	nut.wirecolor = wcol

	selectMore nut
	--show all
	max zoomext sel all

)

fn createbolt boltpos wcol =
(
	head 	= undefined
	thr 	= undefined
	plain 	= undefined
	
	--create the head
	(
	cy = Cylinder()
	cy.radius = headdia/2
	cy.height = headht
	cy.heightsegs = 1
	cy.sides = 6
	cy.smooth = off
	
	hscale = headdia/100.0
	
	pcy = convertToPoly(cy)
	pcy.EditablePoly.SetSelection #Face #{8}
	pcy.EditablePoly.ConvertSelection #Face #Edge
	pcy.EditablePoly.chamferEdges (3.0*hscale)

	pcy.EditablePoly.SetSelection #Edge #{24}
	pcy.EditablePoly.SelectEdgeRing ()
	pcy.EditablePoly.chamferEdges (11.3*hscale)
	pcy.EditablePoly.chamferEdges (6.3*hscale)
	pcy.EditablePoly.SetSelection #Edge #{19..24, 55..60, 69..70, 75..76, 81..82, 87..88, 93..94, 99..100, 109..120}
	pcy.EditablePoly.chamferEdges (2.8*hscale)
	pcy.EditablePoly.SetSelection #Edge #{2, 4, 6, 9, 12, 15}
	pcy.EditablePoly.chamferEdges (1.0*hscale)
	pcy.EditablePoly.SetSelection #Face #{7}
	pcy.EditablePoly.ConvertSelection #Face #Edge
	pcy.EditablePoly.chamferEdges (1.0*hscale)
	facecount = pcy.EditablePoly.getnumfaces()
	pcy.EditablePoly.SetSelection #Face #{1..facecount}
	pcy.autoSmoothThreshold = 25
	pcy.EditablePoly.autosmooth ()
	
	head = pcy
	)


	
	
	if segs<3 then segs = 3
	if segs>60 then segs = 60
		
	rem = mod 360 segs
	if rem>0 then
	(
		for i=1 to 360 do
		(
			segs = segs-1
			rem = mod 360 segs
			if rem<1 then exit
		)
	)
	
	nothreadht = boltht-threadht
	r2 = threaddia/2
	r1 = r2-threaddepth
	d1 = threadpitch/2
	d2 = threadpitch
	turns = (threadht/threadpitch)+1
	density = 360/segs

	ep = editable_mesh name:(uniquename "Thread")
	convertTo ep (Editable_Poly)

	for t=0 to turns*360 by density do
	(
		x	=	r1*cos(t)
		y	=	r1*sin(t)
		z	=	(d2*t/360.0)
		v1 = ep.createVertex [x,y,z]
		x2	=	r2*cos(t)
		y2	=	r2*sin(t)
		v2 = ep.createVertex [x2,y2,z+d1]
		v3 = ep.createVertex [x,y,z+d2]
		
		if t>0 then 
		(
			ep.createFace #(v1,v2,v2-3,v1-3)
			ep.createFace #(v2,v3,v2-2,v1-2)
		)
	)

	ep.weldThreshold = weldThreshold
	polyop.weldVertsByThreshold ep #{1..(getnumverts ep)}

	ep.EditablePoly.SetSelection #Edge #{2}
	ep.EditablePoly.SelectEdgeLoop ()
	ep.EditablePoly.chamferEdges threadchamfer


	r3 = 2.5*r2
	saw = box width:r3 length:r3 height:r3 lengthsegs:1 widthsegs:1 heightsegs:1 pos:[0,0,d2-r3] wirecolor:black
	boolObj.createBooleanObject ep
	boolObj.SetOperandB ep saw 4 2

	addmodifier ep (Cap_Holes ())
	convertTo ep PolyMeshObject
	fs = polyop.getFaceSelection ep
	polyop.setFaceSelection ep #{fs.count}

	ep.bevelFaces d1 (r1-r2)	
	ep.pivot = [0,0,ep.min.z]	
	ep.pos = [0,0,0]	
	addmodifier ep (smooth autosmooth:on THRESHOLD:30)
	convertTo ep PolyMeshObject
	thr = ep

	nothread = cylinder height: nothreadht radius: r2	heightsegs:1 capsegs:1 sides:segs pos:[0,0,threadht]
	ep.EditablePoly.attach nothread ep	

	--text
	if addmark then
	(
		createmark mtext headdia
		polyop.attach head alltext
	)
 	head.pos = [0,0,nothreadht+threadht]
	
	--attach all
	polyop.attach head thr
	head.name = uniquename "Bolt"
	bolt = head
	bolt.pos = boltpos
	bolt.wirecolor = wcol
	select bolt
	
	--show all
	max zoomext sel all
)

rollout setnab "Settings" --width:180 height:520
(
	groupBox group1 "Bolt" 		pos:[5,  5] width:170 height:250 	
	groupBox group2 "Nut" 		pos:[5,260] width:170 height:240 	
	groupBox group3 "Washer" 	pos:[5,500] width:170 height:120 	
	groupBox group4 "Markings" 	pos:[5,620] width:170 height:70 	
-- 	groupBox group5 "Material" 	pos:[5,525] width:170 height:50 	
	
	label lbl1  "Head Diameter" 	pos:[10, 20]
	label lbl2  "Head Height" 		pos:[10, 40]
	label lbl3  "Bolt Diameter" 		pos:[10, 60]
	label lbl4  "Bolt Height" 		pos:[10, 80]
	label lbl5  "Threaded Height" 	pos:[10,100]
	label lbl6  "Thread Depth" 		pos:[10,120]
	label lbl7  "Thread Pitch" 		pos:[10,140]
	label lbl17  "Thread Chamfer" 	pos:[10,160]
	label lbl18  "Weld Threshold" 		pos:[10,180]
	label lbl19  "Segments" 			pos:[10,200]
	
	label lbl24  "Lock Parameters With Bolt" 	pos:[10,280]
	label lbl8  "Outer Diameter" 	pos:[10,300]
	label lbl9  "Inner Diameter" 	pos:[10,320]
	label lbl10 "Nut Height" 		pos:[10,340]
	label lbl11 "Thread Depth" 	pos:[10,360]
	label lbl12 "Thread Pitch" 		pos:[10,380]
	label lbl20  "Thread Chamfer" 	pos:[10,400]
	label lbl21  "Weld Threshold" 		pos:[10,420]
	label lbl22  "Segments" 		pos:[10,440]
	label lbl23  "Play" 				pos:[10,460]
	
	label lbl13  "Outer Diameter" 	pos:[10,520]
	label lbl14  "Inner Diameter" 	pos:[10,540]
	label lbl15  "Washer Height"	pos:[10,560]
	label lbl25  "Washer Chamfer"	pos:[10,580]

	spinner spn1  pos:[100, 20] width:60 range:[1,1000,20] type:#float scale:0.01 align: #left
	spinner spn2  pos:[100, 40] width:60 range:[1,1000,10] type:#float scale:0.01 align: #left
	spinner spn3  pos:[100, 60] width:60 range:[1,1000,10] type:#float scale:0.01 align: #left
	spinner spn4  pos:[100, 80] width:60 range:[1,1000,50] type:#float scale:0.01 align: #left
	spinner spn5  pos:[100,100] width:60 range:[1,1000,35] type:#float scale:0.01 align: #left
	spinner spn6  pos:[100,120] width:60 range:[0,1000,1] type:#float scale:0.01 align: #left
	spinner spn7  pos:[100,140] width:60 range:[0.01,1000,2] type:#float scale:0.01 align: #left
	spinner spn17  pos:[100,160] width:60 range:[0,100,0.15] type:#float scale:0.01 align: #left
	spinner spn18  pos:[100,180] width:60 range:[0,1, 0.01] type:#float scale:0.001 align: #left
	spinner spn19  pos:[100,200] width:60 range:[3,128, 24] type:#integer align: #left
	
	spinner spn8  pos:[100,300] width:60 range:[1,1000,20] type:#float scale:0.01 align: #left enabled:off
	spinner spn9  pos:[100,320] width:60 range:[1,1000,10] type:#float scale:0.01 align: #left enabled:off
	spinner spn10 pos:[100,340] width:60 range:[1,1000,10] type:#float scale:0.01 align: #left enabled:off
	spinner spn11 pos:[100,360] width:60 range:[0,1000,1] type:#float scale:0.01 align: #left enabled:off
	spinner spn12 pos:[100,380] width:60 range:[0.01,1000,2] type:#float scale:0.01 align: #left enabled:off
	spinner spn20  pos:[100,400] width:60 range:[0,100,0.15] type:#float scale:0.01 align: #left enabled:off
	spinner spn21  pos:[100,420] width:60 range:[0,1, 0.01] type:#float scale:0.001 align: #left enabled:off
	spinner spn22  pos:[100,440] width:60 range:[3,128, 24] type:#integer align: #left enabled:off
	spinner spn23  pos:[100,460] width:60 range:[0,100, 0.25] type:#float scale:0.001 align: #left 

	checkbutton lockbtn pos:[140,270] checked:on images:#("LockButton_i.bmp", "LockButton_a.bmp", 1, 1, 1, 1, 1) tooltip:"Lock parameters with those of the bolt"
	pickbutton pickboltpos "Pick Bolt's Position" pos:[10,225] width:160 tooltip:"Right click to reset"
	checkbox chklink "Link to the Bolt" pos:[10,480] checked:true

	spinner spn14  pos:[100,520] width:60 range:[0,1000,30] type:#float scale:0.01 align: #left
	spinner spn15  pos:[100,540] width:60 range:[0,1000,15] type:#float scale:0.01 align: #left
	spinner spn16 pos:[100,560] width:60 range:[0,1000, 2] type:#float scale:0.01 align: #left
	spinner spn24 pos:[100,580] width:60 range:[0,1000, 1] type:#float scale:0.01 align: #left

	checkbox chklink2 "Link to the Bolt" pos:[10,600] checked:true

	edittext marktxt "Text" pos:[10,640] fieldWidth:130 text:"Nuts & Bolts" labelOnTop:false
	checkbox chkmark "Use" pos:[10,660] checked:true

	local pickedboltpos = undefined
	 
	on pickboltpos picked obj do
	( 
		 if obj != undefined do
		 (
			pickedboltpos = obj
			pickboltpos.text = "Position: " + obj.name
		 )
	)-- on
	
	on pickboltpos rightclick do 
	(
		pickedboltpos = undefined
		pickboltpos.text = "Pick Bolt's Position"
	)
	
	on spn5 changed  val do 
	(
		if val > spn4.value then spn4.value = val
	)
	on spn4 changed  val do 
	(
		if val < spn5.value then spn5.value = val
		if preview then 
		(
			prebolt.height = val
			prebolt.pos = [0,0,-val]
		)
	)
	
	--lock parameters
	on spn1 changed  val do 
	(
		if lockbtn.state==on then 
		(
			spn8.value = val
			if preview then prenut.radius = val/2
		)
		if preview then prehead.radius = val/2
	)
	on spn3 changed  val do 
	(
		if lockbtn.state==on then spn9.value = val
		if preview then prebolt.radius = val/2
	)
	on spn2 changed  val do 
	(
		if lockbtn.state==on then 
		(
			spn10.value = val
			if preview then prenut.height = val
		)
		if preview then prehead.height = val
	)
	on spn6 changed  val do 
	(
		if lockbtn.state==on then spn11.value = val
	)
	on spn7 changed  val do 
	(
		if lockbtn.state==on then spn12.value = val
	)
	on spn17 changed  val do 
	(
		if lockbtn.state==on then spn20.value = val
	)
	on spn8 changed  val do 
	(
		if preview then prenut.radius = val/2
	)
	on spn10 changed  val do 
	(
		if preview then prenut.height = val
	)
	on spn18 changed  val do 
	(
		if lockbtn.state==on then spn21.value = val
	)
	on spn19 changed  val do 
	(
		if lockbtn.state==on then spn22.value = val
	)
	on spn14 changed  val do 
	(
		if preview then prewash.radius1 = val/2
	)
	on spn15 changed  val do 
	(
		if preview then prewash.radius2 = val/2
	)
	on spn16 changed  val do 
	(
		if preview then 
		(
			prewash.height = val
			prewash.pos = [0,0,-val]
		)
	)
	
	on lockbtn changed thestate do
	(
		spn8.enabled = not thestate
		spn9.enabled = not thestate
		spn10.enabled = not thestate
		spn11.enabled = not thestate
		spn12.enabled = not thestate
		spn20.enabled = not thestate
		spn21.enabled = not thestate
		spn22.enabled = not thestate
	)
)

rollout helpnab "Help and About" height:100
(
	label lbl2 "Nuts and Bolts Version 0.3.2"
	label lbl3 "Oormi Creations, May 2018"
	button  hbtn1 "Help" width:160	
	hyperlink hlink1 "Online Help" pos:[65,70] address:"http://oormi.in/software/nutshelp-01.html" color: yellow
	label lbl1 "For more cool scripts, visit:"
	hyperlink hlink2 "Oormi Creations" pos:[55,110] address:"http://oormi.in/software-01.html" color: yellow
	bitmap the_bmp fileName:"nuts_doc//OormiLogo.png"
	
	on hbtn1 pressed do 
	(
		sfile = getSourceFileName()
		spath = getFilenamePath sfile
		hfile = spath + "nutshelp-01.html"
		hext = doesFileExist hfile
		if hext then ShellLaunch hfile ""
		else messageBox ("The file nutshelp-01.html was not found.\n\nPlease copy it to " + spath + "\nOr try the online help link") 
	)
)

rollout NABRollout "Nuts & Bolts :: V 0.3.2"  
(
	groupBox group4 "Actions" 	pos:[5,5] width:170 height:200 	
	button  btn1 "Create Nuts & Bolts"	pos:[10,25] width:160 height:40
	checkbutton chkbolt "Bolt" pos:[10,80] width:120 checked:true tooltip:"Enables Bolts" highlightColor:[80,100,80]
	checkbutton chknut  "Nut"  pos:[10,110] width:120 checked:true tooltip:"Enables Nuts" highlightColor:[80,100,80]
	checkbutton chkwash  "Washer"  pos:[10,140] width:120 checked:true tooltip:"Enables Washers" highlightColor:[80,100,80]
	checkbutton chkprev  "Preview"  pos:[10,170] width:120 checked:off tooltip:"Enables Preview" highlightColor:[80,100,80]
	colorpicker cpbolt color: [200,210,220] width: 40 pos:[130,80]
	colorpicker cpnut color: [160,180,220] width: 40 pos:[130,110]
	colorpicker cpwash color: [90,100,110] width: 40 pos:[130,140]
	colorpicker cpprev color: [150,100,100] width: 40 pos:[130,170]

	on NABRollout close do 
	(
		cleanpreview()
		callbackItem=undefined; 
		gc();
-- 		print "NAB Closed"
	)
	
	on chkprev changed thestate do
	(
		--show preview
		if thestate then
		(
			prehead	= cylinder smooth:off heightsegs:1 capsegs:1 sides:6 height:setnab.spn2.value radius:(setnab.spn1.value/2) wirecolor:cpprev.color renderable:off name:(uniquename "BoltHeadPreview")
			prebolt 	= cylinder smooth:on heightsegs:1 capsegs:1 sides:12 height:setnab.spn4.value radius:(setnab.spn3.value/2) wirecolor:cpprev.color renderable:off name:(uniquename "BoltPreview")
			prenut 	= cylinder smooth:off heightsegs:1 capsegs:1 sides:6 height:setnab.spn10.value radius:(setnab.spn8.value/2) wirecolor:cpprev.color renderable:off name:(uniquename "NutPreview")
			prewash = Tube smooth:on sides:32 capsegs:1 heightsegs:1 radius1:(setnab.spn14.value/2) radius2:(setnab.spn15.value/2) height:setnab.spn16.value wirecolor:cpprev.color renderable:off name:(uniquename "WasherPrevview")
			prewash.pos = [0,0,-prewash.height]
			prebolt.pos = [0,0,-prebolt.height]
			prenut.pos = [0,0,((-prebolt.height/2)-prenut.height)]
			preview = on
		)
		else cleanpreview()
	)
	
	on btn1 pressed do
	(
		mtext		= setnab.marktxt.text
		addmark 	= setnab.chkmark.checked
		washht		= setnab.spn16.value
		washdia1	= setnab.spn14.value
		washdia2	= setnab.spn15.value
		washcham	= setnab.spn24.value
		
		boltht		= setnab.spn4.value
		headht		= setnab.spn2.value
		headdia		= setnab.spn1.value
		segs 			= setnab.spn19.value
		threadht 	= setnab.spn5.value
		threaddia 	= setnab.spn3.value
		threadpitch = setnab.spn7.value
		threaddepth 	= setnab.spn6.value
		weldThreshold = setnab.spn18.value
		threadchamfer = setnab.spn17.value
		
		nutdia1		= setnab.spn8.value
		nutdia2		= setnab.spn9.value
		nutht			= setnab.spn10.value
		nutplay 		= setnab.spn23.value
		nutsegs 		= setnab.spn22.value
		nutthreadpitch 	= setnab.spn12.value
		nutthreaddepth 	= setnab.spn11.value
		nutweldThreshold = setnab.spn21.value
		nutthreadchamfer = setnab.spn20.value
		
		bolt = undefined
		nut = undefined
		washer = undefined

		boltpos = [0,0,0]
		if setnab.pickedboltpos !=undefined then
		(
			if isdeleted setnab.pickedboltpos then 
			(
				setnab.pickedboltpos = undefined
				setnab.pickboltpos.text = "Pick Bolt's Position"
			)
		)
		
		if setnab.pickedboltpos !=undefined then boltpos = setnab.pickedboltpos.pos
		nutpos  = boltpos + [0,0, -(boltht-threadht)-2*nutht]
		
		undo "Nuts & Bolts" on
		(
			ver = maxversion()
			if chkbolt.state == on then createbolt boltpos cpbolt.color
			if chknut.state  == on then 
			(
				if(ver[1]<18000)	then createnut1 nutpos cpnut.color
				else createnut2 nutpos cpnut.color
			)
			if chkwash.state  == on then createwasher boltpos cpwash.color
				
			if setnab.chklink.state == on then 
			(
				if nut !=undefined then nut.parent = bolt
				if washer !=undefined then washer.parent = bolt
			)
		)
		cleanpreview()
		chkprev.checked = off
	)
	
)

fn CallbackFn1 ev nd = 
(
	predel = off
	if prehead != undefined then
	(
		if isdeleted prehead then predel = on
	)
	if prenut != undefined then
	(
		if isdeleted prenut then  predel = on
	)
	if prebolt != undefined then
	(
		if isdeleted prebolt then  predel = on
	)
	if prewash != undefined then
	(
		if isdeleted prewash then  predel = on
	)
	
	if predel then
	(
		preview = off
		NABRollout.chkprev.checked = off
		try (delete prebolt);catch()
		try (delete prenut);catch()
		try (delete prehead);catch()
		try (delete prewash);catch()
		redrawviews()
-- 		print "Preview deleted"
	)
)

callbackItem = NodeEventCallback deleted:CallbackFn1 

nabrf = newRolloutFloater  "Nuts & Bolts" 200 630
addRollout NABRollout  nabrf
addRollout setnab  nabrf
addRollout helpnab  nabrf

)
