Tons of features and UI bits still to come, but as of this build, the basics are finally in place. The new gradient editor supports adding/editing/removing an arbitrary number of nodes, all gradient settings are correctly serialized to/from XML strings, GDI+ gradient brushes can be successfully constructed from the results, and PD's brush control can already save/load gradient brushes just like solid and pattern brushes. I've tried to design the gradient editor to be extremely flexible, which will allow me to use gradients in multiple places throughout the project (e.g. a dedicated gradient paint tool vs a gradient map tool). This will enable a range of neat features without the need for complicated custom gradient code, and thanks to the modular design of the pdGradient class, it shouldn't be too much work to someday implement gradient types unsupported by GDI+ (e.g. spiral). Next up is all the missing UI bits for modifying gradient nodes (color, opacity, etc), implementing angle and wrap and other parameters, and after that, "automatic" gradient creation a la Photoshop's "noise gradients" (https://helpx.adobe.com/photoshop/using/gradients.html).
This removes an enormous amount of redundant code, and greatly shrinks the pdLayer class (~700 LoC). It also provides an excellent template for future layer types, where pdLayer only exposes two generic get/set functions for custom layer attributes, which are just wrappers around a separate, dedicated class (which has to manage all that custom data anyway). This should also slightly improve text layer rendering performance, as we do not need to reset text parameters between draws. (All text data is now persistent inside pdTextRenderer.)
PD's internals now respect the differences between basic text layers and typography layers. Instead of silently converting between basic text and typography rendering (which resulted in very confusing behavior, especially at image load-time), the relevant tool panels now explain to the user that they can non-destructively convert text layers to whatever format they desire. This approach doesn't interrupt work flow, and it prevents text layers from changing appearance every time the user switches tools. (Also: as clearly stated in the prompt, converting between layer types is completely non-destructive, and PD shares as many properties as it can between various text layer types.)
Currently, text and typography layers are interchangeable from a coding standpoint. I actually want to forcibly differentiate these layer definitions, to prep for tools like "Convert Text to Generic Vector Layer". (Typography layers expose text as vector objects, while the text tool operates strictly in the raster domain due to the use of system text APIs.) This is also a required change before implementing a "WordArt" type tool (for handling more complicated text shape transformations, like text-to-path).
These were my test case for the new XML-based serializer, and so far, so good.
Another nasty project I've put off for far too long is standardizing PD's internal parameter class (which tracks data passing between PD's central processor and individual processing functions, so we can record it for macros and the like) against PD's various file-specific functions, which have all been migrated to XML. This has been a blocker for a bunch of tasks, including a built-in macro editor (for creating macros without needing to actually *record* them). I've now completed a pdParamXML class which is just about a drop-in replacement for the old pdParamString class. This class fixes a lot of obnoxious interop issues, and it's also much better for backwards-compatibility between versions, as individual processing functions can track parameters by name instead of by ordinal (where parameter changes are impossible to auto-detect). The long-term goal is to remove all function-specific processing from PD's central processor, and have it just blindly pass strings to/from individual functions (instead of parsing out individual parameters, as it does now). Besides macro editing, this is also is a required change before I can implement an official plugin module, but please note that it's going to take some time to get everything switched. Also, this will break macro backwards-compatibility for the 7.0 release. Sorry.
All 53 GDI+ pattern styles are now exposed in a single, custom-built drop-down box. To minimize localization efforts, hatches are listed by numeric ID and live preview, rather than text description. (As an added bonus, I find this much more intuitive than say Paint.NET's similar dropdown, which just gives a tiny 16x16 preview of the brush and wastes the rest of the space on pointless text.) Because PD is awesome, all objects that support generic PD brushes (currently just text layers) automatically acquire this new support.
These controls were sorely missing some kind of visual feedback
WARNING: massive commit! PD 7.0 is going to provide a single master Fill class (brush in GDI/GDI+) and Stroke class (pen in GDI/GDI+) as the back-end for anything that can be filled and/or outlined, eg. text, shapes, arrows, whatever. My goal is to make these classes support every fill/outline setting under the sun, and because the resulting settings are just stored as strings, all new tools will automatically support every fill/outline setting under the sun without any extra work on my part. This commit is the first step toward making that possible. The Typography tool already exposed a lot of these features manually, but now, I've reworked the fill-specific settings into a single, standalone UC with a custom dialog and corresponding render class (pdGraphicsBrush). From here on out, any feature added to the user control + rendering class will be automatically available to all other tools, which is great! There is still a *ton* to implement in the dialog, and textures in particular are going to be weird and messy, but this is an important first step. Note that this commit *IS NOT BACKWARDS COMPATIBLE WITH TEXT IN EXISTING PDI FILES*. PDI text layers will still save/load just fine, but any previous fill settings will be lost, as they are now stored in a totally different format. I will likely be modifying this format further in the coming weeks, so as with any developer build, don't save PDI files you can't afford to lose (just in case). Note that text background region fill settings are also lost; however, text backgrounds now support 100% of the features available when filling the text, so you now have way more options available for text backgrounds. The outline/pen UC is still TBD, but now that the bulk of the infrastructure for the Brush UC + rendering class is done (all that's left is feature implementation), I may turn to the outline/pen tool so I can call the Typography tool more or less done. Then I can move onto implementing other on-canvas tools while still plugging away at fill/outline features. We'll see.
Not glyph-level. With this change, an outlined underline/strikeout looks like one contiguous line, instead of a bunch of tiny glyph-width lines placed next to each other. Trailing whitespace chars are also ignored when calculating underline/strikeout width and placement.
Some path transforms can fail unpredictably; if this happens, the typography tool will now try to be smarter about restoring an unmodified version of the glyph (as a "better than nothing" last resort).
The font's specified positioning and sizing is used in both cases, woohoo! (I'll probably end up moving the actual rendering to a different position in the text engine so that outlining doesn't show the lines between characters, and trailing spaces are ignored, but that's easily done now that I've cracked how to pull the relevant information out of WAPI.)
… behavior GetOutlineTextMetrics is a neat WAPI function that provides a ton of useful data, but man, struct alignment for the return is a disaster, and MSDN isn't helpful because VB silently performs its own word alignment, negating the need for some of the dummy padding bytes. I think I've sorted everything out, since I'm getting proper returns on the underline and strikeout entries on both XP and Win 8. Fingers crossed that more testing bears this out.
…perties Always good to have a failsafe with performance-sensitive features.
Language-specific font properties are no longer cached at program startup (because it was killing performance; see fcfeb0f). Instead, the round-robin cache used by the font dropdown UC caches those properties on-demand. Testing on a 2001-era PC shows no trouble with this approach, so I'm content to make it permanent.
(Well, maybe not the *absolute last* as I still need to fix underline and strikethrough... sigh) Anyway, after this commit, it's time to shift gears and start working on dedicated UCs for pen and brush selection. This will not only let me clean up the Typography tool's various "visual" panels, but will also save me a ton of work on eventual Shape tools (which make use of the same fill and stroke features).
Lots of fun per-character options
This will be an ongoing WIP, seeing as there are so many random system-interaction bits throughout the project, but moving one of the bigger modules into a class is a good start.
Fixes #162. Everything in the original issue report has been handled, save the creation of a matching UC. That's outside the scope of what I need right now, but I'll revisit if/when it becomes relevant.
Yep, PD's that awesome. ;) To keep the on-canvas UI simple, shear can only be controlled from the move/size tool panel. I've seen other software try to cram shear controls onto the canvas (e.g. Inkscape) but this gets unruly pretty quickly. Also, I've temporarily suspended on-canvas arc prediction if shearing is active, because I haven't solved the math necessary to draw a sheared arc without it warping to strange new locations.
I can't promise that these will actually work, but since I've gone to the trouble of implementing matrix-based affine transforms, it should theoretically be trivial to add non-destructive shearing too. If my theory proves incorrect, this commit "causes no harm" so it won't need to be rolled back (and perhaps I can revisit in the future).
If the user initiates a merge operation on an image with text/vector layers, rasterization prompts will now be displayed ONLY if a text/vector layer is actually involved in the current merge operation. Said another way, merging 2+ raster layers will never raise a rasterization prompt.
Cropping to a rectangular selection can be handled instantaneously by simply adjusting layer offsets and canvas size. This effectively makes it a non-destructive operation, as no image data is lost - but even better, it avoids the need for rasterizing text and vector layers!
Resize, rotate, etc now process rotated layers correctly. Since I was here, I also optimized various functions related to these transforms to cut down on memory churn. Overall performance should be much better, especially on systems where RAM is tight.