=begin
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
# Designed by Fredo6 - Copyright November 2008

# Permission to use this software for any purpose and without fee is hereby granted
# Distribution of this software for commercial purpose is subject to:
#  - the expressed, written consent of the author
#  - the inclusion of the present copyright notice in all copies.

# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#-----------------------------------------------------------------------------
# Name			:   FredoScale_Alone.rb
# Original Date	:   8 Mar 2009 - version 2.0
# Description	:   Standalone tools for FredoScale
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
=end

module F6_FredoScale

#--------------------------------------------------------------------------------------------------------------
# Mixin Class for Alone Tools 
#--------------------------------------------------------------------------------------------------------------			 				   

module MixinAloneTool

@@persistence = nil

#Selection of the Tool
def _select
	Sketchup.active_model.select_tool @tool
end

#Placeholder subclassing routines
def sub_initialize(hparam)
	@hparam = hparam
	@title_tool = F6_FredoScale.compute_title_tool hparam
	@model = Sketchup.active_model
	@selection = @model.selection
	@view = @model.active_view
	@color_wireframe = MYDEFPARAM[:DEFAULT_Color_Wireframe]
	persistence_restore
	@operation = false
	@livedeform = false unless @authorize_livedeform
	@top_group = nil
	init_menu_keys
end
	
#Creating the Function Key Options
def init_menu_keys
	key = MYDEFPARAM[:DEFAULT_Key_LiveDeform]
	@fkey_livedeform = Traductor::FKeyOption.new(T6[:MNU_NoDeform], key) { toggle_live_deform }
	key = MYDEFPARAM[:DEFAULT_Key_Wireframe]
	@fkey_wireframe = Traductor::FKeyOption.new(T6[:MNU_Wireframe], key) { toggle_wireframe }
	key = MYDEFPARAM[:DEFAULT_Key_ActivateDice]
	@fkey_dice = Traductor::FKeyOption.new(T6[:MNU_ActivateDice], key) { toggle_dicing }
	key = MYDEFPARAM[:DEFAULT_Key_EdgeNewProp]
	@fkey_new_edges = Traductor::FKeyOption.new(T6[:T_MNU_PropNewEdges], key) { ask_edge_new_prop }
end

def sub_activate
	@lpt_wireframe = nil
end

#Saving parameters across FredoScale tools
def persistence_save
	@@persistence = {} unless @@persistence
	type = @hparam["OriginalToolType"]
	@@persistence[type] = {} unless @@persistence[type]
	hsh = @@persistence[type]
	
	#Parameters specific of the tool
	hsh["LiveDeform"] = @livedeform
	hsh["Wireframe"] = @wireframe
	if @mode_dice
		hsh["DiceActive"] = @dice_active
		hsh["DiceParam"] = @dice_param0
	end	
	hsh["NewEdgeProp"] = @new_edgeprop
end

def persistence_restore
	type = @hparam["OriginalToolType"]
	@@persistence = {} unless @@persistence
	hsh = @@persistence[type]
	unless hsh
		hsh = @@persistence[type] = {}
		hsh["LiveDeform"] = MYDEFPARAM[:DEFAULT_Flag_LiveDeform]
		hsh["Wireframe"] = MYDEFPARAM[:DEFAULT_Flag_Wireframe]
		hsh["DiceActive"] = MYDEFPARAM[:DEFAULT_Flag_ActivateDice]
		hsh["NewEdgeProp"] = MYDEFPARAM[:DEFAULT_Flag_EdgeNewProp]
	end	
	@persistence = hsh
	@livedeform = hsh["LiveDeform"]
	@wireframe = hsh["Wireframe"]
	@new_edgeprop = hsh["NewEdgeProp"]
	compute_new_edgeprop
	if @mode_dice
		@dice_active = hsh["DiceActive"]
		@dice_param0 = hsh["DiceParam"]
		@dice_param0 = @dice_param_def.clone unless @dice_param0
		compute_dice
	end	
end

def sub_get_title_tool
	F6_FredoScale.compute_title_tool @hparam
end

def sub_cursor_set
	F6_FredoScale.get_cursor @hparam
end

def sub_onCancel(flag, view, state)
	if state == 0
		@selection.clear
		@hparam["SelectTool"]._select
	else
		abort_operation
		view.invalidate
	end	
end

def toggle_live_deform
	@livedeform = !@livedeform
	@tool.onMouseMove_zero
end

def toggle_wireframe
	@wireframe = !@wireframe
	@tool.onMouseMove_zero
end

#Invoke dialog box for asking the properties of newly created edges
def ask_edge_new_prop
	@new_edgeprop = G6.ask_prop_new_edges @title_tool, @new_edgeprop
	Traductor::ReturnUp.set_on
end

def compute_new_edgeprop
	if @new_edgeprop == nil
		@new_edgeprop = 'SM'
	elsif @new_edgeprop.class == Array
		@new_edgeprop = @new_edgeprop.join ''
	end	
end
	
def toggle_dicing
	@dice_active = !@dice_active
	compute_dice
	@tool.onMouseMove_zero
end

def compute_dice
	if @dice_active
		@dice_param = @dice_param0
		@dice = G6::TR_Dicer.get_effective_dice @dice_param
	else
		@dice = 0
		@dice_param = nil
	end	
end
	
def sub_deactivate(view)
	@top_group.explode if @top_group
	commit_operation
	persistence_save
	view.invalidate
end

def sub_change_state(state)
	if state == 1 && @operation
		commit_operation
		@lpt_wireframe = @current_wireframe
		@new_origin = true
	end	
end

def sub_activate
	@hsh_entityID = {}
	@lpt_wireframe = G6.wireframe_entities @selection, @hsh_entityID
	@tool.set_hsh_entityID @hsh_entityID
end

#Generic method to perform the deformation of the model selection, either live or in wireframe
def deform_the_entities(final, *args)
	if @livedeform 
		abort_operation
		start_operation
		compute_transformation(*args)
		perform_deformation(*args)
	elsif final
		make_group_selection
		abort_operation
		@selection.add @top_group if @top_group && @top_group.valid?
		start_operation
		compute_transformation(*args)
		perform_deformation(*args)	
	else	
		compute_transformation(*args)
	end		
end

def make_group_selection
	#if @dice && @dice != 0 && @selection.length > 1
	if @selection.length > 1
		start_operation
		@top_group = @model.active_entities.add_group @selection.to_a
		commit_operation
		@selection.clear
		@selection.add @top_group if @top_group.valid?
	end
end

def commit_operation
	if @operation
		@model.commit_operation
		@operation = false
	end	
end

def abort_operation
	if @operation	
		@model.abort_operation
		@selection.add @selection.to_a unless @mode_spy
		@operation = false
	end	
end

def start_operation
	G6.start_operation @model, @title_tool, true
	@operation = true
end
	
def compute_wireframe
	return unless @trnew
	unless @lpt_wireframe
		@hsh_entityID = {}
		@lpt_wireframe = G6.wireframe_entities @selection, @hsh_entityID
		@tool.set_hsh_entityID @hsh_entityID
	end	
	if @dice
		@current_wireframe = dice_wireframe @lpt_wireframe
	else	
		@current_wireframe = @lpt_wireframe.collect { |pt| @trnew * pt }
	end	
	@current_wireframe
end
	
#Drawing method	
def sub_draw_after(view, state)
	draw_wireframe view, state
end

#draw the wireframe if applicable	
def draw_wireframe(view, state)
	return if @livedeform || !@wireframe
	return unless draw_wireframe?(state)
	pts = compute_wireframe
	return unless pts && pts.length > 1
	view.line_stipple = ""
	view.line_width = 1
	view.drawing_color = @color_wireframe
	pts2 = pts.collect { |pt| view.screen_coords(pt) }
	view.draw2d GL_LINES, pts2
end

#Fill the submenu with specific options
def sub_getMenu_after(menu)
	menu.add_separator
	@fkey_livedeform.create_menu_flag menu, @livedeform if @authorize_livedeform
	@fkey_wireframe.create_menu_flag menu, @wireframe	
	if @mode_dice	
		@fkey_dice.create_menu_flag menu, @dice_active
		menu.add_item(T6[:MNU_DiceParam]) { ask_dice }
	end	
	if @mode_new_edges	
		@fkey_new_edges.create_menu_flag menu, @dice_active
	end	
end

#Trap Modifier keys for extended and Keep selection
def check_function_key(key, rpt, flags, view)
	lskey = []
	lskey.push @fkey_livedeform if @authorize_livedeform
	lskey.push @fkey_wireframe
	lskey.push @fkey_dice if @mode_dice
	lskey.push @fkey_new_edges if @mode_new_edges
	lskey.each do |fk|
		return true if fk.test_key(key)
	end	
	false
end
	
def sub_onKeyDown(key, rpt, flags, view)
	#Function Key options
	return true if check_function_key key, rpt, flags, view
	false
end
	
def sub_onKeyUp(key, rpt, flags, view)
	#Dicing Parameters
	if @mode_dice && key == 9
		ask_dice
		return true
	end	
	false
end

#Invoke the dicing parameter dialog box	
def ask_dice
	status = G6::TR_Dicer.ask_dice_parameters @title_tool, @dice_param0
	Traductor::ReturnUp.set_on
	@dice_active = true if status
	compute_dice
end

end	#mixin MixinAloneTool

#--------------------------------------------------------------------------------------------------------------
# Standalone Planar Shear Tool 
#--------------------------------------------------------------------------------------------------------------			 				   

class PlanarShear_AloneTool

#mixin for generic  methods
include MixinAloneTool

#Initialization of the standard Protractor tool
def initialize(hparam)
	@hparam = hparam
	@mode_spy = false
	@mode_new_edges = false
	@authorize_livedeform = true
	@mode_planarshear_alone = true
	@tool = Traductor::StandardProtractorTool.new self, hparam	
end

#Execution method
def sub_execute(origin, normal, basedir, angle) 
	deform_the_entities true, origin, normal, basedir, angle
end

def sub_rotate(view, origin, normal, basedir, angle) 
	deform_the_entities false, origin, normal, basedir, angle
end

def compute_transformation(origin, normal, basedir, angle)
	@trnew = G6::TR_Shearing.new origin, normal, basedir, angle
end

def perform_deformation(*args)
	@trnew.transform_entities @selection
end
	
def draw_wireframe?(state)
	(state == 2)
end
	
end	#class PlanarShearAlone

#--------------------------------------------------------------------------------------------------------------
# Standalone Rotate Tool 
#--------------------------------------------------------------------------------------------------------------			 				   

class Rotate_AloneTool

#mixin for generic  methods
include MixinAloneTool

#Initialization of the standard Protractor tool
def initialize(hparam)
	@hparam = hparam
	@mode_spy = false
	@mode_new_edges = false
	@authorize_livedeform = true
	@mode_rotate_alone = true
	@tool = Traductor::StandardProtractorTool.new self, hparam	
end

#Execution method
def sub_execute(origin, normal, basedir, angle) 
	deform_the_entities true, origin, normal, basedir, angle
end

def sub_rotate(view, origin, normal, basedir, angle) 
	deform_the_entities false, origin, normal, basedir, angle
end

def compute_transformation(origin, normal, basedir, angle)
	@trnew = Geom::Transformation.rotation origin, normal, angle
end

def perform_deformation(*args)
	@model.active_entities.transform_entities @trnew, @selection
end
	
def draw_wireframe?(state)
	(state == 2)
end
	
end	#class RotateAlone

#--------------------------------------------------------------------------------------------------------------
# Standalone Rotate Tool 
#--------------------------------------------------------------------------------------------------------------			 				   

class RadialBend_AloneTool

#mixin for generic  methods
include MixinAloneTool

#Initialization of the standard Protractor tool
def initialize(hparam)
	@hparam = hparam
	@mode_spy = false
	@authorize_livedeform = false
	@mode_rotate_alone = true
	@mode_dice = true
	@mode_new_edges = true
	@dice_param_def = G6::TR_Dicer.create_param -3, true
	compute_dice
	@tool = Traductor::StandardProtractorTool.new self, hparam
	@tool.set_mode_length_direction	
end

#Execution method
def sub_execute(origin, normal, basedir, angle) 
	deform_the_entities true, origin, normal, basedir, angle
	@view.invalidate
end

def sub_rotate(view, origin, normal, basedir, angle) 
	deform_the_entities false, origin, normal, basedir, angle
end

def compute_transformation(origin, normal, basedir, angle)
	@trnew = G6::TR_RadialBending.new origin, normal, basedir, angle, origin.distance(@tool.get_basedir_point), 
	                                  @dice_param
end

def perform_deformation(*args)
	le = @trnew.transform_entities @selection, @new_edgeprop
end
	
def draw_wireframe?(state)
	(state == 2)
end

def dice_wireframe(lpt)
	@trnew.dice_wireframe lpt
end

def draw_guide(view, state)
	return if @new_origin
	
	#Drawing the guide
	pt1 = @tool.get_origin
	pt2 = @tool.get_basedir_point
	return unless pt2
	view.line_width = 4
	view.line_stipple = ""
	view.drawing_color = 'purple'
	view.draw2d GL_LINES, view.screen_coords(pt1), view.screen_coords(pt2)
	
	#Drawing the dicing marks
	if @dice_param && @dice_param.nb != 0
		@dice_param.angle = 0 if state == 1
		G6::TR_Dicer.draw_dicer_marks view, @dice_param, pt1, pt2, @tool.get_normal * pt1.vector_to(pt2), 'darkorange', 10, 3
	end	
end

#Drawing method specifc to Bend	
def sub_draw_after(view, state)
	draw_guide view, state if state > 0 
	draw_wireframe view, state
	@new_origin = false
end
	
end	#class RadialBend_AloneTool

#--------------------------------------------------------------------------------------------------------------
# Make Unique Tool 
#--------------------------------------------------------------------------------------------------------------			 				   

class MakeUnique_UtilTool

#mixin for generic  methods
include MixinAloneTool

#Initialization of the standard Protractor tool
def initialize(hparam)
	@hparam = hparam
	@hparam["Select_Types"] = ["Group", "ComponentInstance"]
	@hparam["Select_NoExtend"] = true
	@model = Sketchup.active_model
	@selection = @model.selection
	@title_tool = F6_FredoScale.compute_title_tool hparam
end

#Selection and activation of the tool
def _select
	Sketchup.active_model.select_tool self
end

def activate
	init
	nb = check_unique @selection
	if nb == 0
		status = UI.messagebox T6[:DLG_Unique_Already]
	else
		#status = UI.messagebox "Make Unique Groups = #{@lst_group.length} Components = #{@lst_comp.length}", MB_OKCANCEL
		status = UI.messagebox T6[:DLG_Unique_InfoDlg, "#{@lst_group.length}", "#{@lst_comp.length}"], MB_OKCANCEL
		start_operation
		make_unique if status == 1
		commit_operation
	end	
	Sketchup.active_model.selection.clear
	@hparam["SelectTool"]._select
end

def init
	@lst_comp = []
	@lst_group = []
	@hsh_def = {}
end

def check_unique(entities)
	entities.each do |e|
		if e.class == Sketchup::Group
			@lst_group.push e unless G6.is_group_unique?(e) 
			check_unique e.entities
		elsif e.class == Sketchup::ComponentInstance
			@lst_comp.push e unless e.definition.count_instances == 1 
			definition = e.definition
			unless @hsh_def[definition.to_s]
				@hsh_def[definition.to_s] = definition
				check_unique definition.entities
			end
		end
	end	
	return @lst_group.length + @lst_comp.length
end

def make_unique
	return if @lst_group.length + @lst_comp.length == 0
	@lst_group.each { |g| g.make_unique }
	@lst_comp.each { |g| g.make_unique }
	init
	check_unique @selection
	make_unique
end

end	#class MakeUnique_UtilTool

#--------------------------------------------------------------------------------------------------------------
# Select Edges Tool 
#--------------------------------------------------------------------------------------------------------------			 				   

class SelectEdges_UtilTool

#Initialization of the standard Protractor tool
def initialize(hparam)
	@hparam = hparam
	@hparam["Select_Types"] = ["Edge"]
	@hparam["Select_NoExtend"] = true
	@hparam["Select_KeepSelection"] = true
	@model = Sketchup.active_model
	@selection = @model.selection
	#@selection.clear
	@title_tool = F6_FredoScale.compute_title_tool hparam
end

#Selection and activation of the tool
def _select
	Sketchup.active_model.select_tool nil
end

end	#class SelectEdges_UtilTool

end	#End Module F6_FredoScale
