This chapter includes:
Printing and drawing are the same in Photon—the difference depends on the draw context, a data structure that defines where the draw stream (i.e. the draw events) flows:
Or:
Or:
To print in Photon:
A print context is a PpPrintContext_t structure whose members control how printing is to be done. For information about what's in a print context, see the Photon Library Reference.
Never directly access the members of a PpPrintContext_t structure; use PpGetPC() to extract members, and PpSetPC() to change them. |
The first step to printing in Photon is to create a print context by calling PpCreatePC():
PpPrintContext_t *pc; pc = PpCreatePC();
Once the print context is created, you must set it up properly for your printer and the options (orientation, paper size, etc.) you want to use. You can do this by calling:
These functions are described in the Photon Library Reference.
You can also use PtPrintSel (see the Photon Widget Reference).
You can get a list of available printers by calling PpLoadPrinterList(). When you're finished with the list, call PpFreePrinterList().
If you're using an application that needs to know anything about the print context, you can use PpGetPC() to get the appropriate information. For example, you might need to know the selected orientation (in order to orient your widgets properly). If you need to know the size of the margins, you can call PpGetCanvas().
Before printing, you must set the source size or resolution. For example:
When setting the source size, take the nonprintable area of the printer into account. All printers have a margin around the page that they won't print on, even if the page margins are set to 0. Therefore, the size set above is actually a bit larger than the size of a page, and the font will be scaled down to fit on the printable part of the page.
In the following example, the page size and nonprintable area are taken into account to give the proper source size and text height. Try this, and measure the output to prove the font is 1″ high from ascender to descender:
#include <stdio.h> #include <stdlib.h> #include <Pt.h> PtWidget_t *label, *window; PpPrintContext_t *pc; int quit_cb (PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo ) { exit (EXIT_SUCCESS); return (Pt_CONTINUE); } int print_cb (PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo ) { int action; PhDim_t size; PhRect_t const *rect; PhDim_t const *dim; action = PtPrintSelection(window, NULL, "Demo Print Selector", pc, Pt_PRINTSEL_DFLT_LOOK); if (action != Pt_PRINTSEL_CANCEL) { /* Get the nonprintable area and page size. Both are in 1/1000ths of an inch. */ PpGetPC(pc, Pp_PC_NONPRINT_MARGINS, &rect); PpGetPC(pc, Pp_PC_PAPER_SIZE, &dim); size.w = ((dim->w - (rect->ul.x + rect->lr.x)) * 72) / 1000; size.h = ((dim->h - (rect->ul.y + rect->lr.y)) * 72) / 1000; /* Set the source size. */ PpSetPC( pc, Pp_PC_SOURCE_SIZE, &size, 0); /* Start printing the label. */ PpStartJob(pc); PpContinueJob(pc); /* Damage the widget. */ PtDamageWidget(label); PtFlush(); /* Close the PC. */ PpSuspendJob(pc); PpEndJob(pc); } return (Pt_CONTINUE); } int main(int argc, char *argv[]) { PtArg_t args[10]; PtWidget_t *print, *quit; PhDim_t win_dim = { 400, 200 }; PhPoint_t lbl_pos = {0, 0}; PhArea_t print_area = { {130, 170}, {60, 20} }; PhArea_t quit_area = { {210, 170}, {60, 20} }; PtCallback_t callbacks[2] = { {print_cb, NULL}, {quit_cb, NULL} }; if (PtInit(NULL) == -1) PtExit(EXIT_FAILURE); /* Create the main window. */ PtSetArg (&args[0], Pt_ARG_DIM, &win_dim, 0); PtSetArg (&args[1], Pt_ARG_WINDOW_TITLE, "Print Example", 0); if ((window = PtCreateWidget(PtWindow, Pt_NO_PARENT, 1, args)) == NULL) PtExit (EXIT_FAILURE); /* Create a print context. */ pc = PpCreatePC(); /* Create a label to be printed. */ PtSetArg (&args[0], Pt_ARG_POS, &lbl_pos, 0); PtSetArg (&args[1], Pt_ARG_TEXT_STRING, "I am 1 inch high", 0); PtSetArg (&args[2], Pt_ARG_TEXT_FONT, "swiss72", 0); PtSetArg (&args[3], Pt_ARG_MARGIN_HEIGHT, 0, 0); PtSetArg (&args[4], Pt_ARG_MARGIN_WIDTH, 0, 0); PtSetArg (&args[5], Pt_ARG_BEVEL_WIDTH, 0, 0); label = PtCreateWidget (PtLabel, window, 6, args); /* Create the print button. */ PtSetArg(&args[0], Pt_ARG_AREA, &print_area, 0); PtSetArg(&args[1], Pt_ARG_TEXT_STRING, "Print", 0); PtSetArg(&args[2], Pt_CB_ACTIVATE, &callbacks[0], 0); print = PtCreateWidget (PtButton, window, 3, args); /* Create the quit button. */ PtSetArg(&args[0], Pt_ARG_AREA, &quit_area, 0); PtSetArg(&args[1], Pt_ARG_TEXT_STRING, "Quit", 0); PtSetArg(&args[2], Pt_CB_ACTIVATE, &callbacks[1], 0); quit = PtCreateWidget (PtButton, window, 3, args); PtRealizeWidget(window); PtMainLoop(); return (EXIT_SUCCESS); }
You should also set the source offset, the upper left corner of what's to be printed. For example, if you have a button drawn at (20, 20) from the top left of a pane and you want it to be drawn at (0, 0) on the page, set the source offset to (20, 20). Any other widgets are drawn relative to their position from this widget's origin. A widget at (40, 40) will be drawn at (20, 20) on the page. The code is as follows:
PhPoint_t offset = {20, 20}; ... PpSetPC( pc, Pp_PC_SOURCE_OFFSET, &offset, 0 );
Once the source size and offset have been set, you can start printing:
PpStartJob(pc); PpContinueJob(pc);
PpStartJob() sets up the print context for printing and PpContinueJob() makes the print context active, causing all Photon draw commands to be redirected to the destination specified in the print context.
After you've made the print context active, you can start printing widgets and so on. This can be done by calling any combination of the following:
If you want to print all the contents of a widget that scrolls, you'll need to do some special preparations. See “Printing scrolling widgets” below. |
You can force a page break at any point by calling PpPrintNewPage():
PpPrintNewPage(pc);
Note that once you call PpStartJob(), any changes to the print context take effect after the next call to PpPrintNewPage().
Photon assumes that the page numbers increase by one. If this isn't the case, manually set the Pp_PC_PAGE_NUM member of the print context to the correct page number. Don't make the page number decrease because the print drivers might not work properly.
If you want to print all the contents of a widget that scrolls, you need some special processing:
The only way to make a PtList print (or draw) all the items is by resizing it to be the total height of all the items. The easiest way is probably by using the resize policy:
This will work only if the total height is smaller than 65K pixels. |
To print a PtMultiText widget's entire text, breaking the output into pages:
For a PtScrollArea, you need to print its virtual canvas, which is where all widgets created within or moved to a scroll area are placed:
PtValidParent( ABW_Scroll_area, PtWidget );
PtWidgetOffset( PtValidParent( ABW_Scroll_area, PtWidget ));
PpPrintWidget( pc, PtValidParent( ABW_Scroll_area, PtWidget ), NULL, NULL, 0);
To suspend a print job and direct all draw events back to the graphics driver at any point after calling PpStartJob(), call:
PpSuspendJob( pc );
To resume a print job, reactivating the print context, causing draw events to be directed towards the destination specified in the print context, call:
PpContinueJob( pc );
When you're finished printing your widgets, the print context must be deactivated and closed. This is done by calling:
PpSuspendJob(pc); PpEndJob(pc);
All draw events will be directed to the graphics driver.
You can reuse the print context for new print jobs, eliminating the need to create and initialize it again. |
When printing is complete and you no longer need the print context, you can free it, which in turn frees any resources used by it.
If you want to remember any information from the print context for future use, save it by calling PpGetPC() before freeing the print context. For example:
short const *orientation; ... PpGetPC( pc, Pp_PC_ORIENTATION, &orientation );
To free a print context, call:
PpReleasePC( pc );
This example creates an application with a main window, and a pane with a few widgets on it. When you press the Print button, a Print Selection Dialog appears. When you select this dialog's Print or Preview button, the pane is “drawn” on the printer.
#include <stdio.h> #include <stdlib.h> #include <Pt.h> PtWidget_t *pane, *window; PpPrintContext_t *pc; int quit_cb ( PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo) { PpReleasePC (pc); exit (EXIT_SUCCESS); return (Pt_CONTINUE); } int print_cb ( PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo) { int action; /* You could make these calls to PpSetPC() right after creating the print context. Having it here lets you reuse the print context. */ PhDim_t size = { 850, 1100 }; PhDim_t size2 = { 200, 150 }; /* Set the source resolution to be proportional to the size of a page. */ PpSetPC(pc, Pp_PC_SOURCE_SIZE, &size, 0); /* Uncomment this to set the source size to be the size of the widget. The widget will be scaled when printed. */ /* PpSetPC(pc, Pp_PC_SOURCE_SIZE, &size2, 0); */ action = PtPrintSelection(window, NULL, "Demo Print Selector", pc, Pt_PRINTSEL_DFLT_LOOK); if (action != Pt_PRINTSEL_CANCEL) { /* Start printing the pane. Note that we're using the same print context for all print jobs. */ PpStartJob(pc); PpContinueJob(pc); /* Print the widget. */ PpPrintWidget(pc, pane, NULL, NULL, 0); /* Close the print context. */ PpSuspendJob(pc); PpEndJob(pc); } return (Pt_CONTINUE); } int main(int argc, char *argv[]) { PtArg_t args[4]; PtWidget_t *print, *quit; PhDim_t win_dim = { 200, 200 }; PhArea_t pane_area = { {0, 0}, {200, 150} }; PhArea_t print_area = { {30, 170}, {60, 20} }; PhArea_t quit_area = { {110, 170}, {60, 20} }; PhArea_t cir_area = { {35, 20}, {130, 110} }; PhArea_t cir2_area = { {67, 40}, {20, 20} }; PhArea_t cir3_area = { {110, 40}, {20, 20} }; PhArea_t cir4_area = { {85, 80}, {30, 30} }; PtCallback_t callbacks[2] = { {print_cb, NULL}, {quit_cb, NULL} }; if (PtInit(NULL) == -1) PtExit(EXIT_FAILURE); /* Create the main window. */ PtSetArg (&args[0], Pt_ARG_DIM, &win_dim, 0); PtSetArg (&args[1], Pt_ARG_WINDOW_TITLE, "Print Example", 0); if ((window = PtCreateWidget(PtWindow, Pt_NO_PARENT, 2, args)) == NULL) PtExit(EXIT_FAILURE); /* Create a print context. */ pc = PpCreatePC(); /* Create the pane to be printed. */ PtSetArg (&args[0], Pt_ARG_AREA, &pane_area, 0); pane = PtCreateWidget (PtPane, window, 1, args); /* put some stuff in the pane to be printed. */ PtSetArg (&args[0], Pt_ARG_AREA, &cir_area, 0); PtCreateWidget (PtEllipse, pane, 1, args); PtSetArg (&args[0], Pt_ARG_AREA, &cir2_area, 0); PtSetArg (&args[1], Pt_ARG_FILL_COLOR, Pg_BLACK, 0); PtCreateWidget (PtEllipse, pane, 2, args); PtSetArg (&args[0], Pt_ARG_AREA, &cir3_area, 0); PtSetArg (&args[1], Pt_ARG_FILL_COLOR, Pg_BLACK, 0); PtCreateWidget (PtEllipse, pane, 2, args); PtSetArg (&args[0], Pt_ARG_AREA, &cir4_area, 0); PtCreateWidget (PtEllipse, pane, 1, args); /* Create the print button. */ PtSetArg(&args[0], Pt_ARG_AREA, &print_area, 0); PtSetArg(&args[1], Pt_ARG_TEXT_STRING, "Print", 0); PtSetArg(&args[2], Pt_CB_ACTIVATE, &callbacks[0], 0); print = PtCreateWidget (PtButton, window, 3, args); /* Create the quit button. */ PtSetArg(&args[0], Pt_ARG_AREA, &quit_area, 0); PtSetArg(&args[1], Pt_ARG_TEXT_STRING, "Quit", 0); PtSetArg(&args[2], Pt_CB_ACTIVATE, &callbacks[1], 0); quit = PtCreateWidget (PtButton, window, 3, args); PtRealizeWidget(window); PtMainLoop(); return (EXIT_SUCCESS); }