gnome-games r8328 - trunk/aisleriot



Author: chpe
Date: Sun Nov 23 19:34:51 2008
New Revision: 8328
URL: http://svn.gnome.org/viewvc/gnome-games?rev=8328&view=rev

Log:
Move option handling code from AisleriotWindow to AisleriotGame.
Now guile is only used from within game.c.

Modified:
   trunk/aisleriot/game.c
   trunk/aisleriot/game.h
   trunk/aisleriot/window.c

Modified: trunk/aisleriot/game.c
==============================================================================
--- trunk/aisleriot/game.c	(original)
+++ trunk/aisleriot/game.c	Sun Nov 23 19:34:51 2008
@@ -1995,15 +1995,36 @@
 }
 
 /**
- * aisleriot_game_get_options_lambda:
+ * aisleriot_game_option_free:
+ * @option: a #AisleriotGameOption
+ *
+ * Frees @options.
+ */
+void
+aisleriot_game_option_free (AisleriotGameOption *option)
+{
+  g_return_if_fail (option != NULL);
+
+  g_free (option->display_name);
+  g_slice_free (AisleriotGameOption, option);
+}
+
+/**
+ * aisleriot_game_get_options:
  * @game:
  *
- * Returns: a #SCM containing the game options
+ * Returns: a newly allocated list containing newly allocated
+ * #AisleriotGameOption structs. 
  */
-SCM
-aisleriot_game_get_options_lambda (AisleriotGame *game)
+GList *
+aisleriot_game_get_options (AisleriotGame *game)
 {
   CallData data = CALL_DATA_INIT;
+  SCM options_list;
+  int l, i;
+  guint32 bit = 1;
+  AisleriotGameOptionType type = AISLERIOT_GAME_OPTION_CHECK;
+  GList *options = NULL;
 
   data.lambda = game->get_options_lambda;
   data.n_args = 0;
@@ -2011,31 +2032,120 @@
                             cscmi_call_lambda, &data,
                             cscmi_catch_handler, NULL);
 
-  return data.retval;
+  options_list = data.retval;
+  if (scm_is_false (scm_list_p (options_list)))
+    return NULL;
+
+  l = scm_to_int (scm_length (options_list));
+  bit = 1;
+  for (i = 0; i < l; i++) {
+    SCM entry;
+
+    /* Each entry in the options list is a list consisting of a name and
+     * a variable.
+     */
+    entry = scm_list_ref (options_list, scm_from_int (i));
+    if (!scm_is_false (scm_list_p (entry))) {
+      SCM entryname;
+      char *entrynamestr;
+      gboolean entrystate;
+      AisleriotGameOption *option;
+
+      entryname = scm_list_ref (entry, scm_from_uint (0));
+      if (!scm_is_string (entryname))
+        continue; /* Shouldn't happen */
+
+      entrynamestr = scm_to_locale_string (entryname);
+      if (!entrynamestr)
+        continue;
+
+      entrystate = SCM_NFALSEP (scm_list_ref (entry, scm_from_uint (1)));
+
+      option = g_slice_new (AisleriotGameOption);
+      option->display_name = g_strdup (entrynamestr);
+      option->type = type;
+      option->value = bit;
+      option->set = entrystate != FALSE;
+
+      options = g_list_prepend (options, option);
+
+      free (entrynamestr);
+
+      bit <<= 1;
+    } else {
+      /* If we encounter an atom, change the mode. What the atom is doesn't
+      * really matter. */
+      if (type == AISLERIOT_GAME_OPTION_CHECK) {
+        type = AISLERIOT_GAME_OPTION_RADIO;
+      } else {
+        type = AISLERIOT_GAME_OPTION_CHECK;
+      }
+    }
+  }
+
+  return g_list_reverse (options);
 }
 
 /**
  * aisleriot_game_apply_options_lambda:
  * @game:
- * @options:
+ * @changed_mask:
+ * @changed_value:
  *
- * Applies @options.
+ * Applies options.
  *
- * Returns: a #SCM with status information
+ * Returns: the new options value
  */
-SCM
-aisleriot_game_apply_options_lambda (AisleriotGame *game, SCM options)
+guint32
+aisleriot_game_change_options (AisleriotGame *game,
+                               guint32 changed_mask,
+                               guint32 changed_value)
 {
   CallData data = CALL_DATA_INIT;
+  CallData data2 = CALL_DATA_INIT;
+  SCM options_list;
+  guint32 bit, value;
+  int l, i;
 
-  data.lambda = game->apply_options_lambda;
-  data.n_args = 1;
-  data.arg1 = options;
+  data.lambda = game->get_options_lambda;
+  data.n_args = 0;
   scm_internal_stack_catch (SCM_BOOL_T,
                             cscmi_call_lambda, &data,
                             cscmi_catch_handler, NULL);
 
-  return data.retval;
+  options_list = data.retval;
+  if (scm_is_false (scm_list_p (options_list)))
+    return 0;
+
+  value = 0;
+  bit = 1;
+  l = scm_to_int (scm_length (options_list));
+  for (i = 0; i < l; i++) {
+    SCM entry;
+
+    entry = scm_list_ref (options_list, scm_from_uint (i));
+    if (scm_is_false (scm_list_p (entry)))
+      continue;
+
+    if (changed_mask & bit)
+      scm_list_set_x (entry, scm_from_uint (1), (changed_value & bit) ? SCM_BOOL_T : SCM_BOOL_F);
+  
+    if (SCM_NFALSEP (scm_list_ref (entry, scm_from_uint (1))))
+      value |= bit;
+
+    bit <<= 1;
+  }
+
+  data2.lambda = game->apply_options_lambda;
+  data2.n_args = 1;
+  data2.arg1 = options_list;
+  scm_internal_stack_catch (SCM_BOOL_T,
+                            cscmi_call_lambda, &data2,
+                            cscmi_catch_handler, NULL);
+
+  /* FIXMEchpe: check for exceptions? */
+
+  return value;
 }
 
 /**

Modified: trunk/aisleriot/game.h
==============================================================================
--- trunk/aisleriot/game.h	(original)
+++ trunk/aisleriot/game.h	Sun Nov 23 19:34:51 2008
@@ -19,8 +19,6 @@
 #ifndef AISLERIOT_GAME_H
 #define AISLERIOT_GAME_H
 
-#include <libguile.h>
-
 #include <gdk/gdk.h>
 
 #include <libgames-support/games-card.h>
@@ -94,6 +92,8 @@
 
 #define AISLERIOT_GAME_ERROR  (aisleriot_game_error_quark ())
 
+#define AISLERIOT_GAME_OPTIONS_MAX (0x7FFFFFFF) /* 31 bits, since we're using int not guint */
+
 typedef struct _AisleriotGame AisleriotGame;
 typedef GObjectClass AisleriotGameClass;
 
@@ -119,8 +119,22 @@
   LAST_GAME_STATE
 } AisleriotGameState;
 
+typedef enum {
+  AISLERIOT_GAME_OPTION_CHECK,
+  AISLERIOT_GAME_OPTION_RADIO
+} AisleriotGameOptionType;
+
+typedef struct {
+  char *display_name;
+  AisleriotGameOptionType type;
+  guint32 value; /* exactly 1 bit set */
+  gboolean set;
+} AisleriotGameOption;
+
 GQuark aisleriot_game_error_quark (void);
 
+void aisleriot_game_option_free (AisleriotGameOption *option);
+
 GType aisleriot_game_get_type (void);
 
 AisleriotGame *aisleriot_game_new (void);
@@ -181,9 +195,11 @@
 
 char *aisleriot_game_get_hint (AisleriotGame *game);
 
-SCM aisleriot_game_get_options_lambda (AisleriotGame * game);
+GList *aisleriot_game_get_options (AisleriotGame * game);
 
-SCM aisleriot_game_apply_options_lambda (AisleriotGame * game, SCM options);
+guint32 aisleriot_game_change_options (AisleriotGame *game,
+                                       guint32 changed_mask,
+                                       guint32 changed_value);
 
 gboolean aisleriot_game_timeout_lambda (AisleriotGame * game);
 

Modified: trunk/aisleriot/window.c
==============================================================================
--- trunk/aisleriot/window.c	(original)
+++ trunk/aisleriot/window.c	Sun Nov 23 19:34:51 2008
@@ -25,12 +25,6 @@
 #include <sys/types.h>
 #include <errno.h>
 
-#include <libguile.h>
-
-#ifndef HAVE_GUILE_1_8
-#include "guile16-compat.h"
-#endif
-
 #include <glib/gi18n.h>
 
 #include <gdk/gdk.h>
@@ -1125,63 +1119,27 @@
   aisleriot_game_deal_cards (priv->game);
 }
 
-/* Make something that's easier to store in conf */
-static guint
-compress_options_to_int (SCM options_list)
-{
-  int i;
-  guint bits;
-  SCM entry;
-
-  bits = 0;
-  for (i = scm_to_int (scm_length (options_list)) - 1; i >= 0; i--) {
-    entry = scm_list_ref (options_list, scm_from_int (i));
-    if (SCM_NFALSEP (scm_list_p (entry))) {
-      bits <<= 1;
-      bits |= SCM_NFALSEP (scm_list_ref (entry, scm_from_int (1))) ? 1 : 0;
-    }
-  }
-
-  return bits;
-}
-
-/* Take the bit-string value and set the option list from it. */
-static void
-expand_options_from_int (SCM options_list, guint bits)
-{
-  gint l, i;
-  SCM entry;
-
-  l = scm_to_int (scm_length (options_list));
-  for (i = 0; i < l; i++) {
-    entry = scm_list_ref (options_list, scm_from_int (i));
-    if (SCM_NFALSEP (scm_list_p (entry))) {
-      scm_list_set_x (entry, scm_from_int (1),
-		      bits & 1 ? SCM_BOOL_T : SCM_BOOL_F);
-      bits >>= 1;
-    }
-  }
-}
-
 /* The "Game Options" menu */
 
 static void
-apply_option (SCM options_list,
-              GtkToggleAction *action)
+apply_option (GtkToggleAction *action,
+              guint32 *changed_mask,
+              guint32 *changed_value)
 {
-  SCM entry;
   gboolean active;
   const char *action_name;
-  guint n;
+  guint32 value;
 
   active = gtk_toggle_action_get_active (action);
 
   action_name = gtk_action_get_name (GTK_ACTION (action));
-  n = g_ascii_strtoull (action_name + strlen ("Option"), NULL, 10);
+  value = g_ascii_strtoull (action_name + strlen ("Option"), NULL, 16);
 
-  entry = scm_list_ref (options_list, scm_from_uint (n));
+  g_print ("option %s changed, value=%x set=%d\n", action_name, value, active);
 
-  scm_list_set_x (entry, scm_from_uint (1), active ? SCM_BOOL_T : SCM_BOOL_F);
+  *changed_mask |= value;
+  if (active)
+    *changed_value |= value;
 }
 
 static void
@@ -1189,8 +1147,8 @@
            AisleriotWindow *window)
 {
   AisleriotWindowPrivate *priv = window->priv;
-  SCM options_list;
   gboolean active;
+  guint32 changed_mask = 0, changed_value = 0, value;
 
   /* Don't change the options if we're just installing the options menu */
   if (priv->changing_game_type)
@@ -1208,8 +1166,6 @@
       !active)
     return;
 
-  options_list = aisleriot_game_get_options_lambda (priv->game);
-
   if (GTK_IS_RADIO_ACTION (action)) {
     GSList *group, *l;
 
@@ -1220,16 +1176,15 @@
     group = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));
 
     for (l = group; l; l = l->next) {
-      apply_option (options_list, GTK_TOGGLE_ACTION (l->data));
+      apply_option (GTK_TOGGLE_ACTION (l->data), &changed_mask, &changed_value);
     }
   } else {
-    apply_option (options_list, action);
+    apply_option (action, &changed_mask, &changed_value);
   }
 
-  aisleriot_conf_set_options (aisleriot_game_get_game_file (priv->game),
-                              compress_options_to_int (options_list));
+  value = aisleriot_game_change_options (priv->game, changed_mask, changed_value);
 
-  aisleriot_game_apply_options_lambda (priv->game, options_list);
+  aisleriot_conf_set_options (aisleriot_game_get_game_file (priv->game), (int) value);
 
   /* Now re-deal, so the option is applied */
   aisleriot_game_new_game (priv->game, NULL);
@@ -1239,10 +1194,10 @@
 install_options_menu (AisleriotWindow *window)
 {
   AisleriotWindowPrivate *priv = window->priv;
-  SCM options_list;
-  int l, i, options;
-  gint mode = OPTION_CHECKMENU;
+  GList *options, *l;
+  int options_value = 0;
   GSList *radiogroup = NULL;
+  int radion = 0;
 
   if (priv->options_merge_id != 0) {
     gtk_ui_manager_remove_ui (priv->ui_manager, priv->options_merge_id);
@@ -1257,99 +1212,74 @@
   /* See gtk bug #424448 */
   gtk_ui_manager_ensure_update (priv->ui_manager);
 
+  /* Only apply the options if they exist. Otherwise the options in the menu
+   * and the real game options are out of sync until first changed by the user.
+   */
+  if (aisleriot_conf_get_options (aisleriot_game_get_game_file (priv->game), &options_value)) {
+    aisleriot_game_change_options (priv->game, AISLERIOT_GAME_OPTIONS_MAX, options_value);
+  }
+
   /* To get radio buttons in the menu insert an atom into the option list
    * in your scheme code. To get back out of radio-button mode insert 
    * another atom. The exact value of the atoms is irrelevant - they merely
    * trigger a toggle - but descriptive names like begin-exclusive and
    * end-exclusive are probably a good idea.
    */
-  options_list = aisleriot_game_get_options_lambda (priv->game);
-
-  if (scm_is_false (scm_list_p (options_list)))
+  options = aisleriot_game_get_options (priv->game);
+  if (!options)
     return;
-    
+
   priv->options_group = gtk_action_group_new ("Options");
   gtk_ui_manager_insert_action_group (priv->ui_manager, priv->options_group, -1);
   g_object_unref (priv->options_group);
 
   priv->options_merge_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
 
-  /* Only apply the options if they exist. Otherwise the options in the menu
-    * and the real game options are out of sync until first changed by the user.
-    */
-  if (aisleriot_conf_get_options (aisleriot_game_get_game_file (priv->game), &options)) {
-    expand_options_from_int (options_list, options);
-    aisleriot_game_apply_options_lambda (priv->game, options_list);
-  }
+  for (l = options; l != NULL; l = l->next) {
+    AisleriotGameOption *option = (AisleriotGameOption *) l->data;
+    GtkToggleAction *action;
+    gchar actionname[32];
+
+    g_print ("installing option value=%08x set=%d type=%d name='%s'\n",
+             option->value, option->set, option->type, option->display_name);
+
+    g_snprintf (actionname, sizeof (actionname), "Option%u", option->value);
+
+    if (option->type == AISLERIOT_GAME_OPTION_CHECK) {
+      action = gtk_toggle_action_new (actionname,
+                                      option->display_name,
+                                      NULL,
+                                      NULL /* tooltip */);
+      radiogroup = NULL; /* make sure to start a new radio group when the next RADIO option comes */
+      radion = 0;
+    } else {
+      action = GTK_TOGGLE_ACTION (gtk_radio_action_new (actionname,
+                                                        option->display_name,
+                                                        NULL,
+                                                        NULL /* tooltip */,
+                                                        radion++));
+      gtk_radio_action_set_group (GTK_RADIO_ACTION (action),
+                                  radiogroup);
+      radiogroup = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));
+    }
 
-  l = scm_to_int (scm_length (options_list));
-  for (i = 0; i < l; i++) {
-    SCM entry;
+    gtk_toggle_action_set_active (action, option->set);
+    g_signal_connect (action, "toggled",
+                      G_CALLBACK (option_cb), window);
 
-    /* Each entry in the options list is a list consisting of a name and
-     * a variable.
-     */
-    entry = scm_list_ref (options_list, scm_from_int (i));
-    if (!scm_is_false (scm_list_p (entry))) {
-      SCM entryname;
-      char *entrynamestr;
-      gboolean entrystate;
-      GtkToggleAction *action;
-      gchar actionname[32];
-
-      entryname = scm_list_ref (entry, scm_from_uint (0));
-      if (!scm_is_string (entryname))
-        continue; /* Shouldn't happen */
-
-      entrynamestr = scm_to_locale_string (entryname);
-      if (!entrynamestr)
-        continue;
-
-      entrystate = SCM_NFALSEP (scm_list_ref (entry, scm_from_uint (1)));
-
-      g_snprintf (actionname, sizeof (actionname), "Option%d", i);
-
-      if (mode == OPTION_CHECKMENU) {
-        action = gtk_toggle_action_new (actionname,
-                                        entrynamestr,
-                                        NULL,
-                                        NULL /* tooltip */);
-      } else {
-        action = GTK_TOGGLE_ACTION (gtk_radio_action_new (actionname,
-                                                          entrynamestr,
-                                                          NULL,
-                                                          NULL /* tooltip */,
-                                                          i));
-        gtk_radio_action_set_group (GTK_RADIO_ACTION (action),
-                                    radiogroup);
-        radiogroup = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));
-      }
+    gtk_action_group_add_action (priv->options_group, GTK_ACTION (action));
+    g_object_unref (action);
 
-      free (entrynamestr);
+    gtk_ui_manager_add_ui (priv->ui_manager,
+                           priv->options_merge_id,
+                           OPTIONS_MENU_PATH,
+                           actionname, actionname,
+                           GTK_UI_MANAGER_MENUITEM, FALSE);
 
-      gtk_toggle_action_set_active (action, entrystate);
-      g_signal_connect (action, "toggled",
-                        G_CALLBACK (option_cb), window);
-
-      gtk_action_group_add_action (priv->options_group, GTK_ACTION (action));
-      g_object_unref (action);
-
-      gtk_ui_manager_add_ui (priv->ui_manager,
-                             priv->options_merge_id,
-                             OPTIONS_MENU_PATH,
-                             actionname, actionname,
-                             GTK_UI_MANAGER_MENUITEM, FALSE);
-    } else {
-      /* If we encounter an atom, change the mode. What the atom is doesn't
-      * really matter. */
-      if (mode == OPTION_CHECKMENU) {
-        mode = OPTION_RADIOMENU;
-        radiogroup = NULL;	/* Start a new radio group. */
-      } else {
-        mode = OPTION_CHECKMENU;
-      }
-    }
+    aisleriot_game_option_free (option);
   }
+
+  g_list_free (options);
 }
 
 /* The "Recent Games" menu */



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