# ##### 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 RotView addon serves the purpose of setting fixed rotation values for each of the
right/left/front/back/top/bottom views.


Documentation

First go to User Preferences->Addons and enable the RotView addon in the 3D View category.
To change the rotation in realtime first press one of the numerical keypad
view shortcuts to switch into a view and set the rotation
value with the slider (doubleclick for keyboard input) or use the <-90 and 90-> buttons to
switch to the next multiple of 90 degrees value.  Button 0 goes back to zero rotation.
The rotation value of each of the views will be remembered when switching into it again from
the numerical keypad.

REMARK - when first enabling the addon, when in an affected view already, rotation will not work.
		 Enable the view again with numerical keypad shortcut.
		 
REMARK - will not work when switching view through the View menu
"""


bl_info = {
	"name": "RotView",
	"author": "Gert De Roost",
	"version": (0, 3, 0),
	"blender": (2, 80, 0),
	"location": "View3D > UI",
	"description": "Set fixed view rotation values",
	"warning": "",
	"wiki_url": "",
	"tracker_url": "",
	"category": "3D View"}


import bpy
from mathutils import *
import math
from time import sleep


activated = 0



class MyProps(bpy.types.PropertyGroup):
	Angle = bpy.props.FloatProperty(
			name = "Rotation angle", 
			description = "Enter rotation angle",
			default = 0)


class PANEL_PT_RotViewPanel(bpy.types.Panel):
	bl_label = "RotViewPanel"
	bl_space_type = "VIEW_3D"
	bl_region_type = 'UI'
	bl_category = "RotView"
	

	def draw(self, context):
		
		scn = context.scene
		layout = self.layout
		
		if activated:
			layout.prop(scn.my_props, "Angle")
			
			row = layout.row()
			row.operator("view.minus90",
				text="<-90")
			row.operator("view.nill",
				text="0")
			row.operator("view.plus90",
				text="90->")
		elif not(activated):
			layout.operator("view3d.rotview", text="Activate")
		

class Minus90(bpy.types.Operator):
	bl_idname = "view.minus90"
	bl_label = ""
	bl_description = "To next 90 degrees multiple"


	def invoke(self, context, event):
		scn = bpy.context.scene
		scn.my_props.Angle -= 90
		if scn.my_props.Angle <= -360:
			scn.my_props.Angle += 720
		return {'FINISHED'}

class Plus90(bpy.types.Operator):
	bl_idname = "view.plus90"
	bl_label = ""
	bl_description = "To previous 90 degrees multiple"


	def invoke(self, context, event):
		scn = bpy.context.scene
		scn.my_props.Angle += 90
		if scn.my_props.Angle > 360:
			scn.my_props.Angle -= 720
		return {'FINISHED'}
	
class Nill(bpy.types.Operator):
	bl_idname = "view.nill"
	bl_label = ""
	bl_description = "Set rotation to 0"


	def invoke(self, context, event):
		scn = bpy.context.scene
		scn.my_props.Angle = 0
		return {'FINISHED'}
	

class VIEW3D_OT_RotView(bpy.types.Operator):
	bl_idname = "view3d.rotview"
	bl_label = "RotView"
	bl_description = "Set fixed view rotation values"
	bl_options = {"REGISTER"}


	def invoke(self, context, event):
		
		global activated
		
		activated = 1
		self.inview = False
		self.oldangle = 0
		self.oldview = 0
		self.viewnum = 0
		self.oldfrontloc = None
		self.oldbackloc = None
		self.oldrightloc = None
		self.oldleftloc = None
		self.oldtoploc = None
		self.oldbottomloc = None
		self.oldfrontquat = None
		self.oldbackquat = None
		self.oldrightquat = None
		self.oldleftquat = None
		self.oldtopquat = None
		self.oldbottomquat = None
		self.oldangle = 0
		
		context.window_manager.modal_handler_add(self)
		wm = context.window_manager
		self._timer = wm.event_timer_add(time_step=0.1, window=context.window)
		
		
		return {'RUNNING_MODAL'}

	def modal(self, context, event):
		
		scn = context.scene
		if event.type == 'TIMER':
			self.redraw()
		if event.type == "MIDDLEMOUSE":
			self.inview = False
			
		return {"PASS_THROUGH"}

	def redraw(self):
	
		scn = bpy.context.scene
			
		matrotX = Matrix.Rotation(math.radians(90), 3, 'X')
		matrotY = Matrix.Rotation(math.radians(0), 3, 'Y')
		matrotZ = Matrix.Rotation(math.radians(0), 3, 'Z')
		self.quat = matrotX.to_quaternion()
		self.quat.rotate(matrotY)
		self.quat.rotate(matrotZ)
		if (self.oldfrontloc != None):
			 bpy.context.space_data.region_3d.view_location = self.oldfrontloc 
		if (self.oldfrontquat == None):
			self.oldfrontquat = self.quat
		elif (self.quat == bpy.context.space_data.region_3d.view_rotation and self.quat != self.oldfrontquat):
			bpy.context.space_data.region_3d.view_rotation = self.oldfrontquat
		if int(self.oldfrontquat[0] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[0] * 10000 + 0.5):
			if int(self.oldfrontquat[1] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[1] * 10000 + 0.5):
				if int(self.oldfrontquat[2] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[2] * 10000 + 0.5):
					if int(self.oldfrontquat[3] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[3] * 10000 + 0.5):
						self.inview = True
						matrotX = Matrix.Rotation(math.radians(90), 3, 'X')
						matrotY = Matrix.Rotation(math.radians(-scn.my_props.Angle), 3, 'Y')
						matrotZ = Matrix.Rotation(math.radians(0), 3, 'Z')
						self.quat = matrotX.to_quaternion()
						self.quat.rotate(matrotY)
						self.quat.rotate(matrotZ)
						bpy.context.space_data.region_3d.view_rotation = self.quat
						self.oldfrontquat = bpy.context.space_data.region_3d.view_rotation.copy()
						self.oldfrontloc = bpy.context.space_data.region_3d.view_location.copy()
			
		matrotX = Matrix.Rotation(math.radians(90), 3, 'X')
		matrotY = Matrix.Rotation(math.radians(0), 3, 'Y')
		matrotZ = Matrix.Rotation(math.radians(180), 3, 'Z')
		self.quat = matrotX.to_quaternion()
		self.quat.rotate(matrotY)
		self.quat.rotate(matrotZ)
		if (self.oldbackloc != None):
			 bpy.context.space_data.region_3d.view_location = self.oldbackloc 
		if (self.oldbackquat == None):
			self.oldbackquat = self.quat
		elif (self.quat == bpy.context.space_data.region_3d.view_rotation and self.quat != self.oldbackquat):
			bpy.context.space_data.region_3d.view_rotation = self.oldbackquat
		if int(self.oldbackquat[0] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[0] * 10000 + 0.5):
			if int(self.oldbackquat[1] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[1] * 10000 + 0.5):
				if int(self.oldbackquat[2] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[2] * 10000 + 0.5):
					if int(self.oldbackquat[3] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[3] * 10000 + 0.5):
						self.inview = True
						matrotX = Matrix.Rotation(math.radians(90), 3, 'X')
						matrotY = Matrix.Rotation(math.radians(-scn.my_props.Angle), 3, 'Y')
						matrotZ = Matrix.Rotation(math.radians(180), 3, 'Z')
						self.quat = matrotX.to_quaternion()
						self.quat.rotate(matrotY)
						self.quat.rotate(matrotZ)
						bpy.context.space_data.region_3d.view_rotation = self.quat
						self.oldbackquat = bpy.context.space_data.region_3d.view_rotation.copy()
						self.oldbackloc = bpy.context.space_data.region_3d.view_location.copy()
	
		matrotX = Matrix.Rotation(math.radians(0), 3, 'X')
		matrotY = Matrix.Rotation(math.radians(90), 3, 'Y')
		matrotZ = Matrix.Rotation(math.radians(90), 3, 'Z')
		self.quat = matrotZ.to_quaternion()
		self.quat.rotate(matrotY)
		self.quat.rotate(matrotX)
		if (self.oldrightloc != None):
			 bpy.context.space_data.region_3d.view_location = self.oldrightloc 
		if (self.oldrightquat == None):
			self.oldrightquat = self.quat
		elif (self.quat == bpy.context.space_data.region_3d.view_rotation and self.quat != self.oldrightquat):
			bpy.context.space_data.region_3d.view_rotation = self.oldrightquat
		if int(self.oldrightquat[0] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[0] * 10000 + 0.5):
			if int(self.oldrightquat[1] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[1] * 10000 + 0.5):
				if int(self.oldrightquat[2] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[2] * 10000 + 0.5):
					if int(self.oldrightquat[3] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[3] * 10000 + 0.5):
						self.inview = True
						matrotX = Matrix.Rotation(math.radians(scn.my_props.Angle), 3, 'X')
						matrotY = Matrix.Rotation(math.radians(90), 3, 'Y')
						matrotZ = Matrix.Rotation(math.radians(90), 3, 'Z')
						self.quat = matrotZ.to_quaternion()
						self.quat.rotate(matrotY)
						self.quat.rotate(matrotX)
						bpy.context.space_data.region_3d.view_rotation = self.quat
						self.oldrightquat = bpy.context.space_data.region_3d.view_rotation.copy()
						self.oldrightloc = bpy.context.space_data.region_3d.view_location.copy()
	
		matrotX = Matrix.Rotation(math.radians(0), 3, 'X')
		matrotY = Matrix.Rotation(math.radians(-90), 3, 'Y')
		matrotZ = Matrix.Rotation(math.radians(-90), 3, 'Z')
		self.quat = matrotZ.to_quaternion()
		self.quat.rotate(matrotY)
		self.quat.rotate(matrotX)
		if (self.oldleftloc != None):
			 bpy.context.space_data.region_3d.view_location = self.oldleftloc 
		if (self.oldleftquat == None):
			self.oldleftquat = self.quat
		elif (self.quat == bpy.context.space_data.region_3d.view_rotation and self.quat != self.oldleftquat):
			bpy.context.space_data.region_3d.view_rotation = self.oldleftquat
		if int(self.oldleftquat[0] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[0] * 10000 + 0.5):
			if int(self.oldleftquat[1] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[1] * 10000 + 0.5):
				if int(self.oldleftquat[2] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[2] * 10000 + 0.5):
					if int(self.oldleftquat[3] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[3] * 10000 + 0.5):
						self.inview = True
						matrotX = Matrix.Rotation(math.radians(-scn.my_props.Angle), 3, 'X')
						matrotY = Matrix.Rotation(math.radians(-90), 3, 'Y')
						matrotZ = Matrix.Rotation(math.radians(-90), 3, 'Z')
						self.quat = matrotZ.to_quaternion()
						self.quat.rotate(matrotY)
						self.quat.rotate(matrotX)
						bpy.context.space_data.region_3d.view_rotation = self.quat
						self.oldleftquat = bpy.context.space_data.region_3d.view_rotation.copy()
						self.oldleftloc = bpy.context.space_data.region_3d.view_location.copy()
	
		matrotX = Matrix.Rotation(math.radians(0), 3, 'X')
		matrotY = Matrix.Rotation(math.radians(0), 3, 'Y')
		matrotZ = Matrix.Rotation(math.radians(0), 3, 'Z')
		self.quat = matrotX.to_quaternion()
		self.quat.rotate(matrotY)
		self.quat.rotate(matrotZ)
		if (self.oldtoploc != None):
			 bpy.context.space_data.region_3d.view_location = self.oldtoploc 
		if (self.oldtopquat == None):
			self.oldtopquat = self.quat
		elif (self.quat == bpy.context.space_data.region_3d.view_rotation and self.quat != self.oldtopquat):
			bpy.context.space_data.region_3d.view_rotation = self.oldtopquat
		if int(self.oldtopquat[0] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[0] * 10000 + 0.5):
			if int(self.oldtopquat[1] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[1] * 10000 + 0.5):
				if int(self.oldtopquat[2] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[2] * 10000 + 0.5):
					if int(self.oldtopquat[3] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[3] * 10000 + 0.5):
						self.inview = True
						matrotX = Matrix.Rotation(math.radians(0), 3, 'X')
						matrotY = Matrix.Rotation(math.radians(0), 3, 'Y')
						matrotZ = Matrix.Rotation(math.radians(scn.my_props.Angle), 3, 'Z')
						self.quat = matrotX.to_quaternion()
						self.quat.rotate(matrotY)
						self.quat.rotate(matrotZ)
						bpy.context.space_data.region_3d.view_rotation = self.quat
						self.oldtopquat = bpy.context.space_data.region_3d.view_rotation.copy()
						self.oldtoploc = bpy.context.space_data.region_3d.view_location.copy()
	
		matrotX = Matrix.Rotation(math.radians(180), 3, 'X')
		matrotY = Matrix.Rotation(math.radians(0), 3, 'Y')
		matrotZ = Matrix.Rotation(math.radians(0), 3, 'Z')
		self.quat = matrotX.to_quaternion()
		self.quat.rotate(matrotY)
		self.quat.rotate(matrotZ)
		if (self.oldbottomloc != None):
			 bpy.context.space_data.region_3d.view_location = self.oldbottomloc 
		if (self.oldbottomquat == None):
			self.oldbottomquat = self.quat
		elif (self.quat == bpy.context.space_data.region_3d.view_rotation and self.quat != self.oldbottomquat):
			bpy.context.space_data.region_3d.view_rotation = self.oldbottomquat
		if int(self.oldbottomquat[0] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[0] * 10000 + 0.5):
			if int(self.oldbottomquat[1] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[1] * 10000 + 0.5):
				if int(self.oldbottomquat[2] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[2] * 10000 + 0.5):
					if int(self.oldbottomquat[3] * 10000 + 0.5) == int(bpy.context.space_data.region_3d.view_rotation[3] * 10000 + 0.5):
						self.inview = True
						matrotX = Matrix.Rotation(math.radians(180), 3, 'X')
						matrotY = Matrix.Rotation(math.radians(0), 3, 'Y')
						matrotZ = Matrix.Rotation(math.radians(-scn.my_props.Angle), 3, 'Z')
						self.quat = matrotX.to_quaternion()
						self.quat.rotate(matrotY)
						self.quat.rotate(matrotZ)
						bpy.context.space_data.region_3d.view_rotation = self.quat
						self.oldbottomquat = bpy.context.space_data.region_3d.view_rotation.copy()
						self.oldbottomloc = bpy.context.space_data.region_3d.view_location.copy()


	
classes = (
	MyProps,
	Nill,
	Plus90,
	Minus90,
	PANEL_PT_RotViewPanel,
	VIEW3D_OT_RotView,
)

def register():
	from bpy.utils import register_class
	for cls in classes:
		register_class(cls)
	bpy.types.Scene.my_props = bpy.props.PointerProperty(type=MyProps)

def unregister():
	from bpy.utils import unregister_class
	for cls in classes:
		unregister_class(cls)


if __name__ == "__main__":
	register()





