From 26c7051c072dc565a1719271978ddbbf49c75aeb Mon Sep 17 00:00:00 2001
From: William Kendrick
Date: Fri, 3 Aug 2007 16:17:46 +0000
Subject: [PATCH] Stamps can now be pre-flipped and/or pre-mirrored-and-flipped
now (in addition to pre-mirrored). Updated version # in some docs. Expanded
comments in tp_magic_example.c Magic plugin example code.
---
docs/ADVANCED-STAMPS-HOWTO.txt | 4 +-
docs/CHANGES.txt | 7 +-
docs/EXTENDING.txt | 23 +-
docs/FAQ.txt | 4 +-
docs/OPTIONS.txt | 2 +-
docs/README.txt | 2 +-
docs/html/ADVANCED-STAMPS-HOWTO.html | 4 +-
docs/html/EXTENDING.html | 28 +-
docs/html/FAQ.html | 4 +-
docs/html/OPTIONS.html | 2 +-
docs/html/README.html | 2 +-
magic/docs/tp_magic_example.c | 483 ++++++++++++++++++++++-----
src/tuxpaint.c | 380 ++++++++++++++++++---
13 files changed, 783 insertions(+), 162 deletions(-)
diff --git a/docs/ADVANCED-STAMPS-HOWTO.txt b/docs/ADVANCED-STAMPS-HOWTO.txt
index d28c4ee7d..7443df2f3 100644
--- a/docs/ADVANCED-STAMPS-HOWTO.txt
+++ b/docs/ADVANCED-STAMPS-HOWTO.txt
@@ -1,5 +1,5 @@
Tux Paint
- version 0.9.17
+ version 0.9.18
Advanced Stamps HOWTO
Copyright 2006 by Albert Cahalan for the Tux Paint project
@@ -8,7 +8,7 @@
albert@users.sf.net
http://www.tuxpaint.org/
- March 8, 2006 - October 26, 2006
+ March 8, 2006 - August 2, 2007
About this HOWTO
diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt
index 5c0d7d4d1..07809af33 100644
--- a/docs/CHANGES.txt
+++ b/docs/CHANGES.txt
@@ -9,7 +9,7 @@ http://www.tuxpaint.org/
$Id$
-2007.July.19 (0.9.18)
+2007.August.2 (0.9.18)
* Interface Improvements:
-----------------------
* Improved 'New' and 'Open' interface:
@@ -27,6 +27,11 @@ $Id$
* Added an Octagon shape to the 'Shapes' tool.
+ * Stamps can now be pre-flipped and/or pre-mirrored-and-flipped now
+ (in addition to pre-mirrored).
+ Use "_flip.png"/"_flip.svg" and "_mirror_flip.png"/"_mirror_flip.png",
+ respectively.
+
* Documentation Imrpovements:
---------------------------
* Improved --usage output.
diff --git a/docs/EXTENDING.txt b/docs/EXTENDING.txt
index 7f00e7d54..aa6505b98 100644
--- a/docs/EXTENDING.txt
+++ b/docs/EXTENDING.txt
@@ -1,5 +1,5 @@
Tux Paint
- version 0.9.17
+ version 0.9.18
Extending Tux Paint
Copyright 2002-2007 by Bill Kendrick and others
@@ -8,7 +8,7 @@
bill@newbreedsoftware.com
http://www.tuxpaint.org/
- June 14, 2002 - May 6, 2007
+ June 14, 2002 - August 2, 2007
--------------------------------------------------------------------------
@@ -428,22 +428,31 @@ Stamps
it as Plain Text, and make sure the filename has ".dat" at the end,
and not ".txt"...
- Pre-Mirrored Images
+ Pre-Mirrored and Flipped Images
In some cases, you may wish to provide a pre-drawn version of a
- stamp's mirror-image. For example, imagine a picture of a fire truck
- with the words "Fire Department" written across the side. You probably
- do not want that text to appear backwards when the image is flipped!
+ stamp's mirror-image, flipped image, or even both. For example,
+ imagine a picture of a fire truck with the words "Fire Department"
+ written across the side. You probably do not want that text to appear
+ backwards when the image is flipped!
To create a mirrored version of a stamp that you want Tux Paint to
use, rather than mirroring one on its own, simply create a second
- ".png" graphics file with the same name, except with the string
+ ".png" or ".svg" graphics file with the same name, except with
"_mirror" before the filename extension.
For example, for the stamp "truck.png" you would create another file
named "truck_mirror.png", which will be used when the stamp is
mirrored (rather than using a backwards version of 'truck.png').
+ As of Tux Paint 0.9.18, you may similarly provide a pre-flipped image
+ with "_flip" in the name, and/or an image that is both mirrored and
+ flipped, by naming it "_mirror_flip".
+
+ Note: If the user flips and mirrors an image, and a pre-drawn
+ "_mirror_flip" doesn't exist, but either "_flip" or "_mirror" does, it
+ will be used, and mirrored or flipped, respectively.
+
--------------------------------------------------------------------------
Fonts
diff --git a/docs/FAQ.txt b/docs/FAQ.txt
index eaad42f4d..fe39a1940 100644
--- a/docs/FAQ.txt
+++ b/docs/FAQ.txt
@@ -1,5 +1,5 @@
Tux Paint
- version 0.9.17
+ version 0.9.18
Frequently Asked Questions
Copyright 2002-2007 by Bill Kendrick and others
@@ -8,7 +8,7 @@
bill@newbreedsoftware.com
http://www.tuxpaint.org/
- September 14, 2002 - June 27, 2007
+ September 14, 2002 - August 2, 2007
Drawing-related
diff --git a/docs/OPTIONS.txt b/docs/OPTIONS.txt
index 5ab0fd415..326920375 100644
--- a/docs/OPTIONS.txt
+++ b/docs/OPTIONS.txt
@@ -1,5 +1,5 @@
Tux Paint
- version 0.9.17
+ version 0.9.18
Options Documentation
diff --git a/docs/README.txt b/docs/README.txt
index 84a3e9176..b2e5c976a 100644
--- a/docs/README.txt
+++ b/docs/README.txt
@@ -1,5 +1,5 @@
Tux Paint
- version 0.9.17
+ version 0.9.18
A simple drawing program for children
diff --git a/docs/html/ADVANCED-STAMPS-HOWTO.html b/docs/html/ADVANCED-STAMPS-HOWTO.html
index f24ae07af..3fc736e9c 100644
--- a/docs/html/ADVANCED-STAMPS-HOWTO.html
+++ b/docs/html/ADVANCED-STAMPS-HOWTO.html
@@ -11,7 +11,7 @@ alink="#FF00FF">
alt="Tux Paint">
version
-0.9.17
+0.9.18
Advanced Stamps HOWTO
@@ -21,7 +21,7 @@ New Breed Software
albert@users.sf.net
http://www.tuxpaint.org/
-March 8, 2006 - October 26, 2006
+March 8, 2006 - August 2, 2007
diff --git a/docs/html/EXTENDING.html b/docs/html/EXTENDING.html
index f5cee893c..4fa134e40 100644
--- a/docs/html/EXTENDING.html
+++ b/docs/html/EXTENDING.html
@@ -12,7 +12,7 @@ alt="Tux Paint">
version
-0.9.17
+0.9.18
Extending Tux Paint
@@ -23,7 +23,7 @@ New Breed Software
bill@newbreedsoftware.com
http://www.tuxpaint.org/
-June 14, 2002 - May 6, 2007
+June 14, 2002 - August 2, 2007
@@ -558,24 +558,34 @@ effect.
- Pre-Mirrored Images
+ Pre-Mirrored and Flipped Images
In some cases, you may wish to provide a pre-drawn version of
- a stamp's mirror-image. For example, imagine a picture of a fire
- truck with the words "Fire Department" written across
- the side. You probably do not want that text to appear backwards
- when the image is flipped!
+ a stamp's mirror-image, flipped image, or even both. For example,
+ imagine a picture of a fire truck with the words
+ "Fire Department" written across the side. You probably
+ do not want that text to appear backwards when the image is flipped!
To create a mirrored version of a stamp that you want Tux Paint
to use, rather than mirroring one on its own, simply create a second
- ".png" graphics file with the same name, except with
- the string "_mirror" before the filename
+ ".png" or ".svg" graphics file with the
+ same name, except with "_mirror" before the filename
extension.
For example, for the stamp "truck.png" you would
create another file named "truck_mirror.png", which
will be used when the stamp is mirrored (rather than using a
backwards version of 'truck.png').
+
+ As of Tux Paint 0.9.18, you may similarly provide a pre-flipped
+ image with "_flip" in the name, and/or an image that
+ is both mirrored and flipped, by naming it
+ "_mirror_flip".
+
+ Note: If the user flips and mirrors an image, and a pre-drawn
+ "_mirror_flip" doesn't exist, but either "_flip"
+ or "_mirror" does, it will be used, and mirrored or flipped,
+ respectively.
diff --git a/docs/html/FAQ.html b/docs/html/FAQ.html
index f95d188ab..2d17eac10 100644
--- a/docs/html/FAQ.html
+++ b/docs/html/FAQ.html
@@ -11,7 +11,7 @@ alink="#FF00FF">
alt="Tux Paint">
version
-0.9.17
+0.9.18
Frequently Asked Questions
@@ -22,7 +22,7 @@ New Breed Software
bill@newbreedsoftware.com
http://www.tuxpaint.org/
-September 14, 2002 - June 27, 2007
+September 14, 2002 - August 2, 2007
Drawing-related
diff --git a/docs/html/OPTIONS.html b/docs/html/OPTIONS.html
index ec2beb2a6..23dfdcdf9 100644
--- a/docs/html/OPTIONS.html
+++ b/docs/html/OPTIONS.html
@@ -11,7 +11,7 @@ alink="#FF00FF">
version
-0.9.17
+0.9.18
Options Documentation
diff --git a/docs/html/README.html b/docs/html/README.html
index 1cf25d98f..41da88783 100644
--- a/docs/html/README.html
+++ b/docs/html/README.html
@@ -12,7 +12,7 @@ alt="Tux Paint">
version
-0.9.17
+0.9.18
A simple drawing program for children
diff --git a/magic/docs/tp_magic_example.c b/magic/docs/tp_magic_example.c
index c2118d27b..d73bb1266 100644
--- a/magic/docs/tp_magic_example.c
+++ b/magic/docs/tp_magic_example.c
@@ -1,176 +1,481 @@
+/* tp_magic_example.c
+
+ An example of a "Magic" tool plugin for Tux Paint
+*/
+
+
+/* Inclusion of header files: */
+/* -------------------------- */
+
#include
-#include
-#include
-#include "tp_magic_api.h"
-#include "SDL_image.h"
-#include "SDL_mixer.h"
+#include // For "strdup()"
+#include // For "gettext()"
+
+#include "tp_magic_api.h" // Tux Paint "Magic" tool API header
+#include "SDL_image.h" // For IMG_Load(), to load our PNG icon
+#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
+
+
+/* Tool Enumerations: */
+/* ------------------ */
/* What tools we contain: */
enum {
- TOOL_ONE,
- TOOL_TWO,
- NUM_TOOLS
+ TOOL_ONE, // Becomes '0'
+ TOOL_TWO, // Becomes '1'
+ NUM_TOOLS // Becomes '2'
};
-/* Our globals: */
+/* A list of filenames for sounds and icons to load at startup: */
+const char * snd_filenames[NUM_TOOLS] = {
+ "one.wav",
+ "two.wav"
+};
+
+const char * icon_filenames[NUM_TOOLS] = {
+ "one.png",
+ "two.png"
+};
+
+
+// Below, we define a macro called "gettext_noop()" that does nothing in our
+// code when compiled (it simply disappears; e.g., 'gettext_noop("foo")'
+// becomes simply "foo"), but is useful because the gettext localization
+// tools will look for it and create a catalog of strings that should be
+// translated into other languages.
+
+#ifndef gettext_noop
+#define gettext_noop(String) String
+#endif
+
+// We'll use this macro below, in some arrays of strings (char *'s) that
+// hold the names and descriptions of our "Magic" tools.
+
+
+/* A list of names for the tools */
+
+const char * names[NUM_TOOLS] = {
+ gettext_noop("A tool"),
+ gettext_noop("Another tool")
+};
+
+
+/* A list of descriptions of the tools */
+
+const char * descs[NUM_TOOLS] = {
+ gettext_noop("This is example tool number 1."),
+ gettext_noop("This is example tool number 2.")
+};
+
+
+
+/* Our global variables: */
+/* --------------------- */
+
+/* Sound effects: */
Mix_Chunk * snd_effect[NUM_TOOLS];
+
+/* The current color (an "RGB" value) the user has selected in Tux Paint: */
Uint8 example_r, example_g, example_b;
-Uint32 example_api_version(void) { return(TP_MAGIC_API_VERSION); }
+/* Our local function prototypes: */
+/* ------------------------------ */
+
+// These functions are called by other functions within our plugin,
+// so we provide a 'prototype' of them, so the compiler knows what
+// they accept and return. This lets us use them in other functions
+// that are declared _before_ them.
+
+void example_drag(magic_api * api, int which, SDL_Surface * canvas,
+ SDL_Surface * snapshot, int ox, int oy, int x, int y,
+ SDL_Rect * update_rect);
+
+void example_line_callback(void * ptr, int which,
+ SDL_Surface * canvas, SDL_Surface * snapshot,
+ int x, int y);
-// No setup required:
+/* Setup Functions: */
+/* ---------------- */
+
+// API Version check
+//
+// The running copy of Tux Paint that has loaded us first asks us what
+// version of the Tux Paint "Magic" tool plugin API we were built against.
+// If it deems us compatible, we'll be used!
+//
+// All we need to do here is return "TP_MAGIC_API_VERSION",
+// which is #define'd in tp_magic_api.h.
+
+Uint32 example_api_version(void)
+{
+ return(TP_MAGIC_API_VERSION);
+}
+
+
+// Initialization
+//
+// This happens once, when Tux Paint starts up and is loading all of the
+// "Magic" tool plugins. (Assuming what we returned from api_version() was
+// acceptable!)
+//
+// All we're doing in this example is loading our sound effects,
+// which we'll use later (in click(), drag() and release())
+// when the user is using our Magic tools.
+//
+// The memory we allocate here to store the sounds will be
+// freed (aka released, aka deallocated) when the user quits Tux Paint,
+// when our shutdown() function is called.
+
int example_init(magic_api * api)
{
+ int i;
char fname[1024];
- snprintf(fname, sizeof(fname), "%s/sounds/magic/one.wav",
- api->data_directory);
- snd_effect[0] = Mix_LoadWAV(fname);
+ for (i = 0; i < NUM_TOOLS; i++)
+ {
+ // Assemble the filename from the "snd_filenames[]" array into
+ // a full path to a real file.
+ //
+ // Use "api->data_directory" to figure out where our sounds should be.
+ // (The "tp-magic-config --dataprefix" command would have told us when
+ // we installed our plugin and its data.)
- snprintf(fname, sizeof(fname), "%s/sounds/magic/two.wav",
- api->data_directory);
- snd_effect[1] = Mix_LoadWAV(fname);
+ snprintf(fname, sizeof(fname),
+ "%s/sounds/magic/%s.wav",
+ api->data_directory, snd_filenames[i]);
+
+
+ // Try to load the file!
+
+ snd_effect[i] = Mix_LoadWAV(fname);
+ }
return(1);
}
-// We have multiple tools:
+
+// Report our tool count
+//
+// Tux Paint needs to know how many "Magic" tools we'll be providing.
+// Return that number here. (We simply grab the value of "NUM_TOOLS"
+// from our 'enum' above!)
+//
+// When Tux Paint is starting up and loading plugins, it will call
+// some of the following setup functions once for each tool we report.
+
int example_get_tool_count(magic_api * api)
{
return(NUM_TOOLS);
}
-// Load our icons:
+
+// Load icons
+//
+// When Tux Paint is starting up and loading plugins, it asks us to
+// provide icons for the "Magic" tool buttons.
+
SDL_Surface * example_get_icon(magic_api * api, int which)
{
char fname[1024];
- if (which == TOOL_ONE)
- {
- snprintf(fname, sizeof(fname), "%s/images/magic/one.png",
- api->data_directory);
- }
- else if (which == TOOL_TWO)
- {
- snprintf(fname, sizeof(fname), "%s/images/magic/two.png",
- api->data_directory);
- }
+ // Assemble the filename from the "icon_filenames[]" array into
+ // a full path to a real file.
+ //
+ // Use "api->data_directory" to figure out where our sounds should be.
+ // (The "tp-magic-config --dataprefix" command would have told us when
+ // we installed our plugin and its data.)
+ //
+ // We use 'which' (which of our tools Tux Paint is asking about)
+ // as an index into the array.
+
+ snprintf(fname, sizeof(fname), "%s/images/magic/%s.png",
+ api->data_directory, icon_filenames[which]);
+
+
+ // Try to load the image, and return the results to Tux Paint:
return(IMG_Load(fname));
}
-// Return our names, localized:
+
+// Report our "Magic" tool names
+//
+// When Tux Paint is starting up and loading plugins, it asks us to
+// provide names (labels) for the "Magic" tool buttons.
+
char * example_get_name(magic_api * api, int which)
{
- if (which == TOOL_ONE)
- return(strdup(gettext("One")));
- else if (which == TOOL_TWO)
- return(strdup(gettext("Two")));
+ const char * our_name_english;
+ const char * our_name_localized;
- return(NULL);
+ // Get our name from the "names[]" array.
+ //
+ // We use 'which' (which of our tools Tux Paint is asking about)
+ // as an index into the array.
+
+ our_name_english = names[which];
+
+
+ // Return a localized (aka translated) version of our name,
+ // if possible.
+ //
+ // We send "gettext()" the English version of the name from our array.
+
+ our_name_localized = gettext(our_name_english);
+
+
+ // Finally, duplicate the string into a new section of memory, and
+ // send it to Tux Paint. (Tux Paint keeps track of the string and
+ // will free it for us, so we have one less thing to keep track of.)
+
+ return(strdup(our_name_localized));
}
-// Return our descriptions, localized:
+
+// Report our "Magic" tool descriptions
+//
+// When Tux Paint is starting up and loading plugins, it asks us to
+// provide names (labels) for the "Magic" tool buttons.
+
char * example_get_description(magic_api * api, int which)
{
- if (which == TOOL_ONE)
- return(strdup(gettext("Tool one.")));
- else
- return(strdup(gettext("Tool two.")));
+ const char * our_desc_english;
+ const char * our_desc_localized;
- return(NULL);
+ // Get our desc from the "descs[]" array.
+ //
+ // We use 'which' (which of our tools Tux Paint is asking about)
+ // as an index into the array.
+
+ our_desc_english = descs[which];
+
+
+ // Return a localized (aka translated) version of our description,
+ // if possible.
+ //
+ // We send "gettext()" the English version of the description from our array.
+
+ our_desc_localized = gettext(our_desc_english);
+
+
+ // Finally, duplicate the string into a new section of memory, and
+ // send it to Tux Paint. (Tux Paint keeps track of the string and
+ // will free it for us, so we have one less thing to keep track of.)
+
+ return(strdup(our_desc_localized));
}
-// Do the effect:
+// Report whether we accept colors
-void do_example(void * ptr, int which, SDL_Surface * canvas, SDL_Surface * last,
- int x, int y)
+int example_requires_colors(magic_api * api, int which)
{
- magic_api * api = (magic_api *) ptr;
- int xx, yy;
+ // Both of our tools accept colors, so we're always returning '1' (for "true")
- if (which == TOOL_ONE)
- {
- api->putpixel(canvas, x, y, SDL_MapRGB(canvas->format,
- example_r,
- example_g,
- example_b));
- }
- else if (which == TOOL_TWO)
- {
- for (yy = -4; yy < 4; yy++)
- {
- for (xx = -4; xx < 4; xx++)
- {
- api->putpixel(canvas, x + xx, y + yy,
- api->getpixel(last,
- canvas->w - x - xx,
- canvas->h - y - yy));
- }
- }
- }
+ return 1;
}
+
+// Shut down
+//
+// Tux Paint is quitting. When it quits, it asks all of the plugins
+// to 'clean up' after themselves. We, for example, loaded some sound
+// effects at startup (in our init() function), so we should free the
+// memory used by them now.
+
+void example_shutdown(magic_api * api)
+{
+ int i;
+
+ // Free (aka release, aka deallocate) the memory used to store the
+ // sound effects that we loaded during init():
+
+ for (i = 0; i < NUM_TOOLS; i++)
+ Mix_FreeChunk(snd_effect[i]);
+}
+
+
+/* Functions that respond to events in Tux Paint: */
+/* ---------------------------------------------- */
+
+// Affect the canvas on click:
+
+void example_click(magic_api * api, int which,
+ SDL_Surface * canvas, SDL_Surface * snapshot,
+ int x, int y, SDL_Rect * update_rect)
+{
+ // In our case, a single click (which is also the start of a drag!)
+ // is identical to what dragging does, but just at one point, rather
+ // than across a line.
+ //
+ // So we 'cheat' here, by calling our draw() function with
+ // (x,y) for both the beginning and end points of a line.
+
+ example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
+}
+
+
// Affect the canvas on drag:
+
void example_drag(magic_api * api, int which, SDL_Surface * canvas,
- SDL_Surface * last, int ox, int oy, int x, int y,
+ SDL_Surface * snapshot, int ox, int oy, int x, int y,
SDL_Rect * update_rect)
{
- api->line(which, canvas, last, ox, oy, x, y, 1, do_example);
+ // Call Tux Paint's "line()" function.
+ //
+ // It will calculate a straight line between (ox,ox) and (x,y).
+ // Every N steps along that line (in this case, N is '1'), it
+ // will call _our_ function, "example_line_callback()", and send
+ // the current X,Y coordinates along the line, as well as other
+ // useful things (which of our "Magic" tools is being used and
+ // the current and snapshot canvases).
+
+ api->line(which, canvas, snapshot, ox, oy, x, y, 1, example_line_callback);
+
+
+ // If we need to, swap the X and/or Y values, so that
+ // (ox,oy) is always the top left, and (x,y) is always the bottom right,
+ // so the values we put inside "update_rect" make sense:
if (ox > x) { int tmp = ox; ox = x; x = tmp; }
if (oy > y) { int tmp = oy; oy = y; y = tmp; }
+
+ // Fill in the elements of the "update_rect" SDL_Rect structure
+ // that Tux Paint is sharing with us.
+
update_rect->x = ox - 4;
update_rect->y = oy - 4;
update_rect->w = (x + 4) - update_rect->x;
update_rect->h = (y + 4) - update_rect->h;
+
+ // Play the appropriate sound effect
+ //
+ // We're calculating a value between 0-255 for where the mouse is
+ // across the canvas (0 is the left, ~128 is the center, 255 is the right).
+ //
+ // These are the exact values Tux Paint's "playsound()" wants,
+ // to determine what speaker to play the sound in.
+ // (So the sound will pan from speaker to speaker as you drag the
+ // mouse around the canvas!)
+
api->playsound(snd_effect[which],
- (x * 255) / canvas->w, (y * 255) / canvas->h);
+ (x * 255) / canvas->w, // pan
+ 255); // distance
}
-// Affect the canvas on click:
-void example_click(magic_api * api, int which,
- SDL_Surface * canvas, SDL_Surface * last,
- int x, int y, SDL_Rect * update_rect)
-{
- example_drag(api, which, canvas, last, x, y, x, y, update_rect);
-}
// Affect the canvas on release:
+
void example_release(magic_api * api, int which,
- SDL_Surface * canvas, SDL_Surface * last,
+ SDL_Surface * canvas, SDL_Surface * snapshot,
int x, int y, SDL_Rect * update_rect)
{
+ // Neither of our effects do anything special when the mouse is released
+ // from a click or click-and-drag, so there's no code here...
}
-// No setup happened:
-void example_shutdown(magic_api * api)
-{
- if (snd_effect[0] != NULL)
- Mix_FreeChunk(snd_effect[0]);
- if (snd_effect[1] != NULL)
- Mix_FreeChunk(snd_effect[1]);
-}
+// Accept colors
+//
+// When any of our "Magic" tools are activated by the user,
+// if that tool accepts colors, the current color selection is sent to us.
+//
+// Additionally, if one of our color-accepting tools is active when the
+// user changes colors, we'll be informed of that, as well.
+//
+// The color comes in as RGB values.
-// Record the color from Tux Paint:
void example_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b)
{
+ // We simply store the RGB values in the global variables we
+ // declared at the top of this file.
+
example_r = r;
example_g = g;
example_b = b;
}
-// Use colors:
-int example_requires_colors(magic_api * api, int which)
+
+/* The Magic Effect Routines! */
+/* -------------------------- */
+
+// Our "callback" function
+//
+// We do the 'work' in this callback. Our plugin file has just one.
+// Some "Magic" tool plugins may have more, depending on the tools they're
+// providing. Some have none (since they're not click-and-drag
+// painting-style tools).
+//
+// Our callback function gets called once for every point along a line between
+// the mouse's previous and current position, as it's being dragged.
+//
+// It pays attention to 'which' to determine which of our plugin's tools
+// is currently selected.
+
+void example_line_callback(void * ptr, int which,
+ SDL_Surface * canvas, SDL_Surface * snapshot,
+ int x, int y)
{
- return 1;
+ // For technical reasons, we can't accept a pointer to the "magic_api"
+ // struct, like the other functions do.
+ //
+ // Instead, we receive a 'generic' pointer (a "void *").
+ // The line below declares a local "magic_api" pointer variable called "api",
+ // and then assigns it to the value of the 'generic' pointer we received.
+ //
+ // (The "(magic_api *)" casts the generic pointer into the 'type' of
+ // pointer we want, a pointer to a "magic_api".)
+ magic_api * api = (magic_api *) ptr;
+ int xx, yy;
+
+
+ // This function handles both of our tools, so we need to check which
+ // is being used right now. We compare the 'which' argument that
+ // Tux Paint sends to us with the values we enumerated above.
+
+ if (which == TOOL_ONE)
+ {
+ // Tool number 1 simply draws a single pixel at the (x,y) location.
+ // It's a 1x1 pixel brush
+
+ api->putpixel(canvas, x, y, SDL_MapRGB(canvas->format,
+ example_r,
+ example_g,
+ example_b));
+
+ // We use "SDL_MapRGB()" to convert the RGB value we receive from Tux Paint
+ // for the user's current color selection to a 'Uint32' pixel value
+ // we can send to Tux Paint's "putpixel()" function.
+ }
+ else if (which == TOOL_TWO)
+ {
+ // Tool number 2 copies an 8x8 square of pixels from the opposite side
+ // of the canvas and puts it under the cursor
+
+ for (yy = -4; yy < 4; yy++)
+ {
+ for (xx = -4; xx < 4; xx++)
+ {
+ api->putpixel(canvas, x + xx, y + yy,
+ api->getpixel(snapshot,
+ canvas->w - x - xx,
+ canvas->h - y - yy));
+
+ // We simply use Tux Paint's "getpixel()" routine to pull pixel
+ // values from the 'snapshot', and then "putpixel()" to draw them
+ // right into the 'canvas'.
+
+ // Note: putpixel() and getpixel() are safe to use, even if your
+ // X,Y values are outside of the SDL surface (e.g., negative, or
+ // greater than the surface's width or height).
+ }
+ }
+ }
}
diff --git a/src/tuxpaint.c b/src/tuxpaint.c
index c23dd0f32..ca306a532 100644
--- a/src/tuxpaint.c
+++ b/src/tuxpaint.c
@@ -1160,7 +1160,10 @@ typedef struct stamp_type
SDL_Surface *thumbnail;
unsigned thumb_mirrored:1;
unsigned thumb_flipped:1;
+ unsigned thumb_mirrored_flipped:1;
unsigned no_premirror:1;
+ unsigned no_preflip:1;
+ unsigned no_premirrorflip:1;
unsigned processed:1; // got *.dat, computed size limits, etc.
@@ -5206,9 +5209,8 @@ static void set_active_stamp(void)
{
stamp_type *sd = stamp_data[stamp_group][cur_stamp[stamp_group]];
unsigned len = strlen(sd->stampname);
- char *buf = alloca(len + strlen("_mirror.EXT") + 1);
-
- /* FIXME: Add support for pre-flipped stamps! -bjk 2007.03.22 */
+ char *buf = alloca(len + strlen("_mirror_flip.EXT") + 1);
+ int needs_mirror, needs_flip;
if (active_stamp)
SDL_FreeSurface(active_stamp);
@@ -5216,8 +5218,129 @@ static void set_active_stamp(void)
memcpy(buf, sd->stampname, len);
- if (sd->mirrored && !sd->no_premirror)
+ printf("\nset_active_stamp()\n");
+
+ /* Look for pre-mirrored and pre-flipped version: */
+
+ needs_mirror = sd->mirrored;
+ needs_flip = sd->flipped;
+
+ if (sd->mirrored && sd->flipped)
{
+ /* Want mirrored and flipped, both */
+
+ printf("want both mirrored & flipped\n");
+
+ if (!sd->no_premirrorflip)
+ {
+#ifndef NOSVG
+ memcpy(buf + len, "_mirror_flip.svg", 17);
+ active_stamp = do_loadimage(buf, 0);
+#endif
+
+ if (active_stamp == NULL)
+ {
+ memcpy(buf + len, "_mirror_flip.png", 17);
+ active_stamp = do_loadimage(buf, 0);
+ }
+ }
+
+
+ if (active_stamp != NULL)
+ {
+ printf("found a _mirror_flip!\n");
+
+ needs_mirror = 0;
+ needs_flip = 0;
+ }
+ else
+ {
+ /* Couldn't get one that was both, look for _mirror then _flip and
+ flip or mirror it: */
+
+ printf("didn't find a _mirror_flip\n");
+
+ if (!sd->no_premirror)
+ {
+#ifndef NOSVG
+ memcpy(buf + len, "_mirror.svg", 12);
+ active_stamp = do_loadimage(buf, 0);
+#endif
+
+ if (active_stamp == NULL)
+ {
+ memcpy(buf + len, "_mirror.png", 12);
+ active_stamp = do_loadimage(buf, 0);
+ }
+ }
+
+ if (active_stamp != NULL)
+ {
+ printf("found a _mirror!\n");
+ needs_mirror = 0;
+ }
+ else
+ {
+ /* Couldn't get one that was just pre-mirrored, look for a
+ pre-flipped */
+
+ printf("didn't find a _mirror, either\n");
+
+ if (!sd->no_preflip)
+ {
+#ifndef NOSVG
+ memcpy(buf + len, "_flip.svg", 10);
+ active_stamp = do_loadimage(buf, 0);
+#endif
+
+ if (active_stamp == NULL)
+ {
+ memcpy(buf + len, "_flip.png", 10);
+ active_stamp = do_loadimage(buf, 0);
+ }
+ }
+
+ if (active_stamp != NULL)
+ {
+ printf("found a _flip!\n");
+ needs_flip = 0;
+ }
+ else
+ printf("didn't find a _flip, either\n");
+ }
+ }
+ }
+ else if (sd->flipped && !sd->no_preflip)
+ {
+ /* Want flipped only */
+
+ printf("want flipped only\n");
+
+#ifndef NOSVG
+ memcpy(buf + len, "_flip.svg", 10);
+ active_stamp = do_loadimage(buf, 0);
+#endif
+
+ if (active_stamp == NULL)
+ {
+ memcpy(buf + len, "_flip.png", 10);
+ active_stamp = do_loadimage(buf, 0);
+ }
+
+ if (active_stamp != NULL)
+ {
+ printf("found a _flip!\n");
+ needs_flip = 0;
+ }
+ else
+ printf("didn't find a _flip\n");
+ }
+ else if (sd->mirrored && !sd->no_premirror)
+ {
+ /* Want mirrored only */
+
+ printf("want mirrored only\n");
+
#ifndef NOSVG
memcpy(buf + len, "_mirror.svg", 12);
active_stamp = do_loadimage(buf, 0);
@@ -5228,11 +5351,25 @@ static void set_active_stamp(void)
memcpy(buf + len, "_mirror.png", 12);
active_stamp = do_loadimage(buf, 0);
}
+
+ if (active_stamp != NULL)
+ {
+ printf("found a _mirror!\n");
+ needs_mirror = 0;
+ }
+ else
+ printf("didn't find a _mirror\n");
}
+
+ /* Didn't want mirrored, or flipped, or couldn't load anything
+ that was pre-rendered: */
+
if (!active_stamp)
{
-#ifndef NOSVG
+ printf("loading normal\n");
+
+#ifndef NOSVG
memcpy(buf + len, ".svg", 5);
active_stamp = do_loadimage(buf, 0);
#endif
@@ -5243,27 +5380,44 @@ static void set_active_stamp(void)
active_stamp = do_loadimage(buf, 0);
}
- if (!active_stamp)
- active_stamp = thumbnail(img_dead40x40, 40, 40, 1); // copy it
- if (sd->mirrored)
- active_stamp = mirror_surface(active_stamp);
}
- if (sd->flipped)
+ /* Never allow a NULL image! */
+
+ if (!active_stamp)
+ active_stamp = thumbnail(img_dead40x40, 40, 40, 1); // copy it
+
+
+ /* If we wanted mirrored or flipped, and didn't get something pre-rendered,
+ do it to the image we did load: */
+
+ if (needs_mirror)
+ {
+ printf("mirroring\n");
+ active_stamp = mirror_surface(active_stamp);
+ }
+
+ if (needs_flip)
+ {
+ printf("flipping\n");
active_stamp = flip_surface(active_stamp);
+ }
+
+ printf("\n\n");
}
static void get_stamp_thumb(stamp_type * sd)
{
SDL_Surface *bigimg = NULL;
unsigned len = strlen(sd->stampname);
- char *buf = alloca(len + strlen("_mirror.EXT") + 1);
- SDL_Surface *wrongmirror = NULL;
- int need_mirror = 0;
+ char *buf = alloca(len + strlen("_mirror_flip.EXT") + 1);
+ int need_mirror, need_flip;
double ratio;
unsigned w;
unsigned h;
+ printf("\nget_stamp_thumb()\n");
+
memcpy(buf, sd->stampname, len);
if (!sd->processed)
@@ -5302,25 +5456,111 @@ static void get_stamp_thumb(stamp_type * sd)
sd->no_txt = !sd->stxt;
}
+
// first see if we can re-use an existing thumbnail
if (sd->thumbnail)
{
- if (sd->mirrored == sd->thumb_mirrored)
+ printf("have an sd->thumbnail\n");
+
+ if (sd->thumb_mirrored_flipped == sd->flipped &&
+ sd->thumb_mirrored_flipped == sd->mirrored &&
+ sd->mirrored == sd->thumb_mirrored &&
+ sd->flipped == sd->thumb_flipped)
{
- if (sd->flipped == sd->thumb_flipped)
- return;
- sd->thumbnail = flip_surface(sd->thumbnail);
- sd->thumb_flipped = !sd->thumb_flipped;
+ // It's already the way we want
+ printf("mirrored == flipped == thumb_mirrored_flipped [bye]\n");
return;
}
- wrongmirror = sd->thumbnail;
}
- /* FIXME: Add support for pre-flipped stamps! -bjk 2007.03.22 */
- // nope, unless perhaps it can be mirrored
- if (sd->mirrored && !sd->no_premirror)
+ // nope, see if there's a pre-rendered one we can use
+
+ need_mirror = sd->mirrored;
+ need_flip = sd->flipped;
+ bigimg = NULL;
+
+ if (sd->mirrored && sd->flipped)
{
+ printf("want mirrored & flipped\n");
+
+ if (!sd->no_premirrorflip)
+ {
+ memcpy(buf + len, "_mirror_flip.png", 17);
+ bigimg = do_loadimage(buf, 0);
+
+#ifndef NOSVG
+ if (bigimg == NULL)
+ {
+ memcpy(buf + len, "_mirror_flip.svg", 17);
+ bigimg = do_loadimage(buf, 0);
+ }
+#endif
+ }
+
+ if (bigimg)
+ {
+ printf("found a _mirror_flip!\n");
+
+ need_mirror = 0;
+ need_flip = 0;
+ }
+ else
+ {
+ printf("didn't find a mirror_flip\n");
+ sd->no_premirrorflip = 1;
+
+ if (!sd->no_premirror)
+ {
+ memcpy(buf + len, "_mirror.png", 12);
+ bigimg = do_loadimage(buf, 0);
+
+#ifndef NOSVG
+ if (bigimg == NULL)
+ {
+ memcpy(buf + len, "_mirror.svg", 12);
+ bigimg = do_loadimage(buf, 0);
+ }
+#endif
+ }
+
+ if (bigimg)
+ {
+ printf("found a _mirror\n");
+
+ need_mirror = 0;
+ }
+ else
+ {
+ printf("didn't find a mirror\n");
+
+ if (!sd->no_preflip)
+ {
+ memcpy(buf + len, "_flip.png", 10);
+ bigimg = do_loadimage(buf, 0);
+
+#ifndef NOSVG
+ if (bigimg == NULL)
+ {
+ memcpy(buf + len, "_flip.svg", 10);
+ bigimg = do_loadimage(buf, 0);
+ }
+#endif
+ }
+
+ if (bigimg)
+ {
+ printf("found a _flip\n");
+
+ need_flip = 0;
+ }
+ }
+ }
+ }
+ else if (sd->mirrored && !sd->no_premirror)
+ {
+ printf("want mirrored only\n");
+
memcpy(buf + len, "_mirror.png", 12);
bigimg = do_loadimage(buf, 0);
@@ -5334,26 +5574,49 @@ static void get_stamp_thumb(stamp_type * sd)
if (bigimg)
{
- if (wrongmirror)
- SDL_FreeSurface(wrongmirror);
+ printf("found a _mirror!\n");
+ need_mirror = 0;
}
else
+ {
+ printf("didn't find a mirror\n");
sd->no_premirror = 1;
+ }
}
- if (wrongmirror && sd->no_premirror)
+ else if (sd->flipped && !sd->no_preflip)
{
- wrongmirror = mirror_surface(wrongmirror);
- sd->thumbnail = wrongmirror;
- sd->thumb_mirrored = !sd->thumb_mirrored;
+ printf("want flipped only\n");
- if (sd->flipped == sd->thumb_flipped)
- return;
- sd->thumbnail = flip_surface(sd->thumbnail);
- sd->thumb_flipped = !sd->thumb_flipped;
- return;
+ memcpy(buf + len, "_flip.png", 10);
+ bigimg = do_loadimage(buf, 0);
+
+#ifndef NOSVG
+ if (bigimg == NULL)
+ {
+ memcpy(buf + len, "_flip.svg", 10);
+ bigimg = do_loadimage(buf, 0);
+ }
+#endif
+
+ if (bigimg)
+ {
+ printf("found a _flip!\n");
+ need_flip = 0;
+ }
+ else
+ {
+ printf("didn't find a flip\n");
+ sd->no_preflip = 1;
+ }
}
+
+
+ /* If we didn't load a pre-rendered, load the normal one: */
+
if (!bigimg)
{
+ printf("loading normal...\n");
+
memcpy(buf + len, ".png", 5);
bigimg = do_loadimage(buf, 0);
@@ -5364,11 +5627,11 @@ static void get_stamp_thumb(stamp_type * sd)
bigimg = do_loadimage(buf, 0);
}
#endif
-
- if (sd->mirrored)
- need_mirror = 1; // want to mirror after scaling
}
+
+ /* Scale the stamp down to its thumbnail size: */
+
w = 40;
h = 40;
if (bigimg)
@@ -5387,16 +5650,41 @@ static void get_stamp_thumb(stamp_type * sd)
else
sd->thumbnail = bigimg;
- if (need_mirror)
- sd->thumbnail = mirror_surface(sd->thumbnail);
- sd->thumb_mirrored = sd->mirrored;
- if (sd->flipped)
+ /* Mirror and/or flip the thumbnail, if we still need to do so: */
+
+ if (need_mirror)
+ {
+ printf("mirroring\n");
+ sd->thumbnail = mirror_surface(sd->thumbnail);
+ }
+
+ if (need_flip)
+ {
+ printf("flipping\n");
sd->thumbnail = flip_surface(sd->thumbnail);
+ }
+
+
+ /* Note the fact that the thumbnail's mirror/flip is the same as the main
+ stamp: */
+
+ if (sd->mirrored && sd->flipped)
+ sd->thumb_mirrored_flipped = 1;
+ else
+ sd->thumb_mirrored_flipped = 0;
+
+ sd->thumb_mirrored = sd->mirrored;
sd->thumb_flipped = sd->flipped;
+ printf("\n\n");
+
+
+ /* Finish up, if we need to: */
+
if (sd->processed)
return;
+
sd->processed = 1; // not really, but on the next line...
loadstamp_finisher(sd, w, h, ratio);
}
@@ -5451,12 +5739,12 @@ static void loadstamp_callback(SDL_Surface * screen,
while (i--)
{
char fname[512];
- const char *dotext, *ext, *mirror_ext;
-
- /* FIXME: Support pre-flipped stamps -bjk 2007.03.22 */
+ const char *dotext, *ext, *mirror_ext, *flip_ext, *mirrorflip_ext;
ext = ".png";
mirror_ext = "_mirror.png";
+ flip_ext = "_flip.png";
+ mirrorflip_ext = "_mirror_flip.png";
dotext = (char *) strcasestr(files[i].str, ext);
#ifndef NOSVG
@@ -5464,6 +5752,8 @@ static void loadstamp_callback(SDL_Surface * screen,
{
ext = ".svg";
mirror_ext = "_mirror.svg";
+ flip_ext = "_flip.svg";
+ mirrorflip_ext = "_mirror_flip.svg";
dotext = (char *) strcasestr(files[i].str, ext);
}
else
@@ -5494,7 +5784,9 @@ static void loadstamp_callback(SDL_Surface * screen,
if (dotext > files[i].str && !strcasecmp(dotext, ext)
&& (dotext - files[i].str + 1 + dirlen < sizeof fname)
- && !strcasestr(files[i].str, mirror_ext))
+ && !strcasestr(files[i].str, mirror_ext)
+ && !strcasestr(files[i].str, flip_ext)
+ && !strcasestr(files[i].str, mirrorflip_ext))
{
snprintf(fname, sizeof fname, "%s/%s", dir, files[i].str);
if (num_stamps[stamp_group] == max_stamps[stamp_group])