This issue we have two bits of handy code from one coder by the name of D M J Cronje, and two from Kiyote Wolf. Both snippets from Cronje were written in QB 4.5 but should compile in FBlite or QB64. Kiyote's code was written for FreeBASIC.
'This snippet demonstrates how to keep an
'increment or decrement within certain bounds
'It can be used for any other routine where an Inc or Decr is required. See
'the left and right arrow code
'A One liner - No IF..Then..END IF
'This code keeps the cursor between Row 1-24 and Column 1-80
'It can be used for any value requiring a limit
'Up, Down, Left, Right Arrows plus the following keys used as diagonal keys
'End (DownLeft), PgDn (DownRight), PgUp (UpRight), Home (UpLeft)
'When the diagonal keys reach Row 1 or 24 then they will go left or right
'until the Column limits are reached, (1-80).
'PLEASE NOTE Plus "+" actually does a minus and Minus "-" does a plus.
'Author : D M J Cronje
'Licence GPL - Which just means give
'me some credit as this is the source code.
'Freeware
'Based on a SUB from my program SHABRU.BAS (c) 1998 in QB4.5
'for completion of a fullscreen data page containing 28 fields.
' *********** End of Comments ************************************
DECLARE SUB PrintIt () 'Print a happy face
DIM SHARED Row%, Col% 'Shared for use in SUB PrintIt
SCREEN 12 'Set SCREEN
WIDTH 80, 25 'Set Screen 80 Columns,25 Rows
COLOR 14, 1 'Yellow on Blue background
CLS 'Clear the SCREEN
LOCATE , , 0 'Switch the cursor off
Row% = 12: Col% = 40
LOCATE Row%, Col%: PRINT CHR$(2); 'start at centre of Screen
LOCATE 25, 30: PRINT " Press Esc to Stop "; 'Message for user
'********** THE MAIN MODULE ***********************************
DO
GetIn$ = "" 'No problems with Inkey$
DO
GetIn$ = INKEY$ 'wait for a user key
LOOP UNTIL GetIn$ <> "" 'LOOP WHILE GetIn$="" causes problems
'It clears the buffer and then
'Continues not waiting for a key Press
'This way it waits
COLOR 0, 1
LOCATE Row%, Col%
PRINT " "; 'Delete happy face (old row,col)
SELECT CASE GetIn$ 'process the key
CASE CHR$(0) + CHR$(80) 'Down Arrow
Row% = Row% - (Row% < 24) 'Plus 1. Stops at 24
PrintIt 'Print happy face
CASE CHR$(0) + CHR$(72) 'Up arrow
Row% = Row% + (Row% > 1) 'Minus 1. Stops at 1
PrintIt
CASE CHR$(0) + CHR$(77) 'Right Arrow
Col% = Col% - (Col% < 80) 'Plus 1. Stops at 80
PrintIt
CASE CHR$(0) + CHR$(75) 'Left arrow
Col% = Col% + (Col% > 1) 'Minus 1. Stops at 1
PrintIt
CASE CHR$(0) + CHR$(73) 'PagUp ( Diagonal UpRight)
Row% = Row% + (Row% > 1)
Col% = Col% - (Col% < 80)
PrintIt
CASE CHR$(0) + CHR$(71) 'Home (Diagonal UpLeft)
Row% = Row% + (Row% > 1)
Col% = Col% + (Col% > 1)
PrintIt
CASE CHR$(0) + CHR$(79) 'End (Diagonal LeftDown)
Row% = Row% - (Row% < 24)
Col% = Col% + (Col% > 1)
PrintIt
CASE CHR$(0) + CHR$(81) 'PgDn (Diagonal RightDown)
Row% = Row% - (Row% < 24)
Col% = Col% - (Col% < 80)
PrintIt
END SELECT
LOOP UNTIL GetIn$ = CHR$(27) 'Exit if Esc pressed
RESET
CLOSE
END
SUB PrintIt
COLOR 14, 1 'Yellow on Blue BackGround
LOCATE Row%, Col%
PRINT CHR$(2); 'Print a happy face at the new co-ordinates
END SUB
Download it here.
'A Menu program with highlights and up/Down arrow keys
'Programmed in QB4.5
'Freeware : Open source
'Licence GPL. Meaning give me credit, nothing else, this is the source.
'Snippet name MenuArow.BAS
'Author D M J Cronje
'This snippet demonstrates : How to use Arrow keys, CALL, SHARE
'CONST, DIM a STRING to a Fixed length
'It also shows how to CALL a SUB with or without using CALL
'The Menu Box size is calculated and the Box is centralized on the screen
REM $DYNAMIC 'Best utilization of memory for arrays
DEFINT A-Z
DECLARE SUB SenterTxt (YPos%, Senter$)
DECLARE SUB ChoiceGet (RowBeg, RowEnd)
DECLARE SUB ChoiceShow (Max)
DECLARE SUB FrameBox (BeginRow%, BeginKol%, EndRow%, EndKol%)
DECLARE SUB FrameScreen (Heading$)
DIM SHARED Choose$, Heading$, Author$, Choice$ 'SHARED between all SUBs
DIM SHARED Maks
CONST RowBeg = 6 'Begin Row - Offset
'Begin Col is calculated
OPTION BASE 1 'Set arrays to start at 1
'--------------------- Messages --------------------------------
Choose$ = " Press the letter of your choice or use Up/Down ArrowKey+Enter"
Author$ = " By D M J Cronj‚ "
'-------------------- MENU CHOICES -------------------------------
'The Max STRING length is 74 chars: Due to Offset and Box size
'MenuBox width is calculated using the STRING length
Maks = 6 'Number choices & Rows. Pos of MenuBox limits Max to 16
REDIM SHARED MENUS(Maks) AS STRING * 31 'Fixed Length of Menu item
'use length of longest item
MENUS(1) = " Input new member's data" 'A
MENUS(2) = " Change/view a member's data" 'B
MENUS(3) = " Make changes on the whole list" 'C
MENUS(4) = " Delete an entry" 'D
MENUS(5) = " Restore an entry" 'E
MENUS(6) = " Exit the program" 'F
1 :
'--------------------- Start/Restart here --------------------------------
RESET 'In case there are open files
CLOSE
SCREEN 0 'Set SCREEN, Width, Initial colors
WIDTH 80, 25
COLOR 14, 1 'Yellow on blue
CLS
'---------------------- PRINT THE MENU -----------------------------
Heading$ = " Sharleen Club Records " 'Set and reset the original Heading
COLOR 14, 1
FrameScreen Heading$ 'Call a SUB without using CALL
CALL ChoiceShow(Maks) 'Call a SUB using CALL
'---------------------- GET THE CHOICE -----------------------------
ChoiceGet RowBeg, Maks 'CALL SUB passing values by reference
'-------------------- PROCESS THE CHOICE ---------------------------
LOCATE , , 1 'Switch cursor back on
Gto = ASC(Choice$) - 64 'Convert A-F to 1-5
Heading$ = MENUS(Gto) 'Set heading to Choice
'------------------- GOTO THE CHOSEN MODULE ------------------------
'ON Gto GOTO MA, MB, MC, MD, ME, MF
'REMmed out to prevent errors
'Change the above labels to meet your requirements.
'----------------- YOUR CODE/MODULES GO HERE ----------------------
' GOTO 1 'Restart after Choice was processed
'--------- THE NEXT LINES ONLY CONFIRM YOUR CHOICE ---------
Chose:
CLS
PRINT "Your choice was : " + Choice$ + " -" + MENUS(Gto)
PRINT
PRINT "Press any key to continue"
SLEEP
CLOSE
RESET
END
'-------------------- END OF MAIN MODULE ----------------------------
REM $STATIC
SUB ChoiceGet (RowBeg, RowEnd)
LOCATE , , 0 'Cursor Off:Use highlights instead
'---------- KEEP ORIGINAL POSITIONS AND SET UP LIMITS ----------
OldRow = RowEnd 'Old POS for highlights &
RowEnd = RowEnd + 5 'restore limits etc
OldRow = RowEnd
Row = RowEnd
BegBox = 40 - (LEN(MENUS(1)) + 3) \ 2 'Calculate Box Begin Col
KolEnd = LEN(MENUS(1)) 'Calculate Box End Col
'---------- SET STARTING CHOICE TO "EXIT THE PROGRAM" ----------
COLOR 15, 2 'Highlight, White on Green
LOCATE RowEnd, BegBox + 3 '+ 3 is a Box Pos Offset
PRINT MENUS(RowEnd - 5); '- 5 is a Row Pos OffSet
'---------- GET KEYBOARD INPUT ----------
DO
Choice$ = ""
Choice$ = UCASE$(INKEY$) 'Change input to upper case
SELECT CASE Choice$
CASE "A" TO "F" 'Allow only "A" to "F"
EXIT DO
CASE CHR$(13) 'Chose a Highlighted item &
Choice$ = CHR$(Row + 65 - RowBeg) 'Converts Row to letter
EXIT DO
CASE CHR$(0) + CHR$(80) 'Down Arrow
IF Row = RowEnd THEN Row = RowBeg - 1 'Wraps to first Row
Row = Row - (Row < RowEnd) 'Plus 1 until Row=RowEnd
CASE CHR$(0) + CHR$(72) 'Up arrow etc.
IF Row = RowBeg THEN Row = RowEnd + 1 'Wraps to end Row
Row = Row + (Row > RowBeg) 'Minus 1 until Row=RowBeg
END SELECT
'---------- HIGHLIGHT THE ROW ----------
SELECT CASE Row
CASE RowBeg TO RowEnd
IF OldRow <> Row THEN 'Arrow Key was pressed
COLOR 15, 2 'Highlight. White on Green
LOCATE Row, BegBox + 3
PRINT MENUS(Row - 5); 'Print highlighted item
COLOR 14, 1 'Normal colours. Yellow on Blue
LOCATE OldRow, BegBox + 3
PRINT MENUS(OldRow - 5); 'Remove highlight
END IF
OldRow = Row
END SELECT
LOOP
COLOR 14, 1 'Reset to Yellow on Blue
LOCATE , , 1 'Switch cursor on
END SUB
SUB ChoiceShow (Max)
'---------- Calculate Box Size and then draw the box ----------
FixedLen = LEN(MENUS(1)) + 3
BegBox = 40 - (FixedLen \ 2) 'calculatye MenuBox start Col
LastCol = FixedLen + BegBox 'The size of the Box
LastRow = RowBeg + Max
CALL FrameBox(RowBeg - 1, BegBox - 1, LastRow, LastCol)
'---------- Print the Menu items ----------
FOR i = 1 TO Max
LOCATE i + 5, BegBox + 3 'Initial Row=i + Offset of 5 &
PRINT MENUS(i); 'Calculated Col + Offset of 3
NEXT
COLOR 0, 7 'Black on low White
FOR i = 1 TO Max
LOCATE i + 5, BegBox
PRINT " "; CHR$(i + 64); " "; 'Print A etc in front of items
NEXT
LOCATE 24, 10: PRINT Choose$; 'How to choose message
COLOR 14, 1 'Reset colour to yellow on blue
END SUB
SUB FrameBox (BeginRow, BeginKol, EndRow, EndKol)
' ÚÄ¿ Print Box using block graphics
' ÀÄÙ
BoxWide = EndKol - BeginKol + 1 'Calculate width of Box
'Print top row Ú Ä ¿
LOCATE BeginRow, BeginKol
PRINT CHR$(218); STRING$(BoxWide - 2, CHR$(196)); CHR$(191);
'Print sides of Box ³
FOR a = BeginRow + 1 TO EndRow - 1
LOCATE a, BeginKol
PRINT CHR$(179); TAB(EndKol); CHR$(179);
NEXT a
'Print bottom row À Ä Ù
LOCATE EndRow, BeginKol
PRINT CHR$(192); STRING$(BoxWide - 2, CHR$(196)); CHR$(217);
END SUB
SUB FrameScreen (Heading$) STATIC
RANDOMIZE TIMER
Vul$ = STRING$(78, (INT(RND * 28) + 98)) 'Randomize a Char to PRINT in Box
COLOR 0, 11
FrameBox 1, 1, 3, 80 ' Draw a Box at top of screen
FrameBox 23, 1, 25, 80 ' Draw a Box at bottom of screen
LOCATE 2, 2: PRINT Vul$; ' Fill Box with a letter
LOCATE 24, 2: PRINT Vul$;
COLOR 14, 11
SenterTxt 2, Heading$ ' CALL From within a SUB i.e replace a Gosub
COLOR 14, 1 ' in a SUB etc. (Preferred way)
SenterTxt 4, Author$
END SUB
SUB SenterTxt (YPos, Centre$) STATIC
LOCATE YPos, 41 - (LEN(Centre$) \ 2) ' Centre text on a 80 column screen
PRINT Centre$;
END SUB
Download it here
Kiyote has this to say about this chunck of code:
This is a routine I hatched awhile ago.
Since we are passing a bunch of point data to the routine to draw our n-gon, I use my string method with the semicolon delimeters to separate individual values.
The FUNCTION GridMulti extracts values from a string of data encoded as such.
“3;20;20;30;30;40;40”
A string like that, passed to the DrawPolygon routine, would tell it 3 points, a triangle, and to put the points at (20,20), (30,30), and (40,40).
Obviously, if you add more ordered pairs, you increase the count, the first value in the list.
I’m sure this can be optimized, but I’m not big on optimization. Not that I don’t like it, just I’m not very good at it.
It draws the polygon, and then once over itself, shifted by one pixel, to close up any gaps. I could’ve increased the precision on the loop which scales the points, but instead I overlap the polygons to do the same job quicker.
~Kiyote!
declare sub DrawPolygon (PointsIn as string, ColrIn as longint)
declare function vert4(ByVal innr As integer) As String
declare function GridMulti(ByVal InChar As String, Cnt As Integer) As Integer
declare FUNCTION AngleOut (Angx1 as integer, Angy1 as integer, Angx2 as integer, Angy2 as integer) as double
FUNCTION AngleOut (Angx1 as integer, Angy1 as integer, Angx2 as integer, Angy2 as integer) as double
dim Rise as double, Runn as double
dim m as double
IF Angx1 = Angx2 AND Angy1 = Angy2 THEN AngleOut = 0: EXIT FUNCTION
rise = Angy2 - Angy1
runn = Angx1 - Angx2
IF Angx1 = Angx2 THEN
IF SGN(rise) = 1 THEN m = 0
IF SGN(rise) = -1 THEN m = 180
END IF
IF Angx1 = Angx2 THEN AngleOut = m: EXIT FUNCTION
IF Angx1 <> Angx2 THEN
m = ATN(rise / runn) * 57.296
IF SGN(runn) = -1 THEN
m = m + 180
END IF
END IF
IF m < 0 THEN m = m + 360
AngleOut = m
END FUNCTION
function GridMulti(ByVal InChar As String, Cnt As Integer) As Integer
Dim in2 As String, w As Integer, z As Integer
If InChar = "" Then Exit Function
'ex.: All entries must have a ; after numerics--one two or 3
z = InStr(InChar, ";")
Select Case Cnt
Case 0
in2 = InChar
Case Else
in2 = InChar
For z = 1 To Cnt
w = InStr(in2, ";")
in2 = Mid$(in2, w + 1)
Next z
End Select
'IF z THEN
GridMulti = Val(in2)
' ELSE
' GridMulti = -1
'END IF
End Function
function vert4(ByVal innr As integer) As String
Dim in2 As Long
in2 = CLng(innr)
vert4 = LTrim(Str(in2)) + ";"
End Function
sub DrawPolygon (PointsIn as string, ColrIn as longint)
REM cnt,x,y,x,y,x,y,x,y
dim ministeps as double
dim Nulll as integer
dim xctr as integer, yctr as integer
dim xin(20) as integer, yin(20) as integer, ang(20) as double, dist(20) as double
dim cntcnt as integer
cntcnt = GridMulti(PointsIn,0)
for Nulll = 1 to cntcnt
xin(Nulll - 1) = GridMulti(PointsIn, (Nulll - 1) * 2 + 1)
yin(Nulll - 1) = GridMulti(PointsIn, (Nulll - 1) * 2 + 2)
next Nulll
xctr = xin(0)
yctr = yin(0)
for Nulll = 2 to cntcnt
xctr = int((xctr + xin(Nulll - 1)) / 2)
yctr = int((yctr + yin(Nulll - 1)) / 2)
next Nulll
for Nulll = 1 to cntcnt
ang(Nulll - 1) = AngleOut(xin(Nulll - 1), yin(Nulll - 1), xctr, yctr)
dist(Nulll - 1) = sqr((xin(Nulll - 1) - xctr) ^ 2 + (yin(Nulll - 1) - yctr) ^ 2)
next Nulll
for ministeps = 0 to 1 step .001
line(xctr + cos(ang(0) / 57.296) * Dist(0) * ministeps, yctr - sin(ang(0) / 57.296) * Dist(0) * ministeps) - _
(xctr + cos(ang(1) / 57.296) * Dist(1) * ministeps, yctr - sin(ang(1) / 57.296) * Dist(1) * ministeps), ColrIn
for Nulll = 3 to cntcnt
line-(xctr + cos(ang(Nulll - 1) / 57.296) * Dist(Nulll - 1) * ministeps, yctr - sin(ang(Nulll - 1) / 57.296) * Dist(Nulll - 1) * ministeps), ColrIn
next Nulll
line-(xctr + cos(ang(0) / 57.296) * Dist(0) * ministeps, yctr - sin(ang(0) / 57.296) * Dist(0) * ministeps), ColrIn
line(xctr + cos(ang(0) / 57.296) * Dist(0) * ministeps + 1, yctr - sin(ang(0) / 57.296) * Dist(0) * ministeps) - _
(xctr + cos(ang(1) / 57.296) * Dist(1) * ministeps + 1, yctr - sin(ang(1) / 57.296) * Dist(1) * ministeps), ColrIn
for Nulll = 3 to cntcnt
line-(xctr + cos(ang(Nulll - 1) / 57.296) * Dist(Nulll - 1) * ministeps + 1, yctr - sin(ang(Nulll - 1) / 57.296) * Dist(Nulll - 1) * ministeps), ColrIn
next Nulll
line-(xctr + cos(ang(0) / 57.296) * Dist(0) * ministeps + 1, yctr - sin(ang(0) / 57.296) * Dist(0) * ministeps), ColrIn
next ministeps
for Nulll = 1 to cntcnt
pset(xin(Nulll-1), yin(Nulll-1)), rgb(255,255,255)
line(xin(Nulll-1)-1, yin(Nulll-1)-1)-(xin(Nulll-1)+1, yin(Nulll-1)+1), rgb(255,255,255), bf
next Nulll
end sub
screen 18,32
dim MaxScrnX as integer = 640
dim MaxScrnY as integer = 480
dim repeater as integer
dim Nul as integer
cls
dim polystrg as string
do
Repeater = int(rnd(1)*20)
polystrg = vert4(Repeater + 1) + vert4(int(rnd(1)*MaxScrnX))
polystrg = polystrg + vert4(int(rnd(1)*MaxScrnY))
for Nul = 0 to Repeater - 1
polystrg = polystrg + vert4(int(rnd(1)*MaxScrnX))
polystrg = polystrg + vert4(int(rnd(1)*MaxScrnY))
next Nul
DrawPolygon polystrg, rgb(int(rnd(1)*256), int(rnd(1)*256), int(rnd(1)*256)) 'RGBclrout24(11)
sleep
cls
loop until multikey(1)
This is a virtual 3rd button, for the mouse.
You intercept the mouse, and if you register a right click, then you call this routine.
To use this ‘virtual’ 3rd mouse button, you have to hold the right mouse button, and while holding it, press the left mouse button, then release the right, THEN, finally release the left.
You pass over the possession of the mouse buttons, while the right is being held constant, you activate the left, then release the right, and finally let go of the left as well.
There is a shareware package, MVP Paint, which uses this, just in case the user doesn’t have a 3 button mouse.
When alot of DOS programs came out, there was various methods of dealing with what perhipherals the user had.
This give your user an extra functionality, without having to make the user let go of the mouse.
I used this, to let my user adjust a magnifying glass ball, changing the size with the left and right buttons. When the user wanted to actually place the effect against the background, he has to use the 3rd mouse button to active and drop the effect on the workspace.
~Kiyote!
dim shared MouseX as integer, MouseY as integer, MouseLeft as integer
dim shared MouseRight as integer
dim shared MouseFontX as integer, MouseFontY as integer
declare sub UpdateMouse
declare function TripleClick () as integer
sub UpdateMouse
dim MseX as integer, MseY as integer, MseB as integer, MseOk as integer
MseOk = GetMouse(MseX,MseY,,MseB)
if MseX = -1 then
MseX = 0
MseY = 0
MseB = 0
end if
MouseX = MseX
MouseY = MseY
MouseFontX = int(MseX / 4)+1
MouseFontY = int(MseY / 6)+1
If MseB And 1 Then
MouseLeft = -1
else
MouseLeft = 0
End If
If MseB And 2 Then
MouseRight = -1
else
MouseRight = 0
End if
sleep 1,1
End Sub
function TripleClick () as integer
TripleClick = 0
if MouseRight then
do
updatemouse
if (MouseLeft = 0) and (MouseRight = 0) then
TripleClick = -1
end if
if (MouseLeft <> 0) and (MouseRight <> 0) then
do
UpdateMouse
TripleClick = -2
loop until MouseLeft = 0
end if
loop until MouseRight = 0
end if
end function
dim Reusable as integer
screen 18
do
UpdateMouse
if MouseRight then
Reusable = TripleClick
if Reusable = -1 then print "Right Button"
if Reusable = -2 then print "Middle Button"
end if
loop until MouseLeft