=begin
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
# Copyright © 2009 Fredo6 - Designed and written April 2009 by Fredo6

# 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			:   RoundCorner_Tool.rb
# Original Date	:   30 April 2009 - version 2.0
# Updated		:   17 Dec 2010 - version 2.2
# Description	:   Sketchup Tool for RoundCorner
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
=end

module RoundCorner

#--------------------------------------------------------------------------------------------------------------
# Top Calling functions: create the classes and launch the tools
#--------------------------------------------------------------------------------------------------------------			 				   

#Actual launching of menus	
def RoundCorner.action__mapping(action_code)
	case action_code
	when :round
		RoundCorner.launch :RDC_ROUND_
	when :sharp
		RoundCorner.launch(:RDC_SHARP_, { :sharp => true })
	when :bevel
		RoundCorner.launch(:RDC_BEVEL_, { :profile_type => ['C', 1] })
	end		
end

def RoundCorner.launch(*hargs)
	Sketchup.active_model.select_tool RoundCornerTool.new(*hargs)
end

#---------------------------------------------------------------------------------------------------------------------------
# Class RoundCornerTool: implement the interactive tool	
#---------------------------------------------------------------------------------------------------------------------------

class RoundCornerTool

@@persistence = nil

def Vector3d(*args) ; Geom::Vector3d.new *args ; end

#Initialization and creation of the tool
def initialize(tool_type, *hargs)
	@tool_type = tool_type.to_s
	
	@model = Sketchup.active_model
	@selection = @model.selection
	@view = @model.active_view
	@ip = Sketchup::InputPoint.new
	@ph = @view.pick_helper	
	
	#Initializing the cursor
	@id_cursor_pick_none = MYPLUGIN.create_cursor "None", 0, 0	
	@id_cursor_pick_invalid = MYPLUGIN.create_cursor "Invalid", 0, 0	
	@id_cursor_pick_vertex = MYPLUGIN.create_cursor "Arrow_Vertex", 0, 0	
	@id_cursor_pick_edge = MYPLUGIN.create_cursor "Arrow_Edge", 0, 0	
	@id_cursor_pick_face = MYPLUGIN.create_cursor "Arrow_Face", 0, 0	
	@id_cursor_arrow_exit = MYPLUGIN.create_cursor "Arrow_Exit", 0, 0	
	@id_cursor_validate = MYPLUGIN.create_cursor "Validate", 0, 0	
	@id_cursor_hourglass_green = Traductor.create_cursor "Cursor_hourGlass_Green", 16, 16	
	@id_cursor_hourglass_blue = Traductor.create_cursor "Cursor_hourGlass_Blue", 16, 16	
	@id_cursor_hourglass_red = Traductor.create_cursor "Cursor_hourGlass_Red", 16, 16	
	
	#Titles and tooltips
	stit = @tool_type + 'Menu'
	@title_tool = T6[stit.intern]
	@label = T6[:MNU_Offset]
	@time_calculation = nil
	
	#Initialization of default parameters
	@edge_prop_filter_default = MYDEFPARAM[:DEFAULT_Flag_EdgePropFilter]
	@edge_prop_border_default = MYDEFPARAM[:DEFAULT_Flag_EdgePropBorder]
	@edge_prop_round_default = MYDEFPARAM[:DEFAULT_Flag_EdgePropRound]
	@color_edges = MYDEFPARAM[:DEFAULT_Color_Edges]
	@color_borders = MYDEFPARAM[:DEFAULT_Color_Borders]
	
	n = MYDEFPARAM[:DEFAULT_NumberLetter]
	@persist_letters = []
	letter = 'A'
	for i in 0..n-1
		@persist_letters.push letter
		letter = letter.next
	end	
		
	#Restablishing previous parameters
	persistence_restore
	
	#Initializating the Selection mode
	hsh = {}
	hsh["modifier"] = @modifier if @modifier
	hsh["anglemax"] = @anglemax if @anglemax
	@selmode = Traductor::SelMode.new hsh
	
	@aperture = MYDEFPARAM[Traductor::SelMode.default_symb_aperture(:RDC_)]
	@aperture = nil if @aperture && @aperture < 5
	
	#Computing the default offset and numseg
	@num_seg = 1 if @tool_type =~/bevel/i
	unless @offset
		@offset = 100.cm
	end	
	
	#Initializing the Algorithm class
	hsh_param = { :strict_offset => @strict_offset, :prop_borders => @edge_prop_border, :prop_rounds => @edge_prop_round,
				  :offset => @offset, :num_seg => @num_seg, :mode_rounding => @mode_rounding,
				  :golden_axis => @golden_axis,
				  :prop_filter => @edge_prop_filter, :cursor_proc => self.method("onSetCursor") }
	@algo = RoundCornerAlgo.new(hsh_param, *hargs)
	@algo.define_end_proc { |status|  end_calculation status }
	
	#Static initialization
	init_text
	init_fkey
	init_palette
	
end

def reset_tool
	#Initializating the Selection mode
	hsh = {}
	hsh["modifier"] = @modifier if @modifier
	hsh["anglemax"] = @anglemax if @anglemax
	@selmode = Traductor::SelMode.new hsh
	
	@aperture = MYDEFPARAM[Traductor::SelMode.default_symb_aperture(:RDC_)]
	@aperture = nil if @aperture && @aperture < 5
	
	
	#Computing the default offset and numseg
	@num_seg = 1 if @tool_type =~/bevel/i
	unless @offset
		@offset = 100.cm
	end	
	
	#Initializing the Algorithm class
	hsh_param = { :strict_offset => @strict_offset, :prop_borders => @edge_prop_border, :prop_rounds => @edge_prop_round,
				  :offset => @offset, :num_seg => @num_seg, :mode_rounding => @mode_rounding,
				  :golden_axis => @golden_axis,
				  :prop_filter => @edge_prop_filter, :cursor_proc => self.method("onSetCursor") }
	@algo = RoundCornerAlgo.new(hsh_param)
	@algo.define_end_proc { |status|  end_calculation status }
end

#Initializing text
def init_text
	@mnu_execute = T6[:MNU_Execute]
	@mnu_exit = T6[:MNU_Exit]
	@mnu_unselect_all = T6[:MNU_UnselectAll]
	@mnu_edge_prop_filter = T6[:MNU_EdgePropFilter]
	@mnu_strict_offset = T6[:MNU_StrictOffset]
	@mnu_rounding = T6[:MNU_Rounding]
	@mnu_offset = T6[:MNU_Offset]
	
	@mnu_all_param = T6[:MNU_AllParam]
	
	@msg_main = T6[:MSG_Main]
	@msg_some_errors = T6[:MSG_SomeErrors]
	
	@tip_computing = T6[:TIP_Computing]
	@tip_invalid = T6[:TIP_Invalid]
	@tip_invalid_best = T6[:TIP_InvalidBest]
	@tip_wrong_nb_faces = T6[:TIP_WrongNbFaces]
	@tip_wrong_coplanar = T6[:TIP_WrongCoplanar]
	@tip_wrong_filter = T6[:TIP_WrongFilter]
	
	@tip_execute = T6[:TIP_Execute]
	@tip_exit = T6[:TIP_Exit]
	@tip_select_edge = T6[:TIP_Select_Edge]
	@tip_unselect_edge = T6[:TIP_UnSelect_Edge]
	@tip_select_face = T6[:TIP_Select_Face]
	@tip_unselect_face = T6[:TIP_UnSelect_Face]
	@tip_select_vertex = T6[:TIP_Select_Vertex]
	@tip_unselect_vertex = T6[:TIP_UnSelect_Vertex]
	@tip_offset = T6[:TIP_Offset]
	@tip_numseg = T6[:TIP_Numseg]
	@tip_axis = T6[:TIP_Axis]
	@tip_interrupt = T6[:TIP_Interrupt]
	
end

#Creating the Function Key Options
def init_fkey
	key = MYDEFPARAM[:DEFAULT_Key_StrictOffset]
	@fkey_strict_offset = Traductor::FKeyOption.new(T6[:MNU_StrictOffset], key) { toggle_strict_offset }
	key = MYDEFPARAM[:DEFAULT_Key_Rounding]
	@fkey_rounding = Traductor::FKeyOption.new(T6[:MNU_Rounding], key) { toggle_rounding }
end

#-----------------------------------
# Palette Management	
#-----------------------------------

#Initialize the button palette
def make_proc(&proc) ; proc ; end

def init_palette
	t0 = Time.now.to_f
	@palette = Traductor::Palette.new 
	draw_local = self.method "draw_button_opengl"

	#Unselect All
	hsh = { :tooltip => @mnu_unselect_all, :draw_proc => :cross_NE3, :main_color => 'red' }
	@palette.declare_button(:pal_unselect_all, hsh) { unselect_all }
	#@palette.declare_separator
	
	#Modifiers for Selection mode	
	@selmode.contribute_palette @palette

	#Edge filters
	@palette.declare_separator
	proc = make_proc() { @edge_prop_filter }
	ttip = T6[:MNU_EdgePropFilter] + "\n" + G6.edge_filter_text(@edge_prop_filter_default)
	hsh = { :value_proc => proc, :text => T6[:MNU_EdgePropFilter2], :tooltip => ttip, 
	        :main_color => 'blue', :default_value => @edge_prop_filter_default }
	@palette.declare_edge_prop(:pal_filter, nil, hsh) { filter_edges @palette.button_get_value(:pal_filter) }

	#Letter param save and restore
	@palette.declare_separator if @persist_letters.length > 0
	@persist_letters.each do |letter|
		p_set = ('pal_set_' + letter).intern
		grayed_proc = make_proc() { !@@persistence[symb_from_letter(letter)] }
		tip_proc = make_proc() { tooltip_from_letter(letter) }
		hsh = { :height => 16, :width => 16, :rank => 1, :text => letter, :grayed_proc => grayed_proc, 
		        :tip_proc => tip_proc, :bk_color => 'gold' }
		@palette.declare_button(p_set, hsh) { persistence_transfer letter, true }
		
		p_save = ('pal_save_' + letter).intern
		hsh = { :height => 16, :width => 16, :draw_proc => :std_disk, :main_color => 'yellow', :tooltip => T6[:TIP_SaveLetter, letter] }
		@palette.declare_button(p_save, hsh) { persistence_save letter }	
	end
	
	#Offset value
	@palette.declare_separator
	wid = 80
	hsh = { :height => 16, :width => wid, :rank => 1, :passive => true, :text => @mnu_offset, :tooltip => @tip_offset }
	@palette.declare_button(:pal_offset_title, hsh)	
	
	text_proc = make_proc() { Sketchup.format_length(@algo.get_offset) }
	hsh = { :height => 16, :width => wid, :text_proc => text_proc, :bk_color => 'lightblue', :tooltip => @tip_offset }
	@palette.declare_button(:pal_offset, hsh) { ask_all_param }	
	
	#Nb of Segments
	wid = 32
	hsh = { :height => 16, :width => wid, :rank => 1, :passive => true, :text => '#', :tooltip => @tip_numseg }
	@palette.declare_button(:pal_numseg_title, hsh)	
	
	text_proc = make_proc() { @algo.get_num_seg.to_s + 's'}
	grayed_proc = make_proc() { get_num_seg_lock }
	hsh = { :height => 16, :width => wid, :text_proc => text_proc, :bk_color => 'lightgreen', :tooltip => @tip_numseg,
		    :grayed_proc => grayed_proc }
	@palette.declare_button(:pal_numseg, hsh) { ask_all_param }	

	#Strict offset
	@palette.declare_separator
	proc = make_proc() { @strict_offset }
	hsh = { :main_color => 'green', :draw_scale => 0.6 }
	hshb = { :value_proc => proc, :draw_proc => draw_local, :tooltip => @mnu_strict_offset }
	@palette.declare_button(:pal_strict_offset, hsh, hshb) { toggle_strict_offset }	

	#Rounding option
	unless @tool_type =~/bevel/i
		proc = make_proc() { @mode_rounding }
		hsh = { :main_color => 'green', :draw_scale => 0.6 }
		hshb = { :value_proc => proc, :draw_proc => draw_local, :tooltip => @mnu_rounding }
		@palette.declare_button(:pal_rounding, hsh, hshb) { toggle_rounding }	
	end
	
	#Axis for Pivot
	unless RUN_ON_MAC
		dexproc = make_proc() { { "Vec" => @golden_axis } }
		@palette.declare_separator
		hsh = { :tooltip => @mnu_axis, :draw_proc => :std_axis, :tooltip => @tip_axis, :passive => true,
				:draw_refresh => true, :draw_extra_proc => dexproc }
		@palette.declare_button(:pal_axis, hsh) { exit_tool }
	end
	
	#Border properties
	@palette.declare_separator
	proc = make_proc() { @edge_prop_border }
	ttip = T6[:TIP_EdgePropBorder] + "\n" + G6.edge_filter_text(@edge_prop_border_default)
	hsh = { :value_proc => proc, :text => T6[:MNU_EdgePropBorder], :tooltip => ttip, 
	        :main_color => 'blue', :edge_prop => 'SMH', :default_value => @edge_prop_border_default}
	@palette.declare_edge_prop(:pal_prop_border, nil, hsh) { prop_border_edges @palette.button_get_value(:pal_prop_border) }
	@palette.declare_separator

	#Round Edges properties
	proc = make_proc() { @edge_prop_round }
	ttip = T6[:TIP_EdgePropRound] + "\n" + G6.edge_filter_text(@edge_prop_round_default)
	hsh = { :value_proc => proc, :text => T6[:MNU_EdgePropRound], :tooltip => ttip, 
	        :main_color => 'blue', :edge_prop => 'SMH', :default_value => @edge_prop_round_default }
	@palette.declare_edge_prop(:pal_prop_round, nil, hsh) { prop_round_edges @palette.button_get_value(:pal_prop_round) }
	
	#Exit and Execute
	@palette.declare_separator
	hsh = { :tooltip => @mnu_exit, :draw_proc => :std_exit }
	@palette.declare_button(:pal_exit, hsh) { exit_tool }
	
	grayed_proc = make_proc() { @algo.get_nb_edges == 0 }
	hsh = { :tooltip => @mnu_execute, :draw_proc => :valid, :grayed_proc => grayed_proc}
	@palette.declare_button(:pal_execute, hsh) { execute_action }
	Traductor.trace6 "#{Time.now.to_f - t0}: RDC End Palette"	
end

#Custom drawing of buttons
def draw_button_opengl(symb, dx, dy)
	code = symb.to_s
	lst_gl = []
	xmid = dx / 2
	
	case code
	
	#Strict Offset
	when /pal_strict_offset/i
		pts = []
		pts.push Geom::Point3d.new(xmid, 2, 0)
		pts.push Geom::Point3d.new(xmid, dy-2, 0)
		lst_gl.push [GL_LINE_STRIP, pts + [pts[0]], @color_edges, 2]
		pts = []
		pts.push Geom::Point3d.new(xmid-7, 2, 0)
		pts.push Geom::Point3d.new(xmid-7, dy-2, 0)
		lst_gl.push [GL_LINE_STRIP, pts + [pts[0]], @color_borders, 2]
		pts = []
		pts.push Geom::Point3d.new(xmid+7, 2, 0)
		pts.push Geom::Point3d.new(xmid+7, dy-2, 0)
		lst_gl.push [GL_LINE_STRIP, pts + [pts[0]], @color_borders, 2]

	#Rounding option	
	when /pal_rounding/i
		pts = []
		pts.push Geom::Point3d.new(2, dy-2, 0)
		pts.push Geom::Point3d.new(2, 2, 0)
		pts.push Geom::Point3d.new(dx-2, 2, 0)
		lst_gl.push [GL_LINE_STRIP, pts, @color_edges, 2, '']
		pts = []
		n = 7
		angle = Math::PI * 0.5 / n
		r = dx * 0.6
		cx = dx - 2
		cy = dy - 2
		for i in 0..n
			pts.push Geom::Point3d.new(cx - Math.sin(angle * i) * r, cy - Math.cos(angle * i) * r, 0)
		end	
		lst_gl.push [GL_LINE_STRIP, pts, @color_borders, 2, '']
		
	end
	
	lst_gl
end

#Dialog box to ask parameters
def ask_all_param
	#Creating the dialog box if not done
	unless @dlgall
		@dlgall = Traductor::DialogBox.new T6[:DLG_All_Title]
		@dlgall.field_numeric "offset", T6[:DLG_All_Offset], 100.cm, nil, nil
		unless @tool_type =~/bevel/i
			@dlgall.field_numeric "num_seg", T6[:DLG_All_Numseg], 6, 1, RoundCorner.max_seg
		end	
		enu_axis = { 'X' => "X (Red)", 'Y' => "Y (Green)", 'Z' => "Z (Blue)" }
		enu_yesno = { 'Y' => 'Yes', 'N' => 'No' }
		@dlgall.field_enum "strict_offset", T6[:DLG_All_StrictOffset], 'N', enu_yesno
		@dlgall.field_enum "mode_rounding", T6[:DLG_All_SuperRounding], 'Y', enu_yesno
		@dlgall.field_enum "golden_axis", T6[:DLG_All_GoldenAxis], 'Z', enu_axis, ['X', 'Y', 'Z']
	end
		
	#Calling the dialog box
	hparam = @algo.get_all_dlg_parameters
	return unless @dlgall.show! hparam
	
	#Changing the parameters
	@algo.change_all_parameters hparam
	
	@offset = @algo.get_offset
	@num_seg = @algo.get_num_seg
	@golden_axis = @algo.get_golden_axis
	@mode_rounding = @algo.get_mode_rounding
	@strict_offset = @algo.get_strict_offset
end

#Check if the number of segments is locked
def get_num_seg_lock
	(@tool_type =~/bevel/i) ? true : @algo.get_num_seg_lock
end

#--------------------------------------------------------------
# Modifiers	settings
#--------------------------------------------------------------

def toggle_strict_offset
	@strict_offset = @algo.change_strict_offset !@strict_offset
end

def toggle_rounding
	@mode_rounding = @algo.change_rounding !@mode_rounding
end

def check_key_golden_axis(key)
	axis = nil
	case key
	when VK_RIGHT
		axis = X_AXIS
	when VK_LEFT
		axis = Y_AXIS
	when VK_UP
		axis = Z_AXIS
	when VK_DOWN
		axis = parse_axis(MYDEFPARAM[:DEFAULT_Flag_Axis])
	else
		return false
	end
	@golden_axis = @algo.change_golden_axis axis if axis	
	@view.invalidate
	true
end

#Trap Modifier keys for extended and Keep selection
def check_function_key(key, rpt, flags, view)
	lskey = []
	lskey.push @fkey_strict_offset
	lskey.push @fkey_rounding unless @tool_type =~/bevel/i
	lskey.each do |fk|
		if fk.test_key(key)
			view.invalidate
			return true
		end	
	end	
	false
end

#--------------------------------------------------------------
# Persistence of parameters
#--------------------------------------------------------------

#Saving parameters across sessions
def persistence_save(letter=nil)
	@@persistence = {} unless @@persistence
	type = @tool_type
	typeall = 'All'

	#Common to all tools
	@@persistence[typeall] = {} unless @@persistence[typeall]
	hsh = @@persistence[typeall]
	
	#Specific to the tool
	@@persistence[type] = {} unless @@persistence[type]
	hsh = @@persistence[type]
	
	#Parameters specific of the tool
	hsh["EdgePropFilter"] = @edge_prop_filter
	hsh["EdgePropBorder"] = @edge_prop_border
	hsh["EdgePropRound"] = @edge_prop_round
	hsh["StrictOffset"] = @strict_offset
	hsh["Rounding"] = @mode_rounding
	hsh["Offset"] = @algo.get_offset
	hsh["Numseg"] = @algo.get_num_seg
	hsh["PivotAxis"] = @golden_axis
	hsh["Numseg"] = @num_seg
	hsh["Modifier"] = @selmode.get_modifier
	hsh["Anglemax"] = @selmode.get_anglemax
	
	#Save permanently
	persistence_write hsh, letter
end

def symb_from_letter(letter=nil)
	letter = '0' unless letter
	symb = '_Reg_' + @tool_type + letter
	symb.intern
end

def tooltip_from_letter(letter)
	hsh = @@persistence[symb_from_letter(letter)]
	if hsh
		offset = hsh["Offset"].to_l.to_s
		ttip = T6[:TIP_LetterInfo, offset, "#{hsh["Numseg"]}"]
	else
		ttip = T6[:TIP_LetterVoid, letter]
	end	
	ttip	
end

#Restoring parameters across sessions
def persistence_restore(letter=nil)
	type = @tool_type
	typeall = 'All'
	@@persistence = {} unless @@persistence
	
	#common to all tool
	hsh = @@persistence[typeall]
	unless hsh
		hsh = @@persistence[typeall] = {}
	end
	
	#Specific to the tool
	hsh = @persistence = @@persistence[type]
	unless hsh
		hsh = @persistence = @@persistence[type] = {}
		hsh["EdgePropFilter"] = @edge_prop_filter_default
		hsh["EdgePropBorder"] = @edge_prop_border_default
		hsh["EdgePropRound"] = @edge_prop_round_default
		hsh["StrictOffset"] = (MYDEFPARAM[:DEFAULT_Flag_StrictOffset]) ? true : false
		hsh["Rounding"] = (MYDEFPARAM[:DEFAULT_Flag_Rounding]) ? true : false
		hsh["PivotAxis"] = parse_axis(MYDEFPARAM[:DEFAULT_Flag_Axis])
		hsh["Numseg"] = MYDEFPARAM[:DEFAULT_Flag_Numseg]
		hsh["Golden_Axis"] = MYDEFPARAM[:DEFAULT_Flag_Axis]
		hsh["Modifier"] = MYDEFPARAM[Traductor::SelMode.default_symb_modifier(:RDC_)]
		hsh["Anglemax"] = MYDEFPARAM[Traductor::SelMode.default_symb_anglemax(:RDC_)]
		persistence_load
		@persist_letters.each { |lt| persistence_load lt }
	end	
	persistence_transfer letter
end

def persistence_load(letter=nil)
	symb = symb_from_letter letter
	sval = MYDEFPARAM[symb]
	return unless sval
	begin
		@@persistence[symb] = eval sval
	rescue
		return {}
	end
end

def persistence_transfer(letter, reset=false)
	hsh = @persistence
	hsh_letter = @@persistence[symb_from_letter(letter)]
	hsh_letter.each { |key, val| hsh[key] = val } if hsh_letter
	
	@edge_prop_filter = hsh["EdgePropFilter"]
	@edge_prop_border = hsh["EdgePropBorder"]
	@edge_prop_round = hsh["EdgePropRound"]
	@strict_offset = hsh["StrictOffset"]
	@mode_rounding = hsh["Rounding"]
	@offset = hsh["Offset"]
	@num_seg = hsh["Numseg"]
	@golden_axis = hsh["PivotAxis"]
	@modifier = hsh["Modifier"]
	@anglemax = hsh["Anglemax"]
	
	return unless reset
	
	#Transferring the new parameters
	@selmode.set_anglemax @anglemax
	@selmode.set_modifier @modifier
	
	hsh_param = { :strict_offset => @strict_offset, :prop_borders => @edge_prop_border, :prop_rounds => @edge_prop_round,
				  :offset => @offset, :num_seg => @num_seg, :mode_rounding => @mode_rounding,
				  :golden_axis => @golden_axis,
				  :prop_filter => @edge_prop_filter }
	@algo.refresh_all_parameters hsh_param
end

def persistence_write(hsh, letter=nil)
	symb = symb_from_letter(letter)
	@@persistence[symb] = hsh.clone
	if MYDEFPARAM[symb] != hsh.inspect
		MYDEFPARAM[symb] = hsh.inspect
		MYDEFPARAM.save_to_file
	end
end

#Parse an axis from string with X, Y, Z
def parse_axis(s)
	return Z_AXIS unless s
	case s
	when /X/i
		vec = X_AXIS
	when /Y/i
		vec = Y_AXIS
	else
		vec = Z_AXIS
	end
	vec	
end

#--------------------------------------------------------------
# Tool Events
#--------------------------------------------------------------

#activation of the tool
def activate
	SUClock.register_ruby 'RoundCorner' if defined?(SUClock)
	
	#initialization
	@pk_vertex = nil
	@pk_edge = nil
	@pk_face = nil
	
	#Analyze the selection
	@algo.analyze_selection @selection
	@selection.clear
	
	@view.invalidate
	show_info
end

#Deactivation of the tool
def deactivate(view)
	@algo.interrupt?(false)
	persistence_save
	@algo.unselect_all
	@x = nil
	clean_VCB
	view.invalidate
	true
end

#Cancel event
def onCancel(flag, view)
	#Cancel current scaling operation if any
	case flag
	when 0	#Press Escape
		#Stopping the processing
		return if @algo.interrupt?
		@algo.unselect_all
		onMouseMove_zero
		
	when 1	#Reactivate the same tool
	
	else	#Undo
		return if @algo.interrupt?(false)

	end		
end

#Setting the proper cursor
def onSetCursor
	if @algo.running? || @running
		case @algo.running?
		when 2
			ic = @id_cursor_hourglass_red
		when 3
			ic = @id_cursor_hourglass_blue
		else
			ic = @id_cursor_hourglass_green
		end	
		return UI::set_cursor(ic)
	end	
	ic = @palette.onSetCursor
	return (ic != 0) if ic
	if @time_calculation
		cursor = @id_cursor_arrow_exit
	elsif @invalid_pick
		cursor = @id_cursor_pick_invalid
	elsif @pk_vertex
		cursor = @id_cursor_pick_vertex
	elsif @pk_edge
		cursor = @id_cursor_pick_edge
	elsif @pk_face
		cursor = @id_cursor_pick_face
	elsif @best_picked
		cursor = @id_cursor_pick_invalid
	elsif @algo.get_nb_edges > 0
		cursor = @id_cursor_validate
	else
		cursor = @id_cursor_arrow_exit
	end	
	UI::set_cursor cursor
end

#Setting the proper cursor
def compute_tooltip
	mode = nil
	if @algo.running? || @running
		tooltip = @tip_computing
		mode = 'I'
		@palette.set_message @tip_interrupt, 'W'
	elsif @invalid_pick
		tooltip = invalid_reason @pk_edge
	elsif @pk_vertex
		tooltip = (@algo.entity_selected?(@pk_vertex)) ? @tip_unselect_vertex : @tip_select_vertex
	elsif @pk_edge
		tooltip = (@algo.entity_selected?(@pk_edge)) ? @tip_unselect_edge : @tip_select_edge
	elsif @pk_face
		tooltip = (@algo.entity_selected?(@pk_face)) ? @tip_unselect_face : @tip_select_face
	elsif @best_picked
		tooltip = @tip_invalid_best
	elsif @algo.get_nb_edges > 0
		tooltip = @tip_execute
	else
		tooltip = @tip_exit
	end	
	@view.tooltip = tooltip
	if @time_calculation
		if @time_calculation == 0
			mode = 'E'
			tooltip = T6[:TIP_Aborted]
		else
			tooltip = T6[:TIP_Time, sprintf("%4.2f", @time_calculation)]
			mode = 'W'
		end	
	else
		tooltip += "\n" + T6[:TIP_Count, @algo.get_nb_edges.to_s, @algo.get_nb_corners.to_s]
	end	
	@palette.set_tooltip tooltip, mode
end

#calculate the reason for edge invalid
def invalid_reason(edge)
	case @algo.invalid_reason(edge)
	when '2'
		reason = @tip_wrong_nb_faces + ": #{edge.faces.length}"
	when 'P'
		reason = @tip_wrong_coplanar
	when 'F'
		reason = @tip_wrong_filter
	else
		reason = ""
	end
	tooltip = @tip_invalid
	tooltip += " (#{reason})" if reason != ''
	tooltip
end

#Contextual menu
def getMenu(menu)
	#Menu Execute or Exit
	if @algo.get_nb_edges > 0
		menu.add_item(@mnu_execute) { execute_action }
		menu.add_separator
	end
	menu.add_item(@mnu_exit) { exit_tool }
	menu.add_item(@mnu_unselect_all) { unselect_all }

	#Dialog box for all parameters
	menu.add_separator
	menu.add_item(@mnu_all_param + " (TAB)") { ask_all_param }
	
	#Modifiers
	@selmode.contribution_menu(menu)
	
	#Filter of edges
	menu.add_separator
	menu.add_item(@mnu_edge_prop_filter + " : #{G6.edge_filter_text(@edge_prop_filter)}") { ask_prop_filter }
	
	#Function key menus
	@fkey_strict_offset.create_menu_flag menu, @strict_offset
	unless @tool_type =~/bevel/i
		@fkey_rounding.create_menu_flag menu, @mode_rounding		
	end
	
end

#dialog box for Edge property filter
def ask_prop_filter
	result = G6.ask_edge_prop_filter T6[:MNU_EdgePropFilter], @edge_prop_filter
	return unless result
	filter_edges result
end

def filter_edges(filter)
	if filter != @edge_prop_filter
		@edge_prop_filter = filter
		@algo.change_prop_filter @edge_prop_filter
	end	
end

def prop_border_edges(prop)
	@edge_prop_border = prop
	@algo.set_prop_borders @edge_prop_border
end

def prop_round_edges(prop)
	@edge_prop_round = prop
	@algo.set_prop_rounds @edge_prop_round
end

#Restart from scratch
def unselect_all
	@algo.unselect_all
end

#resume after view tools
def resume(view)
	onMouseMove_zero
end	

#Handle key down events
def onKeyDown(key, rpt, flags, view)
	key = Traductor.check_key key, flags, false
	
	#Stopping the processing
	return if @algo.interrupt?
	
	#Keys for selection modifiers
	return view.invalidate if @selmode.onKeyDown(key, rpt, flags, view)

	#Change of golden axis
	return if check_key_golden_axis(key)
	
	#Function Key options
	return if check_function_key(key, rpt, flags, view)
	
end

#Handle key up events
def onKeyUp(key, rpt, flags, view)
	key = Traductor.check_key key, flags, true
	
	#TAB key
	if key == 9
		ask_all_param
	end
	
	return view.invalidate if @selmode.onKeyUp(key, rpt, flags, view)
end

def onMouseLeave(view)
	@palette.onMouseLeave(view)
end

def onMouseEnter(view)
	@palette.onMouseEnter(view)
end	

def onReturn(view)
	return if @algo.interrupt?
	execute_action
end

#Left Mouse Button Down pressed
def onLButtonDown(flags, x, y, view)
	return if @algo.interrupt?
	return if @palette.onLButtonDown(flags, x, y, view)
	@button_down = true
	@x_down = x
	@y_down = y
	entity_picked = [@pk_vertex, @pk_edge, @pk_face].find { |e| e }
	if entity_picked
		add_remove_entity @selmode.entity_picked_from_mode(entity_picked)
	elsif !@invalid_pick && !@best_picked
		execute_action
	end	
	compute_tooltip
	view.invalidate
	show_info
end

#add or remove entity from selection
def add_remove_entity(lentity)
	@algo.add_remove_entity lentity
	if @algo.get_error_vertex.length > 0
		@palette.set_message @msg_some_errors, 'E'
	else
		@palette.set_message
	end

end

#Left Mouse Button Down pressed
def onLButtonUp(flags, x, y, view)
	return if @palette.onLButtonUp(flags, x, y, view)
end

#Switch between FreeScale and ScaleToTarget mode
def onLButtonDoubleClick(flags, x, y, view)
	check_entity_picked flags, x, y, view
	entity_picked = [@pk_vertex, @pk_edge, @pk_face].find { |e| e }
	if entity_picked
		entity_picked = (@pk_vertex) ? @pk_vertex.edges[0].all_connected : entity_picked.all_connected
		add_remove_entity entity_picked
	end	
	compute_tooltip
	view.invalidate
	show_info
end

#Execute the Rouding Edge operation
def execute_action
	if @algo.get_nb_edges > 0 && !@time_calculation
		GC.start
		@running = true
		@no_mark = true
		compute_tooltip
		@view.invalidate
		####sleep 0.1
		onSetCursor
		@algo.execute
		@running = false
	else
		exit_tool
	end	
end

#Notification of end of calculation
def end_calculation(time)
	@time_calculation = time
	@time_end = Time.now.to_f
	@palette.set_message
	@no_mark = false
	####UI.start_timer(0.1) { onMouseMove_zero }
	onMouseMove_zero
end

#Exit the tool
def exit_tool
	@model.select_tool nil
end

#Mouse Move methods
def onMouseMove_zero
	onMouseMove 0, @x, @y, @view if @x
end
	
def onMouseMove(flags, x, y, view)

	return unless x
	@x = x
	@y = y
	
	#Synchronize draw and move
	return if @moving
	@moving = true
	
	#Mouse within the palette
	if @palette.onMouseMove(flags, x, y, view)
		compute_tooltip if @time_calculation
		return
	end	

	@selmode.onMouseMove(flags, x, y, view)
	
	
	#Synchronize draw and move
	####return if @moving
	####@moving = true
	
	#Picking elements
	check_entity_picked flags, x, y, view
	
	compute_tooltip
	view.invalidate
	onSetCursor
	show_info
end
	
#Detremine which element is picked at mouse with check if valid
def check_entity_picked(flags, x, y, view)
	#ph.do_pick x, y
	(@aperture) ? @ph.do_pick(x, y, @aperture) : @ph.do_pick(x, y)
	
	@best_picked = @ph.best_picked
	@invalid_pick = false
	unless @best_picked && (@best_picked.class == Sketchup::Group || @best_picked.class == Sketchup::ComponentInstance)
		@ip.pick view, x, y	
		@pk_vertex = @ip.vertex
		@pk_edge = @ip.edge
		@pk_face = @ip.face
		check_pick_valid
		if @best_picked && !@invalid_pick && (@time_end == nil || (Time.now.to_f - @time_end) > 2.0)
			@time_calculation = nil
			@time_end = nil
		end	
	else
		@pk_vertex = nil
		@pk_edge = nil
		@pk_face = nil
		@invalid_pick = false
	end
end
	
def check_pick_valid
	entity = [@pk_vertex, @pk_edge, @pk_face].find { |e| e }
	if entity
		entity2 = @selmode.entity_with_draw_hidden entity
		if entity2 != entity
			entity = @pk_face = entity2
			@pk_vertex = @pk_edge = nil
		end	
		ledge = @selmode.entity_picked_from_mode(entity)
		ledge = (ledge) ? ledge.find_all { |e| @algo.accept_edge?(e) } : []
		@invalid_pick = ((ledge.length == 0) ? true : false)
	else
		@invalid_pick = false
	end	
end
	
#Drawing method for the Tool
def draw(view)

	#Drawing the mark for modifier
	@selmode.draw_mark(view, @x, @y) unless @no_mark
	####@moving = false

	#Drawing all lines
	@algo.get_all_lines_to_draw.each do |ll|
		draw_lines_with_offset view, ll[0], ll[1], ll[2], ll[3]
	end	

	#Vertex in error
	@algo.get_error_vertex.each do |key, v|
		view.draw_points v.position, 10, 2, 'red'
	end	
	@palette.set_message if @algo.get_error_vertex.length == 0
	
	#drawing the palette
	@palette.draw view
	@moving = false
end

#Draw all selected edges
def draw_lines_with_offset(view, lpt, color, width, stipple)
	return if lpt.length == 0
	lpt = lpt.collect { |pt| small_offset view, pt }
	view.line_width = width
	view.line_stipple = stipple
	view.drawing_color = color
	view.draw GL_LINES, lpt
end

#Calculate the point slightly offset to cover the edges
def small_offset(view, pt)
	pt2d = view.screen_coords pt
	ray = view.pickray pt2d.x, pt2d.y
	vec = ray[1]
	size = view.pixels_to_model 1, pt
	pt.offset vec, -size
end

#Standard method to accept text in the VCB: Offset distance and nb of segment
def onUserText(text, view)     
	Traductor::ReturnUp.set_on
	
	#Splitting the text
	ltext = []
	ltext1 = text.split ';'
	ltext1.each { |t| ltext += t.split(/\s/) }
	
	len = nil
	numseg = nil
	anglemax = nil
	numseglock = get_num_seg_lock
	ltext.each do |t|
		if t =~/s\Z/i
			numseg = Traductor.string_to_integer_formula $`
		elsif t =~/d\Z/i
			anglemax = Traductor.string_to_float_formula $`
		else	
			len = Traductor.string_to_length_formula t
		end	
	end	
	
	#Changing the offset and nb of segments
	if len
		if len <= 0
			UI.beep
		else
			@algo.change_offset len
		end	
	end
	if numseg
		if numseglock || numseg <= 0 || numseg > RoundCorner.max_seg
			UI.beep
		else
			@num_seg = @algo.change_numseg numseg
		end
	end	
	if anglemax	
		if anglemax < 0
			UI.beep
		else
			@selmode.set_anglemax anglemax
		end	
	end
	
	return UI.beep unless len || numseg || anglemax
		
	#Refreshing
	view.invalidate
	show_info	
end

#Manage the display of the status bar and VCB
def show_info
	return if @algo.running?
	
	#VCB display
	len = Sketchup.format_length @algo.get_offset
	nb = @algo.get_num_seg
	if get_num_seg_lock
		svalue = (len) ? "#{len} , [#{nb}s]": ""
	else
		svalue = (len) ? "#{len} , #{nb}s": ""
	end	
	label = @label
	
	#status message
	stext = @title_tool + ': ' + @msg_main
	
	Sketchup::set_status_text stext
	Sketchup::set_status_text label, SB_VCB_LABEL
	Sketchup::set_status_text svalue, SB_VCB_VALUE	
end

#Clean the VCB and status bar area
def clean_VCB
	Sketchup::set_status_text ''
	Sketchup::set_status_text '', SB_VCB_LABEL
	Sketchup::set_status_text '', SB_VCB_VALUE	
end

end	#class RoundCornerTool
	
end	#End Module RoundCorner
