diff --git a/magic/icons/shift.png b/magic/icons/shift.png
new file mode 100644
index 000000000..28710c812
Binary files /dev/null and b/magic/icons/shift.png differ
diff --git a/magic/magic-docs/html/shift.html b/magic/magic-docs/html/shift.html
new file mode 100644
index 000000000..07fbbb2af
--- /dev/null
+++ b/magic/magic-docs/html/shift.html
@@ -0,0 +1,25 @@
+
+
Tux Paint "Magic" Tool:
+
+Shift
+
+
+
+
+
+
+
+Tux Paint "Magic" Tool:
+
+Shift
+
+
+
+
+ This shifts your picture around the canvas. Anything that gets
+ shifts off an edge reappears on the opposite edge.
+
+
+
+
diff --git a/magic/magic-docs/shift.txt b/magic/magic-docs/shift.txt
new file mode 100644
index 000000000..c0c063d12
--- /dev/null
+++ b/magic/magic-docs/shift.txt
@@ -0,0 +1,4 @@
+ Tux Paint "Magic" Tool: Shift
+
+ This shifts your picture around the canvas. Anything that gets shifts off
+ an edge reappears on the opposite edge.
diff --git a/magic/src/light.c b/magic/src/light.c
new file mode 100644
index 000000000..78bb36c7c
--- /dev/null
+++ b/magic/src/light.c
@@ -0,0 +1,209 @@
+/*
+ light.c
+
+ Light Magic Tool Plugin
+ Tux Paint - A simple drawing program for children.
+
+ Copyright (c) 2002-2007 by Bill Kendrick and others; see AUTHORS.txt
+ bill@newbreedsoftware.com
+ http://www.tuxpaint.org/
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ (See COPYING.txt)
+
+ Last updated: August 9, 2007
+ $Id$
+*/
+
+#include
+#include
+#include
+#include "tp_magic_api.h"
+#include "SDL_image.h"
+#include "SDL_mixer.h"
+
+#include "math.h"
+
+/* Our globals: */
+
+Mix_Chunk * light1_snd, * light2_snd;
+float light_h, light_s, light_v;
+
+
+Uint32 light_api_version(void) { return(TP_MAGIC_API_VERSION); }
+
+
+// No setup required:
+int light_init(magic_api * api)
+{
+ char fname[1024];
+
+ snprintf(fname, sizeof(fname), "%s/sounds/magic/light1.ogg",
+ api->data_directory);
+ light1_snd = Mix_LoadWAV(fname);
+
+ snprintf(fname, sizeof(fname), "%s/sounds/magic/light2.ogg",
+ api->data_directory);
+ light2_snd = Mix_LoadWAV(fname);
+
+ return(1);
+}
+
+// We have multiple tools:
+int light_get_tool_count(magic_api * api)
+{
+ return(1);
+}
+
+// Load our icons:
+SDL_Surface * light_get_icon(magic_api * api, int which)
+{
+ char fname[1024];
+
+ snprintf(fname, sizeof(fname), "%s/images/magic/light.png",
+ api->data_directory);
+
+ return(IMG_Load(fname));
+}
+
+// Return our names, localized:
+char * light_get_name(magic_api * api, int which)
+{
+ return(strdup(gettext("Light")));
+}
+
+// Return our descriptions, localized:
+char * light_get_description(magic_api * api, int which)
+{
+ return(strdup(gettext("Click and drag to draw a beam of light on your picture.")));
+}
+
+// Do the effect:
+
+void do_light(void * ptr, int which, SDL_Surface * canvas, SDL_Surface * last,
+ int x, int y)
+{
+ magic_api * api = (magic_api *) ptr;
+ int xx, yy;
+ Uint32 pix;
+ Uint8 r, g, b;
+ float h, s, v, new_h, new_s, new_v;
+ float adj;
+
+ for (yy = -8; yy < 8; yy++)
+ {
+ for (xx = -8; xx < 8; xx++)
+ {
+ if (api->in_circle(xx, yy, 8))
+ {
+ pix = api->getpixel(canvas, x + xx, y + yy);
+
+ SDL_GetRGB(pix, canvas->format, &r, &g, &b);
+
+ adj = (7.99 - sqrt(abs(xx * yy))) / 128.0;
+
+ api->rgbtohsv(r, g, b, &h, &s, &v);
+
+ v = min((float) 1.0, v + adj);
+
+ if (light_h == -1 && h == -1)
+ {
+ new_h = -1;
+ new_s = 0;
+ new_v = v;
+ }
+ else if (light_h == -1)
+ {
+ new_h = h;
+ new_s = max(0.0, s - adj / 2.0);
+ new_v = v;
+ }
+ else if (h == -1)
+ {
+ new_h = light_h;
+ new_s = max(0.0, light_s - adj / 2.0);
+ new_v = v;
+ }
+ else
+ {
+ new_h = (light_h + h) / 2;
+ new_s = max(0.0, s - adj / 2.0);
+ new_v = v;
+ }
+
+ api->hsvtorgb(new_h, new_s, new_v, &r, &g, &b);
+
+ api->putpixel(canvas, x + xx, y + yy,
+ SDL_MapRGB(canvas->format, r, g, b));
+ }
+ }
+ }
+}
+
+// Affect the canvas on drag:
+void light_drag(magic_api * api, int which, SDL_Surface * canvas,
+ SDL_Surface * last, int ox, int oy, int x, int y,
+ SDL_Rect * update_rect)
+{
+ api->line((void *) api, which, canvas, last, ox, oy, x, y, 1, do_light);
+
+ if (ox > x) { int tmp = ox; ox = x; x = tmp; }
+ if (oy > y) { int tmp = oy; oy = y; y = tmp; }
+
+ update_rect->x = ox - 8;
+ update_rect->y = oy - 8;
+ update_rect->w = (x + 8) - update_rect->x;
+ update_rect->h = (y + 8) - update_rect->h;
+
+ api->playsound(light1_snd, (x * 255) / canvas->w, 255);
+}
+
+// Affect the canvas on click:
+void light_click(magic_api * api, int which,
+ SDL_Surface * canvas, SDL_Surface * last,
+ int x, int y, SDL_Rect * update_rect)
+{
+ light_drag(api, which, canvas, last, x, y, x, y, update_rect);
+}
+
+// Affect the canvas on release:
+void light_release(magic_api * api, int which,
+ SDL_Surface * canvas, SDL_Surface * last,
+ int x, int y, SDL_Rect * update_rect)
+{
+ api->playsound(light2_snd, (x * 255) / canvas->w, 255);
+}
+
+// No setup happened:
+void light_shutdown(magic_api * api)
+{
+ if (light1_snd != NULL)
+ Mix_FreeChunk(light1_snd);
+ if (light2_snd != NULL)
+ Mix_FreeChunk(light2_snd);
+}
+
+// Record the color from Tux Paint:
+void light_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b)
+{
+ api->rgbtohsv(r, g, b, &light_h, &light_s, &light_v);
+}
+
+// Use colors:
+int light_requires_colors(magic_api * api, int which)
+{
+ return 1;
+}
+
diff --git a/magic/src/shift.c b/magic/src/shift.c
new file mode 100644
index 000000000..306da18b5
--- /dev/null
+++ b/magic/src/shift.c
@@ -0,0 +1,255 @@
+/*
+ shift.c
+
+ Shift Magic Tool Plugin
+ Tux Paint - A simple drawing program for children.
+
+ Copyright (c) 2002-2007 by Bill Kendrick and others; see AUTHORS.txt
+ bill@newbreedsoftware.com
+ http://www.tuxpaint.org/
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ (See COPYING.txt)
+
+ Last updated: August 9, 2007
+ $Id$
+*/
+
+#include
+#include
+#include
+#include "tp_magic_api.h"
+#include "SDL_image.h"
+#include "SDL_mixer.h"
+
+#include "math.h"
+
+/* Our globals: */
+
+int shift_x, shift_y;
+Mix_Chunk * shift_snd;
+
+
+Uint32 shift_api_version(void) { return(TP_MAGIC_API_VERSION); }
+
+
+// No setup required:
+int shift_init(magic_api * api)
+{
+ char fname[1024];
+
+ snprintf(fname, sizeof(fname), "%s/sounds/magic/shift.ogg",
+ api->data_directory);
+ shift_snd = Mix_LoadWAV(fname);
+
+ return(1);
+}
+
+// We have multiple tools:
+int shift_get_tool_count(magic_api * api)
+{
+ return(1);
+}
+
+// Load our icons:
+SDL_Surface * shift_get_icon(magic_api * api, int which)
+{
+ char fname[1024];
+
+ snprintf(fname, sizeof(fname), "%s/images/magic/shift.png",
+ api->data_directory);
+
+ return(IMG_Load(fname));
+}
+
+// Return our names, localized:
+char * shift_get_name(magic_api * api, int which)
+{
+ return(strdup(gettext("Shift")));
+}
+
+// Return our descriptions, localized:
+char * shift_get_description(magic_api * api, int which)
+{
+ return(strdup(gettext("Click and drag to shift your picture around on the canvas.")));
+}
+
+
+// Affect the canvas on drag:
+void shift_drag(magic_api * api, int which, SDL_Surface * canvas,
+ SDL_Surface * last, int ox, int oy, int x, int y,
+ SDL_Rect * update_rect)
+{
+ SDL_Rect dest;
+ int dx, dy;
+
+
+ if (ox == x && oy == y)
+ return; /* No-op */
+
+
+ dx = x - shift_x;
+ dy = y - shift_y;
+
+ while (dx < -canvas->w)
+ dx += canvas->w;
+ while (dx > canvas->w)
+ dx -= canvas->w;
+
+ while (dy < -canvas->h)
+ dy += canvas->h;
+ while (dy > canvas->h)
+ dy -= canvas->h;
+
+
+ /* Center */
+
+ dest.x = dx;
+ dest.y = dy;
+
+ SDL_BlitSurface(last, NULL, canvas, &dest);
+
+
+ if (dy > 0)
+ {
+ if (dx > 0)
+ {
+ /* Top Left */
+
+ dest.x = dx - canvas->w;
+ dest.y = dy - canvas->h;
+
+ SDL_BlitSurface(last, NULL, canvas, &dest);
+ }
+
+
+ /* Top */
+
+ dest.x = dx;
+ dest.y = dy - canvas->h;
+
+ SDL_BlitSurface(last, NULL, canvas, &dest);
+
+
+ if (dx < 0)
+ {
+ /* Top Right */
+
+ dest.x = dx + canvas->w;
+ dest.y = dy - canvas->h;
+
+ SDL_BlitSurface(last, NULL, canvas, &dest);
+ }
+ }
+
+
+ if (dx > 0)
+ {
+ /* Left */
+
+ dest.x = dx - canvas->w;
+ dest.y = dy;
+
+ SDL_BlitSurface(last, NULL, canvas, &dest);
+ }
+
+ if (dx < 0)
+ {
+ /* Right */
+
+ dest.x = dx + canvas->w;
+ dest.y = dy;
+
+ SDL_BlitSurface(last, NULL, canvas, &dest);
+ }
+
+
+ if (dy < 0)
+ {
+ if (dx > 0)
+ {
+ /* Bottom Left */
+
+ dest.x = dx - canvas->w;
+ dest.y = dy + canvas->h;
+
+ SDL_BlitSurface(last, NULL, canvas, &dest);
+ }
+
+
+ /* Bottom */
+
+ dest.x = dx;
+ dest.y = dy + canvas->h;
+
+ SDL_BlitSurface(last, NULL, canvas, &dest);
+
+
+ if (dx < 0)
+ {
+ /* Bottom Right */
+
+ dest.x = dx + canvas->w;
+ dest.y = dy + canvas->h;
+
+ SDL_BlitSurface(last, NULL, canvas, &dest);
+ }
+ }
+
+
+ /* Update everything! */
+
+ update_rect->x = 0;
+ update_rect->y = 0;
+ update_rect->w = canvas->w;
+ update_rect->h = canvas->h;
+
+ api->playsound(shift_snd, (x * 255) / canvas->w, 255);
+}
+
+// Affect the canvas on click:
+void shift_click(magic_api * api, int which,
+ SDL_Surface * canvas, SDL_Surface * last,
+ int x, int y, SDL_Rect * update_rect)
+{
+ shift_x = x;
+ shift_y = y;
+}
+
+// Affect the canvas on release:
+void shift_release(magic_api * api, int which,
+ SDL_Surface * canvas, SDL_Surface * last,
+ int x, int y, SDL_Rect * update_rect)
+{
+}
+
+// No setup happened:
+void shift_shutdown(magic_api * api)
+{
+ if (shift_snd != NULL)
+ Mix_FreeChunk(shift_snd);
+}
+
+// Record the color from Tux Paint:
+void shift_set_color(magic_api * api, Uint8 r, Uint8 g, Uint8 b)
+{
+}
+
+// Use colors:
+int shift_requires_colors(magic_api * api, int which)
+{
+ return 0;
+}
+