| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- #include "window.hpp"
- #include "gdkmm/pixbuf.h"
- #include "gtkmm/cssprovider.h"
- #include "gtkmm/image.h"
- #include "sigc++/adaptors/bind.h"
- #include "sigc++/functors/mem_fun.h"
- #include <memory>
- //}
- // void MainWindow::ApplyStyles() {
- // // Load and apply the CSS file
- // auto css_provider = Gtk::CssProvider::create();
- // css_provider->load_from_path("style.css");
- // Gtk::StyleContext::add_provider_for_display(Gdk::Display::get_default(), css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
- // }
- void MainWindow::OnCellRightClick(int n_press, double n_x, double n_y, int index) {
- (void)n_press, (void)n_x, (void)n_y;
- int x = index % field.getCols();
- int y = index / field.getRows();
- if(field.isCleared(x, y) == false) {
- field.toggleFlag(x, y);
- if(field.isFlagged(x, y)) {
- auto imgflag = Gtk::make_managed<Gtk::Image>();
- imgflag->set(m_pixbufFlag);
- buttons.at(x + y * field.getRows())->set_child(*imgflag);
- buttons.at(x + y * field.getRows())->set_active(true);
- }
- else {
- buttons.at(x + y * field.getRows())->unset_child();
- buttons.at(x+ y * field.getRows())->queue_draw();
- buttons.at(x + y * field.getRows())->set_active(false);
- }
- }
-
- // Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field.getRemainingFlags());
- // flagLabel.set_label(msg);
- }
- void MainWindow::updateFlagsLabel(int flags) {
- Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", flags);
- flagLabel.set_label(msg);
- }
- // void MainWindow::OnNewButtonClick() {
- // newGame = true;
- // gameOver = false;
- // for (auto &button : buttons) {
- // button->set_active(false);
- // button->set_sensitive(true);
- // button->set_label("");
- // }
- // field->remainingFlags = MINES;
- // Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field->remainingFlags);
- // flagLabel.set_label(msg);
- // if (clockConn.connected()) clockConn.disconnect();
- // elapsedTime = 0;
- // clockConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::UpdateClockLabel), 100);
- // }
- // void MainWindow::OpenNearCells(int index, std::set<int> &visited) {
- // int cols = field->Cols();
- // int x = index % cols;
- // int y = index / cols;
- // if (visited.count(index)) return;
- // Cell* cell = field->GetCell(x, y);
- // if (!cell || cell->bombsNearby > 0 || cell->type == CellType::Bomb) return;
- // visited.insert(index);
- // buttons[index]->set_active(true);
- // for (int i = -1; i <= 1; i++) {
- // for (int j = -1; j <= 1; j++) {
- // if (i == 0 && j == 0) continue; // Skip the current cell
- // int nx = x + i;
- // int ny = y + j;
- // int newIndex = ny * cols + nx;
- // Cell* neighborCell = field->GetCell(nx, ny);
- // // Bounds check before recursive call
- // if (nx >= 0 && nx < cols && ny >= 0 && ny < cols) {
- // if (visited.count(newIndex) == 0) {
- // OpenNearCells(newIndex, visited);
- // }
- // if (neighborCell && !buttons[newIndex]->get_active() && !neighborCell->isFlag) {
- // OpenNearCells(newIndex, visited);
- // }
- // }
- // }
- // }
- // }
- void MainWindow::OnCellClick(int x, int y) {
- if (newGame) {
- field.initBombs(x, y);
- newGame = false;
- }
- if(field.isFlagged(x, y)) {
- buttons.at(x + y * field.getRows())->set_active(true);
- }
- else if(field.isBomb(x, y)) {
- openBombs();
- }
- else {
- field.clearCell(x, y);
- }
- }
- void MainWindow::openBombs() {
- for(int i=0; i < field.getCols() * field.getRows(); i++) {
- int x = i % field.getCols();
- int y = i / field.getRows();
- buttons.at(i)->set_sensitive(false);
- if(field.isBomb(x, y)) {
- if(field.isFlagged(x, y)) {
- auto imgFlagBomb = std::make_shared<Gtk::Image>();
- imgFlagBomb->set(m_pixbufFlagBomb);
- buttons.at(i)->set_child(*imgFlagBomb);
- }
- else {
- auto imgBomb = std::make_shared<Gtk::Image>();
- imgBomb->set(m_pixbufBomb);
- buttons.at(i)->set_child(*imgBomb);
- }
- buttons.at(i)->set_active(true);
- }
- }
- }
- void MainWindow::updateCell(int x, int y) {
- if(field.isCleared(x, y)) {
- if (field.bombsNearby(x, y) > 0) {
- switch(field.bombsNearby(x, y)) {
- case 1:
- buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-1");
- break;
- case 2:
- buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-2");
- break;
- case 3:
- buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-3");
- break;
- case 4:
- buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-4");
- break;
- case 5:
- buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-5");
- break;
- case 6:
- buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-6");
- break;
- case 7:
- buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-7");
- break;
- case 8:
- buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-8");
- break;
- }
- buttons.at(x + y * field.getRows())->set_label(Glib::ustring::format(field.bombsNearby(x, y)));
- }
- buttons.at(x + y * field.getRows())->set_active(true);
- buttons.at(x + y * field.getRows())->set_sensitive(false);
- }
- }
- // void MainWindow::ShowGameWonAnimation() {
- // // Limit the number of confetti images to 10
- // int confettiCount = 10;
- // for (int i = 0; i < confettiCount; ++i) {
- // Glib::signal_timeout().connect_once([this]() {
- // auto confetti = Gtk::make_managed<Gtk::Image>();
- // confetti->set_from_resource("/mineSweeper/confetti");
- // // Randomize position on the grid or overlay.
- // grid->attach(*confetti, rand() % COLS, rand() % COLS);
- // grid->queue_draw();
- // }, i * 100); // Add confetti with a delay of 100ms each
- // }
- // }
- // bool MainWindow::AllCellsOpened()
- // {
- // for(int i=0; i<COLS * COLS; i++) {
- // if (!buttons[i]->get_active())
- // return false;
- // }
- // return true;
- // }
- // bool MainWindow::UpdateClockLabel()
- // {
- // if(gameOver) return false;
-
- // elapsedTime++;
- // int deciseconds = elapsedTime % 10;
- // int seconds = (elapsedTime / 10) % 60;
- // int minutes = (elapsedTime /600) % 60;
- // Glib::ustring msg = Glib::ustring::compose("Elapsed time: %1:%2.%3", \
- // Glib::ustring::format(std::setfill(L'0'), std::setw(2), minutes), \
- // Glib::ustring::format(std::setfill(L'0'), std::setw(2), seconds), \
- // Glib::ustring::format(std::setfill(L'0'), std::setw(1), deciseconds));
- // clockLabel.set_label(msg);
-
- // return true;
- // }
- MainWindow::MainWindow()
- {
- // ApplyStyles(); // Load the CSS file
- elapsedTime = 0;
- newGame = true;
- set_title("MineSweeper");
- set_default_size(400, 400);
- set_resizable(false);
- boxV = Gtk::Box(Gtk::Orientation::VERTICAL);
- boxH = Gtk::Box(Gtk::Orientation::HORIZONTAL);
- boxH.set_hexpand(true);
-
- boxV.append(boxH);
- boxH.set_expand(true);
- Gtk::Label labelMines;
- labelMines.set_margin_top(12);
- labelMines.set_margin_start(12);
- labelMines.set_label(Glib::ustring::compose("Total mines: %1", field.getTotalMines()));
- //labelMines.set_hexpand(true);
-
- Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field.getRemainingFlags());
- flagLabel = Gtk::Label(msg);
- flagLabel.set_margin_top(12);
- flagLabel.set_margin_start(12);
- flagLabel.set_margin_end(12);
- //flagLabel.set_hexpand(true);
- clockLabel.set_margin_top(12);
- clockLabel.set_margin_start(12);
- clockLabel.set_margin_end(12);
- clockLabel.set_hexpand(true);
- Glib::ustring clockmsg = Glib::ustring::compose("Elapsed time: 00:00.0");
- clockLabel.set_label(clockmsg);
-
- boxH.append(labelMines);
- boxH.append(clockLabel);
- boxH.append(flagLabel);
- //TODO check if it's okay to mix std::shared_ptr with Gdk::ptr
- m_pixbufBomb = Gdk::Pixbuf::create_from_resource("/minesweeper/bomb-solid");
- m_pixbufFlag = Gdk::Pixbuf::create_from_resource("/minesweeper/flag-solid");
- m_pixbufFlagBomb = Gdk::Pixbuf::create_from_resource("/minesweeper/flag-bomb");
- // bombPix.set_from_resource("/minesweeper/bomb-solid");
-
- auto css_provider = Gtk::CssProvider::create();
- css_provider->load_from_data(
- ".label-1 { font-weight: bold; font-size: 1.5em; color: Blue; }\
- .label-2 { font-weight: bold; font-size: 1.5em; color: Green; }\
- .label-3 { font-weight: bold; font-size: 1.5em; color: Darkorange; }\
- .label-4 { font-weight: bold; font-size: 1.5em; color: Purple; }\
- .label-5 { font-weight: bold; font-size: 1.5em; color: Red; }\
- .label-6 { font-weight: bold; font-size: 1.5em; color: Salmon; }\
- .label-7 { font-weight: bold; font-size: 1.5em; color: Turquoise; }\
- .label-8 { font-weight: bold; font-size: 1.5em; color: Magenta; }");
-
- auto display = Gdk::Display::get_default();
- Gtk::StyleContext::add_provider_for_display(display, css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
-
- for (int i = 0; i < field.getCols() * field.getRows(); i++) {
- auto button = std::make_shared<Gtk::ToggleButton>();
- button->set_size_request(50, 40);
- button->set_sensitive(true);
- button->set_active(false);
- int x = i % field.getCols();
- int y = i / field.getRows();
- button->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::OnCellClick), x, y));
- //button->get_style_context()->add_class("fixed-button");
- auto gesture = Gtk::GestureClick::create();
- gesture->set_button(3);
- gesture->signal_released().connect(sigc::bind(sigc::mem_fun(*this, \
- &MainWindow::OnCellRightClick), i));
- button->add_controller(gesture);
- buttons.push_back(button);
-
- grid.attach(*button, x, y);
- }
- field.clearCellSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateCell)));
- field.remainingFlagsChangedSignal.connect(sigc::bind(sigc::mem_fun(*this, \
- &MainWindow::updateFlagsLabel)));
- //newGameButton.set_label("New");
- //newGameButton.add_css_class("suggested-action");
- //newGameButton.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnNewButtonClick));
- //optionButton.set_icon_name("open-menu");
- //create the minefield
- //field = new MineField(COLS, MINES);
- //bar.pack_start(newGameButton);
- //bar.pack_end(optionButton);
-
- //grid.set_row_homogeneous(false);
- //grid.set_column_homogeneous(false);
- grid.set_margin(10);
- //grid.set_vexpand(true);
- //grid.set_hexpand(true);
- // grid.set_fill(false);
- boxV.append(grid);
-
- this->set_titlebar(bar);
- this->set_child(boxV);
- }
- int main(int argc, char **argv) {
- auto app = Gtk::Application::create("eu.minesweeper");
- return app->make_window_and_run<MainWindow>(argc, argv);
- }
|