Author Topic: and another one for your toolbox...  (Read 21282 times)

0 Members and 1 Guest are viewing this topic.

This topic contains a post which is marked as Best Answer. Press here if you would like to see it.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
and another one for your toolbox...
« on: July 15, 2019, 11:20:40 am »
OK I am sure this has been done 10x's over again and again...

But without a toolbox, one has to figure it out again and again when the occasion arises.

First the story, I was checking into XOR even before Steve provided the link in the Xbox tunnel of love thread when I discovered that &H has the reverse HEX$ and &O has the reverse OCT$ but poor 'ole &B has squat!

So here is BIN$ for your edification and toolbox:
Code: QB64: [Select]
  1. 'does QB64 reverse &B numbers conver HEX$ for base 16, OCT$ for base 8, no base 2?
  2.     INPUT "Enter integer to convert to binary (0 to quit) "; test
  3.     PRINT "Dec2Base$(test, 2) = "; Dec2Base$(test, 2), "BIN$(test) = "; BIN$(test)
  4.     PRINT "and  VAL(" + CHR$(34) + "&B" + CHR$(34) + " + BIN$(test)) ="; VAL("&B" + BIN$(test))
  5.     PRINT
  6. LOOP UNTIL test = 0
  7.  
  8. FUNCTION Dec2Base$ (nDec AS INTEGER, bs AS INTEGER)
  9.     DIM n AS INTEGER, p AS INTEGER, pow AS INTEGER, d AS INTEGER, b$
  10.     n = nDec 'copy this because or nDec gets changed effecting main code
  11.     WHILE bs ^ p <= n
  12.         p = p + 1
  13.     WEND
  14.     FOR pow = p TO 0 STEP -1
  15.         IF n >= bs ^ pow THEN
  16.             d = INT(n / bs ^ pow)
  17.             IF d < 10 THEN
  18.                 b$ = b$ + _TRIM$(STR$(d))
  19.             ELSE
  20.                 b$ = b$ + CHR$(65 + d - 10)
  21.             END IF
  22.             n = n - d * bs ^ pow
  23.         ELSE
  24.             IF b$ <> "" THEN b$ = b$ + "0"
  25.         END IF
  26.     NEXT
  27.     IF b$ = "" THEN b$ = "0"
  28.     Dec2Base$ = b$
  29.  
  30. '2019-12-02 latest eliminates &B prefix
  31. FUNCTION BIN$ (integerBase10 AS _INTEGER64) 'no more &B because easier to add than to remove
  32.     DIM j AS INTEGER
  33.     IF integerBase10 = 0 THEN BIN$ = "0": EXIT FUNCTION
  34.     WHILE 2 ^ j <= integerBase10
  35.         IF (integerBase10 AND 2 ^ j) > 0 THEN BIN$ = "1" + BIN$ ELSE BIN$ = "0" + BIN$
  36.         j = j + 1
  37.     WEND
  38.  

Who needs Bill, the toolbox librarian, just start your own thread! ;- +

BTW, wouldn't it be better if HEX$(base10Integer) returned the string as "&H...." and OCT$ as "&O..." ?

You know, label the number base if it is not your standard base 10.

EDIT: For library code, probably should DIM everything, something a librarian might remind us of if one were present. ;-))

EDIT: 2019-12-01 more elegant version of BIN$
EDIT: 2019-12-02 reconsidered again with RhoSigma's input no &B prefix, also get rid of the limit test for integer and the other junk in demo! see reasons in reply #46


UPDATE: This stuff has been incorporated into QB64 since v1.3 I think, 1.4 for sure.
« Last Edit: September 12, 2020, 02:47:05 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: and another one for your toolbox...
« Reply #1 on: July 15, 2019, 12:19:52 pm »
It is important to have a palindrome detector handy, so that when one is in our midst, we might know:

Code: QB64: [Select]
  1. 'Palindrome tester.txt for JB 2015-11-01 MGA/B+ thanks to BP.org and Wiki
  2. DIM t$
  3. WHILE t$ <> "END"
  4.     READ t$
  5.     PRINT t$;
  6.     IF isPalindrome(t$) THEN PRINT " is a palindrome." ELSE PRINT " is NOT a palindrome."
  7. DATA "A dog, a plan, a canal: pagoda!","A dog, a panic, in a pagoda."
  8. DATA "A man, a plan, a cat, a ham, a yak, a yam, a hat, a canal-Panama!"
  9. DATA "Yada yada day a day"
  10. DATA "RATS","END"
  11.  
  12. FUNCTION isPalindrome (phrase$)
  13.     DIM copy$, b$, p$, char$, i AS INTEGER
  14.     copy$ = UCASE$(phrase$)
  15.     FOR i = 1 TO LEN(copy$) ' I don't see palindromes getting much longer than 32000
  16.         char$ = MID$(copy$, i, 1)
  17.         IF ASC(char$) > 64 AND ASC(char$) < 91 THEN b$ = b$ + char$: p$ = char$ + p$
  18.     NEXT
  19.     IF b$ = p$ THEN isPalindrome = -1
  20.  

Today we have a classic one in our midst.  ;-)) which reminded me of this old code exercise for people who need to get comfortable with using SUBs and FUNCTIONs.

EDIT: line 19 too long, too many redundant calls to MID$ for same thing. I bit the bullet and added another variable for clarity.

UPDATE: Hardy an auspicious start for a mighty thread ;-))
« Last Edit: September 12, 2020, 02:48:17 pm by bplus »

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
Re: and another one for your toolbox...
« Reply #2 on: July 15, 2019, 04:38:19 pm »
"Madam, I'm Adam."
Logic is the beginning of wisdom.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: and another one for your toolbox...
« Reply #3 on: July 28, 2019, 05:18:12 pm »
Top Ten Code:
Code: QB64: [Select]
  1. _Title "Top Ten Tester" ' B+ started 2019-07-28
  2. '2019-07-28 All enclosed in a sub, possible feed it score and see how it stacks up.
  3. '2019-07-28 fix to fill all 10 slots.
  4. '2019-07-29 2nd fix with an n > 10 check, change to a function and get GoAgain reply.
  5.  
  6. ' ref https://www.qb64.org/forum/index.php?topic=1511.msg107586#msg107586
  7.  
  8. Dim score, again$
  9. 'testing function with random scores, would be good to start with
  10. For score = 1 To 15
  11.     again$ = topTenGoAgain$(score * 5 * Rnd)
  12.     If Len(again$) Then Print "Player wants to quit.": End Else Print "Player wants to go again."
  13.     If score = 15 Then
  14.         Print "End of test."
  15.     End If
  16.  
  17. ' This FUNCTION creates a file in the same folder as your .bas source or .exe
  18. 'EDIT: 2019-07-29 change to FUNCTION to combine Top Ten update functions with Go Again reply.
  19. Function topTenGoAgain$ (compareScore As Integer)
  20.     Dim fName$, n As Integer, names$(1 To 10), scores(1 To 10), name$, score As Integer
  21.     Dim settleScore As Integer, i As Integer, dummy$
  22.     fName$ = "Top 10 Scores.txt" '<<<  since this is toolbox code change this as needed for app
  23.     Cls: Print: Print "Your score was:"; compareScore: Print: Print "Top Ten Scorers and Scores:"
  24.     If _FileExists(fName$) Then
  25.         Open fName$ For Input As #1
  26.         While EOF(1) = 0 And n < 10
  27.             n = n + 1
  28.             Input #1, name$
  29.             Input #1, score
  30.             If compareScore >= score And settleScore = 0 Then
  31.                 Print "You have made the Top Ten!"
  32.                 Input "Type your name here: ", names$(n)
  33.                 scores(n) = compareScore
  34.                 settleScore = -1
  35.                 n = n + 1
  36.                 If n <= 10 Then names$(n) = name$: scores(n) = score
  37.             Else
  38.                 scores(n) = score: names$(n) = name$
  39.             End If
  40.         Wend
  41.         Close #1
  42.         If n < 10 And settleScore = 0 Then
  43.             Print "There is a slot open for your name and score."
  44.             Input "Type your name here: ", name$
  45.             If name$ <> "" Then n = n + 1: names$(n) = name$: scores(n) = compareScore
  46.         End If
  47.         Open fName$ For Output As #1
  48.         If n > 10 Then n = 10
  49.         For i = 1 To n
  50.             Print #1, names$(i): Print #1, scores(i)
  51.             Print i, names$(i), scores(i)
  52.         Next
  53.         Close #1
  54.     Else
  55.         Print "You are first into file!"
  56.         Input "Type your name here:"; name$
  57.         Open fName$ For Output As #1
  58.         Print #1, name$: Print #1, compareScore
  59.         Close #1
  60.     End If
  61.     Print: Input "Press <Enter> to play again, <q (or any) + Enter> to quit... "; dummy$
  62.     topTenGoAgain$ = dummy$
  63.  
  64.  
  65.  

Works OK for me. How did name$ get to be NAME$ here in forum post?

Update: Sorry, I did not test the sub enough, only with increasingly good scores. But what happens if score is not better and you have 9 slots left in Top Ten? You fill the next slot, Fixed.

Update: 2019-07-29 found another thing to fix, check if n > 10 Also changed the SUB to a FUNCTION and used it to get Go Again information from the player. It seems the perfect time to ask the player if they want to go again and combining functions saves the player a 2nd question and key press answer to make. This is demo'd in the test code.

2021-10-27 Modified for new Function change in QB64 v 2.0
« Last Edit: October 27, 2021, 07:13:50 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: and another one for your toolbox...
« Reply #4 on: July 31, 2019, 07:39:09 am »
Here's one I think all toolboxes should have (if bplus doesn't mind me adding to his collection here):

Code: [Select]
SUB SubState (toggle)
    STATIC DefaultColor, BackGroundColor, Font, Dest, Source
    IF toggle THEN
        _FONT Font
        COLOR DefaultColor, BackGroundColor
        _DEST Dest
        _SOURCE Source
    ELSE
        Font = _FONT
        DefaultColor = _DEFAULTCOLOR
        BackGroundColor = _BACKGROUNDCOLOR
        Dest = _DEST
        Source = _SOURCE
    END IF
END SUB

When writing a lot of subs, I've found that a majority of them tend to require the same things at the top and bottom of them so that they play nicely with my main routines -- a means to save the main program state and then restore it upon exit.

For example:

Code: QB64: [Select]
  1. SUB QPrint (x, y, kolor, text$)
  2.    LOCATE x,y
  3.    COLOR kolor
  4.    PRINT text$

Now, the above SUB isn't very library friendly, and it's a PITA to plug into most programs.  It changes the default color that we we're printing with when we entered the sub, and it's now something completely different when we exit the sub.  It just doesn't play nice with others.

So how to fix that?


Code: QB64: [Select]
  1. SUB QPrint (x, y, kolor, text$)
  2.    SubState 1
  3.    LOCATE x,y
  4.    COLOR kolor
  5.    PRINT text$
  6.    SubState 0

Note:  This version of SubState isn't for use with recursive routines, or for routines which call others which alter default values on us.  If you guys are interested in it, I'll share it as well for you.  Use this for quick save/exit routines for single call SUB/FUNCTION as illustrated above.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: and another one for your toolbox...
« Reply #5 on: July 31, 2019, 08:22:35 am »
Thanks Steve that's a great idea.

Here is the tail end (currently, it keeps needing more things) to my mBox (messageBox) sub and inputBox sub:
Code: QB64: [Select]
  1.     'put things back
  2.     COLOR _RGB32(255, 255, 255), _RGB32(0, 0, 0): CLS
  3.     _PUTIMAGE , backScrn
  4.     _DISPLAY
  5.     COLOR fg, bg
  6.     _FREEIMAGE backScrn
  7.     _FREEIMAGE mbx
  8.     'clear key presses
  9.     _KEYCLEAR
  10.     LOCATE curRow, curCol
  11.     'clear mouse clicks
  12.     mb = _MOUSEBUTTON(1)
  13.     IF mb THEN
  14.         DO
  15.             WHILE _MOUSEINPUT: WEND
  16.             mb = _MOUSEBUTTON(1)
  17.             _LIMIT 100
  18.         LOOP UNTIL mb = 0
  19.     END IF
  20.  

I was wondering if I was missing more items. I did not do _FONT nor _SOURCE but I do put back row and col, and _AUTODISPLAY / _DISPLAY setting and found the need to clear both mouse click and key press (esc or enter mainly need to be cleared so main program isn't short circuited).

Collecting all these settings and then putting them back really distracts from the code for the procedure, so this could be very useful to use with tool box procedures. Thanks again, I will put a version of this in my toolbox.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: and another one for your toolbox...
« Reply #6 on: July 31, 2019, 08:57:28 am »
MessageBox sub that you can drag around the screen called: mBox title$, message$
(Employs a scnState sub discussed earlier in this thread suggested by SMcNeill.)


Speaking of message Box here is my current version which I updated recently with better mouse button clear (I think) and adding of _DISPLAY / _AUTODISPLAY resets.

The advantage is you don't need Windows and since it is Tool Box code and not Library code, you can copy / paste into your program and are free to modify to needs of program eg, you won't like my colors for message box (I don't like my colors) but you are free to change to fit program you are using message box in. Trying to anticipate every mod change that might be needed for message box turns it into a complex Swiss Army Knife too awkward to be of practical use IMO. So this has the simple parameters of Title$ and message$:

Code: QB64: [Select]
  1. '
  2. ' 2019-05-18 new version of mBox developed from scrollWindow test code (Array Window.bas)
  3. ' hmm... old version saved curRow and curCol ? put back in
  4. ' new version clears mouse clicks
  5.  
  6. ' 2019-07-25  save _autodisplay setting and set it back before leaving, rework clearing mb
  7. 'test #1 does message box work in screen 0
  8. 'mBox "Well?", "Test mBox in Screen 0"    NO! for graphic screens ONLY!!!
  9.  
  10. '2019-07-31 attempt to assimulate Steve's idea for saving and restoring the screen state
  11. ' before a sub messes with all the settings, so in future mBox and inputBox$ will need this
  12. ' helper sub. Damn the fan is back!  Also fix this to make it easier to change colors.
  13. ' OK tests here now try scrollWindow and Geometry Circle Intersects...
  14.  
  15. SCREEN _NEWIMAGE(800, 600, 32)
  16. _SCREENMOVE 100, 20
  17.  
  18. DIM m$, enter$, k$, kh AS LONG, mNum AS INTEGER
  19. COLOR &HFF000000, &HFF888888
  20. PRINT "REMINDER: press escape, enter or spacebar to exit the message box. Escape (again?) to exit this test."
  21. PRINT "Here is some stuff on screen."
  22.  
  23. m$ = "This is the message for mBox in 800x 600 _NEWIMAGE setup, "
  24. m$ = m$ + "how does it handle a long line?   Yeah! grab title bar and move this box around!" 'great
  25. mBox "This is Demo Title", m$
  26.  
  27. PRINT "here is more stuff, is it printing exactly below last stuff?" ' OK now with center fix too!
  28. INPUT "For next test [h | m] for mBox, [esc | space | enter] to quit it and then [esc] again to quit, enter for next test...", enter$
  29.  
  30. 'draw stuff, until h or m press, then show message box
  31.  
  32.     k$ = INKEY$
  33.     IF k$ = "m" OR k$ = "h" THEN doMessage: mNum = mNum + 1: PRINT mNum; "Message done..."
  34.     kh = 0
  35.     LINE (RND * _WIDTH, RND * _HEIGHT)-STEP(RND * 80, RND * 60), _RGB32(RND * 255, RND * 255, RND * 255), BF
  36.     kh = _KEYHIT
  37.     IF kh = 27 THEN EXIT WHILE
  38.     ' _DISPLAY  '<<<< comment out to see if _AUTODISPLAY mode, yep! good
  39.     _LIMIT 60
  40. PRINT "OK where is this print line going to end up, hopefully under the last '# message done'." 'yes! Excellent!
  41.  
  42. SUB doMessage
  43.     DIM title$, mess$
  44.     mess$ = "This is line 1 followed by LF" + CHR$(10)
  45.     mess$ = mess$ + "This is line 2 followed by CR + LF" + CHR$(13) + CHR$(10)
  46.     mess$ = mess$ + "Line 3 is followed by a double LF to make a space." + CHR$(10) + CHR$(10)
  47.     mess$ = mess$ + "Here is a long line that hopefully won't all fit across the screen, so I just keep going on and on ..."
  48.     mess$ = mess$ + "until the screen is half full of this single long, long line so I can test the wrapping my code does "
  49.     mess$ = mess$ + "with this long thing! ending with a double CR." + CHR$(13) + CHR$(13)
  50.     mess$ = mess$ + CHR$(9) + "This line started with a tab which should be replaced by spaces so now this line should be running too long. The End."
  51.     title$ = "123456789012345678901234567890123456789012345678901234567890"
  52.     mBox title$, mess$
  53.  
  54. 'title$ limit is 57 chars, all lines are 58 chars max, version 2019-07-31
  55. 'THIS SUB NOW NEEDS SUB scnState(restoreTF) for saving and restoring screen settings
  56. SUB mBox (title AS STRING, m AS STRING)
  57.  
  58.     bg = &H33404040
  59.     fg = &HFF33AAFF
  60.  
  61.     'first screen dimensions and items to restore at exit
  62.     DIM sw AS INTEGER, sh AS INTEGER
  63.     DIM curScrn AS LONG, backScrn AS LONG, mbx AS LONG 'some handles
  64.     DIM ti AS INTEGER, limit AS INTEGER 'ti = text index for t$(), limit is number of chars per line
  65.     DIM i AS INTEGER, j AS INTEGER, ff AS _BIT, add AS _BYTE 'index, flag and
  66.     DIM bxH AS INTEGER, bxW AS INTEGER 'first as cells then as pixels
  67.     DIM mb AS INTEGER, mx AS INTEGER, my AS INTEGER, mi AS INTEGER, grabx AS INTEGER, graby AS INTEGER
  68.     DIM tlx AS INTEGER, tly AS INTEGER 'top left corner of message box
  69.     DIM lastx AS INTEGER, lasty AS INTEGER, t AS STRING, b AS STRING, c AS STRING, tail AS STRING
  70.     DIM d AS STRING, r AS SINGLE, kh AS LONG
  71.  
  72.     'screen and current settings to restore at end ofsub
  73.     scnState 0
  74.     sw = _WIDTH: sh = _HEIGHT
  75.  
  76.     _KEYCLEAR '<<<<<<<<<<<<<<<<<<<< do i still need this?   Yes 2019-08-06
  77.  
  78.     'screen snapshot
  79.     curScrn = _DEST
  80.     backScrn = _NEWIMAGE(sw, sh, 32)
  81.     _PUTIMAGE , curScrn, backScrn
  82.  
  83.     'setup t() to store strings with ti as index, linit 58 chars per line max, b is for build
  84.     REDIM t(0) AS STRING: ti = 0: limit = 58: b = ""
  85.     FOR i = 1 TO LEN(m)
  86.         c = MID$(m, i, 1)
  87.         'are there any new line signals, CR, LF or both? take CRLF or LFCR as one break but dbl LF or CR means blank line
  88.         SELECT CASE c
  89.             CASE CHR$(13) 'load line
  90.                 IF MID$(m, i + 1, 1) = CHR$(10) THEN i = i + 1
  91.                 t(ti) = b: b = "": ti = ti + 1: REDIM _PRESERVE t(ti) AS STRING
  92.             CASE CHR$(10)
  93.                 IF MID$(m, i + 1, 1) = CHR$(13) THEN i = i + 1
  94.                 t(ti) = b: b = "": ti = ti + 1: REDIM _PRESERVE t(ti)
  95.             CASE ELSE
  96.                 IF c = CHR$(9) THEN c = SPACE$(4): add = 4 ELSE add = 1
  97.                 IF LEN(b) + add > limit THEN
  98.                     tail = "": ff = 0
  99.                     FOR j = LEN(b) TO 1 STEP -1 'backup until find a space, save the tail end for next line
  100.                         d = MID$(b, j, 1)
  101.                         IF d = " " THEN
  102.                             t(ti) = MID$(b, 1, j - 1): b = tail + c: ti = ti + 1: REDIM _PRESERVE t(ti)
  103.                             ff = 1 'found space flag
  104.                             EXIT FOR
  105.                         ELSE
  106.                             tail = d + tail 'the tail grows!
  107.                         END IF
  108.                     NEXT
  109.                     IF ff = 0 THEN 'no break? OK
  110.                         t(ti) = b: b = c: ti = ti + 1: REDIM _PRESERVE t(ti)
  111.                     END IF
  112.                 ELSE
  113.                     b = b + c 'just keep building the line
  114.                 END IF
  115.         END SELECT
  116.     NEXT
  117.     t(ti) = b
  118.     bxH = ti + 3: bxW = limit + 2
  119.  
  120.     'draw message box
  121.     mbx = _NEWIMAGE(60 * 8, (bxH + 1) * 16, 32)
  122.     _DEST mbx
  123.     COLOR _RGB32(128, 0, 0), _RGB32(225, 225, 255)
  124.     LOCATE 1, 1: PRINT LEFT$(SPACE$((bxW - LEN(title) - 3) / 2) + title + SPACE$(bxW), bxW)
  125.     COLOR _RGB32(225, 225, 255), _RGB32(200, 0, 0)
  126.     LOCATE 1, bxW - 2: PRINT " X "
  127.     COLOR fg, bg
  128.     LOCATE 2, 1: PRINT SPACE$(bxW);
  129.     FOR r = 0 TO ti
  130.         LOCATE 1 + r + 2, 1: PRINT LEFT$(" " + t(r) + SPACE$(bxW), bxW);
  131.     NEXT
  132.     LOCATE 1 + bxH, 1: PRINT SPACE$(limit + 2);
  133.  
  134.     'now for the action
  135.     _DEST curScrn
  136.  
  137.     'convert to pixels the top left corner of box at moment
  138.     bxW = bxW * 8: bxH = bxH * 16
  139.     tlx = (sw - bxW) / 2: tly = (sh - bxH) / 2
  140.     lastx = tlx: lasty = tly
  141.     'now allow user to move it around or just read it
  142.     WHILE 1
  143.         CLS
  144.         _PUTIMAGE , backScrn
  145.         _PUTIMAGE (tlx, tly), mbx, curScrn
  146.         _DISPLAY
  147.         WHILE _MOUSEINPUT: WEND
  148.         mx = _MOUSEX: my = _MOUSEY: mb = _MOUSEBUTTON(1)
  149.         IF mb THEN
  150.             IF mx >= tlx AND mx <= tlx + bxW AND my >= tly AND my <= tly + 16 THEN 'mouse down on title bar
  151.                 IF mx >= tlx + bxW - 24 THEN EXIT WHILE
  152.                 grabx = mx - tlx: graby = my - tly
  153.                 DO WHILE mb 'wait for release
  154.                     mi = _MOUSEINPUT: mb = _MOUSEBUTTON(1)
  155.                     mx = _MOUSEX: my = _MOUSEY
  156.                     IF mx - grabx >= 0 AND mx - grabx <= sw - bxW AND my - graby >= 0 AND my - graby <= sh - bxH THEN
  157.                         'attempt to speed up with less updates
  158.                         IF ((lastx - (mx - grabx)) ^ 2 + (lasty - (my - graby)) ^ 2) ^ .5 > 10 THEN
  159.                             tlx = mx - grabx: tly = my - graby
  160.                             CLS
  161.                             _PUTIMAGE , backScrn
  162.                             _PUTIMAGE (tlx, tly), mbx, curScrn
  163.                             lastx = tlx: lasty = tly
  164.                             _DISPLAY
  165.                         END IF
  166.                     END IF
  167.                     _LIMIT 400
  168.                 LOOP
  169.             END IF
  170.         END IF
  171.         kh = _KEYHIT
  172.         IF kh = 27 OR kh = 13 OR kh = 32 THEN EXIT WHILE
  173.         _LIMIT 400
  174.     WEND
  175.  
  176.     'put things back
  177.     COLOR _RGB32(255, 255, 255), _RGB32(0, 0, 0): CLS '
  178.     _PUTIMAGE , backScrn
  179.     _DISPLAY
  180.     _FREEIMAGE backScrn
  181.     _FREEIMAGE mbx
  182.     scnState 1 'Thanks Steve McNeill
  183.  
  184. ' for saving and restoring screen settins
  185. SUB scnState (restoreTF AS INTEGER) 'Thanks Steve McNeill
  186.     STATIC Font AS LONG, DefaultColor AS _UNSIGNED LONG, BackGroundColor AS _UNSIGNED LONG, Dest AS LONG, Source AS LONG
  187.     STATIC row AS INTEGER, col AS INTEGER, autodisplay AS INTEGER, mb AS INTEGER
  188.     IF restoreTF THEN
  189.         _FONT Font
  190.         COLOR DefaultColor, BackGroundColor
  191.         _DEST Dest
  192.         _SOURCE Source
  193.         LOCATE row, col
  194.         IF autodisplay THEN _AUTODISPLAY ELSE _DISPLAY
  195.         _KEYCLEAR
  196.         WHILE _MOUSEINPUT: WEND 'clear mouse clicks
  197.         mb = _MOUSEBUTTON(1)
  198.         IF mb THEN
  199.             DO
  200.                 WHILE _MOUSEINPUT: WEND
  201.                 mb = _MOUSEBUTTON(1)
  202.                 _LIMIT 100
  203.             LOOP UNTIL mb = 0
  204.         END IF
  205.     ELSE
  206.         Font = _FONT: DefaultColor = _DEFAULTCOLOR: BackGroundColor = _BACKGROUNDCOLOR
  207.         Dest = _DEST: Source = _SOURCE
  208.         row = CSRLIN: col = POS(0): autodisplay = _AUTODISPLAY
  209.     END IF
  210.  
  211.  

This will be soon be modified with my version of Steve's new subState (toggle) along with InputBox$

Update: 2019-07-31 11AM: OK modified with more complete srnState(restoreTF) SUB as promised but I see now Steve has improved his further into two SUBs, sheez hard to keep up! I also made it easier to modify colors in mBox sub, see fg, bg settings at top of sub for foreground and background.

Anyway mBox works well and tested in a couple of programs from which I caught bugs earlier:
 
mBox Test as Help for array scroller sub.PNG

Here I try semi-transparent background in mBox SUB.


2019-08-06 Update: _KEYCLEAR was needed when starting mBox, I found the test code that proved it.
comment removed from this line:
_KEYCLEAR '<<<<<<<<<<<<<<<<<<<< do i still need this?
« Last Edit: September 12, 2020, 02:55:19 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: and another one for your toolbox...
« Reply #7 on: July 31, 2019, 09:52:59 am »
And, as promised, here's my expanded routines to save states:

Code: [Select]
SCREEN _NEWIMAGE(120, 25, 0)

PRINT "Currently my print cursor is here =>";
SLEEP
QPrint 10, 10, 4, "Then I jump to 10,10"
SLEEP
PRINT "But I'm still here! =>";
SLEEP
RQPrint 3, 3, 1, "Hello World"
SLEEP
PRINT "And, even after all the recursive work, I'm still here!!"




SUB QPrint (y, x, kolor, text$)
    s = SaveState
    LOCATE x, y
    COLOR kolor
    PRINT text$
    RestoreState s
END SUB

SUB RQPrint (y, x, kolor, text$)
    s = SaveState
    IF kolor < 15 THEN RQPrint x + 1, y + 1, kolor + 1, text$ + "."
    LOCATE x, y
    COLOR kolor
    PRINT text$
    RestoreState s
END SUB




FUNCTION SaveState
    TYPE SaveStateType
        InUse AS INTEGER
        DC AS INTEGER
        BG AS INTEGER
        F AS INTEGER
        D AS INTEGER
        S AS INTEGER
        Disp AS INTEGER
        CurX AS INTEGER
        CurY AS INTEGER
    END TYPE
    DIM SS AS SaveStateType, Temp AS SaveStateType
    SHARED NSS AS LONG 'Number of Saved States
    SHARED SaveMem AS _MEM
    IF _MEMEXISTS(SaveMem) THEN
        'do nothing
    ELSE
        SaveMem = _MEMNEW(LEN(SS) * 255) 'Save up to 255 save states; More than 255 and we toss an error
        $CHECKING:OFF
        _MEMFILL SaveMem, SaveMem.OFFSET, SaveMem.SIZE, 0 AS _UNSIGNED _BYTE
        $CHECKING:ON
    END IF

    'Data to Save
    SS.InUse = -1
    SS.F = _FONT
    SS.DC = _DEFAULTCOLOR
    SS.BG = _BACKGROUNDCOLOR
    SS.D = _DEST
    SS.S = _SOURCE
    SS.Disp = _AUTODISPLAY
    SS.CurX = POS(0)
    SS.CurY = CSRLIN
    $CHECKING:OFF
    FOR i = 1 TO NSS
        o = (i - 1) * LEN(SS)
        _MEMGET SaveMem, SaveMem.OFFSET + o, Temp
        IF Temp.InUse = 0 THEN
            _MEMPUT SaveMem, SaveMem.OFFSET + o, SS
            SaveState = i
            EXIT FUNCTION
        END IF
    NEXT
    _MEMPUT SaveMem, SaveMem.OFFSET + NSS * LEN(SS), SS
    $CHECKING:ON
    NSS = NSS + 1
    SaveState = NSS
END SUB

SUB RestoreState (WhichOne)
    DIM SS AS SaveStateType
    SHARED NSS AS LONG 'Number of Saved States
    SHARED SaveMem AS _MEM
    $CHECKING:ON
    _MEMGET SaveMem, SaveMem.OFFSET + (WhichOne - 1) * LEN(SS), SS
    IF SS.InUse THEN
        SS.InUse = 0 'Let the routine know that we're no longer in use for this handle
        _MEMPUT SaveMem, SaveMem.OFFSET + (WhichOne - 1) * LEN(SS), SS
        _FONT SS.F
        COLOR SS.DC, SS.BG
        _DEST SS.D
        _SOURCE SS.S
        IF SS.Disp THEN _AUTODISPLAY ELSE _DISPLAY
        LOCATE SS.CurY, SS.CurX
    END IF
    $CHECKING:ON
END SUB

Notice here that we get a handle for a saved state, and then when we exit the sub we restore that handle.  This allows us to have one sub call another sub, or recursively call itself, and yet preserves the original information without any problem for us.

One thing to note with this method:  Just like GOSUB can run out of stack space if you call them and exit without using RETURN, this also has a limit of 255 states being saved at a time.  IMHO, that's more than enough for any program I write, unless I've got a glitch somewhere where I'm exiting the sub/function without restoring values. (In which case, I've created a memory leak, and I'd want to find it and fix it anyway...)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: and another one for your toolbox...
« Reply #8 on: July 31, 2019, 11:32:45 am »
Hi Steve,

You know I just started wondering about multiple mBox windows going... how the setting for different windows up might be saved. You anticipated that.

But what happens if you close the windows / screens out of the order they were opened? You would be restoring the wrong settings. Or what happens should any of the other screens start messing with the their settings in between.

Might be a can or worms here, unless keep everything modal.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: and another one for your toolbox...
« Reply #9 on: July 31, 2019, 12:00:10 pm »
Sometimes you just have to do things manually.

Let’s say I have a red screen and print stuff on it.

Now, open a green box in the center of it, and preserve the background so you can restore it later.

Now, open a blue box in the center of that one, and preserve the background so you can restore it later.

If you close the blue box, then the green box, your background will go back to looking as it originally did.

If you close the green box first, then the blue box, your background is now red, with a green box where the blue one used to be.  (You restored the original background when you closed the green box, but closing the blue box put the background behind it — the part of the green box it covered up — back onto the screen.)

As long as you call the routines and exit the routines in order, all is good.  If they’re going to be truly “independent boxes” and not “pop-up boxes” which require closing them in order, then sequentially stacking settings won’t be possible.  You’re looking at Z-order style handling at that point, which is a bit more than the routines above handle.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
Re: and another one for your toolbox...
« Reply #10 on: July 31, 2019, 12:16:24 pm »
We seem to have encountered the same problem that I solved, BPlus. When opening multiple windows, I enter a number in the TYPE field that indicates in which order this  window is  (it is added by _PRESERVE to the window field and at start this number is the same as the record number in the window field). When this window is clicked, the window display order for all windows is changed from the window number. Try the following code. More  complicated code is in objecteditor, which develop version will be released as soon as possible. There is solved also window positioning.

Example for four windows.
Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1800, 1600, 256)
  2. DIM x(4), y(4), position(1 TO 4)
  3. g = 1
  4. FOR f = 0 TO 1350 STEP 450
  5.     x(g) = f
  6.     g = g + 1
  7. g = 1
  8. FOR f = 0 TO 1200 STEP 400
  9.     y(g) = f
  10.     g = g + 1
  11. FOR N = 1 TO 4
  12.     position(N) = N
  13.     FOR d = 1 TO 4
  14.         LINE (x(d), y(d))-(x(d) + 400, y(d) + 350), , B
  15.         _PRINTSTRING (x(d), y(d)), STR$(position(d))
  16.         IF _MOUSEX >= x(d) AND _MOUSEX <= x(d) + 400 THEN
  17.             IF _MOUSEY >= x(y) AND _MOUSEY <= y(d) + 350 THEN
  18.                 IF _MOUSEBUTTON(1) THEN
  19.                     old = position(d)
  20.                     IF position(d) <> 1 THEN
  21.                         position(d) = 1
  22.                         FOR R = 1 TO 4
  23.                             IF R <> d THEN
  24.                                 position(R) = position(R) + 1
  25.                                 IF position(R) > 4 THEN position(R) = old + 1
  26.                             END IF
  27.                         NEXT
  28.                     END IF
  29.                 END IF
  30.             END IF
  31.         END IF
  32.     NEXT
  33.  

Previous code show you windows positions.

For correct view on screen then use Window nr.1 as UBOUND next array, Window nr.2 as second,  Window nr.3 as third and Window with nr.4 as last - LBOUND.

For correct view on screen then just use

FOR ViewIt = Lbound(WindowArray) Ubound(WindowArray)
....
....
graphic operations
NEXT

As you see, UBOUND is last, so window nr.1 as UBOUND in array is always on top.


And you get the answer to the question - what if I close the window in a different order? Window numbers are reduced by one, minimized, or closed is deleted from the field FOR VIEW (so I suggest using an extra field only for window rendering and another field with window position, text, and so on) (so there will only be three), the same loop  render it. There will be another graphic loop below the windows that will not be overwritten by the window array at this location if the window is closed before calling _DISPLAY. Pseudocode:

Loop for background drawing on screen
Loop for rendering windows
_DISPLAY

This way you can make transparent windows, behind which will run  - spiders :).
« Last Edit: July 31, 2019, 01:02:25 pm by Petr »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: and another one for your toolbox...
« Reply #11 on: July 31, 2019, 01:52:54 pm »
Hi Petr,

You guys and your giant screens! Your demo does not fit my screen but OK because I am totally unprepared to take on a Windows management discussion in this thread. For this thread I have other fish to fry... ;-))

Good to know, you have worked on this problem though and are ready with help. Also I am so proud that spiders made such on impression on you! :)

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
Re: and another one for your toolbox...
« Reply #12 on: July 31, 2019, 02:00:26 pm »
Yes BPlus, Spiders are perfect. I hope I understood the topic correctly and did not respond quite badly? If so, just say it and I delete the post, I don't want to spam your tools thread.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: and another one for your toolbox...
« Reply #13 on: July 31, 2019, 07:33:11 pm »
Yes BPlus, Spiders are perfect. I hope I understood the topic correctly and did not respond quite badly? If so, just say it and I delete the post, I don't want to spam your tools thread.

Hi Petr, you are fine coder, no way a spammer!

To all,

Here is the a complementary tool to mBox that I wanted to get posted with mBox, inputBox$.

This lets you get some information from user without any disturbance of the screen. Like mBox you can grab the title bar and move it around the screen.

I combined that with cText, a way to print any size text around the midpoint x, y and overhauled the Top Ten screen used in Invaders bplus style.

inputBox$ and demo:
Code: QB64: [Select]
  1. _TITLE "inputBox$ tester.bas started 2018-10-26 need an input box for WS Editor"
  2. ' 2019-07-32 assimulate scnState(restoreTF) used to save and restore screen settings
  3. ' so sub can do it's thing and restore settings, Thanks Steve McNeill for starter code and idea.
  4.  
  5. SCREEN _NEWIMAGE(800, 600, 32)
  6. _SCREENMOVE 100, 20
  7. DIM well$, enter$, k$, kh AS LONG
  8.  
  9. COLOR &HFFFFFF00, &HFF880000
  10. PRINT "Here is some stuff on screen."
  11. well$ = inputBox$("Well?", "Test inputBox$", 20)
  12. PRINT "inputBox$ returned: "; well$; ". Is this line printing exactly below last stuff sentence?" ' OK now with center fix too!
  13. INPUT "OK? enter for next test, use h or m keypress to invoke inputBox$...", enter$
  14.  
  15. 'draw stuff, until h or m press, then show message box
  16.     k$ = INKEY$
  17.     IF k$ = "m" OR k$ = "h" THEN
  18.         well$ = inputBox$("Well?", "Test call inputBox", 36)
  19.         PRINT "inputBox$() returned: *"; well$; "*"
  20.     END IF
  21.     'kh = 0  'should not need this to stop esc keypress in input box
  22.     LINE (RND * _WIDTH, RND * _HEIGHT)-STEP(RND * 80, RND * 60), _RGB32(RND * 255, RND * 255, RND * 255), BF
  23.     kh = _KEYHIT
  24.     IF kh = 27 THEN EXIT WHILE
  25.     '_DISPLAY   '<< should not need this
  26.     _LIMIT 5
  27. PRINT "OK where is this print line going to end up, hopefully under the last inputBox returned." 'yes! Excellent!
  28. PRINT "InputBox$() last returned: "; well$; ",  Goodbye!"
  29.  
  30. ' You can grab this box by title and drag it around screen for full viewing while answering prompt.
  31. ' Only one line allowed for prompt$
  32. ' boxWidth is 4 more than the allowed length of input, it needs to be longer than title$ and prompt$ also
  33. ' Utilities > Input Box > Input Box 1 tester v 2019-07-31
  34. FUNCTION inputBox$ (prompt$, title$, boxWidth AS _BYTE)
  35.     DIM ForeColor AS _UNSIGNED LONG, BackColor AS _UNSIGNED LONG, White AS _UNSIGNED LONG
  36.     DIM sw AS INTEGER, sh AS INTEGER, curScrn AS LONG, backScrn AS LONG, ibx AS LONG 'some handles
  37.  
  38.     'colors
  39.     ForeColor = &HFF000055 '<  change as desired  prompt text color, back color or type in area
  40.     BackColor = &HFF6080CC '<  change as desired  used fore color in type in area
  41.     White = &HFFFFFFFF
  42.  
  43.     'items to restore at exit
  44.     scnState 0
  45.  
  46.     'screen snapshot
  47.     sw = _WIDTH: sh = _HEIGHT: curScrn = _DEST
  48.     backScrn = _NEWIMAGE(sw, sh, 32)
  49.     _PUTIMAGE , curScrn, backScrn
  50.  
  51.     'moving box around on screen
  52.     DIM bxW AS INTEGER, bxH AS INTEGER
  53.     DIM mb AS INTEGER, mx AS INTEGER, my AS INTEGER, mi AS INTEGER, grabx AS INTEGER, graby AS INTEGER
  54.     DIM tlx AS INTEGER, tly AS INTEGER 'top left corner of message box
  55.     DIM lastx AS INTEGER, lasty AS INTEGER
  56.     DIM inp$, kh&
  57.  
  58.     'draw message box
  59.     bxW = boxWidth * 8: bxH = 7 * 16
  60.     ibx = _NEWIMAGE(bxW, bxH, 32)
  61.     _DEST ibx
  62.     COLOR &HFF880000, White
  63.     LOCATE 1, 1: PRINT LEFT$(SPACE$(INT((boxWidth - LEN(title$) - 3)) / 2) + title$ + SPACE$(boxWidth), boxWidth)
  64.     COLOR White, &HFFBB0000
  65.     LOCATE 1, boxWidth - 2: PRINT " X "
  66.     COLOR ForeColor, BackColor
  67.     LOCATE 2, 1: PRINT SPACE$(boxWidth);
  68.     LOCATE 3, 1: PRINT LEFT$(SPACE$((boxWidth - LEN(prompt$)) / 2) + prompt$ + SPACE$(boxWidth), boxWidth);
  69.     LOCATE 4, 1: PRINT SPACE$(boxWidth);
  70.     LOCATE 5, 1: PRINT SPACE$(boxWidth);
  71.     LOCATE 6, 1: PRINT SPACE$(boxWidth);
  72.     inp$ = ""
  73.     GOSUB finishBox
  74.  
  75.     'convert to pixels the top left corner of box at moment
  76.     bxW = boxWidth * 8: bxH = 5 * 16
  77.     tlx = (sw - bxW) / 2: tly = (sh - bxH) / 2
  78.     lastx = tlx: lasty = tly
  79.     _KEYCLEAR
  80.     'now allow user to move it around or just read it
  81.     WHILE 1
  82.         CLS
  83.         _PUTIMAGE , backScrn
  84.         _PUTIMAGE (tlx, tly), ibx, curScrn
  85.         _DISPLAY
  86.         WHILE _MOUSEINPUT: WEND
  87.         mx = _MOUSEX: my = _MOUSEY: mb = _MOUSEBUTTON(1)
  88.         IF mb THEN
  89.             IF mx >= tlx AND mx <= tlx + bxW AND my >= tly AND my <= tly + 16 THEN 'mouse down on title bar
  90.                 IF mx >= tlx + bxW - 24 THEN EXIT WHILE
  91.                 grabx = mx - tlx: graby = my - tly
  92.                 DO WHILE mb 'wait for release
  93.                     mi = _MOUSEINPUT: mb = _MOUSEBUTTON(1)
  94.                     mx = _MOUSEX: my = _MOUSEY
  95.                     IF mx - grabx >= 0 AND mx - grabx <= sw - bxW AND my - graby >= 0 AND my - graby <= sh - bxH THEN
  96.                         'attempt to speed up with less updates
  97.                         IF ((lastx - (mx - grabx)) ^ 2 + (lasty - (my - graby)) ^ 2) ^ .5 > 10 THEN
  98.                             tlx = mx - grabx: tly = my - graby
  99.                             CLS
  100.                             _PUTIMAGE , backScrn
  101.                             _PUTIMAGE (tlx, tly), ibx, curScrn
  102.                             lastx = tlx: lasty = tly
  103.                             _DISPLAY
  104.                         END IF
  105.                     END IF
  106.                     _LIMIT 400
  107.                 LOOP
  108.             END IF
  109.         END IF
  110.         kh& = _KEYHIT
  111.         SELECT CASE kh& 'whew not much for the main event!
  112.             CASE 13: EXIT WHILE
  113.             CASE 27: inp$ = "": EXIT WHILE
  114.             CASE 32 TO 128: IF LEN(inp$) < boxWidth - 4 THEN inp$ = inp$ + CHR$(kh&): GOSUB finishBox ELSE BEEP
  115.             CASE 8: IF LEN(inp$) THEN inp$ = LEFT$(inp$, LEN(inp$) - 1): GOSUB finishBox ELSE BEEP
  116.         END SELECT
  117.  
  118.         _LIMIT 60
  119.     WEND
  120.  
  121.     'put things back
  122.     scnState 1 'need fg and bg colors set to cls
  123.     CLS '? is this needed YES!!
  124.     _PUTIMAGE , backScrn
  125.     _DISPLAY
  126.     _FREEIMAGE backScrn
  127.     _FREEIMAGE ibx
  128.     scnState 1 'because we have to call _display, we have to call this again
  129.     inputBox$ = inp$
  130.  
  131.     finishBox:
  132.     _DEST ibx
  133.     COLOR BackColor, ForeColor
  134.     LOCATE 5, 2: PRINT LEFT$(" " + inp$ + SPACE$(boxWidth - 2), boxWidth - 2)
  135.     _DEST curScrn
  136.     RETURN
  137.  
  138. 'from mBox v 2019-07-31 update
  139. ' for saving and restoring screen settins
  140. SUB scnState (restoreTF AS INTEGER) 'Thanks Steve McNeill
  141.     STATIC Font AS LONG, DefaultColor AS _UNSIGNED LONG, BackGroundColor AS _UNSIGNED LONG, Dest AS LONG, Source AS LONG
  142.     STATIC row AS INTEGER, col AS INTEGER, autodisplay AS INTEGER, mb AS INTEGER
  143.     IF restoreTF THEN
  144.         _FONT Font
  145.         COLOR DefaultColor, BackGroundColor
  146.         _DEST Dest
  147.         _SOURCE Source
  148.         LOCATE row, col
  149.         IF autodisplay THEN _AUTODISPLAY ELSE _DISPLAY
  150.         _KEYCLEAR
  151.         WHILE _MOUSEINPUT: WEND 'clear mouse clicks
  152.         mb = _MOUSEBUTTON(1)
  153.         IF mb THEN
  154.             DO
  155.                 WHILE _MOUSEINPUT: WEND
  156.                 mb = _MOUSEBUTTON(1)
  157.                 _LIMIT 100
  158.             LOOP UNTIL mb = 0
  159.         END IF
  160.     ELSE
  161.         Font = _FONT: DefaultColor = _DEFAULTCOLOR: BackGroundColor = _BACKGROUNDCOLOR
  162.         Dest = _DEST: Source = _SOURCE
  163.         row = CSRLIN: col = POS(0): autodisplay = _AUTODISPLAY
  164.     END IF
  165.  
  166.  

Here is cText, text and demo:
Code: QB64: [Select]
  1. _TITLE "Text sub tests" 'B+ started 2019-03-25
  2.  
  3. CONST xmax = 1200
  4. CONST ymax = 700
  5.  
  6. SCREEN _NEWIMAGE(xmax, ymax, 32)
  7. _SCREENMOVE 100, 40
  8.  
  9. DIM y, i
  10.  
  11. COLOR _RGB32(0, 0, 255)
  12. PRINT "Hello World"
  13. 'test& = _NEWIMAGE(xmax, ymax, 32)
  14. 'DEST test&
  15. y = ymax
  16. FOR i = 1 TO 60 STEP .5
  17.     CLS
  18.     y = y - 60 / i
  19.     cText xmax / 2, y, 240 / i, _RGB32(255, 0, 0), "So how is this looking?"
  20.     _DISPLAY
  21.     _LIMIT 5
  22. '_DEST 0
  23. '_PUTIMAGE , test&, 0
  24. PRINT "OK, blue?"
  25.  
  26. SUB Text (x, y, textHeight, K AS _UNSIGNED LONG, txt$)
  27.     DIM fg AS _UNSIGNED LONG, cur&, I&, mult, xlen
  28.     fg = _DEFAULTCOLOR
  29.     'screen snapshot
  30.     cur& = _DEST
  31.     I& = _NEWIMAGE(8 * LEN(txt$), 16, 32)
  32.     _DEST I&
  33.     COLOR K, _RGBA32(0, 0, 0, 0)
  34.     _PRINTSTRING (0, 0), txt$
  35.     mult = textHeight / 16
  36.     xlen = LEN(txt$) * 8 * mult
  37.     _PUTIMAGE (x, y)-STEP(xlen, textHeight), I&, cur&
  38.     COLOR fg
  39.     _FREEIMAGE I&
  40.  
  41. 'center the text
  42. SUB cText (x, y, textHeight, K AS _UNSIGNED LONG, txt$)
  43.     DIM fg AS _UNSIGNED LONG, cur&, I&, mult, xlen
  44.     fg = _DEFAULTCOLOR
  45.     'screen snapshot
  46.     cur& = _DEST
  47.     I& = _NEWIMAGE(8 * LEN(txt$), 16, 32)
  48.     _DEST I&
  49.     COLOR K, _RGBA32(0, 0, 0, 0)
  50.     _PRINTSTRING (0, 0), txt$
  51.     mult = textHeight / 16
  52.     xlen = LEN(txt$) * 8 * mult
  53.     _PUTIMAGE (x - .5 * xlen, y - .5 * textHeight)-STEP(xlen, textHeight), I&, cur&
  54.     COLOR fg
  55.     _FREEIMAGE I&
  56.  
  57.  

Here is topTenGoAgain$ code and tester reworked with cText and inputBox$:
Code: QB64: [Select]
  1. _TITLE "Top Ten mod with cText tester" ' B+ started 2019-07-31
  2. '2019-07-28 All enclosed in a sub, possible feed it score and see how it stacks up.
  3. '2019-07-28 fix to fill all 10 slots.
  4. '2019-07-29 2nd fix with an n > 10 check, change to a function and get GoAgain reply.
  5. '2019-07-31 modify Top Ten Screen with cText and inputBox$
  6. ' 1. to make it look better, 2
  7. ' 2. for demo in thread "another one for the tool box"
  8. ' 3. improve Invaders look
  9. ' 4. test new revsions to inputBox$
  10.  
  11. SCREEN _NEWIMAGE(800, 600, 32)
  12. _SCREENMOVE 300, 20
  13.  
  14. DIM score, again$
  15.  
  16. 'for testing
  17. 'IF _FILEEXISTS("Top 10 Scores.txt") THEN KILL "Top 10 Scores.txt"
  18.  
  19. 'testing function with random scores, would be good to start with
  20. FOR score = 1 TO 15
  21.     again$ = topTenGoAgain$(score * 5 * RND)
  22.     CLS
  23.  
  24.     IF LEN(again$) THEN PRINT "Player wants to quit." ELSE PRINT "Player wants to go again."
  25.     IF score = 15 OR LEN(again$) THEN
  26.         PRINT "End of test.": END
  27.     ELSE
  28.         INPUT "Press <enter> to continue testing TopTenGoAgain$ Function.", again$
  29.     END IF
  30.  
  31.  
  32. ' This FUNCTION creates a file in the same folder as your .bas source or .exe
  33. 'EDIT: 2019-07-31 this function needs:
  34. ' SUB cText(x, y, pixelTextHeight, Colr)
  35. ' SUB inputBox$(prompt$, title$, maxBoxWidth)
  36. ' which needs scnState(restoreTF)
  37. FUNCTION topTenGoAgain$ (compareScore AS INTEGER)
  38.     DIM fName$, n AS INTEGER, names$(1 TO 10), scores(1 TO 10), name$, score AS INTEGER
  39.     DIM settleScore AS INTEGER, i AS INTEGER, yc, s$
  40.  
  41.     fName$ = "Top 10 Scores.txt" '<<<  since this is toolbox code change this as needed for app
  42.     CLS
  43.     cText _WIDTH / 2, _HEIGHT / 8, 20, &HFF0000FF, "Your score was:" + STR$(compareScore)
  44.     IF _FILEEXISTS(fName$) THEN
  45.         OPEN fName$ FOR INPUT AS #1
  46.         WHILE EOF(1) = 0 AND n < 10
  47.             n = n + 1
  48.             INPUT #1, name$
  49.             INPUT #1, score
  50.             IF compareScore >= score AND settleScore = 0 THEN
  51.                 names$(n) = inputBox$("Please enter your name here:", "You have made the Top Ten!", 40)
  52.                 scores(n) = compareScore
  53.                 settleScore = -1
  54.                 n = n + 1
  55.                 IF n <= 10 THEN names$(n) = name$: scores(n) = score
  56.             ELSE
  57.                 scores(n) = score: names$(n) = name$
  58.             END IF
  59.         WEND
  60.         CLOSE #1
  61.         IF n < 10 AND settleScore = 0 THEN
  62.             name$ = inputBox$("Please enter your name here:", "Top Ten has slot open for you:", 40)
  63.             IF name$ <> "" THEN n = n + 1: names$(n) = name$: scores(n) = compareScore
  64.         END IF
  65.         IF n > 10 THEN n = 10
  66.         yc = (_HEIGHT - 20 * (n + 2)) / 2
  67.         cText _WIDTH / 2, yc, 40, &HFFFFFF00, "Top Ten Scorers and Scores:"
  68.         OPEN fName$ FOR OUTPUT AS #1
  69.         FOR i = 1 TO n
  70.             PRINT #1, names$(i): PRINT #1, scores(i)
  71.             s$ = RIGHT$(" " + STR$(i), 2) + "  " + LEFT$(names$(i) + STRING$(25, "."), 20)
  72.             s$ = s$ + RIGHT$(SPACE$(10) + STR$(scores(i)), 10)
  73.             cText _WIDTH / 2, yc + 30 + i * 20, 20, &HFF00FFFF, s$
  74.         NEXT
  75.         _DISPLAY
  76.         _DELAY 3.5
  77.         CLOSE #1
  78.     ELSE
  79.         name$ = inputBox("Please enter your name here:", "You are first into Top Ten file.", 40)
  80.         OPEN fName$ FOR OUTPUT AS #1
  81.         PRINT #1, name$: PRINT #1, compareScore
  82.         CLOSE #1
  83.     END IF
  84.     topTenGoAgain$ = inputBox$("Press <Enter> to play again, enter q (or any) to quit... ", "Play Again?", 66)
  85.  
  86. 'center the text around (x, y) point, needs a graphics screen!
  87. SUB cText (x, y, textHeight, K AS _UNSIGNED LONG, txt$)
  88.     DIM fg AS _UNSIGNED LONG, cur&, I&, mult, xlen
  89.     fg = _DEFAULTCOLOR
  90.     'screen snapshot
  91.     cur& = _DEST
  92.     I& = _NEWIMAGE(8 * LEN(txt$), 16, 32)
  93.     _DEST I&
  94.     COLOR K, _RGBA32(0, 0, 0, 0)
  95.     _PRINTSTRING (0, 0), txt$
  96.     mult = textHeight / 16
  97.     xlen = LEN(txt$) * 8 * mult
  98.     _PUTIMAGE (x - .5 * xlen, y - .5 * textHeight)-STEP(xlen, textHeight), I&, cur&
  99.     COLOR fg
  100.     _FREEIMAGE I&
  101.  
  102. ' You can grab this box by title and drag it around screen for full viewing while answering prompt.
  103. ' Only one line allowed for prompt$
  104. ' boxWidth is 4 more than the allowed length of input, it needs to be longer than title$ and prompt$ also
  105. ' Utilities > Input Box > Input Box 1 tester v 2019-07-31
  106. ' This FUNCTION needs scnState(restroreTF)
  107. FUNCTION inputBox$ (prompt$, title$, boxWidth AS _BYTE)
  108.     DIM ForeColor AS _UNSIGNED LONG, BackColor AS _UNSIGNED LONG, White AS _UNSIGNED LONG
  109.     DIM sw AS INTEGER, sh AS INTEGER, curScrn AS LONG, backScrn AS LONG, ibx AS LONG 'some handles
  110.  
  111.     'colors
  112.     ForeColor = &HFF000055 '<  change as desired  prompt text color, back color or type in area
  113.     BackColor = &HFF6080CC '<  change as desired  used fore color in type in area
  114.     White = &HFFFFFFFF
  115.  
  116.     'items to restore at exit
  117.     scnState 0
  118.  
  119.     'screen snapshot
  120.     sw = _WIDTH: sh = _HEIGHT: curScrn = _DEST
  121.     backScrn = _NEWIMAGE(sw, sh, 32)
  122.     _PUTIMAGE , curScrn, backScrn
  123.  
  124.     'moving box around on screen
  125.     DIM bxW AS INTEGER, bxH AS INTEGER
  126.     DIM mb AS INTEGER, mx AS INTEGER, my AS INTEGER, mi AS INTEGER, grabx AS INTEGER, graby AS INTEGER
  127.     DIM tlx AS INTEGER, tly AS INTEGER 'top left corner of message box
  128.     DIM lastx AS INTEGER, lasty AS INTEGER
  129.     DIM inp$, kh&
  130.  
  131.     'draw message box
  132.     bxW = boxWidth * 8: bxH = 7 * 16
  133.     ibx = _NEWIMAGE(bxW, bxH, 32)
  134.     _DEST ibx
  135.     COLOR &HFF880000, White
  136.     LOCATE 1, 1: PRINT LEFT$(SPACE$(INT((boxWidth - LEN(title$) - 3)) / 2) + title$ + SPACE$(boxWidth), boxWidth)
  137.     COLOR White, &HFFBB0000
  138.     LOCATE 1, boxWidth - 2: PRINT " X "
  139.     COLOR ForeColor, BackColor
  140.     LOCATE 2, 1: PRINT SPACE$(boxWidth);
  141.     LOCATE 3, 1: PRINT LEFT$(SPACE$((boxWidth - LEN(prompt$)) / 2) + prompt$ + SPACE$(boxWidth), boxWidth);
  142.     LOCATE 4, 1: PRINT SPACE$(boxWidth);
  143.     LOCATE 5, 1: PRINT SPACE$(boxWidth);
  144.     LOCATE 6, 1: PRINT SPACE$(boxWidth);
  145.     inp$ = ""
  146.     GOSUB finishBox
  147.  
  148.     'convert to pixels the top left corner of box at moment
  149.     bxW = boxWidth * 8: bxH = 5 * 16
  150.     tlx = (sw - bxW) / 2: tly = (sh - bxH) / 2
  151.     lastx = tlx: lasty = tly
  152.     _KEYCLEAR
  153.     'now allow user to move it around or just read it
  154.     WHILE 1
  155.         CLS
  156.         _PUTIMAGE , backScrn
  157.         _PUTIMAGE (tlx, tly), ibx, curScrn
  158.         _DISPLAY
  159.         WHILE _MOUSEINPUT: WEND
  160.         mx = _MOUSEX: my = _MOUSEY: mb = _MOUSEBUTTON(1)
  161.         IF mb THEN
  162.             IF mx >= tlx AND mx <= tlx + bxW AND my >= tly AND my <= tly + 16 THEN 'mouse down on title bar
  163.                 IF mx >= tlx + bxW - 24 THEN EXIT WHILE
  164.                 grabx = mx - tlx: graby = my - tly
  165.                 DO WHILE mb 'wait for release
  166.                     mi = _MOUSEINPUT: mb = _MOUSEBUTTON(1)
  167.                     mx = _MOUSEX: my = _MOUSEY
  168.                     IF mx - grabx >= 0 AND mx - grabx <= sw - bxW AND my - graby >= 0 AND my - graby <= sh - bxH THEN
  169.                         'attempt to speed up with less updates
  170.                         IF ((lastx - (mx - grabx)) ^ 2 + (lasty - (my - graby)) ^ 2) ^ .5 > 10 THEN
  171.                             tlx = mx - grabx: tly = my - graby
  172.                             CLS
  173.                             _PUTIMAGE , backScrn
  174.                             _PUTIMAGE (tlx, tly), ibx, curScrn
  175.                             lastx = tlx: lasty = tly
  176.                             _DISPLAY
  177.                         END IF
  178.                     END IF
  179.                     _LIMIT 400
  180.                 LOOP
  181.             END IF
  182.         END IF
  183.         kh& = _KEYHIT
  184.         SELECT CASE kh& 'whew not much for the main event!
  185.             CASE 13: EXIT WHILE
  186.             CASE 27: inp$ = "": EXIT WHILE
  187.             CASE 32 TO 128: IF LEN(inp$) < boxWidth - 4 THEN inp$ = inp$ + CHR$(kh&): GOSUB finishBox ELSE BEEP
  188.             CASE 8: IF LEN(inp$) THEN inp$ = LEFT$(inp$, LEN(inp$) - 1): GOSUB finishBox ELSE BEEP
  189.         END SELECT
  190.  
  191.         _LIMIT 60
  192.     WEND
  193.  
  194.     'put things back
  195.     scnState 1 'need fg and bg colors set to cls
  196.     CLS '? is this needed YES!!
  197.     _PUTIMAGE , backScrn
  198.     _DISPLAY
  199.     _FREEIMAGE backScrn
  200.     _FREEIMAGE ibx
  201.     scnState 1 'because we have to call _display, we have to call this again
  202.     inputBox$ = inp$
  203.  
  204.     finishBox:
  205.     _DEST ibx
  206.     COLOR BackColor, ForeColor
  207.     LOCATE 5, 2: PRINT LEFT$(" " + inp$ + SPACE$(boxWidth - 2), boxWidth - 2)
  208.     _DEST curScrn
  209.     RETURN
  210.  
  211. 'from mBox v 2019-07-31 update
  212. ' for saving and restoring screen settins
  213. SUB scnState (restoreTF AS INTEGER) 'Thanks Steve McNeill
  214.     STATIC Font AS LONG, DefaultColor AS _UNSIGNED LONG, BackGroundColor AS _UNSIGNED LONG, Dest AS LONG, Source AS LONG
  215.     STATIC row AS INTEGER, col AS INTEGER, autodisplay AS INTEGER, mb AS INTEGER
  216.     IF restoreTF THEN
  217.         _FONT Font
  218.         COLOR DefaultColor, BackGroundColor
  219.         _DEST Dest
  220.         _SOURCE Source
  221.         LOCATE row, col
  222.         IF autodisplay THEN _AUTODISPLAY ELSE _DISPLAY
  223.         _KEYCLEAR
  224.         WHILE _MOUSEINPUT: WEND 'clear mouse clicks
  225.         mb = _MOUSEBUTTON(1)
  226.         IF mb THEN
  227.             DO
  228.                 WHILE _MOUSEINPUT: WEND
  229.                 mb = _MOUSEBUTTON(1)
  230.                 _LIMIT 100
  231.             LOOP UNTIL mb = 0
  232.         END IF
  233.     ELSE
  234.         Font = _FONT: DefaultColor = _DEFAULTCOLOR: BackGroundColor = _BACKGROUNDCOLOR
  235.         Dest = _DEST: Source = _SOURCE
  236.         row = CSRLIN: col = POS(0): autodisplay = _AUTODISPLAY
  237.     END IF
  238.  

and a screen shot of the revised screen after installed in Invaders b0_4:
 
Top Ten Revised screen.PNG
« Last Edit: September 12, 2020, 02:52:12 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: and another one for your toolbox...
« Reply #14 on: August 06, 2019, 01:41:10 am »
And another rather simple routine for your toolbox collection -- a quick mouse handler.

Code: QB64: [Select]
  1.     CLS
  2.     held$ = ""
  3.     SELECT CASE MBS
  4.         CASE 1: left = left + 1
  5.         CASE 2: right = right + 1
  6.         CASE 3: middle = middle + 1
  7.         CASE 4: held$ = "Left held"
  8.         CASE 5: held$ = "Right held"
  9.         CASE 6: held$ = "Middle held"
  10.     END SELECT
  11.  
  12.     PRINT "MouseX: "; _MOUSEX
  13.     PRINT "MouseY: "; _MOUSEY
  14.     PRINT "Left pressed: "; left
  15.     PRINT "Right pressed: "; right
  16.     PRINT "Middle pressed: "; middle
  17.     PRINT held$
  18.     _LIMIT 10
  19.  
  20.  
  21. FUNCTION MBS 'Mouse Button Status
  22.     STATIC StartTimer AS _FLOAT
  23.     STATIC ButtonDown AS INTEGER
  24.     STATIC ClickCount AS INTEGER
  25.     CONST ClickLimit## = 0.2 '2/10th of a second to down, up a key to count as a CLICK.  Down longer counts as a HOLD event.
  26.  
  27.     WHILE _MOUSEINPUT: WEND 'Remark out this line, if mouse main input/clear is going to be handled manually in main program.
  28.  
  29.     IF StartTimer = 0 THEN
  30.         IF _MOUSEBUTTON(1) THEN 'If a button is pressed, start the timer to see what it does (click or hold)
  31.             ButtonDown = 1: StartTimer = TIMER(0.01)
  32.         ELSEIF _MOUSEBUTTON(2) THEN
  33.             ButtonDown = 2: StartTimer = TIMER(0.01)
  34.         ELSEIF _MOUSEBUTTON(3) THEN
  35.             ButtonDown = 3: StartTimer = TIMER(0.01)
  36.         END IF
  37.     ELSE
  38.         BD = ButtonDown MOD 3
  39.         IF BD = 0 THEN BD = 3
  40.         IF TIMER(0.01) - StartTimer <= ClickLimit THEN 'Button was down, then up, within time limit.  It's a click
  41.             IF _MOUSEBUTTON(BD) = 0 THEN MouseHandler = ButtonDown: ButtonDown = 0: StartTimer = 0
  42.         ELSE
  43.             IF _MOUSEBUTTON(BD) = 0 THEN 'hold event has now ended
  44.                 MouseHandler = 0: ButtonDown = 0: StartTimer = 0
  45.             ELSE 'We've now started the hold event
  46.                 MouseHandler = ButtonDown + 3
  47.             END IF
  48.         END IF
  49.     END IF

One quick command to tell you if a button was clicked or held, for any of the 3 mouse buttons.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!