K-Pad is a multi-featured notepad / organizer for Windows: print-out pages or booklets of photos, tables, and rich text.More...
This is my support blog, featuring help, tutorials, and comment. Welcome. :-)

Monday 21 July 2008

K-Pad - Coder's Notes

The problem with using a generic library to do advanced coding is that eventually you will need to do something that the library can't handle: for example, putting coloured text in a treeview control. Your application then becomes limited. Writing your own code - as I did for K-Pad - takes a long time, but then, once it is done, improvements are that much easier. So, what follows is a basic run-down of all the coding modules needed to produce K-Pad.

Programming language
I chose to program in C++, due to its power and modularity. I did not want to be weighted down by clunky wrappers such as MFC (or its alternatives); instead, I would build my own code libraries, targeting the MS Windows platform (I have no time or money for Macs, and I find Linux to be too raw for its own good). I would therefore code using the Windows SDK and the Standard Template Library as my foundations.

Methodology
I adhere to principles of resource management, and the controller-view-model paradigm. Due to the relative complexity of the modules, it is absolutely essential to simplify (by which I mean "break down" into smaller pieces) as much code as possible, over-comment and never repeat common code.

Utility Classes
STL was good, but I needed more helper classes...
- Auto::Vector, Store, List, Queue: to store and manipulate arrays of memory objects.
- Auto::Map: improvements on std::map, particularly with regard to string searching, which is a lot faster using my own ternary search tree algorithm.
- Web: code to (de)cypher mark-up languages such as XML and HTML, useful especially for .ini files.
- Units: conversion between screen pixels, printer dots, mm, inches, and percentages.

Graphics Engine
Originally (and this shows how long I've been working on these libraries) I used a DirectDraw engine. However, that did not support (amongst other things) hardware transparency. I looked into using Direct3D to do "2D in 3D". I considered using Open GL, but I was already using the Windows SDK, and the documentation that I found for D3D seemed better.
To create the "2D in 3D" library, I created some classes I labelled SuperVertex. They used my map classes to create a dictionary linking shapes (and image textures) to the screen. Effectively this means I only need to redraw something that has changed.
I needed printing in addition to screen display, so everything done in D3D needed an HDC equivalent, and that all needed to be handled by SuperVertex.

Debugging
I needed a way to debug the application using a "Release" build, as some errors do not crop up in the "Debug" build, or it is too slow to debug that way. For this I wrote a separate, simple console application, which, if detected, would then be sent string status messages from K-Pad.

Interface (application)
I wanted a panelled environment, with each panel sharing the same window handle. Each panel's contents would therefore need to be clipped, and I would need to code my own (D3D) scroll-bars, title-bars, tool-bars and tab-bars. Each panel would support smooth zooming and panning of content, as required.
I wanted a lot of freedom with respect to positioning of the panels just so, and remembering the layouts (and having customizable layouts to switch to immediately as desired).
Also my own tree-view control, my own menu classes and my own tooltips classes.
Mouse and keyboard commands would have to be properly directed to the appropriate panel, translating for position and zoom as necessary.

Interface (document)
I wanted to create a set of classes to help do the grunt-work, such that I could switch from page-view to web-view, or use whatever size of document I liked, and keep any document-specific draw-code as simple as possible. So, my Output Classes handle all the page formatting, including headers, footers, margins, paper-sizes, hit-testing etc. In this way, printing code is also made simple.

Images
I needed my own basic image-handling and storage classes, to bridge the gap between D3D and the file-specific libraries I wanted to use (JPEG and PNG). I needed to be able to manipulate and resave images to different formats. Manipulation including antialiased scaling and effects like unsharp mask, blur and rotate.
D3D image classes are trickier yet, as textures are generally size-limited (at least, for good performance they are), so I needed a way to break large images into tiles, and use only those tiles necessary for display. I also needed tiles for "zoomed out" images, again to optimize drawing.

Resources
I needed code to interface common Windows Dialogs (Printer, File, Folder, Find, and Font), as well as handle Icon, String and Accelerator resources. Basic brush and pen classes too. Also TextureBanks and TextureSkins.

Save / Load
A lot of data would need to be saved. I wanted to create an engine therefore, that reduced - if not eliminated - any bugs relating to synchronizing save with load. How to do that? Have the file format read from an xml file, and let the engine handle loading and saving, based on that. Thus were born my File::Structure classes. They turn any reasonable file format (one that is not bitwise-encrypted, or absurdly complex) into a database - or database record.
In addition, I needed Document classes to handle the basic save / load / export / import methods.

Lined Paper (Text)
The main module of K-Pad. I needed all the standard NotePad features, plus WYSIWYG, instant spell-check, justification, font effects (inc. the more rare varieties like SmallCaps and double-underlining), and the ability to format words based on an external list. I wanted "unlimited" undo / redo, and embedded find and replace..
I wanted the ability to have a virtual cursor, to point anywhere on the page and be able to type there, without using space and tab, and to have that text join any existing text on the page. I don't know any other word processor that does this.
I wanted a quick way to format my play-scripts, so that it automatically adds an overhang when it detects a colon-tab dialogue combination.
All of this needed to be done using full multi-threading, so as to reduce lag for large documents.

Squared Paper
I wanted a basic DTP element. Hardly suitable for professional graphics designers and architects, but good enough for everyone else to produce something effective, like a cover page, quickly.
I needed basic shapes - including the all-important(!) curved rectangle, and I needed an image object.
I needed to handle z-ordering, in a clever way, such that if there were ten objects, and only two were overlapping, then those two would be governed by their "local" z-order.
I needed a grid - which, unlike every other application I know, would be based on the size of the selected global font. All objects would be centred automatically to ease alignment woes. I needed two types of text, a simple one (not object-based), and a special one (object-based) allowing for different fonts to be used.
I wanted a decent palette control for this, with named colours throughout. I chose to base mine on the X11 standard.

Blank Paper
The quickest module to write! I wanted the ability to insert a blank page into a booklet. Maybe this would appear right after the cover, or maybe before the back page, if the back page would otherwise appear on the inner side of the booklet.

Clipping
Another easy module to code, as much of the work is already done by the other image classes. I needed a page that would merely be an image and a caption. I wanted to link the image file, so that I wouldn't waste disk space, yet I still wanted to use simple effects to present the image the way I wanted. I know of no other application that does this. Modern processors are more than capable of handling these effects on-the-fly.

List
I wanted one module to do lists. Just simple lists, with a heading. Of course, I wanted the capacity to expand these into properly-formatted tables, ready for printing, and to be able to link the lists to other parts of the application - for example, to automatically make bold listed names in the Lined module.

Preview
K-Pad is an app that uses many pages. I needed some sort of thumbnail display to keep track of them. As K-Pad is designed primarily for producing booklets, I had the idea to present these thumbnails like a book which could be leafed through. To create the thumbnails, I'd need to capture a page, scale it down, sharpen it a bit, save to memory as a JPEG, and then convert to a D3D texture. I also required to improve the SuperVertex code in order to map the texture to a parallelogram (the "3D" page) - this rather than dabbling with actual 3D mapping.


Summary
Well, that's about it! To replicate K-Pad, just do all of the above. It shouldn't take you longer than a couple of years! It wasn't exactly easy, and there's still a lot more I want to do. Maybe I'll go into more detail in a future article...

No comments: