[gnome-games] Update Lights Off to use Clutter 0.9



commit c6f81ef9906e0ce2b2a9e53a9cacecb253694521
Author: Tim Horton <hortont424 gmail com>
Date:   Wed Jun 3 21:59:06 2009 -0400

    Update Lights Off to use Clutter 0.9
    
    In addition, Lights Off is now themeable, draws some parts with Cairo,
    has a preferences window, and a (unimplemented) menu. There are some
    animation problems at the moment, which may be due to a Clutter bug.

 configure.in                                       |   17 +-
 lightsoff/0.svg                                    |  209 ------------------
 lightsoff/1.svg                                    |  177 ---------------
 lightsoff/2.svg                                    |  187 ----------------
 lightsoff/3.svg                                    |  207 ------------------
 lightsoff/4.svg                                    |  165 --------------
 lightsoff/5.svg                                    |  187 ----------------
 lightsoff/6.svg                                    |  209 ------------------
 lightsoff/7.svg                                    |  187 ----------------
 lightsoff/8.svg                                    |  227 -------------------
 lightsoff/9.svg                                    |  209 ------------------
 lightsoff/Arrow.js.in                              |   31 +++
 lightsoff/Board.js.in                              |  209 ++++++++++++++++++
 lightsoff/Game.js.in                               |  171 +++++++++++++++
 lightsoff/LED.js.in                                |  211 ++++++++++++++++++
 lightsoff/Light.js.in                              |   74 +++++++
 lightsoff/Makefile.am                              |   60 ++----
 lightsoff/Settings.js.in                           |  107 +++++++++
 lightsoff/arrow.js.in                              |   42 ----
 lightsoff/board.js.in                              |  230 --------------------
 lightsoff/lcd-off.svg                              |  228 -------------------
 lightsoff/light-off.svg                            |  228 -------------------
 lightsoff/light-on.svg                             |  204 -----------------
 lightsoff/light.js.in                              |   93 --------
 lightsoff/lightsoff.in                             |    7 +-
 lightsoff/main-window.ui                           |   90 ++++++++
 lightsoff/main.js.in                               |   82 +++-----
 lightsoff/score.js.in                              |  113 ----------
 lightsoff/settings.ui                              |  137 ++++++++++++
 lightsoff/themes/Makefile.am                       |    1 +
 lightsoff/themes/tango/Makefile.am                 |   18 ++
 lightsoff/themes/tango/arrow.svg                   |   66 ++++++
 .../{lcd-back.svg => themes/tango/backing.svg}     |   48 +++-
 .../{lcd-back.svg => themes/tango/led-back.svg}    |   12 +-
 .../{lcd-front.svg => themes/tango/led-front.svg}  |   14 +-
 lightsoff/{arrow.svg => themes/tango/off.svg}      |   85 +++----
 lightsoff/{arrow.svg => themes/tango/on.svg}       |   85 +++----
 lightsoff/themes/tango/theme.js                    |   23 ++
 lightsoff/themes/tango/theme.js.in                 |   23 ++
 lightsoff/themes/up/Makefile.am                    |   18 ++
 lightsoff/themes/up/arrow.svg                      |   66 ++++++
 lightsoff/{lcd-back.svg => themes/up/backing.svg}  |   48 +++-
 lightsoff/{lcd-back.svg => themes/up/led-back.svg} |   12 +-
 .../{lcd-front.svg => themes/up/led-front.svg}     |   14 +-
 lightsoff/themes/up/off.svg                        |  164 ++++++++++++++
 lightsoff/themes/up/on.svg                         |  198 +++++++++++++++++
 lightsoff/themes/up/theme.js.in                    |   23 ++
 47 files changed, 1864 insertions(+), 3352 deletions(-)
---
diff --git a/configure.in b/configure.in
index 4b19d08..d43ba53 100644
--- a/configure.in
+++ b/configure.in
@@ -1249,13 +1249,20 @@ iagno/iagno.desktop.in
 gnect/data/gnect.desktop.in
 gnomine/gnomine.desktop.in
 lightsoff/Makefile
-lightsoff/arrow.js
-lightsoff/board.js
-lightsoff/light.js
-lightsoff/main.js
-lightsoff/score.js
 lightsoff/lightsoff
 lightsoff/lightsoff.desktop.in
+lightsoff/Arrow.js
+lightsoff/Board.js
+lightsoff/Light.js
+lightsoff/main.js
+lightsoff/Game.js
+lightsoff/LED.js
+lightsoff/Settings.js
+lightsoff/themes/Makefile
+lightsoff/themes/tango/Makefile
+lightsoff/themes/tango/theme.js
+lightsoff/themes/up/Makefile
+lightsoff/themes/up/theme.js
 tests/Makefile
 tests/libgames-support/Makefile
 shave
diff --git a/lightsoff/Arrow.js.in b/lightsoff/Arrow.js.in
new file mode 100644
index 0000000..bb91565
--- /dev/null
+++ b/lightsoff/Arrow.js.in
@@ -0,0 +1,31 @@
+file_prefix = '@prefix@' + "/share/gnome-games/lightsoff/";
+imports.searchPath.unshift(file_prefix);
+
+Settings = imports.Settings;
+Clutter = imports.gi.Clutter;
+
+ArrowView = new GType({
+	parent: Clutter.Group.type,
+	name: "ArrowView",
+	init: function()
+	{
+		// Private
+		
+		var direction = 0;
+		var arrow = new Clutter.Clone({source: Settings.theme.arrow});
+		
+		// Public
+		
+		this.flip_arrow = function()
+		{
+			this.rotation_angle_z = 180;
+			direction = 1;
+		}
+		
+		// Implementation
+		
+		this.anchor_gravity = Clutter.Gravity.CENTER;
+		this.add_actor(arrow);
+		this.reactive = true;
+	}
+});
diff --git a/lightsoff/Board.js.in b/lightsoff/Board.js.in
new file mode 100644
index 0000000..55d10dc
--- /dev/null
+++ b/lightsoff/Board.js.in
@@ -0,0 +1,209 @@
+file_prefix = '@prefix@' + "/share/gnome-games/lightsoff/";
+imports.searchPath.unshift(file_prefix);
+
+Settings = imports.Settings;
+GLib = imports.gi.GLib;
+Clutter = imports.gi.Clutter;
+Light = imports.Light;
+
+var tiles = 5; // fix this
+
+BoardView = new GType({
+	parent: Clutter.Group.type,
+	name: "BoardView",
+	signals: [{name: "game_won"}],
+	init: function()
+	{
+		// Private
+		var self = this;
+		var playable = true;
+		var lights = [];
+		
+		// Create a two-dimensional array of 'tiles*tiles' lights,
+		// connect to their clicked signals, and display them.
+		var create_lights = function()
+		{
+			for(var x = 0; x < tiles; x++)
+			{
+				lights[x] = [];
+				
+				for(var y = 0; y < tiles; y++)
+				{
+					var l = new Light.LightView();
+					l.set_position((x + 0.5) * l.width, (y + 0.5) * l.height);
+					l.signal.button_release_event.connect(light_clicked, {"x":x, "y":y});
+					
+					lights[x][y] = l;
+					self.add_actor(l);
+					
+					GLib.main_context_iteration(null, false);
+				}
+			}
+		}
+		
+		// Toggle a light and those in each cardinal direction around it.
+		var light_toggle = function(x, y)
+		{
+			if(!playable)
+				return;
+			
+			var timeline = new Clutter.Timeline({duration: 300});
+			timeline.signal.completed.connect(check_won);
+			
+			if(x + 1 < tiles)
+				lights[x + 1][y].toggle(timeline);
+			if(x - 1 >= 0)
+				lights[x - 1][y].toggle(timeline);
+			if(y + 1 < tiles)
+				lights[x][y + 1].toggle(timeline);
+			if(y - 1 >= 0)
+				lights[x][y - 1].toggle(timeline);
+
+			lights[x][y].toggle(timeline);
+			
+			timeline.start();
+		}
+		
+		// Check if the game was won; if so, emit the game_won signal
+		// in order to notify the Game controller.
+		
+		var check_won = function()
+		{
+			if(cleared())
+				self.signal.game_won.emit();
+		}
+		
+		// Callback for button_release_event from each light; user_data
+		// is an object containing the coordinates of the clicked light.
+		var light_clicked = function(light, event, coords)
+		{
+			light_toggle(coords.x, coords.y);
+			
+			return false;
+		}
+		
+		// Returns whether or not the board is entirely 'off' (i.e. game is won)
+		var cleared = function()
+		{
+			for(var x = 0; x < tiles; x++)
+				for(var y = 0; y < tiles; y++)
+					if(lights[x][y].get_state())
+						return false;
+			
+			return true;
+		}
+		
+		// Public
+		
+		// Pseudorandomly generates and sets the state of each light based on
+		// a level number; hopefully this is stable between machines, but that
+		// depends on GLib's PRNG stability. Also, provides some semblance of 
+		// symmetry for some levels.
+		this.load_level = function(level)
+		{
+			GLib.random_set_seed(level);
+			
+			do
+			{
+				// log(level^2) gives a reasonable progression of difficulty
+				var count = Math.floor(Math.log(level * level) + 1);
+				var sym = Math.floor(3 * GLib.random_double());
+
+				for (var q = 0; q < count; ++q)
+				{
+					i = Math.round((tiles - 1) * GLib.random_double());
+					j = Math.round((tiles - 1) * GLib.random_double());
+					
+					light_toggle(i, j);
+					
+					// Ensure some level of "symmetry"
+					var x_sym = Math.abs(i - (tiles - 1));
+					var y_sym = Math.abs(j - (tiles - 1));
+					
+					if(sym == 0)
+						light_toggle(x_sym, j);
+					else if(sym == 1)
+						light_toggle(x_sym, y_sym);
+					else
+						light_toggle(i, y_sym);
+				}
+			}
+			while(cleared());
+		}
+		
+		this.set_playable = function(p)
+		{
+			playable = p;
+		}
+		
+		this.fade_out = function(timeline)
+		{
+			self.animate_with_timeline(Clutter.AnimationMode.EASE_OUT_SINE, 
+			                           timeline,
+			{
+				opacity: 0
+			});
+		}
+		
+		this.fade_in = function(timeline)
+		{
+			self.animate_with_timeline(Clutter.AnimationMode.EASE_OUT_SINE, 
+			                           timeline,
+			{
+				opacity: 255
+			});
+		}
+		
+		this.animate_out = function(direction, sign, timeline)
+		{
+			self.animate_with_timeline(Clutter.AnimationMode.EASE_OUT_BOUNCE, 
+			                           timeline,
+			{
+				x: sign * direction * self.width,
+				y: sign * !direction * self.height
+			});
+		}
+		
+		this.animate_in = function(direction, sign, timeline)
+		{
+			self.x = (-sign) * direction * self.width;
+			self.y = (-sign) * !direction * self.height;
+			
+			self.animate_with_timeline(Clutter.AnimationMode.EASE_OUT_BOUNCE, 
+			                           timeline,
+			{
+				x: 0,
+				y: 0
+			});
+		}
+		
+		this.swap_in = function(direction, timeline)
+		{
+			self.animate_with_timeline(Clutter.AnimationMode.EASE_IN_SINE, 
+			                           timeline,
+			{
+				depth: 0,
+				x: 0,
+				y: 0,
+				opacity: 255
+			});
+		}
+		
+		this.swap_out = function(direction, timeline)
+		{
+			self.animate_with_timeline(Clutter.AnimationMode.EASE_IN_SINE, 
+			                           timeline,
+			{
+				depth: 250 * direction,
+				x: 0,
+				y: 0,
+				opacity: 0
+			});
+		}
+		
+		// Implementation
+		
+		create_lights();
+	}
+});
+
diff --git a/lightsoff/Game.js.in b/lightsoff/Game.js.in
new file mode 100644
index 0000000..0301851
--- /dev/null
+++ b/lightsoff/Game.js.in
@@ -0,0 +1,171 @@
+file_prefix = '@prefix@' + "/share/gnome-games/lightsoff/";
+imports.searchPath.unshift(file_prefix);
+
+Settings = imports.Settings;
+GLib = imports.gi.GLib;
+Clutter = imports.gi.Clutter;
+LED = imports.LED;
+Board = imports.Board;
+Arrow = imports.Arrow;
+
+var last_direction, last_sign;
+
+GameView = new GType({
+	parent: Clutter.Group.type,
+	name: "GameView",
+	init: function()
+	{
+		// Private
+		var self = this;
+		var current_level = 1;
+		var score_view = new LED.LEDView();
+		var board_view = new Board.BoardView();
+		var backing_view = new Clutter.Clone({source:Settings.theme.backing});
+		var left_arrow = new Arrow.ArrowView();
+		var right_arrow = new Arrow.ArrowView();
+		var new_board_view = null;
+		var timeline;
+		
+		// Set up a new board.
+		var create_next_board = function()
+		{
+			new_board_view = new Board.BoardView();
+			new_board_view.load_level(current_level);
+			new_board_view.signal.game_won.connect(game_won);
+			new_board_view.hide();
+			new_board_view.set_playable(false);
+			self.add_actor(new_board_view);
+			new_board_view.lower_bottom();
+
+		}
+		
+		// The boards have finished transitioning; delete the old one!
+		var board_transition_complete = function()
+		{
+			self.remove_actor(board_view);
+			board_view = new_board_view;
+			board_view.set_playable(true);
+			timeline = 0;
+			
+			create_next_board();
+		}
+		
+		// The player won the game; create a new board, update the level count,
+		// and transition between the two boards in a random direction.
+		var game_won = function()
+		{
+			if(timeline && timeline.is_playing())
+				return false;
+			
+			var direction, sign;
+			score_view.set_value(++current_level);
+			
+			// Make sure the board transition is different than the previous.
+			do
+			{
+				direction = Math.floor(2 * Math.random());
+				sign = Math.floor(2 * Math.random()) ? 1 : -1;
+			}
+			while(last_direction == direction && last_sign != sign);
+	
+			last_direction = direction;
+			last_sign = sign;
+			
+			timeline = new Clutter.Timeline({duration: 1500});
+		
+			new_board_view.show();
+			new_board_view.animate_in(direction, sign, timeline);
+			board_view.animate_out(direction, sign, timeline);
+			timeline.signal.completed.connect(board_transition_complete);
+				
+			return false;
+		}
+		
+		var swap_board = function(arrow, event, context)
+		{
+			if(timeline && timeline.is_playing())
+				return false;
+			
+			current_level += context.direction;
+			
+			if(current_level <= 0)
+			{
+				current_level = 1;
+				return false;
+			}
+			
+			score_view.set_value(current_level);
+			
+			timeline = new Clutter.Timeline({duration: 500});
+			
+			new_board_view.depth = context.direction * -250;
+			new_board_view.opacity = 0;
+			new_board_view.show();
+			
+			new_board_view.swap_in(context.direction, timeline);
+			board_view.swap_out(context.direction, timeline);
+			timeline.signal.completed.connect(board_transition_complete);
+			
+			timeline.start();
+			
+			return false;
+		}
+		
+		var theme_changed = function()
+		{
+			timeline = new Clutter.Timeline({duration: 1500});
+			
+			create_next_board();
+			new_board_view.opacity = 0;
+			new_board_view.show();
+			
+			board_view.fade_out(timeline);
+			new_board_view.fade_in(timeline);
+			new_board_view.raise_top();
+			
+			timeline.signal.completed.connect(board_transition_complete);
+			timeline.start();
+		}
+		
+		// Public
+		
+		// Implementation
+		
+		// TODO: wrong::
+		
+		current_level = Settings.score;
+		Seed.print(current_level);
+		
+		// Set up and show the initial board
+		board_view.signal.game_won.connect(game_won);
+		board_view.load_level(current_level);
+		this.add_actor(board_view);
+		create_next_board();
+		
+		backing_view.set_position(0, board_view.height);
+		this.add_actor(backing_view);
+		
+		score_view.set_anchor_point(score_view.width / 2, 0);
+		score_view.set_position(board_view.width / 2, board_view.height + 18);
+		this.add_actor(score_view);
+		
+		left_arrow.set_position((score_view.x - score_view.anchor_x) / 2,
+		                        score_view.y + (score_view.height / 2));
+		this.add_actor(left_arrow);
+		
+		right_arrow.flip_arrow();
+		right_arrow.set_position(board_view.width - left_arrow.x,
+		                         score_view.y + (score_view.height / 2));
+		this.add_actor(right_arrow);
+		
+		left_arrow.signal.button_release_event.connect(swap_board, {direction: -1});
+		right_arrow.signal.button_release_event.connect(swap_board, {direction: 1});
+		
+		score_view.set_width(5);
+		score_view.set_value(current_level);
+		
+		this.set_size(board_view.width, score_view.y + score_view.height);
+
+		Settings.Watcher.signal.theme_changed.connect(theme_changed);
+	}
+});
diff --git a/lightsoff/LED.js.in b/lightsoff/LED.js.in
new file mode 100644
index 0000000..9256192
--- /dev/null
+++ b/lightsoff/LED.js.in
@@ -0,0 +1,211 @@
+file_prefix = '@prefix@' + "/share/gnome-games/lightsoff/";
+imports.searchPath.unshift(file_prefix);
+
+Settings = imports.Settings;
+cairo = imports.cairo;
+Clutter = imports.gi.Clutter;
+
+const HORIZONTAL = 0;
+const VERTICAL = 1;
+
+LEDDigit = new GType({
+	parent: Clutter.Group.type,
+	name: "LEDDigit",
+	init: function()
+	{
+		// Private
+		
+		var a, b, c, d, e, f, g;
+		var scale = 23;
+		var thickness = scale / 3;
+		var pointy = thickness / 2;
+		var margin = Math.floor(Math.log(scale));
+		var segments = [];
+		var s;
+		
+		// The state of each segment for each representable digit.
+		var segment_states = { 0: [ 1, 1, 1, 1, 1, 0, 1],
+		                       1: [ 0, 0, 0, 0, 1, 0, 1],
+		                       2: [ 1, 0, 1, 1, 0, 1, 1],
+		                       3: [ 1, 0, 0, 1, 1, 1, 1],
+		                       4: [ 0, 1, 0, 0, 1, 1, 1],
+		                       5: [ 1, 1, 0, 1, 1, 1, 0],
+		                       6: [ 1, 1, 1, 1, 1, 1, 0],
+		                       7: [ 1, 0, 0, 0, 1, 0, 1],
+		                       8: [ 1, 1, 1, 1, 1, 1, 1],
+		                       9: [ 1, 1, 0, 1, 1, 1, 1]};
+		var segment_directions = { 0: HORIZONTAL,
+		                           1: VERTICAL,
+		                           2: VERTICAL,
+		                           3: HORIZONTAL,
+		                           4: VERTICAL,
+		                           5: HORIZONTAL,
+		                           6: VERTICAL };
+		
+		// Draw a single section, in either direction, at the given position
+		var create_segment = function(num, x, y, alpha)
+		{
+			var texture = segments[num];
+					
+			var context = texture.create();
+			var cr = new cairo.Context.steal(context);
+			
+			cr.set_source_rgba(1, 1, 1, 0);
+			cr.paint();
+
+			if(alpha)
+				cr.set_source_rgba(0.145, 0.541, 1, 1);
+			else
+				cr.set_source_rgba(0.2, 0.2, 0.2, 1);
+			
+			cr.new_path();
+			
+			if(segment_directions[num] == VERTICAL)
+			{
+				cr.move_to(thickness / 2, 0);
+				cr.line_to(0, pointy);
+				cr.line_to(0, scale - pointy);
+				cr.line_to(thickness / 2, scale);
+				cr.line_to(thickness, scale - pointy);
+				cr.line_to(thickness, pointy);
+			}
+			else if(segment_directions[num] == HORIZONTAL)
+			{
+				cr.move_to(0, thickness / 2);
+				cr.line_to(pointy, 0);
+				cr.line_to(scale - pointy, 0);
+				cr.line_to(scale, thickness / 2);
+				cr.line_to(scale - pointy, thickness);
+				cr.line_to(pointy, thickness);
+			}
+			
+			cr.close_path();
+			cr.fill();
+			cr.destroy();
+
+			texture.set_position(x, y);
+
+			return texture;
+		}
+		
+		// Creates and arranges segments of the LEDDigit, lit based on the
+		// represented digit.
+		var draw_leds = function(group)
+		{
+			var side = pointy + margin;
+			
+			for(var i = 0; i < 7; i++)
+			{
+				segments[i] = new Clutter.CairoTexture();
+				
+				if(segment_directions[i] == VERTICAL)
+					segments[i].set_surface_size(thickness, scale);
+				else if(segment_directions[i] == HORIZONTAL)
+					segments[i].set_surface_size(scale, thickness);
+				
+				group.add_actor(segments[i]);
+			}
+			
+			create_segment(0, side, 0, s[0]);
+			create_segment(1, 0, side, s[1]);
+			create_segment(2, 0, side + scale + (margin*2), s[2]);
+			create_segment(3, side, (2*scale) + (4*margin), s[3]);
+			create_segment(4, scale + (2*margin),
+			                   side + scale + (margin*2), s[4]);
+			create_segment(5, side, scale + (2*margin), s[5]);
+			create_segment(6, scale + (2*margin), side, s[6]);
+		}
+		
+		// Public
+		
+		this.set_value = function(val)
+		{
+			s = segment_states[val];
+			draw_leds(this);
+		}
+		
+		// Implementation
+		
+		this.set_value(0);
+	}
+});
+
+LEDView = new GType({
+	parent: Clutter.Group.type,
+	name: "LEDView",
+	init: function()
+	{
+		// Private
+		
+		var value = 0;
+		var width = 0;
+		var margin = 5;
+		var digits = [];
+		var back, front;
+		var inner_x_margin = 10;
+		var inner_y_margin = -2;
+		
+		back = new Clutter.Clone({source: Settings.theme.led_back});
+		//front = new Clutter.Clone({source: Settings.theme.led_front});
+		
+		// Public
+		
+		// Creates, arranges, and shows LEDDigits to fill the given width.
+		this.set_width = function(wid)
+		{
+			width = wid;
+			
+			this.remove_all();
+			digits = [];
+			
+			this.add_actor(back);
+			//this.add_actor(front);
+			
+			for(var i = 0; i < width; i++)
+			{
+				digits[i] = new LEDDigit();
+				digits[i].set_anchor_point(0, digits[i].height / 2);
+				digits[i].x = (i * (digits[i].width + margin)) + inner_x_margin;
+				digits[i].y = (back.height / 2) + inner_y_margin;
+				this.add_actor(digits[i]);
+			}
+			
+			back.lower_bottom();
+			//this.raise_child(front, null);
+		}
+		
+		// Set the value represented by the LEDView, and update its
+		// child LEDDigits. Currently ignores digits past the width of the view.
+		this.set_value = function(val)
+		{
+			var d_val = value = val;
+			
+			for(var i = width - 1; i >= 0; i--)
+			{
+				digits[i].set_value(Math.floor(d_val % 10));
+				d_val /= 10;
+			}
+			
+			// TODO: this is a /really/ bad place to do this...
+			try
+			{
+				Settings.gconf_client.set_int("/apps/lightsoff/score", value);
+			}
+			catch(e)
+			{
+				Seed.print("Couldn't save score to GConf.");
+			}
+		}
+		
+		this.get_value = function()
+		{
+			return value;
+		}
+		
+		// Implementation
+		
+		this.add_actor(back);
+		//this.add_actor(front);
+	}
+});
+
diff --git a/lightsoff/Light.js.in b/lightsoff/Light.js.in
new file mode 100644
index 0000000..3d8267a
--- /dev/null
+++ b/lightsoff/Light.js.in
@@ -0,0 +1,74 @@
+file_prefix = '@prefix@' + "/share/gnome-games/lightsoff/";
+imports.searchPath.unshift(file_prefix);
+
+Settings = imports.Settings;
+Clutter = imports.gi.Clutter;
+
+LightView = new GType({
+	parent: Clutter.Group.type,
+	name: "LightView",
+	init: function()
+	{
+		// Private
+		var self = this; // Robb promises something better
+		var on = new Clutter.Clone({source: Settings.theme.light[1],
+		                            anchor_gravity: Clutter.Gravity.CENTER});
+		var off = new Clutter.Clone({source: Settings.theme.light[0],
+		                             anchor_gravity: Clutter.Gravity.CENTER});
+		var state = false;
+		
+		// Public
+		
+		// Animates to the requested lit state with the given timeline.
+		this.set_state = function(new_state, timeline)
+		{
+			state = new_state;
+			
+			// Animate the opacity of the 'off' tile to match the state.
+			off.animate_with_timeline(Clutter.AnimationMode.EASE_OUT_SINE, timeline,
+			{
+				opacity: (state ? 0 : 255)
+			});
+			
+			on.animate_with_timeline(Clutter.AnimationMode.EASE_OUT_SINE, timeline,
+			{
+				opacity: (state ? 255 : 0)
+			});
+			
+			// Animate the tile to be smaller when in the 'off' state.
+			self.animate_with_timeline(Clutter.AnimationMode.EASE_OUT_SINE, timeline,
+			{
+				scale_x: (state ? 1 : 0.9),
+				scale_y: (state ? 1 : 0.9)
+			});
+		}
+		
+		this.get_state = function()
+		{
+			return state;
+		}
+		
+		this.toggle = function(timeline)
+		{
+			self.set_state(!self.get_state(), timeline);
+		}
+		
+		// Implementation
+		
+		this.add_actor(on);
+		this.add_actor(off);
+		
+		this.set_scale(0.9, 0.9);
+		this.reactive = true;
+		this.anchor_gravity = Clutter.Gravity.CENTER;
+		
+		// Add a 2 px margin around the tile image, center tiles within it.
+		this.width += 4;
+		this.height += 4;
+		
+		on.set_position(this.width / 2, this.height / 2);
+		off.set_position(this.width / 2, this.height / 2);
+		
+		on.opacity = 0;
+	}
+});
diff --git a/lightsoff/Makefile.am b/lightsoff/Makefile.am
index 43eee6e..732835c 100644
--- a/lightsoff/Makefile.am
+++ b/lightsoff/Makefile.am
@@ -1,29 +1,16 @@
-losvgdir = $(datadir)/pixmaps/lightsoff
-losvg_DATA = \
-	light-off.svg \
-	light-on.svg \
-	0.svg \
-	1.svg \
-	2.svg \
-	3.svg \
-	4.svg \
-	5.svg \
-	6.svg \
-	7.svg \
-	8.svg \
-	9.svg \
-	lcd-back.svg \
-	lcd-front.svg \
-	lcd-off.svg \
-	arrow.svg
+SUBDIRS = themes
 
 lojsdir = $(pkgdatadir)/lightsoff
 lojs_DATA = \
-	arrow.js \
-	board.js \
-	light.js \
+	Arrow.js \
+	Board.js \
+	Light.js \
 	main.js \
-	score.js
+	Game.js \
+	LED.js \
+	Settings.js \
+	settings.ui \
+	main-window.ui
 
 bin_SCRIPTS = \
 	lightsoff
@@ -36,25 +23,12 @@ desktop_DATA = $(desktop_in_files:.desktop.in.in=.desktop)
 CLEANFILES = $(lojs_DATA) $(desktop_DATA)
 
 EXTRA_DIST = \
-	board.js.in \
-	light.js.in \
+	Arrow.js.in \
+	Board.js.in \
+	Light.js.in \
 	main.js.in \
-	light-off.svg \
-	light-on.svg \
-	0.svg \
-	1.svg \
-	2.svg \
-	3.svg \
-	4.svg \
-	5.svg \
-	6.svg \
-	7.svg \
-	8.svg \
-	9.svg \
-	lcd-back.svg \
-	lcd-front.svg \
-	score.js.in \
-	lcd-off.svg \
-	arrow.svg \
-	lightsoff.in \
-	arrow.js.in
+	Game.js.in \
+	LED.js.in \
+	Settings.js.in \
+	settings.ui \
+	main-window.ui
diff --git a/lightsoff/Settings.js.in b/lightsoff/Settings.js.in
new file mode 100644
index 0000000..a79536c
--- /dev/null
+++ b/lightsoff/Settings.js.in
@@ -0,0 +1,107 @@
+file_prefix = '@prefix@' + "/share/gnome-games/lightsoff/";
+imports.searchPath.unshift(file_prefix);
+
+Gtk = imports.gi.Gtk;
+Gio = imports.gi.Gio;
+GtkBuilder = imports.gtkbuilder;
+main = imports.main;
+GConf = imports.gi.GConf;
+
+GConf.init(Seed.argv);
+
+// Defaults
+var theme, score;
+
+try
+{
+	gconf_client = GConf.Client.get_default();
+	score = gconf_client.get_int("/apps/lightsoff/score");
+	theme = imports.themes[gconf_client.get_string("/apps/lightsoff/theme")].theme;
+}
+catch(e)
+{
+	Seed.print("Couldn't load settings from GConf.");
+	theme = imports.themes["tango"].theme;
+	score = 1;
+}
+
+// Settings Event Handler
+
+SettingsWatcher = new GType({
+	parent: Gtk.Button.type, // Can I make something inherit directly from GObject?!
+	name: "SettingsWatcher",
+	signals: [{name: "theme_changed"}],
+	init: function()
+	{
+		
+	}
+});
+
+var Watcher = new SettingsWatcher();
+
+// Settings UI
+
+handlers = {
+	select_theme: function(selector, ud)
+	{
+		theme = imports.themes[selector.get_active_text()].theme;
+		
+		try
+		{
+			gconf_client.set_string("/apps/lightsoff/theme", selector.get_active_text());
+		}
+		catch(e)
+		{
+			Seed.print("Couldn't save settings to GConf.");
+		}
+	
+		Watcher.signal.theme_changed.emit();
+	},
+	close_settings: function()
+	{
+		//settings_dialog.hide_all();
+	}
+};
+
+// Settings UI Helper Functions
+
+function show_settings()
+{
+	b = new Gtk.Builder();
+	b.add_from_file(file_prefix+"/settings.ui");
+	b.connect_signals(handlers);
+
+	populate_theme_selector(b.get_object("theme-selector"));
+
+	settings_dialog = b.get_object("dialog1");
+	settings_dialog.set_transient_for(main.window);
+	
+	var result = settings_dialog.run();
+	
+	settings_dialog.destroy();
+}
+
+function populate_theme_selector(selector)
+{
+	// Since we're using GtkBuilder, we can't make a Gtk.ComboBox.text. Instead,
+	// we'll construct the cell renderer here, once, and use that.
+	var cell = new Gtk.CellRendererText();
+	selector.pack_start(cell, true);
+	selector.add_attribute(cell, "text", 0);
+
+	file = Gio.file_new_for_path(file_prefix+"/themes");
+	enumerator = file.enumerate_children("standard::name");
+	
+	var i = 0;
+
+	while((child = enumerator.next_file()))
+	{
+		var fname = child.get_name();
+		selector.append_text(fname);
+		
+		if(fname == theme.name)
+			selector.set_active(i);
+		
+		i++;
+	}
+}
diff --git a/lightsoff/lightsoff.in b/lightsoff/lightsoff.in
index 429d900..9c3ff1a 100644
--- a/lightsoff/lightsoff.in
+++ b/lightsoff/lightsoff.in
@@ -1,2 +1,7 @@
 #!/usr/bin/env seed
-Seed.include('@prefix@'+"/share/gnome-games/lightsoff/main.js");
+
+file_prefix = '@prefix@' + "/share/gnome-games/lightsoff/";
+imports.searchPath.unshift(file_prefix);
+
+main = imports.main;
+
diff --git a/lightsoff/main-window.ui b/lightsoff/main-window.ui
new file mode 100644
index 0000000..391c391
--- /dev/null
+++ b/lightsoff/main-window.ui
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.14"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkWindow" id="window1">
+    <property name="title" translatable="yes">Lights Off</property>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkMenuBar" id="menubar2">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkMenuItem" id="menuitem5">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Game</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="menu4">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkImageMenuItem" id="imagemenuitem11">
+                        <property name="label">gtk-new</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkImageMenuItem" id="imagemenuitem12">
+                        <signal name="activate" handler="show_settings"/>
+                        <property name="label">gtk-preferences</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkImageMenuItem" id="imagemenuitem15">
+                        <property name="label">gtk-quit</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menuitem7">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_View</property>
+                <property name="use_underline">True</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menuitem8">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_Help</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="menu6">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkImageMenuItem" id="imagemenuitem20">
+                        <property name="label">gtk-about</property>
+                        <property name="visible">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/lightsoff/main.js.in b/lightsoff/main.js.in
index 0389f4d..1e5734c 100755
--- a/lightsoff/main.js.in
+++ b/lightsoff/main.js.in
@@ -1,67 +1,43 @@
 #!/usr/bin/env seed
 
-// Configuration
-var tiles = 5;
-var tile_size = 75;
+file_prefix = '@prefix@' + "/share/gnome-games/lightsoff/";
+imports.searchPath.unshift(file_prefix);
 
-imports.gi.versions.Clutter = "0.8";
-imports.gi.versions.GtkClutter = "0.8";
-
-Gtk = imports.gi.Gtk;
-Clutter = imports.gi.Clutter;
 GtkClutter = imports.gi.GtkClutter;
-GdkPixbuf = imports.gi.GdkPixbuf;
-GConf = imports.gi.GConf;
-GLib = imports.gi.GLib;
-Pango = imports.gi.Pango;
-GObject = imports.gi.GObject;
-
-Clutter.init(null, null);
-GConf.init(null, null);
-
-var margin = 5;
-var in_setup = false;
-var board_size = (tile_size + margin) * tiles + margin;
-
-Seed.include('@prefix@'+"/share/gnome-games/lightsoff/score.js");
-Seed.include('@prefix@'+"/share/gnome-games/lightsoff/light.js");
-Seed.include('@prefix@'+"/share/gnome-games/lightsoff/board.js");
-Seed.include('@prefix@'+"/share/gnome-games/lightsoff/arrow.js");
+Clutter = imports.gi.Clutter;
+Gtk = imports.gi.Gtk;
+GtkBuilder = imports.gtkbuilder;
 
-var black = new Clutter.Color();
-Clutter.color_parse("Black", black);
+GtkClutter.init(Seed.argv);
 
-var stage = new Clutter.Stage();
-// Needs to be translatable. I haven't figured this out yet.
-stage.title = "Lights Off";
-stage.signal.hide.connect(function () { Clutter.main_quit(); });
-stage.color = black;
+Game = imports.Game;
+Settings = imports.Settings;
 
-score = new Score();
-board = new Board();
-rect = new Clutter.Rectangle({color:black});
-forward = new Arrow();
-back = new Arrow();
+handlers = {
+	show_settings: function(selector, ud)
+	{
+		Settings.show_settings();
+	}
+};
 
-score.set_position((board_size / 2) - (score.width / 2), board_size + margin);
-stage.set_size(board_size, board_size + score.height + margin * 3);
+b = new Gtk.Builder();
+b.add_from_file(file_prefix + "/main-window.ui");
+b.connect_signals(handlers);
 
-rect.set_position(0, board_size);
-rect.set_size(stage.width, stage.height);
+var window = b.get_object("window1");
+var clutter_embed = new GtkClutter.Embed();
+window.signal.hide.connect(Gtk.main_quit);
+b.get_object("vbox1").pack_start(clutter_embed, true, true);
 
-back.set_position(score.x - back.width - 2*margin,
-				  score.y + (.5 * score.height) - (.5 * back.height));
+var stage = clutter_embed.get_stage();
+stage.color = {alpha:255};
 
-forward.flip();
-forward.set_position(score.x + score.width + 2*margin,
-					 score.y + (.5 * score.height) - (.5 * forward.height));
+var game = new Game.GameView();
+stage.add_actor(game);
+stage.set_size(game.width, game.height);
+clutter_embed.set_size_request(stage.width, stage.height);
 
-stage.add_actor(board);
-stage.add_actor(rect);
-stage.add_actor(score);
-stage.add_actor(forward);
-stage.add_actor(back);
 stage.show_all();
+window.show_all();
 
-Clutter.main();
-
+Gtk.main();
diff --git a/lightsoff/settings.ui b/lightsoff/settings.ui
new file mode 100644
index 0000000..19c9437
--- /dev/null
+++ b/lightsoff/settings.ui
@@ -0,0 +1,137 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="dialog1">
+    <property name="title" translatable="yes">Lights Off</property>
+    <property name="border_width">5</property>
+    <property name="type_hint">normal</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <object class="GtkFrame" id="frame3">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment3">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox3">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkHBox" id="hbox1">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkLabel" id="label6">
+                                <property name="visible">True</property>
+                                <property name="label" translatable="yes">Theme:</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkComboBox" id="theme-selector">
+                                <property name="visible">True</property>
+                                <property name="model">liststore1</property>
+                                <signal name="changed" handler="select_theme"/>
+                              </object>
+                              <packing>
+                                <property name="padding">8</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="use-gnome-theme-checkbox">
+                            <property name="label" translatable="yes">Use colors from GNOME theme</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="padding">8</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="ypad">5</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Look &amp;amp; Feel&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="close-button">
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">close-button</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkListStore" id="liststore1">
+    <columns>
+      <!-- column-name str -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+</interface>
diff --git a/lightsoff/themes/Makefile.am b/lightsoff/themes/Makefile.am
new file mode 100644
index 0000000..4280921
--- /dev/null
+++ b/lightsoff/themes/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = tango up
diff --git a/lightsoff/themes/tango/Makefile.am b/lightsoff/themes/tango/Makefile.am
new file mode 100644
index 0000000..6b7e3fc
--- /dev/null
+++ b/lightsoff/themes/tango/Makefile.am
@@ -0,0 +1,18 @@
+themedir = $(pkgdatadir)/lightsoff/themes/tango
+theme_DATA = \
+	arrow.svg \
+	backing.svg \
+	led-back.svg \
+	led-front.svg \
+	off.svg \
+	on.svg \
+	theme.js
+
+EXTRA_DIST = \
+	arrow.svg \
+	backing.svg \
+	led-back.svg \
+	led-front.svg \
+	off.svg \
+	on.svg \
+	theme.js.in
diff --git a/lightsoff/themes/tango/arrow.svg b/lightsoff/themes/tango/arrow.svg
new file mode 100644
index 0000000..7fdb4e8
--- /dev/null
+++ b/lightsoff/themes/tango/arrow.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="32"
+   height="52"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   version="1.0"
+   sodipodi:docname="arrow.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs4">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#000000"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="10.162162"
+     inkscape:cx="13.809616"
+     inkscape:cy="16.285027"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-346.35856,-494.3177)">
+    <path
+       style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       d="M 375.29882,542.10353 L 372.884,544.62335 L 349.89076,521.36761 C 349.26081,520.6677 349.26081,519.96775 349.89076,519.26778 L 372.884,496.01205 L 375.29882,498.53186 L 353.77546,520.26521 L 375.29882,542.10353"
+       id="text2388" />
+  </g>
+</svg>
diff --git a/lightsoff/lcd-back.svg b/lightsoff/themes/tango/backing.svg
similarity index 71%
copy from lightsoff/lcd-back.svg
copy to lightsoff/themes/tango/backing.svg
index dd03b54..31502ba 100644
--- a/lightsoff/lcd-back.svg
+++ b/lightsoff/themes/tango/backing.svg
@@ -9,17 +9,28 @@
    xmlns:xlink="http://www.w3.org/1999/xlink";
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
-   width="251.11343"
-   height="85.04348"
+   width="404.02039"
+   height="204.0204"
    id="svg3307"
    sodipodi:version="0.32"
    inkscape:version="0.46"
    version="1.0"
-   sodipodi:docname="back.svg"
+   sodipodi:docname="backing.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape">
   <defs
      id="defs3309">
     <linearGradient
+       id="linearGradient3163">
+      <stop
+         style="stop-color:#515151;stop-opacity:1;"
+         offset="0"
+         id="stop3165" />
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="1"
+         id="stop3167" />
+    </linearGradient>
+    <linearGradient
        id="linearGradient3169">
       <stop
          style="stop-color:#ffffff;stop-opacity:0.024;"
@@ -67,11 +78,21 @@
        xlink:href="#linearGradient3155"
        id="linearGradient2415"
        gradientUnits="userSpaceOnUse"
-       gradientTransform="translate(60.31257,681.79067)"
+       gradientTransform="matrix(0.8770413,0,0,1.0015122,60.372741,681.7264)"
        x1="251.11343"
        y1="85.043472"
        x2="251.11343"
        y2="-9.9403951e-06" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3163"
+       id="linearGradient3170"
+       x1="351.0405"
+       y1="638.59863"
+       x2="351.0405"
+       y2="838.59863"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.1392903,0,0,0.7531363,-19.604093,156.03603)" />
   </defs>
   <sodipodi:namedview
      id="base"
@@ -83,9 +104,9 @@
      objecttolerance="10"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="1.3330629"
-     inkscape:cx="125"
-     inkscape:cy="41.943272"
+     inkscape:zoom="2.0914786"
+     inkscape:cx="36.744844"
+     inkscape:cy="44.634521"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="false"
@@ -108,10 +129,13 @@
      inkscape:label="Layer 1"
      inkscape:groupmode="layer"
      id="layer1"
-     transform="translate(-60.31257,-681.79066)">
-    <path
-       style="fill:url(#linearGradient2415);fill-opacity:1;stroke:#5d5d5d;stroke-width:1.99999988000000006;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
-       d="M 70.1782,682.79066 L 301.56038,682.79066 C 306.47194,682.79066 310.42601,686.65876 310.42601,691.46355 L 310.42601,757.16125 C 310.42601,761.96603 306.47194,765.83414 301.56038,765.83414 L 70.1782,765.83414 C 65.266641,765.83414 61.31257,761.96603 61.31257,757.16125 L 61.31257,691.46355 C 61.31257,686.65876 65.266641,682.79066 70.1782,682.79066 z"
-       id="rect2540" />
+     transform="translate(50.969685,-636.58844)">
+    <rect
+       style="fill:url(#linearGradient3170);fill-opacity:1;fill-rule:evenodd;stroke:#9a9a9a;stroke-width:1.84583461;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect2389"
+       width="454.60007"
+       height="149.88948"
+       x="-74.825134"
+       y="637.35669" />
   </g>
 </svg>
diff --git a/lightsoff/lcd-back.svg b/lightsoff/themes/tango/led-back.svg
similarity index 83%
copy from lightsoff/lcd-back.svg
copy to lightsoff/themes/tango/led-back.svg
index dd03b54..efcb0a8 100644
--- a/lightsoff/lcd-back.svg
+++ b/lightsoff/themes/tango/led-back.svg
@@ -9,13 +9,13 @@
    xmlns:xlink="http://www.w3.org/1999/xlink";
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
-   width="251.11343"
-   height="85.04348"
+   width="220.35721"
+   height="85.043488"
    id="svg3307"
    sodipodi:version="0.32"
    inkscape:version="0.46"
    version="1.0"
-   sodipodi:docname="back.svg"
+   sodipodi:docname="led-back.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape">
   <defs
      id="defs3309">
@@ -67,7 +67,7 @@
        xlink:href="#linearGradient3155"
        id="linearGradient2415"
        gradientUnits="userSpaceOnUse"
-       gradientTransform="translate(60.31257,681.79067)"
+       gradientTransform="matrix(0.8770413,0,0,1.0015122,60.372741,681.7264)"
        x1="251.11343"
        y1="85.043472"
        x2="251.11343"
@@ -110,8 +110,8 @@
      id="layer1"
      transform="translate(-60.31257,-681.79066)">
     <path
-       style="fill:url(#linearGradient2415);fill-opacity:1;stroke:#5d5d5d;stroke-width:1.99999988000000006;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
-       d="M 70.1782,682.79066 L 301.56038,682.79066 C 306.47194,682.79066 310.42601,686.65876 310.42601,691.46355 L 310.42601,757.16125 C 310.42601,761.96603 306.47194,765.83414 301.56038,765.83414 L 70.1782,765.83414 C 65.266641,765.83414 61.31257,761.96603 61.31257,757.16125 L 61.31257,691.46355 C 61.31257,686.65876 65.266641,682.79066 70.1782,682.79066 z"
+       style="fill:url(#linearGradient2415);fill-opacity:1;stroke:#5d5d5d;stroke-width:1.87442517;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 69.025306,682.72787 L 271.95704,682.72787 C 276.26468,682.72787 279.73256,686.60182 279.73256,691.41388 L 279.73256,757.21092 C 279.73256,762.02297 276.26468,765.89693 271.95704,765.89693 L 69.025306,765.89693 C 64.717666,765.89693 61.249783,762.02297 61.249783,757.21092 L 61.249783,691.41388 C 61.249783,686.60182 64.717666,682.72787 69.025306,682.72787 z"
        id="rect2540" />
   </g>
 </svg>
diff --git a/lightsoff/lcd-front.svg b/lightsoff/themes/tango/led-front.svg
similarity index 86%
copy from lightsoff/lcd-front.svg
copy to lightsoff/themes/tango/led-front.svg
index 74f70a6..9fbddcc 100644
--- a/lightsoff/lcd-front.svg
+++ b/lightsoff/themes/tango/led-front.svg
@@ -9,13 +9,13 @@
    xmlns:xlink="http://www.w3.org/1999/xlink";
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
-   width="250.37199"
-   height="48.383003"
+   width="219.58447"
+   height="44.222527"
    id="svg3343"
    sodipodi:version="0.32"
    inkscape:version="0.46"
    version="1.0"
-   sodipodi:docname="front.svg"
+   sodipodi:docname="led-front.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape">
   <defs
      id="defs3345">
@@ -24,7 +24,7 @@
        xlink:href="#linearGradient3169"
        id="linearGradient2412"
        gradientUnits="userSpaceOnUse"
-       gradientTransform="translate(112.31402,469.99832)"
+       gradientTransform="matrix(0.8770329,0,0,0.9140096,112.31402,469.99832)"
        x1="245.37199"
        y1="48.383003"
        x2="245.37199"
@@ -36,7 +36,7 @@
          offset="0"
          id="stop3171" />
       <stop
-         style="stop-color:#ffffff;stop-opacity:0.42399999;"
+         style="stop-color:#ffffff;stop-opacity:0.35833332;"
          offset="1"
          id="stop3173" />
     </linearGradient>
@@ -69,7 +69,7 @@
      inkscape:pageopacity="1"
      inkscape:pageshadow="2"
      inkscape:zoom="1.2017858"
-     inkscape:cx="203.23922"
+     inkscape:cx="58.870731"
      inkscape:cy="51.468405"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
@@ -103,7 +103,7 @@
      transform="translate(-112.31402,-469.99832)">
     <path
        style="fill:url(#linearGradient2412);fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
-       d="M 121.22444,469.99832 L 353.77562,469.99832 C 358.71201,469.99832 362.68602,473.74996 362.68602,478.41002 L 362.68602,502.98709 C 339.04606,519.09441 116.48074,527.50468 112.31402,502.98709 L 112.31402,478.41002 C 112.31402,473.74996 116.28808,469.99832 121.22444,469.99832 z"
+       d="M 120.12875,469.99832 L 324.08379,469.99832 C 328.41317,469.99832 331.8985,473.42735 331.8985,477.68669 L 331.8985,500.15037 C 311.16548,514.87262 115.96837,522.55968 112.31402,500.15037 L 112.31402,477.68669 C 112.31402,473.42735 115.7994,469.99832 120.12875,469.99832 z"
        id="path2532"
        sodipodi:nodetypes="ccccccc"
        inkscape:export-filename="/home/hortont/seed/examples/lightsoff/bkg_top.png"
diff --git a/lightsoff/arrow.svg b/lightsoff/themes/tango/off.svg
similarity index 50%
copy from lightsoff/arrow.svg
copy to lightsoff/themes/tango/off.svg
index 41afa34..1da3049 100644
--- a/lightsoff/arrow.svg
+++ b/lightsoff/themes/tango/off.svg
@@ -6,57 +6,29 @@
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
    xmlns:svg="http://www.w3.org/2000/svg";
    xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
-   width="49.999996"
-   height="49.999996"
+   width="75"
+   height="75"
    id="svg2"
    sodipodi:version="0.32"
    inkscape:version="0.46"
-   sodipodi:docname="arrow-l.svg"
+   sodipodi:docname="grey.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape"
-   inkscape:export-filename="/Users/hortont/Desktop/drawingON.png"
-   inkscape:export-xdpi="90"
-   inkscape:export-ydpi="90"
    version="1.0">
   <defs
      id="defs4">
     <linearGradient
-       id="linearGradient3537">
+       id="linearGradient3179">
       <stop
-         id="stop3539"
+         style="stop-color:#0c0c0c;stop-opacity:0.96078432;"
          offset="0"
-         style="stop-color:#ffffff;stop-opacity:1;" />
+         id="stop3181" />
       <stop
-         id="stop3541"
+         style="stop-color:#222222;stop-opacity:0.96078432;"
          offset="1"
-         style="stop-color:#ffffff;stop-opacity:0;" />
-    </linearGradient>
-    <linearGradient
-       id="linearGradient3486">
-      <stop
-         id="stop3488"
-         offset="0"
-         style="stop-color:#000000;stop-opacity:1;" />
-      <stop
-         id="stop3492"
-         offset="1"
-         style="stop-color:#000000;stop-opacity:0;" />
-    </linearGradient>
-    <linearGradient
-       id="linearGradient3444">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop3446" />
-      <stop
-         id="stop3452"
-         offset="0.5"
-         style="stop-color:#ffffff;stop-opacity:0;" />
-      <stop
-         style="stop-color:#ffffff;stop-opacity:0;"
-         offset="1"
-         id="stop3448" />
+         id="stop3183" />
     </linearGradient>
     <inkscape:perspective
        sodipodi:type="inkscape:persp3d"
@@ -65,25 +37,35 @@
        inkscape:vp_z="744.09448 : 526.18109 : 1"
        inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
        id="perspective10" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3179"
+       id="linearGradient3193"
+       x1="164.71428"
+       y1="344.79077"
+       x2="315.28571"
+       y2="344.79077"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.4848198,0,0,0.4848197,85.857573,101.05795)" />
   </defs>
   <sodipodi:namedview
      id="base"
-     pagecolor="#000000"
+     pagecolor="#ffffff"
      bordercolor="#666666"
      borderopacity="1.0"
      gridtolerance="10000"
      guidetolerance="10"
      objecttolerance="10"
-     inkscape:pageopacity="0"
+     inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="11.760001"
-     inkscape:cx="24.999998"
-     inkscape:cy="24.999998"
+     inkscape:zoom="10.026667"
+     inkscape:cx="24.983378"
+     inkscape:cy="37.5"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="false"
-     inkscape:window-width="1432"
-     inkscape:window-height="817"
+     inkscape:window-width="1440"
+     inkscape:window-height="842"
      inkscape:window-x="0"
      inkscape:window-y="0" />
   <metadata
@@ -101,10 +83,15 @@
      inkscape:label="Layer 1"
      inkscape:groupmode="layer"
      id="layer1"
-     transform="translate(-353.37656,-318.61163)">
-    <path
-       style="opacity:0.5;fill:#f5f5f5;fill-opacity:0.5098038;stroke:#f5f5f5;stroke-width:2.18480301;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.90196078"
-       d="M 372.51146,327.46981 L 372.51146,336.1791 L 401.09405,336.1791 L 401.09405,351.04416 L 372.51146,351.04416 L 372.51146,359.75345 L 355.65907,343.61163 L 372.51146,327.46981 z"
-       id="rect3273" />
+     transform="translate(-164.71428,-194.21933)">
+    <rect
+       style="opacity:1;fill:url(#linearGradient3193);fill-opacity:1;stroke:#666666;stroke-width:0.96963954;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3157"
+       width="72.030357"
+       height="72.030357"
+       x="166.1991"
+       y="195.70415"
+       rx="4.8481979"
+       ry="4.8481975" />
   </g>
 </svg>
diff --git a/lightsoff/arrow.svg b/lightsoff/themes/tango/on.svg
similarity index 50%
rename from lightsoff/arrow.svg
rename to lightsoff/themes/tango/on.svg
index 41afa34..a7723a4 100644
--- a/lightsoff/arrow.svg
+++ b/lightsoff/themes/tango/on.svg
@@ -6,57 +6,29 @@
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
    xmlns:svg="http://www.w3.org/2000/svg";
    xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
-   width="49.999996"
-   height="49.999996"
+   width="75"
+   height="75"
    id="svg2"
    sodipodi:version="0.32"
    inkscape:version="0.46"
-   sodipodi:docname="arrow-l.svg"
+   sodipodi:docname="blue.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape"
-   inkscape:export-filename="/Users/hortont/Desktop/drawingON.png"
-   inkscape:export-xdpi="90"
-   inkscape:export-ydpi="90"
    version="1.0">
   <defs
      id="defs4">
     <linearGradient
-       id="linearGradient3537">
+       id="linearGradient3179">
       <stop
-         id="stop3539"
+         style="stop-color:#35669b;stop-opacity:0.96078432;"
          offset="0"
-         style="stop-color:#ffffff;stop-opacity:1;" />
+         id="stop3181" />
       <stop
-         id="stop3541"
+         style="stop-color:#5e92c8;stop-opacity:0.96078432;"
          offset="1"
-         style="stop-color:#ffffff;stop-opacity:0;" />
-    </linearGradient>
-    <linearGradient
-       id="linearGradient3486">
-      <stop
-         id="stop3488"
-         offset="0"
-         style="stop-color:#000000;stop-opacity:1;" />
-      <stop
-         id="stop3492"
-         offset="1"
-         style="stop-color:#000000;stop-opacity:0;" />
-    </linearGradient>
-    <linearGradient
-       id="linearGradient3444">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:1;"
-         offset="0"
-         id="stop3446" />
-      <stop
-         id="stop3452"
-         offset="0.5"
-         style="stop-color:#ffffff;stop-opacity:0;" />
-      <stop
-         style="stop-color:#ffffff;stop-opacity:0;"
-         offset="1"
-         id="stop3448" />
+         id="stop3183" />
     </linearGradient>
     <inkscape:perspective
        sodipodi:type="inkscape:persp3d"
@@ -65,25 +37,35 @@
        inkscape:vp_z="744.09448 : 526.18109 : 1"
        inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
        id="perspective10" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3179"
+       id="linearGradient3193"
+       x1="164.71428"
+       y1="344.79077"
+       x2="315.28571"
+       y2="344.79077"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.4848198,0,0,0.4848197,85.857573,101.05795)" />
   </defs>
   <sodipodi:namedview
      id="base"
-     pagecolor="#000000"
+     pagecolor="#ffffff"
      bordercolor="#666666"
      borderopacity="1.0"
      gridtolerance="10000"
      guidetolerance="10"
      objecttolerance="10"
-     inkscape:pageopacity="0"
+     inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="11.760001"
-     inkscape:cx="24.999998"
-     inkscape:cy="24.999998"
+     inkscape:zoom="4.0711576"
+     inkscape:cx="13.632487"
+     inkscape:cy="80.411519"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="false"
-     inkscape:window-width="1432"
-     inkscape:window-height="817"
+     inkscape:window-width="1440"
+     inkscape:window-height="842"
      inkscape:window-x="0"
      inkscape:window-y="0" />
   <metadata
@@ -101,10 +83,15 @@
      inkscape:label="Layer 1"
      inkscape:groupmode="layer"
      id="layer1"
-     transform="translate(-353.37656,-318.61163)">
-    <path
-       style="opacity:0.5;fill:#f5f5f5;fill-opacity:0.5098038;stroke:#f5f5f5;stroke-width:2.18480301;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.90196078"
-       d="M 372.51146,327.46981 L 372.51146,336.1791 L 401.09405,336.1791 L 401.09405,351.04416 L 372.51146,351.04416 L 372.51146,359.75345 L 355.65907,343.61163 L 372.51146,327.46981 z"
-       id="rect3273" />
+     transform="translate(-164.71428,-194.21933)">
+    <rect
+       style="opacity:1;fill:url(#linearGradient3193);fill-opacity:1;stroke:#729fcf;stroke-width:0.96963954;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3157"
+       width="72.030357"
+       height="72.030357"
+       x="166.1991"
+       y="195.70415"
+       rx="4.8481979"
+       ry="4.8481975" />
   </g>
 </svg>
diff --git a/lightsoff/themes/tango/theme.js b/lightsoff/themes/tango/theme.js
new file mode 100644
index 0000000..2dd139b
--- /dev/null
+++ b/lightsoff/themes/tango/theme.js
@@ -0,0 +1,23 @@
+file_prefix = '/usr/local' + "/share/gnome-games/lightsoff/";
+
+Clutter = imports.gi.Clutter;
+
+var name = "tango";
+
+var light = [ load_svg("off.svg"), load_svg("on.svg") ];
+var arrow = load_svg("arrow.svg");
+var backing = load_svg("backing.svg");
+var led_back = load_svg("led-back.svg");
+var led_front = load_svg("led-front.svg");
+
+// helper functions should be put somewhere global
+
+function load_svg(file)
+{
+	// TODO: either imports should set the cwd (and this can go away),
+	// or we need some quick way to compose paths. Really, we need that anyway.
+	
+	var tx = new Clutter.Texture({filename: file_prefix + "themes/" + name + "/" + file});
+	tx.filter_quality = Clutter.TextureQuality.HIGH;
+	return tx;
+}
diff --git a/lightsoff/themes/tango/theme.js.in b/lightsoff/themes/tango/theme.js.in
new file mode 100644
index 0000000..2dd139b
--- /dev/null
+++ b/lightsoff/themes/tango/theme.js.in
@@ -0,0 +1,23 @@
+file_prefix = '/usr/local' + "/share/gnome-games/lightsoff/";
+
+Clutter = imports.gi.Clutter;
+
+var name = "tango";
+
+var light = [ load_svg("off.svg"), load_svg("on.svg") ];
+var arrow = load_svg("arrow.svg");
+var backing = load_svg("backing.svg");
+var led_back = load_svg("led-back.svg");
+var led_front = load_svg("led-front.svg");
+
+// helper functions should be put somewhere global
+
+function load_svg(file)
+{
+	// TODO: either imports should set the cwd (and this can go away),
+	// or we need some quick way to compose paths. Really, we need that anyway.
+	
+	var tx = new Clutter.Texture({filename: file_prefix + "themes/" + name + "/" + file});
+	tx.filter_quality = Clutter.TextureQuality.HIGH;
+	return tx;
+}
diff --git a/lightsoff/themes/up/Makefile.am b/lightsoff/themes/up/Makefile.am
new file mode 100644
index 0000000..48ae2c2
--- /dev/null
+++ b/lightsoff/themes/up/Makefile.am
@@ -0,0 +1,18 @@
+themedir = $(pkgdatadir)/lightsoff/themes/up
+theme_DATA = \
+	arrow.svg \
+	backing.svg \
+	led-back.svg \
+	led-front.svg \
+	off.svg \
+	on.svg \
+	theme.js
+
+EXTRA_DIST = \
+	arrow.svg \
+	backing.svg \
+	led-back.svg \
+	led-front.svg \
+	off.svg \
+	on.svg \
+	theme.js.in
diff --git a/lightsoff/themes/up/arrow.svg b/lightsoff/themes/up/arrow.svg
new file mode 100644
index 0000000..7fdb4e8
--- /dev/null
+++ b/lightsoff/themes/up/arrow.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="32"
+   height="52"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   version="1.0"
+   sodipodi:docname="arrow.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs4">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#000000"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="10.162162"
+     inkscape:cx="13.809616"
+     inkscape:cy="16.285027"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-346.35856,-494.3177)">
+    <path
+       style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       d="M 375.29882,542.10353 L 372.884,544.62335 L 349.89076,521.36761 C 349.26081,520.6677 349.26081,519.96775 349.89076,519.26778 L 372.884,496.01205 L 375.29882,498.53186 L 353.77546,520.26521 L 375.29882,542.10353"
+       id="text2388" />
+  </g>
+</svg>
diff --git a/lightsoff/lcd-back.svg b/lightsoff/themes/up/backing.svg
similarity index 71%
copy from lightsoff/lcd-back.svg
copy to lightsoff/themes/up/backing.svg
index dd03b54..31502ba 100644
--- a/lightsoff/lcd-back.svg
+++ b/lightsoff/themes/up/backing.svg
@@ -9,17 +9,28 @@
    xmlns:xlink="http://www.w3.org/1999/xlink";
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
-   width="251.11343"
-   height="85.04348"
+   width="404.02039"
+   height="204.0204"
    id="svg3307"
    sodipodi:version="0.32"
    inkscape:version="0.46"
    version="1.0"
-   sodipodi:docname="back.svg"
+   sodipodi:docname="backing.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape">
   <defs
      id="defs3309">
     <linearGradient
+       id="linearGradient3163">
+      <stop
+         style="stop-color:#515151;stop-opacity:1;"
+         offset="0"
+         id="stop3165" />
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="1"
+         id="stop3167" />
+    </linearGradient>
+    <linearGradient
        id="linearGradient3169">
       <stop
          style="stop-color:#ffffff;stop-opacity:0.024;"
@@ -67,11 +78,21 @@
        xlink:href="#linearGradient3155"
        id="linearGradient2415"
        gradientUnits="userSpaceOnUse"
-       gradientTransform="translate(60.31257,681.79067)"
+       gradientTransform="matrix(0.8770413,0,0,1.0015122,60.372741,681.7264)"
        x1="251.11343"
        y1="85.043472"
        x2="251.11343"
        y2="-9.9403951e-06" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3163"
+       id="linearGradient3170"
+       x1="351.0405"
+       y1="638.59863"
+       x2="351.0405"
+       y2="838.59863"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.1392903,0,0,0.7531363,-19.604093,156.03603)" />
   </defs>
   <sodipodi:namedview
      id="base"
@@ -83,9 +104,9 @@
      objecttolerance="10"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="1.3330629"
-     inkscape:cx="125"
-     inkscape:cy="41.943272"
+     inkscape:zoom="2.0914786"
+     inkscape:cx="36.744844"
+     inkscape:cy="44.634521"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="false"
@@ -108,10 +129,13 @@
      inkscape:label="Layer 1"
      inkscape:groupmode="layer"
      id="layer1"
-     transform="translate(-60.31257,-681.79066)">
-    <path
-       style="fill:url(#linearGradient2415);fill-opacity:1;stroke:#5d5d5d;stroke-width:1.99999988000000006;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
-       d="M 70.1782,682.79066 L 301.56038,682.79066 C 306.47194,682.79066 310.42601,686.65876 310.42601,691.46355 L 310.42601,757.16125 C 310.42601,761.96603 306.47194,765.83414 301.56038,765.83414 L 70.1782,765.83414 C 65.266641,765.83414 61.31257,761.96603 61.31257,757.16125 L 61.31257,691.46355 C 61.31257,686.65876 65.266641,682.79066 70.1782,682.79066 z"
-       id="rect2540" />
+     transform="translate(50.969685,-636.58844)">
+    <rect
+       style="fill:url(#linearGradient3170);fill-opacity:1;fill-rule:evenodd;stroke:#9a9a9a;stroke-width:1.84583461;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect2389"
+       width="454.60007"
+       height="149.88948"
+       x="-74.825134"
+       y="637.35669" />
   </g>
 </svg>
diff --git a/lightsoff/lcd-back.svg b/lightsoff/themes/up/led-back.svg
similarity index 83%
rename from lightsoff/lcd-back.svg
rename to lightsoff/themes/up/led-back.svg
index dd03b54..efcb0a8 100644
--- a/lightsoff/lcd-back.svg
+++ b/lightsoff/themes/up/led-back.svg
@@ -9,13 +9,13 @@
    xmlns:xlink="http://www.w3.org/1999/xlink";
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
-   width="251.11343"
-   height="85.04348"
+   width="220.35721"
+   height="85.043488"
    id="svg3307"
    sodipodi:version="0.32"
    inkscape:version="0.46"
    version="1.0"
-   sodipodi:docname="back.svg"
+   sodipodi:docname="led-back.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape">
   <defs
      id="defs3309">
@@ -67,7 +67,7 @@
        xlink:href="#linearGradient3155"
        id="linearGradient2415"
        gradientUnits="userSpaceOnUse"
-       gradientTransform="translate(60.31257,681.79067)"
+       gradientTransform="matrix(0.8770413,0,0,1.0015122,60.372741,681.7264)"
        x1="251.11343"
        y1="85.043472"
        x2="251.11343"
@@ -110,8 +110,8 @@
      id="layer1"
      transform="translate(-60.31257,-681.79066)">
     <path
-       style="fill:url(#linearGradient2415);fill-opacity:1;stroke:#5d5d5d;stroke-width:1.99999988000000006;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
-       d="M 70.1782,682.79066 L 301.56038,682.79066 C 306.47194,682.79066 310.42601,686.65876 310.42601,691.46355 L 310.42601,757.16125 C 310.42601,761.96603 306.47194,765.83414 301.56038,765.83414 L 70.1782,765.83414 C 65.266641,765.83414 61.31257,761.96603 61.31257,757.16125 L 61.31257,691.46355 C 61.31257,686.65876 65.266641,682.79066 70.1782,682.79066 z"
+       style="fill:url(#linearGradient2415);fill-opacity:1;stroke:#5d5d5d;stroke-width:1.87442517;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 69.025306,682.72787 L 271.95704,682.72787 C 276.26468,682.72787 279.73256,686.60182 279.73256,691.41388 L 279.73256,757.21092 C 279.73256,762.02297 276.26468,765.89693 271.95704,765.89693 L 69.025306,765.89693 C 64.717666,765.89693 61.249783,762.02297 61.249783,757.21092 L 61.249783,691.41388 C 61.249783,686.60182 64.717666,682.72787 69.025306,682.72787 z"
        id="rect2540" />
   </g>
 </svg>
diff --git a/lightsoff/lcd-front.svg b/lightsoff/themes/up/led-front.svg
similarity index 86%
rename from lightsoff/lcd-front.svg
rename to lightsoff/themes/up/led-front.svg
index 74f70a6..9fbddcc 100644
--- a/lightsoff/lcd-front.svg
+++ b/lightsoff/themes/up/led-front.svg
@@ -9,13 +9,13 @@
    xmlns:xlink="http://www.w3.org/1999/xlink";
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
-   width="250.37199"
-   height="48.383003"
+   width="219.58447"
+   height="44.222527"
    id="svg3343"
    sodipodi:version="0.32"
    inkscape:version="0.46"
    version="1.0"
-   sodipodi:docname="front.svg"
+   sodipodi:docname="led-front.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape">
   <defs
      id="defs3345">
@@ -24,7 +24,7 @@
        xlink:href="#linearGradient3169"
        id="linearGradient2412"
        gradientUnits="userSpaceOnUse"
-       gradientTransform="translate(112.31402,469.99832)"
+       gradientTransform="matrix(0.8770329,0,0,0.9140096,112.31402,469.99832)"
        x1="245.37199"
        y1="48.383003"
        x2="245.37199"
@@ -36,7 +36,7 @@
          offset="0"
          id="stop3171" />
       <stop
-         style="stop-color:#ffffff;stop-opacity:0.42399999;"
+         style="stop-color:#ffffff;stop-opacity:0.35833332;"
          offset="1"
          id="stop3173" />
     </linearGradient>
@@ -69,7 +69,7 @@
      inkscape:pageopacity="1"
      inkscape:pageshadow="2"
      inkscape:zoom="1.2017858"
-     inkscape:cx="203.23922"
+     inkscape:cx="58.870731"
      inkscape:cy="51.468405"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
@@ -103,7 +103,7 @@
      transform="translate(-112.31402,-469.99832)">
     <path
        style="fill:url(#linearGradient2412);fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
-       d="M 121.22444,469.99832 L 353.77562,469.99832 C 358.71201,469.99832 362.68602,473.74996 362.68602,478.41002 L 362.68602,502.98709 C 339.04606,519.09441 116.48074,527.50468 112.31402,502.98709 L 112.31402,478.41002 C 112.31402,473.74996 116.28808,469.99832 121.22444,469.99832 z"
+       d="M 120.12875,469.99832 L 324.08379,469.99832 C 328.41317,469.99832 331.8985,473.42735 331.8985,477.68669 L 331.8985,500.15037 C 311.16548,514.87262 115.96837,522.55968 112.31402,500.15037 L 112.31402,477.68669 C 112.31402,473.42735 115.7994,469.99832 120.12875,469.99832 z"
        id="path2532"
        sodipodi:nodetypes="ccccccc"
        inkscape:export-filename="/home/hortont/seed/examples/lightsoff/bkg_top.png"
diff --git a/lightsoff/themes/up/off.svg b/lightsoff/themes/up/off.svg
new file mode 100644
index 0000000..3cdd8a2
--- /dev/null
+++ b/lightsoff/themes/up/off.svg
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="75"
+   height="75"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="grey.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient10190">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0"
+         id="stop10192" />
+      <stop
+         style="stop-color:#5b8fc7;stop-opacity:0;"
+         offset="1"
+         id="stop10194" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient10182">
+      <stop
+         style="stop-color:#2e3436;stop-opacity:1"
+         offset="0"
+         id="stop10184" />
+      <stop
+         style="stop-color:#555753;stop-opacity:1"
+         offset="1"
+         id="stop10186" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient10146">
+      <stop
+         id="stop10148"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:0.11489362" />
+      <stop
+         id="stop10152"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10182"
+       id="linearGradient10142"
+       x1="178.71428"
+       y1="199.21933"
+       x2="218.71428"
+       y2="267.21933"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10190"
+       id="linearGradient10207"
+       x1="188.71428"
+       y1="233.21933"
+       x2="204.71428"
+       y2="185.21933"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0142532,0,0,1.0147091,-2.882195,-3.3928733)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10146"
+       id="linearGradient10217"
+       x1="229.46428"
+       y1="279.46933"
+       x2="164.96428"
+       y2="185.21933"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4"
+     inkscape:cx="-14.74225"
+     inkscape:cy="37.898498"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1440"
+     inkscape:window-height="842"
+     inkscape:window-x="0"
+     inkscape:window-y="179">
+    <inkscape:grid
+       type="xygrid"
+       id="grid9326" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Ulisse Perusin &lt;ulisail yahoo it&gt;</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:title>Grey Tile</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-164.71428,-194.21933)">
+    <rect
+       ry="4.8481975"
+       rx="4.8481979"
+       y="195.70415"
+       x="166.1991"
+       height="72.030357"
+       width="72.030357"
+       id="rect10098"
+       style="opacity:1;fill:url(#linearGradient10142);fill-opacity:1;stroke:none;stroke-width:0.96963953999999997;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       style="opacity:0.12;fill:url(#linearGradient10207);fill-opacity:1;stroke:none;stroke-width:0.96963953999999997;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 172.63158,197.21933 L 231.79698,197.21933 C 234.52117,197.21933 236.71428,199.41343 236.71428,202.13884 L 236.71428,212.62481 C 232.67057,229.56208 171.75877,229.27231 167.71428,212.62481 L 167.71428,202.13884 C 167.71428,199.41343 169.90739,197.21933 172.63158,197.21933 z"
+       id="rect10198"
+       sodipodi:nodetypes="ccccccc" />
+    <rect
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#2e3436;stroke-width:0.96963953999999997;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3157"
+       width="72.030357"
+       height="72.030357"
+       x="166.1991"
+       y="195.70415"
+       rx="4.8481979"
+       ry="4.8481975" />
+    <rect
+       ry="4.7135825"
+       rx="4.713583"
+       y="196.70415"
+       x="167.1991"
+       height="70.030365"
+       width="70.030365"
+       id="rect10209"
+       style="opacity:0.3;fill:none;fill-opacity:1;stroke:url(#linearGradient10217);stroke-width:0.96963960000000005;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  </g>
+</svg>
diff --git a/lightsoff/themes/up/on.svg b/lightsoff/themes/up/on.svg
new file mode 100644
index 0000000..549518a
--- /dev/null
+++ b/lightsoff/themes/up/on.svg
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="75"
+   height="75"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="blue.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient10190">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0"
+         id="stop10192" />
+      <stop
+         style="stop-color:#5b8fc7;stop-opacity:0;"
+         offset="1"
+         id="stop10194" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient10182">
+      <stop
+         style="stop-color:#204a87;stop-opacity:1"
+         offset="0"
+         id="stop10184" />
+      <stop
+         style="stop-color:#5b8fc7;stop-opacity:1"
+         offset="1"
+         id="stop10186" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient10174">
+      <stop
+         style="stop-color:#6da9ff;stop-opacity:1;"
+         offset="0"
+         id="stop10176" />
+      <stop
+         style="stop-color:#6da9ff;stop-opacity:0;"
+         offset="1"
+         id="stop10178" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient10146">
+      <stop
+         id="stop10148"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:0.11489362" />
+      <stop
+         id="stop10152"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10182"
+       id="linearGradient10142"
+       x1="178.71428"
+       y1="199.21933"
+       x2="218.71428"
+       y2="267.21933"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10174"
+       id="radialGradient10180"
+       cx="202.71428"
+       cy="231.21933"
+       fx="202.09354"
+       fy="251.56584"
+       r="36.015179"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2605304,-1.7746105e-2,1.3882838e-2,0.9861173,-56.023225,6.807352)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10190"
+       id="linearGradient10207"
+       x1="188.71428"
+       y1="233.21933"
+       x2="204.71428"
+       y2="185.21933"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0142532,0,0,1.0147091,-2.882195,-3.3928733)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient10146"
+       id="linearGradient10217"
+       x1="229.46428"
+       y1="279.46933"
+       x2="164.96428"
+       y2="185.21933"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4"
+     inkscape:cx="-14.74225"
+     inkscape:cy="37.898498"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1440"
+     inkscape:window-height="842"
+     inkscape:window-x="0"
+     inkscape:window-y="24">
+    <inkscape:grid
+       type="xygrid"
+       id="grid9326" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <cc:license
+           rdf:resource="" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Ulisse Perusin &lt;ulisail yahoo it&gt;</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:title>Blue Tile</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-164.71428,-194.21933)">
+    <rect
+       ry="4.8481975"
+       rx="4.8481979"
+       y="195.70415"
+       x="166.1991"
+       height="72.030357"
+       width="72.030357"
+       id="rect10098"
+       style="opacity:1;fill:url(#linearGradient10142);fill-opacity:1;stroke:none;stroke-width:0.96963953999999997;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <rect
+       style="opacity:0.82978722999999999;fill:url(#radialGradient10180);fill-opacity:1;stroke:none;stroke-width:0.96963953999999997;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect10154"
+       width="72.030357"
+       height="72.030357"
+       x="166.1991"
+       y="195.70415"
+       rx="4.8481979"
+       ry="4.8481975" />
+    <path
+       style="opacity:0.25;fill:url(#linearGradient10207);fill-opacity:1;stroke:none;stroke-width:0.96963954;stroke-miterlimit:4;stroke-opacity:1"
+       d="M 172.63158,197.21933 L 231.79698,197.21933 C 234.52117,197.21933 236.71428,199.41343 236.71428,202.13884 L 236.71428,212.62481 C 232.67057,229.56208 171.75877,229.27231 167.71428,212.62481 L 167.71428,202.13884 C 167.71428,199.41343 169.90739,197.21933 172.63158,197.21933 z"
+       id="rect10198"
+       sodipodi:nodetypes="ccccccc" />
+    <rect
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#204a87;stroke-width:0.96963953999999997;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3157"
+       width="72.030357"
+       height="72.030357"
+       x="166.1991"
+       y="195.70415"
+       rx="4.8481979"
+       ry="4.8481975" />
+    <rect
+       ry="4.7135825"
+       rx="4.713583"
+       y="196.70415"
+       x="167.1991"
+       height="70.030365"
+       width="70.030365"
+       id="rect10209"
+       style="opacity:0.3;fill:none;fill-opacity:1;stroke:url(#linearGradient10217);stroke-width:0.96963960000000005;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  </g>
+</svg>
diff --git a/lightsoff/themes/up/theme.js.in b/lightsoff/themes/up/theme.js.in
new file mode 100644
index 0000000..d895bd3
--- /dev/null
+++ b/lightsoff/themes/up/theme.js.in
@@ -0,0 +1,23 @@
+file_prefix = '/usr/local' + "/share/gnome-games/lightsoff/";
+
+Clutter = imports.gi.Clutter;
+
+var name = "up";
+
+var light = [ load_svg("off.svg"), load_svg("on.svg") ];
+var arrow = load_svg("arrow.svg");
+var backing = load_svg("backing.svg");
+var led_back = load_svg("led-back.svg");
+var led_front = load_svg("led-front.svg");
+
+// helper functions should be put somewhere global
+
+function load_svg(file)
+{
+	// TODO: either imports should set the cwd (and this can go away),
+	// or we need some quick way to compose paths. Really, we need that anyway.
+	
+	var tx = new Clutter.Texture({filename: file_prefix + "themes/" + name + "/" + file});
+	tx.filter_quality = Clutter.TextureQuality.HIGH;
+	return tx;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]