DrawTextEx

new topic     » topic index » view thread      » older message » newer message

All...

I recently posted a message about examples of doing printing in Windows 
and anyone who had routines to handle word wrapping with printing.  From 
what I gathered, most of us are not doing much printing in Windows with 
Eu.

To that end I have implemented Windows' DrawTextEx function into my 
Win32Lib.  Here's what you give the routine:

- control id (in this case, Printer but you could try other controls)
- text to draw
- length of text
- a sequence of four atoms defining the left, top, right and bottom 
boundaries of your rectangle on the page where you want to print a block 
of text
- formatting options (too many to mention, check out 
http://msdn.microsoft.com/library/psdk/gdi/fontext_4pbs.htm for a 
compelete description of the function/values)
- a structure for additional formatting options (I haven't implemented 
this one, just pass 0.  Please, if you need this structure and 
implement, pass it on!)

The function returns a sequence containing:
- Actual height of text (value returned by Windows) (atom)
- Actual string printed (can be different than what is passed depending 
on the formatting options) (sequence)
- Actual left boundary of rectangle (atom)
- Actual top boundary of rectangle (atom)
- Actual right boundary of rectangle (atom)
- Actual bottom boundary of rectange (atom)

Use DT_WORDBREAK to specify that you want to wrap lines down the page 
with word break (yes, Windows does this FOR you!  Can you believe it?)
The piece that I like about this function is the DT_CALCRECT formatting 
option.  When you specify this option the routine doesn't actually print 
the text but returns the actual dimensions needed to completely print 
the text.  That way you can check if the text exceeds the length of the 
page.  

Here's what I added to Win32Lib:

I added these lines AFTER the xDrawText function in Win32Lib:

    -- Beg CJT01
xDrawTextEx = registerw32Function(user32, "DrawTextExA", {C_POINTER, 
C_POINTER, C_INT, C_POINTER, C_UINT, C_POINTER}, C_INT),
    -- End CJT01                                                     

I added these lines AFTER the definition of DT_VCENTER in Win32Lib:

    -- Beg CJT01
    DT_LEFT       = #0000,
    DT_TOP        = #0000,
    DT_RIGHT      = #0002,
    DT_BOTTOM     = #0008,
    DT_WORDBREAK  = #0010,
    DT_EXPANDTABS = #0040,
    DT_TABSTOP    = #0080,
    DT_NOCLIP     = #0100,
    DT_EXTERNALLEADING = #0200,
    DT_CALCRECT   = #0400,
    DT_NOPREFIX   = #0800,
    DT_INTERNAL   = #1000,
    DT_EDITCONTROL = #2000,
    DT_PATH_ELLIPSIS = #4000,
    DT_END_ELLIPSIS = #8000,
    DT_MODIFYSTRING = #10000,
    DT_RTLREADING = #20000,
    DT_WORD_ELLIPSIS = #40000,
    DT_NOFULLWIDTHCHARBREAK = #80000,
    DT_HIDEPREFIX = #100000,
    DT_PREFIXONLY = #200000,
    -- End CJT01

And finally the function at the END of Win32Lib:

-- Beg CJT01
global function DrawText(atom id, sequence text, atom text_len,
                         sequence format_dim, atom format_opt,
                          object addl_format)

    sequence rtn_val
    atom hDc, text_buf, dtparms, ok, rect
    integer text_height
        
    -- Get the DC of the passed id
    hDc = getDC(id)

    putFontIntoHDC(hDc, id)
                                       
    -- Allocate the string
    text_buf = acquire_mem(0, text)
    
    -- Allocate a buffer to hold the rectangle information
    rect = acquire_mem( 0, SIZEOF_RECT )
    store( rect, rectLeft,   format_dim[1] )
    store( rect, rectTop,    format_dim[2] )
    store( rect, rectRight,  format_dim[3] )
    store( rect, rectBottom, format_dim[4] )
    
    dtparms = 0

    text_height = w32Func(xDrawTextEx, {hDc, text_buf, text_len, rect,
                                       format_opt, dtparms})
                                      
    -- Now get the values that can be modified by DrawTextEx
    rtn_val = {}
    rtn_val = append(rtn_val, text_height)
    rtn_val = append(rtn_val, peek_string(text_buf))
    rtn_val = append(rtn_val, fetch(rect, rectLeft))
    rtn_val = append(rtn_val, fetch(rect, rectTop))
    rtn_val = append(rtn_val, fetch(rect, rectRight))
    rtn_val = append(rtn_val, fetch(rect, rectBottom))
    
    -- Release memory allocated
    release_mem(text_buf)
    release_mem(rect)
    if sequence(addl_format) then
        release_mem(dtparms)
    end if                               
    
    -- replace the font with the default again
    replaceObject( id, hDc, DefaultFontID, ForProgram )
    
    -- Release the device context
    releaseDC( id )

    return rtn_val

end function
-- End CJT01

Now you can try this out with this code.  Of course you'll need to put 
my mods into Win32Lib for this to work.

-- Beginning of code
with trace
include win32lib.ew

constant
    JOB_HDG = "Job: ",
    DATE_HDG = "Date: ",
    TIME_HDG = "Time: ",
    PAGE_HDG = "Page: ",
    COMP_NAME = "Company Name", 
    COMP_ADDR1 = "Address Line 1",
    COMP_ADDR2 = "City/State/Zip Code",
    ITEM_HDG = "Item",
    DESC_HDG = "Description",
    QTY_HDG = "Quantity",
    PRICE_HDG = "Price",
    EXT_HDG = "Extended",
    STATUS_HDG = "Status",
    QUOTE_TEXT = "This is a quote.  It is only a quote.  Had it been" &
                 " an actual order you would have been notified where" &
                 " and when to proceed.  All prices quoted here are" &
                 " completely arbitrary and subject to interpretation" &
                 " of the quoter.  You are not allowed to modify the" &
                 " quote or question the content and/or validity of" &
                 " the information contained in the quote.  If you" &
                 " have any questions do not call us as we are far too" 
&
                 " busy to answer any of your pointless questions." 

global atom main, test

main = create( Window, "Test Print", 0, 0, 0, 300, 150, 0)
test = create( PushButton, "Test", main, 105, 45, 90, 30, 0)

procedure print_job(atom jobheader_number)
    sequence print_parms, prt_dim, wrk_seq, extent, format_dim, result,
	     rtn_text
    atom v_space, h_space, page, cur_x, cur_y, text_height, text_len
    prt_dim = {}        
    wrk_seq = {}        
    format_dim = {}       
    page = 0
    print_parms = getPrinter()
    if length(print_parms) then
        setFont(Printer, "Arial", 10, 0)
        setPenWidth(Printer, 6)
        prt_dim = getRect(Printer)
        h_space = floor(prt_dim[3] * .006)
        v_space = floor(prt_dim[4] * .003)
        if not startDoc("Test Print") then
            return            
        end if  
        if not startPage() then
            return
        end if    
        page += 1
        -- Draw the form
        drawRectangle(Printer, False, prt_dim[1], prt_dim[2],
                      prt_dim[3], prt_dim[4])
        cur_x = (prt_dim[1] + h_space)
        cur_y = (prt_dim[2] + v_space)
        setPenPos(Printer, cur_x, cur_y)
        wrk_seq = sprintf("%d", jobheader_number)
        wPuts(Printer, JOB_HDG & wrk_seq)
        cur_x = (floor(prt_dim[3] * .5))
        setPenPos(Printer, cur_x , cur_y)
        wPuts(Printer, DATE_HDG)         
        cur_x = (floor(prt_dim[3] * .7))
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, TIME_HDG)        
        cur_x = (floor(prt_dim[3] * .9))        
        setPenPos(Printer, cur_x, cur_y)
        wrk_seq = sprintf("%d", page)
        wPuts(Printer, PAGE_HDG & wrk_seq)
        -- Line after job/date/time/page
        cur_x = prt_dim[1]
        cur_y = (floor(prt_dim[4] * .03))
        drawLine(Printer, cur_x, cur_y, prt_dim[3], floor(prt_dim[4] * 
03))
        -- Print company name
        cur_x = (cur_x + h_space)
        cur_y = (cur_y + v_space)
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, COMP_NAME)             
        extent = getTextExtent(Printer, COMP_NAME)
        cur_y = (cur_y + extent[2] + v_space)
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, COMP_ADDR1)       
        extent = getTextExtent(Printer, COMP_ADDR1)    
        cur_y = (cur_y + extent[2] + v_space)            
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, COMP_ADDR2) 
        -- Line seperating company/customer
        cur_x = floor(prt_dim[3] * .5)
        cur_y = floor(prt_dim[4] * .03)
        drawLine(Printer, cur_x, cur_y, floor(prt_dim[3] * .5),
                 floor(prt_dim[4] * .125))
        -- Line after company/customer
        cur_x = prt_dim[1]
        cur_y = floor(prt_dim[4] * .125)
        drawLine(Printer, cur_x, cur_y,
                prt_dim[3], floor(prt_dim[4] * .125))
        -- Set format dimensions for draw text
trace(1)
        format_dim = { (cur_x + h_space) , (cur_y + v_space) ,
			(prt_dim[3] - h_space) , (cur_y + v_space) }
        text_len = length(QUOTE_TEXT)
        result = DrawText(Printer, QUOTE_TEXT, text_len,
                               format_dim, 
                               or_all({DT_CALCRECT,DT_WORDBREAK}),
                               0)
	text_height = result[1]
	rtn_text = result[2]
	format_dim[1] = result[3]
	format_dim[2] = result[4]
	format_dim[3] = result[5]
	format_dim[4] = result[6]
	text_len = length(rtn_text)
        result = DrawText(Printer, rtn_text, text_len,
                               format_dim, 
                               or_all({DT_WORDBREAK, DT_LEFT}),
                               0)
	
        -- Line after terms/conditions
        cur_y = floor(prt_dim[4] * .25)
        drawLine(Printer, cur_x, cur_y, prt_dim[3],
                floor(prt_dim[4] * .25))
        -- Print item number heading
        cur_x = (cur_x + h_space)
        cur_y = (cur_y + v_space)
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, ITEM_HDG)
        -- Line after item number column
        cur_x = floor(prt_dim[3] * .10)
        cur_y = floor(prt_dim[4] * .25)
        drawLine(Printer, cur_x, cur_y,
                floor(prt_dim[3] * .10), prt_dim[4])
        -- Print item description heading
        cur_x = (cur_x + h_space)
        cur_y = (cur_y + v_space)
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, DESC_HDG)
        -- Line after item desc column
        cur_x = floor(prt_dim[3] * .60)
        cur_y = floor(prt_dim[4] * .25)
        drawLine(Printer, cur_x, cur_y, 
                floor(prt_dim[3] * .60), prt_dim[4])
        -- Print item quantity heading
        cur_x = (cur_x + h_space)
        cur_y = (cur_y + v_space)
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, QTY_HDG)
        -- Line after quantity column
        cur_x = floor(prt_dim[3] * .70)
        cur_y = floor(prt_dim[4] * .25)
        drawLine(Printer, cur_x, cur_y,
                floor(prt_dim[3] * .70), prt_dim[4])
        -- Print item price heading
        cur_x = (cur_x + h_space)
        cur_y = (cur_y + v_space)
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, PRICE_HDG)
        -- Line after price column
        cur_x = floor(prt_dim[3] * .80)
        cur_y = floor(prt_dim[4] * .25)
        drawLine(Printer, cur_x, cur_y,
                floor(prt_dim[3] * .80), prt_dim[4])
        -- Print extended heading
        cur_x = (cur_x + h_space)
        cur_y = (cur_y + v_space)
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, EXT_HDG)
        -- Line after extended amount column
        cur_x = floor(prt_dim[3] * .90)
        cur_y = floor(prt_dim[4] * .25)
        drawLine(Printer, cur_x, cur_y,
                floor(prt_dim[3] * .90), prt_dim[4])
        -- Print extended heading
        cur_x = (cur_x + h_space)
        cur_y = (cur_y + v_space)
        setPenPos(Printer, cur_x, cur_y)
        wPuts(Printer, STATUS_HDG)
        -- Line after column headings 
        cur_x = prt_dim[1]
        cur_y = floor(prt_dim[4] * .28)
        drawLine(Printer, cur_x, cur_y, prt_dim[3],
                floor(prt_dim[4] * .28))

        if not endPage() then
            return          
        end if  
        if not endDoc() then
            return
        end if  
        releasePrinter()
    end if
end procedure                               

procedure test_onClick()
    print_job(1)
end procedure
onClick[ test ] = routine_id("test_onClick")

WinMain( main, Normal )
-- End of code

Sorry about the length of this post but this routine really made my life 
easier.  

Feel free to test/comment/take apart/etc.

Jonas

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu