; Nombre: boxtable__define.pro
; Autor: Antonio Santiago

;BoxTable permite definir un widget_base con una tabla "imaginaria".
;El widget queda dividido en filas y columnas, de forma que se pueden
;agragar otros widgets indicando la celda en la que se colocara.

;------------------------------------------------------------------------


;Inicializacion del objeto
function BoxTable::Init, parent, n_columns, n_rows, type, _EXTRA=e

	;Necesario indicar el widget padre.
	if(KEYWORD_SET(parent) EQ 0) then return, 0
	
	if(KEYWORD_SET(n_rows) EQ 0) then n_rows = 1 
	if(KEYWORD_SET(n_columns) EQ 0) then n_columns = 1
	if(KEYWORD_SET(max_children) EQ 0) then max_children = 1
	if(KEYWORD_SET(type) EQ 0) then type = 0
	
	self.parent = parent
	self.boxtable = widget_base(parent, _EXTRA=e)
	self.n_columns = n_columns
	self.n_rows = n_rows
	self.type = type
	self.child = ptr_new( REPLICATE({children}, n_columns, n_rows) )
	
	return, 1	
end


;Eliminamos contenido dinamico del HEAP
pro BoxTable::Cleanup
	ptr_free, self.child
end


;Obtine valores de las propiedades.
pro BoxTable::GetProperty, PARENT=parent, ID=id, N_COLUMNS=n_columns, $
	N_ROWS=n_rows, TYPE=type 

	parent = self.parent
	id = self.boxtable
	n_rows = self.n_rows
	n_columns = self.n_columns
	type = self.type
end					


;A�ade un wiget al boxtable en una posicion determinada.
pro BoxTable::Add, widget, xini, yini, xfin, yfin

	if( (xini EQ xfin) OR (xini GT xfin) ) then xfin = xini + 1
	if( (yini EQ yfin) OR (yini GT yfin) ) then yfin = yini + 1

	geo = widget_info(widget, /GEOMETRY)
		
	(*self.child)[xini,yini].id = widget
	
	;Guardamos ID del widget en esa posicion y el xini y yini al
	;que hacen referencia.
	for y=yini, yfin-1 do begin
		for x=xini, xfin-1 do begin
			(*self.child)[x,y].xsize = geo.xsize
			(*self.child)[x,y].ysize = geo.ysize
			(*self.child)[x,y].xoffset = geo.xoffset
			(*self.child)[x,y].yoffset = geo.yoffset
			(*self.child)[x,y].xini = xini
			(*self.child)[x,y].yini = yini
			(*self.child)[x,y].xfin = xfin
			(*self.child)[x,y].yfin = yfin
			(*self.child)[x,y].set = widget			
		endfor
	endfor

	if ( self.type EQ 0) then self->MakeHeterogeneo $
	else self->MakeHomogeneo
end


;------------------------------------------------------------------------
;Establece los offsets de los widgets para que queden situados segun
;lo indicado en forma de tabla.
pro BoxTable::MakeHomogeneo
	
	for y=0, (self.n_rows-1) do begin
		for x=0, (self.n_columns-1) do begin
			base_x = 0
			base_y = 0
			
			if( (*self.child)[x,y].id NE 0) then begin	
				for i=0, (x-1) do base_x = base_x + self->max_xsize_column(i)
				for i=0, (y-1) do base_y = base_y + self->max_ysize_row(i)
			
				id = (*self.child)[x,y].id
				widget_control, id, xoffset=base_x, yoffset=base_y				
;print, 'id='+string(id)+' x='+string(x)+' y='+string(y) + ' base_x='+string(base_x)+' base_y='+string(base_y)	
			endif					
		endfor
	endfor
;stop
end


;Dada una fila, la recorre de izquierda a derecha, y devuelve
;el valor maximo de y_size
function BoxTable::max_ysize_row, row

	max = 0
	for i=0, (self.n_columns-1) do begin
		;Si el valor es 0, es que no hay widget en esa celda. '0' es el 
		;valor de inicializacion.
		if( ((*self.child)[i, row].ysize GT max ) AND $
			((*self.child)[i, row].id NE 0) ) then $
					max=(*self.child)[i, row].ysize
	endfor
	return, max
end


;Dada una columna , la recorre de arriba a abajo, y devuelve
;el valor maximo de x_size
function BoxTable::max_xsize_column, column

	max = 0
	for i=0, (self.n_rows-1) do begin
		;Si el valor es 0, es que no hay widget en esa celda. '0' es el 
		;valor de inicializacion.
		if( ((*self.child)[column, i].xsize GT max ) AND $
			((*self.child)[column, i].id NE 0) ) then $
					max = (*self.child)[column, i].xsize
	endfor
	return, max
end

;------------------------------------------------------------------------

;Establece los offsets de los widgets para que queden situados segun
;lo indicado en forma de tabla.
;Permite sitiar juntos widget de una misma fila o culumna
pro BoxTable::MakeHeterogeneo
	
	for y=0, (self.n_rows-1) do begin
		for x=0, (self.n_columns-1) do begin
			if( (*self.child)[x,y].id NE 0) then begin
	
				id = (*self.child)[x,y].id
				
				xini = (*self.child)[x,y].xini
				xfin = (*self.child)[x,y].xfin
				yini = (*self.child)[x,y].yini
				yfin = (*self.child)[x,y].yfin
;print, 'xini='+string(xini)+' xfin='+string(xfin)+' yini='+string(yini)+' yfin='+string(yfin)				
				base_x = self->max_xsize_offset(xini, xfin, yini, yfin)
				base_y = self->max_ysize_offset(xini, xfin, yini, yfin)				
				
				widget_control, id, xoffset=base_x, yoffset=base_y
;print, 'x='+string(x)+' y='+string(y) + ' base_x='+string(base_x)+' base_y='+string(base_y)														
			endif					
		endfor
	endfor
	
	;stop
end


;Devuelve el xoffset para la posicion inicial de un widget
function BoxTable::max_xsize_offset, xini, xfin, yini, yfin

	max = 0
	for row=yini, yfin-1 do begin	
		tam = 0
		;Calcula el tama�o de la columna que tiene
		;por encima.
		for colum=0, xini-1 do begin
			;Obtenemos ID, SET actuales y el SET de la columna anterior.
			act_id = (*self.child)[colum, row].id
			act_set = (*self.child)[colum, row].set						
			if( colum EQ 0 ) then begin
				prev_id = 0
				prev_set = 0
			endif else begin
				prev_id = (*self.child)[colum-1, row].id
				prev_set = (*self.child)[colum-1, row].set
			endelse
			
			;Comparamos con la celda anterior para saber si tenemos que
			;sumar su tama�o o no.
			if( act_id EQ act_set ) then $				
				tam = tam + (*self.child)[colum, row].xsize
			
			if( (act_id NE act_set) AND (act_id NE prev_id) AND (act_set EQ prev_set) ) then $
				tam = tam	;No hacemos nada, ya sumamos el tama�o antes.
				
			if( (act_id NE act_set) AND (act_id EQ prev_id) AND (act_set EQ prev_set) ) then $
				tam = tam	;No hacemos nada, ya sumamos el tama�o antes.
			
			if( (act_id NE act_set) AND (act_set NE prev_set) ) then $
				tam = tam + (*self.child)[colum, row].xsize		
		endfor
		;Nos quedamos con el tama�o de la columna mas grande.
		if( max LT tam ) then max = tam
	endfor

	return, max
end

;Devuelve el yoffset para la posicion inicial de un widget 
function BoxTable::max_ysize_offset, xini, xfin, yini, yfin

	max = 0
	for colum=xini, xfin-1 do begin
		tam = 0
		;Este 'for' calcula el tama�o de la fila que 
		;hay antes del widget.
		for row=0, yini-1 do begin
			;Obtenemos ID, SET actuales y el SET de la columna anterior.
			act_id = (*self.child)[colum, row].id
			act_set = (*self.child)[colum, row].set								
			if( row EQ 0 ) then begin
				prev_id = 0
				prev_set = 0	
			endif else begin
				prev_id = (*self.child)[colum, row-1].id
				prev_set = (*self.child)[colum, row-1].set
			endelse
			
			;Comparamos con la celda anterior para saber si tenemos que
			;sumar su tama�o o no.
;print, string(act_id)+string(act_set)+string(prev_id)+string(prev_set)
;print, 'x='+string(colum)+'y='+string(row)			
			if( act_id EQ act_set ) then begin
				;print, 1				
				tam = tam + (*self.child)[colum, row].ysize
			endif
			
			if( (act_id NE act_set) AND (act_id NE prev_id) AND (act_set EQ prev_set) ) then begin
				;print, 2				
				tam = tam	;No hacemos nada, ya sumamos el tama�o antes.
			endif
				
			if( (act_id NE act_set) AND (act_id EQ prev_id) AND (act_set EQ prev_set) ) then begin
				;print, 3
				tam = tam	;No hacemos nada, ya sumamos el tama�o antes.
			endif
			
			if( (act_id NE act_set) AND (act_set NE prev_set) ) then begin
				;print, 4
				tam = tam + (*self.child)[colum, row].ysize
			endif
			
;print, 'tam='+string(tam)
		endfor
		;Comprobamos el tama�o de la fila calculada y
		;nos quedamos con el maximo.
		if( max LT tam ) then max = tam
	endfor
	
	return, max
end


;Definicion de las estructuras del objeto.
;children - Estructura para cada widget hijo
;boxtable - Objeto BoxTable
pro BoxTable__define

	void = { children, $
		id:0L, $
		xsize:0L, $
		ysize:0L, $
		xoffset:0L, $
		yoffset:0L, $
		xini:0L, $
		yini:0L, $
		xfin:0L, $
		yfin:0L, $
		set:0 $
		}
	
	void = {boxtable, $
		parent:0L, $	;ID widget padre
		boxtable:0L, $	;ID boxtable widget
		n_rows:0, $
		n_columns:0, $
		type: 0, $		;0 - Heterogeneo, 1 - Homogeneo
		child: ptr_new() $
		}
end





