This is quite simple really:
There is a GTK API used to drive printing, which is assumed to be based on choosing printer and orientation etc. but we already have a dialog programmed which is very close to what we want. The GTKPrintOperation thing requires you to call gtk_print_operation_run() which will operate a dialog for you and emit signals such as ::draw_page which you are supposed to catch and then call functions to drive the API that actually feeds the printer. It may be much simpler to save screenshot to a (temporary) file and the print the file.
Cairo docs can be found near this useful link. What's interesting is that the same API can drive PNG and PDF and PS file formats as well as screen graphics.
Other than the scale bar and the mark all the GDK interface in Zmap is encapsulated in CanvasFeaturesets and only a few GDK calls are used.
We wish to avoid making major changes to the foo canvas (which uses gdk_ functions to paint the screen) and to make ZMap have control over how things are drawn we need to implement non-Foo code for the scale bar and the mark, and possible also for container backgrounds, if these are drawn. We may also have to recode the ruler in case there are any interaction between gdk and cairo.
The scale bar can be coded as a new type of CanvasFeatureset item - it can respond to zoom using existing practices and fits neatly into a column display.
The mark and ruler are slightly harder to deal with as they cover the whole screen and overlay everything else. Exisiting Foo Canvas and ZMap code handles z-order explicitly via background, and overlay feature and underlay lists, which are implemented at all layers of container. The mark is drawn as two (or three) foo canvas rectangles using a stipple pattern, and these are added to the block overlay list - all the columns in a block appear underneath this as containers in the block's features list. The ruler (in two guises - ruler and mark adjuster) are held directly by the window and are created as children of the canvas root group - this is using code in zmapDraw.c. The ruler tooltip is also implemnented as a foo group on the canvas root. Other than this zmapDraw.c appears to be maily code that has fallen out of use, except for two call from zmapWindowDNAChoose.c, which could be handled by existing sequence highlight code.
The canvas featureset code implements basic graphics objects such as lines and boxes with clipping, and other items (not clipped) such as poly-lines (for wiggle plots) and glyphs (as gdk_polygons, lines, arcs etc). Note that clipping os only an issue for long items at high zoom, in case the Foo Canvas coordinate system wraps round. Drawing overflow is clipped by the X-window code (or gdk). These do not handle stipple patterns.
The obvious course of action (given that we wish to simplify the containers code) is to recode the mark as being part of the canvas root group and size it to according to the relevant block if this is less than the screen size. Ruler and tooltip items will have to be 'raised to top' in Foo Canvas terms. However to encapsulate the drawing code outside the foo canvas we will have to implement a CanvasFeatureset like object covering the the whole screen and appearing on top of the other objects.
This should be 'simple' but we need to factor in some differences such as the fact that by default lines in cairo are two pixels wide and centred on the gap between two pixels. We would be wise to be skeptical about performance:
I tried here and on a Ubuntu 10.10 install on a recent macbook with > the Ambiance theme your example was rather slow. There was an > appreciable delay (0.5s? something like that) between pressing the > top-left button and the display updating. > > I tried running under callgrind and it does seem to be spending a lot > of time somewhere deep inside libcairo (the graphics library that gtk > uses to draw the screen). I don't have a dbg version of cairo handy to > dig deeper.
The cairo drawing API comes from a universe different from GDK and is probably not aimed at drawing large numbers of simple boxes, here's an example of how to implement a widget.
This should also be simple as we just "create a drawable object (for file/ printer output) and pass this to the existing drawing code". However in Blixem this has been done by generating a pixmap using gdk_ code and then using cairo to print it, which precludes generating a crisp PDF image. Referring to the comments above about 'performance skepticism' we may need to implement graphics functions that use gdk or cairo depending on the context.
As there is some doubt that cairo will run fast enough we make be faced with running GDK and cairo on parallel, one for the screen and one for the printer. It would be a good idea to write a simple test program to draw X thousand random boxes and compare the two. Alternatively the cairo calls could be run via a compile time switch or a configuration parameter.
CanvasFeatureset code and data has been optimised for drawing genomic features which may overlap and change appearance depending on zoom level, and also appear neatly lined up in columns. The scale bar also changes appearance with zoom, but this is driven by externally with knowledge of the current scroll window (not accessable to the CanvasFeatureset code). There are a few aspects to this that could result in untidy code...
Attempting to have the best of all possible worlds, we continue to assume that the majority of data will be displayed in columns that do not overlap, but allow for the possibility that we could overlay the screen with some extra data. To handle simple graphics items with no genomic feature attached we will:
The navigator has a scroll region rectangle that can be dragged by the mouse which implies that it can have focus. The ZMap focus module assumes that focussed items are genomic features and previous code handled the scroll regioon foo canvas item directly. If not better solution can be found then the navigator code will handle this featureset item directly, and maintain a pointer to it explicitly.
CanvasFeaturesets were implemented a) to allow presentation of heatmaps that get re-binned on zoom (necessarily requires a columns wide structure) b) effciently. They were later extended to handle basic features and alignments with a view to providing a faster user experience. The FooCanvas is explicitly 2D whereas CanvasFeaturesets are explicitly orgainsed in columns which correspond roughly to FooCanvas groups as used in the Zmap display and as such are quite specific to the ZMap application. The use of graphics primitives in a column such as the Scale Bar maintains this close link to the ZMap run-time environment and we should remain aware that this is not an attempt at producing a generalised graphics engine. Note especially that there is very little explicit Z-ordering, execpt within drawing a single feature and the use of focus (which only applies to genomic features). To subvert this code into 2D operation wih no restriction on x-coordinates would require a major rethink of indexing methodology,
If we use CanvasFeaturesets to overlay/ underlay the whole canvas with decorative features (eg ruler, mark) then the assumption is that this will have little effect on performance: the bulk of display items will remain as genomic features, operating in a similar way as at present.
There are two simple reasons:
The Scale Bar is drawn in two different contexts a) in a pane next the window on its own in its own canvas ad b) in the navigator in a ZMapWindowContainerFeatureSet. Regardless of theis it consists of two foo canvas groups, one for text and one for ticks, which are then oriented left and right.
Theoretically the ticks and text could be swapped round but this would require correct horizontal justifcation and therefore would be more complicated that re-positioning the groups. To avoid having the extra complexity of positioning CanvasFeaturesets we propose to display ticks and text in one CanvasFeatureset, which will require pre-calculation of x-offsets to prevent the need to bump ticks and text after initial display. Note also that as we implement text and ticks as generic simple graphics features we cannot use a CanvasFeatureset zoom function to operate any such bump operation.