Sync'd docs to get new tp_magic_example.c
...now localizable!
This commit is contained in:
parent
3160b07a3c
commit
9986ef2a49
24 changed files with 5360 additions and 139 deletions
7
Makefile
7
Makefile
|
|
@ -4,7 +4,7 @@
|
||||||
# Various contributors (see AUTHORS.txt)
|
# Various contributors (see AUTHORS.txt)
|
||||||
# http://www.tuxpaint.org/
|
# http://www.tuxpaint.org/
|
||||||
|
|
||||||
# June 14, 2002 - October 3, 2022
|
# June 14, 2002 - October 18, 2022
|
||||||
|
|
||||||
|
|
||||||
# The version number, for release:
|
# The version number, for release:
|
||||||
|
|
@ -244,7 +244,6 @@ MAGIC_PREFIX:=$(DESTDIR)$(LIBDIR)/lib$(LIBDIRSUFFIX)/tuxpaint/plugins
|
||||||
|
|
||||||
# Docs and man page:
|
# Docs and man page:
|
||||||
DOC_PREFIX:=$(DESTDIR)$(PREFIX)/share/doc/tuxpaint-$(VER_VERSION)
|
DOC_PREFIX:=$(DESTDIR)$(PREFIX)/share/doc/tuxpaint-$(VER_VERSION)
|
||||||
DEVDOC_PREFIX:=$(DESTDIR)$(PREFIX)/share/doc/tuxpaint-$(VER_VERSION)/tuxpaint-dev
|
|
||||||
MAN_PREFIX:=$(DESTDIR)$(PREFIX)/share/man
|
MAN_PREFIX:=$(DESTDIR)$(PREFIX)/share/man
|
||||||
DEVMAN_PREFIX:=$(DESTDIR)$(PREFIX)/share/man
|
DEVMAN_PREFIX:=$(DESTDIR)$(PREFIX)/share/man
|
||||||
|
|
||||||
|
|
@ -649,9 +648,6 @@ install-magic-plugin-dev: src/tp_magic_api.h
|
||||||
@install -d $(INCLUDE_PREFIX)/tuxpaint
|
@install -d $(INCLUDE_PREFIX)/tuxpaint
|
||||||
@cp src/tp_magic_api.h $(INCLUDE_PREFIX)/tuxpaint
|
@cp src/tp_magic_api.h $(INCLUDE_PREFIX)/tuxpaint
|
||||||
@chmod a+r,g-w,o-w $(INCLUDE_PREFIX)/tuxpaint/tp_magic_api.h
|
@chmod a+r,g-w,o-w $(INCLUDE_PREFIX)/tuxpaint/tp_magic_api.h
|
||||||
@install -d $(DEVDOC_PREFIX)
|
|
||||||
@cp -R magic/docs/* $(DEVDOC_PREFIX)
|
|
||||||
@chmod a=rX,g=rX,u=rwX $(DEVDOC_PREFIX)
|
|
||||||
|
|
||||||
# Installs the various parts for the MinGW/MSYS development/testing environment.
|
# Installs the various parts for the MinGW/MSYS development/testing environment.
|
||||||
|
|
||||||
|
|
@ -748,7 +744,6 @@ uninstall: uninstall-i18n
|
||||||
-rm -r $(MAGIC_PREFIX)
|
-rm -r $(MAGIC_PREFIX)
|
||||||
-rm -r $(INCLUDE_PREFIX)/tuxpaint
|
-rm -r $(INCLUDE_PREFIX)/tuxpaint
|
||||||
-rm $(BIN_PREFIX)/tp-magic-config
|
-rm $(BIN_PREFIX)/tp-magic-config
|
||||||
-rm -r $(DEVDOC_PREFIX)
|
|
||||||
-if [ "x$(BUNDLE)" != "x" ]; then \
|
-if [ "x$(BUNDLE)" != "x" ]; then \
|
||||||
rm -rf $(BUNDLE); \
|
rm -rf $(BUNDLE); \
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ Various contributors (see below, and AUTHORS.txt)
|
||||||
http://www.tuxpaint.org/
|
http://www.tuxpaint.org/
|
||||||
|
|
||||||
|
|
||||||
2022.October.14 (0.9.29)
|
2022.October.18 (0.9.29)
|
||||||
* Improvements to "Stamp" tool:
|
* Improvements to "Stamp" tool:
|
||||||
-----------------------------
|
-----------------------------
|
||||||
* Stamps may now be rotated.
|
* Stamps may now be rotated.
|
||||||
|
|
@ -162,7 +162,11 @@ http://www.tuxpaint.org/
|
||||||
Mark Kim <markuskimius@gmail.com>
|
Mark Kim <markuskimius@gmail.com>
|
||||||
|
|
||||||
* Magic tool API documentation updated to match other docs,
|
* Magic tool API documentation updated to match other docs,
|
||||||
and allow for localization.
|
and allow for localization. (Maintained in "tuxpaint-docs" repo.)
|
||||||
|
Bill Kendrick <bill@newbreedsoftware.com>
|
||||||
|
|
||||||
|
* WIP - Example Magic tool source file ("tp_magic_example.c")
|
||||||
|
now allows for localization. (Maintained in "tuxpaint-docs" repo.)
|
||||||
Bill Kendrick <bill@newbreedsoftware.com>
|
Bill Kendrick <bill@newbreedsoftware.com>
|
||||||
|
|
||||||
* "--verbose-version" now shows whether SDL2_Pango is being used.
|
* "--verbose-version" now shows whether SDL2_Pango is being used.
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
# Bill Kendrick
|
# Bill Kendrick
|
||||||
# bill@newbreedsoftware.com
|
# bill@newbreedsoftware.com
|
||||||
#
|
#
|
||||||
# Sept. 4, 2005 - September 18, 2021
|
# Sept. 4, 2005 - October 18, 2022
|
||||||
|
|
||||||
LINKS_OPTIONS:=-dump -codepage utf8
|
LINKS_OPTIONS:=-dump -codepage utf8
|
||||||
LINKS:=links $(LINKS_OPTIONS)
|
LINKS:=links $(LINKS_OPTIONS)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Magic Tool Plugin API Documentation
|
||||||
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
||||||
https://tuxpaint.org/
|
https://tuxpaint.org/
|
||||||
|
|
||||||
October 3, 2022
|
October 18, 2022
|
||||||
|
|
||||||
+----------------------------------------------------+
|
+----------------------------------------------------+
|
||||||
|Table of Contents |
|
|Table of Contents |
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
October 3, 2022 </p>
|
October 18, 2022 </p>
|
||||||
</center>
|
</center>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -1063,9 +1063,8 @@
|
||||||
Example Code </h1>
|
Example Code </h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The C source file "<a href="../tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
The C source file "<a href="tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
||||||
</p>
|
</p>
|
||||||
</section><!-- H1: Example Code -->
|
</section><!-- H1: Example Code -->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,67 @@
|
||||||
/* tp_magic_example.c
|
/* tp_magic_example.c
|
||||||
|
|
||||||
An example of a "Magic" tool plugin for Tux Paint
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
Last modified: 2021.09.21
|
October 18, 2022
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Inclusion of header files: */
|
/* Inclusion of header files */
|
||||||
/* -------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h> // For "strdup()"
|
#include <string.h> // For "strdup()"
|
||||||
#include <libintl.h> // For "gettext()"
|
#include <libintl.h> // For "gettext()"
|
||||||
|
|
||||||
#include "tp_magic_api.h" // Tux Paint "Magic" tool API header
|
#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_image.h" // For IMG_Load(), to load our PNG icon
|
||||||
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
|
#include "SDL_mixer.h" // For Mix_LoadWAV(), to load our sound effects
|
||||||
|
|
||||||
|
|
||||||
/* Tool Enumerations: */
|
/* Tool Enumerations: */
|
||||||
/* ------------------ */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* What tools we contain: */
|
/* What tools we contain: */
|
||||||
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
TOOL_ONE, // Becomes '0'
|
TOOL_ONE, // Becomes '0'
|
||||||
TOOL_TWO, // Becomes '1'
|
TOOL_ONE, // Becomes '1'
|
||||||
NUM_TOOLS // Becomes '2'
|
NUM_TOOLS // Becomes '2'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A list of filenames for sounds and icons to load at startup: */
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
const char *snd_filenames[NUM_TOOLS] = {
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
"one.wav",
|
"tool_one.wav",
|
||||||
"two.wav"
|
"tool_two.wav"
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *icon_filenames[NUM_TOOLS] = {
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
"one.png",
|
"tool_one.png",
|
||||||
"two.png"
|
"tool_two.png"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
/*
|
||||||
// strings (char *'s) that hold the names and descriptions of our "Magic"
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
// tools. This allows the strings to be localized into other languages.
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* A list of names for the tools */
|
/* A list of names for the tools */
|
||||||
|
|
||||||
const char *names[NUM_TOOLS] = {
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
gettext_noop("A tool"),
|
gettext_noop("A tool"),
|
||||||
gettext_noop("Another tool")
|
gettext_noop("Another tool")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* How to group the tools with other similar tools,
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
within the 'Magic' selector: */
|
|
||||||
|
|
||||||
const int groups[NUM_TOOLS] = {
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
MAGIC_TYPE_PAINTING,
|
MAGIC_TYPE_PAINTING,
|
||||||
MAGIC_TYPE_DISTORTS
|
MAGIC_TYPE_DISTORTS
|
||||||
};
|
};
|
||||||
|
|
@ -67,7 +69,7 @@ const int groups[NUM_TOOLS] = {
|
||||||
|
|
||||||
/* A list of descriptions of the tools */
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
const char *descs[NUM_TOOLS] = {
|
const char *tool_descriptions[NUM_TOOLS] = {
|
||||||
gettext_noop("This is example tool number 1."),
|
gettext_noop("This is example tool number 1."),
|
||||||
gettext_noop("This is example tool number 2.")
|
gettext_noop("This is example tool number 2.")
|
||||||
};
|
};
|
||||||
|
|
@ -75,42 +77,46 @@ const char *descs[NUM_TOOLS] = {
|
||||||
|
|
||||||
|
|
||||||
/* Our global variables: */
|
/* Our global variables: */
|
||||||
/* --------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Sound effects: */
|
/* Sound effects: */
|
||||||
Mix_Chunk *snd_effect[NUM_TOOLS];
|
Mix_Chunk *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
/* The current color (an "RGB" value) the user has selected in Tux Paint: */
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
Uint8 example_r, example_g, example_b;
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
/* Our local function prototypes: */
|
/* 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
|
These functions are called by other functions within our plugin, so we
|
||||||
// they accept and return. This lets us use them in other functions
|
provide a 'prototype' of them, so the compiler knows what they accept and
|
||||||
// that are declared _before_ them.
|
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,
|
void example_drag(magic_api * api, int which, SDL_Surface * canvas,
|
||||||
SDL_Surface * snapshot, 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);
|
||||||
|
|
||||||
void example_line_callback(void *ptr, int which, SDL_Surface * canvas,
|
void example_line_callback(void *pointer, int which, SDL_Surface * canvas,
|
||||||
SDL_Surface * snapshot, int x, int y);
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
/* Setup Functions: */
|
/* Setup Functions: */
|
||||||
/* ---------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
// API Version check
|
/*
|
||||||
//
|
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.
|
The running copy of Tux Paint that has loaded us first asks us what version
|
||||||
// If it deems us compatible, we'll be used!
|
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.
|
All we need to do here is return "TP_MAGIC_API_VERSION", which is defined
|
||||||
|
(#define) in the header file "tp_magic_api.h".
|
||||||
|
*/
|
||||||
|
|
||||||
Uint32 example_api_version(void)
|
Uint32 example_api_version(void)
|
||||||
{
|
{
|
||||||
|
|
@ -118,42 +124,44 @@ Uint32 example_api_version(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Initialization
|
/*
|
||||||
//
|
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
|
This happens once, when Tux Paint starts up and is loading all of the
|
||||||
// acceptable!)
|
'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())
|
All we're doing in this example is loading our sound effects, which we'll
|
||||||
// when the user is using our Magic tools.
|
use later (in example_click(), example_drag(), and example_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,
|
The memory we allocate here to store the sounds will be freed (aka
|
||||||
// when our shutdown() function is called.
|
released, aka deallocated) when the user quits Tux Paint, when our
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
int example_init(magic_api * api)
|
int example_init(magic_api * api)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char fname[1024];
|
char filename[1024];
|
||||||
|
|
||||||
for (i = 0; i < NUM_TOOLS; i++)
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
{
|
{
|
||||||
// Assemble the filename from the "snd_filenames[]" array into
|
/*
|
||||||
// a full path to a real file.
|
Assemble the filename from the "sound_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/%s", api->data_directory,
|
Use "api->data_directory" to figure out where our sounds should be. (The
|
||||||
snd_filenames[i]);
|
"tp-magic-config --dataprefix" command would have told us when we installed
|
||||||
|
our plugin and its data.)
|
||||||
|
|
||||||
printf("Trying to load %s sound file\n", fname);
|
snprintf(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
// Try to load the file!
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
snd_effect[i] = Mix_LoadWAV(fname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
|
|
@ -238,51 +246,58 @@ char *example_get_name(magic_api * api, int which)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Report our "Magic" tool groups
|
/*
|
||||||
//
|
Report our 'Magic' tool groups
|
||||||
// When Tux Paint is starting up and loading plugins, it asks us to
|
|
||||||
// specify where the tool should be grouped.
|
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
int example_get_group(magic_api * api, int which)
|
int example_get_group(magic_api * api, int which)
|
||||||
{
|
{
|
||||||
// Return our group from the "groups[]" array.
|
/*
|
||||||
//
|
Return our group, found in the "tool_groups[]" array.
|
||||||
// We use 'which' (which of our tools Tux Paint is asking about)
|
|
||||||
// as an index into the array.
|
|
||||||
|
|
||||||
return (groups[which]);
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Report our "Magic" tool descriptions
|
/*
|
||||||
//
|
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.
|
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
char *example_get_description(magic_api * api, int which, int mode)
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
{
|
{
|
||||||
const char *our_desc_english;
|
const char *our_desc_english;
|
||||||
const char *our_desc_localized;
|
const char *our_desc_localized;
|
||||||
|
|
||||||
// Get our desc from the "descs[]" array.
|
/*
|
||||||
//
|
Get our description from the "tool_descriptions[]" array.
|
||||||
// We use 'which' (which of our tools Tux Paint is asking about)
|
|
||||||
// as an index into the array.
|
|
||||||
|
|
||||||
our_desc_english = descs[which];
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[which];
|
||||||
|
|
||||||
|
|
||||||
// Return a localized (aka translated) version of our description,
|
/*
|
||||||
// if possible.
|
Return a localized (aka translated) version of our description, if
|
||||||
//
|
possible.
|
||||||
// We send "gettext()" the English version of the description from our array.
|
|
||||||
|
|
||||||
|
We send "gettext" the English version of the description from our array.
|
||||||
|
*/
|
||||||
our_desc_localized = gettext(our_desc_english);
|
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
|
Finally, duplicate the string into a new section of memory, and send it to
|
||||||
// will free it for us, so we have one less thing to keep track of.)
|
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));
|
return (strdup(our_desc_localized));
|
||||||
}
|
}
|
||||||
|
|
@ -291,7 +306,7 @@ char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
|
||||||
int example_requires_colors(magic_api * api, int which)
|
int example_requires_colors(magic_api * api, int which)
|
||||||
{
|
{
|
||||||
// Both of our tools accept colors, so we're always returning '1' (for "true")
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -301,34 +316,36 @@ int example_requires_colors(magic_api * api, int which)
|
||||||
|
|
||||||
int example_modes(magic_api * api, int which)
|
int example_modes(magic_api * api, int which)
|
||||||
{
|
{
|
||||||
// Both of our tools are painted (neither affect the full-screen),
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
// so we're always returning 'MODE_PAINT'
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
return MODE_PAINT;
|
return MODE_PAINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Shut down
|
/*
|
||||||
//
|
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.
|
|
||||||
|
|
||||||
|
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 example_init() function), so we should free the memory used
|
||||||
|
by them now.
|
||||||
|
*/
|
||||||
void example_shutdown(magic_api * api)
|
void example_shutdown(magic_api * api)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// Free (aka release, aka deallocate) the memory used to store the
|
/*
|
||||||
// sound effects that we loaded during init():
|
Free (aka release, aka deallocate) the memory used to store the sound
|
||||||
|
effects that we loaded during example_init():
|
||||||
|
*/
|
||||||
for (i = 0; i < NUM_TOOLS; i++)
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
Mix_FreeChunk(snd_effect[i]);
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Functions that respond to events in Tux Paint: */
|
/* Functions that respond to events in Tux Paint: */
|
||||||
/* ---------------------------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
// Affect the canvas on click:
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
|
@ -446,7 +463,7 @@ void example_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b)
|
||||||
|
|
||||||
|
|
||||||
/* The Magic Effect Routines! */
|
/* The Magic Effect Routines! */
|
||||||
/* -------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
// Our "callback" function
|
// Our "callback" function
|
||||||
//
|
//
|
||||||
579
docs/en/tp_magic_example.c
Normal file
579
docs/en/tp_magic_example.c
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
/* tp_magic_example.c
|
||||||
|
|
||||||
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
|
October 18, 2022
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Inclusion of header files */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h> // For "strdup()"
|
||||||
|
#include <libintl.h> // 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, // Becomes '0'
|
||||||
|
TOOL_ONE, // Becomes '1'
|
||||||
|
NUM_TOOLS // Becomes '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.wav",
|
||||||
|
"tool_two.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.png",
|
||||||
|
"tool_two.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of names for the tools */
|
||||||
|
|
||||||
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
|
gettext_noop("A tool"),
|
||||||
|
gettext_noop("Another tool")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
|
|
||||||
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
|
MAGIC_TYPE_PAINTING,
|
||||||
|
MAGIC_TYPE_DISTORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
|
const char *tool_descriptions[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 *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *pointer, int which, SDL_Surface * canvas,
|
||||||
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 defined
|
||||||
|
(#define) in the header file "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 example_click(), example_drag(), and example_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
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int example_init(magic_api * api)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Assemble the filename from the "sound_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(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
const char *our_name_english;
|
||||||
|
const char *our_name_localized;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool groups
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
|
int example_get_group(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Return our group, found in the "tool_groups[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool descriptions
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
{
|
||||||
|
const char *our_desc_english;
|
||||||
|
const char *our_desc_localized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get our description from the "tool_descriptions[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report whether we accept colors
|
||||||
|
|
||||||
|
int example_requires_colors(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report what modes we work in
|
||||||
|
|
||||||
|
int example_modes(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
|
return MODE_PAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 example_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 example_init():
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions that respond to events in Tux Paint: */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_click(magic_api * api, int which, int mode,
|
||||||
|
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 * snapshot, int ox, int oy, int x, int y,
|
||||||
|
SDL_Rect * update_rect)
|
||||||
|
{
|
||||||
|
// 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((void *) api, 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, // pan
|
||||||
|
255); // distance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Affect the canvas on release:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_release(magic_api * api, int which,
|
||||||
|
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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// 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).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-In event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is enabled, either because the
|
||||||
|
// user just selected it, or they just came back to "Magic" after using
|
||||||
|
// another tool (e.g., Brush or Text), and this was the most-recently
|
||||||
|
// selected Magic tool.
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like
|
||||||
|
// Undo and Redo, and image-changing tools such as New and Open.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it first
|
||||||
|
// receives a 'switchout()', below, for the old mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchin(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-Out event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is disabled, either because the
|
||||||
|
// user selected a different Magic tool, or they selected a completely
|
||||||
|
// different tool (e.g., Brush or Text).
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like Undo and Redo, and
|
||||||
|
// image-changing tools such as New and Open, in which case the
|
||||||
|
// switchin() function will be called moments later.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it then
|
||||||
|
// receives a 'switchin()', above, for the new mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchout(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ Magic Tool Plugin API Documentation
|
||||||
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
||||||
https://tuxpaint.org/
|
https://tuxpaint.org/
|
||||||
|
|
||||||
octubre 3, 2022
|
octubre 18, 2022
|
||||||
|
|
||||||
+----------------------------------------------------+
|
+----------------------------------------------------+
|
||||||
|Table of Contents |
|
|Table of Contents |
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
octubre 3, 2022 </p>
|
octubre 18, 2022 </p>
|
||||||
</center>
|
</center>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -1063,9 +1063,8 @@
|
||||||
Example Code </h1>
|
Example Code </h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The C source file "<a href="../tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
The C source file "<a href="tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
||||||
</p>
|
</p>
|
||||||
</section><!-- H1: Example Code -->
|
</section><!-- H1: Example Code -->
|
||||||
|
|
||||||
|
|
|
||||||
579
docs/es_ES.UTF-8/html/tp_magic_example.c
Normal file
579
docs/es_ES.UTF-8/html/tp_magic_example.c
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
/* tp_magic_example.c
|
||||||
|
|
||||||
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
|
octubre 18, 2022
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Inclusion of header files */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h> // For "strdup()"
|
||||||
|
#include <libintl.h> // 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, // Becomes '0'
|
||||||
|
TOOL_ONE, // Becomes '1'
|
||||||
|
NUM_TOOLS // Becomes '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.wav",
|
||||||
|
"tool_two.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.png",
|
||||||
|
"tool_two.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of names for the tools */
|
||||||
|
|
||||||
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
|
gettext_noop("A tool"),
|
||||||
|
gettext_noop("Another tool")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
|
|
||||||
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
|
MAGIC_TYPE_PAINTING,
|
||||||
|
MAGIC_TYPE_DISTORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
|
const char *tool_descriptions[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 *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *pointer, int which, SDL_Surface * canvas,
|
||||||
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 defined
|
||||||
|
(#define) in the header file "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 example_click(), example_drag(), and example_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
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int example_init(magic_api * api)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Assemble the filename from the "sound_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(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
const char *our_name_english;
|
||||||
|
const char *our_name_localized;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool groups
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
|
int example_get_group(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Return our group, found in the "tool_groups[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool descriptions
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
{
|
||||||
|
const char *our_desc_english;
|
||||||
|
const char *our_desc_localized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get our description from the "tool_descriptions[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report whether we accept colors
|
||||||
|
|
||||||
|
int example_requires_colors(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report what modes we work in
|
||||||
|
|
||||||
|
int example_modes(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
|
return MODE_PAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 example_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 example_init():
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions that respond to events in Tux Paint: */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_click(magic_api * api, int which, int mode,
|
||||||
|
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 * snapshot, int ox, int oy, int x, int y,
|
||||||
|
SDL_Rect * update_rect)
|
||||||
|
{
|
||||||
|
// 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((void *) api, 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, // pan
|
||||||
|
255); // distance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Affect the canvas on release:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_release(magic_api * api, int which,
|
||||||
|
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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// 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).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-In event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is enabled, either because the
|
||||||
|
// user just selected it, or they just came back to "Magic" after using
|
||||||
|
// another tool (e.g., Brush or Text), and this was the most-recently
|
||||||
|
// selected Magic tool.
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like
|
||||||
|
// Undo and Redo, and image-changing tools such as New and Open.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it first
|
||||||
|
// receives a 'switchout()', below, for the old mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchin(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-Out event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is disabled, either because the
|
||||||
|
// user selected a different Magic tool, or they selected a completely
|
||||||
|
// different tool (e.g., Brush or Text).
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like Undo and Redo, and
|
||||||
|
// image-changing tools such as New and Open, in which case the
|
||||||
|
// switchin() function will be called moments later.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it then
|
||||||
|
// receives a 'switchin()', above, for the new mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchout(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
579
docs/es_ES.UTF-8/tp_magic_example.c
Normal file
579
docs/es_ES.UTF-8/tp_magic_example.c
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
/* tp_magic_example.c
|
||||||
|
|
||||||
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
|
octubre 18, 2022
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Inclusion of header files */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h> // For "strdup()"
|
||||||
|
#include <libintl.h> // 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, // Becomes '0'
|
||||||
|
TOOL_ONE, // Becomes '1'
|
||||||
|
NUM_TOOLS // Becomes '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.wav",
|
||||||
|
"tool_two.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.png",
|
||||||
|
"tool_two.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of names for the tools */
|
||||||
|
|
||||||
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
|
gettext_noop("A tool"),
|
||||||
|
gettext_noop("Another tool")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
|
|
||||||
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
|
MAGIC_TYPE_PAINTING,
|
||||||
|
MAGIC_TYPE_DISTORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
|
const char *tool_descriptions[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 *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *pointer, int which, SDL_Surface * canvas,
|
||||||
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 defined
|
||||||
|
(#define) in the header file "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 example_click(), example_drag(), and example_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
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int example_init(magic_api * api)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Assemble the filename from the "sound_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(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
const char *our_name_english;
|
||||||
|
const char *our_name_localized;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool groups
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
|
int example_get_group(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Return our group, found in the "tool_groups[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool descriptions
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
{
|
||||||
|
const char *our_desc_english;
|
||||||
|
const char *our_desc_localized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get our description from the "tool_descriptions[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report whether we accept colors
|
||||||
|
|
||||||
|
int example_requires_colors(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report what modes we work in
|
||||||
|
|
||||||
|
int example_modes(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
|
return MODE_PAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 example_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 example_init():
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions that respond to events in Tux Paint: */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_click(magic_api * api, int which, int mode,
|
||||||
|
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 * snapshot, int ox, int oy, int x, int y,
|
||||||
|
SDL_Rect * update_rect)
|
||||||
|
{
|
||||||
|
// 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((void *) api, 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, // pan
|
||||||
|
255); // distance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Affect the canvas on release:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_release(magic_api * api, int which,
|
||||||
|
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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// 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).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-In event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is enabled, either because the
|
||||||
|
// user just selected it, or they just came back to "Magic" after using
|
||||||
|
// another tool (e.g., Brush or Text), and this was the most-recently
|
||||||
|
// selected Magic tool.
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like
|
||||||
|
// Undo and Redo, and image-changing tools such as New and Open.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it first
|
||||||
|
// receives a 'switchout()', below, for the old mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchin(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-Out event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is disabled, either because the
|
||||||
|
// user selected a different Magic tool, or they selected a completely
|
||||||
|
// different tool (e.g., Brush or Text).
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like Undo and Redo, and
|
||||||
|
// image-changing tools such as New and Open, in which case the
|
||||||
|
// switchin() function will be called moments later.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it then
|
||||||
|
// receives a 'switchin()', above, for the new mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchout(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ Magic Tool Plugin API Documentation
|
||||||
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
||||||
https://tuxpaint.org/
|
https://tuxpaint.org/
|
||||||
|
|
||||||
octobre 3, 2022
|
octobre 18, 2022
|
||||||
|
|
||||||
+----------------------------------------------------+
|
+----------------------------------------------------+
|
||||||
|Table of Contents |
|
|Table of Contents |
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
octobre 3, 2022 </p>
|
octobre 18, 2022 </p>
|
||||||
</center>
|
</center>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -1063,9 +1063,8 @@
|
||||||
Example Code </h1>
|
Example Code </h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The C source file "<a href="../tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
The C source file "<a href="tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
||||||
</p>
|
</p>
|
||||||
</section><!-- H1: Example Code -->
|
</section><!-- H1: Example Code -->
|
||||||
|
|
||||||
|
|
|
||||||
579
docs/fr_FR.UTF-8/html/tp_magic_example.c
Normal file
579
docs/fr_FR.UTF-8/html/tp_magic_example.c
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
/* tp_magic_example.c
|
||||||
|
|
||||||
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
|
octobre 18, 2022
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Inclusion of header files */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h> // For "strdup()"
|
||||||
|
#include <libintl.h> // 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, // Becomes '0'
|
||||||
|
TOOL_ONE, // Becomes '1'
|
||||||
|
NUM_TOOLS // Becomes '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.wav",
|
||||||
|
"tool_two.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.png",
|
||||||
|
"tool_two.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of names for the tools */
|
||||||
|
|
||||||
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
|
gettext_noop("A tool"),
|
||||||
|
gettext_noop("Another tool")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
|
|
||||||
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
|
MAGIC_TYPE_PAINTING,
|
||||||
|
MAGIC_TYPE_DISTORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
|
const char *tool_descriptions[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 *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *pointer, int which, SDL_Surface * canvas,
|
||||||
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 defined
|
||||||
|
(#define) in the header file "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 example_click(), example_drag(), and example_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
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int example_init(magic_api * api)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Assemble the filename from the "sound_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(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
const char *our_name_english;
|
||||||
|
const char *our_name_localized;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool groups
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
|
int example_get_group(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Return our group, found in the "tool_groups[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool descriptions
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
{
|
||||||
|
const char *our_desc_english;
|
||||||
|
const char *our_desc_localized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get our description from the "tool_descriptions[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report whether we accept colors
|
||||||
|
|
||||||
|
int example_requires_colors(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report what modes we work in
|
||||||
|
|
||||||
|
int example_modes(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
|
return MODE_PAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 example_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 example_init():
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions that respond to events in Tux Paint: */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_click(magic_api * api, int which, int mode,
|
||||||
|
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 * snapshot, int ox, int oy, int x, int y,
|
||||||
|
SDL_Rect * update_rect)
|
||||||
|
{
|
||||||
|
// 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((void *) api, 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, // pan
|
||||||
|
255); // distance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Affect the canvas on release:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_release(magic_api * api, int which,
|
||||||
|
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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// 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).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-In event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is enabled, either because the
|
||||||
|
// user just selected it, or they just came back to "Magic" after using
|
||||||
|
// another tool (e.g., Brush or Text), and this was the most-recently
|
||||||
|
// selected Magic tool.
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like
|
||||||
|
// Undo and Redo, and image-changing tools such as New and Open.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it first
|
||||||
|
// receives a 'switchout()', below, for the old mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchin(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-Out event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is disabled, either because the
|
||||||
|
// user selected a different Magic tool, or they selected a completely
|
||||||
|
// different tool (e.g., Brush or Text).
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like Undo and Redo, and
|
||||||
|
// image-changing tools such as New and Open, in which case the
|
||||||
|
// switchin() function will be called moments later.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it then
|
||||||
|
// receives a 'switchin()', above, for the new mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchout(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
579
docs/fr_FR.UTF-8/tp_magic_example.c
Normal file
579
docs/fr_FR.UTF-8/tp_magic_example.c
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
/* tp_magic_example.c
|
||||||
|
|
||||||
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
|
octobre 18, 2022
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Inclusion of header files */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h> // For "strdup()"
|
||||||
|
#include <libintl.h> // 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, // Becomes '0'
|
||||||
|
TOOL_ONE, // Becomes '1'
|
||||||
|
NUM_TOOLS // Becomes '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.wav",
|
||||||
|
"tool_two.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.png",
|
||||||
|
"tool_two.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of names for the tools */
|
||||||
|
|
||||||
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
|
gettext_noop("A tool"),
|
||||||
|
gettext_noop("Another tool")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
|
|
||||||
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
|
MAGIC_TYPE_PAINTING,
|
||||||
|
MAGIC_TYPE_DISTORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
|
const char *tool_descriptions[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 *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *pointer, int which, SDL_Surface * canvas,
|
||||||
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 defined
|
||||||
|
(#define) in the header file "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 example_click(), example_drag(), and example_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
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int example_init(magic_api * api)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Assemble the filename from the "sound_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(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
const char *our_name_english;
|
||||||
|
const char *our_name_localized;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool groups
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
|
int example_get_group(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Return our group, found in the "tool_groups[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool descriptions
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
{
|
||||||
|
const char *our_desc_english;
|
||||||
|
const char *our_desc_localized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get our description from the "tool_descriptions[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report whether we accept colors
|
||||||
|
|
||||||
|
int example_requires_colors(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report what modes we work in
|
||||||
|
|
||||||
|
int example_modes(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
|
return MODE_PAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 example_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 example_init():
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions that respond to events in Tux Paint: */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_click(magic_api * api, int which, int mode,
|
||||||
|
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 * snapshot, int ox, int oy, int x, int y,
|
||||||
|
SDL_Rect * update_rect)
|
||||||
|
{
|
||||||
|
// 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((void *) api, 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, // pan
|
||||||
|
255); // distance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Affect the canvas on release:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_release(magic_api * api, int which,
|
||||||
|
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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// 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).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-In event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is enabled, either because the
|
||||||
|
// user just selected it, or they just came back to "Magic" after using
|
||||||
|
// another tool (e.g., Brush or Text), and this was the most-recently
|
||||||
|
// selected Magic tool.
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like
|
||||||
|
// Undo and Redo, and image-changing tools such as New and Open.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it first
|
||||||
|
// receives a 'switchout()', below, for the old mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchin(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-Out event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is disabled, either because the
|
||||||
|
// user selected a different Magic tool, or they selected a completely
|
||||||
|
// different tool (e.g., Brush or Text).
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like Undo and Redo, and
|
||||||
|
// image-changing tools such as New and Open, in which case the
|
||||||
|
// switchin() function will be called moments later.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it then
|
||||||
|
// receives a 'switchin()', above, for the new mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchout(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ Magic Tool Plugin API Documentation
|
||||||
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
||||||
https://tuxpaint.org/
|
https://tuxpaint.org/
|
||||||
|
|
||||||
Outubro 3, 2022
|
Outubro 18, 2022
|
||||||
|
|
||||||
+----------------------------------------------------+
|
+----------------------------------------------------+
|
||||||
|Table of Contents |
|
|Table of Contents |
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Outubro 3, 2022 </p>
|
Outubro 18, 2022 </p>
|
||||||
</center>
|
</center>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -1063,9 +1063,8 @@
|
||||||
Example Code </h1>
|
Example Code </h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The C source file "<a href="../tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
The C source file "<a href="tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
||||||
</p>
|
</p>
|
||||||
</section><!-- H1: Example Code -->
|
</section><!-- H1: Example Code -->
|
||||||
|
|
||||||
|
|
|
||||||
579
docs/gl_ES.UTF-8/html/tp_magic_example.c
Normal file
579
docs/gl_ES.UTF-8/html/tp_magic_example.c
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
/* tp_magic_example.c
|
||||||
|
|
||||||
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
|
18 de Outubro de 2022
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Inclusion of header files */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h> // For "strdup()"
|
||||||
|
#include <libintl.h> // 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, // Becomes '0'
|
||||||
|
TOOL_ONE, // Becomes '1'
|
||||||
|
NUM_TOOLS // Becomes '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.wav",
|
||||||
|
"tool_two.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.png",
|
||||||
|
"tool_two.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of names for the tools */
|
||||||
|
|
||||||
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
|
gettext_noop("A tool"),
|
||||||
|
gettext_noop("Another tool")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
|
|
||||||
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
|
MAGIC_TYPE_PAINTING,
|
||||||
|
MAGIC_TYPE_DISTORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
|
const char *tool_descriptions[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 *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *pointer, int which, SDL_Surface * canvas,
|
||||||
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 defined
|
||||||
|
(#define) in the header file "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 example_click(), example_drag(), and example_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
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int example_init(magic_api * api)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Assemble the filename from the "sound_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(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
const char *our_name_english;
|
||||||
|
const char *our_name_localized;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool groups
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
|
int example_get_group(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Return our group, found in the "tool_groups[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool descriptions
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
{
|
||||||
|
const char *our_desc_english;
|
||||||
|
const char *our_desc_localized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get our description from the "tool_descriptions[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report whether we accept colors
|
||||||
|
|
||||||
|
int example_requires_colors(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report what modes we work in
|
||||||
|
|
||||||
|
int example_modes(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
|
return MODE_PAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 example_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 example_init():
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions that respond to events in Tux Paint: */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_click(magic_api * api, int which, int mode,
|
||||||
|
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 * snapshot, int ox, int oy, int x, int y,
|
||||||
|
SDL_Rect * update_rect)
|
||||||
|
{
|
||||||
|
// 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((void *) api, 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, // pan
|
||||||
|
255); // distance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Affect the canvas on release:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_release(magic_api * api, int which,
|
||||||
|
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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// 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).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-In event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is enabled, either because the
|
||||||
|
// user just selected it, or they just came back to "Magic" after using
|
||||||
|
// another tool (e.g., Brush or Text), and this was the most-recently
|
||||||
|
// selected Magic tool.
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like
|
||||||
|
// Undo and Redo, and image-changing tools such as New and Open.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it first
|
||||||
|
// receives a 'switchout()', below, for the old mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchin(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-Out event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is disabled, either because the
|
||||||
|
// user selected a different Magic tool, or they selected a completely
|
||||||
|
// different tool (e.g., Brush or Text).
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like Undo and Redo, and
|
||||||
|
// image-changing tools such as New and Open, in which case the
|
||||||
|
// switchin() function will be called moments later.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it then
|
||||||
|
// receives a 'switchin()', above, for the new mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchout(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
579
docs/gl_ES.UTF-8/tp_magic_example.c
Normal file
579
docs/gl_ES.UTF-8/tp_magic_example.c
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
/* tp_magic_example.c
|
||||||
|
|
||||||
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
|
18 de Outubro de 2022
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Inclusion of header files */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h> // For "strdup()"
|
||||||
|
#include <libintl.h> // 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, // Becomes '0'
|
||||||
|
TOOL_ONE, // Becomes '1'
|
||||||
|
NUM_TOOLS // Becomes '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.wav",
|
||||||
|
"tool_two.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.png",
|
||||||
|
"tool_two.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of names for the tools */
|
||||||
|
|
||||||
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
|
gettext_noop("A tool"),
|
||||||
|
gettext_noop("Another tool")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
|
|
||||||
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
|
MAGIC_TYPE_PAINTING,
|
||||||
|
MAGIC_TYPE_DISTORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
|
const char *tool_descriptions[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 *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *pointer, int which, SDL_Surface * canvas,
|
||||||
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 defined
|
||||||
|
(#define) in the header file "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 example_click(), example_drag(), and example_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
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int example_init(magic_api * api)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Assemble the filename from the "sound_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(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
const char *our_name_english;
|
||||||
|
const char *our_name_localized;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool groups
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
|
int example_get_group(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Return our group, found in the "tool_groups[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool descriptions
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
{
|
||||||
|
const char *our_desc_english;
|
||||||
|
const char *our_desc_localized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get our description from the "tool_descriptions[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report whether we accept colors
|
||||||
|
|
||||||
|
int example_requires_colors(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report what modes we work in
|
||||||
|
|
||||||
|
int example_modes(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
|
return MODE_PAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 example_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 example_init():
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions that respond to events in Tux Paint: */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_click(magic_api * api, int which, int mode,
|
||||||
|
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 * snapshot, int ox, int oy, int x, int y,
|
||||||
|
SDL_Rect * update_rect)
|
||||||
|
{
|
||||||
|
// 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((void *) api, 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, // pan
|
||||||
|
255); // distance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Affect the canvas on release:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_release(magic_api * api, int which,
|
||||||
|
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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// 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).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-In event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is enabled, either because the
|
||||||
|
// user just selected it, or they just came back to "Magic" after using
|
||||||
|
// another tool (e.g., Brush or Text), and this was the most-recently
|
||||||
|
// selected Magic tool.
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like
|
||||||
|
// Undo and Redo, and image-changing tools such as New and Open.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it first
|
||||||
|
// receives a 'switchout()', below, for the old mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchin(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-Out event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is disabled, either because the
|
||||||
|
// user selected a different Magic tool, or they selected a completely
|
||||||
|
// different tool (e.g., Brush or Text).
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like Undo and Redo, and
|
||||||
|
// image-changing tools such as New and Open, in which case the
|
||||||
|
// switchin() function will be called moments later.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it then
|
||||||
|
// receives a 'switchin()', above, for the new mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchout(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ Magic Tool Plugin API Documentation
|
||||||
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
Copyright © 2007-2022 by various contributors; see AUTHORS.txt.
|
||||||
https://tuxpaint.org/
|
https://tuxpaint.org/
|
||||||
|
|
||||||
10月 3, 2022
|
10月 18, 2022
|
||||||
|
|
||||||
+----------------------------------------------------+
|
+----------------------------------------------------+
|
||||||
|Table of Contents |
|
|Table of Contents |
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
10月 3, 2022 </p>
|
10月 18, 2022 </p>
|
||||||
</center>
|
</center>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -1063,9 +1063,8 @@
|
||||||
Example Code </h1>
|
Example Code </h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The C source file "<a href="../tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
The C source file "<a href="tp_magic_example.c"><code>tp_magic_example.c</code></a>" contains a complete example of a plugin with multiple simple effects.
|
||||||
</p>
|
</p>
|
||||||
</section><!-- H1: Example Code -->
|
</section><!-- H1: Example Code -->
|
||||||
|
|
||||||
|
|
|
||||||
579
docs/ja_JP.UTF-8/html/tp_magic_example.c
Normal file
579
docs/ja_JP.UTF-8/html/tp_magic_example.c
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
/* tp_magic_example.c
|
||||||
|
|
||||||
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
|
2022年10月18日
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Inclusion of header files */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h> // For "strdup()"
|
||||||
|
#include <libintl.h> // 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, // Becomes '0'
|
||||||
|
TOOL_ONE, // Becomes '1'
|
||||||
|
NUM_TOOLS // Becomes '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.wav",
|
||||||
|
"tool_two.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.png",
|
||||||
|
"tool_two.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of names for the tools */
|
||||||
|
|
||||||
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
|
gettext_noop("A tool"),
|
||||||
|
gettext_noop("Another tool")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
|
|
||||||
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
|
MAGIC_TYPE_PAINTING,
|
||||||
|
MAGIC_TYPE_DISTORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
|
const char *tool_descriptions[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 *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *pointer, int which, SDL_Surface * canvas,
|
||||||
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 defined
|
||||||
|
(#define) in the header file "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 example_click(), example_drag(), and example_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
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int example_init(magic_api * api)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Assemble the filename from the "sound_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(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
const char *our_name_english;
|
||||||
|
const char *our_name_localized;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool groups
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
|
int example_get_group(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Return our group, found in the "tool_groups[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool descriptions
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
{
|
||||||
|
const char *our_desc_english;
|
||||||
|
const char *our_desc_localized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get our description from the "tool_descriptions[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report whether we accept colors
|
||||||
|
|
||||||
|
int example_requires_colors(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report what modes we work in
|
||||||
|
|
||||||
|
int example_modes(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
|
return MODE_PAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 example_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 example_init():
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions that respond to events in Tux Paint: */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_click(magic_api * api, int which, int mode,
|
||||||
|
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 * snapshot, int ox, int oy, int x, int y,
|
||||||
|
SDL_Rect * update_rect)
|
||||||
|
{
|
||||||
|
// 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((void *) api, 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, // pan
|
||||||
|
255); // distance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Affect the canvas on release:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_release(magic_api * api, int which,
|
||||||
|
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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// 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).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-In event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is enabled, either because the
|
||||||
|
// user just selected it, or they just came back to "Magic" after using
|
||||||
|
// another tool (e.g., Brush or Text), and this was the most-recently
|
||||||
|
// selected Magic tool.
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like
|
||||||
|
// Undo and Redo, and image-changing tools such as New and Open.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it first
|
||||||
|
// receives a 'switchout()', below, for the old mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchin(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-Out event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is disabled, either because the
|
||||||
|
// user selected a different Magic tool, or they selected a completely
|
||||||
|
// different tool (e.g., Brush or Text).
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like Undo and Redo, and
|
||||||
|
// image-changing tools such as New and Open, in which case the
|
||||||
|
// switchin() function will be called moments later.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it then
|
||||||
|
// receives a 'switchin()', above, for the new mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchout(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
579
docs/ja_JP.UTF-8/tp_magic_example.c
Normal file
579
docs/ja_JP.UTF-8/tp_magic_example.c
Normal file
|
|
@ -0,0 +1,579 @@
|
||||||
|
/* tp_magic_example.c
|
||||||
|
|
||||||
|
An example of a "Magic" tool plugin for Tux Paint
|
||||||
|
2022年10月18日
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Inclusion of header files */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h> // For "strdup()"
|
||||||
|
#include <libintl.h> // 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, // Becomes '0'
|
||||||
|
TOOL_ONE, // Becomes '1'
|
||||||
|
NUM_TOOLS // Becomes '2'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of filenames for sounds and icons to load at startup: */
|
||||||
|
|
||||||
|
const char *sound_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.wav",
|
||||||
|
"tool_two.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *icon_filenames[NUM_TOOLS] = {
|
||||||
|
"tool_one.png",
|
||||||
|
"tool_two.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: We use a macro called "gettext_noop()" below in some arrays of
|
||||||
|
strings (char *'s) that hold the names and descriptions of our "Magic"
|
||||||
|
tools. This allows the strings to be localized into other languages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of names for the tools */
|
||||||
|
|
||||||
|
const char *tool_names[NUM_TOOLS] = {
|
||||||
|
gettext_noop("A tool"),
|
||||||
|
gettext_noop("Another tool")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* How to group the tools with other similar tools, within the 'Magic' selector: */
|
||||||
|
|
||||||
|
const int tool_groups[$NUM_TOOLS] = {
|
||||||
|
MAGIC_TYPE_PAINTING,
|
||||||
|
MAGIC_TYPE_DISTORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* A list of descriptions of the tools */
|
||||||
|
|
||||||
|
const char *tool_descriptions[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 *sound_effects[NUM_TOOLS];
|
||||||
|
|
||||||
|
/* The current color (an "RGB" -- red, green, blue -- value) the user has selected in Tux Paint: */
|
||||||
|
Uint8 example_r, $example_g, $example_b;
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 *pointer, int which, SDL_Surface * canvas,
|
||||||
|
SDL_Surface * snapshot, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 defined
|
||||||
|
(#define) in the header file "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 example_click(), example_drag(), and example_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
|
||||||
|
example_shutdown() function is called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int example_init(magic_api * api)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char filename[1024];
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Assemble the filename from the "sound_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(filename, sizeof(filename), "%s/sounds/magic/%s", api->data_directory,
|
||||||
|
sound_filenames[i]);
|
||||||
|
|
||||||
|
printf("Trying to load %s sound file\n", filename);
|
||||||
|
|
||||||
|
// Try to load the file!
|
||||||
|
sound_effects[i] = Mix_LoadWAV(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
const char *our_name_english;
|
||||||
|
const char *our_name_localized;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool groups
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to specify
|
||||||
|
where the tool should be grouped.
|
||||||
|
*/
|
||||||
|
int example_get_group(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Return our group, found in the "tool_groups[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
return (tool_groups[which]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Report our 'Magic' tool descriptions
|
||||||
|
|
||||||
|
When Tux Paint is starting up and loading plugins, it asks us to provide
|
||||||
|
descriptions of each 'Magic' tool.
|
||||||
|
*/
|
||||||
|
char *example_get_description(magic_api * api, int which, int mode)
|
||||||
|
{
|
||||||
|
const char *our_desc_english;
|
||||||
|
const char *our_desc_localized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get our description from the "tool_descriptions[]" array.
|
||||||
|
|
||||||
|
We use 'which' (which of our tools Tux Paint is asking about) as an index
|
||||||
|
into the array.
|
||||||
|
*/
|
||||||
|
our_desc_english = tool_descriptions[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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report whether we accept colors
|
||||||
|
|
||||||
|
int example_requires_colors(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools accept colors, so we're always returning '1' (for 'true')
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Report what modes we work in
|
||||||
|
|
||||||
|
int example_modes(magic_api * api, int which)
|
||||||
|
{
|
||||||
|
// Both of our tools are painted (neither affect the full-screen), so we're
|
||||||
|
always returning 'MODE_PAINT'
|
||||||
|
|
||||||
|
return MODE_PAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 example_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 example_init():
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_TOOLS; i++)
|
||||||
|
Mix_FreeChunk(sound_effects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Functions that respond to events in Tux Paint: */
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Affect the canvas on click:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_click(magic_api * api, int which, int mode,
|
||||||
|
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 * snapshot, int ox, int oy, int x, int y,
|
||||||
|
SDL_Rect * update_rect)
|
||||||
|
{
|
||||||
|
// 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((void *) api, 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, // pan
|
||||||
|
255); // distance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Affect the canvas on release:
|
||||||
|
|
||||||
|
void
|
||||||
|
example_release(magic_api * api, int which,
|
||||||
|
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...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
// 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).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-In event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is enabled, either because the
|
||||||
|
// user just selected it, or they just came back to "Magic" after using
|
||||||
|
// another tool (e.g., Brush or Text), and this was the most-recently
|
||||||
|
// selected Magic tool.
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like
|
||||||
|
// Undo and Redo, and image-changing tools such as New and Open.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it first
|
||||||
|
// receives a 'switchout()', below, for the old mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchin(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch-Out event
|
||||||
|
//
|
||||||
|
// This happens whenever a Magic tool is disabled, either because the
|
||||||
|
// user selected a different Magic tool, or they selected a completely
|
||||||
|
// different tool (e.g., Brush or Text).
|
||||||
|
//
|
||||||
|
// (This also applies to momentary tools, like Undo and Redo, and
|
||||||
|
// image-changing tools such as New and Open, in which case the
|
||||||
|
// switchin() function will be called moments later.)
|
||||||
|
//
|
||||||
|
// It also happens when a Magic tool's mode changes (it then
|
||||||
|
// receives a 'switchin()', above, for the new mode).
|
||||||
|
//
|
||||||
|
// Our example doesn't do anything when we switch to, or away from, our
|
||||||
|
// Magic tools, so we just do nothing here.
|
||||||
|
|
||||||
|
void example_switchout(magic_api * api, int which, int mode,
|
||||||
|
SDL_Surface * canvas)
|
||||||
|
{
|
||||||
|
}
|
||||||
1
magic/docs/.indent.pro
vendored
1
magic/docs/.indent.pro
vendored
|
|
@ -1 +0,0 @@
|
||||||
../../src/.indent.pro
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue