cleaning up

This commit is contained in:
Bernardo Magri
2025-04-10 17:15:14 +01:00
parent 2a1d45f998
commit b5f75a29b7
6 changed files with 252 additions and 281 deletions

View File

@@ -11,6 +11,8 @@ res = gnome.compile_resources(
) )
deps = dependency(['gtkmm-4.0', 'sigc++-3.0']) deps = dependency(['gtkmm-4.0', 'sigc++-3.0'])
src = ['src/window.cpp', 'src/window.hpp', 'src/minefield.hpp', 'src/minefield.cpp', res] src = ['src/window.cpp', 'src/window.hpp', 'src/minefield.hpp', 'src/minefield.cpp',
'src/timer.hpp', 'src/timer.cpp', res]
exe = executable('minesweeper', src, dependencies : deps, install : true) exe = executable('minesweeper', src, dependencies : deps, install : true)

View File

@@ -1,30 +0,0 @@
#include "MineField.hpp"
#include <iostream>
int main() {
MineField field(160,160, 100);
srand(time(NULL));
int x = rand() % 160;
int y = rand() % 160;
field.initBombs(x, y);
printf("Opened cell: %i %i\n", x, y);
printf("Neighboor bombs: %i\n", field.bombsNearby(x,y));
while(!field.isGameOver()) {
x = rand() % 160;
y = rand() % 160;
if(field.clearCell(x, y)) {
printf("Opened cell: %i %i\n", x, y);
printf("Neighboor bombs: %i\n", field.bombsNearby(x,y));
}
else {
printf("Bomb found in cell: %i %i\n", x, y);
}
}
}

View File

@@ -1,166 +1,158 @@
#include "minefield.hpp" #include "minefield.hpp"
#include <iostream> #include <iostream>
MineField::MineField(int cols, int rows, int mines): m_rows(rows), MineField::MineField(int cols, int rows, int mines) : m_rows(rows),
m_cols(cols), m_cols(cols),
m_totalMines(mines), m_totalMines(mines),
m_remainingFlags(mines), m_remainingFlags(mines),
m_openCells(0), m_openCells(0),
m_exploded(false) { m_gameOver(false)
for(int i=0; i< m_cols*m_rows; i++) { {
for (int i = 0; i < m_cols * m_rows; i++)
{
std::shared_ptr<Cell> cell = std::make_shared<Cell>(); std::shared_ptr<Cell> cell = std::make_shared<Cell>();
m_cells.push_back(cell); m_cells.push_back(cell);
} }
} }
MineField::~MineField() { MineField::~MineField()
if(m_timerRunning) { {
stopTimer(); m_cells.clear();
}
} }
void MineField::timerTick() { void MineField::initBombs(int x, int y)
{
auto start = std::chrono::system_clock::now();
while(m_timerRunning) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
auto now = std::chrono::system_clock::now();
const auto duration = now - start;
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
m_time += ms.count();
timerSignal.emit(m_time);
start = std::chrono::system_clock::now();
}
}
void MineField::startTimer() {
m_time = 0;
m_timerRunning = true;
m_timerThread = std::thread(&MineField::timerTick, this);
}
void MineField::stopTimer() {
m_timerRunning = false;
if(m_timerThread.joinable()) {
m_timerThread.join();
}
}
void MineField::initBombs(int x, int y) {
int remainingMines = m_totalMines; int remainingMines = m_totalMines;
int startPos = x + y * m_rows; int startPos = x + y * m_rows;
srand(time(NULL)); //initialize rand() srand(time(NULL)); // initialize rand()
while(remainingMines > 0) { while (remainingMines > 0)
{
int position = rand() % (m_cols * m_rows); int position = rand() % (m_cols * m_rows);
if(isBomb(position % m_cols, position / m_cols) || position == startPos) { if (isBomb(position % m_cols, position / m_cols) || position == startPos)
{
continue; continue;
} }
m_cells.at(position)->isBomb = true; m_cells.at(position)->isBomb = true;
--remainingMines; --remainingMines;
} }
startTimer();
//init the timer to zero and start the timer thread
//timerThread.detach(); //not sure if this is okay (better to call join() when I set the condition to stop the thread)
} }
bool MineField::openCell(int x, int y) { bool MineField::openCell(int x, int y)
if(isBomb(x, y)) { {
m_exploded = true; if (isBomb(x, y))
{
m_gameOver = true;
gameOverSignal.emit(); gameOverSignal.emit();
stopTimer(); // stopTimer();
return false; return false;
} }
setOpenCell(x, y); setOpenCell(x, y);
if (bombsNearby(x, y) == 0) { if (bombsNearby(x, y) == 0)
{
openNeighboorhood(x, y); openNeighboorhood(x, y);
} }
return true; return true;
} }
void MineField::computeBombsNearby(int x, int y) { void MineField::computeBombsNearby(int x, int y)
int total = 0; {
//compute bombs in neighboorhood int total = 0;
for(int i=-1; i<2; i++) { // compute bombs in neighboorhood
for(int j=-1; j<2; j++) { for (int i = -1; i < 2; i++)
if(x+i >= 0 && x+i < m_cols && y+j >= 0 && y+j < m_rows) { {
if(isBomb(x+i, y+j)){ for (int j = -1; j < 2; j++)
++total; {
} if (x + i >= 0 && x + i < m_cols && y + j >= 0 && y + j < m_rows)
{
if (isBomb(x + i, y + j))
{
++total;
}
} }
} }
} }
m_cells.at(x + y * m_rows)->bombsNearby = total; m_cells.at(x + y * m_rows)->bombsNearby = total;
} }
void MineField::openNeighboorhood(int x, int y) { void MineField::openNeighboorhood(int x, int y)
//compute bombs in neighboorhood {
for(int i=-1; i<2; i++) { // compute bombs in neighboorhood
for(int j=-1; j<2; j++) { for (int i = -1; i < 2; i++)
if(x+i >= 0 && x+i < m_cols && y+j >= 0 && y+j < m_rows) { {
if((isOpened(x+i, y+j) == false) && (isBomb(x+i, y+j) == false)){ for (int j = -1; j < 2; j++)
setOpenCell((x+i), (y+j)); {
if(bombsNearby(x+i, y+j) == 0) { if (x + i >= 0 && x + i < m_cols && y + j >= 0 && y + j < m_rows)
openNeighboorhood(x+i, y+j); {
} if ((isOpened(x + i, y + j) == false) && (isBomb(x + i, y + j) == false))
} {
setOpenCell((x + i), (y + j));
if (bombsNearby(x + i, y + j) == 0)
{
openNeighboorhood(x + i, y + j);
}
}
} }
} }
} }
} }
bool MineField::isOpened(int x, int y) { bool MineField::isOpened(int x, int y)
{
return m_cells.at(x + y * m_rows)->isCleared; return m_cells.at(x + y * m_rows)->isCleared;
} }
bool MineField::isFlagged(int x, int y) { bool MineField::isFlagged(int x, int y)
{
return m_cells.at(x + y * m_rows)->isFlagged; return m_cells.at(x + y * m_rows)->isFlagged;
} }
bool MineField::isBomb(int x, int y) { bool MineField::isBomb(int x, int y)
{
return m_cells.at(x + y * m_rows)->isBomb; return m_cells.at(x + y * m_rows)->isBomb;
} }
int MineField::bombsNearby(int x, int y) { int MineField::bombsNearby(int x, int y)
if(m_cells.at(x + y * m_rows)->bombsNearby == -1) { {
if (m_cells.at(x + y * m_rows)->bombsNearby == -1)
{
computeBombsNearby(x, y); computeBombsNearby(x, y);
} }
return m_cells.at(x + y * m_rows)->bombsNearby; return m_cells.at(x + y * m_rows)->bombsNearby;
} }
void MineField::setOpenCell(int x, int y) { void MineField::setOpenCell(int x, int y)
{
m_cells.at(x + y * m_rows)->isCleared = true; m_cells.at(x + y * m_rows)->isCleared = true;
openCellSignal.emit(x, y); openCellSignal.emit(x, y);
++m_openCells; ++m_openCells;
checkGameWon(); checkGameWon();
} }
void MineField::checkGameWon() { void MineField::checkGameWon()
if((m_openCells == (m_cols * m_rows - m_totalMines)) && (m_exploded == false) && (m_remainingFlags == 0)) { {
if ((m_openCells == (m_cols * m_rows - m_totalMines)) && (m_gameOver == false) && (m_remainingFlags == 0))
{
m_gameWon = true; m_gameWon = true;
stopTimer();
gameWonSignal.emit(); gameWonSignal.emit();
} }
std::cout << "Open cells: " << m_openCells << "\n" << "Remaining Flags: " << m_remainingFlags << "\n";
} }
bool MineField::toggleFlag(int x, int y) { bool MineField::toggleFlag(int x, int y)
if(m_cells.at(x + y * m_rows)->isFlagged == true) { {
if (m_cells.at(x + y * m_rows)->isFlagged == true)
{
m_cells.at(x + y * m_rows)->isFlagged = false; m_cells.at(x + y * m_rows)->isFlagged = false;
++m_remainingFlags; ++m_remainingFlags;
remainingFlagsSignal.emit(m_remainingFlags); remainingFlagsSignal.emit(m_remainingFlags);
return true; return true;
} }
else if(m_remainingFlags > 0) { else if (m_remainingFlags > 0)
{
m_cells.at(x + y * m_rows)->isFlagged = true; m_cells.at(x + y * m_rows)->isFlagged = true;
--m_remainingFlags; --m_remainingFlags;
remainingFlagsSignal.emit(m_remainingFlags); remainingFlagsSignal.emit(m_remainingFlags);

View File

@@ -1,43 +1,35 @@
#pragma once #pragma once
#include <atomic> #include <cstdlib>
#include <sigc++/signal.h>
#include <utility>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <memory> #include <memory>
#include <thread> #include <sigc++/signal.h>
#include <chrono> #include <vector>
struct Cell { class MineField
bool isFlagged; {
bool isCleared;
bool isBomb; struct Cell
int bombsNearby; {
Cell(): isFlagged(false), isCleared(false), isBomb(false), bombsNearby(-1) {}; bool isFlagged = false;
}; bool isCleared = false;
bool isBomb = false;
int bombsNearby = -1;
};
class MineField {
std::vector<std::shared_ptr<Cell>> m_cells; std::vector<std::shared_ptr<Cell>> m_cells;
int m_rows; int m_rows;
int m_cols; int m_cols;
int m_totalMines; int m_totalMines;
int m_remainingFlags; int m_remainingFlags;
int m_openCells; int m_openCells;
bool m_exploded; bool m_gameOver;
bool m_gameWon; bool m_gameWon;
size_t m_time;
std::atomic_bool m_timerRunning;
std::thread m_timerThread;
void computeBombsNearby(int x, int y); void computeBombsNearby(int x, int y);
void openNeighboorhood(int x, int y); void openNeighboorhood(int x, int y);
void setOpenCell(int x, int y); void setOpenCell(int x, int y);
void checkGameWon(); void checkGameWon();
void timerTick();
void startTimer();
void stopTimer();
public: public:
MineField(int cols, int rows, int mines); MineField(int cols, int rows, int mines);
~MineField(); ~MineField();
@@ -47,18 +39,16 @@ public:
bool isOpened(int x, int y); bool isOpened(int x, int y);
bool openCell(int x, int y); bool openCell(int x, int y);
int bombsNearby(int x, int y); int bombsNearby(int x, int y);
bool isGameOver() {return m_exploded; }; bool isGameOver() { return m_gameOver; };
int getCols() {return m_cols; }; int getCols() { return m_cols; };
int getRows() {return m_rows; }; int getRows() { return m_rows; };
bool toggleFlag(int x, int y); bool toggleFlag(int x, int y);
int getRemainingFlags() {return m_remainingFlags; }; int getRemainingFlags() { return m_remainingFlags; };
size_t getCurrentTime() {return m_time; }; int getTotalMines() { return m_totalMines; };
int getTotalMines() {return m_totalMines; };
void startNewGame(int cols, int rows, int mines); void startNewGame(int cols, int rows, int mines);
sigc::signal<void(int, int)> openCellSignal; sigc::signal<void(int, int)> openCellSignal;
sigc::signal<void(int)> remainingFlagsSignal; sigc::signal<void(int)> remainingFlagsSignal;
sigc::signal<void(void)> gameWonSignal; sigc::signal<void(void)> gameWonSignal;
sigc::signal<void(void)> gameOverSignal; sigc::signal<void(void)> gameOverSignal;
sigc::signal<void(size_t)> timerSignal;
}; };

View File

@@ -3,7 +3,6 @@
#include "sigc++/adaptors/bind.h" #include "sigc++/adaptors/bind.h"
#include "sigc++/functors/mem_fun.h" #include "sigc++/functors/mem_fun.h"
//} //}
// void MainWindow::ApplyStyles() { // void MainWindow::ApplyStyles() {
// // Load and apply the CSS file // // Load and apply the CSS file
@@ -12,21 +11,25 @@
// Gtk::StyleContext::add_provider_for_display(Gdk::Display::get_default(), css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER); // 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 MainWindow::OnCellRightClick(int n_press, double n_x, double n_y, int index)
{
(void)n_press, (void)n_x, (void)n_y; (void)n_press, (void)n_x, (void)n_y;
int x = index % field.getCols(); int x = index % field.getCols();
int y = index / field.getCols(); int y = index / field.getCols();
int pos = x + y * field.getRows(); int pos = x + y * field.getRows();
if(field.isOpened(x, y) == false) { if (field.isOpened(x, y) == false)
{
field.toggleFlag(x, y); field.toggleFlag(x, y);
if(field.isFlagged(x, y)) { if (field.isFlagged(x, y))
{
auto imgflag = Gtk::make_managed<Gtk::Image>(); auto imgflag = Gtk::make_managed<Gtk::Image>();
imgflag->set(m_textureFlag); imgflag->set(m_textureFlag);
buttons.at(pos)->set_child(*imgflag); buttons.at(pos)->set_child(*imgflag);
buttons.at(pos)->set_active(true); buttons.at(pos)->set_active(true);
} }
else { else
{
buttons.at(pos)->unset_child(); buttons.at(pos)->unset_child();
buttons.at(pos)->queue_draw(); buttons.at(pos)->queue_draw();
buttons.at(pos)->set_active(false); buttons.at(pos)->set_active(false);
@@ -34,7 +37,8 @@ void MainWindow::OnCellRightClick(int n_press, double n_x, double n_y, int index
} }
} }
void MainWindow::updateFlagsLabel(int flags) { void MainWindow::updateFlagsLabel(int flags)
{
Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", flags); Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", flags);
flagLabel.set_label(msg); flagLabel.set_label(msg);
} }
@@ -57,78 +61,89 @@ void MainWindow::updateFlagsLabel(int flags) {
// clockConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::UpdateClockLabel), 100); // 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))
{
void MainWindow::OnCellClick(int x, int y) { buttons.at(x + y * field.getRows())->set_active(true);
if (newGame) { }
field.initBombs(x, y); else
newGame = false; {
field.openCell(x, y);
if (field.isBomb(x, y))
{
openBombs();
} }
}
}
if(field.isFlagged(x, y)) { void MainWindow::openBombs()
buttons.at(x + y * field.getRows())->set_active(true); {
} for (int i = 0; i < field.getCols() * field.getRows(); i++)
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 x = i % field.getCols();
int y = i / field.getCols(); int y = i / field.getCols();
buttons.at(i)->set_sensitive(false); buttons.at(i)->set_sensitive(false);
if(field.isBomb(x, y)) { if (field.isBomb(x, y))
if(field.isFlagged(x, y)) { {
auto imgFlagBomb = std::make_shared<Gtk::Image>(); if (field.isFlagged(x, y))
imgFlagBomb->set(m_textureFlagBomb); {
buttons.at(i)->set_child(*imgFlagBomb); auto imgFlagBomb = std::make_shared<Gtk::Image>();
imgFlagBomb->set(m_textureFlagBomb);
buttons.at(i)->set_child(*imgFlagBomb);
} }
else { else
auto imgBomb = std::make_shared<Gtk::Image>(); {
imgBomb->set(m_textureBomb); auto imgBomb = std::make_shared<Gtk::Image>();
buttons.at(i)->set_child(*imgBomb); imgBomb->set(m_textureBomb);
buttons.at(i)->set_child(*imgBomb);
} }
buttons.at(i)->set_active(true); buttons.at(i)->set_active(true);
} }
} }
} }
void MainWindow::updateCell(int x, int y) { void MainWindow::updateCell(int x, int y)
{
int pos = x + y * field.getRows(); int pos = x + y * field.getRows();
if(field.isOpened(x, y)) { if (field.isOpened(x, y))
if (field.bombsNearby(x, y) > 0) { {
switch(field.bombsNearby(x, y)) { if (field.bombsNearby(x, y) > 0)
{
switch (field.bombsNearby(x, y))
{
case 1: case 1:
buttons.at(pos)->get_style_context()->add_class("label-1"); buttons.at(pos)->get_style_context()->add_class("label-1");
break; break;
case 2: case 2:
buttons.at(pos)->get_style_context()->add_class("label-2"); buttons.at(pos)->get_style_context()->add_class("label-2");
break; break;
case 3: case 3:
buttons.at(pos)->get_style_context()->add_class("label-3"); buttons.at(pos)->get_style_context()->add_class("label-3");
break; break;
case 4: case 4:
buttons.at(pos)->get_style_context()->add_class("label-4"); buttons.at(pos)->get_style_context()->add_class("label-4");
break; break;
case 5: case 5:
buttons.at(pos)->get_style_context()->add_class("label-5"); buttons.at(pos)->get_style_context()->add_class("label-5");
break; break;
case 6: case 6:
buttons.at(pos)->get_style_context()->add_class("label-6"); buttons.at(pos)->get_style_context()->add_class("label-6");
break; break;
case 7: case 7:
buttons.at(pos)->get_style_context()->add_class("label-7"); buttons.at(pos)->get_style_context()->add_class("label-7");
break; break;
case 8: case 8:
buttons.at(pos)->get_style_context()->add_class("label-8"); buttons.at(pos)->get_style_context()->add_class("label-8");
break; break;
} }
buttons.at(pos)->set_label(Glib::ustring::format(field.bombsNearby(x, y))); buttons.at(pos)->set_label(Glib::ustring::format(field.bombsNearby(x, y)));
} }
@@ -150,7 +165,6 @@ void MainWindow::updateCell(int x, int y) {
// } // }
// } // }
// bool MainWindow::AllCellsOpened() // bool MainWindow::AllCellsOpened()
// { // {
// for(int i=0; i<COLS * COLS; i++) { // for(int i=0; i<COLS * COLS; i++) {
@@ -159,28 +173,30 @@ void MainWindow::updateCell(int x, int y) {
// } // }
// return true; // return true;
// } // }
void MainWindow::gameOver() { void MainWindow::gameOver()
//clockSignalConn.disconnect(); {
//std::cout << "Signal gameOver emmited\n"; // clockSignalConn.disconnect();
// std::cout << "Signal gameOver emmited\n";
} }
void MainWindow::updateClockLabel() void MainWindow::updateClockLabel()
{ {
size_t time = field.getCurrentTime(); size_t time = 100; // field.getCurrentTime();
int deciseconds = (time / 100) % 10; int deciseconds = (time / 100) % 10;
int seconds = (time / 1000) % 60; int seconds = (time / 1000) % 60;
int minutes = (time /60000) % 60; int minutes = (time / 60000) % 60;
Glib::ustring msg = Glib::ustring::compose("Elapsed time: %1:%2.%3", \ 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), minutes),
Glib::ustring::format(std::setfill(L'0'), std::setw(2), seconds), \ Glib::ustring::format(std::setfill(L'0'), std::setw(2), seconds),
Glib::ustring::format(std::setfill(L'0'), std::setw(1), deciseconds)); Glib::ustring::format(std::setfill(L'0'), std::setw(1), deciseconds));
clockLabel.set_label(msg); clockLabel.set_label(msg);
} }
void MainWindow::handleClockSig(size_t time) { void MainWindow::handleClockSig(size_t time)
{
(void)time; (void)time;
m_clockDispatch.emit(); m_clockDispatch.emit();
} }
@@ -198,7 +214,7 @@ MainWindow::MainWindow()
boxH = Gtk::Box(Gtk::Orientation::HORIZONTAL); boxH = Gtk::Box(Gtk::Orientation::HORIZONTAL);
boxH.set_hexpand(true); boxH.set_hexpand(true);
boxV.append(boxH); boxV.append(boxH);
boxH.set_expand(true); boxH.set_expand(true);
@@ -206,34 +222,33 @@ MainWindow::MainWindow()
labelMines.set_margin_top(12); labelMines.set_margin_top(12);
labelMines.set_margin_start(12); labelMines.set_margin_start(12);
labelMines.set_label(Glib::ustring::compose("Total mines: %1", field.getTotalMines())); labelMines.set_label(Glib::ustring::compose("Total mines: %1", field.getTotalMines()));
//labelMines.set_hexpand(true); // labelMines.set_hexpand(true);
Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field.getRemainingFlags()); Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field.getRemainingFlags());
flagLabel = Gtk::Label(msg); flagLabel = Gtk::Label(msg);
flagLabel.set_margin_top(12); flagLabel.set_margin_top(12);
flagLabel.set_margin_start(12); flagLabel.set_margin_start(12);
flagLabel.set_margin_end(12); flagLabel.set_margin_end(12);
//flagLabel.set_hexpand(true); // flagLabel.set_hexpand(true);
clockLabel.set_margin_top(12); clockLabel.set_margin_top(12);
//clockLabel.set_margin_start(12); // clockLabel.set_margin_start(12);
//Clocklabel.set_margin_end(12); // Clocklabel.set_margin_end(12);
clockLabel.set_hexpand(true); clockLabel.set_hexpand(true);
Glib::ustring clockmsg = Glib::ustring::compose("Elapsed time: 00:00.0"); Glib::ustring clockmsg = Glib::ustring::compose("Elapsed time: 00:00.0");
clockLabel.set_label(clockmsg); clockLabel.set_label(clockmsg);
boxH.append(labelMines); boxH.append(labelMines);
boxH.append(clockLabel); boxH.append(clockLabel);
boxH.append(flagLabel); boxH.append(flagLabel);
// TODO check if it's okay to mix std::shared_ptr with Gdk::ptr
//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_textureBomb = Gdk::Texture::create_from_resource("/minesweeper/bomb-solid");
m_textureFlag = Gdk::Texture::create_from_resource("/minesweeper/flag-solid"); m_textureFlag = Gdk::Texture::create_from_resource("/minesweeper/flag-solid");
m_textureFlagBomb = Gdk::Texture::create_from_resource("/minesweeper/flag-bomb"); m_textureFlagBomb = Gdk::Texture::create_from_resource("/minesweeper/flag-bomb");
// bombPix.set_from_resource("/minesweeper/bomb-solid"); // bombPix.set_from_resource("/minesweeper/bomb-solid");
auto css_provider = Gtk::CssProvider::create(); auto css_provider = Gtk::CssProvider::create();
css_provider->load_from_data( css_provider->load_from_data(
".label-1 { font-weight: bold; font-size: 1.5em; color: Blue; }\ ".label-1 { font-weight: bold; font-size: 1.5em; color: Blue; }\
@@ -244,11 +259,12 @@ MainWindow::MainWindow()
.label-6 { font-weight: bold; font-size: 1.5em; color: Salmon; }\ .label-6 { font-weight: bold; font-size: 1.5em; color: Salmon; }\
.label-7 { font-weight: bold; font-size: 1.5em; color: Turquoise; }\ .label-7 { font-weight: bold; font-size: 1.5em; color: Turquoise; }\
.label-8 { font-weight: bold; font-size: 1.5em; color: Magenta; }"); .label-8 { font-weight: bold; font-size: 1.5em; color: Magenta; }");
auto display = Gdk::Display::get_default(); auto display = Gdk::Display::get_default();
Gtk::StyleContext::add_provider_for_display(display, css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER); Gtk::StyleContext::add_provider_for_display(display, css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
for (int i = 0; i < field.getCols() * field.getRows(); i++) { for (int i = 0; i < field.getCols() * field.getRows(); i++)
{
auto button = std::make_shared<Gtk::ToggleButton>(); auto button = std::make_shared<Gtk::ToggleButton>();
button->set_size_request(50, 40); button->set_size_request(50, 40);
button->set_sensitive(true); button->set_sensitive(true);
@@ -257,55 +273,57 @@ MainWindow::MainWindow()
int y = i / field.getRows(); int y = i / field.getRows();
button->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::OnCellClick), x, y)); button->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::OnCellClick), x, y));
//button->get_style_context()->add_class("fixed-button"); // button->get_style_context()->add_class("fixed-button");
auto gesture = Gtk::GestureClick::create(); auto gesture = Gtk::GestureClick::create();
gesture->set_button(3); gesture->set_button(3);
gesture->signal_released().connect(sigc::bind(sigc::mem_fun(*this, \ gesture->signal_released().connect(sigc::bind(sigc::mem_fun(*this,
&MainWindow::OnCellRightClick), i)); &MainWindow::OnCellRightClick),
i));
button->add_controller(gesture); button->add_controller(gesture);
buttons.push_back(button); buttons.push_back(button);
grid.attach(*button, x, y); grid.attach(*button, x, y);
} }
field.openCellSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateCell))); field.openCellSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateCell)));
field.remainingFlagsSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateFlagsLabel))); field.remainingFlagsSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateFlagsLabel)));
field.gameOverSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::gameOver))); field.gameOverSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::gameOver)));
//newGameButton.set_label("New"); // newGameButton.set_label("New");
//newGameButton.add_css_class("suggested-action"); // newGameButton.add_css_class("suggested-action");
//newGameButton.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnNewButtonClick)); // newGameButton.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnNewButtonClick));
//optionButton.set_icon_name("open-menu"); // optionButton.set_icon_name("open-menu");
field.timerSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::handleClockSig))); // field.timerSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::handleClockSig)));
m_clockDispatch.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateClockLabel))); m_clockDispatch.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateClockLabel)));
//field.timerSignal.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(); // if (clockSignalConn.connected()) clockSignalConn.disconnect();
//elapsedTime = 0; // elapsedTime = 0;
//clockSignalConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::updateClockLabel), 100); // clockSignalConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::updateClockLabel), 100);
//} // }
//create the minefield // create the minefield
//field = new MineField(COLS, MINES); // field = new MineField(COLS, MINES);
//bar.pack_start(newGameButton); // bar.pack_start(newGameButton);
//bar.pack_end(optionButton); // bar.pack_end(optionButton);
//grid.set_row_homogeneous(false); // grid.set_row_homogeneous(false);
//grid.set_column_homogeneous(false); // grid.set_column_homogeneous(false);
grid.set_margin(10); grid.set_margin(10);
//grid.set_vexpand(true); // grid.set_vexpand(true);
//grid.set_hexpand(true); // grid.set_hexpand(true);
// grid.set_fill(false); // grid.set_fill(false);
boxV.append(grid); boxV.append(grid);
this->set_titlebar(bar); this->set_titlebar(bar);
this->set_child(boxV); this->set_child(boxV);
} }
int main(int argc, char **argv) { int main(int argc, char **argv)
auto app = Gtk::Application::create("eu.minesweeper"); {
auto app = Gtk::Application::create("eu.bernardomagri.minesweeper");
return app->make_window_and_run<MainWindow>(argc, argv); return app->make_window_and_run<MainWindow>(argc, argv);
} }

View File

@@ -12,10 +12,9 @@
#define PROJECT_NAME "minesweeper" #define PROJECT_NAME "minesweeper"
class MainWindow : public Gtk::Window class MainWindow : public Gtk::Window
{ {
Gtk::Box boxV{Gtk::Orientation::VERTICAL}; Gtk::Box boxV{Gtk::Orientation::VERTICAL};
Gtk::Box boxH{Gtk::Orientation::HORIZONTAL}; Gtk::Box boxH{Gtk::Orientation::HORIZONTAL};
std::vector<std::shared_ptr<Gtk::ToggleButton>> buttons; std::vector<std::shared_ptr<Gtk::ToggleButton>> buttons;
Gtk::Grid grid; Gtk::Grid grid;
@@ -24,7 +23,7 @@ class MainWindow : public Gtk::Window
Gtk::Button optionButton; Gtk::Button optionButton;
Gtk::Label flagLabel; Gtk::Label flagLabel;
Gtk::Label clockLabel; Gtk::Label clockLabel;
MineField field {16, 16, 1}; MineField field{16, 16, 1};
int m_elapsedTime; int m_elapsedTime;
bool newGame; bool newGame;
std::shared_ptr<Gdk::Texture> m_textureBomb; std::shared_ptr<Gdk::Texture> m_textureBomb;
@@ -39,16 +38,16 @@ class MainWindow : public Gtk::Window
void gameOver(); void gameOver();
sigc::connection clockSignalConn; sigc::connection clockSignalConn;
Glib::Dispatcher m_clockDispatch; Glib::Dispatcher m_clockDispatch;
// void OpenNearCells(int index); // void OpenNearCells(int index);
// void Explode();xo // void Explode();xo
// bool AllCellsOpened(); // bool AllCellsOpened();
public: public:
MainWindow(); MainWindow();
// void OnNewButtonClick(); // void OnNewButtonClick();
void OnCellClick(int x, int y); void OnCellClick(int x, int y);
void OnCellRightClick(int n_press, double n_x, double n_y, int index); void OnCellRightClick(int n_press, double n_x, double n_y, int index);
// void ShowGameWonAnimation(); // void ShowGameWonAnimation();
// void ApplyStyles(); // void ApplyStyles();
// bool UpdateClockLabel(); // bool UpdateClockLabel();
}; };