DrawTextEx
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
|
Not Categorized, Please Help
|
|