Posted by: SMcNeill - 3 hours ago - Forum: SMcNeill
- No Replies
Code: (Select All)
ExtendedInput"What is your name: ", nam$ Print nam$ ExtendedInput"{F8.2}Enter a number (limited to 8 digits and 2 decimal places): ", num$ PrintVal(num$) ExtendedInput"{UIL05}Enter a five digit pin: ", pin$ PrintVal(pin$) ExtendedInput"{UIL05P}Enter a five digit secret pin: ", secret$ PrintVal(secret$) Print Print"And so on!" Print"Note that you can also use arrow keys to edit input, or CTRL-V to paste into the input, or hide the input prompt and answer, or lots of options!"
SubExtendedInput (prompt$, result$) 'Over Engineered Input 'limit VALUES: '1 = Unsigned '2 = Integer '4 = Float '8 = Who cares. It's handled via internal variables and we don't need to know a type for it. 'Uses {} at the start of the prompt to limit possible input 'P = Password 'U = Unsigned 'I = Integer 'F = Float 'L## = Length of max ## 'X##, Y## = LOCATE before printing 'D = Disable paste option 'V = Move CTRL-V to AFTER paste 'H = Hide Input after finished. (Won't leave prompt, or user input on the screen.)
PCopy0, 1
A = _AutoDisplay: X = Pos(0): Y = CsrLin
OX = X: OY = Y 'original x and y positions
CP = 0: OldCP = 0'Cursor Position _KeyClear
length_limit = -1'unlimited length input, by default
IfLeft$(prompt$, 1) = "{"Then'possible limiter
i = InStr(prompt$, "}") If i Then'yep, we have something!
limiter$ = UCase$(Mid$(prompt$, 2, i - 2)) IfInStr(limiter$, "U") Then limit = limit Or1'Unsigned IfInStr(limiter$, "I") Then'can't limit to BOTH an integer AND a float
limit = limit Or2'Integer ElseIfInStr(limiter$, "F") Then
limit = limit Or4'Float
float_before_limit = KB_GetValue(limiter$, "F")
float_after_limit = KB_GetValue(Mid$(limiter$, InStr(limiter$, "F") + 1), ".") End If End If IfInStr(limiter$, "P") Then password_protected = -1: limit = limit Or8'don't show passwords. IfInStr(limiter$, "L") Then'Length Limitation
limit = limit Or8
length_limit = KB_GetValue(limiter$, "L") End If IfInStr(limiter$, "X") Then'X position on screen
limit = limit Or8
X = KB_GetValue(limiter$, "X") End If IfInStr(limiter$, "Y") Then'Y position on scren
limit = limit Or8
Y = KB_GetValue(limiter$, "Y") End If IfInStr(limiter$, "D") Then disable_paste = -1: limit = limit Or8'disable paste IfInStr(limiter$, "V") Then cursor_after_paste = -1: limit = limit Or8'disable paste IfInStr(limiter$, "H") Then clean_exit = -1: limit = limit Or8'hide after finished End If If limit <> 0Then prompt$ = Mid$(prompt$, i + 1)
Do PCopy1, 0 If_KeyDown(100307) Or_KeyDown(100308) Then AltDown = -1Else AltDown = 0
k = _KeyHit If AltDown Then Select Case k 'ignore all keypresses except ALT-number presses Case-57To-48: AltWasDown = -1: alt$ = alt$ + Chr$(-k) End Select Else Select Case k 'without alt, add any keypresses to our input Case8
oldin$ = in$ If CP > 0Then OldCP = CP: CP = CP - 1
in$ = Left$(in$, CP) + Mid$(in$, CP + 2) 'backspace to erase input Case9
oldin$ = in$
in$ = Left$(in$, CP) + Space$(4) + Mid$(in$, CP + 1) 'four spaces for any TAB entered
OldCP = CP
CP = CP + 4 Case32To128 If_KeyDown(100305) Or_KeyDown(100306) Then If k = 118Or k = 86Then If disable_paste = 0Then
oldin$ = in$
temp$ = _Clipboard$
in$ = Left$(in$, CP) + temp$ + Mid$(in$, CP + 1) 'ctrl-v paste 'CTRL-V leaves cursor in position before the paste, without moving it after. 'Feel free to modify that behavior here, if you want it to move to after the paste. If cursor_after_paste Then CP = CP + Len(temp$) End If End If If k = 122Or k = 90ThenSwap in$, oldin$: Swap OldCP, CP 'ctrl-z undo Else
check_input:
oldin$ = in$ If limit And1Then'unsigned If k = 43Or k = 45Then_Continue'remove signs +/- End If If limit And2Then'integer If k = 45And CP = 0ThenGoTo good_input 'only allow a - sign for the first digit If k < 48Or k > 57Then_Continue'remove anything non-numeric End If If limit And4Then'float If k = 45And CP = 0ThenGoTo good_input 'only allow a - sign for the first digit If k = 46AndInStr(in$, ".") = 0ThenGoTo good_input 'only one decimal point If k < 48Or k > 57Then_Continue'remove anything non-numeric IfLeft$(in$, 1) = "-"Then temp$ = Mid$(in$, 2) Else temp$ = in$ IfInStr(in$, ".") = 0Or CP < InStr(in$, ".") Then IfLen(temp$) < float_before_limit Or float_before_limit = -1Then
in$ = Left$(in$, CP) + Chr$(k) + Mid$(in$, CP + 1) 'add input to our string
OldCP = CP
CP = CP + 1 End If Else
temp$ = Mid$(in$, InStr(in$, ".") + 1) IfLen(temp$) < float_after_limit Or float_after_limit = -1Then
in$ = Left$(in$, CP) + Chr$(k) + Mid$(in$, CP + 1) 'add input to our string
OldCP = CP
CP = CP + 1 End If End If _Continue End If
good_input: If CP < length_limit Or length_limit < 0Then
in$ = Left$(in$, CP) + Chr$(k) + Mid$(in$, CP + 1) 'add input to our string
And what is *this* over engineered little routine you ask? Since I just reuploaded my Keyhit Library, I thought I'd take a moment and highlight this little extra tool that goes with it.
This is my ExtendedInput, which works basically like Input but with a ton of built in bells and whistles. Give it a shot. Try to disobey what it asks for. It limits input to floats or integers, or signed or unsigned, or length, or hidden responses. It can clean up and restore your background after itself. It has arrow key support. And paste with CTRL-V. And undo with CTRL-Z...
And it can do your taxes and kiss your wife at night...
Posted by: SMcNeill - 3 hours ago - Forum: SMcNeill
- No Replies
This is basically Windows Only. You can plug it into your Linux/Mac systems, but it simply defaults back to _KEYHIT and does nothing else for you guys.
This library has been around forever and ever now, and is my *most used* personal library of code. This is *ESSENTIAL* for me, and I could've sworn it was on the forums here, but somehow it doesn't seem to be. My apologies for anyone who might've made use of this and missed out on it for that oversight.
So, what *is* this? It's my handy dandy, super dooper, personal replacement for _KEYHIT.
To illustrate its usefulness, let me just pop out the world's simplest little set of code to run with it. Grab the library, extract it to your QB64PE folder, and copy/paste/compile/run this little code snippet.
Only 9 simple lines of code. How the heck could this showcase how useful something could possibly be? All this does is read keyboard input for us and then print the up and down codes related to that input... YAWWWNNN......
But, humor me and give it a test run.
Press keys. See how the values match.
Then get creative. Try some more advanced things, like combo keys. Try something simple like CTRL-1, or CTRL-2, or CTRL-(any number). Or CTRL-TAB...
And then try some three keys combo like CTRL-SHIFT-(any number).
So which is returning proper values for you, and which is missing key up or key down events, or mapping them to god only knows what...
GLUT is screwy. It doesn't work with a BEEP with extended keypresses. So, to deal with that, I wrote my own custom keyboard input handling routines.
Of course, I'm a Windows-Only type of programmer and this reverts back to system calls for us, so it's not Linux/Mac suitable. Just so basic code doesn't break if someone wants to cross-compile, this internally substitutes _KEYHIT for KeyHit (note my routine doesn't have any underscore associated with it), but you lose all the best features with this.
This also has German, Western Europe, and Italian keyboard support provided so you can use it to read from each of those keyboards and not miss any key events. There's also an over-engineered enhanced INPUT routine packaged in this, but it's more than a little complicated for a new user to sort it. (But it's rather impressive on what it can do for us, in its own right.)
Kick it around. Try it out. This might be what you never knew you needed. Then again, if you've never been disappointed with _KEYHIT before, then it might not be. Either way, it's back here on the forums for those who might need to make use of it for their own stuff.
Had a go at calculating some Perfect Numbers. If I EXIT the FOR NEXT and print the number and the sum of it's factors (which should be equal) it works just fine. (After the first four it might take forever because it is a big number.) But if I print the number and the sum of it's factors just before I EXIT the FOR NEXT as well as after then I get several extra unrelated numbers. The line that causes the issue is commented out, but put it in and things go bad. I would have thought that it made no difference except for printing the numbers twice. What's going on?
Code: (Select All)
ChDir startdir$ + "perfect numbers/"
Dim number As _Integer64
Dim trial As _Integer64
Dim div_total As _Integer64
number = 4 'start even and add 2 per pass
top:
div_total = 0
For trial = 1 To ((number / 2) + 1)
If number Mod trial = 0 Then div_total = div_total + trial
'If div_total = number Then Print number, div_total, "x": Exit For
Next trial
If div_total = number Then Print number, div_total
number = number + 2
GoTo top
_FullScreen_Off'Note if you use _FULLSCREEN, you should turn it OFF before making any change _Delay.2'And give it a delay to make certain that it can make that change
With the above, a windows user can set DPI Awareness as they wish for their programs. Note that once Awareness is turned off, the system ignores all other calls so you can't just turn it off and on all willy-nilly.
And what *IS* DPI Awareness? It's the automatic scaling of a program according to the settings you have in your window display settings.
For example, if you have your system set to 200% scaling, it's going to automatically scale all your programs 200% in size.
For a 3840 x 2160 display, this means that the biggest program screen you can make and view would be 1920 x 1080 as it'd scale 200% to fill the 3840 x 2160 display completely.
So with this, you can set your program to decide if it wants to do that scaling or not.
If your program is DPI(Aware), it means you're going to do any necessary scaling yourself.
If it's DPI(UnAware), it means you're going to let the system do that automatic scaling.
By monitor is going to depend on your scaling settings on each monitor and where the program is located on the desktop.
Chances are, if you don't know what DPI Awareness is or that Windows automagically resizes and scales things for you, then you won't need to worry about this. This is mainly something that affects people with scale factors built into their system (like many laptops -- mine defaults to 200% scaling) and if you've never noticed it in the past, then it's probably not something you need to concern yourself about anytime soon.
an example of a means to have overloaed subroutines or at least subroutines with a varying range of variables.
it makes use of a modified version of splitstring that someone else developed that allows the variables to be broken down in the subroutine.
Code: (Select All)
'an example of an overloaded subroutine in QB64
'
'more acurately an example of passing a different range of variables to a sub
'and gettign a different range of results based on those arguments
'
'$Dynamic
Screen _NewImage(500, 240, 256)
Dim Shared klr
Locate 1, 1: Print "A dot (press Any key) "
overload_example "12"
overload_example "100,100"
Sleep
Locate 1, 1: Print " "
Locate 1, 1: Print "Amother dot (press Any key) "
overload_example "50,50,14"
Sleep
Locate 1, 1: Print " "
Locate 1, 1: Print "A Filled Box (press Any key)"
overload_example "50,50,100,100"
Sleep
Cls
Locate 1, 1: Print " "
Locate 1, 1: Print "The code is an example of passing numerical variables "
overload_example "30,30,110,110,2"
For x = 10 To 40 Step 5
A$ = _Trim$(Str$(70 - x))
B$ = _Trim$(Str$(x + 70))
overload_example A$ + "," + A$ + "," + B$ + "," + B$
Next x
End
' overload_example'
'takesa string with a set of arguments delimited by a comma
'if there is one argument the default color is set
'if there are 2 arguments a pixel is drawn in the deafult color with pset
'if there are 3 arguments a pixel is drawn in a temporary color but the default is not changed
'if there are 4 arguments a Box is drawn the default color
'if there are 5 arguments a Filled Box is drawn the temporary color
Sub overload_example (argument$)
Dim argu$(0)
SplitString argument$, ",", argu$()
a_count = UBound(argu$)
Select Case a_count
Case 1 'set the defined color for follwoign statements
klr = Val(argu$(1))
Case 2 'pset in defined color
x0 = Val(argu$(1))
y0 = Val(argu$(2))
PSet (x0, y0), klr
Case 3 'pset in temporary color
x0 = Val(argu$(1))
y0 = Val(argu$(2))
tklr = Val(argu$(3))
PSet (x0, y0), tklr
Case 4 'draw a box in defined color
x0 = Val(argu$(1))
y0 = Val(argu$(2))
x1 = Val(argu$(3))
y1 = Val(argu$(4))
Line (x0, y0)-(x1, y1), klr, B
Case 5 'draw a filled in temporary color
x0 = Val(argu$(1))
y0 = Val(argu$(2))
x1 = Val(argu$(3))
y1 = Val(argu$(4))
tklr = Val(argu$(5))
Line (x0, y0)-(x1, y1), tklr, BF
End Select
End Sub
Sub SplitString (inputString$, delimiter$, wordArray$())
'make sure you have dynamic arrays set up
wordCount% = 0
startPos% = 1
Do
psn% = InStr(startPos%, inputString$, delimiter$) ' Find the next delimiter
If psn% = 0 Then
' No more delimiters found, this is the last word
word$ = Mid$(inputString$, startPos%)
If Len(_Trim$(word$)) > 0 Then ' Check for empty word (e.g., multiple spaces)
wordCount% = wordCount% + 1
ReDim _Preserve wordArray$(wordCount%)
wordArray$(wordCount%) = word$
End If
Exit Do ' Exit the loop
Else
' Delimiter found, extract the word
word$ = Mid$(inputString$, startPos%, psn% - startPos%)
If Len(_Trim$(word$)) > 0 Then ' Check for empty word (e.g., multiple spaces)
wordCount% = wordCount% + 1
ReDim _Preserve wordArray$(wordCount%)
wordArray$(wordCount%) = word$
End If
startPos% = psn% + Len(delimiter$) ' Move the starting position past the delimiter
End If
Loop
End Sub
This involves using Inform.
I've figured out how to load images generated within the program into picture boxes and edit them but I haven't figured out how to save a picturebox as an image file.
It is possible to have all graphics commands write to a buffer image that is loaded into a picturebox when needed throughout execution of the program, and save that to a file when desired. But that defeats some of the purpose of using Inform.
I whipped up an instructional video for QB64. A simple hello world program with random pixels graphics. It's my first attempt in ages and I certainly learned a few things already. Give it a peek if you want to and probably turn up that speaker volume so you can hear me talk as I type.
' QB64 Phoenix Edition Cassette Recorder Simulator with Proper Alpha and Case-Sensitive Variables
DECLARE SUB DrawTapePlayer (LeftReel AS INTEGER, RightReel AS INTEGER, TapeWobble AS INTEGER, TapeType AS INTEGER, Angle AS SINGLE)
' Create high-resolution graphics window
DIM ScreenID AS LONG
ScreenID = _NEWIMAGE(800, 600, 32) ' 800x600 resolution, 32-bit color mode
SCREEN ScreenID
_AUTODISPLAY ' Enables graphics rendering
' Define colors with Alpha Channel (fully opaque)
DIM PlayerColor AS _UNSIGNED LONG
DIM TapeColor AS _UNSIGNED LONG
DIM OxideTapeColor AS _UNSIGNED LONG
DIM RollerColor AS _UNSIGNED LONG
PlayerColor = _RGBA32(50, 50, 50, 255) ' Dark gray for the player casing
TapeColor = _RGBA32(139, 69, 19, 255) ' Standard brown tape
OxideTapeColor = _RGBA32(160, 82, 45, 255) ' Reddish-brown oxide tape
RollerColor = _RGBA32(245, 245, 220, 255) ' Off-white rollers
DIM TapeLength AS INTEGER
DIM SpeedMode AS STRING
DIM TapeType AS INTEGER
DIM LeftReel AS INTEGER
DIM RightReel AS INTEGER
DIM TapeWobble AS INTEGER
DIM KeyPress AS STRING
DIM Angle AS SINGLE
CLS
_PRINTSTRING (50, 50), "Welcome to the QB64 Cassette Recorder Simulator!"
_PRINTSTRING (50, 70), "Press any key to continue..."
DO
KeyPress = INKEY$
LOOP UNTIL KeyPress <> ""
CLS
_PRINTSTRING (50, 50), "Select Tape Length (10, 15, 30, 45, 60, 90, 120 minutes): "
DO
KeyPress = INKEY$
IF KeyPress >= "0" AND KeyPress <= "9" THEN TapeLength = VAL(KeyPress) * 10
LOOP UNTIL TapeLength > 0
_PRINTSTRING (50, 70), "Select Speed Mode (N: Normal, F: Fast, S: Slow, L: Long Play, E: Extra Long Play): "
DO
KeyPress = INKEY$
SELECT CASE KeyPress
CASE "N": SpeedMode = "Normal"
CASE "F": SpeedMode = "Fast"
CASE "S": SpeedMode = "Slow"
CASE "L": SpeedMode = "Long Play"
CASE "E": SpeedMode = "Extra Long Play"
END SELECT
LOOP UNTIL SpeedMode <> ""
_PRINTSTRING (50, 90), "Choose Tape Type (1: Standard Brown, 2: Metal Oxide Red-Brown): "
DO
KeyPress = INKEY$
IF KeyPress = "1" THEN TapeType = 1
IF KeyPress = "2" THEN TapeType = 2
LOOP UNTIL TapeType > 0
' Increase rotation angle
Angle = Angle + 5
IF Angle >= 360 THEN Angle = 0
NEXT
_PRINTSTRING (50, 550), "Playback Complete!"
SUB DrawTapePlayer (LeftReel AS INTEGER, RightReel AS INTEGER, TapeWobble AS INTEGER, TapeType AS INTEGER, Angle AS SINGLE)
' Select tape color
DIM CurrentTapeColor AS _UNSIGNED LONG
IF TapeType = 1 THEN
CurrentTapeColor = TapeColor
ELSE
CurrentTapeColor = OxideTapeColor
END IF
Hi
thanks to Steve I can post this here because I have a STRING$ function that fills fastly a string with a pattern but I have missed the thread about String concatenation and MID$ way String concatenation thread.
By the way in a speed test this function is faster than MID$ way!
So I share it here.
Locate 10, 1
Print Using " Tempo & #.#### #.#### #.#### "; "String = String + String "; (t2# - t1#); t1#; t2#
Print Using " Tempo & #.#### #.#### #.#### "; "MID$ way "; t4# - t3#; t3#; t4#
Print Using " Tempo & #.#### #.#### #.#### "; "String = String + Pattern "; t6# - t5#; t5#; t6#
End
Function FillString (Size As Long, Bases As String, S As String)
FillString = 0
S = Bases
Do
S = S + S
Loop Until Len(S) > Size
S = Left$(S, Size)
FillString = -1
End Function
Function FillString2 (Size As Long, Bases As String, S As String)
FillString2 = 0
Dim posi As Long
S = Space$(Size)
posi = 0
Do
Mid$(S, posi, 4) = Bases
posi = posi + 4
Loop Until posi > Size
S = Left$(S, Size)
FillString2 = -1
End Function
Function SlowFillString (Size As Long, Bases As String, S As String)
SlowFillString = 0
Dim As Double Starts, Ends
Dim Counter As Long
Starts = Timer(.001)
Ends = 10#
Counter = 0
Do
Counter = Counter + 1
S = S + Bases
Loop Until Len(S) > Size Or (Timer(.001) - Starts >= Ends)
Print , Counter; " cycles", Len(S); " lenght of string vs max size"; Size
S = Left$(S, Size)
SlowFillString = -1
End Function
Wellcome feedbacks and improvements of FillString or STRING$pattern (what name is more explicative?),
maybe any other friend of QB64pe wants share something better for performance and or algorythm.
In the other thread there is the screenshot with comparisons and a graphic explanation of why it works well.