inline void fl_draw(...){ fl->draw(...);};
Apart from all primitives the device also defines method
Fl_Output_Device * Fl_Output_Device::set_current()
which sets particular device as active output (do not change
fl directly!!!) The method returns
previously active device. If you want to change device / make printing
from other thread than mail fltk loop is running, you have to
lock -u sing Fl::lock() - the fltk engine. After setting the
current device back to screen one, you should unlock it back. A static
function
static Fl_Output_Device * Fl_Output_Device::current( Fl_Output_Device * d)
is equivalent to Fl_Output_Device * Fl_Output_Device::current(
Fl_Output_Device * d){return d->set_current();}. Function
static Fl_Output_Device * Fl_Output_Device::current()
just returns active device.
Fl_Printer
Fl_Printer base for all paging devices defines some useful methods for
formating and placing output on the page:
int Fl_Printer::page(int format);
int Fl_Printer::page(int w, int h, int media=0);
The first method sets new page for printing with supplied format using
enumerations
Fl_Printer::A0
Fl_Printer::A1
Fl_Printer::A2
Fl_Printer::A3
Fl_Printer:: A4
Fl_Printer::A5
Fl_Printer::A6
Fl_Printer::A7
Fl_Printer::A8
Fl_Printer::A9
Fl_Printer::B0
Fl_Printer::B1
Fl_Printer::B2
Fl_Printer::B3
Fl_Printer::B4
Fl_Printer::B5
Fl_Printer::B6
Fl_Printer::B7
Fl_Printer::B8
Fl_Printer::B9
Fl_Printer::B10
Fl_Printer::C5E
Fl_Printer::DLE
Fl_Printer::EXECUTIVE
Fl_Printer::FOLIO
Fl_Printer::LEDGER
Fl_Printer::LEGAL
Fl_Printer:: LETTER
Fl_Printer::TABLOID
Fl_Printer::ENVELOPE
Fl_Printer::PORTRAIT
Fl_Printer::LANDSCAPE
Fl_Printer::MEDIA
You should call that function before each page. The page format
can be combined (using OR operator "
|"
or "
+") with
Fl_Printer::LANDSCAPE
(default is portrait) to set the orientation. By default, the function
only defines paper size for positioning of drawings in the page, it
does not set the media itself. A printer manager is usually responsible
for media selection. If format specification is combined with
Fl_Printer::MEDIA enumeration,
the printer tries to set paging
device to fulfill the page size request. In such a case you should set
page_policy(int p) to rescribe what
to do if
particular media is not available (default is 1, see postscript
documentation).
The second format sets virtual page dimensions according to the
values supplied by the user. All units are in points (1/72
inch) but you can use convenient predefined constants
FL_POINT , FL_INCH
, FL_MM , FL_CM, FL_PICA to multiply your particular
preferred units. Methods
double Fl_Output_Device::page_width();
double Fl_Output_Device::page_height();
which return dimensions of the page (and depends also on the page
orientation) may be used later for calculation of widget
placements on the page.
After page(...) is called, the origin of coordination system is placed
in the upper left corner with such scaling that logical unit (pixel on
the screen) corresponds to 1/72 inches. In most (all) cases you have to
use one of following methods to place/scale your drawing to required
position:
void Fl_Printer::place(double x, double y, double tx, double ty, double scale = 1);
void Fl_Printer::place(double x, double y, double w, double h, double tx, double ty, double tw, double th, int align = FL_ALIGN_CENTER);
void Fl_Printer::place(Fl_Widget * w, double tx, double ty, double tw, double th, int align = FL_ALIGN_CENTER );
The first method translates the drawings in a way that position x, y
from source will be placed at tx, ty physical coordinates on the page.
For instance, if you want place upper left corner of your widget to the
upper left corner within margins of 1 inch thick (size of logical point
being 0.5 mm), you can write
printer->place(widget->x(), widget->y(), FL_INCH, FL_INCH, 0.5 * FL_MM);
Second and third functions translate the drawing and scales it to
its maximum so that it tries to fit source area [x, y, w, h] inside
target rectangle [tx, ty, tw, th]. The scaling is isotropic, the widget
is aligned in x respectively y direction according to align parameter
using fltk FL_ALIGN_* enumerations. The second form is a shortcut to
Fl_Printer::fit(w->x(),
w->y(), w->w(); w->h(), tx, ty, tw, th, align). After setting
the transformation, you should redirect the drawing by set_current()
method or Fl_Device::current(...) static function. From now you can use
all drawing primitives (clipping being probably most usefully) and
especially new function
fl_draw(Fl_Widget *)
for printing whole single or composite (group) widgets.
After printing you *must* set the screen back to be the active
device - again using (set_)current().
An alternative approach - without explicit change of the current device
- is to use device member method
void Fl_Printer::draw(Fl_Widget * w);
This method draws the widget to particular
device using necessary device swapping before and after drawing.
Fl_PS_Printer
This class allows printing to postscript devices using FILE * streams.
Fl_PS_Printer(FILE *o, int lang_level, int pages = 0)
This is a constructor of PostScript device.
o
is the FILE * stream to to which printing will be performed,
lang_level sets the postscript
language level
and is important when printing masked images and images with alpha
channel:
- For levels 1-2 only mono-color true bitmasks are generated,
for multi-color images with transparent color this transparent color is
substituted by a background
color (see bg_color method, default is FL_GRAY), for alpha channel this
color is mixed with
RGB.
- For level 3 masked images are rendered with proper mask,
alpha-images are rendered using 4x4sub-pixel Floyd-Steinberg dithering
(with slight propagation of the rounding error to the neighbor pixels)
Parameter
pages should
correspond to number of pages. If 0 is supplied %%Pages: (attend) is
generated.
Fl_PS_Printer(FILE *o, int lang_level, int x, int y, int w, int h)
An encapsulated postscript constructor:
x, y, w, h is the bounding
box with x, y
bottom-left
corner. The
origin is placed in the upper left corner of that bounding box, but you
can use place(...) methods in
the same manner as for paged printing.
page_width()
and
page_height()
return dimensions of that box. Do not use page(...) method with
encapsulated postscript!
~Fl_PS_Printer()
deletes the device, but it does not close by default the
stream. If you assign a close function to the postscript device using
void Fl_PS_Printer::close_function( void(*f)(FILE *)),
it will close the stream by that function when the destructor is called.
Printing to an external command (*nix)
fl_printer_chooser() is rather
limited example for printing to
external program under POSIX systems. Because you should regard it
more as an inspiration, it is more-less fully implemented in the header
(you do not need to include it). The
command creates a postscript device and returns a pointer to a device
to
which you can print your drawings. The device will pipe the postscript
output to the external program. You can use any program which accepts
the postscript from its standard input, ie
lpr. Yo can also use GUI
managers such as
kprinter,
qtcups,
xpp. Please read their documentation
for command line parameters (ie for kprinter you should use
--stdin option)
#include <FL/fl_printer_chooser.H> // it also includes (Fl_PS_Printer.H)
Fl_PS_Printer * fl_printer_chooser (int lang_level = 3, int pages = 0, char * * command = 0, const char * default_command = 0, const char * label = "Choose printing command")
lang_level describes the
postscript language level. Parameter
command is a location to the name of
external program. If this location is zero, function will ask (when
used for the first time) for the name of external program and allocate
necessary memory for it. If the location is no-zero, but
pointer to the string (
*command)
is zero, it will also ask the user but
newly allocated command will be assigned to that command address. If
both
command and
* command are non-zero, it will use
supplied command for execution. The behavior is that if the printing
program is not specified, if will ask the user only once. You can use
it ie in a sequence
char * my_command = 0;
Fl_PS_Printer * p = fl_printer_chooser(2, 0, &my_command);
printf("This is chosen command: %s\n", my_command); // just checking
The parameter
default_command is the
default
field value when the user is asked to supply one. Parameter
label is the message in the dialog
box. When you delete printer device, the stream is closed using
pclose().
Note, that using
fl_printer_chooser
my suspend the execution of your
program during printing. This is especially true if you use GUI printer
manager which waits for user response (clicking print or cancel
buttons) to resume printing. In such a case your program will wait at
the point of device destruction, which uses pclose() to close the
stream. You can avoid this by starting printing sequence from another
thread, but you should use
Fl::lock()
(see fltk documentation) before any
drawing attempt and
Fl::unlock()
immediately after printing, but
before destruction of the
device
(just to unlock fltk thread before waiting pclose is executed):
Fl_Printer * p = fl_printer_chooser(...);
p->page(...);
p->place(...);
Fl::lock();
fl_draw(...)
...
Fl::unlock();
delete p;
Creates the device upon particular
device context "gc" and DEVMODE "mode". Usually you do not use this
constructor directly
but the pointer to new Fl_GDI_Printer is returned by
fl_printer_chooser(...).