Re: [Tuxpaint-devel] Magic size option
An award-winning drawing program for children of all ages
Brought to you by:
wkendrick
From: Bill K. <nb...@so...> - 2023-04-20 18:05:42
|
On Thu, Apr 13, 2023 at 10:18:56AM -0700, Bill Kendrick wrote: > > I've extended Tux Paint's Magic "API", and added a UI element to the > Magic tool, to allow magic tools to support sizes. Whew! This has been tedious, and some of the older Magic tools that I don't fully understand the operation of (fancy math, etc.) have taken (or will take) a bit of work to retrofit... but I've so far gone through a lot of the plugins already, and either: (a) added support for sizes (e.g., Toothpaste can come out different thicknesses, the Bricks tool collapses down to one item in the toolbar, with two size options -- unless "--nomagicsizes" is specified, in which case it splits into two separate tools again, to avoid removing any pre-existing functionality), or (b) had them respond correctly to the updated API, so they load again (e.g., Stretch, Perspective, Checkerboard, etc. do not offer sizing options, as it wouldn't make sense). For those interested in what has been involved, generally it's: In all cases: 1. add the "Uint32 disabled_features" argument to _init() 2. create a new "Uint8 _accepted_sizes()" function 3. create a new "Uint8 _default_size()" function 4. create a new "void _set_size()" function 5. update/add function prototypes to correspond to all those And, in the case of (a), adding sizing support: 1. Change a global "const int" or "#define" value into a regular global "int", or add a new global "int" if none existed (or sometimes it was a "float") 2. Have "_accepted_sizes()" return some value > 1 3. Have "_default_size()" return a value that will end up matching the tool's size (e.g., the radius of a painted brush or applied effect) as it has been all along (in 0.9.29 & earlier). This way, "out of the box" (that is, without the user having to make adjustments to the size setting), it will work like it always has, prior to 0.9.30. And, importantly, if the "--nomagicsizes" option is set, and the sizing controls are therefore not available, it will simply work like it always has. 4. Have "_set_size()" accept the size setting (which will be a value between '1' and the maximum -- what we returned in "_accepted_sizes()") and place it into the global variable. Some calculation may take place here. i.e., if the default size was 16, I might choose to offer 6 size settings, with the default being "4", and then multiply the size by 4 to get the radius in pixels. (Therefore the tool would suppport 4px, 8px, 12px, 16px, 20px, and 24px radii.) It's all a bit arbitrary, which is where alpha & beta testing might come in handy. "Did the numbers Bill selected late at night after a long day's work _actually make sense?_" ;) 5. If the radius was hard-coded, or perhaps some other calculations were hard-coded, update them as necessary to use the new global variable. (For example, "confetti.c" used "CONFETTI_BRUSH_SIZE", but _also_ had some hard-coded numbers related to how the effect should be spread out, which I updated to be based on a multiple of CONFETTI_BRUSH_SIZE, so that it also scaled up/down properly.) 6. Watch out for other unintended consequences related to size changes! (For example, "toothpaste.c" had "toothpaste_RADIUS = 10", which I was able to utilize, but then I noticed the effect didn't work properly at sizes larger than the original. It turns out there was a kind of cached 'intensity' matrix, "toothpaste_weights", which was allocated & filled during _init(). The solution was to free(), re-malloc(), and re-fill it every time the size was changed via "_set_size()") 7. Always remember to mention new features ("tool X now supports sizes") in the changelog! (docs/CHANGES.txt) ;-) For some plugins, it's a little more complicated. Many plugins offer multiple tools, and/or run in different modes... * Size options may only make sense with some of the plugin's tools. Or, the sizes you want to make available may differ for each tool. Consult the "which" variable sent to each function, especially in "_accepted_sizes()". * For tools that offer both "painting" (brush) and "entire picture" (full canvas) application of an effect -- such as the "Blur" tool, and where the size option is being used to set the radius of the applied effect when "painting" it -- the size option doesn't make sense in the "entire picture" mode. Check the "mode" variable against "MODE_FULLSCREEN" in your "_accepted_sizes()", and return 0 or 1 (both mean the same), in that case. Note: This isn't a hard and fast rule. As long as it's not confusing to users, it might actually make sense for the "sizing" options to have different meanings in the two different modes. While I'm generally using for the literal size (radius) of an effect, the sizing option could also be used to indicate "intensity". And, for example, the "Bricks" tools use size to dictate the size of the brick shapes, not a specific "radius". Finally, in the case of (b), making plugins work again (without supporting size options), simply extend the plugin so it contains all of the functions that the updated API requires. This was handled in the "in all cases" steps above, but to wrap that up, you need to: 1. Have "_accepted_sizes()" return a 0 (or a 1), which means "I only offer one size; do not make the sizing controls available". 2. Have "_default_size()" return anything (0 makes sense). 3. "_set_size()" can be an empty function. Unfortunately, I'm not sure how to get Tux Paint to detect whether a function knows to accept certain arguments or not, but it does complain (& avoid trying to load any Magic tools from a plugin) if functions are completely missing. So when you run Tux Paint, you will see complaints like: Error: plugin /usr/local/lib/tuxpaint/plugins/clone.so is missing accepted_sizes Error: plugin /usr/local/lib/tuxpaint/plugins/clone.so is missing default_size Error: plugin /usr/local/lib/tuxpaint/plugins/clone.so is missing set_size (Despite this, I'm also also being sure to update every plugin's "init()" function, to accept the new "Uint32 disabled_features" argument.) For examples of where plugins detect "--nomagicsizes" being set ("_init()" receives the bit "MAGIC_FEATURE_SIZE" in "disabled_features"), and then behave differently, see "googlyeyes.c" and "bricks.c". Those plugins historically provided two different tools (large & small). Now, they can just provide one tool which offers two (or more) sizes via the new sizing feature. However, if the sizing feature is disabled, they revert back to providing two separate tools, as they did in 0.9.29 & prior. Whew! I hope this all makes sense; typing it up over a long period while doing other things. :-) -bill! |