Announcement

Collapse
No announcement yet.

mapping fixed font to pixels

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • mapping fixed font to pixels

    Working on my hexdump application, which draws a page of hex data using a fixed font (Courier New), I wanted to ignore clicks on the whitespace between the columns. The character spacing is fixed, so asking Windows for the horizontal size, rather than using a number which seemed to fit my console, seemed like a good idea. However, the character size returned by GetTextMetrics is too small, and GetTextCharacterExtra returns zero.

    my question is: is there a reliable way of predicting the pixel position of fixed-font text, and if so, what is it?

    here's a compileable example, click on the data part of the display and metrics appear in the dialog caption.

    Code:
    ' Does GetTextMetrics lie?
    ' to investigate mapping pixel positions to characters displayed in a LABEL
    ' Chris Holbrook Sep 2008
    '
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "WIN32API.INC"
    %IDD_DIALOG1 =  101
    %IDC_LABEL1  = 1001
    
    '----------------------------------------------------------------------
    FUNCTION MakeFont(BYVAL fName AS STRING, BYVAL ptSize AS LONG, _
                      OPT BYVAL attr AS STRING) AS DWORD
       '--------------------------------------------------------------------
       ' Create a desired font and return its handle.
       ' attr = "biu" for bold, italic, and underlined (any order)
       '--------------------------------------------------------------------
       LOCAL hDC AS DWORD, CharSet AS LONG, CyPixels AS LONG
       LOCAL BOLD, italic, uLine AS LONG
        LOCAL tm AS TEXTMETRIC
       IF LEN(attr) THEN
          IF INSTR(LCASE$(attr), "b") THEN BOLD = %FW_BOLD
          IF INSTR(LCASE$(attr), "i") THEN italic = 1
          IF INSTR(LCASE$(attr), "u") THEN uLine = 1
       END IF
       hDC = GetDC(%HWND_DESKTOP)
       CyPixels  = GetDeviceCaps(hDC, %LOGPIXELSY)
       ReleaseDC %HWND_DESKTOP, hDC
       PtSize = 0 - (ptSize * CyPixels) \ 72
       FUNCTION = CreateFont(ptSize, 0, 0, 0, BOLD, italic, uLine, _
                 %FALSE, CharSet, %OUT_TT_PRECIS, _
                 %CLIP_DEFAULT_PRECIS, %DEFAULT_QUALITY, _
                 %FF_MODERN , BYCOPY fName)
    END FUNCTION
    '-------------------------------------------------------------------------
    CALLBACK FUNCTION ShowDIALOG1Proc()
        LOCAL s, stopline AS STRING
        LOCAL i, j, l, x, y, row, col AS LONG
        LOCAL ppage AS DWORD
        LOCAL q AS BYTE PTR
        LOCAL buffer AS STRING
        LOCAL pt AS POINTAPI
        LOCAL hFont, lcolor AS DWORD
        LOCAL tm AS TEXTMETRIC
        STATIC charwidth, rowheight AS LONG
        LOCAL hdc AS DWORD
        LOCAL m AS LONG
        
    
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                FOR i = 1 TO 256
                    buffer = buffer + CHR$(i)
                NEXT
                ppage = STRPTR(buffer)
                hDC = getDC(getdlgitem(CBHNDL,%IDC_LABEL1))
                GetTextmetrics hDc, tm
                rowheight = tm.tmheight
                LOCAL intercharspace AS LONG
                intercharspace = GetTextCharacterExtra ( hdc)
                charwidth = tm.tmAveCharWidth + intercharspace'its a fixed font, so all chars should have the same width
                GOSUB drawlabel
    
            CASE %WM_LBUTTONDOWN
                pt.X = LO(WORD,CBLPARAM): pt.Y = HI(WORD,CBLPARAM)
                X = pt.X - (11*charwidth)
                ' 11 characters precede the data block but this only gets us to char 10!
                ' try to work out if click was on whitespace or on a value
                m = x MOD (3*charwidth)
                col = x \ 3*charwidth ' assume first char width in 3-char column is a space
                IF m > charwidth THEN
                     DIALOG SET TEXT CBHNDL, "charwidth =" + STR$(charwidth) + _
                                             " pos in row =" + STR$(x) + _
                                             " pos in block =" + STR$(m) + _
                                             " column = " + STR$(col)
                ELSE
                    DIALOG SET TEXT CBHNDL, SPACE$(100)
                END IF
                row = (pt.Y - (2*rowheight)) \ rowheight
    
        END SELECT
        EXIT FUNCTION
    drawlabel:
        s = STRING$(80 * 16, $SPC)
        FOR i = 0 TO 15
            FOR j = 0 TO 15
                q = ppage + (i*16) + j
                MID$(s, (i * 80) + (j*3)+ 10, 2) = HEX$(@q,2)
                IF INSTR ( "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"" £$%^&*()_+{}[]:@~;'#,./\<>?`¬",CHR$(@q)) <> 0 THEN
                    MID$(s, (i * 80) + 59 + j, 1) = CHR$(@q)
                ELSE
                    MID$(s, (i * 80) + 59 + j, 1) = "."
                END IF
            NEXT
            MID$(s, ((i) * 80) + 1, 11) = HEX$(ppage + i*16, 8)
            MID$(s, ((i + 1) * 80) -2, 2) = $CRLF
        NEXT
        stopline = SPACE$(11)
        FOR i = 0 TO 15
            stopline = stopline + HEX$(((ppage AND &HF) + i ) AND &HF)+ "  "
        NEXT
        s = stopline + _
            $CRLF + STRING$(57,"-") + "  " + STRING$(16,"-") + $CRLF + " " + s
        CONTROL SET TEXT CBHNDL, %idc_label1,  s
        RETURN
    END FUNCTION
    '-------------------------------------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
    
        LOCAL hDlg   AS DWORD
        LOCAL hFont1 AS DWORD
    
        DIALOG NEW hParent, "character and pixel positioning                             Chris Holbrook Sep 2008", _
            70, 70, 430, 207, _
            %WS_POPUP OR %WS_BORDER OR _
            %WS_DLGFRAME OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR _
            %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _
            %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
        CONTROL ADD LABEL, hDlg, %IDC_LABEL1, "", _
            5, 5, 420, 200, _
            %WS_CHILD OR %WS_VISIBLE 'OR %SS_NOWORDWRAP
    
        hFont1 = makefont("Courier New",10)
        CONTROL SEND hDlg, %IDC_LABEL1, %WM_SETFONT, hFont1, 0
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
        DeleteObject hFont1
        FUNCTION = lRslt
    END FUNCTION
    '------------------------------------------------------------
    FUNCTION PBMAIN()
        ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION

  • #2
    Forget the above, an array of 256 labels works much better.

    Comment

    Working...
    X