//*--------------------------- SciWave toolbox -----------------------------*//
// name of the function = fview
// version : 2.0
// authors : Rémy Abergel, Lionel Moisan
// function : view (or flip) one (or two) grayscaled image(s) in a window, intensity displayed is rescaled to be into [0,255]
// usage : figure_handle = fview(im1, [optional] im2, [optional] o, [optional] z)
//
// input description:
//	- im1 (matrix): pixel map of the first image
//	- im2 (matrix): [optional] pixel map of the second image
//	- o (Default = 0): interpolation order for sub-pixel transformation (zoom, translation)
//	    available interpolations are:
//     		order = 0           nearest neighbor (default)
//     		order = 1           bilinear
//     		order = -3          bicubic Keys
//     		order = 3,5,7,9,11  spline with specified order
//	- z (Default = 1): zoom factor for display
//
// output description:
//    figure_handle (handle): handle of the Scilab figure
//
// interactive Mouse commands: 
//	Left button: toggle to print the gray level at the current coordinates (x,y).
//	Middle button: Restore the image (also available using key 'o').
//	Right button: Local zooming.
//
// interactive Keyboard commands:
//	'q': Quit.
//	'h': Help. // TODO
//	'o': Restore the image.
//	'u': Unzoom x2.
//	'l': Plot the current Line section.
//	'c': Plot the current Column section.
//	'g': Maximize contrast.
//	'm': Change interpolation order.
//	'w': change contrast, pointed value become white
//	'b': change contrast, pointed value become black
//	Space:        Toggle images.
//	Left arrow:   Go Left.
//	Right arrow:  Go Right.
//	Up arrow:     Go Up.
//	Down arrow:   Go Down.
// 
// example: 
//	fview(grand(512,512,'uin',0,255),z=1,o=0); 
//	fview(grand(256,256,'uin',0,255),z=2,o=5); 
//	fview(grand(256,256,'uin',0,255),grand(256,256,'uin',0,255)); 
//*-------------------------------------------------------------------------*//
// v1.0 (10/2012): initial version (Rémy)
//*-------------------------------------------------------------------------*//


function [fig_hdl] = fview(im_mat1,im_mat2,o,z)

	//* Deal with optional inputs *//
	nb_max_ipt = 4; 
	nb_input = argn(2);  
	if ((~exists("im_mat1","local"))|(nb_input > nb_max_ipt)) then 
		str = 	"/*--------------------------------------- FVIEW -------------------------------------*/\n" + ...
			"/* authors: Rémy Abergel & Lionel Moisan                                             */\n" + ... 
			"/* view (or flip) one (or two) grayscaled image(s) in a window                       */\n" + ...
			"/*-----------------------------------------------------------------------------------*/\n" + ...
			"usage: fig_hdl = fview(im1,im2,o,z)\n" + ...
			"     - im1 : (matrix of double) pixel map of the first image\n" + ...
			"     - im2 [optional] : (matrix of double) pixel map of the second image\n" + ...
			"     - o [optional, def. 0] : interpolation order (0,1,-3,3,5,7,9,11)\n" + ...
			"     - z [optional, def. 1] : display zoom factor (at interpolation order = o)\n" + ...
			"     - fg_hdl [optional] : handle of the Scilab figure\n"; 
		printf(str); 	
		error(39);
	end
	defset = 0; 
	if ~exists("im_mat2","local") then flip_mode = 0; defset = defset+1; else flip_mode = 1; end
	if ~exists("o","local") then o = 0; defset = defset+1; end; 
	if ~exists("z","local") then z = 1; defset = defset+1; end;
	if (defset ~= nb_max_ipt-nb_input) then 
		printf("you entered an unrecognized input name\n"); 
		error(999); 
	end

	//* basic consistency checks *//
	[height width] = size(im_mat1);
	if length(size(im_mat1)) == 3 then 
		im_mat1 = 0.2126*im_mat1(:,:,1) + 0.7152*im_mat1(:,:,2) + 0.0722*im_mat1(:,:,3); 
		warning("Color information has been lost !");  
	end 
	if flip_mode then
		[h,w] = size(im_mat2);
		if ((h~=height)|(w~=width)) then error("The two inputs must have the same dimensions",60); end
		if length(size(im_mat2)) == 3 then 
			im_mat2 = 0.2126*im_mat2(:,:,1) + 0.7152*im_mat2(:,:,2) + 0.0722*im_mat2(:,:,3); 
			warning("Color information has been lost !");  
		end 
	end

	//* Deal with display zoom *//
	// TODO Deal properly with z option
	if (z ~= 1) then 
		im_mat1 = imresample(im_mat1,1:1/z:width,1:1/z:height,o);
		if flip_mode then 
			im_mat2 = imresample(im_mat2,1:1/z:width,1:1/z:height,o);
		end
		[height width] = size(im_mat1);
	end

	//* compute coefficients for contrast change *//
	m = min(im_mat1); M = max(im_mat1);
	if (M-m)==0 then m = 0; if M == 0 then M = 1; end end // deal with constant image case, to avoid division by zero

	//* Now let's build the image viewer *//
	fig_hdl = figure(); // NB: fig_hdl = figure("axes_size",[width,height],"auto_resize","off"); does not work well, because after "File", "Tools", "Edit" & "?" menus deletion, the dimensions will be wrong!
	delmenu(fig_hdl.figure_id,gettext("&File"));  //delete File menu (work for all languages)
	delmenu(fig_hdl.figure_id,gettext("&Tools")); //delete Tools menu.    
	delmenu(fig_hdl.figure_id,gettext("&Edit"));  //delete Edit menu.
	delmenu(fig_hdl.figure_id,gettext("&?"));     //delete help menu.
	str_id = sprintf("%d",fig_hdl.figure_id);
	fig_hdl.color_map = graycolormap(256); //set a linear gray colormap with 256 gray levels varying linearly from black to white.
	if nb_input == 1 then nme = "image n°"+str_id; else nme = "input n°1"; end
	fig_hdl.figure_name = nme;
	toolbar(fig_hdl.figure_id,'off'); //remove the toolbar.
	fig_hdl.axes_size = [width,height]; 
	fig_hdl.auto_resize = "off";

	//* attach some usefull data to this figure entity *//
	fig_hdl.user_data=[0,1,flip_mode,m,M,1,1,width,1,height,o]; 
	// = [left_click_info,zoom_info,flip_mode,min_input1,max_input1,displayed_input,X1,X2,Y1,Y2] 
	// user_data(1) <=> left_click_info = 0 for "even-time left-click, 1 for "odd-time left-click"
	// user_data(2) <=> zoom_info =1 for 100%, 2 for 200% etc. 
	// user_data(3) <=> flip_mode = 0 (off) or 1 (on) 
	// user_data(4) <=> coeff m for contrast change g(u) = 255/(M-m) * (u -m) 
	// user_data(5) <=> coeff M for contrast change g(u) = 255/(M-m) * (u -m) 
	// user_data(6) <=> displayed_input = 1 or 2  (always 1 if flip_mode == 0, else it changes each time "space" key is pressed)
	// [ user_data(7) , user_data(8) ] <=> [ Xi , Xf ]  such as sampling X-grid is Xi:1/zoom_factor:Xf
	// [ user_data(9) , user_data(10) ] <=> [ Yi , Yf ]  such as sampling Y-grid is Yi:1/zoom_factor:Yf

	//* adjust axes properties *//
	ax_hdl=gca();//get current axes handle
	ax_hdl.data_bounds = [1,1;width,height];
	ax_hdl.axes_visible = ["off","off","off"];
	ax_hdl.isoview = "on";
	ax_hdl.tight_limits = "on"; //axes will adapt in order to fit exactly with the data_bounds
	ax_hdl.margins = [0,0,0,0];

	//* Let's declare several global variables *// 
	// - a copy of the inital 2 images' data
	// - a "to_display" variable that will be used in case of flip_mode==1
	execstr("global f" + str_id + "_initpixmp1");
	execstr("f" + str_id + "_initpixmp1 = im_mat1"); 
	execstr("global f" + str_id + "_crt1");
	execstr("f" + str_id + "_crt1 = im_mat1"); 
	if flip_mode then
		execstr("global f" + str_id + "_initpixmp2");
		execstr("f" + str_id + "_initpixmp2 = im_mat2"); 
		execstr("global f" + str_id + "_crt2");
		execstr("f" + str_id + "_crt2 = im_mat2"); 
	end

	//* Now we can plot the (rescaled) first image *//
	Matplot((255/(M-m))*(im_mat1-m)); //rescale im_mat1 values into [0,255]
	mtplt_hdl = gce();
	mtplt_hdl.user_data=["Matplot",str_id]; //Tag the Matplot entity

	//* Add an event handler function *//
	fig_hdl.event_handler = "event_fview"
	fig_hdl.event_handler_enable = "on";	
endfunction



function event_fview(win,x,y,ibut)
	scf(win);
	fig_hdl = gcf();
	str_id = sprintf("%d",fig_hdl.figure_id);

	if (ibut == -1000) then // Quit event
		execstr("clearglobal f" + str_id + "_initpixmp1");
		execstr("clearglobal f" + str_id + "_crt1");
		if fig_hdl.user_data(3) then // flip_mode is ON
			execstr("clearglobal f" + str_id + "_initpixmp2");
			execstr("clearglobal f" + str_id + "_crt2");
		end
		return 
	else
		mtplt_hdl = findobj("user_data",["Matplot",str_id]); //retreive Matplot object using its tag
		execstr("global f" + str_id + "_initpixmp1"); //global variable declaration (this variable contains the initial pix_map for input 1)
		execstr("global f" + str_id + "_crt1");
		if fig_hdl.user_data(3) then // flip_mode is ON
			execstr("global f" + str_id + "_initpixmp2"); //global variable declaration (this variable contains the initial pix_map for input 2)
			execstr("global f" + str_id + "_crt2");
		end 
		execstr("[height,width] = size(f"+str_id+"_initpixmp1)");

		if ibut == 3 then // left click detected
			if fig_hdl.user_data(1) then //odd-time left-click, info_message has to be killed
				fig_hdl.user_data(1)=0; 
				fig_hdl.info_message = ""; 
			else // even-time left-click, info_message has to be shown
				fig_hdl.user_data(1)=1; 
				execstr(sprintf("pix_val = f%s_crt%d(y+1,x+1)",str_id,fig_hdl.user_data(6)));
				fig_hdl.info_message = " (x="+string(x)+ " , y="+string(y) + ") value="+string(pix_val);
			end

		elseif ((ibut == -1)&(fig_hdl.user_data(1))) then // mouse pointer has moved AND info_message is not empty
			execstr(sprintf("pix_val = f%s_crt%d(y+1,x+1)",str_id,fig_hdl.user_data(6)));
			fig_hdl.info_message = " (x="+string(x)+ " , y="+string(y) + ") value="+string(pix_val); 
		
		elseif (ibut == 5)|(ibut == 37)|(ibut == 38)|(ibut == 39)|(ibut == 40)|(ibut == 117)|(ibut == 109) then
			usrdat = fig_hdl.user_data; 
			// compute new sampling grid //
			if (ibut == 5)|(ibut == 117) then // right-click OR key 'u' pressed event ==> ZOOM x2 OR ZOOM x0.5
				x0sci = usrdat(7) + x/usrdat(2); y0sci = usrdat(9) + y/usrdat(2); 
				usrdat(2) = ((ibut==5)*2+(ibut==117)*0.5)*usrdat(2);
				if (usrdat(2) == 1)&(ibut == 117) then // unzoom asked @ zoom factor == 1, set sampling grid = initial grid
					usrdat(7) = 1; usrdat(8) = width; 
					usrdat(9) = 1; usrdat(10) = height; 
				else 
					usrdat(7) = x0sci-x/usrdat(2); usrdat(8) = x0sci + (width-x-1)/usrdat(2); 
					usrdat(9) = y0sci-y/usrdat(2); usrdat(10) = y0sci + (height-y-1)/usrdat(2); 
				end
			elseif (ibut == 109) then // key 'm' has been pressed ==> CHANGE INTERPOLATION ORDER
				select usrdat(11) 
					case 0  then usrdat(11) =  1; 
					case 1  then usrdat(11) = -3; 
					case -3 then usrdat(11) =  3; 
					case 3  then usrdat(11) =  5; 
					case 5  then usrdat(11) =  7; 
					case 7  then usrdat(11) =  9; 
					case 9  then usrdat(11) = 11; 
					case 11 then usrdat(11) =  0; 
				end 
				disp("changed interpolation order to "+string(usrdat(11)));
			elseif (ibut == 37) then // left arrow key has been pressed ==> TRANSLATION
				nc = 0.1*(usrdat(8)-usrdat(7));
				usrdat(7) = usrdat(7)-nc;
				usrdat(8) = usrdat(8)-nc;
			elseif (ibut == 38) then // top arrow key has been pressed ==> TRANSLATION
				nc = 0.1*(usrdat(10)-usrdat(9));
				usrdat(9) = usrdat(9)-nc;
				usrdat(10) = usrdat(10)-nc;
			elseif (ibut == 39) then // right arrow key has been pressed ==> TRANSLATION
				nc = 0.1*(usrdat(8)-usrdat(7));
				usrdat(7) = usrdat(7)+nc;
				usrdat(8) = usrdat(8)+nc;
			elseif (ibut == 40) then // bottom arrow key has been pressed ==> TRANSLATION
				nc = 0.1*(usrdat(10)-usrdat(9));
				usrdat(9) = usrdat(9)+nc;
				usrdat(10) = usrdat(10)+nc;
			end
			
			Xgrid = usrdat(7):(1/usrdat(2)):usrdat(8);
			Ygrid = usrdat(9):(1/usrdat(2)):usrdat(10);

			//* compute transformed images & update display *//
			execstr("f"+str_id+"_crt1 = imresample(f"+str_id+"_initpixmp1,Xgrid,Ygrid,usrdat(11));"); 
			if usrdat(3) then // flip mode
				execstr("f"+str_id+"_crt2 = imresample(f"+str_id+"_initpixmp2,Xgrid,Ygrid,usrdat(11));"); 
			end
			execstr(sprintf("mtplt_hdl.data = min(255,max(0,(255/(usrdat(5)-usrdat(4)))*(f%s_crt%d-usrdat(4))));",str_id,usrdat(6)));

			//* deal with figure_name & info_message *//
			fig_hdl.figure_name = sprintf("input n°%d (zoom: x"+string(usrdat(2))+")",usrdat(6));
			if(usrdat(1)) then 
				execstr(sprintf("pix_val = f%s_crt%d(y+1,x+1)",str_id,usrdat(6)));
				fig_hdl.info_message = " (x="+string(x)+ " , y="+string(y) + ") value="+string(pix_val); 
			end
			fig_hdl.user_data = usrdat;

		elseif ((ibut == 4)|(ibut == 111)) then // middle click has been done or key 'o' has been pressed ==> draw back initial image
			//* draw back initial image *//
			execstr(sprintf("m = min(f%s_initpixmp%d)",str_id,fig_hdl.user_data(6))); 
			execstr(sprintf("M = max(f%s_initpixmp%d)",str_id,fig_hdl.user_data(6)));
			if (M-m)==0 then m = 0; if M == 0 then M = 1; end end // deal with constant image case, to avoid division by zero
			fig_hdl.user_data(4) = m; fig_hdl.user_data(5) = M; 
			execstr(sprintf("f%s_crt1 = f%s_initpixmp1;",str_id,str_id));
			if fig_hdl.user_data(3) then //flip mode
				execstr(sprintf("f%s_crt2 = f%s_initpixmp2;",str_id,str_id));
			end
			execstr(sprintf("mtplt_hdl.data = (255/(M-m))*(f%s_initpixmp%d-m);",str_id,fig_hdl.user_data(6)));
			//* deal with figure_name & info_message *//
			fig_hdl.figure_name = sprintf("input n°%d",fig_hdl.user_data(6));
			if fig_hdl.user_data(1) then 
				execstr(sprintf("pix_val = f%s_crt%d(y+1,x+1)",str_id,fig_hdl.user_data(6)));
				fig_hdl.info_message = " (x="+string(x)+ " , y="+string(y) + ") value="+string(pix_val); 
			end
			//* update zoom factor, X1, X2, Y1 & Y2 *//
			fig_hdl.user_data(2)=1;
			fig_hdl.user_data(7) = 1; fig_hdl.user_data(8) = width;
			fig_hdl.user_data(9) = 1; fig_hdl.user_data(10) = height;

		elseif ((ibut == 32)&(fig_hdl.user_data(3))) then // Space key has been pressed AND flip_mode is "on" ==> FLIP
			fig_hdl.user_data(6) = modulo(fig_hdl.user_data(6),2)+1; 
			m = fig_hdl.user_data(4); M = fig_hdl.user_data(5); 
			execstr(sprintf("mtplt_hdl.data = min(255,max(0,(255/(M-m))*(f%s_crt%d-m)))",str_id,fig_hdl.user_data(6)));
			//* deal with figure_name & info_message *//
			fig_hdl.figure_name = sprintf("input n°%d",fig_hdl.user_data(6));
			if(fig_hdl.user_data(1)) then 
				execstr(sprintf("pix_val = f%s_crt%d(y+1,x+1)",str_id,fig_hdl.user_data(6)));
				fig_hdl.info_message = " (x="+string(x)+ " , y="+string(y) + ") value="+string(pix_val); 
			end
		
		elseif ibut == 99 then //key "c" has been pressed
			if(findobj('user_data',["column_seg"])==[]) then
				xsegs([x,x],[0,height-1],addcolor([1,0,0])); // creates segment and add red color to the colormap
				colseg=gce();
				colseg.user_data=["column_seg"];
			end

		elseif ibut == -99 then //key "c" has been released
			delete(gce());
			fig_hdl.color_map(size(fig_hdl.color_map,1),:)=[]; //remove redcolor from the colormap
			nme = sprintf("%s: column plot (x=%d)",fig_hdl.figure_name,x);
			execstr(sprintf("linecol_plot(fig_hdl,f%s_crt%d(:,x+1),nme)",str_id,fig_hdl.user_data(6)));

		elseif ibut == 108 then //key "l" has been pressed
			if(findobj('user_data',["line_seg"])==[]) then
				xsegs([0,width-1],[height-1-y,height-1-y],addcolor([1,0,0])); // creates segment and add red color to the colormap
				colseg=gce();
				colseg.user_data=["line_seg"];
			end

		elseif ibut == -108 then // key "l" has been released
			delete(gce());
			fig_hdl.color_map(size(fig_hdl.color_map,1),:)=[]; //remove redcolor from the colormap
			nme = sprintf("%s: line plot (y=%d)",fig_hdl.figure_name,y);
			execstr(sprintf("linecol_plot(fig_hdl,f%s_crt%d(y+1,:),nme)",str_id,fig_hdl.user_data(6)));

		elseif ibut == 103 then // key 'g' has been pressed ==> rescale gray levels
			//* compute new contrast change coefficients *//
			execstr(sprintf("m = min(f%s_crt%d)",str_id,fig_hdl.user_data(6)));
			execstr(sprintf("M = max(f%s_crt%d)",str_id,fig_hdl.user_data(6)));
			if (M-m)==0 then m = 0; if M == 0 then M = 1; end end // deal with constant image case, to avoid division by zero
			fig_hdl.user_data(4) = m; fig_hdl.user_data(5) = M;
			//* update display *//
			execstr(sprintf("mtplt_hdl.data = (255/(M-m))*(f%s_crt%d-m)",str_id,fig_hdl.user_data(6)));

		elseif ibut == 113 then // key 'q' has been pressed ==> quit
			execstr("clearglobal f" + str_id + "_initpixmp1");
			execstr("clearglobal f" + str_id + "_crt1");
			if fig_hdl.user_data(3) then 
				execstr("clearglobal f" + str_id + "_initpixmp2");
				execstr("clearglobal f" + str_id + "_crt2");
			end
			close (fig_hdl);

		elseif ibut == 98 // kew 'b' has been pressed ==> set pointed value to black
			execstr(sprintf("m = f%s_crt%d(y+1,x+1)",str_id,fig_hdl.user_data(6)));
			M = fig_hdl.user_data(5); 
			if (M == m) then m = 0; if (M==0) then M = 1; end end
			execstr(sprintf("mtplt_hdl.data = min(255,max(0,(255/(M-m))*(f%s_crt%d-m)))",str_id,fig_hdl.user_data(6)));
			fig_hdl.user_data(4) = m; fig_hdl.user_data(5) = M; 

		elseif ibut == 119 // kew 'w' has been pressed ==> set pointed value to white
			execstr(sprintf("M = f%s_crt%d(y+1,x+1)",str_id,fig_hdl.user_data(6)));
			m = fig_hdl.user_data(4); 
			if (M == m) then m = 0; if (M==0) then M = 1; end end
			execstr(sprintf("mtplt_hdl.data = min(255,max(0,(255/(M-m))*(f%s_crt%d-m)))",str_id,fig_hdl.user_data(6)));
			fig_hdl.user_data(4) = m; fig_hdl.user_data(5) = M; 
		end
	end
endfunction
