1/*
2 * Color lines for GNOME
3 * Copyright © 1999 Free Software Foundation
4 * Authors: Robert Szokovacs <szo@appaloosacorp.hu>
5 *          Szabolcs Ban <shooby@gnome.hu>
6 *          Karuna Grewal <karunagrewal98@gmail.com>
7 *          Ruxandra Simion <ruxandra.simion93@gmail.com>
8 * Copyright © 2007 Christian Persch
9 *
10 * This game is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <https://www.gnu.org/licenses/>.
22 */
23
24[GtkTemplate (ui = "/org/gnome/five-or-more/ui/five-or-more.ui")]
25public class GameWindow : Gtk.ApplicationWindow
26{
27    [GtkChild]
28    private Gtk.HeaderBar headerbar;
29
30    [GtkChild]
31    private Gtk.Box preview_hbox;
32
33    [GtkChild]
34    private Gtk.MenuButton primary_menu_button;
35
36    [GtkChild]
37    private Games.GridFrame grid_frame;
38
39    private Settings? settings = null;
40    private bool window_tiled;
41    public bool window_maximized { get; private set; }
42    public int window_width { get; private set; }
43    public int window_height { get; private set; }
44
45    private Game? game = null;
46    private ThemeRenderer? theme = null;
47
48    private Games.Scores.Context highscores;
49    private string[] status = {
50            _("Match five objects of the same type in a row to score!"),
51            _("You can’t move there!"),
52            _("Game Over!"),
53            _("Score: %d")
54    };
55
56    public GameWindow (Gtk.Application app, Settings settings)
57    {
58        Object (application: app);
59
60        this.settings = settings;
61        game = new Game (settings);
62        theme = new ThemeRenderer (settings);
63
64        set_default_size (settings.get_int ("window-width"), settings.get_int ("window-height"));
65        if (settings.get_boolean ("window-is-maximized"))
66            maximize ();
67
68        NextPiecesWidget next_pieces_widget = new NextPiecesWidget (settings, game, theme);
69        preview_hbox.pack_start (next_pieces_widget);
70        next_pieces_widget.realize ();
71        next_pieces_widget.show ();
72
73        grid_frame.set (game.n_cols, game.n_rows);
74        game.board.board_changed.connect (() => { grid_frame.set (game.n_cols, game.n_rows); });
75        game.notify["score"].connect ((s, p) => { set_status_message (status[StatusMessage.NONE].printf(game.score)); });
76        game.notify["status-message"].connect ((s, p) => { set_status_message (status[game.status_message].printf(game.score)); });
77        set_status_message (status[game.status_message]);
78
79        View game_view = new View (settings, game, theme);
80        grid_frame.add (game_view);
81        game_view.show ();
82
83        grid_frame.show ();
84
85        var importer = new Games.Scores.DirectoryImporter ();
86        highscores = new Games.Scores.Context.with_importer ("five-or-more",
87                                                _("Board Size: "),
88                                                this,
89                                                create_category_from_key,
90                                                Games.Scores.Style.POINTS_GREATER_IS_BETTER,
91                                                importer);
92        game.game_over.connect (score_cb);
93    }
94
95    protected override bool window_state_event (Gdk.EventWindowState event)
96    {
97        if ((event.changed_mask & Gdk.WindowState.MAXIMIZED) != 0)
98            window_maximized = (event.new_window_state & Gdk.WindowState.MAXIMIZED) != 0;
99
100        if ((event.changed_mask & Gdk.WindowState.TILED) != 0)
101            window_tiled = (event.new_window_state & Gdk.WindowState.TILED) != 0;
102
103        return false;
104    }
105
106    protected override void size_allocate (Gtk.Allocation allocation)
107    {
108        base.size_allocate (allocation);
109
110        if (window_maximized || window_tiled)
111            return;
112
113        window_width = allocation.width;
114        window_height = allocation.height;
115    }
116
117    private void score_cb ()
118    {
119
120        string name = category_name_from_key (game.score_current_category);
121        var current_category = new Games.Scores.Category (game.score_current_category, name);
122        highscores.add_score (game.score,
123                              current_category,
124                              new Cancellable ());
125
126        show_scores ();
127    }
128
129    public void restart_game ()
130    {
131        game.restart ();
132    }
133
134    private void set_status_message (string? message)
135    {
136        headerbar.set_subtitle (message);
137    }
138
139    public void show_scores ()
140    {
141        highscores.run_dialog ();
142    }
143
144    public void change_size (BoardSize size)
145    {
146        var game_size = settings.get_int ("size");
147
148        if (game_size == size)
149            return;
150
151        primary_menu_button.set_active (false);
152
153        if (game.score > 0) {
154            var flags = Gtk.DialogFlags.DESTROY_WITH_PARENT;
155            var restart_game_dialog = new Gtk.MessageDialog (this,
156                                                             flags,
157                                                             Gtk.MessageType.WARNING,
158                                                             Gtk.ButtonsType.NONE,
159                                                             _("Are you sure you want to restart the game?"),
160                                                             null);
161            restart_game_dialog.add_buttons (_("_Cancel"), Gtk.ResponseType.CANCEL,
162                                             _("_Restart"), Gtk.ResponseType.OK,
163                                             null);
164
165            var result = restart_game_dialog.run ();
166            restart_game_dialog.destroy ();
167            switch (result)
168            {
169                case Gtk.ResponseType.OK:
170                     if (!settings.set_int (FiveOrMoreApp.KEY_SIZE, size))
171                        warning ("Failed to set size: %d", size);
172                    break;
173                case Gtk.ResponseType.CANCEL:
174                    break;
175            }
176        } else {
177            settings.set_int (FiveOrMoreApp.KEY_SIZE, size);
178        }
179
180    }
181
182    private Games.Scores.Category? create_category_from_key (string key)
183    {
184        string? name = category_name_from_key (key);
185        return new Games.Scores.Category (key, name);
186    }
187
188    private string category_name_from_key (string key)
189    {
190        for (int i = 0; i < game.n_categories; i++) {
191            if (Game.scorecats[i].key == key)
192                return Game.scorecats[i].name;
193        }
194        return "";
195    }
196}
197