# ##### BEGIN GPL 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.
#
#  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

__bpydoc__ = """\
The MeshSymm addon enables selecting and constructing of mesh elements with n-point symmetry.


Documentation

First go to User Preferences->Addons and enable the MeshSymm addon in the Mesh category.
Activate it (button in the Mesh Tools panel).

Click "Start MeshSymm" at the bottom of the Mesh Tools area.

MeshSymm overrides standard viewport behaviour, it is made to center on the 3D cursor constantly,
this way symmetry is always built around a center point.  (When rotating the view, small corrections
will be made cause Blender doesnt rotate exactly around the view center.)  This behaviour could
change in the future, dont hesitate to propose other systems!

Once started, the Mesh Tool panels shows some options: first the number of points ("# points")...
It allows you to choose the number of points used on a circle around the 3Dcursor center.  The
points are visualized through a number of small lightblue circles around the center.


Then theres the "Select" and "Construct" tick boxes allow to toggle on/off the symmetrical mesh
constructing and/or the symmetrical mesh selection.

Selection :  when toggled on, when rightclicking/border/circle selecting, the addon will look
if theres any mesh element on the symmetrical positions around the center and will select them.
Right-clicking again will deselect all symmetrical elements.  When looking for symmetrical
elements, the addon will select everything within the "Tolerance" distance set in the panel.
Whenever you want to select normally again, just uncheck "Select".

Construction :  when constructing using Ctrl-Shift-leftclick (BEWARE Ctrl-leftclick doesnt work
with symmetry at the moment, because it deforms the mesh such that symmetry is not always
possible...) or constructing using Fkey / bevelling with Ctrl-Shift-Bkey / Ekey, the addon will
symmetrize the newly constructed mesh elements.  More work can be done here, let me know
which construction shortcut functions you would like to see symmetrized!
BEWARE only construction using hotkeys works, menu selections will be ignored.
Whenever you want to construct normally again, just uncheck "Construct".

Click "Stop MeshSymm" to restore Blender to normal behaviour.
"""


bl_info = {
	"name": "MeshSymm",
	"author": "Gert De Roost",
	"version": (0, 1, 3),
	"blender": (2, 6, 7),
	"location": "View3D > Tools",
	"description": "Enables selecting and constructing of mesh elements with n-point symmetry.",
	"warning": "",
	"wiki_url": "",
	"tracker_url": "",
	"category": "Mesh"}


import bpy
from bpy_extras import *
from bgl import *
import bmesh
from mathutils import *
import math




npoints = 4
do_check = 0
zooming = 0
rotating = 0
started = 0
do_selection = 0
foundnew = False
foundsel = False
foundset = set([])
savestate = 1
deselvert = None
deseledge = None
deselface = None
cumul = 0


bpy.types.Scene.Npoints = bpy.props.IntProperty(
		name = "# points", 
		description = "Sets the number of symmetrical points",
		min = 2,
		max = 1000,
		default = 4)

bpy.types.Scene.Tolerance = bpy.props.FloatProperty(
		name = "Tolerance", 
		description = "Sets the tolerance in which vertices are found",
		min = 0.0001,
		max = 10,
		default = 0.0001)

bpy.types.Scene.Construct = bpy.props.BoolProperty(
		name = "Construct", 
		description = "Turns symmetrical construction on/off",
		default = True)

bpy.types.Scene.Select = bpy.props.BoolProperty(
		name = "Select", 
		description = "Turns symmetrical selection on/off",
		default = True)





class SimpleMouseOperator(bpy.types.Operator):
	bl_idname = "wm.mouse_position"
	bl_label = "Invoke Mouse Operator"

	def invoke(self, context, event):

		global mx, my

		mx = event.mouse_region_x
		my = event.mouse_region_y

		return {'FINISHED'}


class MeshSymmStop(bpy.types.Operator):
	bl_idname = "meshsymm.stop"
	bl_label = "Stop MeshSymm"
	bl_description = "Stop MeshSymm"
	bl_options = {"REGISTER", "UNDO"}
	
	def invoke(self, context, event):
		
		global started
		
		started = 0
		bm.free()
		if eval(str(bpy.app.build_revision)[2:7]) >= 53207:
			bpy.types.SpaceView3D.draw_handler_remove(_handle, "WINDOW")
		else:
			context.region.callback_remove(_handle)
		bpy.context.user_preferences.edit.use_global_undo = save_global_undo
		bpy.ops.object.editmode_toggle()
		bpy.ops.object.editmode_toggle()
		
		return {'FINISHED'}


class MeshSymmStart(bpy.types.Operator):
	bl_idname = "mesh.meshsymm"
	bl_label = "Start MeshSymm"
	bl_description = "Enables selecting and constructing of mesh elements with n-point symmetry"
	bl_options = {"REGISTER", "UNDO"}
	
	@classmethod
	def poll(cls, context):
		obj = context.active_object
		return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
		
	def invoke(self, context, event):
	
		global _handle, save_global_undo
	
		save_global_undo = bpy.context.user_preferences.edit.use_global_undo
		bpy.context.user_preferences.edit.use_global_undo = False
		
		enter_meshsymm(self)
		
		context.window_manager.modal_handler_add(self)
		if eval(str(bpy.app.build_revision)[2:7]) >= 53207:
			_handle = bpy.types.SpaceView3D.draw_handler_add(drawcursor, (), 'WINDOW', 'POST_PIXEL')
		else:
			_handle = context.region.callback_add(drawcursor, (), 'POST_PIXEL')
		
		return {'RUNNING_MODAL'}

	def modal(self, context, event):
		
		global mx, my, rotating
		global do_check, do_selection
		
		if event.type == "NONE":
			return {'PASS_THROUGH'}
		
		scn = bpy.context.scene
		
		rotating = 0
		
		mx = event.mouse_region_x
		my = event.mouse_region_y
			
		if event.type in ["LEFT_SHIFT", "LEFT_CTRL"]:
			return {'PASS_THROUGH'}
				
		if do_check == 1:
			do_selection = 1
			region.tag_redraw()
			
		if do_check == 2:
			do_check = 1
			region.tag_redraw()
			
		if do_check == 6:
			do_check = 4
			region.tag_redraw()
	
		if not(event.type == "MOUSEMOVE"):
			print (event.type, event.value)

		if event.type in ["MIDDLEMOUSE"]:
			rotating = 1
			region.tag_redraw()
			return {'PASS_THROUGH'}
			
		if event.type in ["RIGHTMOUSE"]:
			if scn.Select:
				if event.value in ["RELEASE"]:
					return {'PASS_THROUGH'}
				if event.value == "CLICK":
					do_selection = 1
					do_check = 0
					region.tag_redraw()
					return {'PASS_THROUGH'}
				do_check = 1
				region.tag_redraw()
				return {'PASS_THROUGH'}
			else:
				do_check = 5
				region.tag_redraw()
				return {'PASS_THROUGH'}
			
		if event.type in ["B"] and event.ctrl and event.shift:
			if "VERT" in bm.select_mode:
				bmelements = list(bm.verts)
			elif "EDGE" in bm.select_mode:
				bmelements = list(bm.edges)
			elif "FACE" in bm.select_mode:
				bmelements = list(bm.faces)
			for elem in bmelements:
				if elem.select:
					if "VERT" in bm.select_mode:
						local = [elem]
					else:
						local = list(elem.verts)
					checkselverts(elem, local, bmelements, 1)
					for elem2 in foundset:
						elem2.select = 1
			mesh.update()
			return {'PASS_THROUGH'}
		
		if event.type in ["B"]:
			do_check = 2
			do_selection = 1
			region.tag_redraw()
			return {'PASS_THROUGH'}
			
		if scn.Construct:
			if event.type in ["LEFTMOUSE"] and event.ctrl and event.shift:
				if event.value in ["PRESS", "RELEASE"]:
					return {'PASS_THROUGH'}
				do_check = 4
				region.tag_redraw()
				return {'PASS_THROUGH'}
			if event.type in ["F"]:
				if event.value in ["PRESS"]:
					return {'PASS_THROUGH'}
				do_check = 4
				region.tag_redraw()
				return {'PASS_THROUGH'}
			if event.type in ["E", "DEL"]:
				do_check = 6
				region.tag_redraw()
				return {'PASS_THROUGH'}
			
		if event.type in ["C"]:
			do_check = 2
			do_selection = 1
			region.tag_redraw()
			return {'PASS_THROUGH'}
			
		if event.type in ["ESC"]:
			do_check = 0
			return {'PASS_THROUGH'}
	
		if event.type in ["MOUSEMOVE", "INBETWEEN_MOUSEMOVE"] and do_check == 0:
			region.tag_redraw()
			return {'PASS_THROUGH'}
		
		if event.type in ["MOUSEMOVE", "INBETWEEN_MOUSEMOVE"]:
			return {'PASS_THROUGH'}
		
		do_check = 5
		region.tag_redraw()
		
		return {'PASS_THROUGH'}


def panel_func(self, context):
	
	global radius
	
	scn = bpy.context.scene
	radius = 20
	self.layout.label(text="MeshSymm:")
	if not(started):
		self.layout.operator("mesh.meshsymm", text="Start MeshSymm")
	else:
		self.layout.operator("meshsymm.stop", text="Stop MeshSymm")
		self.layout.prop(scn, "Construct")
		self.layout.prop(scn, "Select")
		self.layout.prop(scn, "Npoints")
		self.layout.prop(scn, "Tolerance")
	

def register():
	bpy.utils.register_module(__name__)
	bpy.types.VIEW3D_PT_tools_meshedit.append(panel_func)
	bpy.types.VIEW3D_PT_tools_objectmode.append(panel_func)


def unregister():
	bpy.utils.unregister_module(__name__)
	bpy.types.VIEW3D_PT_tools_meshedit.remove(panel_func)
	bpy.types.VIEW3D_PT_tools_objectmode.remove(panel_func)


if __name__ == "__main__":
	register()






def adapt():
	
	global matrix
	
	# Rotating / panning / zooming 3D view is handled here.
	# Calculate matrix.
	if selobj.rotation_mode == "AXIS_ANGLE":
		# object rotationmode axisangle
		ang, x, y, z =  selobj.rotation_axis_angle
		matrix = Matrix.Rotation(-ang, 4, Vector((x, y, z)))
	elif selobj.rotation_mode == "QUATERNION":
		# object rotationmode quaternion
		w, x, y, z = selobj.rotation_quaternion
		x = -x                      
		y = -y
		z = -z
		quat = Quaternion([w, x, y, z])
		matrix = quat.to_matrix()
		matrix.resize_4x4()
	else:
		# object rotationmode euler
		ax, ay, az = selobj.rotation_euler
		mat_rotX = Matrix.Rotation(-ax, 4, 'X')
		mat_rotY = Matrix.Rotation(-ay, 4, 'Y')
		mat_rotZ = Matrix.Rotation(-az, 4, 'Z')
	if selobj.rotation_mode == "XYZ":
		matrix = mat_rotX * mat_rotY * mat_rotZ
	elif selobj.rotation_mode == "XZY":
		matrix = mat_rotX * mat_rotZ * mat_rotY
	elif selobj.rotation_mode == "YXZ":
		matrix = mat_rotY * mat_rotX * mat_rotZ
	elif selobj.rotation_mode == "YZX":
		matrix = mat_rotY * mat_rotZ * mat_rotX
	elif selobj.rotation_mode == "ZXY":
		matrix = mat_rotZ * mat_rotX * mat_rotY
	elif selobj.rotation_mode == "ZYX":
		matrix = mat_rotZ * mat_rotY * mat_rotX

	# handle object scaling
	sx, sy, sz = selobj.scale
	mat_scX = Matrix.Scale(sx, 4, Vector([1, 0, 0]))
	mat_scY = Matrix.Scale(sy, 4, Vector([0, 1, 0]))
	mat_scZ = Matrix.Scale(sz, 4, Vector([0, 0, 1]))
	matrix = mat_scX * mat_scY * mat_scZ * matrix


def getscreencoords(pvector):
	# calculate screencoords of given Vector
	region = bpy.context.region
	rv3d = bpy.context.space_data.region_3d	
#	pvector = vector * matrix
#	pvector = pvector + selobj.location
	
	svector = view3d_utils.location_3d_to_region_2d(region, rv3d, pvector)
	if svector == None:
		return Vector((0, 0))
	else:
		return Vector((svector[0], svector[1]))
		



def enter_meshsymm(self):

	global bm, mesh, selobj, region, started
	global oldselverts, oldseledges, oldselfaces, oldvcos, oldecos, oldfcos
	global oldbmverts, oldbmedges, oldbmfaces

	# main operation
	started = 1
	context = bpy.context
	region = context.region  
	selobj = bpy.context.active_object
	mesh = selobj.data
	bm = bmesh.from_edit_mesh(mesh)
	area = bpy.context.area
	
	oldselverts = []
	oldseledges = []
	oldselfaces = []
	for v in bm.verts:
		if v.select:
			oldselverts.append(v)
	for e in bm.edges:
		if e.select:
			oldseledges.append(e)
	for f in bm.faces:
		if f.select:
			oldselfaces.append(f)
				
	oldvcos = [Vector(v.co[:]) for v in bm.verts]
	oldecos = []
	for e in bm.edges:
		oldecos.append([])
		for v in e.verts:
			oldecos[-1].append(Vector(v.co[:]))
	oldfcos = []
	for f in bm.faces:
		oldfcos.append([])
		for v in f.verts:
			oldfcos[-1].append(Vector(v.co[:]))
			
	oldbmverts = list(bm.verts)
	oldbmedges = list(bm.edges)
	oldbmfaces = list(bm.faces)
	
	adapt()
		
		
		
		

def checkselverts(element, localverts, bmelements, state):

	global savestate, found, foundset, foundlist

	scn = bpy.context.scene

	center = bpy.context.space_data.cursor_location
	rv3d = bpy.context.space_data.region_3d
	eye = Vector(rv3d.view_matrix[2][:3])
	eyevec = rv3d.view_location + eye
	x1 = rv3d.view_location
	x2 = eyevec
	A = x1
	B = x2
	
	mirr = []
	for n in range(npoints):
		mirr.append([])
	for i in range(len(localverts)):
		eco = localverts[i].co * matrix + selobj.location
		esco = getscreencoords(eco)
		startang = (esco - getscreencoords(center)).angle_signed(Vector((1, 0)))
		x0 = eco
		radius = ((x0 - x1).cross((x0 - x2)).length) / (x2 - x1).length
		P = x0
		Pp = ((B-A).dot((P-A)) / ((B-A).length**2))*(B-A) + A
		for n in range(npoints):
			rmat = Matrix.Rotation(math.radians((360 / npoints) * n), 3, eye)
			mi = Vector(((math.cos(startang) * radius), math.sin(startang) * radius, 0))
			mi = mi * rv3d.view_matrix.to_3x3()
			mi = rmat * mi
			mi += Pp
			mirr[n].append(mi)
	tol = scn.Tolerance
	foundlist = []
	for n in range(npoints):
		foundlist.append(None)
	if not(cumul):
		foundset = set([])
	for elem2 in bmelements:
		if elem2 in foundset:
			continue
		if len(localverts) > 2:
			if len(element.verts) != len(elem2.verts):
				continue
		coset = set([])
		if len(localverts) == 1:
			coset.add((elem2.co * matrix + selobj.location)[:])
		else:
			for j in range(len(localverts)):
				coset.add((elem2.verts[j].co * matrix + selobj.location)[:])
			
		for n in range(npoints):
			savset = set(coset)
			def check(co1):
				foundco = False
				for co2 in coset:
					co2 = Vector(co2)
					if abs(co1[0] - co2[0]) <= tol:
						if abs(co1[1] - co2[1]) <= tol:
							if abs(co1[2] - co2[2]) <= tol:
								foundco = co2[:]
				if foundco:
					coset.remove(foundco)
					
			for j in range(len(localverts)):
				check(mirr[n][j])
			if len(coset) == 0:
				found = 1
				foundlist[n] = elem2
				foundset.add(elem2)
				savestate = state
			coset = set(savset)
	return found



def drawcursor():
	
	global npoints, center, do_check, mx, my, zooming
	global selverts, oldselverts, seledges, oldseledges, selfaces, oldselfaces 
	global oldbmverts, oldbmedges, oldbmfaces, oldvcos, oldecos, oldfcos
	global do_selection, cumul
	global deselvert, deseledge, deselface, foundnew, foundsel, foundlist, foundset, savestate
	
	scn = bpy.context.scene
	
	bpy.ops.wm.mouse_position('INVOKE_DEFAULT')
	
	if zooming == 0 and not(rotating):
		x, y = getscreencoords(bpy.context.space_data.cursor_location)
		if abs(x - region.width/2) > 1 and abs(y - region.height/2) > 1:
			zooming = 1
			bpy.ops.view3d.view_center_cursor()
	else:
		x, y = getscreencoords(bpy.context.space_data.cursor_location)
		if abs(x - region.width/2) <= 1 and abs(y - region.height/2) <= 1:
			zooming = 0
			
	if do_check == 5:
		do_check = 0
		
		oldselverts = []
		oldseledges = []
		oldselfaces = []
		oldbmverts = list(bm.verts)
		oldbmedges = list(bm.edges)
		oldbmfaces = list(bm.faces)
		oldselverts = [v for v in bm.verts if v.select]
		oldseledges = [e for e in bm.edges if e.select]
		oldselfaces = [f for f in bm.faces if f.select]

		oldvcos = [Vector(v.co[:]) for v in bm.verts]
		oldecos = []
		for e in bm.edges:
			oldecos.append([])
			for v in e.verts:
				oldecos[-1].append(Vector(v.co[:]))
		oldfcos = []
		for f in bm.faces:
			oldfcos.append([])
			for v in f.verts:
				oldfcos[-1].append(Vector(v.co[:]))
	
	
	if do_check > 0:
		if do_check == 1:
			do_check = 0
		npoints = scn.Npoints
		adapt()
		selverts = [v for v in bm.verts if v.select]
		seledges = [e for e in bm.edges if e.select]
		selfaces = [f for f in bm.faces if f.select]
		selobj = bpy.context.active_object
		bmverts = list(bm.verts)
		bmedges = list(bm.edges)
		bmfaces = list(bm.faces)
		oldnewv = []
		elist = []
		vdict = {}
		mirr = []
		found = 0
		foundsel = 0
		foundnew = 0
		foundvert = 0
		foundedge = 0
		if scn.Construct and do_check == 4:
			do_check = 0
			
			def deleteVEF(selelements, oldselelements, kind):
				vs = [v for v in bm.verts if v.select]
				es = [e for e in bm.edges if e.select]
				fs = [f for f in bm.faces if f.select]
				for el1 in oldselelements:
					if not(el1 in selelements):
						bpy.ops.mesh.select_all(action="DESELECT")
						if kind == "VERT":
							elco = oldvcos[oldselverts.index(el1)]
							el2 = bm.verts.new(elco)
							checkselverts(el2, [el2], bm.verts, 1)
						elif kind == "EDGE":
							elco = oldecos[oldbmedges.index(el1)]
							vli = [oldbmverts[oldvcos.index(co)] for co in elco]
							el2 = bm.edges.new(vli)
							checkselverts(el2, el2.verts, bm.edges, 1)
						elif kind == "FACE":
							elco = oldfcos[oldbmfaces.index(el1)]
							vli = [oldbmverts[oldvcos.index(co)] for co in elco]
							el2 = bm.faces.new(vli)
							checkselverts(el2, el2.verts, bm.faces, 1)
						bmesh.update_edit_mesh(mesh, tessface=True, destructive=True)
						for v in foundset:
							v.select = 1
						mesh.update()
						if kind == "FACE":
							kind = "ONLY_FACE"
						bpy.ops.mesh.delete(type=kind)
					for v in vs:
						v.select = 1
					for e in es:
						e.select = 1
					for f in fs:
						f.select = 1

			# Check for deleted elements
			deleteVEF(bmverts, oldbmverts, "VERT")
			deleteVEF(bmedges, oldbmedges, "EDGE")
			deleteVEF(bmfaces, oldbmfaces, "FACE")


			# Check for new verts
			center = bpy.context.space_data.cursor_location
			rv3d = bpy.context.space_data.region_3d
			eye = Vector(rv3d.view_matrix[2][:3])
			eyevec = rv3d.view_location + eye
			x1 = rv3d.view_location
			x2 = eyevec
			A = x1
			B = x2
			for v in bmverts:
				if not(v in oldbmverts):
					print ("CONSTRUCT")
					vco = v.co * matrix + selobj.location
					vsco = getscreencoords(vco)
					startang = (vsco - getscreencoords(center)).angle_signed(Vector((1, 0)))
					x0 = vco
					radius = ((x0 - x1).cross((x0 - x2)).length) / (x2 - x1).length
					P = x0
					Pp = ((B-A).dot((P-A)) / ((B-A).length**2))*(B-A) + A
					for n in range(1, npoints, 1):
						rmat = Matrix.Rotation(math.radians((360 / npoints) * n), 3, eye)
						mirr.append(Vector(((math.cos(startang) * radius), math.sin(startang) * radius, 0)))
						mirr[-1] = mirr[-1] * rv3d.view_matrix.to_3x3()
						mirr[-1] = rmat * mirr[-1]
						mirr[-1] += Pp
						mi = mirr[-1]
						mi -= selobj.location
						mi = mi * matrix.inverted()
						newv = bm.verts.new(mi)
						foundnew = 1
						bm.verts.index_update()
						oldnewv.append(newv)
						foundvert = 1
					bmesh.update_edit_mesh(mesh, tessface=True, destructive=True)		


			def constructEF(bmelements, oldbmelements):
				vs = [v for v in bm.verts if v.select]
				es = [e for e in bm.edges if e.select]
				fs = [f for f in bm.faces if f.select]
				modelist = bpy.context.tool_settings.mesh_select_mode
				if modelist[2]:
					savmode = "FACE"
				if modelist[1]:
					savmode = "EDGE"
				if modelist[0]:
					savmode = "VERT"
				bpy.ops.mesh.select_mode(type='VERT')	
				for el in bmelements:
					if not(el in oldbmelements):
						print ("EDGEFACE")
						elvlists = []
						for i in range(npoints):
							elvlists.append([])
						if len(el.verts) == 2:
							elverts = list(el.verts)
						else:
							elverts = []
							for l1 in el.loops:
								elverts.append(l1.vert)
						for v1 in elverts:
							checkselverts(v1, [v1], bm.verts, 1)
							if not(None in foundlist):
								for i, v2 in enumerate(foundlist): 
									elvlists[i].append(v2)
							else:
								bpy.ops.mesh.select_mode(type=savmode)	
								bpy.ops.mesh.select_all(action="DESELECT")
								for v in vs:
									v.select = 1
								for e in es:
									e.select = 1
								for f in fs:
									f.select = 1
								return
						for elvl in elvlists:
							bpy.ops.mesh.select_all(action="DESELECT")
							for v in elvl:
								v.select = 1
							mesh.update()
							bpy.ops.mesh.edge_face_add()
				bpy.ops.mesh.select_mode(type=savmode)	
				bpy.ops.mesh.select_all(action="DESELECT")
				for v in vs:
					v.select = 1
				for e in es:
					e.select = 1
				for f in fs:
					f.select = 1
					
					
			# Check for new edges
			bmedges = list(bm.edges)
			constructEF(bmedges, oldbmedges)
			
			# Check for new faces
			bmfaces = list(bm.faces)
			constructEF(bmfaces, oldbmfaces)
			
			# Updating...
			bmesh.update_edit_mesh(mesh, tessface=True, destructive=True)		
			mesh.update(calc_tessface=True, calc_edges=True)
			# And then making normals uniform
			vs = []
			for v in bm.verts:
				if v.select:
					vs.append(v)
			es = []
			for e in bm.edges:
				if e.select:
					es.append(e)
			fs = []
			for f in bm.faces:
				if f.select:
					fs.append(f)
			bpy.ops.mesh.select_all(action="SELECT")
			bpy.ops.mesh.normals_make_consistent(inside=False)
			bpy.ops.mesh.select_all(action="DESELECT")
#			if "VERT" in bm.select_mode:
			for v in vs:
				v.select = 1
#			if "EDGE" in bm.select_mode:
			for e in es:
				e.select = 1
#			if "FACE" in bm.select_mode:
			for f in fs:
				f.select = 1
			# Setting 'old' lists for remebering values
			oldbmverts = list(bm.verts)
			oldbmedges = list(bm.edges)
			oldbmfaces = list(bm.faces)
					
					
		if scn.Select:
			if not(foundnew):		
				
				cumul = 1
				
				if "VERT" in bm.select_mode:
				# Look if any verts were selected
					for v1 in selverts:
						if not(v1 in oldselverts):
								
							foundsel = checkselverts(v1, [v1], bm.verts, 1)
											
				if "EDGE" in bm.select_mode:
					# Look if any edges were selected
					for e1 in seledges:
						if not(e1 in oldseledges):
	
							foundsel = checkselverts(e1, e1.verts, bm.edges, 1)
											
				if "FACE" in bm.select_mode:
					# Look if any faces were selected
					for f1 in selfaces:
						if not(f1 in oldselfaces):
	
							foundsel = checkselverts(f1, f1.verts, bm.faces, 1)


				if not(foundsel):
					if "VERT" in bm.select_mode:
						# Look if anything was deselected
						for v1 in oldselverts:
							if not(v1 in selverts):
										
								checkselverts(v1, [v1], bm.verts, 0)
								deselvert = v1
											
					if "EDGE" in bm.select_mode:
						# Look if any edges were selected
						for e1 in oldseledges:
							if not(e1 in seledges):
		
								checkselverts(e1, e1.verts, bm.edges, 0)
								deseledge = e1
												
					if "FACE" in bm.select_mode:
						# Look if any faces were selected
						for f1 in oldselfaces:
							if not(f1 in selfaces):
		
								checkselverts(f1, f1.verts, bm.faces, 0)
								deselface = f1
								
				cumul = 0
			
	elif do_selection:
		do_selection = 0
		print ("ACTION", savestate)
		print (foundset)
		if not(foundset == set([])):
			for elem in foundset:
				elem.select = savestate
			foundset = set([])
			bm.select_flush(0)
		
		# Updating...
#		bmesh.update_edit_mesh(mesh, tessface=True, destructive=True)		
		mesh.update()
		# Setting 'old' lists for remebering values
		oldselverts = [v for v in bm.verts if v.select]
		oldseledges = [e for e in bm.edges if e.select]
		oldselfaces = [f for f in bm.faces if f.select]
		
		oldvcos = [Vector(v.co[:]) for v in bm.verts]
		oldecos = []
		for e in bm.edges:
			oldecos.append([])
			for v in e.verts:
				oldecos[-1].append(Vector(v.co[:]))
		oldfcos = []
		for f in bm.faces:
			oldfcos.append([])
			for v in f.verts:
				oldfcos[-1].append(Vector(v.co[:]))
				
		region.tag_redraw()
	
	
	# Updating...
#	bmesh.update_edit_mesh(mesh, tessface=True, destructive=True)		
	mesh.update(calc_tessface=True, calc_edges=True)
		
	
	# Drawing point-circles
	center = bpy.context.space_data.cursor_location
	c = getscreencoords(center)
	mouse = Vector((mx, my))
	r = (c - mouse).length
	startang = (mouse - getscreencoords(center)).angle_signed(Vector((1, 0)))
	glColor3f(0.7, 0.7, 1.0)
	for i in range(npoints):
		angle = (i * 2 * math.pi / npoints) + startang
		p = (c[0] + (math.cos(angle) * r), c[1] + (math.sin(angle) * r))
		glBegin(GL_LINE_LOOP)
		for j in range(100):
			angle = j * 2 * math.pi / 100
			glVertex2f(p[0] + (math.cos(angle) * 20), p[1] + (math.sin(angle) * 20))
		glEnd()
		

