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.
This commit is contained in:
William Kendrick 2007-08-03 16:17:46 +00:00
parent 51c6783846
commit 26c7051c07
13 changed files with 783 additions and 162 deletions

View file

@ -1,5 +1,5 @@
Tux Paint Tux Paint
version 0.9.17 version 0.9.18
Advanced Stamps HOWTO Advanced Stamps HOWTO
Copyright 2006 by Albert Cahalan for the Tux Paint project Copyright 2006 by Albert Cahalan for the Tux Paint project
@ -8,7 +8,7 @@
albert@users.sf.net albert@users.sf.net
http://www.tuxpaint.org/ http://www.tuxpaint.org/
March 8, 2006 - October 26, 2006 March 8, 2006 - August 2, 2007
About this HOWTO About this HOWTO

View file

@ -9,7 +9,7 @@ http://www.tuxpaint.org/
$Id$ $Id$
2007.July.19 (0.9.18) 2007.August.2 (0.9.18)
* Interface Improvements: * Interface Improvements:
----------------------- -----------------------
* Improved 'New' and 'Open' interface: * Improved 'New' and 'Open' interface:
@ -27,6 +27,11 @@ $Id$
* Added an Octagon shape to the 'Shapes' tool. * 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: * Documentation Imrpovements:
--------------------------- ---------------------------
* Improved --usage output. * Improved --usage output.

View file

@ -1,5 +1,5 @@
Tux Paint Tux Paint
version 0.9.17 version 0.9.18
Extending Tux Paint Extending Tux Paint
Copyright 2002-2007 by Bill Kendrick and others Copyright 2002-2007 by Bill Kendrick and others
@ -8,7 +8,7 @@
bill@newbreedsoftware.com bill@newbreedsoftware.com
http://www.tuxpaint.org/ 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, it as Plain Text, and make sure the filename has ".dat" at the end,
and not ".txt"... 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 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 stamp's mirror-image, flipped image, or even both. For example,
with the words "Fire Department" written across the side. You probably imagine a picture of a fire truck with the words "Fire Department"
do not want that text to appear backwards when the image is flipped! 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 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 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. "_mirror" before the filename extension.
For example, for the stamp "truck.png" you would create another file For example, for the stamp "truck.png" you would create another file
named "truck_mirror.png", which will be used when the stamp is named "truck_mirror.png", which will be used when the stamp is
mirrored (rather than using a backwards version of 'truck.png'). 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 Fonts

View file

@ -1,5 +1,5 @@
Tux Paint Tux Paint
version 0.9.17 version 0.9.18
Frequently Asked Questions Frequently Asked Questions
Copyright 2002-2007 by Bill Kendrick and others Copyright 2002-2007 by Bill Kendrick and others
@ -8,7 +8,7 @@
bill@newbreedsoftware.com bill@newbreedsoftware.com
http://www.tuxpaint.org/ http://www.tuxpaint.org/
September 14, 2002 - June 27, 2007 September 14, 2002 - August 2, 2007
Drawing-related Drawing-related

View file

@ -1,5 +1,5 @@
Tux Paint Tux Paint
version 0.9.17 version 0.9.18
Options Documentation Options Documentation

View file

@ -1,5 +1,5 @@
Tux Paint Tux Paint
version 0.9.17 version 0.9.18
A simple drawing program for children A simple drawing program for children

View file

@ -11,7 +11,7 @@ alink="#FF00FF">
alt="Tux&nbsp;Paint"><br> alt="Tux&nbsp;Paint"><br>
version version
0.9.17 0.9.18
<br> <br>
Advanced Stamps HOWTO</h1> Advanced Stamps HOWTO</h1>
@ -21,7 +21,7 @@ New Breed Software</p>
<p><a href="mailto:albert@users.sf.net">albert@users.sf.net</a><br> <p><a href="mailto:albert@users.sf.net">albert@users.sf.net</a><br>
<a href="http://www.tuxpaint.org/">http://www.tuxpaint.org/</a></p> <a href="http://www.tuxpaint.org/">http://www.tuxpaint.org/</a></p>
<p>March 8, 2006 - October 26, 2006</p> <p>March 8, 2006 - August 2, 2007</p>
</center> </center>

View file

@ -12,7 +12,7 @@ alt="Tux&nbsp;Paint"><br>
version version
0.9.17 0.9.18
<br> <br>
Extending Tux Paint</h1> Extending Tux Paint</h1>
@ -23,7 +23,7 @@ New Breed Software</p>
<p><a href="mailto:bill@newbreedsoftware.com">bill@newbreedsoftware.com</a><br> <p><a href="mailto:bill@newbreedsoftware.com">bill@newbreedsoftware.com</a><br>
<a href="http://www.tuxpaint.org/">http://www.tuxpaint.org/</a></p> <a href="http://www.tuxpaint.org/">http://www.tuxpaint.org/</a></p>
<p>June 14, 2002 - May 6, 2007</p> <p>June 14, 2002 - August 2, 2007</p>
</center> </center>
<hr size=2 noshade> <hr size=2 noshade>
@ -558,24 +558,34 @@ effect.</p>
</blockquote> </blockquote>
</blockquote> </blockquote>
<h3>Pre-Mirrored Images</h3> <h3>Pre-Mirrored and Flipped Images</h3>
<blockquote> <blockquote>
<p>In some cases, you may wish to provide a pre-drawn version of <p>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 a stamp's mirror-image, flipped image, or even both. For example,
truck with the words "<i>Fire&nbsp;Department</i>" written across imagine a picture of a fire&nbsp;truck with the words
the side. You probably do not want that text to appear backwards "<i>Fire&nbsp;Department</i>" written across the side. You probably
when the image is flipped!</p> do not want that text to appear backwards when the image is flipped!</p>
<p>To create a mirrored version of a stamp that you want Tux&nbsp;Paint <p>To create a mirrored version of a stamp that you want Tux&nbsp;Paint
to use, rather than mirroring one on its own, simply create a second to use, rather than mirroring one on its own, simply create a second
"<code>.png</code>" graphics file with the same name, except with "<code>.png</code>" or "<code>.svg</code>" graphics file with the
the string "<code><b>_mirror</b></code>" before the filename same name, except with "<code><b>_mirror</b></code>" before the filename
extension.</p> extension.</p>
<p>For example, for the stamp "<code><b>truck.png</b></code>" you would <p>For example, for the stamp "<code><b>truck.png</b></code>" you would
create another file named "<code><b>truck_mirror.png</b></code>", which create another file named "<code><b>truck_mirror.png</b></code>", which
will be used when the stamp is mirrored (rather than using a will be used when the stamp is mirrored (rather than using a
backwards version of '<code>truck.png</code>').</p> backwards version of '<code>truck.png</code>').</p>
<p>As of Tux&nbsp;Paint 0.9.18, you may similarly provide a pre-flipped
image with "<code><b>_flip</b></code>" in the name, and/or an image that
is both mirrored and flipped, by naming it
"<code><b>_mirror_flip</b></code>".</p>
<p><b>Note:</b> If the user flips and mirrors an image, and a pre-drawn
"<code>_mirror_flip</code>" doesn't exist, but either "<code>_flip</code>"
or "<code>_mirror</code>" does, it will be used, and mirrored or flipped,
respectively.</p>
</blockquote> </blockquote>
</blockquote> </blockquote>

View file

@ -11,7 +11,7 @@ alink="#FF00FF">
alt="Tux&nbsp;Paint"><br> alt="Tux&nbsp;Paint"><br>
version version
0.9.17 0.9.18
<br> <br>
Frequently Asked Questions</h1> Frequently Asked Questions</h1>
@ -22,7 +22,7 @@ New Breed Software</p>
<p><a href="mailto:bill@newbreedsoftware.com">bill@newbreedsoftware.com</a><br> <p><a href="mailto:bill@newbreedsoftware.com">bill@newbreedsoftware.com</a><br>
<a href="http://www.tuxpaint.org/">http://www.tuxpaint.org/</a></p> <a href="http://www.tuxpaint.org/">http://www.tuxpaint.org/</a></p>
<p>September 14, 2002 - June 27, 2007</p> <p>September 14, 2002 - August 2, 2007</p>
</center> </center>
<h2>Drawing-related</h2> <h2>Drawing-related</h2>

View file

@ -11,7 +11,7 @@ alink="#FF00FF">
version version
0.9.17 0.9.18
</h1> </h1>
<h2>Options Documentation</h2> <h2>Options Documentation</h2>

View file

@ -12,7 +12,7 @@ alt="Tux&nbsp;Paint"><br>
version version
0.9.17 0.9.18
</h1> </h1>
<h3>A simple drawing program for children</h3> <h3>A simple drawing program for children</h3>

View file

@ -1,176 +1,481 @@
/* tp_magic_example.c
An example of a "Magic" tool plugin for Tux Paint
*/
/* Inclusion of header files: */
/* -------------------------- */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h> // For "strdup()"
#include <libintl.h> #include <libintl.h> // For "gettext()"
#include "tp_magic_api.h"
#include "SDL_image.h" #include "tp_magic_api.h" // Tux Paint "Magic" tool API header
#include "SDL_mixer.h" #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: */ /* What tools we contain: */
enum { enum {
TOOL_ONE, TOOL_ONE, // Becomes '0'
TOOL_TWO, TOOL_TWO, // Becomes '1'
NUM_TOOLS 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]; 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; 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 example_init(magic_api * api)
{ {
int i;
char fname[1024]; char fname[1024];
snprintf(fname, sizeof(fname), "%s/sounds/magic/one.wav", for (i = 0; i < NUM_TOOLS; i++)
api->data_directory); {
snd_effect[0] = Mix_LoadWAV(fname); // 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", snprintf(fname, sizeof(fname),
api->data_directory); "%s/sounds/magic/%s.wav",
snd_effect[1] = Mix_LoadWAV(fname); api->data_directory, snd_filenames[i]);
// Try to load the file!
snd_effect[i] = Mix_LoadWAV(fname);
}
return(1); 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) int example_get_tool_count(magic_api * api)
{ {
return(NUM_TOOLS); 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) SDL_Surface * example_get_icon(magic_api * api, int which)
{ {
char fname[1024]; char fname[1024];
if (which == TOOL_ONE) // Assemble the filename from the "icon_filenames[]" array into
{ // a full path to a real file.
snprintf(fname, sizeof(fname), "%s/images/magic/one.png", //
api->data_directory); // Use "api->data_directory" to figure out where our sounds should be.
} // (The "tp-magic-config --dataprefix" command would have told us when
else if (which == TOOL_TWO) // we installed our plugin and its data.)
{ //
snprintf(fname, sizeof(fname), "%s/images/magic/two.png", // We use 'which' (which of our tools Tux Paint is asking about)
api->data_directory); // 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(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) char * example_get_name(magic_api * api, int which)
{ {
if (which == TOOL_ONE) const char * our_name_english;
return(strdup(gettext("One"))); const char * our_name_localized;
else if (which == TOOL_TWO)
return(strdup(gettext("Two")));
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) char * example_get_description(magic_api * api, int which)
{ {
if (which == TOOL_ONE) const char * our_desc_english;
return(strdup(gettext("Tool one."))); const char * our_desc_localized;
else
return(strdup(gettext("Tool two.")));
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 example_requires_colors(magic_api * api, int which)
int x, int y)
{ {
magic_api * api = (magic_api *) ptr; // Both of our tools accept colors, so we're always returning '1' (for "true")
int xx, yy;
if (which == TOOL_ONE) 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)
{ {
api->putpixel(canvas, x, y, SDL_MapRGB(canvas->format, int i;
example_r,
example_g, // Free (aka release, aka deallocate) the memory used to store the
example_b)); // sound effects that we loaded during init():
for (i = 0; i < NUM_TOOLS; i++)
Mix_FreeChunk(snd_effect[i]);
} }
else if (which == TOOL_TWO)
/* 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)
{ {
for (yy = -4; yy < 4; yy++) // 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
for (xx = -4; xx < 4; xx++) // than across a line.
{ //
api->putpixel(canvas, x + xx, y + yy, // So we 'cheat' here, by calling our draw() function with
api->getpixel(last, // (x,y) for both the beginning and end points of a line.
canvas->w - x - xx,
canvas->h - y - yy)); example_drag(api, which, canvas, snapshot, x, y, x, y, update_rect);
}
}
}
} }
// Affect the canvas on drag: // Affect the canvas on drag:
void example_drag(magic_api * api, int which, SDL_Surface * canvas, 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) 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 (ox > x) { int tmp = ox; ox = x; x = tmp; }
if (oy > y) { int tmp = oy; oy = y; y = 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->x = ox - 4;
update_rect->y = oy - 4; update_rect->y = oy - 4;
update_rect->w = (x + 4) - update_rect->x; update_rect->w = (x + 4) - update_rect->x;
update_rect->h = (y + 4) - update_rect->h; 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], 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: // Affect the canvas on release:
void example_release(magic_api * api, int which, 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) 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) // Accept colors
Mix_FreeChunk(snd_effect[1]); //
} // 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) 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_r = r;
example_g = g; example_g = g;
example_b = b; 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).
}
}
}
} }

View file

@ -1160,7 +1160,10 @@ typedef struct stamp_type
SDL_Surface *thumbnail; SDL_Surface *thumbnail;
unsigned thumb_mirrored:1; unsigned thumb_mirrored:1;
unsigned thumb_flipped:1; unsigned thumb_flipped:1;
unsigned thumb_mirrored_flipped:1;
unsigned no_premirror:1; unsigned no_premirror:1;
unsigned no_preflip:1;
unsigned no_premirrorflip:1;
unsigned processed:1; // got *.dat, computed size limits, etc. 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]]; stamp_type *sd = stamp_data[stamp_group][cur_stamp[stamp_group]];
unsigned len = strlen(sd->stampname); unsigned len = strlen(sd->stampname);
char *buf = alloca(len + strlen("_mirror.EXT") + 1); char *buf = alloca(len + strlen("_mirror_flip.EXT") + 1);
int needs_mirror, needs_flip;
/* FIXME: Add support for pre-flipped stamps! -bjk 2007.03.22 */
if (active_stamp) if (active_stamp)
SDL_FreeSurface(active_stamp); SDL_FreeSurface(active_stamp);
@ -5216,7 +5218,49 @@ static void set_active_stamp(void)
memcpy(buf, sd->stampname, len); 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 #ifndef NOSVG
memcpy(buf + len, "_mirror.svg", 12); memcpy(buf + len, "_mirror.svg", 12);
@ -5230,8 +5274,101 @@ static void set_active_stamp(void)
} }
} }
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);
#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
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) if (!active_stamp)
{ {
printf("loading normal\n");
#ifndef NOSVG #ifndef NOSVG
memcpy(buf + len, ".svg", 5); memcpy(buf + len, ".svg", 5);
active_stamp = do_loadimage(buf, 0); active_stamp = do_loadimage(buf, 0);
@ -5243,27 +5380,44 @@ static void set_active_stamp(void)
active_stamp = do_loadimage(buf, 0); active_stamp = do_loadimage(buf, 0);
} }
}
/* Never allow a NULL image! */
if (!active_stamp) if (!active_stamp)
active_stamp = thumbnail(img_dead40x40, 40, 40, 1); // copy it active_stamp = thumbnail(img_dead40x40, 40, 40, 1); // copy it
if (sd->mirrored)
/* 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); active_stamp = mirror_surface(active_stamp);
} }
if (sd->flipped) if (needs_flip)
{
printf("flipping\n");
active_stamp = flip_surface(active_stamp); active_stamp = flip_surface(active_stamp);
} }
printf("\n\n");
}
static void get_stamp_thumb(stamp_type * sd) static void get_stamp_thumb(stamp_type * sd)
{ {
SDL_Surface *bigimg = NULL; SDL_Surface *bigimg = NULL;
unsigned len = strlen(sd->stampname); unsigned len = strlen(sd->stampname);
char *buf = alloca(len + strlen("_mirror.EXT") + 1); char *buf = alloca(len + strlen("_mirror_flip.EXT") + 1);
SDL_Surface *wrongmirror = NULL; int need_mirror, need_flip;
int need_mirror = 0;
double ratio; double ratio;
unsigned w; unsigned w;
unsigned h; unsigned h;
printf("\nget_stamp_thumb()\n");
memcpy(buf, sd->stampname, len); memcpy(buf, sd->stampname, len);
if (!sd->processed) if (!sd->processed)
@ -5302,25 +5456,111 @@ static void get_stamp_thumb(stamp_type * sd)
sd->no_txt = !sd->stxt; sd->no_txt = !sd->stxt;
} }
// first see if we can re-use an existing thumbnail // first see if we can re-use an existing thumbnail
if (sd->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) // It's already the way we want
return; printf("mirrored == flipped == thumb_mirrored_flipped [bye]\n");
sd->thumbnail = flip_surface(sd->thumbnail);
sd->thumb_flipped = !sd->thumb_flipped;
return; return;
} }
wrongmirror = sd->thumbnail;
} }
/* FIXME: Add support for pre-flipped stamps! -bjk 2007.03.22 */
// nope, unless perhaps it can be mirrored // nope, see if there's a pre-rendered one we can use
if (sd->mirrored && !sd->no_premirror)
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); memcpy(buf + len, "_mirror.png", 12);
bigimg = do_loadimage(buf, 0); bigimg = do_loadimage(buf, 0);
@ -5334,26 +5574,49 @@ static void get_stamp_thumb(stamp_type * sd)
if (bigimg) if (bigimg)
{ {
if (wrongmirror) printf("found a _mirror!\n");
SDL_FreeSurface(wrongmirror); need_mirror = 0;
} }
else else
{
printf("didn't find a mirror\n");
sd->no_premirror = 1; sd->no_premirror = 1;
} }
if (wrongmirror && sd->no_premirror)
{
wrongmirror = mirror_surface(wrongmirror);
sd->thumbnail = wrongmirror;
sd->thumb_mirrored = !sd->thumb_mirrored;
if (sd->flipped == sd->thumb_flipped)
return;
sd->thumbnail = flip_surface(sd->thumbnail);
sd->thumb_flipped = !sd->thumb_flipped;
return;
} }
else if (sd->flipped && !sd->no_preflip)
{
printf("want flipped only\n");
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) if (!bigimg)
{ {
printf("loading normal...\n");
memcpy(buf + len, ".png", 5); memcpy(buf + len, ".png", 5);
bigimg = do_loadimage(buf, 0); bigimg = do_loadimage(buf, 0);
@ -5364,11 +5627,11 @@ static void get_stamp_thumb(stamp_type * sd)
bigimg = do_loadimage(buf, 0); bigimg = do_loadimage(buf, 0);
} }
#endif #endif
if (sd->mirrored)
need_mirror = 1; // want to mirror after scaling
} }
/* Scale the stamp down to its thumbnail size: */
w = 40; w = 40;
h = 40; h = 40;
if (bigimg) if (bigimg)
@ -5387,16 +5650,41 @@ static void get_stamp_thumb(stamp_type * sd)
else else
sd->thumbnail = bigimg; 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); 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; sd->thumb_flipped = sd->flipped;
printf("\n\n");
/* Finish up, if we need to: */
if (sd->processed) if (sd->processed)
return; return;
sd->processed = 1; // not really, but on the next line... sd->processed = 1; // not really, but on the next line...
loadstamp_finisher(sd, w, h, ratio); loadstamp_finisher(sd, w, h, ratio);
} }
@ -5451,12 +5739,12 @@ static void loadstamp_callback(SDL_Surface * screen,
while (i--) while (i--)
{ {
char fname[512]; char fname[512];
const char *dotext, *ext, *mirror_ext; const char *dotext, *ext, *mirror_ext, *flip_ext, *mirrorflip_ext;
/* FIXME: Support pre-flipped stamps -bjk 2007.03.22 */
ext = ".png"; ext = ".png";
mirror_ext = "_mirror.png"; mirror_ext = "_mirror.png";
flip_ext = "_flip.png";
mirrorflip_ext = "_mirror_flip.png";
dotext = (char *) strcasestr(files[i].str, ext); dotext = (char *) strcasestr(files[i].str, ext);
#ifndef NOSVG #ifndef NOSVG
@ -5464,6 +5752,8 @@ static void loadstamp_callback(SDL_Surface * screen,
{ {
ext = ".svg"; ext = ".svg";
mirror_ext = "_mirror.svg"; mirror_ext = "_mirror.svg";
flip_ext = "_flip.svg";
mirrorflip_ext = "_mirror_flip.svg";
dotext = (char *) strcasestr(files[i].str, ext); dotext = (char *) strcasestr(files[i].str, ext);
} }
else else
@ -5494,7 +5784,9 @@ static void loadstamp_callback(SDL_Surface * screen,
if (dotext > files[i].str && !strcasecmp(dotext, ext) if (dotext > files[i].str && !strcasecmp(dotext, ext)
&& (dotext - files[i].str + 1 + dirlen < sizeof fname) && (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); snprintf(fname, sizeof fname, "%s/%s", dir, files[i].str);
if (num_stamps[stamp_group] == max_stamps[stamp_group]) if (num_stamps[stamp_group] == max_stamps[stamp_group])