=begin
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
# Designed by Fredo6 - Copyright April 2009

# 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			:   HoverSelect_Palette.rb
# Original Date	:   8 May 2009 - version 1.0
# Description	:   Modules waiting for incorporation into LibFredo6
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
=end


module F6_HoverSelect

T6[:Palette_TIP_TipZone] = "Information area"
T6[:Palette_TIP_Pos] = "Position Top or Bottom"
T6[:Palette_TIP_Shrink] = "Shrink / Expand Palette"

#--------------------------------------------------------------------------------------------------------------
# Button Palette
#--------------------------------------------------------------------------------------------------------------			 

class Palette

Palette_Button = Struct.new "Palette_Button", :symb, :rank, :state, :tooltip, :tr, :tr1, :tr2, 
                                              :width, :height, :quad, :quad1, :quad2,
                                              :buttons, :value_proc, :action_proc, :draw_proc, :draw_code, :instructions,
                                              :bkcolor, :text, :xleft, :ybot, :computed, :draw_scale,
											  :parent, :value, :type, :multi, :main_color, :frame_color,
											  :passive, :hidden, :grayed, :selected

#Create a palette instance
def initialize(proc=nil, top_pos=true, height=32)
	@height = height
	@height2 = height / 2
	@proc = proc
	@top_pos = top_pos
	
	@lst_symbs = nil
	@lst_buttons = []
	@hsh_buttons = {}
	@widmax_tip = 400
	@wid_ctrl = 16
	@lrectnum = [0, 0, 1, 1]
	@tra_basis = [1, 0, 0, 0] + [0, -1, 0, 0] + [0, 0, 1, 0] + [0, 0, 0, 1]
	@computed = false	
	@ptxy = Geom::Point3d.new 0, 0, 0
	@origin = Geom::Point3d.new 0, @height, 0
	
	@bkcolor_normal = 'lightgrey'
	@bkcolor_hilight = 'lightgrey'
	@bkcolor_selected = 'oldlace'
	@bkcolor_down = 'oldlace'
	@frcolor_white = 'white'
	@frcolor_gray = 'gray'
	@frcolor_dark = 'darkgray'
	
	@id_cursor_hand = MYPLUGIN.create_cursor "Hand", 2, 2	
	
	@tooltip = ""
	@nb_sepa = 0
	
	@view = Sketchup.active_model.active_view
	@standard_draw_proc = self.method "standard_draw_proc"
	
	#Create the standard buttons
	@button_shrink = create_button :_bt_shrink, { :tooltip => T6[:Palette_TIP_Shrink], :width => @height2, :rank => 1 }
	@button_pos = create_button :_bt_pos, { :tooltip => T6[:Palette_TIP_Pos], :width => @height2 }
	@button_tip = create_button :_bt_tip, { :tooltip => T6[:Palette_TIP_TipZone], :passive => true }
	adjust_draw_standard_button
end

def button_get_value(symb)
	button = @hsh_buttons[symb]
	(button) ? button.value : nil
end

#Create a button structure
def create_button(symb, *args, &action_proc)
	button = @hsh_buttons[symb]
	button = Palette_Button.new unless button
	button.symb = symb
	button.action_proc = action_proc
	args.each do |arg|	
		arg.each { |key, value|  parse_button_args(button, key, value) } if arg.class == Hash
	end
	@hsh_buttons[symb] = button
	button
end

#Declare the parent of a button
def button_set_parent(button, sparent)
	parent = @hsh_buttons[sparent]
	parent = create_button sparent unless parent
	parent.buttons = [] unless parent.buttons
	parent.buttons.push button unless parent.buttons.include?(button)
	button.parent = parent
end

def button_set_args(symb, *args)
	button = @hsh_buttons[symb]
	return unless button
	args.each do |arg|	
		arg.each { |key, value|  parse_button_args(button, key, value) } if arg.class == Hash
	end
end

def button_set_draw_proc(symb, draw_proc, main_color=nil, frame_color=nil)
	button = @hsh_buttons[symb]
	return unless button
	parse_button_args button, :draw_proc, draw_proc
	parse_button_args button, :main_color, main_color if main_color
	parse_button_args button, :frame_color, frame_color if frame_color
	button.instructions = nil
end

def adjust_draw_standard_button
	button_set_draw_proc :_bt_shrink, ((@shrinked) ? :triangle_EP : :triangle_WP), "red"
	button_set_draw_proc :_bt_pos, ((@top_pos) ? :triangle_SP : :triangle_NP), "green"
end

def parse_button_args(button, key, value)
	skey = key.to_s
	case skey
	when /width/i
		button.width = value
	when /height/i
		button.height = value
	when /parent/i
		button_set_parent button, value
	when /bk_color/i
		button.bkcolor = value
	when /rank/i
		button.rank = value
	when /tip/i
		button.tooltip = value
	when /text/i
		button.text = value
	when /passive/i
		button.passive = value
	when /main_color/i
		button.main_color = value
	when /frame_color/i
		button.frame_color = value
	when /type/i
		button.type = value
	when /draw_scale/i
		button.draw_scale = value
	when /draw_proc/i
		if value.class == Symbol
			button.draw_proc = @standard_draw_proc
			button.draw_code = value
		else
			button.draw_proc = value
		end	
	when /value_proc/i
		button.value_proc = value
	when /value/i
		button.value = value
	end	
	button.computed = false
end

#Declare a button
def declare_button(symb, *args, &action_proc)
	button = create_button symb, *args, &action_proc	
	@lst_buttons.push button unless button.parent
	@computed = false
	symb
end

def declare_separator
	s = '__sepa__' + @nb_sepa.to_s
	@nb_sepa += 1
	symb = s.intern
	declare_button symb, { :passive => true, :height => @height, :width => @height / 2, :draw_proc => :separator }
	symb
end

def concat_symb(symb, text)
	s = symb.to_s + '___' + text
	s.intern
end

def declare_edge_prop(symb, rgshow, *args, &action_proc)
	#declare_button(symb, { :type => 'multi' }, *args) { stateproc.call if stateproc }
	declare_button(symb, { :type => 'multi' }, *args, &action_proc)
	button = @hsh_buttons[symb]
	hp = { :parent => symb, :width => 32, :main_color => button.main_color}
	list = [['P', 'Plain', :edge_prop_plain], ['S', 'Soft', :edge_prop_soft], 
	        ['M', 'Smooth', :edge_prop_smooth], ['H', 'Hidden', :edge_prop_hidden]]
	list.each do |ll|
		code = ll[0]
		next unless !rgshow || code =~ rgshow
		tip = ll[1]
		sdraw = ll[2]
		declare_button concat_symb(symb, code), hp, { :draw_proc => sdraw, :value => code, :tooltip => tip }
	end	
	symb
end

def compute_button(button, forced=false)
	return if button.computed && !forced
	return compute_multi(button, forced=false) if button.type =~ /multi/i
	button.rank = 0 unless button.rank
	button.width = button.height unless button.width
	button.width = @height unless button.width
	button.height = button.width unless button.height
	button_make_quads button
	button.computed = true
end

def compute_multi(button, forced=false)
	return if button.computed && !forced
	w = 0
	button.height = @height2
	button.buttons.each do |b|
		b.rank = 0
		b.height = @height - button.height
		b.computed = false
		compute_button b
		w += b.width unless b.hidden	
	end
	button.width = w
	button.rank = 1
	button_make_quads button
	button.multi = true
	button.computed = true
end

def button_make_quads(button)
	button.quad = make_quad button.width, button.height
	button.quad1 = make_quad button.width, button.height, 1
	button.quad2 = make_quad button.width, button.height, 2
end

def check_multi_state(button)
	#sval = button.stateproc.call if button.stateproc
	sval = button.value_proc.call if button.value_proc
	button.value = sval
	lv = (sval) ? sval.upcase.split(';;') : nil
	button.buttons.each do |b|
		if b.value
			b.selected = (lv && !lv.include?(b.value.upcase)) ? false : true
		else
			b.selected = false
		end	
	end	
end

def compute_all
	@hsh_buttons.each { |symb, button|	compute_button button } unless @computed
	
	@lst_buttons.each do |button|
		if button.multi
			check_multi_state button if button.multi
		elsif button.value_proc
			button.selected = button.value_proc.call
		end	
	end
	
	return if @computed
	
	#Compute all buttons
	
	#initialization
	vpwid = @view.vpwidth
	@yref = (@top_pos) ? @height + 1 : @view.vpheight - 1
	
	#compute the width for the buttons
	widbut = 0
	@lst_buttons.each do |button|
		widbut += button.width
	end
	w = vpwid - widbut - @wid_ctrl
	@wid_tip = (w > @widmax_tip) ? @widmax_tip : w
	@xstart_button = @wid_tip + @wid_ctrl
	@button_tip.width = @wid_tip
	button_make_quads @button_tip
	
	#computing the basic buttons
	button_transfo @button_shrink, 0, 1
	button_transfo @button_pos, 0, 0
	button_transfo @button_tip, @wid_ctrl, 0
	
	#Computing the other buttons
	xpos = @xstart_button
	@lst_buttons.each do |button|
		if button.type == nil
			button_transfo button, xpos, button.rank
			xpos += button.width if button.rank == 0
		elsif button.type =~ /multi/i
			button_transfo button, xpos, button.rank
			x = xpos
			button.buttons.each do |b|
				next if b.hidden
				button_transfo b, x, 0
				x += b.width
			end
			xpos += button.width
		end	
	end
	
	#Computing the list of buttons
	@lst_visible_buttons = @hsh_buttons.values.sort { |b1, b2| b1.symb.to_s <=> b2.symb.to_s }
	
	#Declaring computing OK
	@computed = true
end

#Set the transformation for the button
def button_transfo(button, x, rank)
	button.xleft = @tra_basis[12] = x
	button.ybot = @tra_basis[13] = @yref - rank * button.height
	button.tr = Geom::Transformation.new @tra_basis
	@tra_basis[12] += 1
	@tra_basis[13] -= 1
	button.tr1 = Geom::Transformation.new @tra_basis
	@tra_basis[12] += 1
	@tra_basis[13] -= 1
	button.tr2 = Geom::Transformation.new @tra_basis
end

def make_quad(w, h, incr=0)
	pt1 = Geom::Point3d.new incr, incr, 0
	pt2 = Geom::Point3d.new incr, h - incr, 0
	pt3 = Geom::Point3d.new w - incr, h - incr, 0
	pt4 = Geom::Point3d.new w - incr, incr, 0
	[pt1, pt2, pt3, pt4]
end

def draw_button(view, button)
	return if button.hidden
	compute_button button
	bt_color = button.bkcolor
	clickable = button_is_clickable?(button)
	
	#drawing the area
	if !clickable
		bkcolor = (bt_color) ? bt_color : @bkcolor_normal
		width = 1
		color1 = @frcolor_dark
		color2 = @frcolor_dark
	elsif button.selected
		bkcolor = @bkcolor_selected
		width = 2
		color1 = @frcolor_gray
		color2 = @frcolor_white
	elsif button == @sel_button	
		bkcolor = @bkcolor_down
		width = 2
		color1 = @frcolor_gray
		color2 = @frcolor_white
	elsif button == @hi_button
		bkcolor = (bt_color) ? bt_color : @bkcolor_hilight
		width = 2
		color1 = @frcolor_white
		color2 = @frcolor_gray
	else	
		bkcolor = (bt_color) ? bt_color : @bkcolor_normal
		width = 1
		color1 = 'darkgray'
		color2 = 'darkgray'
	end	
	
	if width == 1
		t = button.tr
		quad = button.quad
		pts = quad.collect { |pt| t * pt }
		pts1 = [pts[1], pts[2]]
		pts2 = [pts[0], pts[3]]
	else
		t = button.tr1
		quad = button.quad1
		pts = quad.collect { |pt| t * pt }
		pts1 = [pts[0], pts[1], pts[2]]
		pts2 = [pts[2], pts[3], pts[0]]
	end	

	#drawing the background
	view.drawing_color = bkcolor
	view.draw2d GL_QUADS, pts
	
	#Drawing the content"
	content = draw_button_content view, button
	
	#drawing the border
	view.line_width = width
	view.line_stipple = ""
	view.drawing_color = color1
	view.draw2d GL_LINE_STRIP, pts1
	view.drawing_color = color2
	view.draw2d GL_LINE_STRIP, pts2
	
	#draw a border for groups
	if clickable && width == 1 && !content && button.text == nil
		view.drawing_color = 'silver'
		view.line_width = 1
		pts = button.quad2.collect { |pt| t * pt }
		view.draw2d GL_LINE_LOOP, pts
	end	
	
	#Draw the text if any
	if button.text && button.text.length > 0
		view.draw_text t * Geom::Point3d.new(3, button.height+1, 0), button.text
	end
end

def draw_button_content(view, button)
	#getting the instructions
	unless button.instructions
		if button.draw_code
			button.instructions = @standard_draw_proc.call(button.draw_code, button.width - 4, 
			                                               button.height - 4, button.main_color, button.frame_color,
														   button.draw_scale)
		else
			button.instructions = button.draw_proc.call(button.symb, button.width - 4, button.height - 4) if button.draw_proc
		end	
	end
	
	return false unless button.instructions
	
	#processing the instructions
	process_draw_GL view, button.tr2, button.instructions
end

#Top drawing method for the palette
def draw(view)
	compute_all
		
	#Drawing the elements
	list_visible.each { |button| draw_button view, button }
	
end

def set_tooltip(tooltip=nil)
	@button_tip.text = (tooltip) ? tooltip : ""
end

def toggle_shrinked
	@shrinked = !@shrinked
	adjust_draw_standard_button
	onMouseMove_zero
	@view.invalidate
end

def toggle_top_down
	@top_pos = !@top_pos
	adjust_draw_standard_button
	@computed = false
	compute_all
	onMouseMove_zero
	@view.invalidate
end

#check if a button is not clickable
def button_is_clickable?(button)
	!(button.passive || button.grayed || button.hidden)
end

def list_visible
	if (@shrinked)
		ls = [@button_pos, @button_shrink]
	else
		compute_all unless @lst_visible_buttons
		ls = @lst_visible_buttons
	end
	ls
end

def locate_button(x, y)
	#Quick test if within the palette
	@mouse_button = nil
	
	#Finding the button
	list_visible.each do |button|
		if x >= button.xleft && x <= button.xleft + button.width && y <= button.ybot && y >= button.ybot - button.height
			@mouse_button = button
			break
		end	
	end
	@mouse_button
end

#Set the cursor
def onSetCursor
	return false unless @mouse_button
	if button_is_clickable?(@mouse_button)
		ic = @id_cursor_hand
	else
		ic = 0
	end
	UI::set_cursor ic
	ic
end

def onMouseMove_zero
	onMouseMove -1, @x, @y, @view if @x
end

def onMouseMove(flags, x, y, view)
	return false if cancel_button_down(flags)	
	@x = x
	@y = y
	button = locate_button x, y
	unless button || @button_down
		@hi_button = nil
		return false
	end	
	
	if @button_down
		@hi_button = nil
		if button == nil || (@sel_button && button != @sel_button)
			return true
		end
	else	
		@hi_button = button
	end	
	if @hi_button
		@view.tooltip = @hi_button.tooltip
		@view.invalidate
	end	
	true
end

def onMouseLeave(view)
	@hi_button = false
	@view.invalidate
end

def onMouseEnter(view)
end

def cancel_button_down(flags)
	if (flags >= 0) && @button_down && (flags & 1 != 1)
		@hi_button = nil
		@sel_button = nil
		@button_down = false
		@view.invalidate
	end	
end	

#Button click - Means that we end the selection
def onLButtonDown(flags, x, y, view)
	button = locate_button x, y
	return false unless button
	@button_down = true
	@view.tooltip = ""
	@sel_button = button
	@sel_button = nil unless button_is_clickable?(@sel_button)
	@view.invalidate
	true
end

#Button click - Means that we end the selection
def onLButtonUp(flags, x, y, view)
	button = locate_button x, y
	
	if button && !@button_down
		@hi_button = nil
		@view.invalidate
		return true
	end
	
	#Not an event for the palette
	unless @button_down && button
		@hi_button = nil
		@sel_button = nil
		@view.invalidate
		return false
	end
	
	@button_down = false
	
	#Trapping the click if clic up is on the same button as click down
	if @sel_button && button == @sel_button 
		execute_button @sel_button if button_is_clickable?(@sel_button)
	else
		
	end

	@sel_button = nil
	@view.invalidate
	true
end

#Execution of action when clicking on button
def execute_button(button)
	#skip passive, hidden, grayed buttons
	return unless button && button_is_clickable?(button)
	
	symb = button.symb
	
	#Standard
	if symb == :_bt_pos
		return toggle_top_down
	elsif symb == :_bt_shrink
		return toggle_shrinked
	end
	
	#Checking multiple button
	parent = button.parent
	if parent && parent.multi
		execute_multi button, parent
		button = parent
	elsif button.multi
		lv = []
		button.buttons.each { |b| lv.push b.value if b.value }
		button.value = lv.join(';;')		
	end	
	
	#Calling the custom proc
	if button.action_proc
		button.action_proc.call
	elsif @proc	
		@proc.call :click, button.symb, button.value
	end	
end

def execute_multi(button, parent)
	sval = parent.value
	lv = (sval) ? sval.split(';;') : []
	if button.selected
		lv -= [button.value]
	else
		lv.push button.value unless lv.include?(button.value)
	end
	parent.value = lv.join ';;'
end

def process_draw_GL(view, t, lgl)
	return false unless lgl && lgl.length > 0
	view.drawing_color = 'black'
	view.line_stipple = ''
	view.line_width = 1
	
	lgl.each do |ll|
		code = ll[0]
		begin
			next unless ll[1]
			if code.class == String && code == 'T'
				view.draw_text t * ll[1], ll[2]
			else
				view.drawing_color = ll[2] if ll[2]
				view.line_width = ll[3] if ll[3]			
				view.line_stipple = ll[4] if ll[4]
				pts = ll[1].collect { |pt| t * pt }
				view.draw2d ll[0], pts
			end	
		rescue
			puts "problem with draw GL"
		end
	end	
	true
end

def standard_draw_proc(code, dx, dy, main_color=nil, frame_color= nil, scale=nil)
	lst_gl = []
	scode = code.to_s
	case scode
	
	when /separator/i
		xmid = dx / 2 - 1
		pt1 = Geom::Point3d.new xmid, 1, 0
		pt2 = Geom::Point3d.new xmid, dy - 1, 0
		lst_gl.push [GL_LINE_STRIP, [pt1, pt2], @frcolor_dark]
		xmid += 1
		pt1 = Geom::Point3d.new xmid, 1, 0
		pt2 = Geom::Point3d.new xmid, dy - 1, 0
		lst_gl.push [GL_LINE_STRIP, [pt1, pt2], @frcolor_white]
		
	when /edge_prop/i
		opengl_edge_prop lst_gl, dx, dy, code, main_color

	when /valid/i
		opengl_valid lst_gl, dx, dy, code, main_color, frame_color, scale
		
	when /line/i
		opengl_line lst_gl, dx, dy, code, main_color, frame_color, scale

	when /cross/i
		opengl_cross lst_gl, dx, dy, code, main_color, frame_color, scale

	when /triangle/i
		opengl_triangle lst_gl, dx, dy, code, main_color, frame_color, scale
		
	when /arrow/i
		opengl_arrow lst_gl, dx, dy, code, main_color, frame_color, scale
		
	when /circle/i
		opengl_circle lst_gl, dx, dy, code, main_color, frame_color, scale
		
	end
	
	lst_gl
end

#--------------------------------------------------------------------------------------------------------------
# Standrad Open GL instructions for common button drawing
#--------------------------------------------------------------------------------------------------------------			 

#Transformation for NSEW orientation
def opengl_orientate(code, ptmid, scale=nil)
	scode = (code) ? code.to_s : ''
	ts = (scale) ? Geom::Transformation.scaling(ptmid, scale) : Geom::Transformation.new
	factor = 0
	case scode
	when /NE/i ; factor = 0.25
	when /NW/i ; factor = 0.75
	when /SW/i ; factor = 1.25
	when /SE/i ; factor = 1.75
	when /E/i ; factor = 0
	when /W/i ; factor = 1		
	when /N/i ; factor = 0.5
	when /S/i ; factor = 1.5
	else ; factor = 0
	end
	t = Geom::Transformation.rotation ptmid, Z_AXIS, Math::PI * factor
	t * ts
end
		
#drawing instruction for edge properties	
def opengl_edge_prop(lst_gl, dx, dy, code, maincolor=nil)
	maincolor = 'black' unless maincolor
	x = dx * 3 / 4
	case code
	when :edge_prop_plain
		line = 'line_2'
	when :edge_prop_soft	
		line = 'line_U'
	when :edge_prop_smooth	
		line = 'line_'
		maincolor = 'darkgray'
	when :edge_prop_hidden	
		line = 'line_U'
		maincolor = 'darkgray'
	end
	opengl_line lst_gl, dx, dy, line, maincolor
end
	
#Drawing instructions for lines	
def opengl_line(lst_gl, dx, dy, code, maincolor=nil, frame_color=nil, scale=nil)
	maincolor = 'black' unless maincolor
	ymid = dy / 2
	pts = [Geom::Point3d.new(1, ymid, 0), Geom::Point3d.new(dx - 1, ymid, 0)]
	ptmid = Geom::Point3d.new dx / 2, dy / 2, 0
	scode = code.to_s
	border = (scode =~ /\d/) ? $&.to_i : 1
	stipple = (stipple) ? stipple : ''
	
	scode =~ /line/i
	ori = $'
	t = opengl_orientate ori, ptmid, scale
	
	case ori
	when /U/i ; stipple = '_'
	when /D/i ; stipple = '-'
	when /A/i ; stipple = '-.-'
	else ; stipple = ''
	end
	
	lpts = pts.collect { |pt| t * pt }
	color = (frame_color) ? frame_color : maincolor
	lst_gl.push [GL_LINE_STRIP, lpts, color, border, stipple] if border > 0	
end
	
#Drawing instructions for lines	
def opengl_cross(lst_gl, dx, dy, code, maincolor=nil, frame_color=nil, scale=nil)
	maincolor = 'black' unless maincolor
	ymid = dy / 2
	xmid = dx / 2
	pts1 = [Geom::Point3d.new(1, ymid, 0), Geom::Point3d.new(dx - 1, ymid, 0)]
	pts2 = [Geom::Point3d.new(xmid, 1, 0), Geom::Point3d.new(xmid, dy - 1, 0)]
	ptmid = Geom::Point3d.new dx / 2, dy / 2, 0
	scode = code.to_s
	border = (scode =~ /\d/) ? $&.to_i : 1
	stipple = (stipple) ? stipple : ''
	
	scode =~ /cross/i
	ori = $'
	t = opengl_orientate ori, ptmid, scale
	
	case ori
	when /U/i ; stipple = '_'
	when /D/i ; stipple = '-'
	when /A/i ; stipple = '-.-'
	else ; stipple = ''
	end
	
	lpts1 = pts1.collect { |pt| t * pt }
	lpts2 = pts2.collect { |pt| t * pt }
	color = (frame_color) ? frame_color : maincolor
	lst_gl.push [GL_LINE_STRIP, lpts1, color, border, stipple] if border > 0	
	lst_gl.push [GL_LINE_STRIP, lpts2, color, border, stipple] if border > 0	
end
	
#Drawing instructions for lines	
def opengl_valid(lst_gl, dx, dy, code, maincolor=nil, frame_color=nil, scale=nil)
	maincolor = 'green' unless maincolor
	ymid = dy / 2
	xmid = dx / 2
	pts = [Geom::Point3d.new(1, ymid - 2, 0), Geom::Point3d.new(xmid, 1, 0), Geom::Point3d.new(dx - 1, dy - 1, 0)]
	ptmid = Geom::Point3d.new dx / 2, dy / 2, 0
	scode = code.to_s
	border = (scode =~ /\d/) ? $&.to_i : 4
	stipple = (stipple) ? stipple : ''
	
	scode =~ /valid/i
	ori = $'
	scale = 0.5 unless scale
	t = opengl_orientate ori, ptmid, scale
	
	case ori
	when /U/i ; stipple = '_'
	when /D/i ; stipple = '-'
	when /A/i ; stipple = '-.-'
	else ; stipple = ''
	end
	
	lpts = pts.collect { |pt| t * pt }
	color = (frame_color) ? frame_color : maincolor
	lst_gl.push [GL_LINE_STRIP, lpts, color, border, stipple] if border > 0	
end
	
#Drawing instructions for triangles	
def opengl_triangle(lst_gl, dx, dy, code, maincolor=nil, frame_color=nil, scale=nil)
	maincolor = 'black' unless maincolor
	ymid = dy / 2
	pts = [Geom::Point3d.new(1, 2, 0), Geom::Point3d.new(1, dy - 2, 0), Geom::Point3d.new(dx - 1, ymid, 0)]
	ptmid = Geom::Point3d.new dx / 2, dy / 2, 0
	scode = code.to_s
	plain = (scode =~ /p/i)
	border = (scode =~ /\d/) ? $&.to_i : 0
	plain = true if border == 0
	
	scode =~ /triangle/i
	ori = $'
	t = opengl_orientate ori, ptmid, scale	
	lpts = pts.collect { |pt| t * pt }
	if plain
		lst_gl.push [GL_POLYGON, lpts, maincolor]
	end	
	color = (frame_color) ? frame_color : maincolor
	lst_gl.push [GL_LINE_LOOP, lpts, color, border] if border > 0	
end
	
#Drawing instructions for Circle or portions of circle	
def opengl_circle(lst_gl, dx, dy, code, maincolor=nil, frame_color=nil, scale=nil)
	maincolor = 'black' unless maincolor
	ptmid = Geom::Point3d.new dx / 2, dy / 2, 0
	scode = code.to_s
	
	nb = 6
	pts = []
	anglesec = Math::PI / 2 / nb
	xmid = dx / 2
	ymid = dy / 2
	for i in 0..nb
		angle = anglesec * i
		pts.push Geom::Point3d.new(xmid * (1 + Math.cos(angle)), ymid * (1 + Math.sin(angle)), 0)
	end
	
	lsectors = [0, 1, 2, 3]
	case scode
	when /_NE/i ; lsectors = [0]
	when /_SE/i ; lsectors = [1]
	when /_SW/i ; lsectors = [2]
	when /_NW/i ; lsectors = [3]
	when /_N/i ; lsectors = [0, 3]
	when /_S/i ; lsectors = [2, 1]
	when /_W/i ; lsectors = [3, 2]
	when /_E/i ; lsectors = [1, 0]
	else
		lsectors = [0, 3, 2, 1]
	end
	
	scale = 0.8 unless scale
	lpts = []
	lt = ['E', 'S', 'W', 'N']
	lsectors.each do |i|
		t = opengl_orientate lt[i], ptmid, scale
		lpts += pts.collect { |pt| t * pt }
	end	
			
	plain = (scode =~ /p/i)
	border = (scode =~ /\d/) ? $&.to_i : 0
	center = (scode =~ /X/i)
	plain = true if border == 0
	
	lpts += [ptmid] if lsectors.length == 1 && (plain || center)
	gl_code = (plain || center) ? GL_LINE_LOOP : GL_LINE_STRIP
	
	if plain
		lst_gl.push [GL_POLYGON, lpts, maincolor]
	end	
	color = (frame_color) ? frame_color : maincolor
	lst_gl.push [gl_code, lpts, color, border] if border > 0	
end
	
#Drawing instructions for Circle or portions of circle	
def opengl_arrow(lst_gl, dx, dy, code, maincolor=nil, frame_color=nil, scale=nil)
	maincolor = 'black' unless maincolor
	#dy = dy - 1 if (dy / 2) * 2 == dy
	scode = code.to_s

	#drawing the reference arrow
	ymid = dy / 2
	y13 = dy / 3
	y23 = y13 * 2
	x34 = dx / 2 
	ptmid = Geom::Point3d.new dx / 2, ymid, 0
	
	pts = []
	pts.push Geom::Point3d.new(1, y23, 0)
	pts.push Geom::Point3d.new(x34, y23, 0)
	pts.push Geom::Point3d.new(x34, dy - 1, 0)
	pts.push Geom::Point3d.new(dx - 1, ymid, 0)
	pts.push Geom::Point3d.new(x34, 1, 0)
	pts.push Geom::Point3d.new(x34, y13, 0)
	pts.push Geom::Point3d.new(1, y13, 0)
	pts1 = [pts[0], pts[1], pts[5], pts[6]]
	pts2 = [pts[2], pts[3], pts[4]]
	
	#Computing the sectors	
	scode =~ /arrow/i
	arrow = $'
	lsectors = []
	lsectors.push 0 if arrow =~ /R/i
	lsectors.push 1 if arrow =~ /U/i
	lsectors.push 2 if arrow =~ /L/i
	lsectors.push 3 if arrow =~ /D/i
		
	scale = 0.78 unless scale
	if lsectors.length > 1
		scale *= 0.5
		vec = ptmid.vector_to pts[3]
		tt = Geom::Transformation.translation vec
		gl_code = GL_LINE_STRIP
	else
		tt = Geom::Transformation.new
		gl_code = GL_LINE_LOOP
	end
	tvec1 = Geom::Transformation.translation Y_AXIS		
	
	plain = (scode =~ /p/i)
	border = (scode =~ /\d/) ? $&.to_i : 0
	plain = true if border == 0
	
	tori = opengl_orientate(arrow, ptmid)
	
	lpts = []
	lpts1 = []
	lpts2 = []
	lt = ['E', 'N', 'W', 'S']
	lsectors.each do |i|
		t = tori * opengl_orientate(lt[i], ptmid, scale) * tt
		#t = tvec1 * t if i == 0
		lpts.push pts.collect { |pt| t * pt }
		if plain
			lpts1.push pts1.collect { |pt| t * pt }
			lpts2.push pts2.collect { |pt| t * pt }
		end	
	end	
	
	if plain
		lpts1.each { |pts| lst_gl.push [GL_POLYGON, pts, maincolor] }
		lpts2.each { |pts| lst_gl.push [GL_POLYGON, pts, maincolor] }
	end	
	if border > 0
		color = (frame_color) ? frame_color : maincolor
		lpts.each do |pts|
			lst_gl.push [gl_code, pts, color, border] if border > 0
		end
	end	
end
		
end	# class Palette

end	#module F6_HoverSelect

