[gbrainy] New games + allow to draw text from xml definitions + fixes



commit 40b05fdaa6d6499381fb6fafe48ddaf1002bbf86
Author: Jordi Mas <jmas softcatala org>
Date:   Sun Jul 4 21:15:05 2010 +0200

    New games + allow to draw text from xml definitions + fixes

 data/Makefile.am                                   |    4 +-
 data/game-graphics/box.svg                         |   59 ++++++
 data/games.xml                                     |   79 ++++++++
 gbrainy.csproj                                     |    5 +-
 src/Clients/Classical/Dialogs/CustomGameDialog.cs  |    2 +-
 .../Classical/Dialogs/PlayerHistoryDialog.cs       |    8 +-
 src/Core/Core.csproj                               |    1 +
 src/Core/Main/GameManager.cs                       |   17 ++-
 src/Core/Main/GameTypes.cs                         |   22 ++-
 src/Core/Main/Xml/CodeEvaluation.cs                |  175 +++++++++++++++++
 src/Core/Main/Xml/GameXml.cs                       |  200 +++++---------------
 src/Core/Main/Xml/GameXmlDefinition.cs             |   51 ++++-
 src/Core/Main/Xml/GameXmlFactory.cs                |   71 ++++++-
 src/Core/Makefile.am                               |    1 +
 src/Core/Views/PlayerHistoryView.cs                |    8 +-
 15 files changed, 515 insertions(+), 188 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index c3b7bd6..2ade944 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -49,7 +49,8 @@ analogies_DATA = \
 	game-graphics/password.svg \
 	game-graphics/tennis.svg \
 	game-graphics/father_son.svg \
-	game-graphics/money.svg 
+	game-graphics/money.svg \
+	game-graphics/box.svg
 	
 
 install-data-local:
@@ -70,6 +71,7 @@ install-data-local:
 	$(INSTALL_DATA) $(srcdir)/game-graphics/tennis.svg $(DESTDIR)$(images)/tennis.svg
 	$(INSTALL_DATA) $(srcdir)/game-graphics/father_son.svg $(DESTDIR)$(images)/father_son.svg
 	$(INSTALL_DATA) $(srcdir)/game-graphics/money.svg $(DESTDIR)$(images)/money.svg
+	$(INSTALL_DATA) $(srcdir)/game-graphics/box.svg $(DESTDIR)$(images)/box.svg
 
 gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
 
diff --git a/data/game-graphics/box.svg b/data/game-graphics/box.svg
new file mode 100644
index 0000000..c614bb2
--- /dev/null
+++ b/data/game-graphics/box.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/";) -->
+
+<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";
+   height="500"
+   id="svg548"
+   inkscape:version="0.47 r22583"
+   sodipodi:docname="box.svg"
+   sodipodi:version="0.32"
+   width="500"
+   version="1.1">
+  <defs
+     id="defs550">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 500 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="500 : 500 : 1"
+       inkscape:persp3d-origin="250 : 333.33333 : 1"
+       id="perspective26" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     inkscape:cx="301.39179"
+     inkscape:cy="203.66957"
+     inkscape:window-height="694"
+     inkscape:window-width="1152"
+     inkscape:window-x="0"
+     inkscape:window-y="52"
+     inkscape:zoom="0.472"
+     showgrid="true"
+     showguides="true"
+     snaptoguides="true"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg548" />
+  <path
+     d="m 84.7922,148.96 c 0.8479,0 239.9618,105.143 239.9618,105.143 L 485.012,111.652 268.791,53.1451 84.7922,148.96 z"
+     id="path554"
+     sodipodi:nodetypes="ccccc"
+     style="fill:#e6e6e6;fill-rule:evenodd;stroke:#000000;stroke-width:9.45112896;stroke-linejoin:round;stroke-dasharray:none"
+     transform="matrix(1,0,0,1.119522,-36.46066,-46.20438)" />
+  <path
+     d="m 49.17954,121.509 c 0,0.9493 1.6958,230.6719 0.8479,229.7225 L 289.9893,488.8756 286.5973,237.3202 49.17954,121.509 z"
+     id="path555"
+     sodipodi:nodetypes="ccccc"
+     style="font-size:12px;fill:#e6e6e6;fill-rule:evenodd;stroke:#000000;stroke-width:10;stroke-linejoin:round;stroke-dasharray:none" />
+  <path
+     d="M 326.45,478.802 323.906,254.103 485.012,111.652 482.468,328.72 326.45,478.802 z"
+     id="path557"
+     style="font-size:12px;fill:#e6e6e6;fill-rule:evenodd;stroke:#000000;stroke-width:9.45112896;stroke-linejoin:round;stroke-dasharray:none"
+     transform="matrix(1,0,0,1.119522,-36.46066,-46.20438)" />
+</svg>
diff --git a/data/games.xml b/data/games.xml
index c26dc8a..0c26526 100644
--- a/data/games.xml
+++ b/data/games.xml
@@ -145,4 +145,83 @@
 			<_rationale>Compound interest is paid on the original amount and on the accumulated past interest.</_rationale>
 		</variant>
 	</game>
+
+	<game>
+		<_name>Simple equations</_name>
+		<type>Calculation</type>
+		<difficulty>All</difficulty>
+
+		<!-- Addition -->
+		<variant>
+			<variables>
+				int num_a = 30 + random.Next (20);
+				int num_b = 60 + random.Next (20);
+				int rslt = num_b - num_a;
+			</variables>
+			<_question>What number plus [num_a] equals [num_b]?</_question>
+			<string _text = "x + [num_a] = [num_b]" x = "0.5" y = "0.4" centered = "yes" size = "big"/>
+			<answer>[rslt]</answer>
+			<_rationale>It is the result of the operation [num_b] - [num_a].</_rationale>
+		</variant>
+
+		<!-- Subtraction -->
+		<variant>
+			<variables>
+				int num_a = 30 + random.Next (20);
+				int num_b = 60 + random.Next (20);
+				int rslt = num_b + num_a;
+			</variables>
+			<_question>What number minus [num_a] equals [num_b]?</_question>
+			<string _text = "x - [num_a] = [num_b]" x = "0.5" y = "0.4" centered = "yes" size = "big"/>
+			<answer>[rslt]</answer>
+			<_rationale>It is the result of the operation [num_a] + [num_b].</_rationale>
+		</variant>
+
+		<!-- Multiplication -->
+		<variant>
+			<variables>
+				int num_a = 3 + random.Next (5);
+				int num_b = (30 + random.Next (20)) * num_a;
+				int rslt = num_b / num_a;
+			</variables>
+			<_question>What number multiplied by [num_a] equals [num_b]?</_question>
+			<string _text = "x * [num_a] = [num_b]" x = "0.5" y = "0.4" centered = "yes" size = "big"/>
+			<answer>[rslt]</answer>
+			<_rationale>It is the result of the operation [num_b] / [num_a].</_rationale>
+		</variant>
+
+		<!-- Division -->
+		<variant>
+			<variables>
+				int num_a = 3 + random.Next (5);
+				int num_b = 3 + random.Next (5); 
+				int rslt = num_a * num_b;
+			</variables>
+			<_question>What number divided by [num_a] equals [num_b]?</_question>
+			<string _text = "x / [num_a] = [num_b]" x = "0.5" y = "0.4" centered = "yes" size = "big"/>
+			<answer>[rslt]</answer>
+			<_rationale>It is the result of the operation [num_a] * [num_b].</_rationale>
+		</variant>
+	</game>
+
+	<game>
+		<_name>Boxes</_name>
+		<type>Logic</type>
+		<difficulty>All</difficulty>
+		<variant>
+			<svg file = "box.svg" x = "0.1" y = "0.1" width = "0.6" height = "0.5"/>
+			<string _text = "Container" x = "0.4" y = "0.62" centered = "yes" />
+			<svg file = "box.svg" x = "0.75" y = "0.2" width = "0.1" height = "0.1"/>
+			<string _text = "Box" x = "0.8" y = "0.32" centered = "yes" />
+			<variables>
+				double z = 4 + random.Next (5);
+				double big_box = 6 * 5 * z;
+				double small_box = 1 * 1 * 0.5;
+				double rslt = big_box / small_box;
+			</variables>
+			<_question>How many boxes measuring 1 x 1 x 0.5 can be packed into a container measuring 6 x 5 x [z]?</_question>
+			<answer>[rslt]</answer>
+			<_rationale>You can pack 6 * 5 boxes multiplied by the depth [z] * 2.</_rationale>
+		</variant>
+	</game>
 </games>
diff --git a/gbrainy.csproj b/gbrainy.csproj
index 277413d..65d72be 100644
--- a/gbrainy.csproj
+++ b/gbrainy.csproj
@@ -85,6 +85,7 @@
     <Compile Include="src\Clients\Classical\Builder\BuilderConnectFunc.cs" />
     <Compile Include="src\Clients\Classical\Defines.cs" />
     <Compile Include="src\Clients\Classical\Dialogs\HigMessageDialog.cs" />
+    <Compile Include="src\Clients\Classical\CommandLine.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
@@ -97,7 +98,9 @@
     </EmbeddedResource>
     <EmbeddedResource Include="src\Clients\Classical\Dialogs\ui\PreferencesDialog.ui" />
     <EmbeddedResource Include="src\Clients\Classical\Dialogs\ui\PlayerHistoryDialog.ui" />
-    <EmbeddedResource Include="src\Clients\Classical\Dialogs\ui\CustomGameDialog.ui" />
+    <EmbeddedResource Include="src\Clients\Classical\Dialogs\ui\CustomGameDialog.ui">
+      <LogicalName>CustomGameDialog.ui</LogicalName>
+    </EmbeddedResource>
     <EmbeddedResource Include="data\app-graphics\allgames-32.png">
       <LogicalName>allgames-32.png</LogicalName>
     </EmbeddedResource>
diff --git a/src/Clients/Classical/Dialogs/CustomGameDialog.cs b/src/Clients/Classical/Dialogs/CustomGameDialog.cs
index 07e8234..78ac383 100644
--- a/src/Clients/Classical/Dialogs/CustomGameDialog.cs
+++ b/src/Clients/Classical/Dialogs/CustomGameDialog.cs
@@ -94,7 +94,7 @@ namespace gbrainy.Clients.Classical
 
 					game = (Game) Activator.CreateInstance (games [i].TypeOf, true);
 					game.Variant = games [i].Variant;
-					type = GameTypesDescription.Get (game.Type);
+					type = GameTypesDescription.GetLocalized(game.Type);
 					games_store.AppendValues (game.Name, type, true, game, i);
 				}
 			}
diff --git a/src/Clients/Classical/Dialogs/PlayerHistoryDialog.cs b/src/Clients/Classical/Dialogs/PlayerHistoryDialog.cs
index 23d862f..a3f52a8 100644
--- a/src/Clients/Classical/Dialogs/PlayerHistoryDialog.cs
+++ b/src/Clients/Classical/Dialogs/PlayerHistoryDialog.cs
@@ -64,10 +64,10 @@ namespace gbrainy.Clients.Classical
 			drawing_area.Visible = true;
 
 	 		checkbutton_total.Label = Catalog.GetString ("Total");
-	 		checkbutton_logic.Label = GameTypesDescription.Get (GameTypes.LogicPuzzle);
-	 		checkbutton_calculation.Label = GameTypesDescription.Get (GameTypes.MathTrainer);
-	 		checkbutton_memory.Label = GameTypesDescription.Get (GameTypes.MemoryTrainer);
-	 		checkbutton_verbal.Label = GameTypesDescription.Get (GameTypes.VerbalAnalogy);
+	 		checkbutton_logic.Label = GameTypesDescription.GetLocalized (GameTypes.LogicPuzzle);
+	 		checkbutton_calculation.Label = GameTypesDescription.GetLocalized (GameTypes.MathTrainer);
+	 		checkbutton_memory.Label = GameTypesDescription.GetLocalized (GameTypes.MemoryTrainer);
+	 		checkbutton_verbal.Label = GameTypesDescription.GetLocalized (GameTypes.VerbalAnalogy);
 
 	 		checkbutton_total.Active = checkbutton_memory.Active = checkbutton_logic.Active = checkbutton_calculation.Active = checkbutton_verbal.Active = true;
 		}
diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
index 2687b60..d7316bf 100644
--- a/src/Core/Core.csproj
+++ b/src/Core/Core.csproj
@@ -94,6 +94,7 @@
     <Compile Include="Libraries\SVGImage.cs" />
     <Compile Include="Libraries\GetText.cs" />
     <Compile Include="Platform\Unix.cs" />
+    <Compile Include="Main\Xml\CodeEvaluation.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
diff --git a/src/Core/Main/GameManager.cs b/src/Core/Main/GameManager.cs
index 984b59f..d39b223 100644
--- a/src/Core/Main/GameManager.cs
+++ b/src/Core/Main/GameManager.cs
@@ -94,7 +94,7 @@ namespace gbrainy.Core.Main
 			cnt_verbal += AddVerbalGamesAndVariations (VerbalAnalogiesInternal);
 
 			// Load defined XML games
-			cnt_logic += LoadXmlGames ();
+			LoadXmlGames ();
 
 			LoadPlugins ();
 
@@ -267,7 +267,7 @@ namespace gbrainy.Core.Main
 		}
 
 		// XML are stored using the Variant as a pointer to the game + the internal variant
-		int LoadXmlGames ()
+		void LoadXmlGames ()
 		{
 			Type type = typeof (GameXml);
 			int cnt = 0;
@@ -278,9 +278,19 @@ namespace gbrainy.Core.Main
 				for (int i = 0; i < game.Variants.Count; i++)
 				{
 					available_games.Add (new GameLocator (type, cnt++, game.Type, false));
+
+					switch (game.Type) {
+					case GameTypes.LogicPuzzle:
+						cnt_logic++;
+						break;
+					case GameTypes.MathTrainer:
+						cnt_calculation++;
+						break;
+					default:
+						break;
+					}
 				}
 			}
-			return cnt;
 		}
 
 		void LoadPlugins ()
@@ -422,7 +432,6 @@ namespace gbrainy.Core.Main
 					break;
 				}
 			}
-
 			enumerator = play_list.GetEnumerator ();
 		}
 
diff --git a/src/Core/Main/GameTypes.cs b/src/Core/Main/GameTypes.cs
index e380771..9216477 100644
--- a/src/Core/Main/GameTypes.cs
+++ b/src/Core/Main/GameTypes.cs
@@ -35,8 +35,8 @@ namespace gbrainy.Core.Main
 	// Since we cannot override ToString in an enum type we use a helper class
 	public static class GameTypesDescription
 	{
-		// Type enum to string representation
-		static public string Get (GameTypes type)
+		// Type enum to string representation (locale sensitive)
+		static public string GetLocalized (GameTypes type)
 		{
 			switch (type) 
 			{
@@ -52,5 +52,23 @@ namespace gbrainy.Core.Main
 					throw new InvalidOperationException ("Unknown game type");
 			}
 		}
+
+		// string (not localized) to enum representation 
+		static public GameTypes FromString (string type)
+		{
+			switch (type)
+			{
+				case "Logic":
+					return GameTypes.LogicPuzzle;
+				case "Memory":
+					return GameTypes.MemoryTrainer;
+				case "Calculation":
+					return GameTypes.MathTrainer;
+				case "Verbal":
+					return GameTypes.VerbalAnalogy;
+				default:
+					throw new InvalidOperationException ("Unknown game type");
+			}
+		}
 	}
 }
diff --git a/src/Core/Main/Xml/CodeEvaluation.cs b/src/Core/Main/Xml/CodeEvaluation.cs
new file mode 100644
index 0000000..cb7c03a
--- /dev/null
+++ b/src/Core/Main/Xml/CodeEvaluation.cs
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2010 Jordi Mas i Hernàndez <jmas softcatala org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using Mono.CSharp;
+using Mono.Unix;
+
+namespace gbrainy.Core.Main.Xml
+{
+	// Code evaluation functions
+	public static class CodeEvaluation
+	{
+		static bool? monofix_needed;
+
+		static public void EvaluateVariables (string code)
+		{
+			string eval;
+
+			try
+			{
+				// Using's for the variables section
+				// We need to evaluate either declarations (like using) or expression/statements separately
+				eval = "using System;\n";
+				Mono.CSharp.Evaluator.Run (eval);
+
+				// Infrastructure for the user available
+				eval = "Random random = new Random ();\n";
+				Mono.CSharp.Evaluator.Run (eval);
+				Mono.CSharp.Evaluator.Run (code);
+			}
+
+			catch (Exception e)
+			{
+				Console.WriteLine ("GameXml. Error in games.xml: {0} when evaluating variable definition [{1}]", e.Message, code);
+			}
+		}
+
+		static public string ReplaceVariables (string str)
+		{
+			const string exp = "\\[[a-z_]+\\]+";
+			string var, vars, var_value;
+			Regex regex;
+			Match match;
+
+			if (String.IsNullOrEmpty (str))
+				return str;
+
+			regex = new Regex (exp, RegexOptions.IgnoreCase);
+			match = regex.Match (str);
+
+			vars = Evaluator.GetVars ();
+			vars = FixGetVars (vars);
+
+			while (String.IsNullOrEmpty (match.Value) == false)
+			{
+				var = match.Value.Substring (1, match.Value.Length - 2);
+				var_value = GetVarValue (vars, var);
+
+				if (String.IsNullOrEmpty (var_value) == false)
+					str = str.Replace (match.Value, var_value);
+
+				match = match.NextMatch ();
+			}
+			return str;
+		}
+
+		// Before Mono 2.6 (rev. 156533) there is no line separator between vars
+		static string FixGetVars (string str)
+		{
+			if (monofix_needed == null)
+			{
+				string eval, vars;
+
+				eval = "int a = 1; int b = 1;";
+				Evaluator.Run (eval);
+				vars = Evaluator.GetVars ();
+
+				monofix_needed = vars.IndexOf (System.Environment.NewLine) == -1;
+			}
+
+			if (monofix_needed == false)
+				return str;
+
+			// We just guarantee that int, doubles, and float are separated as modern Mono versions do
+			StringBuilder output = new StringBuilder ();
+			string [] keywords = new string [] {"int", "double", "float"};
+			int pos = 0, cur = 0, tmp_pos, keyword;
+
+			while (pos != -1)
+			{
+				pos = keyword = -1;
+				// Look for the nearest of these keywords
+				for (int i = 0; i < keywords.Length; i++)
+				{
+					tmp_pos = str.IndexOf (keywords [i], cur);
+					if (tmp_pos == -1)
+						continue;
+
+					if (pos == -1 || pos > 0 && tmp_pos < pos) {
+						keyword = i;
+						pos = tmp_pos;
+					}
+				}
+
+				if (pos == -1)
+					continue;
+
+				output.Append (str.Substring (cur, pos - cur));
+				output.AppendLine ();
+				output.Append (str.Substring (pos, keywords[keyword].Length));
+				cur = pos + keywords[keyword].Length;
+			}
+
+			output.Append (str.Substring (cur, str.Length - cur));
+			return output.ToString ();
+		}
+
+		static string GetVarValue (string vars, string _var)
+		{
+			const string exp = "([a-z0-9._%+-]+) ([a-z0-9._%+-]+) (=) ([0-9]+)";
+			Match match;
+			int idx, cur, newline_len;
+			string line;
+
+			Regex regex = new Regex (exp, RegexOptions.IgnoreCase);
+
+			newline_len = System.Environment.NewLine.Length;
+			cur = 0;
+
+			do
+			{
+				// Process a line
+				idx = vars.IndexOf (System.Environment.NewLine, cur);
+				if (idx == -1) idx = vars.Length;
+
+				line = vars.Substring (cur, idx - cur);
+				cur = idx + newline_len;
+				match = regex.Match (line);
+
+				//  "int num = 2";
+				//   group 1 -> int,  group 2 -> num,  group 3 -> =, group 4 -> 2
+				if (match.Groups.Count == 5)
+				{
+					if (match.Groups[2].Value == _var)
+						return match.Groups[4].Value;
+				}
+
+			} while (cur < vars.Length);
+
+			return string.Empty;
+		}
+	}
+}
diff --git a/src/Core/Main/Xml/GameXml.cs b/src/Core/Main/Xml/GameXml.cs
index 4f748cd..bf2e0fb 100644
--- a/src/Core/Main/Xml/GameXml.cs
+++ b/src/Core/Main/Xml/GameXml.cs
@@ -49,7 +49,6 @@ namespace gbrainy.Core.Main.Xml
 		// Shared with all instances
 		static List <GameXmlDefinition> games;
 		static List <DefinitionLocator> locators;
-		static bool? monofix_needed;
 
 		DefinitionLocator current;
 		GameXmlDefinition game;
@@ -120,10 +119,10 @@ namespace gbrainy.Core.Main.Xml
 			if (String.IsNullOrEmpty (variables) == false)
 			{
 				// Evaluate code
-				EvaluateVariables (variables);
-				question = ReplaceVariables (question);
-				answer = ReplaceVariables (answer);
-				rationale = ReplaceVariables (rationale);
+				CodeEvaluation.EvaluateVariables (variables);
+				question = CodeEvaluation.ReplaceVariables (question);
+				answer = CodeEvaluation.ReplaceVariables (answer);
+				rationale = CodeEvaluation.ReplaceVariables (rationale);
 			}
 
 			right_answer = answer;
@@ -155,9 +154,51 @@ namespace gbrainy.Core.Main.Xml
 		{
 			base.Draw (gr, area_width, area_height, rtl);
 
-			if (String.IsNullOrEmpty (game.Image.Filename) == false)
-				gr.DrawImageFromFile (Path.Combine (Defines.DATA_DIR, game.Image.Filename),
-					game.Image.X, game.Image.Y, game.Image.Width, game.Image.Height);
+			DrawObjects (gr, game); // Draw objects shared by all variants
+
+			if (game.Variants.Count > 0)
+				DrawObjects (gr, game.Variants[current.Variant]); // Draw variant specific objects
+		}
+
+		void DrawObjects (CairoContextEx gr, GameXmlDefinitionVariant definition)
+		{
+			if (definition.DrawingObjects != null)
+			{
+				foreach (DrawingObject draw_object in definition.DrawingObjects)
+				{
+					if (draw_object is TextDrawingObject)
+					{
+						string text;
+						TextDrawingObject draw_string = draw_object as TextDrawingObject;
+			
+						text = CatalogGetString (draw_string.Text);
+						text = CodeEvaluation.ReplaceVariables (text);
+
+						if (draw_string.Big)
+							gr.SetPangoLargeFontSize ();
+						else
+							gr.SetPangoNormalFontSize ();
+
+						if (draw_string.Centered) {
+							gr.DrawTextCentered (draw_string.X, draw_string.Y, text);
+						} else {
+							gr.MoveTo (draw_string.X, draw_string.Y);
+							gr.ShowPangoText (text);
+							gr.Stroke ();
+						}
+					} 
+					else if (draw_object is ImageDrawingObject)
+					{
+						ImageDrawingObject image = draw_object as ImageDrawingObject;
+
+						if (String.IsNullOrEmpty (image.Filename) == false)
+						{
+							gr.DrawImageFromFile (Path.Combine (Defines.DATA_DIR, image.Filename),
+								image.X, image.Y, image.Width, image.Height);
+						}
+					}
+				}
+			}
 		}
 
 		void BuildLocationList ()
@@ -180,148 +221,5 @@ namespace gbrainy.Core.Main.Xml
 
 			return Catalog.GetString (str);
 		}
-
-		/*
-			Code evaluation functions
-		*/
-
-		static void EvaluateVariables (string code)
-		{
-			string eval;
-
-			try
-			{
-				// Using's for the variables section
-				// We need to evaluate either declarations (like using) or expression/statements separately
-				eval = "using System;\n";
-				Mono.CSharp.Evaluator.Run (eval);
-
-				// Infrastructure for the user available
-				eval = "Random random = new Random ();\n";
-				Mono.CSharp.Evaluator.Run (eval);
-				Mono.CSharp.Evaluator.Run (code);
-			}
-
-			catch (Exception e)
-			{
-				Console.WriteLine ("GameXml. Error in games.xml: {0} when evaluating variable definition [{1}]", e.Message, code);
-			}
-		}
-
-		// Before Mono 2.6 (rev. 156533) there is no line separator between vars
-		static string FixGetVars (string str)
-		{
-			if (monofix_needed == null)
-			{
-				string eval, vars;
-
-				eval = "int a = 1; int b = 1;";
-				Evaluator.Run (eval);
-				vars = Evaluator.GetVars ();
-
-				monofix_needed = vars.IndexOf (System.Environment.NewLine) == -1;
-			}
-
-			if (monofix_needed == false)
-				return str;
-
-			// We just guarantee that int, doubles, and float are separated as modern Mono versions do
-			StringBuilder output = new StringBuilder ();
-			string [] keywords = new string [] {"int", "double", "float"};
-			int pos = 0, cur = 0, tmp_pos, keyword;
-
-			while (pos != -1)
-			{
-				pos = keyword = -1;
-				// Look for the nearest of these keywords
-				for (int i = 0; i < keywords.Length; i++)
-				{
-					tmp_pos = str.IndexOf (keywords [i], cur);
-					if (tmp_pos == -1)
-						continue;
-
-					if (pos == -1 || pos > 0 && tmp_pos < pos) {
-						keyword = i;
-						pos = tmp_pos;
-					}
-				}
-
-				if (pos == -1)
-					continue;
-
-				output.Append (str.Substring (cur, pos - cur));
-				output.AppendLine ();
-				output.Append (str.Substring (pos, keywords[keyword].Length));
-				cur = pos + keywords[keyword].Length;
-			}
-
-			output.Append (str.Substring (cur, str.Length - cur));
-			return output.ToString ();
-		}
-
-		static string GetVarValue (string vars, string _var)
-		{
-			const string exp = "([a-z0-9._%+-]+) ([a-z0-9._%+-]+) (=) ([0-9]+)";
-			Match match;
-			int idx, cur, newline_len;
-			string line;
-
-			Regex regex = new Regex (exp, RegexOptions.IgnoreCase);
-
-			newline_len = System.Environment.NewLine.Length;
-			cur = 0;
-
-			do
-			{
-				// Process a line
-				idx = vars.IndexOf (System.Environment.NewLine, cur);
-				if (idx == -1) idx = vars.Length;
-
-				line = vars.Substring (cur, idx - cur);
-				cur = idx + newline_len;
-				match = regex.Match (line);
-
-				//  "int num = 2";
-				//   group 1 -> int,  group 2 -> num,  group 3 -> =, group 4 -> 2
-				if (match.Groups.Count == 5)
-				{
-					if (match.Groups[2].Value == _var)
-						return match.Groups[4].Value;
-				}
-
-			} while (cur < vars.Length);
-
-			return string.Empty;
-		}
-
-		static string ReplaceVariables (string str)
-		{
-			const string exp = "\\[[a-z_]+\\]+";
-			string var, vars, var_value;
-			Regex regex;
-			Match match;
-
-			if (String.IsNullOrEmpty (str))
-				return str;
-
-			regex = new Regex (exp, RegexOptions.IgnoreCase);
-			match = regex.Match (str);
-
-			vars = Evaluator.GetVars ();
-			vars = FixGetVars (vars);
-
-			while (String.IsNullOrEmpty (match.Value) == false)
-			{
-				var = match.Value.Substring (1, match.Value.Length - 2);
-				var_value = GetVarValue (vars, var);
-
-				if (String.IsNullOrEmpty (var_value) == false)
-					str = str.Replace (match.Value, var_value);
-
-				match = match.NextMatch ();
-			}
-			return str;
-		}
-
 	}
 }
diff --git a/src/Core/Main/Xml/GameXmlDefinition.cs b/src/Core/Main/Xml/GameXmlDefinition.cs
index 5176f0c..e1437ad 100644
--- a/src/Core/Main/Xml/GameXmlDefinition.cs
+++ b/src/Core/Main/Xml/GameXmlDefinition.cs
@@ -23,24 +23,55 @@ using System.Collections.Generic;
 
 namespace gbrainy.Core.Main.Xml
 {
-	public class GameXmlDefinitionVariant
+	public class DrawingObject
 	{
-		public struct SVGImage
-		{
-			public string Filename { get; set; }
-			public double X { get; set; }
-			public double Y { get; set; }
-			public double Width { get; set; }
-			public double Height { get; set; }
-		};
 
+	}
+
+	public class ImageDrawingObject : DrawingObject
+	{
+		public string Filename { get; set; }
+		public double X { get; set; }
+		public double Y { get; set; }
+		public double Width { get; set; }
+		public double Height { get; set; }
+	};
+
+	public class TextDrawingObject : DrawingObject
+	{
+		public string Text { get; set; }
+		public double X { get; set; }
+		public double Y { get; set; }
+		public bool Centered { get; set; }
+		public bool Big { get; set; }
+	};
+
+	public class GameXmlDefinitionVariant
+	{
 		public string Question { get; set; }
 		public string Tip { get; set; }
 		public string Rationale { get; set; }
 		public string Answer { get; set; }
 		public string Variables { get; set; }
 
-		public SVGImage Image;
+		List <DrawingObject> drawing_objects;
+
+		public DrawingObject [] DrawingObjects {
+			get {
+				if (drawing_objects == null)
+					return null;
+	
+				return drawing_objects.ToArray ();
+			}
+		}
+
+		public void AddDrawingObject (DrawingObject obj)
+		{
+			if (drawing_objects == null)
+				drawing_objects = new List <DrawingObject> ();
+
+			drawing_objects.Add (obj);
+		}
 
 		public override string ToString ()
 		{
diff --git a/src/Core/Main/Xml/GameXmlFactory.cs b/src/Core/Main/Xml/GameXmlFactory.cs
index 12f7433..b8e94b5 100644
--- a/src/Core/Main/Xml/GameXmlFactory.cs
+++ b/src/Core/Main/Xml/GameXmlFactory.cs
@@ -62,12 +62,15 @@ namespace gbrainy.Core.Main.Xml
 					case "games":
 						break;
 					case "type":
+						if (reader.NodeType != XmlNodeType.Element)
+							break;
+
+						game.Type = GameTypesDescription.FromString (reader.ReadElementString ());
 						break;
 					case "game":
 						if (reader.NodeType == XmlNodeType.Element) {
 							game = new GameXmlDefinition ();
 						} else if (reader.NodeType == XmlNodeType.EndElement) {
-
 							games.Add (game);
 						}
 						break;
@@ -107,31 +110,79 @@ namespace gbrainy.Core.Main.Xml
 						if (reader.NodeType != XmlNodeType.Element)
 							break;
 
-						game.Image.Filename = reader.GetAttribute ("file");
+						ImageDrawingObject draw_image = new ImageDrawingObject ();
+
+						if (processing_variant)
+							game.Variants[variant].AddDrawingObject (draw_image);
+						else
+							game.AddDrawingObject (draw_image);
+
+						draw_image.Filename = reader.GetAttribute ("file");
 
 						str = reader.GetAttribute ("x");
 						if (String.IsNullOrEmpty (str) == false)
-							game.Image.X = Double.Parse (str, CultureInfo.InvariantCulture);
+							draw_image.X = Double.Parse (str, CultureInfo.InvariantCulture);
 						else
-							game.Image.X = 0.1;
+							draw_image.X = 0.1;
 
 						str = reader.GetAttribute ("y");
 						if (String.IsNullOrEmpty (str) == false)
-							game.Image.Y = Double.Parse (str, CultureInfo.InvariantCulture);
+							draw_image.Y = Double.Parse (str, CultureInfo.InvariantCulture);
 						else
-							game.Image.Y = 0.1;
+							draw_image.Y = 0.1;
 
 						str = reader.GetAttribute ("width");
 						if (String.IsNullOrEmpty (str) == false)
-							game.Image.Width = Double.Parse (str, CultureInfo.InvariantCulture);
+							draw_image.Width = Double.Parse (str, CultureInfo.InvariantCulture);
 						else
-							game.Image.Width = 0.8;
+							draw_image.Width = 0.8;
 
 						str = reader.GetAttribute ("height");
 						if (String.IsNullOrEmpty (str) == false)
-							game.Image.Height = Double.Parse (str, CultureInfo.InvariantCulture);
+							draw_image.Height = Double.Parse (str, CultureInfo.InvariantCulture);
+						else
+							draw_image.Height = 0.8;
+
+						break;
+					case "string":
+						if (reader.NodeType != XmlNodeType.Element)
+							break;
+
+						TextDrawingObject draw_string = new TextDrawingObject ();
+
+						if (processing_variant)
+							game.Variants[variant].AddDrawingObject (draw_string);
+						else
+							game.AddDrawingObject (draw_string);
+
+						draw_string.Text = reader.GetAttribute ("text");
+	
+						if (String.IsNullOrEmpty (draw_string.Text))
+							draw_string.Text = reader.GetAttribute ("_text");
+
+						str = reader.GetAttribute ("x");
+						if (String.IsNullOrEmpty (str) == false)
+							draw_string.X = Double.Parse (str, CultureInfo.InvariantCulture);
+						else
+							draw_string.X = 0.1;
+
+						str = reader.GetAttribute ("y");
+						if (String.IsNullOrEmpty (str) == false)
+							draw_string.Y = Double.Parse (str, CultureInfo.InvariantCulture);
+						else
+							draw_string.Y = 0.1;
+
+						str = reader.GetAttribute ("centered");
+						if (String.Compare (str, "yes", true) == 0)
+							draw_string.Centered = true;
+						else
+							draw_string.Centered = false;
+
+						str = reader.GetAttribute ("size");
+						if (String.Compare (str, "big", true) == 0)
+							draw_string.Big = true;
 						else
-							game.Image.Height = 0.8;
+							draw_string.Big = false;
 
 						break;
 					case "_question":
diff --git a/src/Core/Makefile.am b/src/Core/Makefile.am
index b613a75..2ad2d90 100644
--- a/src/Core/Makefile.am
+++ b/src/Core/Makefile.am
@@ -18,6 +18,7 @@ CSDISTFILES =  \
 		$(srcdir)/Main/GameSessionHistoryExtended.cs \
 		$(srcdir)/Main/GameTypes.cs		\
 		$(srcdir)/Main/GameTips.cs		\
+		$(srcdir)/Main/Xml/CodeEvaluation.cs	\
 		$(srcdir)/Main/Xml/GameXml.cs		\
 		$(srcdir)/Main/Xml/GameXmlFactory.cs	\
 		$(srcdir)/Main/Xml/GameXmlDefinition.cs	\
diff --git a/src/Core/Views/PlayerHistoryView.cs b/src/Core/Views/PlayerHistoryView.cs
index afaff17..afbf3c0 100644
--- a/src/Core/Views/PlayerHistoryView.cs
+++ b/src/Core/Views/PlayerHistoryView.cs
@@ -74,7 +74,7 @@ namespace gbrainy.Core.Views
 			cr.Stroke ();
 			cr.Color = text_color;
 			cr.MoveTo (x + line_size + offset_x, y - 0.01 + second_row);
-			cr.ShowPangoText (GameTypesDescription.Get (GameTypes.LogicPuzzle));
+			cr.ShowPangoText (GameTypesDescription.GetLocalized (GameTypes.LogicPuzzle));
 			cr.Stroke ();
 
 			x += space_hor;
@@ -84,7 +84,7 @@ namespace gbrainy.Core.Views
 			cr.Stroke ();
 			cr.Color = text_color;
 			cr.MoveTo (x + line_size + offset_x, y - 0.01);
-			cr.ShowPangoText (GameTypesDescription.Get (GameTypes.MemoryTrainer));
+			cr.ShowPangoText (GameTypesDescription.GetLocalized (GameTypes.MemoryTrainer));
 			cr.Stroke ();
 
 			cr.Color = math_color;
@@ -93,7 +93,7 @@ namespace gbrainy.Core.Views
 			cr.Stroke ();
 			cr.Color = text_color;
 			cr.MoveTo (x + line_size + offset_x, y - 0.01 + second_row);
-			cr.ShowPangoText (GameTypesDescription.Get (GameTypes.MathTrainer));
+			cr.ShowPangoText (GameTypesDescription.GetLocalized (GameTypes.MathTrainer));
 			cr.Stroke ();
 
 			x += space_hor;
@@ -103,7 +103,7 @@ namespace gbrainy.Core.Views
 			cr.Stroke ();
 			cr.Color = text_color;
 			cr.MoveTo (x + line_size + offset_x, y - 0.01);
-			cr.ShowPangoText (GameTypesDescription.Get (GameTypes.VerbalAnalogy));
+			cr.ShowPangoText (GameTypesDescription.GetLocalized (GameTypes.VerbalAnalogy));
 			cr.Stroke ();
 
 			cr.LineWidth = old_width;



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