diff --git a/.gitattributes b/.gitattributes index d9d6b5075b..6909dba3cd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -81,6 +81,7 @@ components/aggpas/image_resample.dpr svneol=native#text/plain components/aggpas/image_transforms.dpr svneol=native#text/plain components/aggpas/image_transforms.txt svneol=native#text/plain components/aggpas/interactive_polygon_.pas svneol=native#text/plain +components/aggpas/lazarus/aggpaslcl.lpk svneol=native#text/plain components/aggpas/line_patterns.dpr svneol=native#text/plain components/aggpas/lion.dpr svneol=native#text/plain components/aggpas/lion_lens.dpr svneol=native#text/plain @@ -295,6 +296,9 @@ components/aggpas/src/pf_rgb565_gamma.inc svneol=native#text/plain components/aggpas/src/pf_rgb565_pre.inc svneol=native#text/plain components/aggpas/src/pf_rgba32.inc svneol=native#text/plain components/aggpas/src/pf_rgba32_pre.inc svneol=native#text/plain +components/aggpas/src/platform/lcl/agg_linux_mini_libc.pas svneol=native#text/plain +components/aggpas/src/platform/lcl/agg_platform_support.pas svneol=native#text/plain +components/aggpas/src/platform/lcl/file_utils_.pas svneol=native#text/plain components/aggpas/src/platform/linux/agg_linux_mini_libc.pas svneol=native#text/plain components/aggpas/src/platform/linux/agg_platform_support.pas svneol=native#text/plain components/aggpas/src/platform/linux/file_utils_.pas svneol=native#text/plain diff --git a/components/aggpas/lazarus/aggpaslcl.lpk b/components/aggpas/lazarus/aggpaslcl.lpk new file mode 100644 index 0000000000..d19a1db3e0 --- /dev/null +++ b/components/aggpas/lazarus/aggpaslcl.lpk @@ -0,0 +1,912 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/aggpas/src/platform/lcl/agg_linux_mini_libc.pas b/components/aggpas/src/platform/lcl/agg_linux_mini_libc.pas new file mode 100644 index 0000000000..314983f15b --- /dev/null +++ b/components/aggpas/src/platform/lcl/agg_linux_mini_libc.pas @@ -0,0 +1,21 @@ +unit agg_linux_mini_libc; + +{$mode delphi} + +interface + +uses + ctypes; + +const + clib = 'c'; + CLOCKS_PER_SEC = 1000000; +type + clock_t = clong; + +function clock:clock_t;cdecl;external clib name 'clock'; + +implementation + +end. + diff --git a/components/aggpas/src/platform/lcl/agg_platform_support.pas b/components/aggpas/src/platform/lcl/agg_platform_support.pas new file mode 100644 index 0000000000..461b39da2d --- /dev/null +++ b/components/aggpas/src/platform/lcl/agg_platform_support.pas @@ -0,0 +1,2516 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 (Public License) +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3) +// Pascal Port By: Milan Marusinec alias Milano +// milan@marusinec.sk +// http://www.aggpas.org +// Copyright (c) 2005-2006 +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +// +//---------------------------------------------------------------------------- +// +// class platform_support +// +// It's not a part of the AGG library, it's just a helper class to create +// interactive demo examples. Since the examples should not be too complex +// this class is provided to support some very basic interactive graphical +// funtionality, such as putting the rendered image to the window, simple +// keyboard and mouse input, window resizing, setting the window title, +// and catching the "idle" events. +// +// The most popular platforms are: +// +// Windows-32 API +// X-Window API +// SDL library (see http://www.libsdl.org/) +// MacOS C/C++ API +// +// All the system dependent stuff sits in the platform_specific class. +// The platform_support class has just a pointer to it and it's +// the responsibility of the implementation to create/delete it. +// This class being defined in the implementation file can have +// any platform dependent stuff such as HWND, X11 Window and so on. +// +// [Pascal Port History] ----------------------------------------------------- +// +// 23.06.2006-Milano: ptrcomp adjustments +// 29.03.2006-Milano: finished & tested OK +// 28.03.2006-Milano: platform_specific & platform_support +// 20.03.2006-Milano: Unit port establishment +// +{ agg_platform_support.pas } +unit + agg_platform_support ; + +INTERFACE + +{$I agg_mode.inc } +{$I- } +uses + X ,Xlib ,Xutil ,Xatom ,keysym ,CTypes ,SysUtils , + agg_linux_mini_libc , + agg_basics , + agg_ctrl , + agg_rendering_buffer , + agg_trans_affine , + agg_trans_viewport , + agg_color_conv , + file_utils_ ; + +const + {$IFDEF Ver2_2} + xFalse = False; + xTrue = True; + {$ELSE} + xFalse = 0; + xTrue = 1; + {$ENDIF} + +{ TYPES DEFINITION } +const +//----------------------------------------------------------window_flag_e +// These are flags used in method init(). Not all of them are +// applicable on different platforms, for example the win32_api +// cannot use a hardware buffer (window_hw_buffer). +// The implementation should simply ignore unsupported flags. + window_resize = 1; + window_hw_buffer = 2; + window_keep_aspect_ratio = 4; + window_process_all_keys = 8; + +type +//-----------------------------------------------------------pix_format_e +// Possible formats of the rendering buffer. Initially I thought that it's +// reasonable to create the buffer and the rendering functions in +// accordance with the native pixel format of the system because it +// would have no overhead for pixel format conersion. +// But eventually I came to a conclusion that having a possibility to +// convert pixel formats on demand is a good idea. First, it was X11 where +// there lots of different formats and visuals and it would be great to +// render everything in, say, RGB-24 and display it automatically without +// any additional efforts. The second reason is to have a possibility to +// debug renderers for different pixel formats and colorspaces having only +// one computer and one system. +// +// This stuff is not included into the basic AGG functionality because the +// number of supported pixel formats (and/or colorspaces) can be great and +// if one needs to add new format it would be good only to add new +// rendering files without having to modify any existing ones (a general +// principle of incapsulation and isolation). +// +// Using a particular pixel format doesn't obligatory mean the necessity +// of software conversion. For example, win32 API can natively display +// gray8, 15-bit RGB, 24-bit BGR, and 32-bit BGRA formats. +// This list can be (and will be!) extended in future. + pix_format_e = ( + + pix_format_undefined , // By default. No conversions are applied + pix_format_bw, // 1 bit per color B/W + pix_format_gray8, // Simple 256 level grayscale + pix_format_gray16, // Simple 65535 level grayscale + pix_format_rgb555, // 15 bit rgb. Depends on the byte ordering! + pix_format_rgb565, // 16 bit rgb. Depends on the byte ordering! + pix_format_rgbAAA, // 30 bit rgb. Depends on the byte ordering! + pix_format_rgbBBA, // 32 bit rgb. Depends on the byte ordering! + pix_format_bgrAAA, // 30 bit bgr. Depends on the byte ordering! + pix_format_bgrABB, // 32 bit bgr. Depends on the byte ordering! + pix_format_rgb24, // R-G-B, one byte per color component + pix_format_bgr24, // B-G-R, native win32 BMP format. + pix_format_rgba32, // R-G-B-A, one byte per color component + pix_format_argb32, // A-R-G-B, native MAC format + pix_format_abgr32, // A-B-G-R, one byte per color component + pix_format_bgra32, // B-G-R-A, native win32 BMP format + pix_format_rgb48, // R-G-B, 16 bits per color component + pix_format_bgr48, // B-G-R, native win32 BMP format. + pix_format_rgba64, // R-G-B-A, 16 bits byte per color component + pix_format_argb64, // A-R-G-B, native MAC format + pix_format_abgr64, // A-B-G-R, one byte per color component + pix_format_bgra64, // B-G-R-A, native win32 BMP format + + end_of_pix_formats ); + +const +//-------------------------------------------------------------input_flag_e +// Mouse and keyboard flags. They can be different on different platforms +// and the ways they are obtained are also different. But in any case +// the system dependent flags should be mapped into these ones. The meaning +// of that is as follows. For example, if kbd_ctrl is set it means that the +// ctrl key is pressed and being held at the moment. They are also used in +// the overridden methods such as on_mouse_move(), on_mouse_button_down(), +// on_mouse_button_dbl_click(), on_mouse_button_up(), on_key(). +// In the method on_mouse_button_up() the mouse flags have different +// meaning. They mean that the respective button is being released, but +// the meaning of the keyboard flags remains the same. +// There's absolut minimal set of flags is used because they'll be most +// probably supported on different platforms. Even the mouse_right flag +// is restricted because Mac's mice have only one button, but AFAIK +// it can be simulated with holding a special key on the keydoard. + mouse_left = 1; + mouse_right = 2; + kbd_shift = 4; + kbd_ctrl = 8; + +//--------------------------------------------------------------key_code_e +// Keyboard codes. There's also a restricted set of codes that are most +// probably supported on different platforms. Any platform dependent codes +// should be converted into these ones. There're only those codes are +// defined that cannot be represented as printable ASCII-characters. +// All printable ASCII-set can be used in a regilar C/C++ manner: +// ' ', 'A', '0' '+' and so on. +// Since the clasas is used for creating very simple demo-applications +// we don't need very rich possibilities here, just basic ones. +// Actually the numeric key codes are taken from the SDL library, so, +// the implementation of the SDL support does not require any mapping. +// ASCII set. Should be supported everywhere + key_backspace = 8; + key_tab = 9; + key_clear = 12; + key_return = 13; + key_pause = 19; + key_escape = 27; + +// Keypad + key_delete = 127; + key_kp0 = 256; + key_kp1 = 257; + key_kp2 = 258; + key_kp3 = 259; + key_kp4 = 260; + key_kp5 = 261; + key_kp6 = 262; + key_kp7 = 263; + key_kp8 = 264; + key_kp9 = 265; + key_kp_period = 266; + key_kp_divide = 267; + key_kp_multiply = 268; + key_kp_minus = 269; + key_kp_plus = 270; + key_kp_enter = 271; + key_kp_equals = 272; + +// Arrow-keys and stuff + key_up = 273; + key_down = 274; + key_right = 275; + key_left = 276; + key_insert = 277; + key_home = 278; + key_end = 279; + key_page_up = 280; + key_page_down = 281; + +// Functional keys. You'd better avoid using +// f11...f15 in your applications if you want +// the applications to be portable + key_f1 = 282; + key_f2 = 283; + key_f3 = 284; + key_f4 = 285; + key_f5 = 286; + key_f6 = 287; + key_f7 = 288; + key_f8 = 289; + key_f9 = 290; + key_f10 = 291; + key_f11 = 292; + key_f12 = 293; + key_f13 = 294; + key_f14 = 295; + key_f15 = 296; + +// The possibility of using these keys is +// very restricted. Actually it's guaranteed +// only in win32_api and win32_sdl implementations + key_numlock = 300; + key_capslock = 301; + key_scrollock = 302; + + max_ctrl = 128; + +type +//----------------------------------------------------------ctrl_container +// A helper class that contains pointers to a number of controls. +// This class is used to ease the event handling with controls. +// The implementation should simply call the appropriate methods +// of this class when appropriate events occure. + crtl_container_ptr = ^ctrl_container; + ctrl_container = object + m_ctrl : array[0..max_ctrl - 1 ] of ctrl_ptr; + + m_num_ctrl : unsigned; + m_cur_ctrl : int; + + constructor Construct; + destructor Destruct; + + procedure add(c : ctrl_ptr ); + + function in_rect(x ,y : double ) : boolean; + + function on_mouse_button_down(x ,y : double ) : boolean; + function on_mouse_button_up (x ,y : double ) : boolean; + + function on_mouse_move(x ,y : double; button_flag : boolean ) : boolean; + function on_arrow_keys(left ,right ,down ,up : boolean ) : boolean; + + function set_cur(x ,y : double ) : boolean; + + end; + +//---------------------------------------------------------platform_support +// This class is a base one to the apllication classes. It can be used +// as follows: +// +// the_application = object(platform_support ) +// +// constructor Construct(bpp : unsigned; flip_y : boolean ); +// . . . +// +// //override stuff . . . +// procedure on_init; virtual; +// procedure on_draw; virtual; +// procedure on_resize(sx ,sy : int ); virtual; +// // . . . and so on, see virtual functions +// +// //any your own stuff . . . +// }; +// +// VAR +// app : the_application; +// +// BEGIN +// app.Construct(pix_format_rgb24 ,true ); +// app.caption ("AGG Example. Lion" ); +// +// if app.init(500 ,400 ,window_resize ) then +// app.run; +// +// app.Destruct; +// +// END. +// +const + max_images = 16; + +type + platform_specific_ptr = ^platform_specific; + platform_specific = object + m_format , + m_sys_format : pix_format_e; + m_byte_order : int; + + m_flip_y : boolean; + m_bpp , + m_sys_bpp : unsigned; + m_display : PDisplay; + m_screen , + m_depth : int; + m_visual : PVisual; + m_window : TWindow; + m_gc : TGC; + + m_window_attributes : TXSetWindowAttributes; + + m_ximg_window : PXImage; + m_close_atom : TAtom; + m_buf_window : pointer; + m_buf_alloc : unsigned; + m_buf_img : array[0..max_images - 1 ] of pointer; + m_img_alloc : array[0..max_images - 1 ] of unsigned; + + m_keymap : array[0..255 ] of unsigned; + + m_update_flag , + m_resize_flag , + m_initialized : boolean; + + //m_wait_mode : boolean; + m_sw_start : clock_t; + + constructor Construct(format : pix_format_e; flip_y : boolean ); + destructor Destruct; + + procedure caption_ (capt : PChar ); + procedure put_image(src : rendering_buffer_ptr ); + + end; + + platform_support_ptr = ^platform_support; + platform_support = object + m_specific : platform_specific_ptr; + m_ctrls : ctrl_container; + + m_format : pix_format_e; + + m_bpp : unsigned; + + m_rbuf_window : rendering_buffer; + m_rbuf_img : array[0..max_images - 1 ] of rendering_buffer; + + m_window_flags : unsigned; + m_wait_mode , + m_flip_y : boolean; // flip_y - true if you want to have the Y-axis flipped vertically + m_caption : shortstring; + m_resize_mtx : trans_affine; + + m_initial_width , + m_initial_height : int; + + m_quit : boolean; + + constructor Construct(format_ : pix_format_e; flip_y_ : boolean ); + destructor Destruct; + + // Setting the windows caption (title). Should be able + // to be called at least before calling init(). + // It's perfect if they can be called anytime. + procedure caption_(cap : shortstring ); + + // These 3 menthods handle working with images. The image + // formats are the simplest ones, such as .BMP in Windows or + // .ppm in Linux. In the applications the names of the files + // should not have any file extensions. Method load_img() can + // be called before init(), so, the application could be able + // to determine the initial size of the window depending on + // the size of the loaded image. + // The argument "idx" is the number of the image 0...max_images-1 + function load_img (idx : unsigned; file_ : shortstring ) : boolean; + function save_img (idx : unsigned; file_ : shortstring ) : boolean; + function create_img(idx : unsigned; width_ : unsigned = 0; height_ : unsigned = 0 ) : boolean; + + // init() and run(). See description before the class for details. + // The necessity of calling init() after creation is that it's + // impossible to call the overridden virtual function (on_init()) + // from the constructor. On the other hand it's very useful to have + // some on_init() event handler when the window is created but + // not yet displayed. The rbuf_window() method (see below) is + // accessible from on_init(). + function init(width_ ,height_ ,flags : unsigned ) : boolean; + function run : int; + procedure quit; + + // The very same parameters that were used in the constructor + function _format : pix_format_e; + function _flip_y : boolean; + function _bpp : unsigned; + + // The following provides a very simple mechanism of doing someting + // in background. It's not multitheading. When whait_mode is true + // the class waits for the events and it does not ever call on_idle(). + // When it's false it calls on_idle() when the event queue is empty. + // The mode can be changed anytime. This mechanism is satisfactory + // for creation very simple animations. + function _wait_mode : boolean; + procedure wait_mode_(wait_mode : boolean ); + + // These two functions control updating of the window. + // force_redraw() is an analog of the Win32 InvalidateRect() function. + // Being called it sets a flag (or sends a message) which results + // in calling on_draw() and updating the content of the window + // when the next event cycle comes. + // update_window() results in just putting immediately the content + // of the currently rendered buffer to the window without calling + // on_draw(). + procedure force_redraw; + procedure update_window; + + // So, finally, how to draw anythig with AGG? Very simple. + // rbuf_window() returns a reference to the main rendering + // buffer which can be attached to any rendering class. + // rbuf_img() returns a reference to the previously created + // or loaded image buffer (see load_img()). The image buffers + // are not displayed directly, they should be copied to or + // combined somehow with the rbuf_window(). rbuf_window() is + // the only buffer that can be actually displayed. + function rbuf_window : rendering_buffer_ptr; + function rbuf_img(idx : unsigned ) : rendering_buffer_ptr; + + // Returns file extension used in the implemenation for the particular + // system. + function _img_ext : shortstring; + + // + procedure copy_img_to_window(idx : unsigned ); + procedure copy_window_to_img(idx : unsigned ); + procedure copy_img_to_img (idx_to ,idx_from : unsigned ); + + // Event handlers. They are not pure functions, so you don't have + // to override them all. + // In my demo applications these functions are defined inside + // the the_application class + procedure on_init; virtual; + procedure on_resize(sx ,sy : int ); virtual; + procedure on_idle; virtual; + + procedure on_mouse_move(x ,y : int; flags : unsigned ); virtual; + + procedure on_mouse_button_down(x ,y : int; flags : unsigned ); virtual; + procedure on_mouse_button_up (x ,y : int; flags : unsigned ); virtual; + + procedure on_key(x ,y : int; key ,flags : unsigned ); virtual; + procedure on_ctrl_change; virtual; + procedure on_draw; virtual; + procedure on_post_draw(raw_handler : pointer ); virtual; + + // Adding control elements. A control element once added will be + // working and reacting to the mouse and keyboard events. Still, you + // will have to render them in the on_draw() using function + // render_ctrl() because platform_support doesn't know anything about + // renderers you use. The controls will be also scaled automatically + // if they provide a proper scaling mechanism (all the controls + // included into the basic AGG package do). + // If you don't need a particular control to be scaled automatically + // call ctrl::no_transform() after adding. + procedure add_ctrl(c : ctrl_ptr ); + + // Auxiliary functions. trans_affine_resizing() modifier sets up the resizing + // matrix on the basis of the given width and height and the initial + // width and height of the window. The implementation should simply + // call this function every time when it catches the resizing event + // passing in the new values of width and height of the window. + // Nothing prevents you from "cheating" the scaling matrix if you + // call this function from somewhere with wrong arguments. + // trans_affine_resizing() accessor simply returns current resizing matrix + // which can be used to apply additional scaling of any of your + // stuff when the window is being resized. + // width(), height(), initial_width(), and initial_height() must be + // clear to understand with no comments :-) + procedure trans_affine_resizing_(width_ ,height_ : int ); + function _trans_affine_resizing : trans_affine_ptr; + + function _width : double; + function _height : double; + function _initial_width : double; + function _initial_height : double; + function _window_flags : unsigned; + + // Get raw display handler depending on the system. + // For win32 its an HDC, for other systems it can be a pointer to some + // structure. See the implementation files for detals. + // It's provided "as is", so, first you should check if it's not null. + // If it's null the raw_display_handler is not supported. Also, there's + // no guarantee that this function is implemented, so, in some + // implementations you may have simply an unresolved symbol when linking. + function _raw_display_handler : pointer; + + // display message box or print the message to the console + // (depending on implementation) + procedure message_(msg : PChar ); + + // Stopwatch functions. Function elapsed_time() returns time elapsed + // since the latest start_timer() invocation in millisecods. + // The resolutoin depends on the implementation. + // In Win32 it uses QueryPerformanceFrequency() / QueryPerformanceCounter(). + procedure start_timer; + function elapsed_time : double; + + // Get the full file name. In most cases it simply returns + // file_name. As it's appropriate in many systems if you open + // a file by its name without specifying the path, it tries to + // open it in the current directory. The demos usually expect + // all the supplementary files to be placed in the current + // directory, that is usually coincides with the directory where + // the the executable is. However, in some systems (BeOS) it's not so. + // For those kinds of systems full_file_name() can help access files + // preserving commonly used policy. + // So, it's a good idea to use in the demos the following: + // FILE* fd = fopen(full_file_name("some.file"), "r"); + // instead of + // FILE* fd = fopen("some.file", "r"); + function full_file_name(file_name : shortstring ) : shortstring; + function file_source (path ,fname : shortstring ) : shortstring; + + end; + +{ GLOBAL PROCEDURES } + + +IMPLEMENTATION +{ LOCAL VARIABLES & CONSTANTS } +{ UNIT IMPLEMENTATION } +{ CONSTRUCT } +constructor ctrl_container.Construct; +begin + m_num_ctrl:=0; + m_cur_ctrl:=-1; + +end; + +{ DESTRUCT } +destructor ctrl_container.Destruct; +begin +end; + +{ ADD } +procedure ctrl_container.add; +begin + if m_num_ctrl < max_ctrl then + begin + m_ctrl[m_num_ctrl ]:=c; + + inc(m_num_ctrl ); + + end; + +end; + +{ IN_RECT } +function ctrl_container.in_rect; +var + i : unsigned; + +begin + result:=false; + + if m_num_ctrl > 0 then + for i:=0 to m_num_ctrl - 1 do + if m_ctrl[i ].in_rect(x ,y ) then + begin + result:=true; + + exit; + + end; + +end; + +{ ON_MOUSE_BUTTON_DOWN } +function ctrl_container.on_mouse_button_down; +var + i : unsigned; + +begin + result:=false; + + if m_num_ctrl > 0 then + for i:=0 to m_num_ctrl - 1 do + if m_ctrl[i ].on_mouse_button_down(x ,y ) then + begin + result:=true; + + exit; + + end; + +end; + +{ ON_MOUSE_BUTTON_UP } +function ctrl_container.on_mouse_button_up; +var + i : unsigned; + +begin + result:=false; + + if m_num_ctrl > 0 then + for i:=0 to m_num_ctrl - 1 do + if m_ctrl[i ].on_mouse_button_up(x ,y ) then + begin + result:=true; + + exit; + + end; + +end; + +{ ON_MOUSE_MOVE } +function ctrl_container.on_mouse_move; +var + i : unsigned; + +begin + result:=false; + + if m_num_ctrl > 0 then + for i:=0 to m_num_ctrl - 1 do + if m_ctrl[i ].on_mouse_move(x ,y ,button_flag ) then + begin + result:=true; + + exit; + + end; + +end; + +{ ON_ARROW_KEYS } +function ctrl_container.on_arrow_keys; +begin + result:=false; + + if m_cur_ctrl >= 0 then + result:=m_ctrl[m_cur_ctrl ].on_arrow_keys(left ,right ,down ,up ); + +end; + +{ SET_CUR } +function ctrl_container.set_cur; +var + i : unsigned; + +begin + result:=false; + + if m_num_ctrl > 0 then + for i:=0 to m_num_ctrl - 1 do + if m_ctrl[i ].in_rect(x ,y ) then + begin + if m_cur_ctrl <> i then + begin + m_cur_ctrl:=i; + + result:=true; + + end; + + exit; + + end; + + if m_cur_ctrl <> -1 then + begin + m_cur_ctrl:=-1; + + result:=true; + + end; + +end; + +{ CONSTRUCT } +constructor platform_specific.Construct; +var + i : unsigned; + +begin + m_format :=format; + m_sys_format:=pix_format_undefined; + m_byte_order:=LSBFirst; + m_flip_y :=flip_y; + + m_bpp :=0; + m_sys_bpp:=0; + m_display:=NIL; + m_screen :=0; + m_depth :=0; + m_visual :=NIL; + m_window :=0; + m_gc :=NIL; + + m_ximg_window:=NIL; + m_close_atom :=0; + m_buf_window :=NIL; + m_buf_alloc :=0; + + m_update_flag:=true; + m_resize_flag:=true; + m_initialized:=false; + //m_wait_mode:=true; + + fillchar(m_buf_img[0 ] ,sizeof(m_buf_img ) ,0 ); + + for i:=0 to 255 do + m_keymap[i ]:=i; + + m_keymap[XK_Pause and $FF ]:=key_pause; + m_keymap[XK_Clear and $FF ]:=key_clear; + + m_keymap[XK_KP_0 and $FF ]:=key_kp0; + m_keymap[XK_KP_1 and $FF ]:=key_kp1; + m_keymap[XK_KP_2 and $FF ]:=key_kp2; + m_keymap[XK_KP_3 and $FF ]:=key_kp3; + m_keymap[XK_KP_4 and $FF ]:=key_kp4; + m_keymap[XK_KP_5 and $FF ]:=key_kp5; + m_keymap[XK_KP_6 and $FF ]:=key_kp6; + m_keymap[XK_KP_7 and $FF ]:=key_kp7; + m_keymap[XK_KP_8 and $FF ]:=key_kp8; + m_keymap[XK_KP_9 and $FF ]:=key_kp9; + + m_keymap[XK_KP_Insert and $FF ] :=key_kp0; + m_keymap[XK_KP_End and $FF ] :=key_kp1; + m_keymap[XK_KP_Down and $FF ] :=key_kp2; + m_keymap[XK_KP_Page_Down and $FF ]:=key_kp3; + m_keymap[XK_KP_Left and $FF ] :=key_kp4; + m_keymap[XK_KP_Begin and $FF ] :=key_kp5; + m_keymap[XK_KP_Right and $FF ] :=key_kp6; + m_keymap[XK_KP_Home and $FF ] :=key_kp7; + m_keymap[XK_KP_Up and $FF ] :=key_kp8; + m_keymap[XK_KP_Page_Up and $FF ] :=key_kp9; + m_keymap[XK_KP_Delete and $FF ] :=key_kp_period; + m_keymap[XK_KP_Decimal and $FF ] :=key_kp_period; + m_keymap[XK_KP_Divide and $FF ] :=key_kp_divide; + m_keymap[XK_KP_Multiply and $FF ] :=key_kp_multiply; + m_keymap[XK_KP_Subtract and $FF ] :=key_kp_minus; + m_keymap[XK_KP_Add and $FF ] :=key_kp_plus; + m_keymap[XK_KP_Enter and $FF ] :=key_kp_enter; + m_keymap[XK_KP_Equal and $FF ] :=key_kp_equals; + + m_keymap[XK_Up and $FF ] :=key_up; + m_keymap[XK_Down and $FF ] :=key_down; + m_keymap[XK_Right and $FF ] :=key_right; + m_keymap[XK_Left and $FF ] :=key_left; + m_keymap[XK_Insert and $FF ] :=key_insert; + m_keymap[XK_Home and $FF ] :=key_delete; + m_keymap[XK_End and $FF ] :=key_end; + m_keymap[XK_Page_Up and $FF ] :=key_page_up; + m_keymap[XK_Page_Down and $FF ]:=key_page_down; + + m_keymap[XK_F1 and $FF ] :=key_f1; + m_keymap[XK_F2 and $FF ] :=key_f2; + m_keymap[XK_F3 and $FF ] :=key_f3; + m_keymap[XK_F4 and $FF ] :=key_f4; + m_keymap[XK_F5 and $FF ] :=key_f5; + m_keymap[XK_F6 and $FF ] :=key_f6; + m_keymap[XK_F7 and $FF ] :=key_f7; + m_keymap[XK_F8 and $FF ] :=key_f8; + m_keymap[XK_F9 and $FF ] :=key_f9; + m_keymap[XK_F10 and $FF ]:=key_f10; + m_keymap[XK_F11 and $FF ]:=key_f11; + m_keymap[XK_F12 and $FF ]:=key_f12; + m_keymap[XK_F13 and $FF ]:=key_f13; + m_keymap[XK_F14 and $FF ]:=key_f14; + m_keymap[XK_F15 and $FF ]:=key_f15; + + m_keymap[XK_Num_Lock and $FF ] :=key_numlock; + m_keymap[XK_Caps_Lock and $FF ] :=key_capslock; + m_keymap[XK_Scroll_Lock and $FF ]:=key_scrollock; + + case m_format of + pix_format_gray8 : + m_bpp:=8; + + pix_format_rgb565 , + pix_format_rgb555 : + m_bpp:=16; + + pix_format_rgb24 , + pix_format_bgr24 : + m_bpp:=24; + + pix_format_bgra32 , + pix_format_abgr32 , + pix_format_argb32 , + pix_format_rgba32 : + m_bpp:=32; + + end; + + m_sw_start:=clock; + +end; + +{ DESTRUCT } +destructor platform_specific.Destruct; +begin +end; + +{ CAPTION_ } +procedure platform_specific.caption_; +var + tp : TXTextProperty; + +begin + tp.value :=PCUChar(@capt[1 ] ); + tp.encoding:=XA_WM_NAME; + tp.format :=8; + tp.nitems :=strlen(capt ); + + XSetWMName (m_display ,m_window ,@tp ); + XStoreName (m_display ,m_window ,capt ); + XSetIconName (m_display ,m_window ,capt ); + XSetWMIconName(m_display ,m_window ,@tp ); + +end; + +{ PUT_IMAGE } +procedure platform_specific.put_image; +var + row_len : int; + buf_tmp : pointer; + + rbuf_tmp : rendering_buffer; + +begin + if m_ximg_window = NIL then + exit; + + m_ximg_window.data:=m_buf_window; + + if m_format = m_sys_format then + XPutImage( + m_display , + m_window , + m_gc , + m_ximg_window , + 0 ,0 ,0 ,0 , + src._width , + src._height ) + + else + begin + row_len:=src._width * m_sys_bpp div 8; + + agg_getmem(buf_tmp ,row_len * src._height ); + + rbuf_tmp.Construct; + + if m_flip_y then + rbuf_tmp.attach( + buf_tmp , + src._width, + src._height , + -row_len ) + else + rbuf_tmp.attach( + buf_tmp , + src._width, + src._height , + row_len ); + + case m_sys_format of + pix_format_rgb555 : + case m_format of + pix_format_rgb555 : color_conv(@rbuf_tmp ,src ,color_conv_rgb555_to_rgb555 ); + pix_format_rgb565 : color_conv(@rbuf_tmp ,src ,color_conv_rgb565_to_rgb555 ); + //pix_format_rgb24 : color_conv(@rbuf_tmp ,src ,color_conv_rgb24_to_rgb555 ); + pix_format_bgr24 : color_conv(@rbuf_tmp ,src ,color_conv_bgr24_to_rgb555 ); + //pix_format_rgba32 : color_conv(@rbuf_tmp ,src ,color_conv_rgba32_to_rgb555 ); + //pix_format_argb32 : color_conv(@rbuf_tmp ,src ,color_conv_argb32_to_rgb555 ); + pix_format_bgra32 : color_conv(@rbuf_tmp ,src ,color_conv_bgra32_to_rgb555 ); + //pix_format_abgr32 : color_conv(@rbuf_tmp ,src ,color_conv_abgr32_to_rgb555 ); + + end; + + pix_format_rgb565 : + case m_format of + pix_format_rgb555 : color_conv(@rbuf_tmp ,src ,color_conv_rgb555_to_rgb565 ); + //pix_format_rgb565 : color_conv(@rbuf_tmp ,src ,color_conv_rgb565_to_rgb565 ); + //pix_format_rgb24 : color_conv(@rbuf_tmp ,src ,color_conv_rgb24_to_rgb565 ); + pix_format_bgr24 : color_conv(@rbuf_tmp ,src ,color_conv_bgr24_to_rgb565 ); + //pix_format_rgba32 : color_conv(@rbuf_tmp ,src ,color_conv_rgba32_to_rgb565 ); + //pix_format_argb32 : color_conv(@rbuf_tmp ,src ,color_conv_argb32_to_rgb565 ); + pix_format_bgra32 : color_conv(@rbuf_tmp ,src ,color_conv_bgra32_to_rgb565 ); + //pix_format_abgr32 : color_conv(@rbuf_tmp ,src ,color_conv_abgr32_to_rgb565 ); + + end; + + pix_format_rgba32 : + case m_format of + pix_format_rgb555 : color_conv(@rbuf_tmp ,src ,color_conv_rgb555_to_rgba32 ); + //pix_format_rgb565 : color_conv(@rbuf_tmp ,src ,color_conv_rgb565_to_rgba32 ); + //pix_format_rgb24 : color_conv(@rbuf_tmp ,src ,color_conv_rgb24_to_rgba32 ); + pix_format_bgr24 : color_conv(@rbuf_tmp ,src ,color_conv_bgr24_to_rgba32 ); + //pix_format_rgba32 : color_conv(@rbuf_tmp ,src ,color_conv_rgba32_to_rgba32 ); + //pix_format_argb32 : color_conv(@rbuf_tmp ,src ,color_conv_argb32_to_rgba32 ); + pix_format_bgra32 : color_conv(@rbuf_tmp ,src ,color_conv_bgra32_to_rgba32 ); + //pix_format_abgr32 : color_conv(@rbuf_tmp ,src ,color_conv_abgr32_to_rgba32 ); + + end; + + pix_format_abgr32 : + case m_format of + pix_format_rgb555 : color_conv(@rbuf_tmp ,src ,color_conv_rgb555_to_abgr32 ); + //pix_format_rgb565 : color_conv(@rbuf_tmp ,src ,color_conv_rgb565_to_abgr32 ); + //pix_format_rgb24 : color_conv(@rbuf_tmp ,src ,color_conv_rgb24_to_abgr32 ); + pix_format_bgr24 : color_conv(@rbuf_tmp ,src ,color_conv_bgr24_to_abgr32 ); + //pix_format_abgr32 : color_conv(@rbuf_tmp ,src ,color_conv_abgr32_to_abgr32 ); + //pix_format_rgba32 : color_conv(@rbuf_tmp ,src ,color_conv_rgba32_to_abgr32 ); + //pix_format_argb32 : color_conv(@rbuf_tmp ,src ,color_conv_argb32_to_abgr32 ); + pix_format_bgra32 : color_conv(@rbuf_tmp ,src ,color_conv_bgra32_to_abgr32 ); + + end; + + pix_format_argb32 : + case m_format of + pix_format_rgb555 : color_conv(@rbuf_tmp ,src ,color_conv_rgb555_to_argb32 ); + //pix_format_rgb565 : color_conv(@rbuf_tmp ,src ,color_conv_rgb565_to_argb32 ); + //pix_format_rgb24 : color_conv(@rbuf_tmp ,src ,color_conv_rgb24_to_argb32 ); + pix_format_bgr24 : color_conv(@rbuf_tmp ,src ,color_conv_bgr24_to_argb32 ); + pix_format_rgba32 : color_conv(@rbuf_tmp ,src ,color_conv_rgba32_to_argb32 ); + //pix_format_argb32 : color_conv(@rbuf_tmp ,src ,color_conv_argb32_to_argb32 ); + pix_format_abgr32 : color_conv(@rbuf_tmp ,src ,color_conv_abgr32_to_argb32 ); + pix_format_bgra32 : color_conv(@rbuf_tmp ,src ,color_conv_bgra32_to_argb32 ); + + end; + + pix_format_bgra32 : + case m_format of + pix_format_rgb555 : color_conv(@rbuf_tmp ,src ,color_conv_rgb555_to_bgra32 ); + //pix_format_rgb565 : color_conv(@rbuf_tmp ,src ,color_conv_rgb565_to_bgra32 ); + //pix_format_rgb24 : color_conv(@rbuf_tmp ,src ,color_conv_rgb24_to_bgra32 ); + pix_format_bgr24 : color_conv(@rbuf_tmp ,src ,color_conv_bgr24_to_bgra32 ); + pix_format_rgba32 : color_conv(@rbuf_tmp ,src ,color_conv_rgba32_to_bgra32 ); + pix_format_argb32 : color_conv(@rbuf_tmp ,src ,color_conv_argb32_to_bgra32 ); + pix_format_abgr32 : color_conv(@rbuf_tmp ,src ,color_conv_abgr32_to_bgra32 ); + pix_format_bgra32 : color_conv(@rbuf_tmp ,src ,color_conv_bgra32_to_bgra32 ); + + end; + + end; + + m_ximg_window.data:=buf_tmp; + + XPutImage( + m_display , + m_window , + m_gc , + m_ximg_window , + 0 ,0 ,0 ,0 , + src._width , + src._height ); + + agg_freemem(buf_tmp ,row_len * src._height ); + + rbuf_tmp.Destruct; + + end; + +end; + +{ CONSTRUCT } +constructor platform_support.Construct; +var + i : unsigned; + + p ,n ,x : shortstring; + +begin + new(m_specific ,Construct(format_ ,flip_y_ ) ); + + m_ctrls.Construct; + m_rbuf_window.Construct; + + for i:=0 to max_images - 1 do + m_rbuf_img[i ].Construct; + + m_resize_mtx.Construct; + + m_format:=format_; + + m_bpp:=m_specific.m_bpp; + + m_window_flags:=0; + m_wait_mode :=true; + m_flip_y :=flip_y_; + + m_initial_width :=10; + m_initial_height:=10; + + m_caption:='Anti-Grain Geometry Application'#0; + +// Change working dir to the application one + spread_name(ParamStr(0 ) ,p ,n ,x ); + + p:=p + #0; + + SetCurrentDir(p); + // libc.__chdir(PChar(@p[1 ] ) ); + +end; + +{ DESTRUCT } +destructor platform_support.Destruct; +var + i : unsigned; + +begin + dispose(m_specific ,Destruct ); + + m_ctrls.Destruct; + m_rbuf_window.Destruct; + + for i:=0 to max_images - 1 do + m_rbuf_img[i ].Destruct; + +end; + +{ CAPTION_ } +procedure platform_support.caption_; +begin + m_caption:=cap + #0; + + dec(byte(m_caption[0 ] ) ); + + if m_specific.m_initialized then + m_specific.caption_(PChar(@m_caption[1 ] ) ); + +end; + +{ isdigit } +function isdigit(c : char ) : boolean; +begin + case c of + '0'..'9' : + result:=true; + + else + result:=false; + + end; + +end; + +{ atoi } +function atoi(c : char_ptr ) : int; +var + s : shortstring; + e : int; + +begin + s:=''; + + repeat + case c^ of + '0'..'9' : + s:=s + c^; + + else + break; + + end; + + inc(ptrcomp(c ) ); + + until false; + + val(s ,result ,e ); + +end; + +{ LOAD_IMG } +function platform_support.load_img; +var + fd : file; + buf : array[0..1023 ] of char; + len : int; + ptr : char_ptr; + ret : boolean; + + width ,height : unsigned; + + buf_img : pointer; + rbuf_img_ : rendering_buffer; + +begin + result:=false; + + if idx < max_images then + begin + file_:=file_ + _img_ext; + + if not file_exists(file_ ) then + file_:='ppm/' + file_; + + AssignFile(fd ,file_ ); + reset (fd ,1 ); + + if IOResult <> 0 then + exit; + + blockread(fd ,buf ,1022 ,len ); + + if len = 0 then + begin + close(fd ); + exit; + + end; + + buf[len ]:=#0; + + if (buf[0 ] <> 'P' ) and + (buf[1 ] <> '6' ) then + begin + close(fd ); + exit; + + end; + + ptr:=@buf[2 ]; + + while (ptr^ <> #0 ) and + not isdigit(ptr^ ) do + inc(ptrcomp(ptr ) ); + + if ptr^ = #0 then + begin + close(fd ); + exit; + + end; + + width:=atoi(ptr ); + + if (width = 0 ) or + (width > 4096 ) then + begin + close(fd ); + exit; + + end; + + while (ptr^ <> #0 ) and + isdigit(ptr^ ) do + inc(ptrcomp(ptr ) ); + + while (ptr^ <> #0 ) and + not isdigit(ptr^ ) do + inc(ptrcomp(ptr ) ); + + if ptr^ = #0 then + begin + close(fd ); + exit; + + end; + + height:=atoi(ptr ); + + if (height = 0 ) or + (height > 4096 ) then + begin + close(fd ); + exit; + + end; + + while (ptr^ <> #0 ) and + isdigit(ptr^ ) do + inc(ptrcomp(ptr ) ); + + while (ptr^ <> #0 ) and + not isdigit(ptr^ ) do + inc(ptrcomp(ptr ) ); + + if atoi(ptr ) <> 255 then + begin + close(fd ); + exit; + + end; + + while (ptr^ <> #0 ) and + isdigit(ptr^ ) do + inc(ptrcomp(ptr ) ); + + if ptr^ = #0 then + begin + close(fd ); + exit; + + end; + + inc (ptrcomp(ptr ) ); + seek (fd ,ptrcomp(ptr ) - ptrcomp(@buf ) ); + create_img(idx ,width ,height ); + + ret:=true; + + if m_format = pix_format_rgb24 then + blockread(fd ,m_specific.m_buf_img[idx ]^ ,width * height * 3 ) + else + begin + agg_getmem(buf_img ,width * height * 3 ); + + rbuf_img_.Construct; + + if m_flip_y then + rbuf_img_.attach(buf_img ,width ,height ,-width * 3 ) + else + rbuf_img_.attach(buf_img ,width ,height ,width * 3 ); + + blockread(fd ,buf_img^ ,width * height * 3 ); + + case m_format of + //pix_format_rgb555 : color_conv(@m_rbuf_img[idx ] ,@rbuf_img_ ,color_conv_rgb24_to_rgb555 ); + //pix_format_rgb565 : color_conv(@m_rbuf_img[idx ] ,@rbuf_img_ ,color_conv_rgb24_to_rgb565 ); + pix_format_bgr24 : color_conv(@m_rbuf_img[idx ] ,@rbuf_img_ ,color_conv_rgb24_to_bgr24 ); + //pix_format_rgba32 : color_conv(@m_rbuf_img[idx ] ,@rbuf_img_ ,color_conv_rgb24_to_rgba32 ); + //pix_format_argb32 : color_conv(@m_rbuf_img[idx ] ,@rbuf_img_ ,color_conv_rgb24_to_argb32 ); + pix_format_bgra32 : color_conv(@m_rbuf_img[idx ] ,@rbuf_img_ ,color_conv_rgb24_to_bgra32 ); + //pix_format_abgr32 : color_conv(@m_rbuf_img[idx ] ,@rbuf_img_ ,color_conv_rgb24_to_abgr32 ); + else + ret:=false; + + end; + + agg_freemem(buf_img ,width * height * 3 ); + + rbuf_img_.Destruct; + + end; + + close(fd ); + + result:=ret; + + end; + +end; + +{ SAVE_IMG } +function platform_support.save_img; +var + fd : file; + + s ,c : shortstring; + + w ,h ,y : unsigned; + + tmp_buf ,src : pointer; + +begin + result:=false; + + if (idx < max_images ) and + (rbuf_img(idx )._buf <> NIL ) then + begin + AssignFile(fd ,file_ ); + rewrite (fd ,1 ); + + if IOResult <> 0 then + exit; + + w:=rbuf_img(idx )._width; + h:=rbuf_img(idx )._height; + + str(w ,c ); + + s:='P6'#13 + c + ' '; + + str(h ,c ); + + s:=s + c + #13'255'#13; + + blockwrite(fd ,s[1 ] ,length(s ) ); + + agg_getmem(tmp_buf ,w * 3 ); + + y:=0; + + while y < rbuf_img(idx )._height do + begin + if m_flip_y then + src:=rbuf_img(idx ).row(h - 1 - y ) + else + src:=rbuf_img(idx ).row(y ); + + case m_format of + pix_format_rgb555 : color_conv_rgb555_to_rgb24(tmp_buf ,src ,w ); + //pix_format_rgb565 : color_conv_rgb565_to_rgb24(tmp_buf ,src ,w ); + pix_format_bgr24 : color_conv_bgr24_to_rgb24 (tmp_buf ,src ,w ); + //pix_format_rgb24 : color_conv_rgb24_to_rgb24 (tmp_buf ,src ,w ); + //pix_format_rgba32 : color_conv_rgba32_to_rgb24(tmp_buf ,src ,w ); + //pix_format_argb32 : color_conv_argb32_to_rgb24(tmp_buf ,src ,w ); + pix_format_bgra32 : color_conv_bgra32_to_rgb24(tmp_buf ,src ,w ); + //pix_format_abgr32 : color_conv_abgr32_to_rgb24(tmp_buf ,src ,w ); + + end; + + blockwrite(fd ,tmp_buf^ ,w * 3 ); + inc (y ); + + end; + + agg_getmem(tmp_buf ,w * 3 ); + close (fd ); + + result:=true; + + end; + +end; + +{ CREATE_IMG } +function platform_support.create_img; +begin + result:=false; + + if idx < max_images then + begin + if width_ = 0 then + width_:=trunc(rbuf_window._width ); + + if height_ = 0 then + height_:=trunc(rbuf_window._height ); + + agg_freemem(m_specific.m_buf_img[idx ] ,m_specific.m_img_alloc[idx ] ); + + m_specific.m_img_alloc[idx ]:=width_ * height_ * (m_bpp div 8 ); + + agg_getmem(m_specific.m_buf_img[idx ] ,m_specific.m_img_alloc[idx ] ); + + if m_flip_y then + m_rbuf_img[idx ].attach( + m_specific.m_buf_img[idx ] , + width_ ,height_ , + -width_ * (m_bpp div 8 ) ) + else + m_rbuf_img[idx ].attach( + m_specific.m_buf_img[idx ] , + width_ ,height_ , + width_ * (m_bpp div 8 ) ); + + result:=true; + + end; + +end; + +{ INIT } +function platform_support.init; +const + xevent_mask = + PointerMotionMask or + ButtonPressMask or + ButtonReleaseMask or + ExposureMask or + KeyPressMask or + StructureNotifyMask; + +var + r_mask ,g_mask ,b_mask ,window_mask : unsigned; + + t ,hw_byte_order : int; + + hints : PXSizeHints; + +begin + m_window_flags:=flags; + + m_specific.m_display:=XOpenDisplay(NIL ); + + if m_specific.m_display = NIL then + begin + writeln(stderr ,'Unable to open DISPLAY!' ); + + result:=false; + + exit; + + end; + + m_specific.m_screen:=XDefaultScreen(m_specific.m_display ); + m_specific.m_depth :=XDefaultDepth (m_specific.m_display ,m_specific.m_screen ); + m_specific.m_visual:=XDefaultVisual(m_specific.m_display ,m_specific.m_screen ); + + r_mask:=m_specific.m_visual.red_mask; + g_mask:=m_specific.m_visual.green_mask; + b_mask:=m_specific.m_visual.blue_mask; + + if (m_specific.m_depth < 15 ) or + (r_mask = 0 ) or + (g_mask = 0 ) or + (b_mask = 0 ) then + begin + writeln(stderr ,'There''s no Visual compatible with minimal AGG requirements:' ); + writeln(stderr ,'At least 15-bit color depth and True- or DirectColor class.' ); + writeln(stderr ); + + XCloseDisplay(m_specific.m_display ); + + result:=false; + + exit; + + end; + + t:=1; + + hw_byte_order:=LSBFirst; + + if byte(pointer(@t )^ ) = 0 then + hw_byte_order:=MSBFirst; + +// Perceive SYS-format by mask + case m_specific.m_depth of + 15 : + begin + m_specific.m_sys_bpp:=16; + + if (r_mask = $7C00 ) and + (g_mask = $3E0 ) and + (b_mask = $1F ) then + begin + m_specific.m_sys_format:=pix_format_rgb555; + m_specific.m_byte_order:=hw_byte_order; + + end; + + end; + + 16 : + begin + m_specific.m_sys_bpp:=16; + + if (r_mask = $F800 ) and + (g_mask = $7E0 ) and + (b_mask = $1F ) then + begin + m_specific.m_sys_format:=pix_format_rgb565; + m_specific.m_byte_order:=hw_byte_order; + + end; + + end; + + 24 ,32 : + begin + m_specific.m_sys_bpp:=32; + + if g_mask = $FF00 then + begin + if (r_mask = $FF ) and + (b_mask = $FF0000 ) then + case m_specific.m_format of + pix_format_rgba32 : + begin + m_specific.m_sys_format:=pix_format_rgba32; + m_specific.m_byte_order:=LSBFirst; + + end; + + pix_format_abgr32 : + begin + m_specific.m_sys_format:=pix_format_abgr32; + m_specific.m_byte_order:=MSBFirst; + + end; + + else + begin + m_specific.m_byte_order:=hw_byte_order; + + if hw_byte_order = LSBFirst then + m_specific.m_sys_format:=pix_format_rgba32 + else + m_specific.m_sys_format:=pix_format_abgr32; + + end; + + end; + + if (r_mask = $FF0000 ) and + (b_mask = $FF ) then + case m_specific.m_format of + pix_format_argb32 : + begin + m_specific.m_sys_format:=pix_format_argb32; + m_specific.m_byte_order:=MSBFirst; + + end; + + pix_format_bgra32 : + begin + m_specific.m_sys_format:=pix_format_bgra32; + m_specific.m_byte_order:=LSBFirst; + + end; + + else + begin + m_specific.m_byte_order:=hw_byte_order; + + if hw_byte_order = MSBFirst then + m_specific.m_sys_format:=pix_format_argb32 + else + m_specific.m_sys_format:=pix_format_bgra32; + + end; + + end; + + end; + + end; + + end; + + if m_specific.m_sys_format = pix_format_undefined then + begin + writeln(stderr ,'RGB masks are not compatible with AGG pixel formats:' ); + write (stderr ,'R=' ,r_mask ,'G=' ,g_mask ,'B=' ,b_mask ); + + XCloseDisplay(m_specific.m_display ); + + result:=false; + + exit; + + end; + + fillchar( + m_specific.m_window_attributes , + sizeof(m_specific.m_window_attributes ) ,0 ); + + m_specific.m_window_attributes.border_pixel:= + XBlackPixel(m_specific.m_display ,m_specific.m_screen ); + + m_specific.m_window_attributes.background_pixel:= + XWhitePixel(m_specific.m_display ,m_specific.m_screen ); + + m_specific.m_window_attributes.override_redirect:=xfalse; + + window_mask:=CWBackPixel or CWBorderPixel; + + m_specific.m_window:= + XCreateWindow( + m_specific.m_display , + XDefaultRootWindow(m_specific.m_display ) , + 0 ,0 , + width_ ,height_ , + 0 , + m_specific.m_depth , + InputOutput , + CopyFromParent , + window_mask , + @m_specific.m_window_attributes ); + + m_specific.m_gc:=XCreateGC(m_specific.m_display ,m_specific.m_window ,0 ,0 ); + + m_specific.m_buf_alloc:=width_ * height_ * (m_bpp div 8 ); + + agg_getmem(m_specific.m_buf_window ,m_specific.m_buf_alloc ); + fillchar (m_specific.m_buf_window^ ,m_specific.m_buf_alloc ,255 ); + + if m_flip_y then + m_rbuf_window.attach( + m_specific.m_buf_window , + width_ ,height_ , + -width_ * (m_bpp div 8 ) ) + else + m_rbuf_window.attach( + m_specific.m_buf_window , + width_ ,height_ , + width_ * (m_bpp div 8 ) ); + + m_specific.m_ximg_window:= + XCreateImage( + m_specific.m_display , + m_specific.m_visual , //CopyFromParent, + m_specific.m_depth , + ZPixmap , + 0 , + m_specific.m_buf_window , + width_ ,height_ , + m_specific.m_sys_bpp , + width_ * (m_specific.m_sys_bpp div 8 ) ); + + m_specific.m_ximg_window.byte_order:=m_specific.m_byte_order; + + m_specific.caption_(PChar(@m_caption[1 ] ) ); + + m_initial_width :=width_; + m_initial_height:=height_; + + if not m_specific.m_initialized then + begin + on_init; + + m_specific.m_initialized:=true; + + end; + + trans_affine_resizing_(width_ ,height_ ); + + on_resize(width_ ,height_ ); + + m_specific.m_update_flag:=true; + + hints:=XAllocSizeHints; + + if hints <> NIL then + begin + if flags and window_resize <> 0 then + begin + hints.min_width :=32; + hints.min_height:=32; + hints.max_width :=4096; + hints.max_height:=4096; + + end + else + begin + hints.min_width :=width_; + hints.min_height:=height_; + hints.max_width :=width_; + hints.max_height:=height_; + + end; + + hints.flags:=PMaxSize or PMinSize; + + XSetWMNormalHints(m_specific.m_display ,m_specific.m_window ,hints ); + XFree (hints ); + + end; + + XMapWindow (m_specific.m_display ,m_specific.m_window ); + XSelectInput(m_specific.m_display ,m_specific.m_window ,xevent_mask ); + + m_specific.m_close_atom:= + XInternAtom(m_specific.m_display ,'WM_DELETE_WINDOW' ,false ); + + XSetWMProtocols( + m_specific.m_display , + m_specific.m_window , + @m_specific.m_close_atom ,1 ); + + result:=true; + +end; + +{ RUN } +function platform_support.run; +var + flags ,i : unsigned; + + cur_x ,cur_y ,width ,height : int; + + x_event ,te : TXEvent; + + key : TKeySym; + + left ,up ,right ,down : boolean; + +begin + XFlush(m_specific.m_display ); + + m_quit:=false; + + while not m_quit do + begin + if m_specific.m_update_flag then + begin + on_draw; + update_window; + + m_specific.m_update_flag:=false; + + end; + + if not m_wait_mode then + if XPending(m_specific.m_display ) = 0 then + begin + on_idle; + continue; + + end; + + XNextEvent(m_specific.m_display ,@x_event ); + + // In the Idle mode discard all intermediate MotionNotify events + if not m_wait_mode and + (x_event._type = MotionNotify ) then + begin + te:=x_event; + + repeat + if XPending(m_specific.m_display ) = 0 then + break; + + XNextEvent(m_specific.m_display ,@te ); + + if te._type <> MotionNotify then + break; + + until false; + + x_event:=te; + + end; + + case x_event._type of + ConfigureNotify : + if (x_event.xconfigure.width <> trunc(m_rbuf_window._width ) ) or + (x_event.xconfigure.height <> trunc(m_rbuf_window._height ) ) then + begin + width :=x_event.xconfigure.width; + height:=x_event.xconfigure.height; + + agg_freemem(m_specific.m_buf_window ,m_specific.m_buf_alloc ); + + m_specific.m_ximg_window.data:=0; + + XDestroyImage(m_specific.m_ximg_window ); + + m_specific.m_buf_alloc:=width * height * (m_bpp div 8 ); + + agg_getmem(m_specific.m_buf_window ,m_specific.m_buf_alloc ); + + if m_flip_y then + m_rbuf_window.attach( + m_specific.m_buf_window , + width ,height , + -width * (m_bpp div 8 ) ) + else + m_rbuf_window.attach( + m_specific.m_buf_window , + width ,height , + width * (m_bpp div 8 ) ); + + m_specific.m_ximg_window:= + XCreateImage(m_specific.m_display , + m_specific.m_visual , //CopyFromParent, + m_specific.m_depth , + ZPixmap , + 0 , + m_specific.m_buf_window , + width ,height , + m_specific.m_sys_bpp , + width * (m_specific.m_sys_bpp div 8 ) ); + + m_specific.m_ximg_window.byte_order:=m_specific.m_byte_order; + + trans_affine_resizing_(width ,height ); + + on_resize(width ,height ); + on_draw; + update_window; + + end; + + Expose : + begin + m_specific.put_image(@m_rbuf_window ); + + XFlush(m_specific.m_display ); + XSync (m_specific.m_display ,false ); + + end; + + KeyPress : + begin + key :=XLookupKeysym(@x_event.xkey ,0 ); + flags:=0; + + if x_event.xkey.state and Button1Mask <> 0 then + flags:=flags or mouse_left; + + if x_event.xkey.state and Button3Mask <> 0 then + flags:=flags or mouse_right; + + if x_event.xkey.state and ShiftMask <> 0 then + flags:=flags or kbd_shift; + + if x_event.xkey.state and ControlMask <> 0 then + flags:=flags or kbd_ctrl; + + left :=false; + up :=false; + right:=false; + down :=false; + + case m_specific.m_keymap[key and $FF ] of + key_left : left :=true; + key_up : up :=true; + key_right : right:=true; + key_down : down :=true; + + key_f2 : + begin + copy_window_to_img(max_images - 1 ); + save_img (max_images - 1 ,'screenshot.ppm' ); + + end; + + end; + + if m_ctrls.on_arrow_keys(left ,right ,down ,up ) then + begin + on_ctrl_change; + force_redraw; + + end + else + if m_flip_y then + on_key( + x_event.xkey.x , + trunc(m_rbuf_window._height ) - x_event.xkey.y , + m_specific.m_keymap[key and $FF ] ,flags ) + else + on_key( + x_event.xkey.x , + x_event.xkey.y , + m_specific.m_keymap[key and $FF ] ,flags ) + + end; + + ButtonPress : + begin + flags:=0; + + if x_event.xbutton.state and ShiftMask <> 0 then + flags:=flags or kbd_shift; + + if x_event.xbutton.state and ControlMask <> 0 then + flags:=flags or kbd_ctrl; + + if x_event.xbutton.button = Button1 then + flags:=flags or mouse_left; + + if x_event.xbutton.button = Button3 then + flags:=flags or mouse_right; + + cur_x:=x_event.xbutton.x; + + if m_flip_y then + cur_y:=trunc(m_rbuf_window._height ) - x_event.xbutton.y + else + cur_y:=x_event.xbutton.y; + + if flags and mouse_left <> 0 then + if m_ctrls.on_mouse_button_down(cur_x ,cur_y ) then + begin + m_ctrls.set_cur(cur_x ,cur_y ); + on_ctrl_change; + force_redraw; + + end + else + if m_ctrls.in_rect(cur_x ,cur_y ) then + if m_ctrls.set_cur(cur_x ,cur_y ) then + begin + on_ctrl_change; + force_redraw; + + end + else + else + on_mouse_button_down(cur_x ,cur_y ,flags ); + + if flags and mouse_right <> 0 then + on_mouse_button_down(cur_x ,cur_y ,flags ); + + //m_specific.m_wait_mode:=m_wait_mode; + //m_wait_mode :=true; + + end; + + MotionNotify : + begin + flags:=0; + + if x_event.xmotion.state and Button1Mask <> 0 then + flags:=flags or mouse_left; + + if x_event.xmotion.state and Button3Mask <> 0 then + flags:=flags or mouse_right; + + if x_event.xmotion.state and ShiftMask <> 0 then + flags:=flags or kbd_shift; + + if x_event.xmotion.state and ControlMask <> 0 then + flags:=flags or kbd_ctrl; + + cur_x:=x_event.xbutton.x; + + if m_flip_y then + cur_y:=trunc(m_rbuf_window._height ) - x_event.xbutton.y + else + cur_y:=x_event.xbutton.y; + + if m_ctrls.on_mouse_move(cur_x ,cur_y ,flags and mouse_left <> 0 ) then + begin + on_ctrl_change; + force_redraw; + + end + else + if not m_ctrls.in_rect(cur_x ,cur_y ) then + on_mouse_move(cur_x ,cur_y ,flags ); + + end; + + ButtonRelease : + begin + flags:=0; + + if x_event.xbutton.state and ShiftMask <> 0 then + flags:=flags or kbd_shift; + + if x_event.xbutton.state and ControlMask <> 0 then + flags:=flags or kbd_ctrl; + + if x_event.xbutton.button = Button1 then + flags:=flags or mouse_left; + + if x_event.xbutton.button = Button3 then + flags:=flags or mouse_right; + + cur_x:=x_event.xbutton.x; + + if m_flip_y then + cur_y:=trunc(m_rbuf_window._height ) - x_event.xbutton.y + else + cur_y:=x_event.xbutton.y; + + if flags and mouse_left <> 0 then + if m_ctrls.on_mouse_button_up(cur_x ,cur_y ) then + begin + on_ctrl_change; + force_redraw; + + end; + + if flags and (mouse_left or mouse_right ) <> 0 then + on_mouse_button_up(cur_x ,cur_y ,flags ); + + //m_wait_mode:=m_specific.m_wait_mode; + + end; + + ClientMessage : + if (x_event.xclient.format = 32 ) and + (x_event.xclient.data.l[0 ] = int(m_specific.m_close_atom ) ) then + m_quit:=true; + + end; + + end; + + i:=max_images; + + while i <> 0 do + begin + dec(i ); + + if m_specific.m_buf_img[i ] <> NIL then + agg_freemem(m_specific.m_buf_img[i ] ,m_specific.m_img_alloc[i ] ); + + end; + + agg_freemem(m_specific.m_buf_window ,m_specific.m_buf_alloc ); + + m_specific.m_ximg_window.data:=NIL; + + XDestroyImage (m_specific.m_ximg_window ); + XFreeGC (m_specific.m_display ,m_specific.m_gc ); + XDestroyWindow(m_specific.m_display ,m_specific.m_window ); + XCloseDisplay (m_specific.m_display ); + + result:=0; + +end; + +{ QUIT } +procedure platform_support.quit; +begin + m_quit:=true; + +end; + +{ _FORMAT } +function platform_support._format; +begin + result:=m_format; + +end; + +{ _FLIP_Y } +function platform_support._flip_y; +begin + result:=m_flip_y; + +end; + +{ _BPP } +function platform_support._bpp; +begin + result:=m_bpp; + +end; + +{ _WAIT_MODE } +function platform_support._wait_mode; +begin + result:=m_wait_mode; + +end; + +{ WAIT_MODE_ } +procedure platform_support.wait_mode_; +begin + m_wait_mode:=wait_mode; + +end; + +{ FORCE_REDRAW } +procedure platform_support.force_redraw; +begin + m_specific.m_update_flag:=true; + +end; + +{ UPDATE_WINDOW } +procedure platform_support.update_window; +begin + m_specific.put_image(@m_rbuf_window ); + +// When m_wait_mode is true we can discard all the events +// came while the image is being drawn. In this case +// the X server does not accumulate mouse motion events. +// When m_wait_mode is false, i.e. we have some idle drawing +// we cannot afford to miss any events + XSync(m_specific.m_display ,m_wait_mode ); + +end; + +{ RBUF_WINDOW } +function platform_support.rbuf_window; +begin + result:=@m_rbuf_window; + +end; + +{ RBUF_IMG } +function platform_support.rbuf_img; +begin + result:=@m_rbuf_img[idx ]; + +end; + +{ _IMG_EXT } +function platform_support._img_ext; +begin + result:='.ppm'; + +end; + +{ COPY_IMG_TO_WINDOW } +procedure platform_support.copy_img_to_window; +begin + if (idx < max_images ) and + (rbuf_img(idx )._buf <> NIL ) then + rbuf_window.copy_from(rbuf_img(idx ) ); + +end; + +{ COPY_WINDOW_TO_IMG } +procedure platform_support.copy_window_to_img; +begin + if idx < max_images then + begin + create_img(idx ,rbuf_window._width ,rbuf_window._height ); + rbuf_img (idx ).copy_from(rbuf_window ); + + end; + +end; + +{ COPY_IMG_TO_IMG } +procedure platform_support.copy_img_to_img; +begin + if (idx_from < max_images ) and + (idx_to < max_images ) and + (rbuf_img(idx_from )._buf <> NIL ) then + begin + create_img( + idx_to , + rbuf_img(idx_from )._width , + rbuf_img(idx_from )._height ); + + rbuf_img(idx_to ).copy_from(rbuf_img(idx_from ) ); + + end; + +end; + +{ ON_INIT } +procedure platform_support.on_init; +begin +end; + +{ ON_RESIZE } +procedure platform_support.on_resize; +begin +end; + +{ ON_IDLE } +procedure platform_support.on_idle; +begin +end; + +{ ON_MOUSE_MOVE } +procedure platform_support.on_mouse_move; +begin +end; + +{ ON_MOUSE_BUTTON_DOWN } +procedure platform_support.on_mouse_button_down; +begin +end; + +{ ON_MOUSE_BUTTON_UP } +procedure platform_support.on_mouse_button_up; +begin +end; + +{ ON_KEY } +procedure platform_support.on_key; +begin +end; + +{ ON_CTRL_CHANGE } +procedure platform_support.on_ctrl_change; +begin +end; + +{ ON_DRAW } +procedure platform_support.on_draw; +begin +end; + +{ ON_POST_DRAW } +procedure platform_support.on_post_draw; +begin +end; + +{ ADD_CTRL } +procedure platform_support.add_ctrl; +begin + m_ctrls.add(c ); + + c.transform(@m_resize_mtx ); + +end; + +{ TRANS_AFFINE_RESIZING_ } +procedure platform_support.trans_affine_resizing_; +var + vp : trans_viewport; + ts : trans_affine_scaling; + +begin + if m_window_flags and window_keep_aspect_ratio <> 0 then + begin + vp.Construct; + vp.preserve_aspect_ratio(0.5 ,0.5 ,aspect_ratio_meet ); + + vp.device_viewport(0 ,0 ,width_ ,height_ ); + vp.world_viewport (0 ,0 ,m_initial_width ,m_initial_height ); + + vp.to_affine(@m_resize_mtx ); + + end + else + begin + ts.Construct( + width_ / m_initial_width , + height_ / m_initial_height ); + + m_resize_mtx.assign(@ts ); + + end; + +end; + +{ _TRANS_AFFINE_RESIZING } +function platform_support._trans_affine_resizing; +begin + result:=@m_resize_mtx; + +end; + +{ _WIDTH } +function platform_support._width; +begin + result:=m_rbuf_window._width; + +end; + +{ _HEIGHT } +function platform_support._height; +begin + result:=m_rbuf_window._height; + +end; + +{ _INITIAL_WIDTH } +function platform_support._initial_width; +begin + result:=m_initial_width; + +end; + +{ _INITIAL_HEIGHT } +function platform_support._initial_height; +begin + result:=m_initial_height; + +end; + +{ _WINDOW_FLAGS } +function platform_support._window_flags; +begin + result:=m_window_flags; + +end; + +{ _RAW_DISPLAY_HANDLER } +function platform_support._raw_display_handler; +begin +end; + +{ MESSAGE_ } +procedure platform_support.message_; +const + x_event_mask = + ExposureMask or + KeyPressMask; + + capt = ' PRESS ANY KEY TO CONTINUE THE AGGPAS DEMO ...'; + plus = 4; + +var + x_display : PDisplay; + x_window : TWindow; + x_event : TXEvent; + x_close : TAtom; + x_changes : TXWindowChanges; + x_hints : PXSizeHints; + + x_gc : TGC; + x_tp : TXTextProperty; + x_tx : TXTextItem; + + str ,cur : char_ptr; + + y ,len ,cnt ,max ,x_dx ,x_dy : unsigned; + + font_dir ,font_ascent ,font_descent : int; + + font_str : TXCharStruct; + +procedure draw_text; +begin + x_dx:=0; + x_dy:=0; + + y :=20; + cur:=PChar(@msg[0 ] ); + max:=strlen(msg ); + len:=0; + cnt:=0; + + while cnt < max do + begin + if len = 0 then + str:=cur; + + case cur^ of + #13 : + begin + XDrawString (x_display ,x_window ,x_gc ,10 ,y ,str ,len ); + XQueryTextExtents( + x_display ,XGContextFromGC(x_gc) , + str ,len , + @font_dir , + @font_ascent , + @font_descent , + @font_str ); + + inc(y ,font_str.ascent + font_str.descent + plus ); + inc(x_dy ,font_str.ascent + font_str.descent + plus ); + + if font_str.width > x_dx then + x_dx:=font_str.width; + + len:=0; + + end; + + else + inc(len ); + + end; + + inc(ptrcomp(cur ) ); + inc(cnt ); + + end; + + if len > 0 then + begin + XDrawString (x_display ,x_window ,x_gc ,10 ,y ,str ,len ); + XQueryTextExtents( + x_display ,XGContextFromGC(x_gc) , + str ,len , + @font_dir , + @font_ascent , + @font_descent , + @font_str ); + + inc(x_dy ,font_str.ascent + font_str.descent + plus ); + + if font_str.width > x_dx then + x_dx:=font_str.width; + + end; + +end; + +begin + x_display:=XOpenDisplay(NIL ); + + if x_display <> NIL then + begin + x_window := + XCreateSimpleWindow( + x_display , + XDefaultRootWindow(x_display ) , + 50 ,50 , + 550 ,300 , + 0 ,0 , + 255 + (255 shl 8 ) + (255 shl 16 ) ); + + x_gc:=XCreateGC(x_display ,x_window ,0 ,0 ); + + draw_text; + XResizeWindow(x_display ,x_window ,x_dx + 20 ,x_dy + 40 ); + + x_hints:=XAllocSizeHints; + + if x_hints <> NIL then + begin + x_hints.min_width :=x_dx + 20; + x_hints.min_height:=x_dy + 40; + x_hints.max_width :=x_dx + 20; + x_hints.max_height:=x_dy + 40; + + x_hints.flags:=PMaxSize or PMinSize; + + XSetWMNormalHints(x_display ,x_window ,x_hints ); + XFree (x_hints ); + + end; + + x_tp.value :=PCUChar(@capt[1 ] ); + x_tp.encoding:=XA_WM_NAME; + x_tp.format :=8; + x_tp.nitems :=strlen(capt ); + + XSetWMName (x_display ,x_window ,@x_tp ); + XStoreName (x_display ,x_window ,capt ); + XSetIconName (x_display ,x_window ,capt ); + XSetWMIconName(x_display ,x_window ,@x_tp ); + + XMapWindow (x_display ,x_window ); + XSelectInput(x_display ,x_window ,x_event_mask ); + + x_close:= + XInternAtom(x_display ,'WM_DELETE_WINDOW' ,false ); + + XSetWMProtocols( + x_display , + x_window , + @x_close ,1 ); + + XFlush(x_display ); + + repeat + XNextEvent(x_display ,@x_event ); + + XFlush(x_display ); + XSync (x_display ,true ); + + case x_event._type of + Expose : + draw_text; + + KeyPress : + break; + + ClientMessage : + if (x_event.xclient.format = 32 ) and + (x_event.xclient.data.l[0 ] = int(x_close ) ) then + break; + + end; + + + until false; + + while XPending(x_display ) > 0 do + begin + XNextEvent(x_display ,@x_event ); + + XFlush(x_display ); + XSync (x_display ,true ); + + end; + + XFreeGC (x_display ,x_gc ); + XDestroyWindow(x_display ,x_window ); + XCloseDisplay (x_display ); + + end + else + writeln(stderr ,msg ); + +end; + +{ START_TIMER } +procedure platform_support.start_timer; +begin + m_specific.m_sw_start:=clock; + +end; + +{ ELAPSED_TIME } +function platform_support.elapsed_time; +var + stop : clock_t; + +begin + stop:=clock; + + result:=(stop - m_specific.m_sw_start ) * 1000.0 / CLOCKS_PER_SEC; + +end; + +{ FULL_FILE_NAME } +function platform_support.full_file_name; +begin + result:=file_name; + +end; + +{ FILE_SOURCE } +function platform_support.file_source; +var + f : file; + e : integer; + +begin + result:=fname; + + e:=ioresult; + + AssignFile(f ,result ); + reset (f ,1 ); + + if ioresult <> 0 then + result:=path + '/' + fname; + + close(f ); + + e:=ioresult; + +end; + +END. + diff --git a/components/aggpas/src/platform/lcl/file_utils_.pas b/components/aggpas/src/platform/lcl/file_utils_.pas new file mode 100644 index 0000000000..1f6391b299 --- /dev/null +++ b/components/aggpas/src/platform/lcl/file_utils_.pas @@ -0,0 +1,776 @@ +// +// AggPas 2.4 RM3 demo framework file utility library +// Milan Marusinec alias Milano (c) 2006 +// +unit + file_utils_ ; + +INTERFACE + +{$I agg_mode.inc } +{$I- } +uses + agg_basics ; + +{ TYPES DEFINITION } +type + api_file_ptr = ^api_file; + api_file = record + fileName : shortstring; + isOpened : boolean; + + fSize , + fRead : int; + + // FSOpenFork parameters + df : file; + + end; + +{ GLOBAL PROCEDURES } + function cut_str(s : shortstring ) : shortstring; + function up_str (s : shortstring ) : shortstring; + function cmp_str(s : shortstring ) : shortstring; + + function str_dir(s : shortstring ) : shortstring; + function dir_str(s : shortstring ) : shortstring; + + function str_disk(fn : shortstring ) : shortstring; + function str_path(fn : shortstring ) : shortstring; + function str_name(fn : shortstring ) : shortstring; + function str_ext (fn : shortstring ) : shortstring; + + function fold_name (p ,n ,x : shortstring ) : shortstring; + procedure spread_name(fn : shortstring; var p ,n ,x : shortstring ); + + function file_exists(fn : shortstring ) : boolean; + + function api_open_file (var af : api_file; fname : shortstring ) : boolean; + function api_read_file (var af : api_file; buff : pointer; aloc : int; var read : int ) : boolean; + function api_close_file(var af : api_file ) : boolean; + + function param_count : int; + function param_str(i : int ) : shortstring; + + +IMPLEMENTATION +{ LOCAL VARIABLES & CONSTANTS } +type + tSCAN = ( + + SCAN_0 , + SCAN_1 ,SCAN_2 ,SCAN_3 ,SCAN_4 ,SCAN_5 ,SCAN_6 ,SCAN_7 ,SCAN_8 ,SCAN_9 , + SCAN_A ,SCAN_B ,SCAN_C ,SCAN_D ,SCAN_E ,SCAN_F ,SCAN_G ,SCAN_H ,SCAN_I , + SCAN_J ,SCAN_K ,SCAN_L ,SCAN_M ,SCAN_N ,SCAN_O ,SCAN_P ,SCAN_Q ,SCAN_R , + SCAN_S ,SCAN_T ,SCAN_U ,SCAN_V ,SCAN_W ,SCAN_X ,SCAN_Y ,SCAN_Z + + ); + + tITEM = ( + + ITEM_0 , + ITEM_1 ,ITEM_2 ,ITEM_3 ,ITEM_4 ,ITEM_5 ,ITEM_6 ,ITEM_7 ,ITEM_8 ,ITEM_9 , + ITEM_A ,ITEM_B ,ITEM_C ,ITEM_D ,ITEM_E ,ITEM_F ,ITEM_G ,ITEM_H ,ITEM_I , + ITEM_J ,ITEM_K ,ITEM_L ,ITEM_M ,ITEM_N ,ITEM_O ,ITEM_P ,ITEM_Q ,ITEM_R , + ITEM_S ,ITEM_T ,ITEM_U ,ITEM_V ,ITEM_W ,ITEM_X ,ITEM_Y ,ITEM_Z + + ); + +const + dir_slash = '/'; + + pageEqHigh : shortstring = + #1#2#3#4#5#6#7#8#9#10#11#12#13#14#15#16 + + #17#18#19#20#21#22#23#24#25#26#27#28#29#30#31#32 + + #33#34#35#36#37#38#39#40#41#42#43#44#45#46#47#48 + + #49#50#51#52#53#54#55#56#57#58#59#60#61#62#63#64 + + #65#66#67#68#69#70#71#72#73#74#75#76#77#78#79#80 + + #81#82#83#84#85#86#87#88#89#90#91#92#93#94#95#96 + + #65#66#67#68#69#70#71#72#73#74#75#76#77#78#79#80 + + #81#82#83#84#85#86#87#88#89#90#123#124#125#126#127#128 + + #129#130#131#132#133#134#135#136#137#138#139#140#141#142#143#144 + + #145#146#147#148#149#150#151#152#153#154#155#156#157#158#159#160 + + #161#162#163#164#165#166#167#168#169#170#171#172#173#174#175#176 + + #177#178#179#180#181#182#183#184#185#186#187#188#189#190#191#192 + + #193#194#195#196#197#198#199#200#201#202#203#204#205#206#207#208 + + #209#210#211#212#213#214#215#216#217#218#219#220#221#222#223#224 + + #225#226#227#228#229#230#231#232#233#234#235#236#237#238#239#240 + + #241#242#243#244#245#246#247#248#249#250#251#252#253#254#255; + +{ UNIT IMPLEMENTATION } +{ CUT_STR } +function cut_str; +var + fcb : byte; + scn : tSCAN; + +begin + result:=''; + + scn:=SCAN_1; + + if length(s ) > 0 then + for fcb:=length(s ) downto 1 do + case scn of + SCAN_1 : + case s[fcb ] of + ' ' : + else + begin + result:=s[fcb ]; + + scn:=SCAN_2; + + end; + + end; + + SCAN_2 : + result:=s[fcb ] + result; + + end; + +end; + +{ CMP_STR } +function cmp_str; +begin + cmp_str:=up_str(cut_str(s ) ); + +end; + +{ UP_STR } +function up_str; +var + fcb : byte; + +begin + if length(s ) > 0 then + for fcb:=1 to length(s ) do + if byte(s[fcb ] ) > 0 then + s[fcb ]:=pageEqHigh[byte(s[fcb ] ) ]; + + result:=s; + +end; + +{ STR_DIR } +function str_dir; +begin + s:=cut_str(s ); + + if length(s ) > 0 then + if s[length(s ) ] <> dir_slash then + s:=s + dir_slash; + + result:=s; + +end; + +{ DIR_STR } +function dir_str; +begin + s:=cut_str(s ); + + if length(s ) > 0 then + if s[length(s ) ] = dir_slash then + dec(byte(s[0 ] ) ); + + result:=s; + +end; + +{ STR_DISK } +function str_disk; +var + fcb : byte; + str : shortstring; + itm : tITEM; + +begin + str:=''; + itm:=ITEM_1; + + if length(fn ) > 0 then + for fcb:=1 to length(fn ) do + case itm of + ITEM_1 : + case fn[fcb ] of + 'a'..'z' ,'A'..'Z' : + begin + str:=fn[fcb ]; + itm:=ITEM_2; + + end; + + '\' ,'/' : + begin + str:=fn[fcb ]; + itm:=ITEM_3; + + end; + + else + break; + + end; + + ITEM_2 : + case fn[fcb ] of + ':' : + begin + str:=str + fn[fcb ]; + itm:=ITEM_F; + + break; + + end; + + else + break; + + end; + + ITEM_3 : + case fn[fcb ] of + '\' ,'/' : + begin + str:=str + fn[fcb ]; + itm:=ITEM_4; + + end; + + else + break; + + end; + + ITEM_4 : + case fn[fcb ] of + '\' ,'/' ,':' ,'<' ,'>' ,'.' ,'"' ,'|' ,#0..#31 : + break; + + else + begin + str:=str + fn[fcb ]; + itm:=ITEM_F; + + end; + + end; + + ITEM_F : + case fn[fcb ] of + '\' ,'/' : + break; + + else + str:=str + fn[fcb ]; + + end; + + end; + + if itm = ITEM_F then + result:=str + else + result:=''; + +end; + +{ STR_PATH } +function str_path; +var + fcb : byte; + pth , + str : shortstring; + itm : tITEM; + +begin + pth:=''; + str:=''; + itm:=ITEM_1; + + if length(fn ) > 0 then + for fcb:=1 to length(fn ) do + case itm of + ITEM_1 : + case fn[fcb ] of + '\' ,'/' : + begin + str:=fn[fcb ]; + itm:=ITEM_2; + + end; + + else + begin + str:=fn[fcb ]; + itm:=ITEM_3; + + end; + + end; + + ITEM_2 : + case fn[fcb ] of + '\' ,'/' : + begin + str:=str + fn[fcb ]; + itm:=ITEM_3; + + end; + + else + begin + pth:=str; + str:=fn[fcb ]; + itm:=ITEM_A; + + end; + + end; + + ITEM_3 : + case fn[fcb ] of + '\' ,'/' : + begin + pth:=fn[fcb ]; + str:=''; + itm:=ITEM_A; + + end; + + else + str:=str + fn[fcb ]; + + end; + + ITEM_A : + case fn[fcb ] of + '\' ,'/' : + begin + pth:=pth + str + fn[fcb ]; + str:=''; + + end; + + else + str:=str + fn[fcb ]; + + end; + + end; + + result:=pth; + +end; + +{ STR_NAME } +function str_name; +var + fcb : byte; + str , + ext : shortstring; + itm : tITEM; + +begin + str:=''; + ext:=''; + itm:=ITEM_1; + + if length(fn ) > 0 then + for fcb:=1 to length(fn ) do + case itm of + ITEM_1 : + case fn[fcb ] of + '\' ,'/' : + itm:=ITEM_2; + + 'a'..'z' ,'A'..'Z' : + begin + ext:=fn[fcb ]; + itm:=ITEM_4; + + end; + + '.' : + begin + str:=''; + ext:=fn[fcb ]; + itm:=ITEM_B; + + end; + + else + begin + str:=fn[fcb ]; + itm:=ITEM_A; + + end; + + end; + + ITEM_2 : + case fn[fcb ] of + '\' ,'/' : + itm:=ITEM_3; + + '.' : + begin + str:=''; + ext:=fn[fcb ]; + itm:=ITEM_B; + + end; + + else + begin + str:=fn[fcb ]; + itm:=ITEM_A; + + end; + + end; + + ITEM_3 : + case fn[fcb ] of + '\' ,'/' : + begin + str:=''; + itm:=ITEM_A; + + end; + + end; + + ITEM_4 : + case fn[fcb ] of + '\' ,'/' : + begin + str:=''; + itm:=ITEM_A; + + end; + + ':' : + itm:=ITEM_5; + + '.' : + begin + str:=ext; + ext:=fn[fcb ]; + itm:=ITEM_B; + + end; + + else + begin + str:=ext + fn[fcb ]; + ext:=''; + itm:=ITEM_A; + + end; + + end; + + ITEM_5 : + case fn[fcb ] of + '\' ,'/' : + begin + str:=''; + itm:=ITEM_A; + + end; + + '.' : + begin + str:=''; + ext:=fn[fcb ]; + itm:=ITEM_B; + + end; + + else + begin + str:=fn[fcb ]; + itm:=ITEM_A; + + end; + + end; + + ITEM_A : + case fn[fcb ] of + '\' ,'/' : + begin + str:=''; + ext:=''; + + end; + + '.' : + begin + ext:=fn[fcb ]; + itm:=ITEM_B; + + end; + + else + str:=str + fn[fcb ]; + + end; + + ITEM_B : + case fn[fcb ] of + '\' ,'/' : + begin + str:=''; + ext:=''; + itm:=ITEM_A; + + end; + + '.' : + begin + str:=str + ext; + ext:=fn[fcb ]; + + end; + + end; + + end; + + result:=str; + +end; + +{ STR_EXT } +function str_ext; +var + fcb : byte; + ext : shortstring; + itm : tITEM; + +begin + ext:=''; + itm:=ITEM_1; + + if length(fn ) > 0 then + for fcb:=1 to length(fn ) do + case itm of + ITEM_1 : + case fn[fcb ] of + '\' ,'/' : + itm:=ITEM_2; + + '.' : + begin + ext:=fn[fcb ]; + itm:=ITEM_B; + + end; + + else + itm:=ITEM_A; + + end; + + ITEM_2 : + case fn[fcb ] of + '\' ,'/' : + itm:=ITEM_3; + + '.' : + begin + ext:=fn[fcb ]; + itm:=ITEM_B; + + end; + + else + itm:=ITEM_A; + + end; + + ITEM_3 : + case fn[fcb ] of + '\' ,'/' : + itm:=ITEM_A; + + end; + + ITEM_A : + case fn[fcb ] of + '.' : + begin + ext:=fn[fcb ]; + itm:=ITEM_B; + + end; + + end; + + ITEM_B : + case fn[fcb ] of + '\' ,'/' : + begin + ext:=''; + itm:=ITEM_A; + + end; + + '.' : + ext:=fn[fcb ]; + + else + ext:=ext + fn[fcb ]; + + end; + + end; + + result:=cut_str(ext ); + + if result = '.' then + result:=''; + +end; + +{ FOLD_NAME } +function fold_name; +var + dsk , + nme , + pth , + ext : shortstring; + +begin + dsk:=str_disk(p ); + pth:=str_dir (str_path(p ) ); + nme:=str_name(n ); + ext:=str_ext (x ); + + result:=dsk + pth + nme + ext; + +end; + +{ SPREAD_NAME } +procedure spread_name; +begin + p:=str_disk(fn ) + str_dir(str_path(fn ) ); + n:=str_name(fn ); + x:=str_ext (fn ); + +end; + +{ FILE_EXISTS } +function file_exists; +var + f : file; + +begin + AssignFile(f ,fn ); + reset (f ); + + if IOResult = 0 then + begin + close(f ); + + result:=true; + + end + else + result:=false; + +end; + +{ API_OPEN_FILE } +function api_open_file; +begin + result:=false; + + fillchar(af ,sizeof(api_file ) ,0 ); + + af.fileName:=fname; + af.isOpened:=false; + + IOResult; + + AssignFile(af.df ,fname ); + reset (af.df ,1 ); + + if IOResult = 0 then + begin + af.isOpened:=true; + + af.fSize:=filesize(af.df ); + af.fRead:=0; + + end; + + result:=af.isOpened; + +end; + +{ API_READ_FILE } +function api_read_file; +begin + result:=false; + read :=0; + + if af.isOpened then + begin + if aloc > af.fSize - af.fRead then + aloc:=af.fSize - af.fRead; + + blockread(af.df ,buff^ ,aloc ,read ); + + if aloc = read then + begin + inc(af.fRead ,read ); + + result:=true; + + end + else + read:=0; + + end; + +end; + +{ API_CLOSE_FILE } +function api_close_file; +begin + result:=false; + + if af.isOpened then + begin + system.close(af.df ); + + af.isOpened:=false; + + result:=true; + + end; + +end; + +{ PARAM_COUNT } +function param_count; +begin + result:=ParamCount; + +end; + +{ PARAM_STR } +function param_str; +begin + result:=ParamStr(i ); + +end; + +END. +