Got gameplay working and board resizing with window.
[gmemory:gmemory.git] / src / main.c
1 /*
2  *  GMemory - main.c
3  *
4  *  Copyright (C) 2010 Openismus GmbH
5  *
6  *  Author: Chris Kühl <chrisk@openismus.com>
7  *
8  *  This program is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <gtk/gtk.h>
23 #include <glib/gi18n.h>
24 #include <stdlib.h>
25
26 #include <clutter-gtk/clutter-gtk.h>
27
28 #include "config.h"
29 #include "gmemory-game.h"
30
31 /* GMemory Constants */
32 #define INITIAL_WINDOW_WIDTH  400
33 #define INITIAL_WINDOW_HEIGHT 500
34
35 #define LAYOUT_SPACING 6
36 #define GAME_BORDER    10
37
38 #define UI_MANAGER_XML_PATH "ui/gmemory-ui-manager.xml"
39
40 #define DEFAULT_PLAYING_AREA_SIZE 5 /* N-by-N square of cards */
41
42 /* Callbacks */
43 static gboolean delete_event(GtkWidget*, GdkEvent*, gpointer);
44 static void     destroy     (GtkWidget *, gpointer);
45
46 static void new_game_started_cb(GMemoryGame *);
47 static void game_ended_cb(GMemoryGame *, gboolean);
48 static void set_game_size_cb   (GtkClutterEmbed *, GtkAllocation *, GMemoryGame *);
49
50 /* Action callbacks */
51 static void new_action   (GtkAction *action, gpointer data);
52 static void quit_action  (GtkAction *action, gpointer data);
53 static void about_action (GtkAction *action, gpointer data);
54
55 /* Action Names */
56 static const gchar NEW_ACTION_NAME[]   = "NewAction";
57 static const gchar QUIT_ACTION_NAME[]  = "QuitAction";
58 static const gchar ABOUT_ACTION_NAME[] = "AboutAction";
59
60 static GMemoryGame *game;
61
62 /* Define actions */
63 static GtkActionEntry actions[] = {
64         /*      Name       stock id   Label */
65         { "GameMenuAction", NULL,    N_("_File") },
66         { "HelpMenuAction", NULL,    N_("_Help") },
67
68         /* Game menu actions */
69         { NEW_ACTION_NAME,           /* Name              */
70           GTK_STOCK_NEW,             /* stock_id          */
71           N_("_New"),                /* Label             */
72           "<control>N",              /* Accelerator       */
73           N_("Start a new game."),   /* Tooltip           */
74           G_CALLBACK (new_action) }, /* Action (callback) */
75
76         { QUIT_ACTION_NAME,
77           GTK_STOCK_QUIT,
78           N_("_Quit"),
79           "<control>Q",
80           N_("Quit GMemory."),
81           G_CALLBACK (quit_action) },
82
83         /* Help menu actions */
84         { ABOUT_ACTION_NAME,
85           GTK_STOCK_ABOUT,
86           N_("_About"),
87           "",
88           N_("About GMemory."),
89           G_CALLBACK (about_action) }
90 };
91 static const guint N_ACTIONS = G_N_ELEMENTS(actions);
92
93 int
94 main(int argc, char *argv[]) {
95
96         GtkWidget      *window;
97         GtkWidget      *main_vbox;
98         GtkWidget      *menubar;
99         GtkWidget      *toolbar;
100         GtkWidget      *statusbar;
101         GtkActionGroup *action_group;
102         GtkUIManager   *ui_manager;
103         GError         *error;
104
105         GtkWidget    *clutter_embed;
106
107         ClutterColor  color      = { 0x3f, 0x3f, 0x3f, 0xff }; /* Gray */
108         ClutterColor  rect_color = { 0xFf, 0x3f, 0x2f, 0xff }; /* Red */
109
110         gtk_clutter_init(&argc, &argv);
111
112         /* i18n */
113         bindtextdomain(GETTEXT_PACKAGE, PROGRAMNAME_LOCALEDIR);
114         bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
115         textdomain(GETTEXT_PACKAGE);
116
117         /* Start building window. */
118         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
119         gtk_widget_set_size_request(window, INITIAL_WINDOW_WIDTH,
120                                     INITIAL_WINDOW_HEIGHT);
121         gtk_container_set_border_width(GTK_CONTAINER(window), 0);
122
123         main_vbox = gtk_vbox_new(FALSE, LAYOUT_SPACING);
124         gtk_container_add(GTK_CONTAINER(window), main_vbox);
125
126         /* Start setting up UI Manager (menus, toolbars and actions). */
127         ui_manager = gtk_ui_manager_new();
128         action_group = gtk_action_group_new("MainActions");
129
130         error = NULL;
131         gtk_ui_manager_add_ui_from_file(ui_manager, UI_MANAGER_XML_PATH, &error);
132
133         if (G_UNLIKELY(error))
134                 g_error("Building menus failed. Error: %s", error->message);
135
136         gtk_action_group_add_actions(action_group, actions, N_ACTIONS, window);
137         gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
138
139         menubar = gtk_ui_manager_get_widget(ui_manager, "/MainMenu");
140         gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, FALSE, 0);
141         toolbar = gtk_ui_manager_get_widget(ui_manager, "/MainToolbar");
142         gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH);
143         gtk_box_pack_start(GTK_BOX(main_vbox), toolbar, FALSE, FALSE, 0);
144
145         gtk_window_add_accel_group(GTK_WINDOW(window),
146                         gtk_ui_manager_get_accel_group(ui_manager));
147         /* Finished setting up menus and actions. */
148
149         /* Setup playing area. */
150         clutter_embed = gtk_clutter_embed_new();
151
152         gtk_box_pack_start(GTK_BOX(main_vbox), clutter_embed, TRUE, TRUE, 0);
153         gtk_widget_set_size_request (clutter_embed, 100, 100);
154
155         ClutterActor *stage;
156         stage = gtk_clutter_embed_get_stage(GTK_CLUTTER_EMBED(clutter_embed));
157         clutter_stage_set_color(CLUTTER_STAGE(stage), &color);
158
159         game = gmemory_game_new();
160         clutter_actor_set_position(CLUTTER_ACTOR(game), GAME_BORDER, GAME_BORDER);
161         clutter_container_add_actor(CLUTTER_CONTAINER(stage), CLUTTER_ACTOR(game));
162
163         /* Attach callbacks */
164         g_signal_connect(window, "destroy", G_CALLBACK (destroy), NULL);
165         g_signal_connect(window, "delete-event", G_CALLBACK (delete_event), NULL);
166
167         g_signal_connect(GMEMORY_GAME(game),              "start-game",
168                          G_CALLBACK(new_game_started_cb), NULL);
169         g_signal_connect(GMEMORY_GAME(game),              "end-game",
170                          G_CALLBACK(game_ended_cb), NULL);
171         g_signal_connect(clutter_embed,                "size-allocate",
172                          G_CALLBACK(set_game_size_cb), game);
173
174         gmemory_game_set_difficulty(GMEMORY_GAME(game), GAME_DIFFICULTY_NORMAL);
175         gmemory_game_start(GMEMORY_GAME(game));
176
177         /* Display widgets and show window. */
178         gtk_widget_show_all(main_vbox);
179         gtk_widget_show(window);
180
181         /* Show clutter actors after the widgets to avoid flickering. */
182         clutter_actor_show(stage);
183
184         gtk_main();
185
186         return EXIT_SUCCESS;
187 }
188
189 /* Callbacks. */
190 static gboolean
191 delete_event(G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEvent *event,
192              G_GNUC_UNUSED gpointer data) {
193         return FALSE;
194 }
195
196 static void
197 destroy(G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gpointer data) {
198         gtk_main_quit();
199 }
200
201 static void
202 new_game_started_cb(GMemoryGame * game) {
203         g_print("New game started.\n");
204 }
205
206 static void
207 game_ended_cb(GMemoryGame * game, gboolean completed) {
208         if(completed)
209                 g_print("Congratulations. you've finished the game. ");
210
211         g_print("Press 'New' to start a new game.\n");
212 }
213
214 static void
215 set_game_size_cb (GtkClutterEmbed *embed,
216                   GtkAllocation   *allocation,
217                   GMemoryGame     *game) {
218         guint w = allocation->width;
219         guint h = allocation->height;
220         clutter_actor_set_size(CLUTTER_ACTOR(game), w, h);
221 }
222
223 /* Action callbacks.*/
224 static void
225 new_action (GtkAction *action, gpointer data) {
226         gmemory_game_start(game);
227 }
228
229 static void
230 quit_action (GtkAction *action, gpointer data) {
231         destroy(NULL, NULL);
232 }
233
234 static void
235 about_action (GtkAction *action, gpointer data) {
236         GtkWindow *window = GTK_WINDOW(data);
237
238         const char *authors[] = {
239                _("Main game:"),
240                "Chris Kühl <chrisk@openismus.com>",
241                NULL
242         };
243
244         gtk_show_about_dialog(window, "program-name", _("GMemory"),
245                                       "title",        _("About GMemory"),
246                                       "authors",      authors,
247                                       NULL);
248 }