Back2BASIC

You are here: Home > Issues > Issue #5 > B2B Code Show

B2B Code Show

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.

INCBOUND.BAS

'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.

MENUAROW.BAS

'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

Polygon plotting routine

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)

Virtual 3rd Mouse Button

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

| top |