[ease/themes: 125/125] [themes] Started new themes system.



commit a8621726f060bacd7ab104a832f08a702868efed
Author: Nate Stedman <natesm gmail com>
Date:   Wed Jul 21 13:23:24 2010 -0400

    [themes] Started new themes system.

 data/Makefile.am          |    8 +-
 data/theme-defaults.json  |   27 ++++
 src/ease-json-parser.vala |   34 -----
 src/ease-slide.vala       |   11 ++
 src/ease-theme.vala       |  334 ++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 376 insertions(+), 38 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index a76ec48..ba8b5f5 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -10,5 +10,11 @@ svg_DATA = $(wildcard $(top_srcdir)/data/svg/*.svg)
 uidir = $(datadir)/ease/ui
 ui_DATA = $(wildcard $(top_srcdir)/data/ui/*.ui)
 
-EXTRA_DIST = $(ui_DATA) $(svg_DATA) $(desktop_in_files)
+jsondir = $(datadir)/ease
+json_DATA = theme-defaults.json
 
+EXTRA_DIST = \
+    $(ui_DATA) \
+    $(svg_DATA) \
+    $(desktop_in_files) \
+    $(json_DATA)
diff --git a/data/theme-defaults.json b/data/theme-defaults.json
new file mode 100644
index 0000000..7c9cdd8
--- /dev/null
+++ b/data/theme-defaults.json
@@ -0,0 +1,27 @@
+{
+	"master-defaults" : {
+		"background-color" : "#FFFFFFFF"
+	},
+	
+	"text-defaults" : {
+		"text-font" : "Bitstream Vera Sans",
+		"text-size" : "12",
+		"padding-top" : "10",
+		"padding-left" : "10",
+		"padding-right" : "10",
+		"padding-bottom" : "10"
+	}
+	
+	"elements" : [
+		"header-text" : {
+			"height" : "30",
+			"text-size" : "24"
+		},
+		
+		"author-text" : {
+			"padding-top" : "0",
+			"height" : "20",
+			"text-size" : "18"
+		}
+	]
+}
diff --git a/src/ease-json-parser.vala b/src/ease-json-parser.vala
index d3b262d..14fb45a 100644
--- a/src/ease-json-parser.vala
+++ b/src/ease-json-parser.vala
@@ -60,40 +60,6 @@ public static class Ease.JSONParser
 		return document;
 	}
 	
-	/**
-	 * Parses a theme JSON file, creating a { link Theme}.
-	 *
-	 * @param path The path to the { link Theme}
-	 */
-	public static Theme theme(string path) throws GLib.Error
-	{
-		string filename = absolute_path(path);
-		var theme = new Theme();
-		theme.path = Temp.extract(filename);
-	
-		var parser = new Json.Parser();
-		
-		// attempt to load the file
-		parser.load_from_file(Path.build_filename(theme.path, "Theme.json"));
-		
-		// grab the root object
-		var root = parser.get_root().get_object();
-		
-		// set theme properties
-		theme.title = root.get_string_member("title");
-		
-		// add all slides
-		var slides = root.get_array_member("slides");
-		
-		for (var i = 0; i < slides.get_length(); i++)
-		{
-			var node = slides.get_object_element(i);
-			theme.add_slide(theme.length, parse_slide(node));
-		}
-		
-		return theme;
-	}
-	
 	private static Slide parse_slide(Json.Object obj)
 	{
 		var slide = new Slide();
diff --git a/src/ease-slide.vala b/src/ease-slide.vala
index 469a98a..7f236d4 100644
--- a/src/ease-slide.vala
+++ b/src/ease-slide.vala
@@ -217,6 +217,17 @@ public class Ease.Slide : GLib.Object
 	}
 	
 	/**
+	 * Adds an { link Element} to this slide at the end index.
+	 * 
+	 * @param e The element to add;.
+	 */
+	public void add(Element e)
+	{
+		e.parent = this;
+		elements.insert(count - 1, e);
+	}
+	
+	/**
 	 * Creates HTML markup for this Slide.
 	 * 
 	 * The <div> tag for this Slide is appended to the "HTML" parameter.
diff --git a/src/ease-theme.vala b/src/ease-theme.vala
index ad3f891..ecdc6a7 100644
--- a/src/ease-theme.vala
+++ b/src/ease-theme.vala
@@ -16,18 +16,346 @@
 */
 
 /**
- * Internal representation of Ease themes
+ * Internal representation of Ease themes.
  */
-public class Ease.Theme : SlideSet
+public class Ease.Theme : GLib.Object
 {
+	// json file
+	private const string DEFAULTS_PATH = "theme-defaults.json";
+	private const string MASTERS = "masters";
+	private const string ELEMENTS = "elements";
+	private const string MASTER_DEF = "master-defaults";
+	private const string ELEMENT_DEF = "element-defaults";
+	
+	// master slides
+	public const string TITLE = "title";
+	public const string CONTENT = "content";
+	public const string CONTENT_HEADER = "content-header";
+	public const string CONTENT_DUAL = "content-dual";
+	public const string CONTENT_DUAL_HEADER = "content-dual-header";
+	public const string MEDIA = "media";
+	public const string MEDIA_HEADER = "media-header";
+	
+	// text content types
+	private const string TITLE_TEXT = "title-text";
+	private const string AUTHOR_TEXT = "author-text";
+	private const string CONTENT_TEXT = "content-text";
+	private const string HEADER_TEXT = "header-text";
+	
+	// text properties
+	private const string TEXT_FONT = "text-font";
+	private const string TEXT_SIZE = "text-size";
+	
+	// media content types
+	public const string CONTENT_MEDIA = "content-media";
+	
+	// generic element properties
+	public const string PAD_LEFT = "padding-left";
+	public const string PAD_RIGHT = "padding-right";
+	public const string PAD_TOP = "padding-top";
+	public const string PAD_BOTTOM = "padding-bottom";
+	public const string WIDTH = "width";
+	public const string HEIGHT = "height";
+	
 	/**
 	 * The title of the Theme.
 	 */
 	public string title { get; set; }
+	
+	/**
+	 * A map of internal master slide settings overriden by the theme.
+	 */
+	private Gee.Map<string, Gee.Map<string, string>> masters;
+	
+	/**
+	 * A map of internal element settings overriden by the theme.
+	 */
+	private Gee.Map<string, Gee.Map<string, string>> elements;
+	
+	/**
+	 * A map of master slide settings, used as a fallback for all masters when
+	 * the specified master does not provide the given property.
+	 *
+	 * For example, the background properties are typically the same
+	 * throughout the theme. This is an efficient place for those properties.
+	 */
+	private Gee.Map<string, string> master_defaults;
+	
+	/**
+	 * A map of element settings, used as a fallback for all elements when
+	 * the specified element does not provide the given property.
+	 *
+	 * For example, the text-font property is often the same throughout the
+	 * theme. This is an efficient place for properties like that.
+	 */
+	private Gee.Map<string, string> element_defaults;
+	
+	/**
+	 * A Theme containing default values for elements and master slides.
+	 */
+	private static Theme defaults
+	{
+		get
+		{
+			if (defaults_store != null) return defaults_store;
+			return defaults_store = new Theme(data_path(DEFAULTS_PATH));
+		}
+	}
+	
+	/**
+	 * Storage for "defaults" property.
+	 */
+	private static Theme defaults_store;
 
 	/**
 	 * Creates an empty Theme.
+	 *
+	 * @param path The path to the theme's JSON file.
 	 */
-	public Theme() { }
+	public Theme(string path)
+	{
+		// create collections
+		masters = new Gee.HashMap<string, Gee.Map<string, string>>();
+		elements = new Gee.HashMap<string, Gee.Map<string, string>>();
+		master_defaults = new Gee.HashMap<string, string>();
+		element_defaults = new Gee.HashMap<string, string>();
+		
+		var parser = new Json.Parser();
+		try { parser.load_from_file(path); }
+		catch (GLib.Error e)
+		{
+			if (path == DEFAULTS_PATH)
+			{
+				error(_("Could not load theme defaults: %s"), e.message);
+			}
+			else
+			{
+				error_dialog(_("Error Loading Theme"),
+				             (_("Error loading theme: %s\n\n") + e.message).
+				             printf(path));
+			}
+		}
+		
+		
+		// get the document's root element
+		var root = parser.get_root().get_object();
+		
+		// find all masters and element overrides
+		fill_map(root, MASTERS, masters);
+		fill_map(root, ELEMENTS, elements);
+		fill_single_map(root.get_object_member(MASTER_DEF), master_defaults);
+		fill_single_map(root.get_object_member(ELEMENT_DEF), element_defaults);
+	}
+	
+	public Slide? create_slide(string master, int width, int height)
+	{
+		Slide slide = new Slide();
+		
+		switch (master)
+		{
+			case TITLE:
+				// create the presentation's title
+				int left = element_get(TITLE_TEXT, PAD_LEFT).to_int(),
+				    h = element_get(TITLE_TEXT, HEIGHT).to_int();
+				slide.add(create_text(
+					TITLE_TEXT,
+					left,
+					height / 2 - h - element_get(TITLE_TEXT, PAD_BOTTOM).to_int(),
+					width - left - element_get(TITLE_TEXT, PAD_RIGHT).to_int(),
+					h
+				));
+				
+				// create the presentation's author field
+				left = element_get(AUTHOR_TEXT, PAD_LEFT).to_int();
+				slide.add(create_text(
+					AUTHOR_TEXT,
+					left,
+					height / 2 + element_get(AUTHOR_TEXT, PAD_TOP).to_int(),
+					width - left - element_get(AUTHOR_TEXT, PAD_RIGHT).to_int(),
+					element_get(AUTHOR_TEXT, HEIGHT).to_int()
+				));
+				
+				return slide;
+				
+			case CONTENT:
+				int left = element_get(CONTENT_TEXT, PAD_LEFT).to_int(),
+				    top = element_get(CONTENT_TEXT, PAD_TOP).to_int();
+				
+				slide.add(create_text(
+					CONTENT_TEXT,
+					left,
+					top,
+					width - left - element_get(CONTENT_TEXT, PAD_RIGHT).to_int(),
+					height - top - element_get(HEADER_TEXT, PAD_BOTTOM).to_int()
+				));
+				
+			case CONTENT_HEADER:
+				// create the slide's header
+				int left = element_get(HEADER_TEXT, PAD_LEFT).to_int(),
+				    top = element_get(HEADER_TEXT, PAD_TOP).to_int();
+				
+				slide.add(create_text(
+					HEADER_TEXT,
+					left,
+					top,
+					width - left - element_get(HEADER_TEXT, PAD_RIGHT).to_int(),
+					element_get(HEADER_TEXT, HEIGHT).to_int()
+				));
+				
+				// create the slide's content
+				left = element_get(CONTENT_TEXT, PAD_LEFT).to_int();
+				top += element_get(HEADER_TEXT, HEIGHT).to_int() + 
+				       element_get(CONTENT_TEXT, PAD_TOP).to_int();
+				slide.add(create_text(
+					CONTENT_TEXT,
+					left,
+					top,
+					width - left - element_get(CONTENT_TEXT, PAD_RIGHT).to_int(),
+					height - top - element_get(HEADER_TEXT, PAD_BOTTOM).to_int()
+				));
+				
+				return slide;
+			
+			case CONTENT_DUAL:
+			case CONTENT_DUAL_HEADER:
+			case MEDIA:
+			case MEDIA_HEADER:
+				break;
+		}
+		
+		error(_("Invalid master slide title."));
+	}
+	
+	/**
+	 * Creates a text element, given an element type and dimensions.
+	 */
+	private TextElement create_text(string type, int x, int y, int w, int h)
+	{
+		// error if an improper element type is used
+		if (!(type == TITLE_TEXT || type == AUTHOR_TEXT ||
+		      type == CONTENT_TEXT || type == HEADER_TEXT))
+		{
+			error(_("Not a valid text element type: %s"), type);
+		}
+		
+		// otherwise, construct the text element
+		var text = new TextElement();
+		text.font_name = element_get(TITLE_TEXT, TEXT_FONT);
+		text.font_size = element_get(TITLE_TEXT, TEXT_SIZE).to_int();
+		text.x = x;
+		text.y = y;
+		text.width = w;
+		text.height = h;
+		
+		return text;
+	}
+	
+	/**
+	 * Retrieves an element property.
+	 *
+	 * @param element The element name to search for.
+	 * @param prop The property name to search for.
+	 */
+	private string element_get(string element, string prop)
+	{
+		// try local specifics
+		var str = elements.get(element).get(prop);
+		if (str != null) return str;
+		
+		// try local generics
+		str = element_defaults.get(prop);
+		if (str != null) return str;
+		
+		// use default settings
+		if (defaults == this)
+		{
+			error(_("Could not find property %s on element type %s."),
+			      element, prop);
+		}
+		
+		return defaults.element_get(element, prop);
+	}
+	
+	/**
+	 * Retrieves an master property.
+	 *
+	 * @param master The master name to search for.
+	 * @param prop The property name to search for.
+	 */
+	private string master_get(string master, string prop)
+	{
+		// try local specifics
+		var str = masters.get(master).get(prop);
+		if (str != null) return str;
+		
+		// try local generics
+		str = master_defaults.get(prop);
+		if (str != null) return str;
+		
+		// use default settings
+		if (defaults == this)
+		{
+			error(_("Could not find property %s on master type %s."),
+			      master, prop);
+		}
+		
+		return defaults.master_get(master, prop);
+	}
+	
+	/**
+	 * Fills a Gee.Map with style property overrides in the form of more
+	 * Gee.Maps.
+	 *
+	 * @param obj The root object.
+	 * @param name The name of the JSON array to use.
+	 * @param map The map to fill with submaps.
+	 */
+	private void fill_map(Json.Object obj, string name,
+	                      Gee.Map<string, Gee.Map<string, string>> map)
+	{
+		var array = obj.get_array_member(name);
+		if (array == null) return;
+		
+		for (unowned List<string>* i = obj.get_members();
+		     i != null; i = i->next)
+		{
+			// get the current object (an array)
+			var curr_obj = obj.get_member(i->data).get_object();
+			
+			// create a map for the values
+			var submap = new Gee.HashMap<string, string>();
+		
+			// add each override to the map
+			fill_single_map(curr_obj, submap);
+			
+			// add the map to the map of overrides
+			map.set(i->data, submap);
+		}
+	}
+	
+	/**
+	 * Fill a Gee.Map with key/value pairs.
+	 *
+	 * @param obj The json object to use.
+	 * @param map The map to fill.
+	 */
+	private void fill_single_map(Json.Object obj, Gee.Map<string, string> map)
+	{
+		for (unowned List<string>* j = obj.get_members();
+		     j != null; j = j->next)
+		{
+			map.set(j->data, obj.get_member(j->data).get_string());
+		}
+	}
 }
 
+public enum Ease.Master
+{
+	TITLE,
+	CONTENT,
+	CONTENT_HEADER,
+	CONTENT_DUAL,
+	CONTENT_DUAL_HEADER,
+	MEDIA,
+	MEDIA_HEADER
+}



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