QB64 Phoenix Edition
Possible bug: Word-wrap oddity - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: Chatting and Socializing (https://qb64phoenix.com/forum/forumdisplay.php?fid=11)
+--- Forum: General Discussion (https://qb64phoenix.com/forum/forumdisplay.php?fid=2)
+--- Thread: Possible bug: Word-wrap oddity (/showthread.php?tid=331)

Pages: 1 2


Possible bug: Word-wrap oddity - hanness - 05-04-2022

I'm in the very early stages of writing a program that emulates one of my favorite screensavers of all time. The program simply displays a series of words on the screen, highlighting the appropriate words to spell out the time.

Below is a screenshot showing some sample output. Note that in every case, where a word would be cut off if printed on the current line, QB64 instead drops the word onto the next line. This is perfect and is exactly the behavior that I want, to avoid words being split across two lines. However, notice the second to last line of text in the screenshot below. For some reason, on only this one line, the word "fifty-six" is split across two lines.

Am I encountering some sort of bug here? Maybe something like the letter "x" at the end of the word is falling precisely on the 800 pixel width boundry and it's not being calculated precisely correctly?

Following the screenshot is the entire code, just in case this helps at all.

NOTE: I've done some testing and if I shift words around a bit I can get the error on other lines as well, where I have words that are not hyphenated. In other words, the hyphen in the word "fifty-six" has nothing to do with the problem.


It may also be worth noting that if I change the screen width from 800 to 799 the problem goes away.

[Image: Image1.jpg]

Code: (Select All)
Option _Explicit
Option Base 1

Dim AM_PM As String ' This flag will be set to either "AM" or "PM"
Dim CurrentDate As String ' Hold the entire date (Month / Day / Year) as a string
Dim CurrentTime As String ' Hold the entire time (Hours / Minutes / Seconds) as a string
Dim Day As Integer ' Day of the month (1-31) as a number
Dim DayOfWeek As Integer ' Day of the week (1-7) as a number
Dim DayOfWeekString(7) As String ' An array holding each day of the week as an English word
Dim DayString(31) As String ' An array holding each day of the month (1-31) as a string
Dim Decade As Integer ' The numerical value of the last 2 digits of the year
Dim font As Long
Dim fontpath As String
Dim handle As Long
Dim Hour As Integer ' Numerical value holding the current hour (0-23)
Dim HourString(12) As String ' The current hour as an English word. Since we use AM / PM this holds only one through twelve.
Dim LeapYear As Integer ' To to indicate if current year is a leap year. 1 = Leap Year, 0 = No Leap Year
Dim Minute As Integer ' The current minute as a numeral from 0 to 59
Dim MinuteString(59) As String ' An array hold minutes as English words from one to fifty-nine
Dim Month As Integer ' The current month as a number from 1 to 12
Dim MonthString(12) As String ' The current month as an English word (January, February, ... , November, December).
Dim MonthTable(12) As Integer ' A table with an offset for each month used to calculate what day of the week it is (Monday, Tuesday, etc).
Dim OldSecond As Integer ' A variable that is used to determine if the seconds have changed from the last time we checked
Dim Result1 As Integer ' A temporary variable
Dim Result2 As Integer ' A temporary variable
Dim Result3 As Integer ' A temporary variable
Dim Second As Integer ' The current seconds as a number (0-59)
Dim SecondString(59) As String ' The current seconds as an English word from one through fifty-nine
Dim Temp As Integer ' A temporary variable
Dim Temp2 As Integer ' A temporary variable

Dim x As Integer
Dim Year As Integer

handle& = _NewImage(800, 600, 256)
Screen handle&

'handle& = _NewImage(_DesktopWidth, _DesktopHeight, 256)
'Screen handle&
'_FullScreen




fontpath$ = Environ$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LoadFont(fontpath$, 16)
_Font font&

' Read the spelled out version of various elements into arrays. This will save time later so that we don't have to constantly
' parse this over and over in out main program loop.

Restore DayOfWeek
For x = 1 To 7
    Read DayOfWeekString$(x)
Next x

Restore Day
For x = 1 To 31
    Read DayString$(x)
Next x

Restore Month
For x = 1 To 12
    Read MonthString$(x)
Next x

Restore Hour
For x = 1 To 12
    Read HourString$(x)
Next x

Restore Minute
For x = 1 To 59
    Read MinuteString$(x)
Next x

Restore Second
For x = 1 To 59
    Read SecondString$(x)
Next x

Restore MonthTable
For x = 1 To 12
    Read MonthTable(x)
Next x

Cls

' This is the main loop that retries the date and time, breaks it down into individual components, and then
' displays the time and date in words.

Do
    _Limit 60 ' Limit the number of times that we perform this loop to a maximum of 60 iterations per second

    CurrentDate$ = Date$
    CurrentTime$ = Time$
    Month = Val(Left$(CurrentDate$, 2))
    Day = Val(Mid$(CurrentDate$, 4, 3))
    Year = Val(Right$(CurrentDate$, 4))
    Decade = Val(Right$(CurrentDate$, 2))
    Hour = Val(Left$(CurrentTime$, 2))
    Minute = Val(Mid$(CurrentTime$, 4, 2))
    Second = Val(Right$(CurrentTime$, 2))

    ' At the end of the loop that displays the time on the screen, we set OldSecond to the current seconds. When we reach
    ' this point again, if the current seconds are still the same, we skip the display process since there are no changes.
    ' If the seconds have changed, then proceed with updating the display.

    If (OldSecond = Second) Then GoTo DisplayFinished

    ' Calculate the day of the week
    ' IMPORTANT: The calculations below are valid through 2099.

    ' Step 1: Add the day of the month and the number from the month table. We will read the values from the month table.

    Temp = Day + MonthTable(Month)

    ' Step 2: If the number calculated above is greater than 6, then subtract the highest multiple of 7 from this number.

    If Temp > 6 Then
        Temp2 = Int(Temp / 7)
        Temp = Temp - (Temp2 * 7)
    End If

    Result1 = Temp

    ' Step 3: From the last two digits of the year, subtract the year that has the highest multiple of 28.

    Temp = Decade

    If Decade > 27 Then
        Temp2 = Int(Temp / 28)
        Temp = Decade - (Temp2 * 28)
    End If

    Result2 = Temp

    ' Step 4: Take the last 2 digits of the year, divide by 4, and drop anything after the decimal point. Add that value to Result2.

    Temp = 0

    If Decade > 3 Then
        Temp = Int(Decade / 4)
    End If

    Result3 = Result2 + Temp

    ' Step 5: If the month is Jan or Feb AND the year is a leap year, subtract 1 from Result3.

    If Month < 3 Then

        If (Year / 4) = (Int(Year / 4)) Then
            LeapYear = 1
        Else
            LeapYear = 0
        End If

        Result3 = Result3 - LeapYear

    End If

    ' Step 6: Add Result1 and Result3. Subtract the highest multiple of 7. The result will be 0-6 with 0 being Sat, and 6 being Fri.

    Result3 = Result3 + Result1

    If Result3 > 6 Then
        Temp = Int(Result3 / 7)
        Result3 = Result3 - (Temp * 7)
    End If

    ' To make handling easier, we will add 1 to result so that the day of the week will now be a number from 1 to 7. The
    ' end result is that Sat = 1, Fri = 7.

    DayOfWeek = Result3 + 1

    ' End calculation of the day of the week.

    ' Set the default color of items printed to the screen to grey on black. Current values will be highlighted.
    ' Currently, this means white text on a red background, but we intend to allow customization later.

    Locate 1, 1
    Color 8, 0

    ' Print all days of the week

    For x = 1 To 7

        If x = DayOfWeek Then
            Color 15, 4: Print DayOfWeekString$(x);: Color 8, 0: Print " ";
        Else
            Print DayOfWeekString$(x); " ";
        End If

    Next x

    ' Always print the word "the" in the highlight color

    Color 15, 4: Print "the";: Color 8, 0: Print " ";

    ' Print the day of the month

    For x = 1 To 31

        If x = Day Then
            Color 15, 4: Print DayString$(x);: Color 8, 0: Print " ";
        Else
            Print DayString$(x); " ";
        End If

    Next x

    ' Always print the word "of" in the highlight color

    Color 15, 4: Print "of";: Color 8, 0: Print " ";

    ' Print the month

    For x = 1 To 12

        If x = Month Then
            Color 15, 4: Print MonthString$(x);: Color 8, 0: Print " ";
        Else
            Print MonthString$(x); " ";
        End If

    Next x

    ' Always print a comma (,) in the highlight color

    Color 15, 4: Print ",";: Color 8, 0: Print " ";

    ' Print the hour. Hours are numbered from 0 to 23. Since we are using AM and PM we need to manipulate the hours a little bit
    ' and set an AM / PM flag.

    ' Set an AM / PM Flag. AM_PM$ will be set to either "AM" or "PM".

    Select Case Hour
        Case 0 TO 11
            AM_PM$ = "AM"
        Case Else
            AM_PM$ = "PM"
    End Select

    ' Convert 24 hour time to AM / PM (12 hour) format

    Select Case Hour
        Case 0
            Hour = Hour + 12
            Exit Select
        Case 13 TO 23
            Hour = Hour - 12
            Exit Select
    End Select

    For x = 1 To 12

        If x = Hour Then
            Color 15, 4: Print HourString$(x);: Color 8, 0: Print " ";
        Else
            Print HourString$(x); " ";
        End If

    Next x

    ' If minutes are equal to zero, highlight the word "o'clock".

    If (Minute = 0) Then
        Color 15, 4: Print "o'clock";: Color 8, 0: Print " ";
    Else
        Print "o'clock ";
    End If

    ' Print the minute. Minutes are numbered from 0 to 59. If seconds are 0, then we highlight the word "precisely",
    ' otherwise we highlight the word "and" and the appropriate second following the minutes.

    For x = 1 To 59

        If x = Minute Then
            Color 15, 4: Print MinuteString$(x);: Color 8, 0: Print " ";
        Else
            Print MinuteString$(x); " ";
        End If

    Next x

    ' Print the AM and PM indicators.

    Select Case AM_PM$
        Case "AM"
            Color 15, 4: Print "AM";: Color 8, 0: Print " "; "PM"; " ";
        Case "PM"
            Print "AM";: Print " ";: Color 15, 4: Print "PM";: Color 8, 0: Print " ";
    End Select

    ' If seconds are 0, then highlight the word "precisely", otherwise, highlight the word "and".

    Select Case Second
        Case 0
            Print "and ";
            Color 15, 4: Print "precisely";: Color 8, 0: Print " ";
        Case Else
            Color 15, 4: Print "and";: Color 8, 0: Print " ";
            Print "precisely ";
    End Select

    ' Print the second. Seconds are numbered from 0 to 59.

    For x = 1 To 59

        Select Case x
            Case 1

                If Second = 1 Then
                    Color 15, 4: Print SecondString$(x);: Color 8, 0: Print " ";: Color 15, 4: Print "second";: Color 8, 0: Print " ";
                Else
                    Print SecondString$(x);: Print " ";: Print "second"; " ";
                End If

            Case Else

                If Second = x Then
                    Color 15, 4: Print SecondString$(x);: Color 8, 0: Print " ";
                Else
                    Print SecondString$(x); " ";
                End If

        End Select

    Next x

    ' Highlight the word "seconds" if Second > 1.

    Select Case Second
        Case 0, 1
            Print "seconds ";
        Case Else
            Color 15, 4: Print "seconds";: Color 8, 0: Print " ";
    End Select

    OldSecond = Second

    DisplayFinished:

Loop

End



DayOfWeek:
Data "Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday"

Day:
Data "first","second","third","fourth","fifth","sixth","seventh","eighth","ninth","tenth","eleventh","twelfth","thirteenth"
Data "fourteenth","fifteenth","sixteenth","seventeenth","eighteenth","nineteenth","twentieth","twenty-first","twenty-second"
Data "twenty-third","twenty-fourth","twenty-fifth","twenty-sixth","twenty-seventh","twenty-eighth","twenty-ninth","thirtieth","thirty-first"

Month:
Data "January","February","March","April","May","June","July","August","September","October","November","December"

Hour:
Data "one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"

Minute:
Data "oh-one","oh-two","oh-three","oh-four","oh-five","oh-six","oh-seven","oh-eight","oh-nine","ten","eleven","twelve","thirteen"
Data "fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four"
Data "twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three"
Data "thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three"
Data "forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three"
Data "fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine"

Second:
Data "one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen"
Data "fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four"
Data "twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three"
Data "thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three"
Data "forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three"
Data "fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine"

MonthTable:
Data 0,3,3,6,1,4,6,2,5,0,3,5



RE: Possible bug: Word-wrap oddity - Pete - 05-04-2022

I use SCREEN 0 for Word Wrap. POS(0) = 80 is the end of the screen. In you 800 example, POS(800) would b the end position, and the font width would be 8 pixels. So if we did a LOCATE , 800 - 8: PRINT "*"; the asterisk should be printed in the right upper corner, but instead it gets wrapped by the system to the second row, first column (left side) of the screen. I'd call that a bug.

To further illustrate:

Code: (Select All)
OPTION _EXPLICIT
OPTION BASE 1

DIM handle AS LONG, fontpath AS STRING, font AS LONG, i AS INTEGER
handle& = _NEWIMAGE(800, 600, 256)
SCREEN handle&

fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LOADFONT(fontpath$, 16)
_FONT font&
_DELAY .1

LOCATE , 800 - 8: PRINT "*";

SLEEP

CLS
' This should print as one line, but the last asterisk gets wrapped.
FOR i = 1 TO 80
    PRINT "*";
NEXT
END

EDIT: Ah, did some research. It may not be a bug after all, as looking over your code once more, I noticed you did not include "MONOSPACE" for the font. Without that, the system will not specify an 8-character font width.

So try it now...

Code: (Select All)
OPTION _EXPLICIT
OPTION BASE 1

DIM AM_PM AS STRING ' This flag will be set to either "AM" or "PM"
DIM CurrentDate AS STRING ' Hold the entire date (Month / Day / Year) as a string
DIM CurrentTime AS STRING ' Hold the entire time (Hours / Minutes / Seconds) as a string
DIM Day AS INTEGER ' Day of the month (1-31) as a number
DIM DayOfWeek AS INTEGER ' Day of the week (1-7) as a number
DIM DayOfWeekString(7) AS STRING ' An array holding each day of the week as an English word
DIM DayString(31) AS STRING ' An array holding each day of the month (1-31) as a string
DIM Decade AS INTEGER ' The numerical value of the last 2 digits of the year
DIM font AS LONG
DIM fontpath AS STRING
DIM handle AS LONG
DIM Hour AS INTEGER ' Numerical value holding the current hour (0-23)
DIM HourString(12) AS STRING ' The current hour as an English word. Since we use AM / PM this holds only one through twelve.
DIM LeapYear AS INTEGER ' To to indicate if current year is a leap year. 1 = Leap Year, 0 = No Leap Year
DIM Minute AS INTEGER ' The current minute as a numeral from 0 to 59
DIM MinuteString(59) AS STRING ' An array hold minutes as English words from one to fifty-nine
DIM Month AS INTEGER ' The current month as a number from 1 to 12
DIM MonthString(12) AS STRING ' The current month as an English word (January, February, ... , November, December).
DIM MonthTable(12) AS INTEGER ' A table with an offset for each month used to calculate what day of the week it is (Monday, Tuesday, etc).
DIM OldSecond AS INTEGER ' A variable that is used to determine if the seconds have changed from the last time we checked
DIM Result1 AS INTEGER ' A temporary variable
DIM Result2 AS INTEGER ' A temporary variable
DIM Result3 AS INTEGER ' A temporary variable
DIM Second AS INTEGER ' The current seconds as a number (0-59)
DIM SecondString(59) AS STRING ' The current seconds as an English word from one through fifty-nine
DIM Temp AS INTEGER ' A temporary variable
DIM Temp2 AS INTEGER ' A temporary variable

DIM x AS INTEGER
DIM Year AS INTEGER

handle& = _NEWIMAGE(800, 600, 256)
SCREEN handle&

'handle& = _NewImage(_DesktopWidth, _DesktopHeight, 256)
'Screen handle&
'_FullScreen


fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LOADFONT(fontpath$, 16, "MONOSPACE")
_FONT font&

' Read the spelled out version of various elements into arrays. This will save time later so that we don't have to constantly
' parse this over and over in out main program loop.

RESTORE DayOfWeek
FOR x = 1 TO 7
    READ DayOfWeekString$(x)
NEXT x

RESTORE Day
FOR x = 1 TO 31
    READ DayString$(x)
NEXT x

RESTORE Month
FOR x = 1 TO 12
    READ MonthString$(x)
NEXT x

RESTORE Hour
FOR x = 1 TO 12
    READ HourString$(x)
NEXT x

RESTORE Minute
FOR x = 1 TO 59
    READ MinuteString$(x)
NEXT x

RESTORE Second
FOR x = 1 TO 59
    READ SecondString$(x)
NEXT x

RESTORE MonthTable
FOR x = 1 TO 12
    READ MonthTable(x)
NEXT x

CLS

' This is the main loop that retries the date and time, breaks it down into individual components, and then
' displays the time and date in words.

DO
    _LIMIT 60 ' Limit the number of times that we perform this loop to a maximum of 60 iterations per second

    CurrentDate$ = DATE$
    CurrentTime$ = TIME$
    Month = VAL(LEFT$(CurrentDate$, 2))
    Day = VAL(MID$(CurrentDate$, 4, 3))
    Year = VAL(RIGHT$(CurrentDate$, 4))
    Decade = VAL(RIGHT$(CurrentDate$, 2))
    Hour = VAL(LEFT$(CurrentTime$, 2))
    Minute = VAL(MID$(CurrentTime$, 4, 2))
    Second = VAL(RIGHT$(CurrentTime$, 2))

    ' At the end of the loop that displays the time on the screen, we set OldSecond to the current seconds. When we reach
    ' this point again, if the current seconds are still the same, we skip the display process since there are no changes.
    ' If the seconds have changed, then proceed with updating the display.

    IF (OldSecond = Second) THEN GOTO DisplayFinished

    ' Calculate the day of the week
    ' IMPORTANT: The calculations below are valid through 2099.

    ' Step 1: Add the day of the month and the number from the month table. We will read the values from the month table.

    Temp = Day + MonthTable(Month)

    ' Step 2: If the number calculated above is greater than 6, then subtract the highest multiple of 7 from this number.

    IF Temp > 6 THEN
        Temp2 = INT(Temp / 7)
        Temp = Temp - (Temp2 * 7)
    END IF

    Result1 = Temp

    ' Step 3: From the last two digits of the year, subtract the year that has the highest multiple of 28.

    Temp = Decade

    IF Decade > 27 THEN
        Temp2 = INT(Temp / 28)
        Temp = Decade - (Temp2 * 28)
    END IF

    Result2 = Temp

    ' Step 4: Take the last 2 digits of the year, divide by 4, and drop anything after the decimal point. Add that value to Result2.

    Temp = 0

    IF Decade > 3 THEN
        Temp = INT(Decade / 4)
    END IF

    Result3 = Result2 + Temp

    ' Step 5: If the month is Jan or Feb AND the year is a leap year, subtract 1 from Result3.

    IF Month < 3 THEN

        IF (Year / 4) = (INT(Year / 4)) THEN
            LeapYear = 1
        ELSE
            LeapYear = 0
        END IF

        Result3 = Result3 - LeapYear

    END IF

    ' Step 6: Add Result1 and Result3. Subtract the highest multiple of 7. The result will be 0-6 with 0 being Sat, and 6 being Fri.

    Result3 = Result3 + Result1

    IF Result3 > 6 THEN
        Temp = INT(Result3 / 7)
        Result3 = Result3 - (Temp * 7)
    END IF

    ' To make handling easier, we will add 1 to result so that the day of the week will now be a number from 1 to 7. The
    ' end result is that Sat = 1, Fri = 7.

    DayOfWeek = Result3 + 1

    ' End calculation of the day of the week.

    ' Set the default color of items printed to the screen to grey on black. Current values will be highlighted.
    ' Currently, this means white text on a red background, but we intend to allow customization later.

    LOCATE 1, 1
    COLOR 8, 0

    ' Print all days of the week

    FOR x = 1 TO 7

        IF x = DayOfWeek THEN
            COLOR 15, 4: PRINT DayOfWeekString$(x);: COLOR 8, 0: PRINT " ";
        ELSE
            PRINT DayOfWeekString$(x); " ";
        END IF

    NEXT x

    ' Always print the word "the" in the highlight color

    COLOR 15, 4: PRINT "the";: COLOR 8, 0: PRINT " ";

    ' Print the day of the month

    FOR x = 1 TO 31

        IF x = Day THEN
            COLOR 15, 4: PRINT DayString$(x);: COLOR 8, 0: PRINT " ";
        ELSE
            PRINT DayString$(x); " ";
        END IF

    NEXT x

    ' Always print the word "of" in the highlight color

    COLOR 15, 4: PRINT "of";: COLOR 8, 0: PRINT " ";

    ' Print the month

    FOR x = 1 TO 12

        IF x = Month THEN
            COLOR 15, 4: PRINT MonthString$(x);: COLOR 8, 0: PRINT " ";
        ELSE
            PRINT MonthString$(x); " ";
        END IF

    NEXT x

    ' Always print a comma (,) in the highlight color

    COLOR 15, 4: PRINT ",";: COLOR 8, 0: PRINT " ";

    ' Print the hour. Hours are numbered from 0 to 23. Since we are using AM and PM we need to manipulate the hours a little bit
    ' and set an AM / PM flag.

    ' Set an AM / PM Flag. AM_PM$ will be set to either "AM" or "PM".

    SELECT CASE Hour
        CASE 0 TO 11
            AM_PM$ = "AM"
        CASE ELSE
            AM_PM$ = "PM"
    END SELECT

    ' Convert 24 hour time to AM / PM (12 hour) format

    SELECT CASE Hour
        CASE 0
            Hour = Hour + 12
            EXIT SELECT
        CASE 13 TO 23
            Hour = Hour - 12
            EXIT SELECT
    END SELECT

    FOR x = 1 TO 12

        IF x = Hour THEN
            COLOR 15, 4: PRINT HourString$(x);: COLOR 8, 0: PRINT " ";
        ELSE
            PRINT HourString$(x); " ";
        END IF

    NEXT x

    ' If minutes are equal to zero, highlight the word "o'clock".

    IF (Minute = 0) THEN
        COLOR 15, 4: PRINT "o'clock";: COLOR 8, 0: PRINT " ";
    ELSE
        PRINT "o'clock ";
    END IF

    ' Print the minute. Minutes are numbered from 0 to 59. If seconds are 0, then we highlight the word "precisely",
    ' otherwise we highlight the word "and" and the appropriate second following the minutes.

    FOR x = 1 TO 59

        IF x = Minute THEN
            COLOR 15, 4: PRINT MinuteString$(x);: COLOR 8, 0: PRINT " ";
        ELSE
            PRINT MinuteString$(x); " ";
        END IF

    NEXT x

    ' Print the AM and PM indicators.

    SELECT CASE AM_PM$
        CASE "AM"
            COLOR 15, 4: PRINT "AM";: COLOR 8, 0: PRINT " "; "PM"; " ";
        CASE "PM"
            PRINT "AM";: PRINT " ";: COLOR 15, 4: PRINT "PM";: COLOR 8, 0: PRINT " ";
    END SELECT

    ' If seconds are 0, then highlight the word "precisely", otherwise, highlight the word "and".

    SELECT CASE Second
        CASE 0
            PRINT "and ";
            COLOR 15, 4: PRINT "precisely";: COLOR 8, 0: PRINT " ";
        CASE ELSE
            COLOR 15, 4: PRINT "and";: COLOR 8, 0: PRINT " ";
            PRINT "precisely ";
    END SELECT

    ' Print the second. Seconds are numbered from 0 to 59.

    FOR x = 1 TO 59

        SELECT CASE x
            CASE 1

                IF Second = 1 THEN
                    COLOR 15, 4: PRINT SecondString$(x);: COLOR 8, 0: PRINT " ";: COLOR 15, 4: PRINT "second";: COLOR 8, 0: PRINT " ";
                ELSE
                    PRINT SecondString$(x);: PRINT " ";: PRINT "second"; " ";
                END IF

            CASE ELSE

                IF Second = x THEN
                    COLOR 15, 4: PRINT SecondString$(x);: COLOR 8, 0: PRINT " ";
                ELSE
                    PRINT SecondString$(x); " ";
                END IF

        END SELECT

    NEXT x

    ' Highlight the word "seconds" if Second > 1.

    SELECT CASE Second
        CASE 0, 1
            PRINT "seconds ";
        CASE ELSE
            COLOR 15, 4: PRINT "seconds";: COLOR 8, 0: PRINT " ";
    END SELECT

    OldSecond = Second

    DisplayFinished:

LOOP

END



DayOfWeek:
DATA "Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday"

Day:
DATA "first","second","third","fourth","fifth","sixth","seventh","eighth","ninth","tenth","eleventh","twelfth","thirteenth"
DATA "fourteenth","fifteenth","sixteenth","seventeenth","eighteenth","nineteenth","twentieth","twenty-first","twenty-second"
DATA "twenty-third","twenty-fourth","twenty-fifth","twenty-sixth","twenty-seventh","twenty-eighth","twenty-ninth","thirtieth","thirty-first"

Month:
DATA "January","February","March","April","May","June","July","August","September","October","November","December"

Hour:
DATA "one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"

Minute:
DATA "oh-one","oh-two","oh-three","oh-four","oh-five","oh-six","oh-seven","oh-eight","oh-nine","ten","eleven","twelve","thirteen"
DATA "fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four"
DATA "twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three"
DATA "thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three"
DATA "forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three"
DATA "fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine"

Second:
DATA "one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen"
DATA "fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four"
DATA "twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three"
DATA "thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three"
DATA "forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three"
DATA "fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine"

MonthTable:
DATA 0,3,3,6,1,4,6,2,5,0,3,5

Pete


RE: Possible bug: Word-wrap oddity - Pete - 05-04-2022

Added one more feature, left justify...

Code: (Select All)
OPTION _EXPLICIT
OPTION BASE 1

DIM AM_PM AS STRING ' This flag will be set to either "AM" or "PM"
DIM CurrentDate AS STRING ' Hold the entire date (Month / Day / Year) as a string
DIM CurrentTime AS STRING ' Hold the entire time (Hours / Minutes / Seconds) as a string
DIM Day AS INTEGER ' Day of the month (1-31) as a number
DIM DayOfWeek AS INTEGER ' Day of the week (1-7) as a number
DIM DayOfWeekString(7) AS STRING ' An array holding each day of the week as an English word
DIM DayString(31) AS STRING ' An array holding each day of the month (1-31) as a string
DIM Decade AS INTEGER ' The numerical value of the last 2 digits of the year
DIM font AS LONG
DIM fontpath AS STRING
DIM handle AS LONG
DIM Hour AS INTEGER ' Numerical value holding the current hour (0-23)
DIM HourString(12) AS STRING ' The current hour as an English word. Since we use AM / PM this holds only one through twelve.
DIM LeapYear AS INTEGER ' To to indicate if current year is a leap year. 1 = Leap Year, 0 = No Leap Year
DIM Minute AS INTEGER ' The current minute as a numeral from 0 to 59
DIM MinuteString(59) AS STRING ' An array hold minutes as English words from one to fifty-nine
DIM Month AS INTEGER ' The current month as a number from 1 to 12
DIM MonthString(12) AS STRING ' The current month as an English word (January, February, ... , November, December).
DIM MonthTable(12) AS INTEGER ' A table with an offset for each month used to calculate what day of the week it is (Monday, Tuesday, etc).
DIM OldSecond AS INTEGER ' A variable that is used to determine if the seconds have changed from the last time we checked
DIM Result1 AS INTEGER ' A temporary variable
DIM Result2 AS INTEGER ' A temporary variable
DIM Result3 AS INTEGER ' A temporary variable
DIM Second AS INTEGER ' The current seconds as a number (0-59)
DIM SecondString(59) AS STRING ' The current seconds as an English word from one through fifty-nine
DIM Temp AS INTEGER ' A temporary variable
DIM Temp2 AS INTEGER ' A temporary variable

DIM x AS INTEGER
DIM Year AS INTEGER

handle& = _NEWIMAGE(800, 600, 256)
SCREEN handle&

'handle& = _NEWIMAGE(_DESKTOPWIDTH, _DESKTOPHEIGHT, 256)
'SCREEN handle&
'_FullScreen


fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LOADFONT(fontpath$, 16, "MONOSPACE")
_FONT font&

' Read the spelled out version of various elements into arrays. This will save time later so that we don't have to constantly
' parse this over and over in out main program loop.

RESTORE DayOfWeek
FOR x = 1 TO 7
    READ DayOfWeekString$(x)
NEXT x

RESTORE Day
FOR x = 1 TO 31
    READ DayString$(x)
NEXT x

RESTORE Month
FOR x = 1 TO 12
    READ MonthString$(x)
NEXT x

RESTORE Hour
FOR x = 1 TO 12
    READ HourString$(x)
NEXT x

RESTORE Minute
FOR x = 1 TO 59
    READ MinuteString$(x)
NEXT x

RESTORE Second
FOR x = 1 TO 59
    READ SecondString$(x)
NEXT x

RESTORE MonthTable
FOR x = 1 TO 12
    READ MonthTable(x)
NEXT x

CLS

' This is the main loop that retries the date and time, breaks it down into individual components, and then
' displays the time and date in words.

DO
    _LIMIT 60 ' Limit the number of times that we perform this loop to a maximum of 60 iterations per second

    CurrentDate$ = DATE$
    CurrentTime$ = TIME$
    Month = VAL(LEFT$(CurrentDate$, 2))
    Day = VAL(MID$(CurrentDate$, 4, 3))
    Year = VAL(RIGHT$(CurrentDate$, 4))
    Decade = VAL(RIGHT$(CurrentDate$, 2))
    Hour = VAL(LEFT$(CurrentTime$, 2))
    Minute = VAL(MID$(CurrentTime$, 4, 2))
    Second = VAL(RIGHT$(CurrentTime$, 2))

    ' At the end of the loop that displays the time on the screen, we set OldSecond to the current seconds. When we reach
    ' this point again, if the current seconds are still the same, we skip the display process since there are no changes.
    ' If the seconds have changed, then proceed with updating the display.

    IF (OldSecond = Second) THEN GOTO DisplayFinished

    ' Calculate the day of the week
    ' IMPORTANT: The calculations below are valid through 2099.

    ' Step 1: Add the day of the month and the number from the month table. We will read the values from the month table.

    Temp = Day + MonthTable(Month)

    ' Step 2: If the number calculated above is greater than 6, then subtract the highest multiple of 7 from this number.

    IF Temp > 6 THEN
        Temp2 = INT(Temp / 7)
        Temp = Temp - (Temp2 * 7)
    END IF

    Result1 = Temp

    ' Step 3: From the last two digits of the year, subtract the year that has the highest multiple of 28.

    Temp = Decade

    IF Decade > 27 THEN
        Temp2 = INT(Temp / 28)
        Temp = Decade - (Temp2 * 28)
    END IF

    Result2 = Temp

    ' Step 4: Take the last 2 digits of the year, divide by 4, and drop anything after the decimal point. Add that value to Result2.

    Temp = 0

    IF Decade > 3 THEN
        Temp = INT(Decade / 4)
    END IF

    Result3 = Result2 + Temp

    ' Step 5: If the month is Jan or Feb AND the year is a leap year, subtract 1 from Result3.

    IF Month < 3 THEN

        IF (Year / 4) = (INT(Year / 4)) THEN
            LeapYear = 1
        ELSE
            LeapYear = 0
        END IF

        Result3 = Result3 - LeapYear

    END IF

    ' Step 6: Add Result1 and Result3. Subtract the highest multiple of 7. The result will be 0-6 with 0 being Sat, and 6 being Fri.

    Result3 = Result3 + Result1

    IF Result3 > 6 THEN
        Temp = INT(Result3 / 7)
        Result3 = Result3 - (Temp * 7)
    END IF

    ' To make handling easier, we will add 1 to result so that the day of the week will now be a number from 1 to 7. The
    ' end result is that Sat = 1, Fri = 7.

    DayOfWeek = Result3 + 1

    ' End calculation of the day of the week.

    ' Set the default color of items printed to the screen to grey on black. Current values will be highlighted.
    ' Currently, this means white text on a red background, but we intend to allow customization later.

    LOCATE 1, 1
    COLOR 8, 0

    ' Print all days of the week

    FOR x = 1 TO 7

        IF x = DayOfWeek THEN
            COLOR 15, 4: PRINT DayOfWeekString$(x);: COLOR 8, 0: IF POS(0) > 1 THEN PRINT " ";
        ELSE
            PRINT DayOfWeekString$(x);: IF POS(0) > 1 THEN PRINT " ";
        END IF

    NEXT x

    ' Always print the word "the" in the highlight color

    COLOR 15, 4: PRINT "the";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";

    ' Print the day of the month

    FOR x = 1 TO 31

        IF x = Day THEN
            COLOR 15, 4: PRINT DayString$(x);: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
        ELSE
            PRINT DayString$(x);: IF POS(0) > 1 THEN PRINT " ";
        END IF

    NEXT x

    ' Always print the word "of" in the highlight color

    COLOR 15, 4: PRINT "of";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";

    ' Print the month

    FOR x = 1 TO 12

        IF x = Month THEN
            COLOR 15, 4: PRINT MonthString$(x);: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
        ELSE
            PRINT MonthString$(x);: IF POS(0) > 1 THEN PRINT " ";
        END IF

    NEXT x

    ' Always print a comma (,) in the highlight color

    COLOR 15, 4: PRINT ",";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";

    ' Print the hour. Hours are numbered from 0 to 23. Since we are using AM and PM we need to manipulate the hours a little bit
    ' and set an AM / PM flag.

    ' Set an AM / PM Flag. AM_PM$ will be set to either "AM" or "PM".

    SELECT CASE Hour
        CASE 0 TO 11
            AM_PM$ = "AM"
        CASE ELSE
            AM_PM$ = "PM"
    END SELECT

    ' Convert 24 hour time to AM / PM (12 hour) format

    SELECT CASE Hour
        CASE 0
            Hour = Hour + 12
            EXIT SELECT
        CASE 13 TO 23
            Hour = Hour - 12
            EXIT SELECT
    END SELECT

    FOR x = 1 TO 12

        IF x = Hour THEN
            COLOR 15, 4: PRINT HourString$(x);: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
        ELSE
            PRINT HourString$(x);: IF POS(0) > 1 THEN PRINT " ";
        END IF

    NEXT x

    ' If minutes are equal to zero, highlight the word "o'clock".

    IF (Minute = 0) THEN
        COLOR 15, 4: PRINT "o'clock";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
    ELSE
        PRINT "o'clock ";
    END IF

    ' Print the minute. Minutes are numbered from 0 to 59. If seconds are 0, then we highlight the word "precisely",
    ' otherwise we highlight the word "and" and the appropriate second following the minutes.

    FOR x = 1 TO 59

        IF x = Minute THEN
            COLOR 15, 4: PRINT MinuteString$(x);: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
        ELSE
            PRINT MinuteString$(x);: IF POS(0) > 1 THEN PRINT " ";
        END IF

    NEXT x

    ' Print the AM and PM indicators.

    SELECT CASE AM_PM$
        CASE "AM"
            COLOR 15, 4: PRINT "AM";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
            PRINT "PM";: IF POS(0) > 1 THEN PRINT " ";
        CASE "PM"
            PRINT "AM";: PRINT " ";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
            COLOR 15, 4: PRINT "PM";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
    END SELECT

    ' If seconds are 0, then highlight the word "precisely", otherwise, highlight the word "and".

    SELECT CASE Second
        CASE 0
            PRINT "and";: IF POS(0) > 1 THEN PRINT " ";
            COLOR 15, 4: PRINT "precisely";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
        CASE ELSE
            COLOR 15, 4: PRINT "and";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
            PRINT "precisely";: IF POS(0) > 1 THEN PRINT " ";
    END SELECT

    ' Print the second. Seconds are numbered from 0 to 59.

    FOR x = 1 TO 59

        SELECT CASE x
            CASE 1

                IF Second = 1 THEN
                    COLOR 15, 4: PRINT SecondString$(x);: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
                    COLOR 15, 4: PRINT "second";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
                ELSE
                    PRINT SecondString$(x);: IF POS(0) > 1 THEN PRINT " ";
                    PRINT "second";: IF POS(0) > 1 THEN PRINT " ";
                END IF

            CASE ELSE

                IF Second = x THEN
                    COLOR 15, 4: PRINT SecondString$(x);: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
                ELSE
                    PRINT SecondString$(x);: IF POS(0) > 1 THEN PRINT " ";
                END IF

        END SELECT

    NEXT x

    ' Highlight the word "seconds" if Second > 1.

    SELECT CASE Second
        CASE 0, 1
            PRINT "seconds";: IF POS(0) > 1 THEN PRINT " ";
        CASE ELSE
            COLOR 15, 4: PRINT "seconds";: IF POS(0) > 1 THEN COLOR 8, 0: PRINT " ";
    END SELECT

    OldSecond = Second

    DisplayFinished:

LOOP

END



DayOfWeek:
DATA "Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday"

Day:
DATA "first","second","third","fourth","fifth","sixth","seventh","eighth","ninth","tenth","eleventh","twelfth","thirteenth"
DATA "fourteenth","fifteenth","sixteenth","seventeenth","eighteenth","nineteenth","twentieth","twenty-first","twenty-second"
DATA "twenty-third","twenty-fourth","twenty-fifth","twenty-sixth","twenty-seventh","twenty-eighth","twenty-ninth","thirtieth","thirty-first"

Month:
DATA "January","February","March","April","May","June","July","August","September","October","November","December"

Hour:
DATA "one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"

Minute:
DATA "oh-one","oh-two","oh-three","oh-four","oh-five","oh-six","oh-seven","oh-eight","oh-nine","ten","eleven","twelve","thirteen"
DATA "fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four"
DATA "twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three"
DATA "thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three"
DATA "forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three"
DATA "fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine"

Second:
DATA "one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen"
DATA "fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty","twenty-one","twenty-two","twenty-three","twenty-four"
DATA "twenty-five","twenty-six","twenty-seven","twenty-eight","twenty-nine","thirty","thirty-one","thirty-two","thirty-three"
DATA "thirty-four","thirty-five","thirty-six","thirty-seven","thirty-eight","thirty-nine","forty","forty-one","forty-two","forty-three"
DATA "forty-four","forty-five","forty-six","forty-seven","forty-eight","forty-nine","fifty","fifty-one","fifty-two","fifty-three"
DATA "fifty-four","fifty-five","fifty-six","fifty-seven","fifty-eight","fifty-nine"

MonthTable:
DATA 0,3,3,6,1,4,6,2,5,0,3,5


So just remember "monospace" is needed to make the fonts fixed width, as well as to get the _FONTWIDTH function to return a value other than zero.

Pete


RE: Possible bug: Word-wrap oddity - SMcNeill - 05-04-2022

One thing to keep in mind @Pete -- fonts don't always keep the same ratio. Our default is 8x16, which is what you're probably thinking of, but lucon is 10x16...

Code: (Select All)
Option _Explicit
Option Base 1

Dim handle As Long, fontpath As String, font As Long, i As Integer
handle& = _NewImage(800, 600, 256)
Screen handle&

fontpath$ = Environ$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LoadFont(fontpath$, 16)
_Font font&
_Delay .1

Locate , 800 - _PrintWidth("*"): Print "*";
Print _PrintWidth("*")

Sleep

Cls
' This should print as one line, but the last asterisk gets wrapped.
For i = 1 To 80
    Print "*";
Next
End

Notice by backing up the proper number of pixels, that astrick doesn't wrap like it does for you. Wink


RE: Possible bug: Word-wrap oddity - hanness - 05-04-2022

Thanks greatly. That works perfectly.

So much to learn, but it's actually a lot of fun :-).


RE: Possible bug: Word-wrap oddity - Pete - 05-04-2022

@hannes

It is fun, and, at least for me, it was a big reason for sticking with a true BASIC language. The names of the statements make sense, are easily remembered, and many of the accompanying statements start with the root word.

@admin

There's another thing that I lost in memory, width 10, not 8. When you mentioned that, I vaguely recalled a project from three or fur years ago where I worked with the lucon width size. THANKS! You know the saying, "I've probably forgotten more information in life than most people ever had." is really not comforting.

Anyway, i = 1 to 80 prints 80 asterisks at width 10 pixels, makes perfect sense, but like I showed hannes, the monospace element does need to be present to do that or, apparently, the system doesn't consider the font width to be fixed at 10 pixels, as _FONTWIDTH without monospace added would be zero, (undefined), instead of 10.

So here is a little demo of not using and using monospace in the font declaration to illustrate this...

Code: (Select All)
handle& = _NEWIMAGE(800, 600, 256)
SCREEN handle&

fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LOADFONT(fontpath$, 16)
_FONT font&
_DELAY .1

PRINT "Demo without monospace added.": PRINT
FOR i = 1 TO 80
    ' With monospace added, this will print as one line.
    PRINT "*";
NEXT

fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LOADFONT(fontpath$, 16, "monospace")
_FONT font&

SLEEP

CLS
PRINT "Demo with monospace added.": PRINT
FOR i = 1 TO 80
    ' With monospace added, this will print as one line.
    PRINT "*";
NEXT

Pete


I may be old, but I'm not.. ah I'm not...


RE: Possible bug: Word-wrap oddity - SMcNeill - 05-04-2022

@Pete:  The glitch here is in the sheer fact that you start printing at pixel 1, instead of pixel 0, which is wrong when dealing with non-monospaced fonts.

Code: (Select All)
handle& = _NewImage(800, 600, 256)
Screen handle&

fontpath$ = Environ$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LoadFont(fontpath$, 16)
_Font font&

Sleep

Cls
Print "Demo with monospace added.": Print
For i = 0 To 79
    ' With monospace added, this will print as one line.
    Color 4
    Locate 2, 10 * i: Print "*";
    Color 3
    _PrintString (10 * i, _FontHeight * 3), "*"
Next

When you run, LOCATE gives you an error on line 15 for the first character, as it refuses to print at pixel #0.  (Printstring doesn't care about this and is happy to print to such a point.)

Since you start printing characters from pixel 1 to 10...11 to 20...21 to 30...31 to 40....  you'll end up with the last pixel going on 791 to 800.... but the screen is dimensioned from 0 to 799, so you're off-screen and have to move down to the next line to print.

Adjust your print position to account for that single pixel offset (which is goofy), and then you're golden!

Code: (Select All)
handle& = _NewImage(800, 600, 256)
Screen handle&

fontpath$ = Environ$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LoadFont(fontpath$, 16)
_Font font&

'Sleep

Cls
Print "Demo with monospace added.": Print
For i = 0 To 79
    ' With monospace added, this will print as one line.
    Color 4
    If i = 0 Then
        Locate 2, 1: Print "*" 'shift forward one pixel to print at LOC 1, not LOC 0.
    Else
        Locate 2, 10 * i: Print "*";
    End If
    Color 3
    _PrintString (10 * i, _FontHeight * 3), "*"
Next

It's not the lack of monospace which is screwing things up, it's the restriction that PRINT has to start on the 1st pixel, and not the 0th one when dealing with non-monsopaced fonts.


RE: Possible bug: Word-wrap oddity - hanness - 05-04-2022

CORRECTION

Maybe the point size is the number of pixels. I forgot that I was using a font size of 40 in this test which just about matches my calculated number of 39.38. I'm still not sure how to calculate the font size I need to use because I somehow need to account for word wrap and dropping of spaces to accommodate left justification, but I least I have a basis with which to start.

END OF CORRECTION


I have another question related to this discussion.

I would like to be able to allow my program to size the font so that a page of information comes close to filling the entire screen without overflowing it or leaving a huge amount of space unused.

Is there any way to do this?

I was trying to figure out exactly how wide a font would be, but I can't make sense of the numbers. Clearly, when we say that a font is a 16 pt. font that doesn't mean it's 16 pixels high or wide, does it?

As an example, if I run my program full screen, it is then running at a resolution of 2560 x 1440 (on my machine at least). I get 65 characters across on the screen and that works out to roughly 39.38 pixels width per character (and yes, that is monospaced).


RE: Possible bug: Word-wrap oddity - SMcNeill - 05-04-2022

Fix for LOCATE is rather simple to find...  open libqb.cpp and look for the label    width8050switch_done:    in  qbg_sub_locate.

Change the next few lines to the following:
Code: (Select All)
    if (passed&2){
        if (column<0) goto error;
        if (column>w - 1) goto error;
    }


Save, use the batch file and purge libqb, and you can now locate from 0 to _width -1, as you should be able to, with non-monospaced fonts.



The fix for PRINT, to adjust it back one pixel naturally by default with non-monospaced fonts, is eluding me at the moment, however.


RE: Possible bug: Word-wrap oddity - Pete - 05-04-2022

You would need a much more sophisticated word-wrap routine to pull this off, before you attempt to calculate the pixel space available. The larger the words get, the fewer can be placed on a line without being broken. In other words, you have to get the limit of characters per line, and chop each sentence accordingly. That would give you a responsive print out. Next you would have to calculate just how large a font could be used to accomplish this to nearly fill the page, and that all depends on the number of rows generated by the wrap routine. I mean a non-math cheat would be to use trial and error, increasing size (without printing or printing on a hidden page) until the last line can't fit. Dial it back one font size and them either print it that way, or dial it back one font size on the hidden page, and then flip that page to the foreground. QB64 is fast enough to pull that off. Another alternative is to use _INSTRREV on the whole string, to calculate the number of rows for any given font height, until the best fit is determined.

Pete