QB64.org Forum
		Active Forums => QB64 Discussion => Topic started by: RhoSigma on August 06, 2019, 03:58:57 am
		
			
			- 
				As the title line says, has anybody have a documentation of the functions provided via "falcon.h"? As it is used in InForm, Fellippe maybe? I know there was once a whole thread about it on the old [abandoned, outdated and now likely malicious qb64 dot net website - don’t go there] forum, but as this is only available in very rudimentary form now, I cannot find it there anymore.
 Thanx
 
- 
				The original thread for it contained a demo program and some rather detailed notes on all the parameters - which of course I have no record of and is probably lost forever.
 
 falcon was never really intended for public consumption (originally it was part of a long-abandoned menuing system, then it got picked up for InForm) so I think there's a few versions of it floating around; for reference I have attached my copy of it, and it's what I'll base my notes below on.
 
 DECLARE LIBRARY "falcon"
 SUB uprint_extra (BYVAL x&, BYVAL y&, BYVAL chars%&, BYVAL length%&, BYVAL kern&, BYVAL do_render&, txt_width&, BYVAL charpos%&, charcount&, BYVAL colour~&, BYVAL max_width&)
 FUNCTION uprint (BYVAL x&, BYVAL y&, chars$, BYVAL txt_len&, BYVAL colour~&, BYVAL max_width&)
 FUNCTION uprintwidth (chars$, BYVAL txt_len&, BYVAL max_width&)
 FUNCTION uheight& ()
 FUNCTION falcon_uspacing& ALIAS uspacing ()
 FUNCTION uascension& ()
 END DECLARE
 
 Strings are expected to be UTF-8 encoded.
 
 uprint_extra is the main function:
 - x&, y& : coordinates to render at
- chars%& : offset to text (i.e. _OFFSET(text$))
- length%& : string length in bytes
- kern& : boolean value to enable/disable kerninig
- do_render& : boolean value to enable/disable actually printing text. Disabling this is useful for doing size calculations with variable-width fonts
- txt_width& (output) : returns the horizontal size of the rendered text, in pixels
- charpos%& (output) : Declare an array     REDIM charpos(LEN(text$)) AS LONG and pass _OFFSET(charpos()). Then charpos(1) is the location of the end of the first character, charpos(2) the end of the second character, and so on. Locations are horizontal pixel distances from the left boundary.
- charcount& (output) : The number of characters actually printed
- colour~& : Font colour. Use _RGB32().
- max_width& : The maximum width in pixels the text should have. If there is not enough room, the text is truncated to however many characters will fit.
 
 The uprint function differs only in that it takes a string argument for the text, and has the defaults:
 - kern = true
- do_render = true
 It returns the txt_width parameter described above. Other output values are not available.
 
 The uprintwidth function takes only the text data and the maximum print width, and returns the actual width the text would have if printed.
 
 The other functions are font metrics, and my memory's a little shaky. You might need to experiment a little:
 uheight& is the vertical distance between baselines, in pixels.
 uascension& is the distance from the baseline to the top. Lets you find the position of the baseline.
 uspacing& ¯\_(ツ)_/¯
 
 Finally, here's a cute textbox I found that uses the charpos() array to draw a cursor:
 DECLARE LIBRARY "falcon"
 SUB uprint_extra (BYVAL x&, BYVAL y&, BYVAL chars%&, BYVAL length%&, BYVAL kern&, BYVAL do_render&, txt_width&, BYVAL charpos%&, charcount&, BYVAL colour~&, BYVAL max_width&)
 FUNCTION uprint (BYVAL x&, BYVAL y&, chars$, BYVAL txt_len&, BYVAL colour~&, BYVAL max_width&)
 FUNCTION uprintwidth (chars$, BYVAL txt_len&, BYVAL max_width&)
 FUNCTION uheight& ()
 FUNCTION falcon_uspacing& ALIAS uspacing ()
 FUNCTION uascension& ()
 END DECLARE
 
 TYPE textbox_t
 shadow_screen AS LONG
 hardware_screen AS LONG
 box_x AS LONG
 box_y AS LONG
 box_width AS LONG
 box_height AS LONG
 cursor_offset AS LONG
 cursorx AS LONG
 cursory AS LONG
 cursor_image AS LONG
 END TYPE
 
 DEFLNG A-Z
 
 CONST FONTFILE = "cyberbit.ttf"
 CONST BOX_X = 60
 CONST BOX_Y = 90
 CONST BOX_WIDTH = 520
 CONST BOX_HEIGHT = 300
 
 SCREEN _NEWIMAGE(640, 480, 32)
 
 DIM textbox AS textbox_t
 create_textbox _LOADFONT(FONTFILE, 16), BOX_X, BOX_Y, BOX_WIDTH, BOX_HEIGHT, textbox
 cursor_image = create_cursor
 
 text$ = "Quis sunt vel ut dolor sed natus. Autem odit eius sapiente nostrum velit blanditiis eius. Aut earum sed est."
 textcopy$ = text$
 textbox.cursor_offset = 10
 _DISPLAYORDER _HARDWARE
 
 typeset_textbox textbox, textcopy$
 DO
 _LIMIT 50
 k$ = INKEY$
 IF k$ <> "" THEN
 SELECT CASE k$
 CASE CHR$(8)
 IF textbox.cursor_offset > 0 THEN
 IF textbox.cursor_offset = LEN(text$) THEN
 text$ = LEFT$(text$, LEN(text$) - 1)
 ELSE
 text$ = LEFT$(text$, textbox.cursor_offset - 1) + MID$(text$, textbox.cursor_offset + 1)
 END IF
 textbox.cursor_offset = textbox.cursor_offset - 1
 END IF
 CASE CHR$(0) + "M"
 IF textbox.cursor_offset < LEN(text$) THEN textbox.cursor_offset = textbox.cursor_offset + 1
 CASE CHR$(0) + "K"
 IF textbox.cursor_offset > 0 THEN textbox.cursor_offset = textbox.cursor_offset - 1
 CASE CHR$(0) + "G"
 textbox.cursor_offset = 0
 CASE CHR$(0) + "O"
 textbox.cursor_offset = LEN(text$)
 CASE ELSE
 IF textbox.cursor_offset = LEN(text$) THEN
 text$ = text$ + k$
 ELSE
 text$ = LEFT$(text$, textbox.cursor_offset) + k$ + MID$(text$, textbox.cursor_offset + 1)
 END IF
 textbox.cursor_offset = textbox.cursor_offset + 1
 END SELECT
 textcopy$ = text$
 typeset_textbox textbox, textcopy$
 END IF
 render_textbox textbox
 _DISPLAY
 LOOP
 
 SUB render_textbox (textbox AS textbox_t)
 _PUTIMAGE (textbox.box_x, textbox.box_y), textbox.hardware_screen
 _PUTIMAGE (textbox.box_x + textbox.cursorx, textbox.box_y + textbox.cursory), textbox.cursor_image
 END SUB
 
 SUB bench (t0!, t1!, t2!)
 STATIC n, a1!, a2!
 a1! = (a1! * n + (t1! - t0!)) / (n + 1)
 a2! = (a2! * n + (t2! - t1!)) / (n + 1)
 n = n + 1
 _TITLE STR$(a1!) + " " + STR$(a2!)
 END SUB
 
 FUNCTION create_cursor
 image = _NEWIMAGE(1, uheight&, 32)
 olddest = _DEST
 _DEST image
 LINE (0, 0)-(0, uheight&), _RGB32(255, 0, 0)
 _DEST olddest
 create_cursor = _COPYIMAGE(image, 33)
 _FREEIMAGE image
 END FUNCTION
 
 
 SUB typeset_textbox (textbox AS textbox_t, s$)
 LINE (textbox.box_x, textbox.box_y)-STEP(textbox.box_width, textbox.box_height), _RGB32(255, 255, 255), BF
 olddest = _DEST
 _DEST textbox.shadow_screen
 LINE (0, 0)-(BOX_WIDTH, BOX_HEIGHT), _RGB32(255, 255, 255), BF
 REDIM charpos(LEN(s$)) AS LONG
 cursor_offset = textbox.cursor_offset
 
 DO
 uprint_extra 0, vertical_offset, _OFFSET(s$), LEN(s$), -1, -1, txt_width&, _OFFSET(charpos()), charcount&, _RGB32(0, 0, 0), BOX_WIDTH
 
 'Line ended partway through a word?
 IF LEN(s$) > charcount& THEN
 IF MID$(s$, charcount&, 1) <> " " AND MID$(s$, charcount& + 1, 1) <> " " THEN
 'Find end of previous word
 charcount& = reverse_find_word_end(s$, charcount&)
 END IF
 END IF
 
 newwidth& = charpos&(charcount&)
 LINE (newwidth& + 1, vertical_offset)-(BOX_WIDTH, vertical_offset + uheight& - 1), _RGB32(255, 255, 255), BF
 
 IF NOT cursor_found AND cursor_offset <= charcount& THEN
 textbox.cursorx = charpos(cursor_offset)
 textbox.cursory = vertical_offset
 cursor_found = -1
 END IF
 
 vertical_offset = vertical_offset + uheight&
 
 IF LEN(s$) = charcount& THEN
 EXIT DO
 ELSE
 'remove leading spaces
 'WARNING: This part will mean the cursor offsets are no longer contiguous; it will break on line ends and get positions wrong
 'Need to decide on a behaviour to make them both work
 'FOR i = charcount& + 1 TO LEN(s$)
 '    IF MID$(s$, i, 1) <> " " THEN EXIT FOR
 'NEXT i
 'IF i > LEN(s$) THEN EXIT DO 'turns out the entire remaining text was spaces
 's$ = MID$(s$, i)
 s$ = MID$(s$, charcount& + 1)
 
 'Keep cursor offset relative to our ever-shrinking string
 cursor_offset = cursor_offset - charcount&
 END IF
 LOOP
 IF textbox.hardware_screen <> 0 THEN _FREEIMAGE textbox.hardware_screen
 textbox.hardware_screen = _COPYIMAGE(textbox.shadow_screen, 33)
 _DEST olddest
 END SUB
 
 
 SUB create_textbox (fonthandle, box_x, box_y, box_width, box_height, textbox AS textbox_t)
 textbox.shadow_screen = _NEWIMAGE(box_width, box_height, 32)
 textbox.box_x = box_x
 textbox.box_y = box_y
 textbox.box_width = box_width
 textbox.box_height = box_height
 textbox.cursor_image = create_cursor
 
 olddest = _DEST
 _DEST textbox.shadow_screen
 _FONT fonthandle
 _DEST olddest
 END SUB
 
 
 'Finds the end of the last complete word in the substring of s$ from start to length&
 FUNCTION reverse_find_word_end (s$, length&)
 FOR i = length& TO 2 STEP -1
 'Looking for a space proceeded by a non-space
 IF MID$(s$, i, 1) = " " AND MID$(s$, i - 1, 1) <> " " THEN
 reverse_find_word_end = i - 1
 EXIT FUNCTION
 END IF
 NEXT i
 'What to do if there's no location meeting this condition?
 END FUNCTION
- 
				Thank you Luke, this will help alot.