#include "window.hpp" #include "gdkmm/texture.h" #include "sigc++/adaptors/bind.h" #include "sigc++/functors/mem_fun.h" //} // 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.getCols(); int pos = x + y * field.getRows(); if (field.isOpened(x, y) == false) { field.toggleFlag(x, y); if (field.isFlagged(x, y)) { auto imgflag = Gtk::make_managed(); imgflag->set(m_textureFlag); buttons.at(pos)->set_child(*imgflag); buttons.at(pos)->set_active(true); } else { buttons.at(pos)->unset_child(); buttons.at(pos)->queue_draw(); buttons.at(pos)->set_active(false); } } } 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::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 { field.openCell(x, y); if (field.isBomb(x, y)) { openBombs(); } } } void MainWindow::openBombs() { for (int i = 0; i < field.getCols() * field.getRows(); i++) { int x = i % field.getCols(); int y = i / field.getCols(); buttons.at(i)->set_sensitive(false); if (field.isBomb(x, y)) { if (field.isFlagged(x, y)) { auto imgFlagBomb = std::make_shared(); imgFlagBomb->set(m_textureFlagBomb); buttons.at(i)->set_child(*imgFlagBomb); } else { auto imgBomb = std::make_shared(); imgBomb->set(m_textureBomb); buttons.at(i)->set_child(*imgBomb); } buttons.at(i)->set_active(true); } } } void MainWindow::updateCell(int x, int y) { int pos = x + y * field.getRows(); if (field.isOpened(x, y)) { if (field.bombsNearby(x, y) > 0) { switch (field.bombsNearby(x, y)) { case 1: buttons.at(pos)->get_style_context()->add_class("label-1"); break; case 2: buttons.at(pos)->get_style_context()->add_class("label-2"); break; case 3: buttons.at(pos)->get_style_context()->add_class("label-3"); break; case 4: buttons.at(pos)->get_style_context()->add_class("label-4"); break; case 5: buttons.at(pos)->get_style_context()->add_class("label-5"); break; case 6: buttons.at(pos)->get_style_context()->add_class("label-6"); break; case 7: buttons.at(pos)->get_style_context()->add_class("label-7"); break; case 8: buttons.at(pos)->get_style_context()->add_class("label-8"); break; } buttons.at(pos)->set_label(Glib::ustring::format(field.bombsNearby(x, y))); } buttons.at(pos)->set_active(true); buttons.at(pos)->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(); // 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; iget_active()) // return false; // } // return true; // } void MainWindow::gameOver() { // clockSignalConn.disconnect(); // std::cout << "Signal gameOver emmited\n"; } void MainWindow::updateClockLabel() { size_t time = 100; // field.getCurrentTime(); int deciseconds = (time / 100) % 10; int seconds = (time / 1000) % 60; int minutes = (time / 60000) % 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); } void MainWindow::handleClockSig(size_t time) { (void)time; m_clockDispatch.emit(); } MainWindow::MainWindow() { // ApplyStyles(); // Load the CSS file m_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_textureBomb = Gdk::Texture::create_from_resource("/minesweeper/bomb-solid"); m_textureFlag = Gdk::Texture::create_from_resource("/minesweeper/flag-solid"); m_textureFlagBomb = Gdk::Texture::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(); 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.openCellSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateCell))); field.remainingFlagsSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateFlagsLabel))); field.gameOverSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::gameOver))); // 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"); // field.timerSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::handleClockSig))); m_clockDispatch.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateClockLabel))); // field.timerSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateClockLabel))); // if (clockSignalConn.connected()) clockSignalConn.disconnect(); // elapsedTime = 0; // clockSignalConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::updateClockLabel), 100); // } // 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.bernardomagri.minesweeper"); return app->make_window_and_run(argc, argv); }