/* Copyright (C) 2011, Stephane Bisaro, aka iri License : you can do what you want with this source code This code is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. */ /* Create a text fields interface with the 2dGraphic Scol API. These text object are managed by Scol. They are slower than the 2dOS api but they are more customizables. Documentation : Text API : http://www.scolring.org/files/doc_html/comptext_.html This GUI has two fields : - an input field (editable line only) - an output field which displays what has been written Few keywords ae predefined to run actions : - load, save the content - reset - change the first line displayed - and more (see below) */ /* 2DGraphic objects, resources and resize - 2DGraphic Objects =================== By default, all these objects are "empty" i.e. without graphics resources (background, scroll bar, etc). Developers can customize them as they want. Few "2D library" written in this API already exist : an advanced graphic designer could build a graphic interface with limited code. However, this api is slower and less easy than the 2dOS library. Its documentation can be found at this url : http://www.scolring.org/files/doc_html/2d_graphic_api.html In this example, we use two object types : a container and a text field. The first contains any objects : others containers and/or differents fields (text, list, tree, checkbox, etc) The second can not contain any other object and must be inside a container. - - The container ----------------- Their Scol type is ObjContainer. Usually, a container is created from a window object (ObjWin) but it can be created from another container or ex-nihilo (rarier). It can be replace a window and allows to create non-square graphic interface. To create a container, you currently use the Scol function _CRcontainerFromObjWin (from an ObjWin) or _CRcontainerFromObjCont (from another container). Rarely, you use _CRcontainer. Remember to destroy them when no longer needed (via _DScontainer). If the parent is resized, the container can be resized too (i.e. can be resized or can be no resized, as you want). Another use of containers is a background to a (or more) child object : color, effect, pattern, bitmap, etc. See http://www.scolring.org/files/doc_html/objcontainer_.html - - Text fields --------------- These fields can be editable or not. They are always included in an ObjContainer. Their Scol type is CompText. See http://www.scolring.org/files/doc_html/comptext_.html To create them, you will use _CRcompText and to destroy them, _DScompText. When they are created, you should define the resize flag (horizontal and vertical behaviors) : - OBJ_LW_FLEX : the distance between the left border of container and the left border of text field can be variable (default if not defined) - OBJ_MW_FLEX : the width of the text field is variable - OBJ_RW_FLEX : the distance between the right border of container and the right border of text field can be variable - OBJ_LH_FLEX : the distance between the top border of container and the top border of text field can be variable (default if not defined) - OBJ_MH_FLEX : the height of the text field is variable - OBJ_RH_FLEX : the distance between the bottom border of container and the bottom border of text field can be variable When the father (a container) is resized ... : before the resize after the resize _____________________________ ____________________________________ | container | | container | | | | | | ------------------- | | ------------------- | | * text field * | =======================> | * text field * | | * * | resize with OBJ_LW_FLEX | * * | | ------------------- | | ------------------- | | | | | | | | | _____________________________ ____________________________________ _____________________________ ____________________________________ | container | | container | | | | | | ------------------- | | -------------------------- | | * text field * | =======================> | * text field * | | * * | resize with OBJ_MW_FLEX | * * | | ------------------- | | -------------------------- | | | | | | | | | _____________________________ ____________________________________ _____________________________ ____________________________________ | container | | container | | | | | | ------------------- | | ------------------- | | * text field * | =======================> | * text field * | | * * | resize with OBJ_RH_FLEX | * * | | ------------------- | | ------------------- | | | | | | | | | _____________________________ ____________________________________ The process is similar for the vertical behaviour. You could define the "filter flags" too. If an event occurs on the text field (for example, a key pressed, a mouse click, a move, etc), this event can ran a reflex if a callback has been defined. But if no callback defined, the behavior depends to these filter flags. An event occurs and a callback has been defined ========> the reflex is ran and and the event doesn't propagate An event occurs and no callback has been defined =======> all depends to the filter flags : if a filter flag is defined to this event, the event is sent to the father (the container) otherwise, this event is ignored. OBJ_CONTAINER_CLICK ========> if added, the pressed mouse click event will be sent to the parent object OBJ_CONTAINER_UNCLICK ====> if added, the released mouse click event will be sent to the parent object OBJ_CONTAINER_DBLCLICK ====> if added, the double mouse click event will be sent to the parent object OBJ_CONTAINER_MOUSEWHEEL > if added, the mouse wheel event will be sent to the parent object OBJ_CONTAINER_KEYDOWN ====> if added, the pressed key event will be sent to the parent object OBJ_CONTAINER_KEYUP ========> if added, the released key event will be sent to the parent object OBJ_CONTAINER_MOVE ========> if added, the move event will be sent to the parent object OBJ_CONTAINER_ALLEVENTS ====> if added, all these events are sent 0 or nil ================> no filter flag defined, so no event will be sent. Example : OBJ_CONTAINER_CLICK|OBJ_CONTAINER_UNCLICK Scroll bars are your graphics resources. There are not any default resources included. If you want a scroll bar, you must load or create these resources. Otherwise or if the resources are corrupted / incorrect, no scroll bars will be displayed. Then, if you defined them and they don't appear, either the resources are bad or the parameters in _CRcompText are wrong. See below "Graphics resources". - Graphics resources ==================== This must be an AlphaBitmap i.e. a graphic resource with an alpha layer (may be nil but it is not recommended). This structure is necessarily : the left (or top) arrow, the body, the right (or bottom) arrow, the cursor. For an horizontal scroll bar : d1 d2 d3 <-- offsets ___ ________________ ___ _ | < || || > ||X| |___||________________||___||_| left body right cursor arrow arrow For a vertical scroll bar : offsets ____ | /\ | top arrow ____ d1 | | | | | | | | body | | | | ____ d2 | \/ | bottom arrow ____ d3 | XX | cursor ____ So, from 0 to d1 : the left or top arrow from d1 to d2 : the body from d2 to d3 : the right or bottom arrow from d3 to then end : the cursor. Then, it is necessary to define d1, d2 and d3. There are "offsets" that you'll define in (v)slide tuple when you create a text field (in the two last arguments of _CRcompText). You can add few flags : - SLB_DISABLE : the scroll bar has a disabled state. In this case, the resource must have a disabled state - SLB_MASK : the scroll bar has a mask state. In this case, the resource must have a mask state - SLB_ROLLOVER : the scroll bar changes with the rollover. In this case, the resource must have these differents states. See the file "vslide.png" et the code below for an example. You can load any png file via _LDalphaBitmap (http://www.scolring.org/files/doc_html/_ldalphabitmap.html) or create by the code your resource : - use Bitmaps functions : http://www.scolring.org/files/doc_html/bitmap.html - - create a bitmap (_CRbitmap) - - color, text, gradient, blur or others things - - create the (future) alpha layer (_CRbitmap8) - next, use _CRalphaBitmap : http://www.scolring.org/files/doc_html/_cralphabitmap.html ** ** Note : the width (the height) of the AlphaBitmap should be equal at the initial width ** (the height) of the text field. ** - Resize a graphic resource =========================== When the text field is resized, the resource lost the good size ! You must resize it ... this is not always clear ! - Extract the ObjBitmap from the AlphaBitmap via _GETalphaBitmaps : _GETalphaBitmaps : fun [AlphaBitmap] [ObjBitmap ObjBitmap8] : the bitmap and the alpha layer - Define new d1, d2 and d3 values (depend of the new size) - Resize the bitmap and the alpha layer, per blocks : from 0 to d1 (usually, it's just a copy, without resize) from d1 to d2 (usually, there is a stretch) from d2 to d3 (usually, it's just a copy, without resize) from d3 to end (usually, it's just a copy, without resize) via _CPbitmap, _SCPbitmap24, _CPbitmap8, _SCPbitmap8 and others functions if needed. - Set the AlphaBitmap via _CRalphaBitmap This must be done in the function defined by _CBcompTextResizeResource. These actions may take some time ... */ typeof window = ObjWin;; // main window typeof container = ObjContainer;; // main container, child of the main window typeof containerLine = ObjContainer;; // child container of the main container typeof cText = CompText;; // output text field typeof cLine = CompText;; // input text field typeof aScrollHz = AlphaBitmap;; // graphic resource for the horizontal scroll bar (output text field) typeof aScrollVe = AlphaBitmap;; // graphic resource for the vertical scroll bar (output text field) typeof rFont = ObjFont;; // used font var mainBgColor = 0x555555;; // background color var mainFoColor = 0xdddddd;; // foreground color var lineBgColor = 0x666666;; // text line background color var lineFoColor = 0xeeeeee;; // text line foreground color var promptColor = 0x1111ee;; // prompt color var prompt = "$ ";; var toggleFoo = 0;; // Display (1) or not (0) the ascii code in the console (when the user hits a key) var fileContent = "tutorials/text/content.txt";; /* Add a string to the output field. _ADDcompText just concatenates the previous content with any string. If you want a new line, you must do this explicitely ("\n") Note : font and and colors are not yet implemented You should repaint the father container when you change anything : _PAINTcontainer. Otherwise, changes may not be visibles. Prototype : fun [S] I */ fun addContent (string)= _ADDcompText cText prompt rFont [promptColor 0 0 0] CT_END; _ADDcompText cText string rFont [mainFoColor 0 0 0] CT_END; _PAINTcontainer container; 0;; /* Set a string to the output field. _SETcompText just concatenates the previous content with any string. If you want a new line, you must do this explicitely ("\n") Note : font and and colors are not yet implemented You should repaint the father container when you change anything : _PAINTcontainer. Otherwise, changes may not be visibles. Prototype : fun [S] I */ fun setContent (string)= _SETcompText cText prompt rFont [promptColor 0 0 0] CT_END; _ADDcompText cText string rFont [mainFoColor 0 0 0] CT_END; _PAINTcontainer container; 0;; /* Build a simple help / usage and display it in the output field Prototype : fun [] I */ fun displayHelp ()= let "Welcome in this small example of Scol application\n F1 : show this help\n F2 : save the content to a predefined file (old content will be overwritten)\n F3 : load the old content from a predefined file\n F4 : content becomes empty\n F5 : write (or not) the ascii code of each pressed key in the console\n HOME : display the top of the content, if any\n END : display the bottom of the content, if any\n Page UP : up to 10 lines\n Page Down : down to 10 lines\n" -> help in addContent help; 0;; /* Save the current content of the output field to a predefined file. _GETtext returns this content. _createpack saves any content in any file, the file must be in a write-reference file only (_getmodifypack) See : http://www.scolring.org/files/doc_html/file_system.html Prototype : fun [] I */ fun saveContent ()= let _GETcompText cText -> content in _createpack content _getmodifypack fileContent; 0;; /* Load a saved content and display it in the output field. If any, the old content will be deleted _getpack reads the full content of any file, file must be in a read-reference file (_checkpack) See : http://www.scolring.org/files/doc_html/file_system.html Prototype : fun [] I */ fun loadContent ()= let _getpack _checkpack fileContent -> content in setContent content; 0;; /* The output field becomes empty Prototype : fun [] I */ fun reset ()= setContent ""; 0;; /* Reverse the value of the variable "toggleFoo". If it's 1, the ascii code of the pressed key will be displayed in the console Prototype : fun [] I */ fun foo ()= set toggleFoo = !toggleFoo; 0;; /* Display the top of the content _SETcompTextFirstLine sets the first visible line if the text is scrolled If the line is 0 then the top of the text will be visible Prototype : fun [] I */ fun displayTop ()= _SETcompTextFirstLine cText 0; 0;; /* Display the bottom of the content _GETcompTextLineCount returns the total number of lines The bottom of text will be visible Prototype : fun [] I */ fun displayBottom ()= _SETcompTextFirstLine cText _GETcompTextLineCount cText; 0;; /* Up to ten lines _GETcompTextFirstLine returns the current first visible line Prototype : fun [] I */ fun displayUp ()= let (_GETcompTextFirstLine cText) - 10 -> n in ( set n = if n < 0 then 0 else n; _SETcompTextFirstLine cText n; 0 );; /* Down to ten lines See comments above Prototype : fun [] I */ fun displayDown ()= let (_GETcompTextFirstLine cText) + 10 -> n in ( set n = if n > _GETcompTextLineCount cText then _GETcompTextLineCount cText else n; _SETcompTextFirstLine cText n; 0 );; /* Reflex called when the user hits the return key Some hotkeys are defined. Il the user enters one of them, a special function is called and ran. Otherwise, the content of the input field is added to the content of output field. If toggleFoo is at 1, the ascii value is displayed in the console. To know that, set toggleFoo to 1 and hit the key ! Prototype : fun [CompText I I I] I */ fun CBcontLineKey (obj, user_parameter, keycode, asciicode)= if toggleFoo == 1 then _fooId asciicode else 0; if asciicode == 65470 then // F1 -> Help displayHelp else if asciicode == 65471 then // F2 -> Save saveContent else if asciicode == 65472 then // F3 -> Load loadContent else if asciicode == 65473 then // F4 -> Clear reset else if asciicode == 65474 then // F5 -> toggle asciicode displayed in console foo else if asciicode == 65360 then // HOME -> display the top of content displayTop else if asciicode == 65367 then // END -> display the bottom of content displayBottom else if asciicode == 65365 then // Page UP -> up to 10 lines displayUp else if asciicode == 65366 then // Page DOWN -> down to 10 lines displayDown else 0;; /* Reflex called when the user validate the input message by : - the return key - the click inside the input field For example, if the user hits the return key, his message will be added to the output field If the users clicks in the input field, his default name (defined in the configuration panel of Scol) will be concatenates with his message. Prototype : fun [CompText I I S] I */ fun CBlineOK (obj, user_parameter, type, content)= if type == CT_VALIDENTER then // the user hits the return key ( let strcat content "\n" -> string in addContent string; _SETcompText cLine "" rFont [lineFoColor 0 0 0] CT_BEGIN; _PAINTcontainer containerLine; 0 ) else if type == CT_VALIDCLICK then // the user clicks inside the line text field ( let strcatn (_getress "DefaultName") :: " > " :: content :: "\n" :: nil -> string in addContent string; _SETcompText cLine "" rFont [lineFoColor 0 0 0] CT_BEGIN; _PAINTcontainer containerLine; 0 ) else ( _fooS "Strange ! this function shoud not be called !"; 0 );; /* Reflex called when the main container has been resized When a child object is created, resize flags can be defined. By default and if not defined, the child object is not resized : its size is fixed. See the top of this file too. Otherwise, the graphic resource must be resized. Note : _SAVEbitmap save in a file the current state of the bitmap, to verify if the way is good :) */ fun CBslideVeResize (slide, user_parameter, newW, newH, offset)= let offset -> [v1 v2 v3] in // old offset let _GETalphaBitmaps aScrollVe -> [bmp bmp8] in // extract bitmap and alpha layer from the old AlphaBitmap let _GETalphaBitmapSize aScrollVe -> [oldW oldH] in // old size of the old AlphaBitmap let _GETalphaBitmapBackground aScrollVe -> bg in // current background value let _GETalphaBitmapTransparency aScrollVe -> trans in // current transparency value let _CRbitmap _channel newW newH -> newbmp in // a new bitmap is created with the new size let _CRbitmap8 _channel newW newH -> newbmp8 in // a new alpha layer is created with the new size let newH-(oldH-v3) -> newV3 in // define the new third offset (d3) let newH-(oldH-v2) -> newV2 in // define the new second offset (d2) let v1 -> newV1 in // define the new first offset (d1) ( _CPbitmap24 newbmp 0 0 bmp 0 0 oldW v1 nil; // bitmap : from 0 to d1 _CPbitmap8 newbmp8 0 0 bmp8 0 0 oldW v1 nil; // alpha layer : from 0 to d1 // _SAVEbitmap newbmp _getmodifypack "examples/text/test1.bmp"; _SCPbitmap newbmp 0 newV1 newW newV2 bmp 0 v1 oldW v2 nil; // bitmap : from d1 to d2 _SCPbitmap8 newbmp8 0 newV1 newW newV2 bmp8 0 v1 oldW v2 nil; // alpha layer : from d1 to d2 // _SAVEbitmap newbmp _getmodifypack "examples/text/test2.bmp"; _CPbitmap24 newbmp 0 newV2 bmp 0 v2 oldW v3-v2 nil; // bitmap : from d2 to d3 _CPbitmap8 newbmp8 0 newV2 bmp8 0 v2 oldW v3-v2 nil; // alpha layer : from d2 to dd3 // _SAVEbitmap newbmp _getmodifypack "examples/text/test3.bmp"; _CPbitmap24 newbmp 0 newV3 bmp 0 v3 oldW oldH-v3 nil; // bitmap : from d3 to end _CPbitmap8 newbmp8 0 newV3 bmp8 0 v3 oldW oldH-v3 nil; // alpha layer : from d3 to end // _SAVEbitmap newbmp _getmodifypack "examples/text/test4.bmp"; [_CRalphaBitmap _channel newbmp newbmp8 bg trans [newV1 newV2 newV3]] // set the new resource with the new offsets );; /* Add container and text fields in the main window container is the main container, child of the main window containerLine is the child of container. It gives a background color to the input text field. See others comments above */ fun create2dGrahic ()= let _GETwindowSizePosition window -> [wWin hWin _ _] in ( set container = _CRcontainerFromObjWin _channel window 0 0 wWin hWin CO_CHILDINSIDE|CO_NOBORDER mainBgColor nil; set containerLine = _CRcontainerFromObjCont _channel container 3 hWin-35 wWin-6 30 CO_CHILDINSIDE|CO_NOBORDER lineBgColor nil; _CBcontainerKeyDown containerLine @CBcontLineKey 0; _CBcontainerKeyDown container @CBcontLineKey 0; _SETfocusContainer containerLine; _SETobjNodeFocus _CONVERTcompTextToObjNode cLine; set cText = _CRcompText _channel container nil [5 5] OBJ_ENABLE|OBJ_VISIBLE|OBJ_MW_FLEX|OBJ_MH_FLEX|CT_LABEL|CT_WORDWRAP OBJ_CONTAINER_ALLEVENTS wWin-10 hWin-50 ">>> Hello\n\n" rFont [mainFoColor 0 0 0] [0 50] [[wWin-26 0] OBJ_LW_FLEX|SLB_MASK|SLB_ROLLOVER aScrollVe [13 376 386]] nil; set cLine = _CRcompText _channel containerLine nil [5 5] OBJ_ENABLE|OBJ_VISIBLE|OBJ_MW_FLEX|OBJ_LH_FLEX|CT_EDITLINE OBJ_CONTAINER_ALLEVENTS wWin-10 20 "Enter your message here" rFont [lineFoColor 0 0 0] [0 50] nil nil; _SETcompTextFirstLine cText _GETcompTextLineCount cText; _CBcompTextResizeResource cText @CBslideVeResize 0 nil 0; _CBcompTextValidation cLine @CBlineOK 0 CT_VALIDENTER|CT_VALIDCLICK; _PAINTcontainer containerLine; _PAINTcontainer container; 0 );; /* Function called when the main windoww is resized _SIZEcontainer allows to ... resize a container because the resize is NOT automatic when the mother window is resized. The childs object are resized (or not), that depends if a corresponding flags bas been defined when the object has been created. Prototype : fun [ObjWin I I I] I */ fun CBwinResize (win, user_parameter, newWidth, newHeight)= _SIZEcontainer container 0 0 newWidth newHeight; _SIZEcontainer containerLine 3 newHeight-35 newWidth-6 30; 0;; // Destroy the virtual Scol machine - fun [] I fun end ()= _closemachine;; // Function called when the main window is destroyed - fun [ObjWin I] I fun CBwinEnd (win, user_parameter)= // we destroy all components _DScompText cText; _DScompText cLine; _DScontainer containerLine; _DScontainer container; _DSalphaBitmap aScrollVe; _DSalphaBitmap aScrollHz; _DSfont rFont; end;; /* Main function. The main window is created. _SETwindowMinSize and _SETwindowMaxSize define the minimal (respectively maximale) size of the window Prototype : fun [] I */ fun main ()= _showconsole; // we create a window in the center of the screen let _GETscreenSize -> [wScreen hScreen] in let [500 437] -> [width height] in let [(wScreen/2)-(width/2) (hScreen/2)-(height/2)] -> [x y] in ( set window = _CRwindow _channel nil x y width height WN_MENU|WN_SIZEBOX " Example : 2D Graphic > Text"; let _GETwindowExSizePosition window -> [wall hall _ _] in ( _SETwindowMinSize window wall hall; _SETwindowMaxSize window wScreen hall; ) ); // we define the window callbacks _CBwinDestroy window @CBwinEnd 0; // window is destroyed _CBwinSize window @CBwinResize 0; // window is resized // we create a font set rFont = _CRfont _channel 14 0 0 "Arial"; // we load the png file (vslide) set aScrollVe = _LDalphaBitmap _channel _checkpack "tutorials/text/vslide.png"; // we call the function that creates the 2d graphics components create2dGrahic; 0;;