/*

// wrapper for {Picture} control, {Bitmap}, {Canvas}, {Font}

CLASS {AL4_drawing|_csharp}, NATIVE, UNTESTED, BYTES :
IMPORT: {Control}, {Bitmap}, {Stream}, {Icon},
        {String_functions}, {AL4_form},
        {Paintbox}, {File_stream}, {File_path}, {Long_int} .
IMPORT: {Canvas}, {Bitmap_direct}, {System_functions} .
IMPORT, ANYWAY: {Geometry}, {NATIVE_Stream_on_C_Stream} .

NATIVE: "using System.Windows.Forms;" .
NATIVE: "using System.Drawing;" .
NATIVE: "using System.Drawing.Imaging;" .

NATIVE: "///COPY WebPWrapper.cs" .

*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.IO;

using System.Runtime.InteropServices;
using System.Reflection;

using AL4;
using AL4_project;
//?{WebP}
 	using WebPWrapper;
//.

namespace AL4
{

public partial class AL4Form : Form
{
    
    /*
	TODO: "In Windows 8, SystemColors do not work properly. Thanks." .    

    FUNCTION Get_system_color(
    	{Canvas}.{system_color} C|olor_index) ==> INT, NATIVE :
    @   "switch (X_C)"
        "{"
        "case 0: RESULT = SystemColors.ActiveCaption.ToArgb();"
        "        break;"
        "case 1: RESULT = SystemColors.GradientActiveCaption.ToArgb();"
        "        break;"
        "case 2: RESULT = SystemColors.ActiveBorder.ToArgb();"
        "        break;"
        "case 3: RESULT = SystemColors.ActiveCaptionText.ToArgb();"
        "        break;"
        "case 4: RESULT = SystemColors.Control.ToArgb();"
        "        break;"
        "case 5: RESULT = SystemColors.ControlText.ToArgb();"
        "        break;"
        "case 6: RESULT = SystemColors.ControlLightLight.ToArgb();"
        "        break;"
        "case 7: RESULT = SystemColors.ControlDark.ToArgb();"
        "        break;"
        "case 8: RESULT = SystemColors.Desktop.ToArgb();"
        "        break;"
        "case 9: RESULT = SystemColors.GrayText.ToArgb();"
        "        break;"
        "case 10: RESULT = SystemColors.Info.ToArgb();"
        "        break;"
        "case 11: RESULT = SystemColors.InfoText.ToArgb();"
        "        break;"
        "case 12: RESULT = SystemColors.InactiveCaption.ToArgb();"
        "        break;"
        "case 13: RESULT = SystemColors.GradientInactiveCaption.ToArgb();"
        "        break;"
        "case 14: RESULT = SystemColors.InactiveBorder.ToArgb();"
        "        break;"
        "case 15: RESULT = SystemColors.InactiveCaptionText.ToArgb();"
        "        break;"
        "case 16: RESULT = SystemColors.Menu.ToArgb();"
        "        break;"
        "case 17: RESULT = SystemColors.MenuText.ToArgb();"
        "        break;"
        "case 18: RESULT = SystemColors.MenuHighlight.ToArgb();"
        "        break;"
        "case 19: RESULT = SystemColors.ScrollBar.ToArgb();"
        "        break;"
        "case 20: RESULT = SystemColors.Window.ToArgb();"
        "        break;"
        "case 21: RESULT = SystemColors.WindowText.ToArgb();"
        "        break;"
        "case 22: RESULT = SystemColors.WindowFrame.ToArgb();"
        "        break;"
        "case 23: RESULT = SystemColors.Highlight.ToArgb();"
        "        break;"
        "case 24: RESULT = SystemColors.HighlightText.ToArgb();"
        "        break;"
        "}" 
        "RESULT = (int)((RESULT & 0xFF) << 16 | (RESULT & 0xFF0000) >> 16 |"
        "         (RESULT & 0xFF00) | 0xFF000000);"
        .
        
	FUN Get_rgba_order ==> {Canvas}.{rgba_order} := 'R_G_B_A' .

    
    FUN Create_paint_box(
        {Control} P|icture_control,
        STR Scroll|_and_focus_options_VHF) ==> INT
        :
        INT form|_handle = P.Form_.Handle
        
        RESULT = do_Create_paint_box(form, P, "V" IN Scroll, "H" IN Scroll,
        	"F" IN Scroll, TRUE)
        .
    FUN do_Create_paint_box(
    	INT Form|_handle, {Control} P|icture_control,
    	BOOL Vert|ical_scroll, BOOL Hor|izontal_scroll,
    	BOOL Focus|able, BOOL Calls_paint|_event) ==> INT, NATIVE : @
        "RESULT = AL4Form.Do_Create_paintbox("
        "	(int)X_Form, X_P, X_Vert, X_Hor, X_Focus, X_Calls_paint);" .
        
    FUN Create_scene_2D(
        {Control} P|icture_control,
        STR Options|_V_H_F) ==> INT
        :
        INT form|_handle = P.Form_.Handle
        
        RESULT = do_Create_paint_box(form, P,
        	"V" IN Options, "H" IN Options, "F" IN Options, FALSE)
        .

    */
    public static int Do_Create_paintbox(int H, Ref_obj X_P, bool X_V, bool X_H, 
            bool Can_focus, bool Calls_paint)
    {
        AL4Column C = AL4Form.Get_parent_for_new_control(H);
        Scrolled_paintbox P = new Scrolled_paintbox(X_V, X_H, Can_focus, X_P);
        int Result = AL4Form.AllocDescriptor(P);
        P.Tag = X_P;
        P.Parent = C;
        C.Child_controls.Add(P);
        Adjust_control_location(C);
        P.PBox.Tag = X_P;
        Set_control_events(C, P);
        AL4Form.Set_control_events(C, P.PBox);
        P.PBox.MouseDown += new MouseEventHandler(P.Control_MouseDown);
        P.PBox.Paint += new PaintEventHandler(PaintBox_Paint);
        P.PBox.Resize += new EventHandler(PaintBox_Resize);
        P.PBox.Enter += new EventHandler(P.Control_Enter);
        P.PBox.Leave += new EventHandler(P.Control_Leave);
        return Result;
    }
    
    /*
    
    FUN Invalidate_paintbox(INT H|andle_paint_box,
        {Geometry}.{rect} R|ectangle_invalidate)
        :
		do_Invalidate(H, R.Loc.X, R.Loc.Y, R.Width, R.Height) .
    FUN do_Invalidate(INT PB|ox_handle, REAL X|_rectangle,
    	REAL Y|_rectangle, REAL W|idth_rectangle, REAL H|eight_rectangle),
    	NATIVE : @
        "if (X_PB == 0) return;"
        "Scrolled_paintbox P "
        "	= (Scrolled_paintbox)AL4Form.All_descriptors[(int)X_PB];"
        "if (P.is_painting_now) return;"     
        "RectangleF R = new RectangleF(AL4Form.Points_float(X_X),"
        " 	AL4Form.Points_float(X_Y),"
        "	AL4Form.Points_float(X_W), AL4Form.Points_float(X_H));"
        "R.Inflate(1, 1);"
        "AL4Form.reset_exception_state(P.PBox);"     
        "P.PBox.Invalidate(new Rectangle((int)R.X, (int)R.Y, (int)R.Width,"
            "(int)R.Height));"
        .
        
    FUN Update_paintbox(INT H|andle_paint_box), NATIVE : @
    	"if (X_H == 0) return;"
        "Scrolled_paintbox P "
        "	= (Scrolled_paintbox)AL4Form.All_descriptors[(int)X_H];"
        "if (P.is_painting_now) return;"
        "AL4Form.reset_exception_state(P.PBox);"     
        "P.PBox.Update();" .
        
    FUN Get_invalid_rect(
    INT H|andle_paint_box, REAL A|rray_coords_dynamic[]): .

    FUN Set_paintbox_content_area(INT P|aint_box_handle,
        REAL W|idth_area_points, REAL H|eight_area_points,
        REAL Row_w|idth, REAL Line_h|eight), NATIVE :
	    CASE P == 0 ? ==> ;
	    NATIVE @     
    	"AL4Form.Do_set_content_area_size("
    	"	(int)X_P, X_W, X_H, X_Row_w, X_Line_h);" .
    */
    public static void Do_set_content_area_size(int C, double W, double H,
    	double row_w, double line_h)
    {
        Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors[C];
        P.Content_width = W;
        P.Content_height = H;
        P.row_width = row_w;
        P.line_height = line_h;

        P.Adjust_bars();
    }
    
    /*
    
 	FUN Paintbox_client_width(
 		INT P|aint_box_handle) ==> REAL, NATIVE :
	@	"Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors["
		"	(int)X_P];"
		"	RESULT = AL4Form.Pixels(P.PBox.Width);" .
	
 	FUN Paintbox_client_height(
 		INT P|aint_box_handle) ==> REAL, NATIVE :
	@	"Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors["
		"	(int)X_P];"
		"	RESULT = AL4Form.Pixels(P.PBox.Height);" .
	
    FUN Set_paint_lines_line_height(
    INT P|aint_box_handle,
    REAL H|eight_of_line_points), NATIVE :
	    CASE P == 0 ? ==> ;
	    NATIVE @     
        "      AL4Form.Do_set_paint_lines_line_height((int)X_P, X_H);" .
    */
    public static void Do_set_paint_lines_line_height(int C, double H)
    {
        Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors[C];
        try
        {
	        if (P.VBar != null)
	        {
	            P.VBar.SmallChange = (int)((AL4Form.Points(H) / P.coeff_vert));
	        }
        } catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
        P.Adjust_bars();
    }
    
    /*
    
    FUN Get_hscroll_height(
    	INT H|andle_paint_box) ==> REAL RESULT|_points, NATIVE :
        CASE H == 0 ? ==> ;
        NATIVE @
        "Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors["
        "	(int)X_H];"
        "if (P.HBar != null) RESULT = AL4Form.Pixels(P.HBar.Height);" .


    FUN Get_vscroll_width(
    	INT H|andle_paint_box) ==> REAL RESULT|_points, NATIVE :
        CASE H == 0 ? ==> ;
        NATIVE @
        "Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors["
        "	(int)X_H];"
        "if (P.VBar != null) RESULT = AL4Form.Pixels(P.VBar.Width);" .
        
        
    FUN Get_scroll_position(
        INT H|andle_paint_box,
        STR What|_box_VH) ==> REAL RESULT|_points, NATIVE
        :
        CASE H == 0 ? ==> ;
        BOOL v|ertical = "v" IN What.Lower
        BOOL h|orizontal = "h" IN What.Lower
        NATIVE @
        "Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors["
        "	(int)X_H];"
        "if (X_v && P.VBar != null) {"
        "	if (P.coeff_vert <= 1)"     
        "   	RESULT = P.VBar.Value;"
        "   else RESULT = P.VBar.Value * P.coeff_vert;"
        "}"
        "else if (X_h && P.HBar != null) {"
        "	if (P.coeff_horz <= 1)"
        "		RESULT = P.HBar.Value;"     
        "   else RESULT = P.HBar.Value * P.coeff_horz;" 
        "}" .
        
        
    FUN Set_scroll_position(
        INT H|andle_paint_box,
        STR What|_box_VH, REAL Value|_points), NATIVE
        :
        CASE H == 0 ? ==> ;
        BOOL v|ertical = "v" IN What.Lower
        BOOL h|orizontal = "h" IN What.Lower
        NATIVE @
        "Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors["
        "	(int)X_H];"
        "if (X_v && P.VBar != null) {"
        "	int n = (int)Math.Round(P.VBar.Minimum + "
        "		X_Value / P.coeff_vert);"
        "   if (n >= P.VBar.Minimum && n <= P.VBar.Maximum) P.VBar.Value = n;"
        "}"
        "else if (X_h && P.HBar != null) {"
        "	int n = (int)Math.Round(P.HBar.Minimum + "
        "		X_Value / P.coeff_horz);"
        "	if (n >= P.HBar.Minimum && n <= P.HBar.Maximum)	P.HBar.Value = n;"
        "}"
        .
        
    */
    
    public static List<BitmapEx> All_bitmaps = new List<BitmapEx>();
    public static List<int> Free_bitmaps = new List<int>();
    
    //---------------------------------------------------------------------
    // Thanks to Lazy Evaluation Ltd for the code and solution the problem.
    static  List<Control> controls_need_reset_graphics = new List<Control>();
    static void ResetExceptionState(Control control) {
		typeof(Control).InvokeMember("SetState", BindingFlags.NonPublic |
			BindingFlags.InvokeMethod | BindingFlags.Instance, null,
			control, new object[] { 0x400000, false });
	}
	
	public static void reset_exception_state(Control control) {
        for (int i=controls_need_reset_graphics.Count-1; i >= 0; i--)
        {
			if (controls_need_reset_graphics[i] == control) {
				controls_need_reset_graphics.RemoveAt(i);
				ResetExceptionState(control);
				break;
			} 
        }
	}
    
    static void PaintBox_Paint(object sender, PaintEventArgs e)
    {
//? {Paintbox}
	FocusPictureBox PBox = null;
	Limit_handler.Lock_raise = true;
	bool raised_exception = false;
	try {
		try {
	        PBox = (FocusPictureBox)sender;
	        reset_exception_state(PBox);
	        C_Paintbox CPic = (C_Paintbox)((Ref_obj)PBox.Tag).Obj;
	        
	        Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors[
	        	(int)CPic.F_Handle];
	        	
	        Graphics g = e.Graphics;
	        
	        AL4Form AForm = (AL4Form)P.Parent.Parent;
	        C_Form Form = (C_Form)AForm.AL4Object.Obj;
	        C_Form F = Form;
	        
	 		P.is_painting_now = true;
	 		try {
		        F.Do.M_operation_started(21, CPic.hard_link);
		        try {
			        try {
				        CPic.Do.M_before_paint();
				        AL4Form.Do_transform_reset(CPic.F_Canvas);
			        }
			        catch (Exception Ex) {
			        	controls_need_reset_graphics.Add(PBox);
			        	if (Ex is AL4_Exception) {
			        		raised_exception = Ex is E_Limit_exceeded;
			        		throw;
			        	}
			        }
		        }
		        finally {
		        F.Do.M_operation_ended(21);
		        }
		        if (CPic.F_need_repaint)
	        	{
		            Screen_handler.Allow_handle_events -= 1;
		            try {
			            F.Do.M_operation_started(22, CPic.hard_link);
			            try {
			            	//if (!F.Do.M_paint_skip())
			            	{
					            try {
					            Form.Do.M_paint();
					            }
					            catch (Exception Ex) {
					            	controls_need_reset_graphics.Add(PBox);
						        	if (Ex is AL4_Exception) {
						        		raised_exception = Ex is E_Limit_exceeded;
						        		throw;
						        	}
						        }
			            	}
			            }
			            finally {
			            F.Do.M_operation_ended(22);
			            }
		            }
		            finally {
		            Screen_handler.Allow_handle_events += 1;
		            }
		        }
		        F.Do.M_operation_started(23, CPic.hard_link);
		        try {
			        try {
			        CPic.Do.M_after_paint();        
			        }
			        catch (Exception Ex) {
			        	controls_need_reset_graphics.Add(PBox);
			        	if (Ex is AL4_Exception) {
			        		raised_exception = Ex is E_Limit_exceeded;
			        		throw;
			        	}
			        }
		        }
		        finally {
		        F.Do.M_operation_ended(23);
		        }
	        
		        C_Bitmap CBmp = (C_Bitmap)CPic.F_buffer.Obj;
		        if (CBmp.F_Handle != 0)
		        {
		            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)CBmp.F_Handle];
		            g.DrawImageUnscaled(B.Bmp, new Point(0, 0));
		            //if (true)
		            //	B.Bmp.Save("test_save.bmp");
		        }	
	 		}
	 		finally {
	 			P.is_painting_now = false;
	 		}
		}
		catch (Exception Ex2) {
			if (PBox != null) controls_need_reset_graphics.Add(PBox);
			if (Ex2 is AL4_Exception) {
				raised_exception = Ex2 is E_Limit_exceeded;
				throw;
			}
		}
		
	}
	finally {
		Limit_handler.Lock_raise = false;
		if (Limit_handler.Need_raise > 0) {
			controls_need_reset_graphics.Add(PBox);
			int id = Limit_handler.Need_raise; 
			Limit_handler.Need_raise = -1;
			if (!raised_exception)
				throw new E_Limit_exceeded(id);
		}
	}
	
//.
    }
    
    static void PaintBox_Resize(object sender, EventArgs e)
    {
    	AL4Form.reset_exception_state((FocusPictureBox)sender);
        ((FocusPictureBox)sender).Invalidate();
    }

    
    

    /*
    
    // Invalidate picture control
    //---------------------------
    
    FUN Invalidate_picture(
    	INT H|andle_picture_control), NATIVE :
        "      AL4Form.Do_Invalidate_picture((int)X_H);" .
    */
    public static void Do_Invalidate_picture(int H)
    {
        FocusPictureBox P = (FocusPictureBox)AL4Form.All_descriptors[H];
        P.Invalidate();
    }

    //------------------------------------------ B I T M A P

    /*
    // Create BitmapEx object, return descriptor.
    //-------------------------------------------
    
    FUN Create_bitmap({Bitmap} B|itmap_object,
        INT Bpp|bits_per_pixel) ==> INT, NATIVE :
        "    RESULT = AL4Form.Do_Create_bitmap(X_B, (int)X_Bpp);" .
    */
    ///-public static int Total_bitmaps_count;
    
    public static int Do_Create_bitmap(Ref_obj X_B, int X_Bpp)
    {
        PixelFormat PF = PixelFormat.Format32bppArgb;
        switch (X_Bpp)
        {
            case 1: PF = PixelFormat.Format1bppIndexed; break;
            case 4: PF = PixelFormat.Format4bppIndexed; break;
            case 8: PF = PixelFormat.Format8bppIndexed; break;
            case 15: PF = PixelFormat.Format16bppRgb555; break;
            case 16: PF = PixelFormat.Format16bppRgb565; break;
            case 24: PF = PixelFormat.Format24bppRgb; break;
        }
        C_Bitmap C_B = (C_Bitmap)(X_B.Obj);
        BitmapEx B = new BitmapEx(PF, (int)C_B.F_Width, (int)C_B.F_Height);
        B.RefBmp = X_B;
        B.Bmp.Tag = X_B;
        int Result = AL4Form.AllocBitmapDescr(B);
        
        //--------------------------------------
        //Total_bitmaps_count += 1;
        //Console.WriteLine("Create bitmap " + B.Bmp.Width.ToString() + "x" +
        //    B.Bmp.Height.ToString() + " --> " + Total_bitmaps_count.ToString() );
        //--------------------------------------
        return Result;
    }
    
    public static int AllocBitmapDescr(BitmapEx obj)
    {
        if (All_bitmaps.Count == 0)
            All_bitmaps.Add(new BitmapEx(PixelFormat.Format32bppRgb, 1, 1));
        if (Free_bitmaps.Count > 0)
        {
            int Result = Free_bitmaps[Free_bitmaps.Count-1];
            Free_bitmaps.RemoveAt(Free_bitmaps.Count-1);
            
            All_bitmaps[Result] = obj;
            return Result;
        }
        All_bitmaps.Add(obj);
        return All_bitmaps.Count - 1;
    }

    public static void ReleaseBitmapDescr(int idx)
    {
        if (idx <= 0) return;
        All_bitmaps[idx] = null;
        Free_bitmaps.Add(idx);
    }

    
    
    /*
    
    FUN Get_bitmap_depth(
    	INT B|itmap_handle) ==> INT RESULT|bpp_or_0, NATIVE :
		CASE B <= 0 ? ==> ;
		NATIVE @
		"   BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];"
        "   RESULT = B.Bpp;" .
    
    // Set Bitmap new size
    //--------------------
    
    FUN Set_bitmap_size(INT B|itmap_handle,
        INT W|idth_bitmap, INT H|eight_bitmap), NATIVE :
		CASE B <= 0 ? ==> ;
		NATIVE @
        "     AL4Form.Do_Set_bitmap_size((int)X_B, (int)X_W, (int)X_H);" .
    */
    public static void Do_Set_bitmap_size(int X_B, int X_W, int X_H)
    {
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
        if (B.Bmp.Width == X_W && B.Bmp.Height == X_H) return;
        Bitmap New = new Bitmap(X_W, X_H, B.Bmp.PixelFormat);
        New.Tag = B.Bmp.Tag;
        if (B.Bmp.Width > 1 && B.Bmp.Height > 1)
        {
	        Graphics g = Graphics.FromImage(New);
	        try
	        {
	            g.DrawImageUnscaled(B.Bmp, new Point(0, 0));
	        }
	        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
	            	else return;
                }
        }
        B.Bmp.Dispose();
        B.Bmp = New;
    }

    /*
    // Load Bitmap from file
    //----------------------
    
    FUN Load_bitmap_native|_from_file(
    INT B|itmap_handle, STR Path|_image_file)
    	:
    	{File_stream} temp|_stream = Read_file_stream(Path)
    	NONE = Get_bitmap_from_stream(temp, B) .
        
	FUN Get_bitmap_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL, NATIVE :
		BYTE a|s_memory_bytes[]
		CASE !Source.Load_bytes(a[], Source.Size.To_int) ? ==> ;
		NATIVE @
		"	RESULT = AL4Form.Do_get_bitmap_from_stream(X_a, (int)X_B, 1);" .

	//FUN Load_jpeg_native|_from_file(
	//INT B|itmap_handle, STR Path|_image_file) : Load_bitmap_native(B, Path) .
	
	FUN Get_jpeg_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL, NATIVE :
		BYTE a|s_memory_bytes[]
		CASE !Source.Load_bytes(a[], Source.Size.To_int) ? ==> ;
		NATIVE @
		"	RESULT = AL4Form.Do_get_bitmap_from_stream(X_a, (int)X_B, 1);" .

	FUN Get_jpeg_from_stream_ex(
	{Stream} Source|_stream, INT B|itmap_handle, INT Div|ide_size) ==> BOOL,
	NATIVE :
		BYTE a|s_memory_bytes[]
		CASE !Source.Load_bytes(a[], Source.Size.To_int) ? ==> ;
		NATIVE @
		"	RESULT = AL4Form.Do_get_bitmap_from_stream("
		"					 X_a, (int)X_B, (int)X_Div);" .

    //FUN Load_png_native|_from_file(
    //INT B|itmap_handle, STR Path|_image_file) : Load_bitmap_native(B, Path) .

	FUN Get_png_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL, NATIVE :
		BYTE a|s_memory_bytes[]
		CASE !Source.Load_bytes(a[], Source.Size.To_int) ? ==> ;
		NATIVE @
		"	RESULT = AL4Form.Do_get_bitmap_from_stream(X_a, (int)X_B, 1);" .

	FUN Get_png_from_stream_ex(
	{Stream} Source|_stream, INT B|itmap_handle, INT Div|ide_size) ==> BOOL,
	NATIVE :
		BYTE a|s_memory_bytes[]
		CASE !Source.Load_bytes(a[], Source.Size.To_int) ? ==> ;
		NATIVE @
		"	RESULT = AL4Form.Do_get_bitmap_from_stream("
		"			 X_a, (int)X_B, (int)X_Div);" .

        
	//FUN Load_gif_native|_from_file(
	//INT B|itmap_handle, STR Path|_image_file) : Load_bitmap_native(B, Path) .
	
	FUN Get_gif_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL, NATIVE :
		BYTE a|s_memory_bytes[]
		CASE !Source.Load_bytes(a[], Source.Size.To_int) ? ==> ;
		NATIVE @
		"	RESULT = AL4Form.Do_get_bitmap_from_stream(X_a, (int)X_B, 1);" .

	FUN Get_animated_gif_from_stream
	|_in_CSharp_the_same_as_previous_one(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL, NATIVE :
	//DEBUG: ==> ;
		BYTE a|s_memory_bytes[]
		CASE !Source.Load_bytes(a[], Source.Size.To_int) ? ==> ;
		NATIVE @
		"	RESULT = AL4Form.Do_get_bitmap_from_stream(X_a, (int)X_B, 1);" .
		
	FUN Get_gif_frames_count(
	INT H|andle_gif) ==> INT, NATIVE : @
	"	BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_H];"
	"	FrameDimension dim = new FrameDimension(B.Bmp.FrameDimensionsList[0]);"
	"	RESULT = B.Bmp.GetFrameCount(dim);" .
	
	FUN Set_gif_current_frame(
	INT H|andle_gif, INT I|ndex_frame), NATIVE : @
	"	AL4Form.Do_Set_gif_current_frame((int)X_H, (int)X_I);" .
	
	*/
	public static void Do_Set_gif_current_frame(
	int X_H, int X_I)
	{
//?{Gif}
	 	BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_H];
	 	FrameDimension dim = new FrameDimension(B.Bmp.FrameDimensionsList[0]);
	 	B.Bmp.SelectActiveFrame(dim, X_I);
//.
	}
	/*
	
	FUN Get_gif_frame_duration(
	INT H|andle_gif) ==> INT RESULT|milliseconds,
	NATIVE : @
	"	BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_H];"
	"	PropertyItem item = B.Bmp.GetPropertyItem(0x5100);"
	"	RESULT = (item.Value[0] + item.Value[1] * 256) * 10;" .
    */
    
    public static bool dummyThumbnailCallback()
	{
	    return false;
	}
	
	public static Bitmap image_to_bitmap(Image im)
	{
//?{Bitmap}
		if (im is Bitmap) return (Bitmap)im;
		MemoryStream ms = new MemoryStream();
		im.Save(ms, ImageFormat.Bmp);
		ms.Position = 0;
		Bitmap result = (Bitmap)Bitmap.FromStream(ms);
		return result;
//.
	}
	
    public static bool Do_get_bitmap_from_stream(
    				   DynAByte X_A, int X_B, int X_Div)
    {
//?{Bitmap}
		if (X_B <= 0) return false;
        try
        {
			MemoryStream MS = new MemoryStream();
			byte[] buf = new byte[X_A.Count];
			for (int i = 0; i < X_A.Count; i++)
				buf[i] = X_A.get_byte(i); 
			MS.Write(buf, 0, X_A.Count);
			MS.Position = 0;
		
            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
            Bitmap New = null;
            if (X_Div == 1)
            	New = (Bitmap)Bitmap.FromStream(MS);
            else {
            	Image img = Image.FromStream(MS, true, false);
            	Image.GetThumbnailImageAbort dummyCallback =
    				new Image.GetThumbnailImageAbort(dummyThumbnailCallback);
            	Image thumbnail = img.GetThumbnailImage(
    				img.Width/X_Div, img.Height/X_Div,
    				dummyCallback, IntPtr.Zero);
            	New = image_to_bitmap(thumbnail);
            }
            Object tag = B.Bmp.Tag;
            
            B.Bmp.Dispose();
            B.Bmp = null;
            B.Bmp = New; // new Bitmap(New);
            B.Bmp.Tag = tag;
            
            C_Bitmap CB = (C_Bitmap)B.RefBmp.Obj;
            CB.F_Width = New.Width;
            CB.F_Height = New.Height;
            //B.Bmp.Save("test_save.bmp");
            //GC.Collect();
            //GC.WaitForPendingFinalizers();
            //GC.Collect();
			
			return CB.F_Width > 0 && CB.F_Height > 0; 
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
		return false;
    }

    /*
    
	FUN Get_pcx_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL : .
    
	FUN Get_psd_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL : .
	
	FUN Get_tga_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL : .

	FUN Get_tiff_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL, NATIVE : 
		BYTE a|s_memory_bytes[]
		CASE !Source.Load_bytes(a[], Source.Size.To_int) ? ==> ;
		NATIVE @
		"	RESULT = AL4Form.Do_get_bitmap_from_stream(X_a, (int)X_B, 1);" .

	FUN Get_webp_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL, NATIVE :
		BYTE a|s_memory_bytes[]
		CASE !Source.Load_bytes(a[], Source.Size.To_int) ? ==> ;
		NATIVE @     
		"RESULT = AL4Form.Do_get_webp_from_stream(X_a, (int)X_B);" .
		
	*/
    public static bool Do_get_webp_from_stream(DynAByte X_A, int X_B)
    {
//?{WebP}
		if (X_B <= 0) return false;
        try
        {
			byte[] buf = new byte[X_A.Count];
			for (int i = 0; i < X_A.Count; i++)
				buf[i] = X_A.get_byte(i); 
		
            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
            
            WebP ww = new WebP(); 
            Bitmap New = ww.Decode(buf);
            Object tag = B.Bmp.Tag;
            
            B.Bmp.Dispose();
            B.Bmp = null;
            B.Bmp = New; // new Bitmap(New);
            B.Bmp.Tag = tag;
            
            C_Bitmap CB = (C_Bitmap)B.RefBmp.Obj;
            CB.F_Width = New.Width;
            CB.F_Height = New.Height;
            //B.Bmp.Save("test_save.bmp");
            //GC.Collect();
            //GC.WaitForPendingFinalizers();
            //GC.Collect();
			
			return CB.F_Width > 0 && CB.F_Height > 0; 
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
		return false;
    }
    /*
	
		
	FUN Save_to_stream_webp(
	INT B|itmap_handle, {Stream} S|tream_dest, 
	REAL Q|uality_option, BOOL Lossless) ==> BOOL : .

	FUN Get_xpm_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL : .

	FUN Get_pcd_from_stream(
	{Stream} Source|_stream, INT B|itmap_handle) ==> BOOL : .
	    


    // Save Bitmap to file
    //----------------------
    
	FUN Save_to_stream_bmp(
	INT B|itmap_handle, {Stream} S|tream_dest) ==> BOOL, NATIVE : @
	"	RESULT = AL4Form.Do_Save_to_stream_bmp((int)X_B, X_S);" .

    FUN Save_bitmap_native|_to_file_default_format(
    	INT B|itmap_handle,
        STR Path|_image_file) ==> BOOL
        :
	CASE Path.Ext.Lower ?
	[".bmp"]: RESULT = B.Save_bitmap_bmp(Path)
	[".png"]: RESULT = B.Save_bitmap_png(Path)
	[".gif"]: RESULT = B.Save_bitmap_gif(Path)
	[".jpg", ".jpeg"]: RESULT = B.Save_bitmap_jpg(Path, 80) ; .
        
	FUN Save_bitmap_bmp(INT B|itmap_handle,
        STR Path|_image_file) ==> BOOL, NATIVE :
		CASE B <= 0 ? ==> ;
		NATIVE @
	"     RESULT = AL4Form.Do_Save_bitmap_bmp((int)X_B, X_Path);" .

	FUN Save_to_stream_png(INT B|itmap_handle,
	    {Stream} S|tream_dest, REAL Quality|_10_to_100) ==> BOOL, NATIVE : @
	    "RESULT = AL4Form.Do_Save_to_stream_png((int)X_B, X_S, (int)X_Quality);"
	    .
	
	FUN Save_bitmap_png(INT B|itmap_handle,
        STR Path|_image_file) ==> BOOL, NATIVE :
		CASE B <= 0 ? ==> ;
		NATIVE @
	"     RESULT = AL4Form.Do_Save_bitmap_png((int)X_B, X_Path);" .

	FUN Save_to_stream_jpg(INT B|itmap_handle,
	    {Stream} S|tream_dest, REAL Quality|_10_to_100) ==> BOOL, NATIVE : @
	    "RESULT = AL4Form.Do_Save_to_stream_jpg((int)X_B, X_S, (int)X_Quality);" .
	
	FUN Save_bitmap_jpg(INT B|itmap_handle,
        STR Path|_image_file, REAL Quality|_jpeg_10_100) ==> BOOL, NATIVE :
		CASE B <= 0 ? ==> ;
		NATIVE @
	"     RESULT = AL4Form.Do_Save_bitmap_jpg("
	"			   (int)X_B, X_Path, (int)X_Quality);" .

	FUN Save_bitmap_gif(INT B|itmap_handle,
        STR Path|_image_file) ==> BOOL, NATIVE :
		CASE B <= 0 ? ==> ;
		NATIVE @
	"     RESULT = AL4Form.Do_Save_bitmap_gif((int)X_B, X_Path);" .
	
	FUN Save_to_stream_gif(INT B|itmap_handle,
        {Stream} S|tream_dest) ==> BOOL, NATIVE :
		CASE B <= 0 ? ==> ;
		NATIVE @
	"     RESULT = AL4Form.Do_Save_to_stream_gif((int)X_B, X_S);" .
	
	FUN Can_load_bitmap_fmt(
	STR Format|_BMP_JPG_PNG_GIF_WEBP) ==> BOOL, NATIVE : 
	STR format|_uppered = Format.Upper
	NATIVE @
	"RESULT = AL4Form.Do_Can_load_bitmap_fmt(X_format);" .
	
	*/
	
	public static bool file_exists(String file_path)
	{
		if (File.Exists(file_path)) return true;
		String path_start = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
		return File.Exists(path_start + '\\' + file_path);
	}
	
	public static bool Do_Can_load_bitmap_fmt(String X_Format)
	{
		bool RESULT = false
//?{Bmp}
			|| X_Format == "BMP"
//.
//?{Jpeg}
			|| X_Format == "JPG" || X_Format == "JPEG"
//.
//?{Png}
			|| X_Format == "PNG"
//.
//?{Gif}
			|| X_Format == "GIF"
//.
//?{Icon}
			|| X_Format == "ICO"
			|| X_Format == "CUR"
//.
//?{WebP}
   			|| (X_Format == "WEBP") &&
   			   (IntPtr.Size == 8 && file_exists("libwebp64.dll")
   			   || IntPtr.Size == 4 && file_exists("libwebp32.dll"))
//.
//?{Tiff}
			|| (X_Format == "TIF" || X_Format == "TIFF")
//.
//?{Psd}
//			|| (X_Format == "PSD")
//.
			;
		return RESULT; 
	}
	
	/*

	FUN Can_save_bitmap_fmt(
	STR Format|_BMP_JPG_PNG_GIF) ==> BOOL, NATIVE : @
	"RESULT = AL4Form.Do_Can_save_bitmap_fmt(X_Format);" .
	
   	*/
   	public static bool Do_Can_save_bitmap_fmt(String X_Format)
   	{
		bool RESULT = false
//?{Bmp}
			|| X_Format == "BMP"
//.
//?{Jpeg}
			|| X_Format == "JPG"
//.
//?{Png}
			|| X_Format == "PNG"
//.
//?{Gif}
			|| X_Format == "GIF"
//.
			;
		return RESULT; 
   	}

	
    public static bool Do_Save_to_stream_bmp(int X_B, Ref_obj X_S)
    {
//?{Bmp}
        try
        {
            BitmapEx B = (BitmapEx)AL4Form.All_descriptors[(int)X_B];
            Stream S = NATIVE_Stream_on_C_Stream.Stream_from_C_Stream(
            	(C_Stream)X_S.Obj);
            B.Bmp.Save(S, ImageFormat.Bmp);
            return true;
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
        return false;
    }

    public static bool Do_Save_bitmap_bmp(int X_B, string X_Path)
    {
//?{Bmp}
        try
        {
            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
            using (var ms = new MemoryStream())
            {
            	Bitmap clone_bmp = new Bitmap(B.Bmp);
            	clone_bmp.Save(ms, ImageFormat.Bmp);
            	clone_bmp.Dispose();
            	clone_bmp = null;
            	save_memory_stream_to_file(ms, X_Path);
            }
            return File.Exists(X_Path);
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
        return false;
    }

    public static bool Do_Save_to_stream_png(int X_B, Ref_obj X_S, int X_Quality)
    {
//?{Png}
        try
        {
            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
            Stream S = NATIVE_Stream_on_C_Stream.Stream_from_C_Stream(
            	(C_Stream)X_S.Obj);
        	Bitmap clone_bmp = new Bitmap(B.Bmp);
        	clone_bmp.Save(S, ImageFormat.Png);
        	clone_bmp.Dispose();
        	clone_bmp = null;
            return true;
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
        return false;
    }
    
    public static bool Do_Save_bitmap_png(int X_B, string X_Path)
    {
//?{Png}
        try
        {
            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
            using (var ms = new MemoryStream())
            {
            	Bitmap clone_bmp = new Bitmap(B.Bmp);
            	clone_bmp.Save(ms, ImageFormat.Png);
            	clone_bmp.Dispose();
            	clone_bmp = null;
            	save_memory_stream_to_file(ms, X_Path);
            }
            return File.Exists(X_Path);
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
        return false;
    }
    
    private static ImageCodecInfo GetEncoder(ImageFormat format)
	{
	    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
	    foreach (ImageCodecInfo codec in codecs)
	    {
	        if (codec.FormatID == format.Guid)
	        {
	            return codec;
	        }
	    }
	    return null;
	}

    public static bool Do_Save_to_stream_jpg(int X_B, Ref_obj X_S, int X_Quality)
    {
//?{Jpeg}
        try
        {
            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
            ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg);
		
		    // Create an Encoder object based on the GUID
		    // for the Quality parameter category.
		    System.Drawing.Imaging.Encoder myEncoder =
		        System.Drawing.Imaging.Encoder.Quality;
		
		    // Create an EncoderParameters object.
		    // An EncoderParameters object has an array of EncoderParameter
		    // objects. In this case, there is only one
		    // EncoderParameter object in the array.
		    EncoderParameters myEncoderParameters = new EncoderParameters(1);
		
		    EncoderParameter myEncoderParameter = new EncoderParameter(
		    	myEncoder, X_Quality);
		    	
		    myEncoderParameters.Param[0] = myEncoderParameter;
		    Stream S = NATIVE_Stream_on_C_Stream.Stream_from_C_Stream(
		    	(C_Stream)X_S.Obj);
	    	Bitmap clone_bmp = new Bitmap(B.Bmp);
        	clone_bmp.Save(S, jgpEncoder, myEncoderParameters);
	    	clone_bmp.Dispose();
	    	clone_bmp = null;
            return true;
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
        return false;
    }
    
    public static bool Do_Save_bitmap_jpg(int X_B, string X_Path, int X_Quality)
    {
//?{Jpeg}
        try
        {
            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
            ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg);
		
		    // Create an Encoder object based on the GUID
		    // for the Quality parameter category.
		    System.Drawing.Imaging.Encoder myEncoder =
		        System.Drawing.Imaging.Encoder.Quality;
		
		    // Create an EncoderParameters object.
		    // An EncoderParameters object has an array of EncoderParameter
		    // objects. In this case, there is only one
		    // EncoderParameter object in the array.
		    EncoderParameters myEncoderParameters = new EncoderParameters(1);
		
		    EncoderParameter myEncoderParameter = new EncoderParameter(
		    	myEncoder, X_Quality);
		    	
		    myEncoderParameters.Param[0] = myEncoderParameter;
		    using (var ms = new MemoryStream())
		    {
		    	//B.Bmp.Save(X_Path, jgpEncoder, myEncoderParameters);
		    	Bitmap clone_bmp = new Bitmap(B.Bmp);
            	clone_bmp.Save(ms, jgpEncoder, myEncoderParameters);
		    	clone_bmp.Dispose();
		    	clone_bmp = null;
		    	save_memory_stream_to_file(ms, X_Path);
		    }
            //B.Bmp.Save(X_Path, ImageFormat.Jpeg);
            return File.Exists(X_Path);
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
        return false;
    }
    
    public static void save_memory_stream_to_file(MemoryStream ms, string Path)
    {
    	using (var fs = new FileStream(Path, FileMode.OpenOrCreate,
    		FileAccess.Write, FileShare.ReadWrite))
    	{
    		ms.Position = 0;
    		ms.WriteTo(fs);
    		fs.Close();
    		fs.Dispose();
    		//fs = null;
    	}
    	GC.Collect();
		GC.WaitForPendingFinalizers();
		GC.Collect();
    }

    public static bool Do_Save_bitmap_gif(int X_B, string X_Path)
    {
//?{Gif}
        try
        {
            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
            using (var ms = new MemoryStream())
            {
            	//B.Bmp.Save(X_Path, ImageFormat.Gif);
            	Bitmap clone_bmp = new Bitmap(B.Bmp);
            	clone_bmp.Save(ms, ImageFormat.Gif);
            	clone_bmp.Dispose();
            	save_memory_stream_to_file(ms, X_Path);
            }
            return File.Exists(X_Path);
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
        return false;
    }

    public static bool Do_Save_to_stream_gif(int X_B, Ref_obj X_S)
    {
//?{Gif}
        try
        {
            BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
            Stream S = NATIVE_Stream_on_C_Stream.Stream_from_C_Stream(
            	(C_Stream)X_S.Obj);
        	Bitmap clone_bmp = new Bitmap(B.Bmp);
        	clone_bmp.Save(S, ImageFormat.Gif);
        	clone_bmp.Dispose();
            return true;
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
        return false;
    }


    /*
    // Destroy Bitmap object
    //----------------------
    
    FUN Destroy_bitmap(INT B|itmap_handle), NATIVE :
		CASE B <= 0 ? ==> ;
		NATIVE @
        "     AL4Form.Do_Destroy_bitmap((int)X_B);" .
    */
    public static void Do_Destroy_bitmap(int X_B)
    {
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
        //---------------------------------
        //Total_bitmaps_count -= 1;
        //Console.WriteLine("destroy bitmap " + B.Bmp.Width.ToString() + "x" +
        //    B.Bmp.Height.ToString() + "-->" + Total_bitmaps_count.ToString());
    	//---------------------------------
        AL4Form.All_bitmaps[(int)X_B] = null;
        AL4Form.ReleaseBitmapDescr(X_B);
        B.Bmp.Dispose();
        B.Bmp = null;
        
    }
    
    /*
    
	FUN Draw_bitmap_rotated_flipped(
	INT Target|_bitmap_handle, INT Source|_bitmap_handle,
	INT Angle|_0_90_180_270,
	BOOL Flip_w|idth, BOOL Flip_h|eight), NATIVE : @
	"	RotateFlipType param = RotateFlipType.RotateNoneFlipNone;"
	"	switch (X_Angle)"
	"	{"
	"	case 0: if (X_Flip_w && X_Flip_h)"
	"				param = RotateFlipType.RotateNoneFlipXY;"
	"			else if (X_Flip_w) param = RotateFlipType.RotateNoneFlipX;"
	"			else if(X_Flip_h) param = RotateFlipType.RotateNoneFlipY;"
	"			else param = RotateFlipType.RotateNoneFlipNone;"
	"			break;"
    "	case 90:if (X_Flip_w && X_Flip_h)"
    "				param = RotateFlipType.Rotate90FlipXY;"
	"			else if (X_Flip_w) param = RotateFlipType.Rotate90FlipX;"
	"			else if(X_Flip_h) param = RotateFlipType.Rotate90FlipY;"
	"			else param = RotateFlipType.Rotate90FlipNone;"
	"			break;"
	"	case 180:if (X_Flip_w && X_Flip_h)"
    "				param = RotateFlipType.Rotate180FlipXY;"
	"			else if (X_Flip_w) param = RotateFlipType.Rotate180FlipX;"
	"			else if(X_Flip_h) param = RotateFlipType.Rotate180FlipY;"
	"			else param = RotateFlipType.Rotate180FlipNone;"
	"			break;"
	"	case 270:if (X_Flip_w && X_Flip_h)"
	"				param = RotateFlipType.Rotate270FlipXY;"
	"			else if (X_Flip_w) param = RotateFlipType.Rotate270FlipX;"
	"			else if(X_Flip_h) param = RotateFlipType.Rotate270FlipY;"
	"			else param = RotateFlipType.Rotate270FlipNone;"
	"			break;"
	"	}"
	"	AL4Form.do_draw_bitmap_rotated_flipped("
	"		(int)X_Target, (int)X_Source, param);" .
	
    */
    public static void do_draw_bitmap_rotated_flipped(
    int X_Target, int X_Source, RotateFlipType param)
    {
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_Source];
        BitmapEx D = (BitmapEx)AL4Form.All_bitmaps[(int)X_Target];
        if (B == null || D == null) return;
        //if (((C_Canvas)(D.Obj)).F_Handle == 0) return;
        D.Bmp = B.Bmp.Clone(new Rectangle(0,0,B.Bmp.Width,B.Bmp.Height),
        	B.Bmp.PixelFormat);
        D.Bmp.RotateFlip(param);
    }
    
    /*
    
	FUN Draw_bitmap_inverted(
	INT Target|_bitmap_handle, INT Source|_bitmap_handle), NATIVE : @
   "    BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_Source];"
   "    BitmapEx D = (BitmapEx)AL4Form.All_bitmaps[(int)X_Target];"
   "    if (B == null || D == null) return;"
   "    ColorMatrix clrMatrix = new ColorMatrix(new float[][]"
   "          {"
   "             new float[] {-1, 0, 0, 0, 0},"
   "             new float[] {0, -1, 0, 0, 0},"
   "             new float[] {0, 0, -1, 0, 0},"
   "             new float[] {0, 0, 0, 1, 0},"
   "             new float[] {1, 1, 1, 0, 1}"
   "          });"
   "    using (ImageAttributes attrImage = new ImageAttributes())"
   "          {"
   "             attrImage.SetColorMatrix(clrMatrix);"
   "             using (Graphics g = Graphics.FromImage(D.Bmp))"
   "             {"
   "                g.DrawImage(B.Bmp, new Rectangle(0, 0,"
   "                   B.Bmp.Width, B.Bmp.Height), 0, 0,"
   "                   B.Bmp.Width, B.Bmp.Height, GraphicsUnit.Pixel,"
   "                   attrImage);"
   "             }"
   "          }   " .
    
    
FUN Canvas_copy_rect(
{Canvas} Dest|ination_canvas, {rect} R_dest|ination_rectangle,
{Canvas} Source|_canvas, {rect} R_source|_rectangle)
	:
	CASE Dest == NONE || Source == NONE ? ==> ;
	
	call_canvas_copy_rect(Dest, R_dest.Loc.X, R_dest.Loc.Y, 
		R_dest.Width, R_dest.Height,
		Source, R_source.Loc.X, R_source.Loc.Y,
		R_source.Width, R_source.Height)
	.
FUN call_canvas_copy_rect({Canvas} Dest|ination,
REAL X_dest|ination, REAL Y_dest|ination,
REAL W_dest|ination, REAL H_dest|ination,
{Canvas} Source|_canvas,
REAL X_source, REAL Y_source, REAL W_source, REAL H_source), NATIVE :
"	AL4Form.do_canvas_copy_rect(X_Dest, X_X_dest, X_Y_dest, X_W_dest, X_H_dest,"
"		X_Source, X_X_source, X_Y_source, X_W_source, X_H_source);" .
		
*/
public static void do_canvas_copy_rect(Ref_obj X_Dest,
double X_dest, double Y_dest, double W_dest, double H_dest,
Ref_obj X_Source,
double X_source, double Y_source, double W_source, double H_source)
{
 	BitmapEx D = AL4Form.All_bitmaps[
 		(int)((C_Canvas)(X_Dest.Obj)).F_Handle];
 	if (D == null) return;
 	BitmapEx S = AL4Form.All_bitmaps[
 		(int)((C_Canvas)(X_Source.Obj)).F_Handle];
 	if (S == null) return;
 	Graphics gD = Graphics.FromImage(D.Bmp);
 	C_Canvas cD = (C_Canvas)X_Dest.Obj;
 	if (Math.Abs(W_dest - W_source) < 0.1 && Math.Abs(H_dest - H_source) < 0.1
 		&& Math.Abs(X_dest - X_source) < 0.1 && Math.Abs(Y_dest-Y_source) < 0.1)
	 	gD.DrawImageUnscaled(S.Bmp,
	 		(int)UnitsToPixels(cD, (float)X_dest),
		    (int)UnitsToPixels(cD, (float)Y_dest));
 	else
	 	gD.DrawImage(S.Bmp, new RectangleF(
	 		UnitsToPixels(cD, (float)X_dest),
		    UnitsToPixels(cD, (float)Y_dest),
		    UnitsToPixels(cD, (float)W_dest),
		    UnitsToPixels(cD, (float)H_dest)),
	 	new RectangleF(
	 		UnitsToPixels(cD, (float)X_source),
			UnitsToPixels(cD, (float)Y_source),
			UnitsToPixels(cD, (float)W_source),
			UnitsToPixels(cD, (float)H_source)), GraphicsUnit.Pixel);
}
/*  
    FUN Draw_bitmap_on_canvas(
        INT B|itmap_handle,
        {Canvas} D|est_canvas_handle,
        REAL X|_destination_in_pixels,
        REAL Y|_destination_in_pixels,
        REAL W|idth_pixels,
        REAL H|eight_pixels), NATIVE
        :
        "   AL4Form.Do_draw_bitmap((int)X_B, X_D, X_X, X_Y, X_W, X_H);" .
    */
 	public static Graphics Graphics_FromImage(BitmapEx bex, bool need_transform)
 	{
 		C_Bitmap C_D = null;
 		C_Canvas C_Dc = null;
 		if (bex.RefBmp.Obj is C_Canvas)
 			C_Dc = (C_Canvas)bex.RefBmp.Obj;
 		else
 		{
	 		C_D = (C_Bitmap)bex.RefBmp.Obj;
	        C_Dc = (C_Canvas)C_D.F_draw_canvas.Obj;
        }
        Graphics G = null;
//?{Printer}
 		if (bex.printer_handle != 0)
 			G = AL4Print.extract_graphics_4printer(bex.printer_handle);
 		else
//.
		if (bex.Bmp.PixelFormat == PixelFormat.Indexed ||
			bex.Bmp.PixelFormat == PixelFormat.Format8bppIndexed ||
			bex.Bmp.PixelFormat == PixelFormat.Format4bppIndexed ||
			bex.Bmp.PixelFormat == PixelFormat.Format1bppIndexed)
		{
			Bitmap b_new = new Bitmap(bex.Bmp.Width, bex.Bmp.Height);
			b_new.Tag = bex.Bmp.Tag;
			G = Graphics.FromImage(b_new);
			G.DrawImageUnscaled(bex.Bmp, new Point(0, 0));
			Bitmap old = bex.Bmp;
			bex.Bmp = b_new;
			old.Dispose();
		}
			
		if (G == null)
 			G = Graphics.FromImage(bex.Bmp);
 		if (need_transform && bex.Transformed)
            G.Transform = bex.TransMatrix;		
	
 		C_Geometry.St_rect r = (C_Geometry.St_rect)C_Dc.F_Clip.Obj;
 		C_Geometry.St_point p = (C_Geometry.St_point)r.f_Loc.Obj;
 		if (r.f_Width > 0 || r.f_Height > 0)
 		{
 			G.SetClip(new RectangleF(
 				UnitsToPixels(C_Dc, (float)p.f_X),
 				UnitsToPixels(C_Dc, (float)p.f_Y),
 				UnitsToPixels(C_Dc, (float)r.f_Width),
 				UnitsToPixels(C_Dc, (float)r.f_Height)));
 		}
 		else G.ResetClip();
 		return G;
 	}   
 	
 	private static unsafe Bitmap DuplicateBitmap(Bitmap inputBitmap)
    {
        byte[] buffer = new byte[inputBitmap.Height * inputBitmap.Width *
        	   Image.GetPixelFormatSize(inputBitmap.PixelFormat) / 8];  

        fixed (byte* p = buffer)
        {
            BitmapData b1Data = new BitmapData()
            {
                Scan0 = (IntPtr)p,
                Height = inputBitmap.Height,
                Width = inputBitmap.Width,
                PixelFormat = inputBitmap.PixelFormat,
                Stride = inputBitmap.Width 
                	   * Image.GetPixelFormatSize(inputBitmap.PixelFormat) / 8
            }; 

            inputBitmap.LockBits(new Rectangle(Point.Empty, inputBitmap.Size),
                ImageLockMode.ReadOnly | ImageLockMode.UserInputBuffer,
                inputBitmap.PixelFormat, b1Data);
            Bitmap result = null;
            try
            {  
	            result = new Bitmap(b1Data.Width, b1Data.Height, 
	            	   b1Data.Stride, inputBitmap.PixelFormat, b1Data.Scan0);
            } finally {
            	inputBitmap.UnlockBits(b1Data);
            }
            return result;
        }
    }
	
	
    public static void Do_draw_bitmap(int X_B, Ref_obj X_D, 
        double X, double Y, double W, double H)
    {
        if (X_B == 0 || X_D == null) return;
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
        if (B == null || X_D.Obj.Is_NONE_object) return;
        if (((C_Canvas)(X_D.Obj)).F_Handle == 0) return;
        BitmapEx D = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_D.Obj)).F_Handle];
        if (D == null) return;
        Graphics g = Graphics_FromImage(D, true); // false);
        
        C_Bitmap C_D = null;
        C_Canvas C_Dc = null;
        if (D.RefBmp.Obj is C_Canvas)
    		C_Dc = (C_Canvas)D.RefBmp.Obj;
        else {
	        C_D = (C_Bitmap)D.RefBmp.Obj;
	        C_Dc = (C_Canvas)C_D.F_draw_canvas.Obj;
        }
        g.SmoothingMode = smoothing_mode(C_Dc);
        g.CompositingQuality = compositing_quality(C_Dc);
        g.InterpolationMode = interpolation_mode(C_Dc);
        
        Bitmap b = B.Bmp;
        if (B.Ico != null) {
        	b = B.Ico.ToBitmap();
        }
        if (W < 0 || H < 0)
        {
        	b = DuplicateBitmap(b);
        	if (W < 0 && H < 0)
        	{
        		X += W;
        		W = -W;
        		Y += H;
        		H = -H;
        		b.RotateFlip(RotateFlipType.RotateNoneFlipXY);
        	}
        	if (W < 0)
        	{
        		X += W;
        		W = -W;
        		b.RotateFlip(RotateFlipType.RotateNoneFlipX);
        	}
        	if (H < 0)
        	{
        		Y += H;
        		H = -H;
        		b.RotateFlip(RotateFlipType.RotateNoneFlipY);
        	}
        }
        try {
	        if (Math.Round(X) == X && Math.Round(Y) == Y &&
	        	Math.Round(W) == b.Width && Math.Round(H) == b.Height)
	        {
	            g.CompositingQuality = CompositingQuality.HighSpeed;
	            g.InterpolationMode = InterpolationMode.NearestNeighbor;
                //g.DrawImageUnscaled(b, new Rectangle(
                //    (int)X, (int)Y, (int)W, (int)H) );
	            g.DrawImage(b, new RectangleF( 
	                (float)X, (float)Y, (float)W, (float)H) );
	        }
	        else
	        {
	            g.DrawImage(b, new RectangleF( 
	                (float)X, (float)Y, (float)W, (float)H) );
	        }
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
        if (b != B.Bmp) b.Dispose();
    }
    
    //----------------------------------------------- {Icon}
    
	/*
	
	FUN Capture_screen_rectangle_to_bitmap(
		INT B|itmap_handle, REAL X|_coordinate, REAL Y|_coordinate), NATIVE : @
		"AL4Form.do_Capture_screen_rectangle_to_bitmap((int)X_B, X_X, X_Y);" .
	*/
	
	[DllImport("gdi32.dll")]
    static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int
    wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, CopyPixelOperation rop);
    [DllImport("gdi32.dll")]
    static extern IntPtr DeleteDC(IntPtr hDc);
    [DllImport("gdi32.dll")]
    static extern IntPtr DeleteObject(IntPtr hDc);
    [DllImport("gdi32.dll")]
    static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
    [DllImport("gdi32.dll")]
    static extern IntPtr CreateCompatibleDC(IntPtr hdc);
    [DllImport("gdi32.dll")]
    static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp);
    [DllImport("user32.dll")]
    public static extern IntPtr GetDesktopWindow();
    [DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr ptr);
	
	public static void do_Capture_screen_rectangle_to_bitmap(
	int X_B, double X_X, double X_Y)
	{
		BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
		int w = B.Bmp.Width;
		int h = B.Bmp.Height;
		IntPtr hDesk = GetDesktopWindow();
	    IntPtr hSrce = GetWindowDC(hDesk);
	    IntPtr hDest = CreateCompatibleDC(hSrce);
	    IntPtr hBmp = CreateCompatibleBitmap(hSrce, w, h);
	    IntPtr hOldBmp = SelectObject(hDest, hBmp);
	    bool b = BitBlt(hDest, 0, 0, w, h, hSrce, 
	    	AL4Form.Points(X_X), AL4Form.Points(X_Y),
	    	CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
	    Bitmap bmp = null;
	    if (b) 
	    {
		    bmp = Bitmap.FromHbitmap(hBmp);
		    Graphics G = AL4Form.Graphics_FromImage(B, false);
		    
		    G.DrawImageUnscaled(bmp, new Rectangle(0, 0, w, h));
	    }
	    
	    SelectObject(hDest, hOldBmp);
	    DeleteObject(hBmp);
	    DeleteDC(hDest);
	    ReleaseDC(hDesk, hSrce);
	    if (bmp != null) bmp.Dispose();
	}	
    
    /*
    
    FUN Get_bitmap_from_clipboard(
	INT B|itmap_handle) ==> BOOL, NATIVE : @
	"BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];"
	"RESULT = AL4Form.Do_get_bitmap_from_clipboard(B);" .
	
    FUN Put_bitmap_to_clipboard(
	INT B|itmap_handle) ==> BOOL, NATIVE : @
	"BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];"
	"RESULT = AL4Form.Do_put_bitmap_to_clipboard(B);" .
	
	*/
	
	public static bool Do_get_bitmap_from_clipboard(BitmapEx B)
	{
		if (Clipboard.ContainsImage())
		{
			Image im = Clipboard.GetImage() ;
			if (im == null) return false;
			if (im is Bitmap)
				B.Bmp = (Bitmap)im;
			else
			{
				B.Bmp = new Bitmap(im.Width, im.Height);
				Graphics g = Graphics.FromImage(B.Bmp);
				g.DrawImageUnscaled(im, new Point(0, 0));
			}
			C_Bitmap cb = (C_Bitmap)B.RefBmp.Obj;
			cb.F_Width = B.Bmp.Width;
			cb.F_Height = B.Bmp.Height;
			return B.Bmp.Width * B.Bmp.Height > 0;
		}
		return false;
	}
	
	public static bool Do_put_bitmap_to_clipboard(BitmapEx B)
	{
		try
		{
			Clipboard.SetImage(B.Bmp);
			return true;
		}
		catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw;
                	else return false; 
                }
	}
	
	/*

    // Create Icon object, return descriptor.
    //-------------------------------------------
    
    FUN Create_icon({Icon} Icon|_object) ==> INT, NATIVE :
        "    RESULT = AL4Form.Do_Create_bitmap(X_Icon, 32);" .
        
	FUN Screen_desktop|_pixels ==> {rect}:
		INT coord|inates_desktop[] << 0 << 0 << 0 << 0
		get_Screen_desktop(coord[0 TO *])
		
		RESULT = {rect}(
			Loc=Pt(coord[0], coord[1]), Width=coord[2], Height=coord[3])
		.
	FUN get_Screen_desktop(INT coord|inates_desktop[*]), NATIVE : @
   "Rectangle R = new Rectangle(int.MaxValue, int.MinValue,"
   "    int.MinValue, int.MinValue);"
   "foreach(Screen s in Screen.AllScreens) R = Rectangle.Union(R, s.Bounds);"
   "X_coord.set_int(0, R.X);"
   "X_coord.set_int(1, R.Y);"
   "X_coord.set_int(2, R.Width);"
   "X_coord.set_int(3, R.Height);" .
        
    // Load icon from file and from stream
    //------------------------------------
    
   	FUN Load_icon_from_file(
   	INT B|itmap_handle, STR Path|_icon)
   		:
		CASE Path.Ext.Lower == ".cur" ?
		     Load_cursor_from_file(B, Path)
		ELSE {File_stream} fs|tream_temp = Read_file_stream(Path)
			 Load_icon_from_stream(B, fs) ; .
		
    FUN Load_icon_from_stream(
    INT B|itmap_handle, {Stream} In|_stream),
        NATIVE({NATIVE_Stream_on_C_Stream}, 
        {Stream}, 
        {Stream}.Set_pos,
        {Stream}.Position,
        {Stream}.Size,
        {Stream}.Read_bytes,
        {Stream}.Close) :
        "     AL4Form.Do_load_icon((int)X_B, X_In);" .
        
    FUN Load_cursor_from_file(
    INT B|itmap_handle, STR Path|_cursor_file), NATIVE:
        "     AL4Form.Do_load_cursor((int)X_B, X_Path);" .
        
    */
	    public static void Do_load_icon(int X_B, Ref_obj X_In)
	    {
	        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
	        try
	        {
	            C_Stream CS = (C_Stream)(X_In.Obj);
	            Stream S = NATIVE_Stream_on_C_Stream.Stream_from_C_Stream(CS);
	            S.Position = 0;
	            B.Ico = new Icon(S);
	            C_Bitmap cB = (C_Bitmap)B.RefBmp.Obj;
	            cB.F_Width = B.Ico.Width;
	            cB.F_Height = B.Ico.Height;
	        }
	        catch (Exception Ex)
	        {
	        	if (Ex is AL4_Exception) throw;
	            AL4_system.Any_exception(Ex);
	            B.Ico = null;
	        }
	    }
	    
	    [DllImport("user32.dll",SetLastError=true,CharSet=CharSet.Auto)]
	    private static extern IntPtr LoadCursorFromFile(string path);

	    public static void Do_load_cursor(int X_B, string X_Path)
	    {
	        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
	        try
	        {
	            Cursor cur = new Cursor(LoadCursorFromFile(X_Path));
	            B.Bmp = new Bitmap(cur.Size.Width, cur.Size.Height);
	            Graphics g = Graphics.FromImage(B.Bmp);
	            cur.Draw(g, new Rectangle(0,0,cur.Size.Width,cur.Size.Height));
	            C_Bitmap cB = (C_Bitmap)B.RefBmp.Obj;
	            cB.F_Width = B.Bmp.Width;
	            cB.F_Height = B.Bmp.Height;
	        }
	        catch (Exception Ex)
	        {
	        	if (Ex is AL4_Exception) throw;
	            AL4_system.Any_exception(Ex);
	            B.Ico = null;
	        }
	    }

    //------------------------------------------------ {Bitmap_direct}
    
    /*
    // Lock bitmap pixels
    //----------------------
    
    FUN LockBitmapPixels({Bitmap_direct} B|itmap_object, INT Y|_position,
        INT H|eight_rectangle, BOOL Read|_source), NATIVE :
        "   AL4Form.Do_LockBitmapPixels(X_B, (int)X_Y, (int)X_H, X_Read);" .
    */
    public static void Do_LockBitmapPixels(Ref_obj X_Bitmap, int X_Y, 
            int X_H, bool X_Read)
    {
    	int X_B = (int)((C_Bitmap_direct)X_Bitmap.Obj).F_Handle;
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
        B.LockedBits = B.Bmp.LockBits(new Rectangle(0, X_Y, B.Bmp.Width, X_H),
            ImageLockMode.ReadWrite, B.Bmp.PixelFormat);
//? {Bitmap_direct}
        int bits_per_pixel = AL4Form.Calculate_bits_per_pixel(
            B.LockedBits.Width, B.LockedBits.Stride);
        C_Bitmap_direct D = (C_Bitmap_direct)B.RefBmp.Obj;
        D.F_Row_width = bits_per_pixel * B.LockedBits.Width / 8;
        B.Local_copy_bits = new byte[
            (int)D.F_Row_width * B.LockedBits.Height];
        B.Locked_Y = X_Y;
        //B.Locked_H = X_H;
        if (X_Read)
        {
            int to = 0;
            for (int y = 0; y < B.LockedBits.Height; y++)
            //for (int y = 0; y < X_H; y++)
            {
                Marshal.Copy((IntPtr)((long)B.LockedBits.Scan0 +
                    B.LockedBits.Stride * y),
                    B.Local_copy_bits, to, (int)D.F_Row_width);
                to += (int)D.F_Row_width;
            }
        }
        D.F_Pixels = new FixAByte(B.Local_copy_bits);
//.
    }
    
    /*
    // Unlock bitmap pixels
    //----------------------
    
    FUN UnlockBitmapPixels(
    	{Bitmap_direct} B|itmap_object, BOOL Write|_back), NATIVE :
        "   AL4Form.Do_UnlockBitmapPixels(X_B, X_Write);" .
    */
    public static void Do_UnlockBitmapPixels(Ref_obj X_Bitmap, bool X_Write)
    {
    	int X_B = (int)((C_Bitmap_direct)X_Bitmap.Obj).F_Handle;
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[(int)X_B];
//? {Bitmap_direct}
        int bits_per_pixel = AL4Form.Calculate_bits_per_pixel(
            B.LockedBits.Width, B.LockedBits.Stride);
        C_Bitmap_direct D = (C_Bitmap_direct)B.RefBmp.Obj;
        if (X_Write)
        {
            int from = 0;
            for (int y = 0; y < B.LockedBits.Height; y++)
            //for (int y = 0; y < B.Locked_H; y++)
            {
                Marshal.Copy(B.Local_copy_bits, from, 
                    (IntPtr)((long)B.LockedBits.Scan0 +
                    B.LockedBits.Stride * y), (int)D.F_Row_width);
                from += bits_per_pixel * B.LockedBits.Width / 8;
            }
        }
        D.F_Pixels = new FixAByte(0);
//.
        B.Local_copy_bits = new byte[1];
        B.Bmp.UnlockBits(B.LockedBits);
    }
    
    
    public static int Calculate_bits_per_pixel(int width, int stride)
    {
        if (stride < 0) stride = -stride;
        int Result = 1;
        while (Result < 32)
        {
            if ((Result * 2) * width / 8 > stride) break;
            Result *= 2;
        }
        if (Result == 16 && Result * width / 8 < stride &&
            3 * width <= stride)
            Result = 24;
        return Result;
    }
    
    //----------------------------------------------------- C A N V A S

    /*
    
    FUN Need_erase_paintbox_1|st_time_buffer_created ==> BOOL : .
    
    FUN Get_mask_RGB({Bitmap_direct}.{rgb} C|omponent) ==> INT :
		RESULT = (0xFF).ShiftL(Get_shift_RGB(C)) .
    
    FUN Get_shift_RGB(
    {Bitmap_direct}.{rgb} C|omponent) ==> INT
    	:
		CASE C ?
		['R']: RESULT = 16
		['G']: RESULT = 8
		['B']: RESULT = 0
		['A']: RESULT = 24 ; .
    
    // Create Canvas object, return descriptor.
    //-------------------------------------------

    FUN Create_bitmap_canvas({Canvas} C|anvas_object,
    {Bitmap} B|itmap_object) ==> INT
        :
		RESULT = do_Create_bitmap_canvas(C, B)
		.
    FUN do_Create_bitmap_canvas({Canvas} C|anvas_object,
    {Bitmap} B|itmap_object) ==> INT, NATIVE : @
    "	   Object_assign_hard(ref ((C_Bitmap)X_B.Obj).F_draw_canvas, X_C.Obj);"
    "      return AL4Form.Do_Create_bitmap_canvas(X_C, X_B);" .
    */
    public static int Do_Create_bitmap_canvas(Ref_obj X_C, Ref_obj X_B)
    {
        return (int)((C_Bitmap)(X_B.Obj)).F_Handle;
    }
    
    /*
    
    FUN Direct_draw_canvas(INT H|andle_control_dummy) ==> BOOL :
        RESULT = FALSE .
    
    FUN Create_control_canvas(
        {Canvas} Canv|as_object_dummy, 
        {Control} Cont|rol_object_dummy) ==> INT RESULT|Handle
        :
        RESULT = 0 .
        
   	FUN Create_printer_canvas(
   		{Canvas} C|anvas_object,
		INT Printer_handle) ==> INT, NATIVE :
	"   return AL4Form.Do_Create_printer_canvas(X_C, (int)X_Printer_handle);" .
	
	*/
	
	public static int Do_Create_printer_canvas(Ref_obj X_C, int X_Printer_handle)
    {
        BitmapEx B = new BitmapEx(PixelFormat.Format1bppIndexed, 1, 1);
        B.RefBmp = X_C;
        B.Bmp.Tag = X_C;
        B.printer_handle = X_Printer_handle;
        int Result = AL4Form.AllocBitmapDescr(B);
        //int Result = AL4Form.AllocDescriptor(B);
        return Result;
    }
	
	/*
    
    // Destroy Canvas object (actually not needed, still it is owned by TBitmapEx)
    //---------------------------------------------------------------------------
    
	FUN Destroy_canvas(INT C|anvas_handle), NATIVE :
        "    AL4Form.Do_Destroy_canvas((int)X_C);" .
    */
    public static void Do_Destroy_canvas(int X_C)
    {
    }

//?{Bitmap}
    public static C_Canvas C_Canvas_from_Bitmap(Bitmap B)
    {
        Ref_obj BRef = (Ref_obj)B.Tag;
        if (BRef == null) return null;
        if (BRef.Obj is C_Canvas)
        	return (C_Canvas)BRef.Obj;
        C_Bitmap CBmp = (C_Bitmap)BRef.Obj;
        
        C_Canvas CCanv = (C_Canvas)CBmp.F_draw_canvas.Obj;
        return CCanv;
    }
//.

    public static Pen Get_pen(Ref_obj X_C)
    {
        Pen P = null;
//?{Bitmap}
        BitmapEx B = (BitmapEx)All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        C_Canvas CCanv = C_Canvas_from_Bitmap(B.Bmp);
        
        Color pen_color = Color.FromArgb( 
        	(int)(CCanv.F_Foreground >> 24) & 0xFF, 
        	(int)CCanv.F_Foreground & 0xFF,
        	(int)(CCanv.F_Foreground >> 8) & 0xFF,
        	(int)(CCanv.F_Foreground >> 16) & 0xFF);
        	
        P = new Pen(pen_color, (float)CCanv.F_Pen_width);
//.
        return P;
    }

    public static Brush Get_brush(Ref_obj X_C)
    {
        Brush Br = null;
//?{Bitmap}
        BitmapEx B = (BitmapEx)All_bitmaps[
        		(int)((C_Canvas)(X_C.Obj)).F_Handle];
        C_Canvas CCanv = C_Canvas_from_Bitmap(B.Bmp);
        Color pen_color =
            Color.FromArgb((int)(CCanv.F_Foreground >> 24) & 0xFF, 
            			   (int)CCanv.F_Foreground & 0xFF,
            			   (int)(CCanv.F_Foreground >> 8) & 0xFF, 
            			   (int)(CCanv.F_Foreground >> 16) & 0xFF);
        Color brush_color =
            Color.FromArgb((int)(CCanv.F_Background >> 24) & 0xFF,
            			   (int)CCanv.F_Background & 0xFF,
            			   (int)(CCanv.F_Background >> 8) & 0xFF,
            			   (int)(CCanv.F_Background >> 16) & 0xFF);
        switch (CCanv.F_Brush)
        {
            case 1: Br = new SolidBrush(Color.FromArgb(0, Color.Black)); break;
            case 2: Br = new HatchBrush(HatchStyle.Horizontal, pen_color, brush_color); break;
            case 3: Br = new HatchBrush(HatchStyle.Vertical, pen_color, brush_color); break;
            case 4: Br = new HatchBrush(HatchStyle.ForwardDiagonal, pen_color, brush_color); break;
            case 5: Br = new HatchBrush(HatchStyle.BackwardDiagonal, pen_color, brush_color); break;
            case 6: Br = new HatchBrush(HatchStyle.Cross, pen_color, brush_color); break;
            case 7: Br = new HatchBrush(HatchStyle.DiagonalCross, pen_color, brush_color); break;
            default: Br = new SolidBrush(brush_color); break;
        }
//.
        return Br;
    }

    public static Font Get_font(Ref_obj X_C)
    {
        FontEx Fex = null;
//?{Bitmap}
        BitmapEx B = (BitmapEx)All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        C_Canvas CCanv = C_Canvas_from_Bitmap(B.Bmp);
        C_Font CFont = (C_Font)CCanv.F_Font.Obj;
        Fex = (FontEx)All_descriptors[(int)CFont.F_Handle];
        
        if (CFont.F_Face != Fex.Font.Name ||
            CFont.F_Size != Fex.Font.Size ||
            CFont.F_Bold != Fex.Font.Bold ||
            CFont.F_Italic != Fex.Font.Italic ||
            CFont.F_Underline != Fex.Font.Underline ||
            CFont.F_Strikeout != Fex.Font.Strikeout)
        {
            FontStyle fs = System.Drawing.FontStyle.Regular;
            if (CFont.F_Bold) fs |= System.Drawing.FontStyle.Bold;
            if (CFont.F_Italic) fs |= System.Drawing.FontStyle.Italic;
            if (CFont.F_Underline) fs |= System.Drawing.FontStyle.Underline;
            if (CFont.F_Strikeout) fs |= System.Drawing.FontStyle.Strikeout;
            Fex.Font = new System.Drawing.Font(CFont.F_Face,
                (float)Fex.Font.Size, fs, GraphicsUnit.Point,
                Fex.Font.GdiCharSet);
        }
//.
        return Fex.Font;
    }
    
    /*
    
    FUN Units_to_pixels(
    {Canvas} C|anvas_object, REAL V|alue_units) ==> REAL, NATIVE : @
    "C_Canvas C_C = (C_Canvas)X_C.Obj;"
    "RESULT = AL4Form.UnitsToPixels(C_C, X_V);" .     

    FUN Pixels_to_units(
    {Canvas} C|anvas_object, REAL V|alue_pixels) ==> REAL, NATIVE : @
    "C_Canvas C_C = (C_Canvas)X_C.Obj;"
    "RESULT = AL4Form.UnitsFromPixels(C_C, X_V);" .     

    */

    public static float UnitsToPixels(C_Canvas C_C, double Value_units)
    {
	           switch (C_C.F_Units)
	           {
	              case 0: return Points_float(Value_units);
	              case 1: return (float)Value_units;
	              case 2: return Points_float(Value_units * 72);
	              case 3: return Points_float(Value_units / 2.54 * 72);
	              default: return 0;
	           }
    }

    public static double UnitsFromPixels(C_Canvas C_C, double Value_pixels)
    {
	           switch (C_C.F_Units)
	           {
	              case 0: return Pixels(Value_pixels);
	              case 1: return Value_pixels;
	              case 2: return Pixels(Value_pixels) / 72.0;
	              case 3: return Pixels(Value_pixels) * 2.54 / 72.0;
	              default: return 0;
	           }
    }

    /*
    // Erase rect
    //-----------
    
    FUN Erase_rect(
    	{Canvas} C|anvas_object, {rect} R|ectangle)
    	:
		do_erase(C, R.Loc.X, R.Loc.Y, R.Width, R.Height) .
    FUN do_erase({Canvas} C|anvas_object, REAL X|_rectangle, REAL Y|_rectangle,
    REAL W|idth_rectangle, REAL H|eight_rectangle), NATIVE : @
        "      AL4Form.Do_Erase_rect(X_C, X_X, X_Y, X_W, X_H);" .
    */
    public static void Do_Erase_rect(Ref_obj X_C, double X, double Y,
    	double W, double H)
    {
//?{Bitmap}
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, true);
        G.CompositingMode = CompositingMode.SourceCopy;
        C_Canvas C = C_Canvas_from_Bitmap(B.Bmp);
        RectangleF R = new System.Drawing.RectangleF(
            UnitsToPixels(C, X),
            UnitsToPixels(C, Y),
            UnitsToPixels(C, W),
            UnitsToPixels(C, H));
        G.FillRectangle(Get_brush(X_C), R);
//.
    }

    /*
    // Paint rect
    //-----------
    
    FUN Paint_rect(
    	{Canvas} C|anvas_object, {rect} R|ectangle)
    	:
	//DEBUG: << "do_paint_rect: " R.Srect #NL ;
		do_paint_rect(C, R.Loc.X, R.Loc.Y, R.Width, R.Height) .
    FUN do_paint_rect({Canvas} C|anvas_object, REAL X|_rectangle,
    REAL Y|_rectangle, REAL W|idth_rectangle, REAL H|eight_rectangle), NATIVE :@
        "      AL4Form.Do_Paint_rect(X_C, X_X, X_Y, X_W, X_H);" .
    */
 	public static SmoothingMode smoothing_mode(C_Canvas C)
 	{
 		switch(C.F_Quality)
 		{
 			case 0: return SmoothingMode.AntiAlias;
 			case 1: return SmoothingMode.Default;
 			default: return SmoothingMode.None;
 		}
 	}   
	
 	public static CompositingQuality compositing_quality(C_Canvas C)
 	{
 		switch(C.F_Quality)
 		{
 			case 0: return CompositingQuality.HighQuality;
 			case 1: return CompositingQuality.Default;
 			default: return CompositingQuality.HighSpeed;
 		}
 	}   
	
 	public static InterpolationMode interpolation_mode(C_Canvas C)
 	{
 		switch(C.F_Quality)
 		{
 			case 0: return InterpolationMode.HighQualityBicubic;
 			case 1: return InterpolationMode.Bilinear;
 			default: return InterpolationMode.NearestNeighbor;
 		}
 	}   
	
    public static void Do_Paint_rect(Ref_obj X_C, double X, double Y,
    	double W, double H)
    {
//?{Bitmap}
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, true);
        
        C_Canvas C = C_Canvas_from_Bitmap(B.Bmp);
        G.SmoothingMode = smoothing_mode(C); //SmoothingMode.AntiAlias;
        RectangleF R = new System.Drawing.RectangleF(
            UnitsToPixels(C, X),
            UnitsToPixels(C, Y),
            UnitsToPixels(C, W),
            UnitsToPixels(C, H));
        if (C.F_Brush != 1)
            G.FillRectangle(Get_brush(X_C), R);
        if (C.F_Pen_style == 0)
            G.DrawRectangle(Get_pen(X_C), R.Left, R.Top, R.Width, R.Height);
//.
    }

    /*
    /// Paint line
    //-----------
    
    FUN Paint_line({Canvas} C|anvas_object,
        {Geometry}.{point} P1|_point, {point} P2|_point)
        :
		do_paint_line(C, P1.X, P1.Y, P2.X, P2.Y) .
    FUN do_paint_line({Canvas} C|anvas_object, REAL X1|_point, REAL Y1|_point,
    REAL X2|_point, REAL Y2|_point), NATIVE : @
        "      AL4Form.Do_Paint_line(X_C, X_X1, X_Y1, X_X2, X_Y2);" .
    */
    public static void Do_Paint_line(Ref_obj X_C, double P1_X, double P1_Y,
        double P2_X, double P2_Y)
    {
//?{Bitmap}
		try
		{
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, true);
        
        C_Canvas C = C_Canvas_from_Bitmap(B.Bmp);
        G.SmoothingMode = smoothing_mode(C);
        if (C.F_Pen_style == 0)
            G.DrawLine(Get_pen(X_C), 
                UnitsToPixels(C, P1_X), UnitsToPixels(C, P1_Y),
                UnitsToPixels(C, P2_X), UnitsToPixels(C, P2_Y));
        }
        catch (Exception Ex)
                {
                	if (Ex is AL4_Exception) throw; 
                }
//.
    }

    /*
    // Paint ellipse
    //--------------
    
    FUN Paint_ellipse(
    	{Canvas} C|anvas_object, {rect} R|ectangle_ellipse)
    	:
		do_paint_ellipse(C, R.Loc.X, R.Loc.Y, R.Width, R.Height) .
    FUN do_paint_ellipse({Canvas} C|anvas_object,
    REAL X|_rectangle, REAL Y|_rectangle, REAL W|idth_rectangle,
    REAL H|eight_rectangle), NATIVE : @
        "     AL4Form.Do_Paint_ellipse(X_C, X_X, X_Y, X_W, X_H);" .
    */
    public static void Do_Paint_ellipse(Ref_obj X_C, double X, double Y,
    double W, double H)
    {
//?{Bitmap}
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, true);

        C_Canvas C = C_Canvas_from_Bitmap(B.Bmp);
        G.SmoothingMode = smoothing_mode(C);
        RectangleF R = new System.Drawing.RectangleF(
            UnitsToPixels(C, X),
            UnitsToPixels(C, Y),
            UnitsToPixels(C, W),
            UnitsToPixels(C, H));
        if (R.Width < 0.01 || R.Height < 0.01)
        	return;
        if (C.F_Brush != 1)
            G.FillEllipse(Get_brush(X_C), R);
        if (C.F_Pen_style == 0)
            G.DrawEllipse(Get_pen(X_C), R.Left, R.Top, R.Width, R.Height);
//.
    }

    /*
    // Paint arc/pie
    //--------------
    
    FUN Paint_arc(
    {Canvas} C|anvas_object, {Canvas}.{arc} A|rc_information)
    	:
		do_paint_arc(C, A.Rect.Loc.X, A.Rect.Loc.Y, A.Rect.Width, A.Rect.Height,
		A.Angles.X, A.Angles.Y, A.Sided)
		.
    FUN do_paint_arc({Canvas} C|anvas_object, REAL X|_rectangle,
    REAL Y|_rectangle, REAL W|idth_rectangle, REAL H|eight_rectangle,
    REAL Fr|om_angle, REAL To|_angle, BOOL S|ided_arc), NATIVE : @
        "     AL4Form.Do_Paint_arc(X_C, X_X, X_Y, X_W, X_H, X_Fr, X_To, X_S);" .
    */
 	public static float correct_angle(float a)
 	{
 		if (a >= 0) return a;
 		return 360 + a;
 	}   
	
    public static void Do_Paint_arc(Ref_obj X_C, double X, double Y,
    	double W, double H, double Fr, double To, bool Sided)
    {
//?{Bitmap}
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, true);
        
        C_Canvas C = C_Canvas_from_Bitmap(B.Bmp);
        G.SmoothingMode = smoothing_mode(C);
        RectangleF R = new System.Drawing.RectangleF(
            UnitsToPixels(C, X),
            UnitsToPixels(C, Y),
            UnitsToPixels(C, W),
            UnitsToPixels(C, H));
        if (R.Width <= 0.01 || R.Height <= 0.01) return;
        if (Sided)
        {
            if (C.F_Brush != 1)
                G.FillPie(Get_brush(X_C), R.Left, R.Top, R.Width, R.Height,
                    (float)Fr, 
                    correct_angle((float)Math.Abs(To - Fr)));
            if (C.F_Pen_style == 0)
                G.DrawPie(Get_pen(X_C), R, (float)Fr, 
                    correct_angle((float)Math.Abs(To - Fr)));
        }
        else
        {
            if (C.F_Pen_style == 0)
                G.DrawArc(Get_pen(X_C), R,
                    (float)Fr, 
                    correct_angle((float)(To - Fr)));
        }
//.
    }



 	/*
    // Paint poly
    //--------------
    
    FUN Paint_poly({Canvas} C|anvas_object,
    {point} P|oints_array[*], BOOL Closed|_polygon)
    	:
    	REAL x|_coordinates[]
    	REAL y|_coordinates[]
    	FOR i IN [0 TO P[].Count-1] :
    	    x[] << P[i].X 
    	    y[] << P[i].Y ;
		do_paint_poly(C, x[0 TO *], y[0 TO *], Closed) .
    FUN do_paint_poly({Canvas} C|anvas_object,
    REAL X|_coordinates[*], REAL Y|_coordinates[*],
    BOOL Closed|_polygon), NATIVE : @
        "     AL4Form.Do_Paint_poly(X_C, X_X, X_Y, X_Closed);" .
    */
    public static void Do_Paint_poly(Ref_obj X_C, ArrayReal X, ArrayReal Y, 
           bool X_Closed)
    {
//?{Bitmap}
        if (X.Count == 0) return;
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, true);
        
        C_Canvas C = C_Canvas_from_Bitmap(B.Bmp);
        G.SmoothingMode = smoothing_mode(C);
        if (X.Count == 1 && X_Closed)
        {
            RectangleF R = new System.Drawing.RectangleF(
                UnitsToPixels(C, X[0]), 
                UnitsToPixels(C, Y[0]), 1, 1);
            if (C.F_Brush != 1)
                G.FillRectangle(Get_brush(X_C), R);
        }
        else 
        {
            PointF[] Pts = new PointF[X.Count];
            for (int i = 0; i < X.Count; i++)
                Pts[i] = new PointF(
                    UnitsToPixels(C, X[i]), 
                    UnitsToPixels(C, Y[i]));
            if (X_Closed)
            {
                if (C.F_Brush != 1)
                    G.FillPolygon(Get_brush(X_C), Pts);
                if (C.F_Pen_style == 0)
                    G.DrawPolygon(Get_pen(X_C), Pts);
            }
            else
            {
                if (C.F_Pen_style == 0)
                    G.DrawLines(Get_pen(X_C), Pts); 
            }
        }
//.
    }


    /*
    // Reset transforms
    //-----------------
    
    FUN Canvas_transform_reset(
    {Canvas} C|anvas_object), NATIVE :
        "     AL4Form.Do_transform_reset(X_C);" .
    */
    public static void Do_transform_reset(Ref_obj X_C)
    {
    	int h = (int)((C_Canvas)(X_C.Obj)).F_Handle;
    	if (h == 0) return;
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[h];
        Graphics G = Graphics_FromImage(B, false);
        G.ResetTransform();
        B.Transformed = false;
    }

    /*
    // Offset transformation
    //----------------------
    
    FUN Canvas_transform_offset(
    {Canvas} C|anvas_object, REAL Dx|_delta, REAL Dy|_delta), NATIVE :
        "     AL4Form.Do_transform_offset(X_C, X_Dx, X_Dy);" .
    */
    public static void Do_transform_offset(Ref_obj X_C, double Dx, double Dy)
    {
//?{Bitmap}
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, true);
        
        C_Canvas CCanv = C_Canvas_from_Bitmap(B.Bmp);
        if (CCanv == null) return;
        G.TranslateTransform((float)UnitsToPixels(CCanv, Dx), 
                             (float)UnitsToPixels(CCanv, Dy));
        B.TransMatrix = G.Transform;
        B.Transformed = true;
//.
    }

    /*
    // Rotation transformation
    //------------------------
    
    FUN Canvas_transform_rotate(
    	{Canvas} C|anvas_object, REAL Angle|_degrees),
        NATIVE :
        "     AL4Form.Do_transform_rotate(X_C, X_Angle);" .
    */
    public static void Do_transform_rotate(Ref_obj X_C, double Angle)
    {
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, true);
        
        G.RotateTransform((float)Angle);//, MatrixOrder.Prepend);
        B.TransMatrix = G.Transform;
        B.Transformed = true;
    }

    /*
    // Scale transformation
    //---------------------
    
    FUN Canvas_transform_scale(
    	{Canvas} C|anvas_object,
    	REAL Scale_x|_value,
        REAL Scale_y|_value), NATIVE :
        "     AL4Form.Do_transform_scale(X_C, X_Scale_x, X_Scale_y);" .
    */
    public static void Do_transform_scale(Ref_obj X_C, double Sx, double Sy)
    {
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, true);
        
        G.ScaleTransform((float)Sx, (float)Sy);
        B.TransMatrix = G.Transform;
        B.Transformed = true;
    }
    
    /*
    // Paint text
    //--------------
    
    FUN Paint_text({Canvas} C|anvas_object, {point} P|oint_top_left, 
        STR Text|_draw)
        :
		do_paint_text(C, P.X, P.Y, Text) .
    FUN do_paint_text({Canvas} C|anvas_object,
    REAL X|_of_point, REAL Y|_of_point, STR Text|_draw), NATIVE : @
    "     AL4Form.Do_Paint_text(X_C, X_X, X_Y, X_Text);" .
    */
    public static void Do_Paint_text(Ref_obj X_C, double X, double Y, string X_Text)
    {
//?{Bitmap}
	        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
	        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
	        Graphics G = Graphics_FromImage(B, true);
	        
	        C_Canvas C = C_Canvas_from_Bitmap(B.Bmp);
	        G.SmoothingMode = smoothing_mode(C);
	
	        PointF P = new System.Drawing.PointF(
	            UnitsToPixels(C, X),
	            UnitsToPixels(C, Y));
	
	        int save_background = (int)C.F_Background;
	        byte save_back_style = C.F_Brush;
	        C.F_Background = C.F_Foreground;
	        switch (C.F_Pen_style)
	        {
	            case 0: C.F_Brush = 0; break; // solid pen
	            case 1: C.F_Brush = 1; break; // clear pen
	        }
	        
	        try
	        {
	        	switch (C.F_Quality) {
	        	case 0:
    	    		G.TextRenderingHint = System.Drawing.Text.
    	    		TextRenderingHint.ClearTypeGridFit;
    	    		break;
	        	case 1:
    	    		G.TextRenderingHint = System.Drawing.Text.
    	    		TextRenderingHint.AntiAlias;
    	    		break;
	        	default:
    	    		G.TextRenderingHint = System.Drawing.Text.
    	    		TextRenderingHint.SingleBitPerPixel;
    	    		break;
	        	}
	        	G.DrawString(X_Text, Get_font(X_C), Get_brush(X_C), P.X, P.Y,
	        		StringFormat.GenericTypographic);
	        }
	        finally
	        {
	            C.F_Background = save_background;
	            C.F_Brush = save_back_style;
	        }
//.
    }
    /*
    // String measure for current font
    //---------------------------------
    // there is a bug in C# MeasureString implementation: it incorrectly counts
    // trailing spaces.
    //--------------------------------------------------------------------------
    
    FUN String_measure(
    	{Canvas} C|anvas_object, STR S|tring_to_measure) ==> {rect}
    	:
    	REAL m|easure_values[] << 0 << 0
    	do_string_measure(C, S, m[]) 
    	RESULT = {rect}(Width = m[0], Height = m[1]) .
    FUN do_string_measure({Canvas} C|anvas_object, STR S|tring_to_measure,
    REAL M|easured_values_W_H[]), NATIVE :
        "AL4Form.Do_String_measure(X_C, X_S, X_M);" .
    */
    
    //[DllImport("gdi32.dll", CharSet=CharSet.Unicode)]
    //static extern bool GetTextExtentPoint32(
    //    IntPtr hdc, string lpString, int cbString, out Size lpSize);
        
    ////[DllImport("gdi32.dll", EntryPoint = "SelectObject")]
    ////static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj);
	
    ////[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
    ////[return: MarshalAs(UnamanagedType.Bool)]
    ////static extern bool DeleteObject([In] IntPtr hobj);
	
    //public static void Do_String_measure(Ref_obj X_C, string X_S,
    //    ArrayReal X_M)
    //{
////?{Bitmap}
    //    BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
    //        (int)((C_Canvas)(X_C.Obj)).F_Handle];
    //    Graphics G = Graphics_FromImage(B, false);
    //    C_Canvas CC = AL4Form.C_Canvas_from_Bitmap(B.Bmp);
    //    Font F = AL4Form.Get_font(X_C);

    //    String s = X_S; //.Trim();
    
    //    Size R = TextRenderer.MeasureText(s, F, new Size(10000, 10000));
    //    //Size R = Size.Empty;
    //    //IntPtr hdc = G.GetHdc();
    //    //IntPtr oldfnt = SelectObject(hdc, F.ToHfont());
    //    //GetTextExtentPoint32(hdc, s, s.Length, out R);
    //    //DeleteObject(SelectObject(hdc, oldfnt));
    //    //G.ReleaseHdc(hdc);

    //    float w = R.Width;
    //    float h = R.Height;
    //    X_M.set_real(0, AL4Form.UnitsFromPixels(CC, w));
    //    X_M.set_real(1, AL4Form.UnitsFromPixels(CC, h));
////.
    //}
        
    public static void Do_String_measure(Ref_obj X_C, string X_S,
    	ArrayReal X_M)
    {
//?{Bitmap}
        BitmapEx B = (BitmapEx)AL4Form.All_bitmaps[
        	(int)((C_Canvas)(X_C.Obj)).F_Handle];
        Graphics G = Graphics_FromImage(B, false);
        C_Canvas CC = AL4Form.C_Canvas_from_Bitmap(B.Bmp);
        Font F = AL4Form.Get_font(X_C);
    
        StringFormat sf = new StringFormat(StringFormat.GenericTypographic);
        sf.FormatFlags = StringFormatFlags.FitBlackBox 
        	| StringFormatFlags.NoClip | StringFormatFlags.NoWrap;
        String s = X_S.Trim();
        SizeF Sz = G.MeasureString(s, F, 0, sf);
        SizeF Sz2 = G.MeasureString(s + s, F, 0, sf);
        float w = Sz2.Width - Sz.Width;

        if (s.Length < X_S.Length) {
        	Sz = G.MeasureString("a a", F, 0, sf);
        	Sz2 = G.MeasureString("a  a", F, 0, sf);
        	w += (Sz2.Width - Sz.Width) * (X_S.Length - s.Length);
        }
        
        X_M.set_real(0, AL4Form.UnitsFromPixels(CC, w));
        X_M.set_real(1, AL4Form.UnitsFromPixels(CC, Sz.Height) + 1);
//.
    }
    
    
}

public class FontEx
{
    public Font Font;
    public object Tag;

    ~FontEx()
    {
        if (Font != null)
            Font.Dispose();
    }
}

public class BitmapEx 
{
    public Bitmap Bmp;
    public Icon Ico;
    public Ref_obj RefBmp;
    public int Bpp;
    public int printer_handle;

    public BitmapEx(PixelFormat PF, int w, int h)
    {
    	if (w < 1) w = 1;
    	if (h < 1) h = 1;
        Bmp = new System.Drawing.Bitmap(w, h, PF);
        switch(PF)
        {
            case PixelFormat.Format1bppIndexed: Bpp = 0; break;
            case PixelFormat.Format4bppIndexed: Bpp = 4; break;
            case PixelFormat.Format8bppIndexed: Bpp = 8; break;
            case PixelFormat.Format16bppRgb555: Bpp = 16; break;
            case PixelFormat.Format16bppRgb565: Bpp = 16; break;
            case PixelFormat.Format24bppRgb: Bpp = 24; break;
            case PixelFormat.Format32bppArgb: Bpp = 32; break;
            case PixelFormat.Format32bppRgb: Bpp = 32; break;
            default: Bpp = 0; break;
        }
    }

    public BitmapEx(FileStream fs)
    {
        Bmp = new Bitmap(fs);
    }

    ~BitmapEx()
    {
        RefBmp = null;
        if (Bmp != null) Bmp.Dispose();
        Bmp = null;
    }

    public bool Transformed;
    public Matrix TransMatrix;
    
    public BitmapData LockedBits;
    public byte[] Local_copy_bits;
    public int Locked_Y;
}

public class FocusPictureBox : PictureBox
{
    public void Do_set_style(ControlStyles cs, bool do_set)
    {
        SetStyle(cs, do_set);
    }
    
    protected override bool IsInputKey(Keys keyData)
    {
        if (TabStop && ((Scrolled_paintbox)Parent).Can_focus)
        {
            if (!handle_tab() && (
            	keyData == Keys.Tab || (keyData == (Keys.Tab | Keys.Shift))))
            {
                return false;
            }
            if (keyData == Keys.Escape)
            {
            	AL4Form F = AL4Form.Parent_form(this);
            	if (F.CancelButton != null)
            	{
            		C_Form CF = (C_Form)F.AL4Object.Obj;
            		if (((C_Button)CF.F_Cancel_button.Obj).Do.M_Enabled())
            			return false;
            	}
            }
            if (keyData == Keys.Return)
            {
            	AL4Form F = AL4Form.Parent_form(this);
            	if (F.AcceptButton != null) 
            	{
            		C_Form CF = (C_Form)F.AL4Object.Obj;
            		if (((C_Button)CF.F_Default_button.Obj).Do.M_Enabled())
            			return false;
            	}
            }
            return true;
        }
        else
        {
            return base.IsInputKey(keyData);
        }
    }    
    
    protected bool handle_tab()
    {
		Scrolled_paintbox spb = (Scrolled_paintbox)Parent;
		if (((C_Paintbox)spb.AL4Object.Obj).F_Handle_tab)
				return true;
		return false;
    }
    
    protected override void OnKeyDown(KeyEventArgs e)
    {				
    	if (TabStop && e.KeyData == Keys.Tab && !handle_tab())
    	{
    		int t = TabIndex;
    		Control p = this;
    		Form f = FindForm();
    		if (f == null)
    		{
    			e.Handled = p.SelectNextControl(this, true, true, true, true);
    			return;
    		}
    		if (f.ActiveControl != null) t = f.ActiveControl.TabIndex;
    		int k = 0; 
    		do {
    			e.Handled = f.SelectNextControl(this, true, true, true, true);
    			if (f.ActiveControl != p) break;
    			TabIndex = TabIndex + 1;
	    		k += 1;
	    		if (k > 2) break;
    		} while(f != null && f.ActiveControl != null);
    	}
    	else
    	{
    		base.OnKeyDown(e);
    	}
    }
}

public class V_ScrollBar : VScrollBar
{
	public V_ScrollBar()
	{
		SetStyle(ControlStyles.Selectable, false);
		TabStop = false;
	}
}

public class H_ScrollBar : HScrollBar
{
	public H_ScrollBar()
	{
		SetStyle(ControlStyles.Selectable, false);
		TabStop = false;
	}
}

public class Scrolled_paintbox : Panel
{
	public Ref_obj AL4Object;
    public FocusPictureBox PBox;
    public VScrollBar VBar;
    public HScrollBar HBar;

    public double coeff_vert = 1;
    public double coeff_horz = 1;
    public bool Can_focus;
    public bool caret_active;
    public bool is_painting_now;
    
    public Scrolled_paintbox(bool V, bool H, bool X_Can_focus, 
    	Ref_obj X_Paintbox)
    {
//?{Paintbox}
    	AL4Object = X_Paintbox;
        Can_focus = X_Can_focus;
        AutoScroll = false;
        Width = 100;
        Height = 100;
        if (V)
        {
            VBar = new V_ScrollBar();
            VBar.Parent = this;
            VBar.Left = Width - VBar.Width;
            VBar.Top = 0;
            VBar.Height = Height;
            VBar.Anchor = AnchorStyles.Top | 
                          AnchorStyles.Right | 
                          AnchorStyles.Bottom;
            VBar.Scroll += new ScrollEventHandler(VBar_scroll);
        }
        if (H)
        {
            HBar = new H_ScrollBar();
            HBar.Parent = this;
            HBar.Top = Height - HBar.Height;
            HBar.Left = 0;
            HBar.Width = Width;
            HBar.Anchor = AnchorStyles.Left | 
                          AnchorStyles.Bottom | 
                          AnchorStyles.Right;
            HBar.Scroll += new ScrollEventHandler(HBar_scroll);
        }
        if (V && H)
        {
            VBar.Height = Height - HBar.Height;
            HBar.Width = Width - VBar.Width;
        }
        PBox = new FocusPictureBox();
        PBox.Parent = this;
        PBox.Left = 0;
        PBox.Top = 0;
        PBox.Width = Width - (V ? VBar.Width : 0);
        PBox.Height = Height - (H ? HBar.Height : 0);
        PBox.Anchor = AnchorStyles.Left |
                      AnchorStyles.Right |
                      AnchorStyles.Top | 
                      AnchorStyles.Bottom;
                      
        ((FocusPictureBox)PBox).Do_set_style(
        	ControlStyles.AllPaintingInWmPaint, true);
        if (Can_focus)
        {
            ((FocusPictureBox)PBox).Do_set_style(ControlStyles.Selectable, true);
            PBox.TabStop = true;
        }
        Resize += new EventHandler(Paintbox_resized);
//.
    }
    
    public void VBar_scroll(object sender, ScrollEventArgs e)
    {
//?{Paintbox}
    	AL4Form form = (AL4Form)Parent.Parent;
    	C_Form F = (C_Form)form.AL4Object.Obj;
    	C_Paintbox P = (C_Paintbox)AL4Object.Obj;
  	
		F.Do.M_operation_started(25, P.hard_link);
		try {
			try {
				P.Do.M_scrolled();
			} //catch(Stop) {}
			catch (Exception Ex) {
	        	if (Ex is AL4_Exception) throw;
	        }
		}
		finally {
		F.Do.M_operation_ended(25);
		}
		
		call_form_scrolled();
		AL4Form.reset_exception_state(PBox);
        PBox.Invalidate();
//.
    }
    
    public void HBar_scroll(object sender, ScrollEventArgs e)
    {
//?{Paintbox}
		AL4Form.reset_exception_state(PBox);
        PBox.Invalidate();
		call_form_scrolled();
//.
    }
    
    public void call_form_scrolled()
    {
//?{Form}.scrolled
		Control C = this;
		Ref_obj CR = (Ref_obj)C.Tag;
            AL4Form form = (AL4Form)Parent.Parent;
    		C_Form F = (C_Form)form.AL4Object.Obj;

        F.Do.M_operation_started(25, CR);
        try {
        	F.Do.M_scrolled();
        }
        finally {
        F.Do.M_operation_ended(25);
        }
//.
    }
    
    /*
    
    FUN Suspend_paintbox({Paintbox} P|aintbox_control), NATIVE :
        INT h|andle_paintbox = P.Handle 
    	CASE h == 0 ? ==> ;
    NATIVE @
    "Scrolled_paintbox SPB = (Scrolled_paintbox)AL4Form.All_descriptors["
    "		(int)X_h];"
    "SPB.suspend_count ++;" .
    
    FUN Resume_paintbox({Paintbox} P|aintbox_control), NATIVE :
        INT h|andle_paintbox = P.Handle 
    	CASE h == 0 ? ==> ;
    NATIVE @
    "Scrolled_paintbox SPB = (Scrolled_paintbox)AL4Form.All_descriptors["
    "		(int)X_h];"
    "SPB.suspend_count --;" 
    "if (SPB.suspend_count <= 0)"
    "	 SPB.Adjust_bars();" .
    

 	FUN Get_control_bitmap_bpp ==> INT := 0 .
    
    
    FUNCTION Call_form_scrolled(
    INT P|aintbox_control_handle), NATIVE : @
    "Scrolled_paintbox SPB = (Scrolled_paintbox)AL4Form.All_descriptors["
    "		(int)X_P];"
    "SPB.call_form_scrolled();" .
		
	FUN Adjust_paintbox_components(
	{Paintbox} P|aintbox_object): .

	FUN Paint_lines_activated(INT H|andle_control), NATIVE : @
	"Control C = (Control)AL4Form.All_descriptors[(int)X_H];"
	"if (!(C is Scrolled_paintbox)) return;"
	"Scrolled_paintbox spb = (Scrolled_paintbox)C;"
	"spb.PBox.Focus();" .    
	
    */
    
    public int suspend_count;
    
    public void Paintbox_resized(Object Sender, EventArgs E)
    {
//?{Paintbox}
        Adjust_bars();
//.
    }
    
	public double Content_width;
	public double Content_height;
	public double line_height = 1;
	public double row_width = 1;
	
	public int count_change_bar_visibility;
	public long last_time_bar_visibility;
	public bool bars_state_fixed;
	public int height_fixed;
	public int width_fixed;
	public int last_time_pbox_width;
    
    public void Adjust_bars()
    {
//?{Paintbox}
		if(suspend_count > 0) return;

        if (Content_width / row_width <= int.MaxValue) coeff_horz = 1;
        else coeff_horz = (Content_width + 1) / ((double)int.MaxValue - 1);
        if (Content_height <= int.MaxValue) coeff_vert = 1;
        else coeff_vert = (Content_height + 1) / ((double)int.MaxValue - 1);
        
		double w_a = PBox != null ? AL4Form.Pixels(PBox.Width) : 0;
		double h_a = PBox != null ? AL4Form.Pixels(PBox.Height): 0;
		if (w_a > Content_width) w_a = Content_width;
		if (h_a > Content_height) h_a = Content_height;

		w_a = ((int)(w_a / row_width)) * row_width;
		h_a = ((int)(h_a / line_height)) * line_height;
		
		bool was_visible_VBar = VBar != null && VBar.Visible;
		bool was_visible_HBar = HBar != null && HBar.Visible;
		bool want_v = false;
		bool want_h = false;
		
        if (VBar != null)
        {
            int m = (int)(Content_height / coeff_vert);
            int new_max = (m < 0 ? 0 : m) + 1;
            if (new_max != VBar.Maximum) VBar.Maximum = new_max;
            int new_lch = (int)Math.Max(0, h_a / coeff_vert + 1);
            if (new_lch != VBar.LargeChange) VBar.LargeChange = new_lch;
            double d_h =  AL4Form.Pixels(PBox.Height);
            if (HBar != null) d_h += AL4Form.Pixels(bar_size);
            want_v = new_max > new_lch;
            if (!want_v && 
            	bars_state_fixed && height_fixed == Height && width_fixed == Width)
            	want_v = true;
        }
        if (HBar != null)
        {
            int m = (int)(Content_width / coeff_horz);
            int new_max = (coeff_horz <= 1 ? (int)Content_width : m < 0 ? 0 : m) + 1;
            if (new_max != HBar.Maximum) HBar.Maximum = new_max;
            int new_lch = coeff_horz <= 1 ? (int)AL4Form.Pixels(PBox.Width)
            	: (int)Math.Max(0, w_a / coeff_horz + 1); 
            if (new_lch != HBar.LargeChange) HBar.LargeChange = new_lch;
            double d_w = AL4Form.Pixels(PBox.Width);
            if (VBar != null) d_w += AL4Form.Pixels(bar_size);
            //////////////////////////////
            //Console.WriteLine("Content_width=" + Content_width.ToString() +
            //    " d_w=" + d_w.ToString() + "");
            //////////////////////////////
            want_h = new_max > new_lch;
            if (!want_h &&
            	bars_state_fixed && height_fixed == Height && width_fixed == Width)
            {
            	//AL4.WriteLine("want_h");
            	want_h = true;
            }
        }
        if (last_time_pbox_width != PBox.Width) {
        	last_time_pbox_width = PBox.Width;
        	count_change_bar_visibility = 0;
        }
        if (was_visible_VBar != want_v || was_visible_HBar != want_h)
        {
        	bars_state_fixed = false;
        	if (Environment.TickCount - last_time_bar_visibility > 1000)
			{
				last_time_bar_visibility = Environment.TickCount;
				count_change_bar_visibility = 0;
			}
			count_change_bar_visibility ++ ;
			if (count_change_bar_visibility > 3)
			{
				bars_state_fixed = true;
				height_fixed = Width;
				width_fixed = Height;
				want_v = true;
				want_h = true;
                //Console.WriteLine("therefore want_h=TRUE, count_change_bar_visibility=" +
                // count_change_bar_visibility.ToString());
			}
        } else count_change_bar_visibility = 0;
        if (VBar != null && want_v != VBar.Visible)
        	VBar.Visible = want_v;
        if (HBar != null && want_h != HBar.Visible)
        	HBar.Visible = want_h;
        if (bar_size == 0 && VBar != null && VBar.Visible) bar_size = VBar.Width;
        if (bar_size == 0 && HBar != null && HBar.Visible) bar_size = HBar.Height;
        
        int new_w = Width - ((VBar != null && VBar.Visible) ? VBar.Width : 0); 
        if (PBox.Width != new_w) PBox.Width = new_w;
        int new_h = Height - ((HBar!=null && HBar.Visible) ? HBar.Height : 0); 
        if (PBox.Height != new_h) PBox.Height = new_h;
//.
    }
    
    public static int bar_size;
    
    public void Control_Enter(object Sender, EventArgs E)
    {
//?{Form}.enter
        Ref_obj CR = (Ref_obj)Tag;
        C_Paintbox CC = (C_Paintbox)CR.Obj;

        Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors[
        	(int)CC.F_Handle];
        AL4Form AForm = (AL4Form)P.Parent.Parent;
        C_Form F = (C_Form)AForm.AL4Object.Obj;
        
        F.Do.M_operation_started(24, CR);
        try {
	        try {
	        	F.Do.M_enter();
	        } //catch(Stop) {}
	        catch (Exception Ex) {
	        	if (Ex is AL4_Exception) throw;
	        }
        }
        finally {
        F.Do.M_operation_ended(24);
        }
//.
    }
    
    public void Control_Leave(object Sender, EventArgs E)
    {
//?{Form}.leave
        Ref_obj CR = (Ref_obj)Tag;
        C_Paintbox CC = (C_Paintbox)CR.Obj;

        Scrolled_paintbox P = (Scrolled_paintbox)AL4Form.All_descriptors[
        	(int)CC.F_Handle];
        AL4Form AForm = (AL4Form)P.Parent.Parent;
        C_Form F = (C_Form)AForm.AL4Object.Obj;

        F.Do.M_operation_started(24, CR);
        try {
	        try {
	        	F.Do.M_leave();
	        } //catch(Stop) {}
	        catch (Exception Ex) {
	        	if (Ex is AL4_Exception) throw;
	        }
        }
        finally {
        F.Do.M_operation_ended(24);
        }
//.
    }
    
    public void Control_MouseDown(Object Sender, MouseEventArgs E)
    {
        if (Can_focus)
            ((Control)Sender).Focus();
    }
    
    /*
    
    FUNCTION Set_paint_lines_cursor_shape(
        INT H|andle_paint_lines,
        {Paintbox}.{cursor} C|ursor_shape )
        :
        Set_control_cursor_shape(H, C) .    
    
    FUNCTION Set_control_cursor_shape(
        INT H|andle_control,
        {cursor} C|ursor_shape ), NATIVE :
    @   "Control C = (Control)AL4Form.All_descriptors[(int)X_H];"
    	"if (C is Scrolled_paintbox)"
    	"	C = ((Scrolled_paintbox)C).PBox;" 
        "switch(X_C)"
        "{"
        "case 0: C.Cursor = Cursors.Arrow; break;"
        "case 1: C.Cursor = Cursors.IBeam; break;"
        "case 2: C.Cursor = Cursors.No; break;"
        "case 3: C.Cursor = Cursors.Cross; break;"
        "case 4: C.Cursor = Cursors.Hand; break;"
        "case 5: C.Cursor = Cursors.WaitCursor; break;"
        "case 6: C.Cursor = Cursors.AppStarting; break;"
        "case 7: C.Cursor = Cursors.UpArrow; break;"
        "case 8: C.Cursor = Cursors.SizeAll; break;"
        "case 9: C.Cursor = Cursors.SizeWE; break;"
        "case 10: C.Cursor = Cursors.SizeNS; break;"
        "case 11: C.Cursor = Cursors.SizeNESW; break;"
        "case 12: C.Cursor = Cursors.SizeNWSE; break;"
        "case 13: C.Cursor = Cursors.Help; break;"
        "}"
        .
    */
//----------------------------------------------- C A R E T ------------
    /*
    
    FUNCTION Set_caret_blink_time(INT Msec|onds),
    DEPRECATED('Platform dependent'), NATIVE : @
        "Scrolled_paintbox.Do_Set_caret_blink_time((int)X_Msec);" .
    
    FUNCTION Provide_window_caret(
        INT S|crolled_paintbox_handle,
        REAL X|_pos_points,
        REAL Y|_pos_points,
        REAL Caret_w|idth_points,
        REAL Caret_h|eight_points), NATIVE
        :
        INT off_x|_in_pixels = Points(X)
        INT off_y|_in_points = Points(Y)
        INT w_caret|_pixels = Points(Caret_w)
        INT h_caret|_pixels = Points(Caret_h)
        NATIVE @
        "Scrolled_paintbox.Do_provide_window_caret("
        "	(int)X_S, (int)X_off_x, (int)X_off_y, "
        "   (int)X_w_caret, (int)X_h_caret);" .
        
    */
    [DllImport("user32.dll")]
    static extern bool SetCaretBlinkTime(int milliseconds);
    
    public static void Do_Set_caret_blink_time(int msec)
    {
    	SetCaretBlinkTime(msec);
    }

    
    [DllImport("user32", CharSet=CharSet.Auto, SetLastError= true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SystemParametersInfo(int uAction, bool uParam,
    	ref int pvParam, int fuWinIni);
    
    [DllImport("user32.dll")]
    static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, 
        int nHeight);
    [DllImport("user32.dll")]
    static extern bool ShowCaret(IntPtr hWnd);
    [DllImport("user32.dll")]
    static extern bool HideCaret(IntPtr hWnd);
    [DllImport("user32.dll")]
    static extern bool SetCaretPos(int x, int y);
    [DllImport("user32.dll")]
    static extern IntPtr GetFocus();
    [DllImport("user32.dll")]
    static extern IntPtr SetFocus(IntPtr hWnd);
    
    public static void Do_provide_window_caret(int X_S, int off_x, int off_y, 
            int w_caret, int h_caret)
    {
        Scrolled_paintbox S = (Scrolled_paintbox)AL4Form.All_descriptors[
        	(int)X_S];
        IntPtr H = S.PBox.Handle;
        if (w_caret < 1) {
        	int pixels = 1;
        	SystemParametersInfo(0x2006, //SPI_GETCARETWIDTH
        	false, ref pixels, 0);
        	w_caret = pixels;
        }
        CreateCaret(H, IntPtr.Zero, w_caret, h_caret);
        
        AL4Form f = (AL4Form)((AL4Column)S.Parent).Parent;
        if (AL4Form.Do_Is_form_active((int)((C_Form)f.AL4Object.Obj).F_Handle))
            SetFocus(H);
        
        if (GetFocus() == H)
        {
            SetCaretPos(off_x, off_y);
            ShowCaret(H);
            S.caret_active = true;
        }
        else {
        	if (S.caret_active)
        	{
        		S.caret_active = false;
        	}
        }
    }
    
    /*
    
    FUNCTION Destroy_window_caret(
    	INT S|crolled_paintbox_handle), NATIVE :
    @   "Scrolled_paintbox.Do_destroy_window_caret((int)X_S);" .
    */

    public static void Do_destroy_window_caret(int X_S)
    {
        Scrolled_paintbox S = (Scrolled_paintbox)AL4Form.All_descriptors[
        	(int)X_S];
        IntPtr H = S.PBox.Handle;
        HideCaret(H);
    }
    
	/*
    
    FUNCTION Set_canvas_quality(
    	{Canvas} C|anvas_object, {Canvas}.{quality} Q|uality_set) : .
    	
    FUN End_paint_of_canvas(
	{Canvas} C|anvas_object_dummy): .

    */
    
}

}

/*
END
*/
