window.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. #include "window.hpp"
  2. #include "gdkmm/texture.h"
  3. #include "sigc++/functors/mem_fun.h"
  4. //}
  5. // void MainWindow::ApplyStyles() {
  6. // // Load and apply the CSS file
  7. // auto css_provider = Gtk::CssProvider::create();
  8. // css_provider->load_from_path("style.css");
  9. // Gtk::StyleContext::add_provider_for_display(Gdk::Display::get_default(), css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
  10. // }
  11. void MainWindow::OnCellRightClick(int n_press, double n_x, double n_y, int index) {
  12. (void)n_press, (void)n_x, (void)n_y;
  13. int x = index % field.getCols();
  14. int y = index / field.getCols();
  15. int pos = x + y * field.getRows();
  16. if(field.isOpened(x, y) == false) {
  17. field.toggleFlag(x, y);
  18. if(field.isFlagged(x, y)) {
  19. auto imgflag = Gtk::make_managed<Gtk::Image>();
  20. imgflag->set(m_textureFlag);
  21. buttons.at(pos)->set_child(*imgflag);
  22. buttons.at(pos)->set_active(true);
  23. }
  24. else {
  25. buttons.at(pos)->unset_child();
  26. buttons.at(pos)->queue_draw();
  27. buttons.at(pos)->set_active(false);
  28. }
  29. }
  30. }
  31. void MainWindow::updateFlagsLabel(int flags) {
  32. Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", flags);
  33. flagLabel.set_label(msg);
  34. }
  35. // void MainWindow::OnNewButtonClick() {
  36. // newGame = true;
  37. // gameOver = false;
  38. // for (auto &button : buttons) {
  39. // button->set_active(false);
  40. // button->set_sensitive(true);
  41. // button->set_label("");
  42. // }
  43. // //field->remainingFlags = MINES;
  44. // Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field->remainingFlags);
  45. // flagLabel.set_label(msg);
  46. // if (clockConn.connected()) clockConn.disconnect();
  47. // elapsedTime = 0;
  48. // clockConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::UpdateClockLabel), 100);
  49. // }
  50. void MainWindow::OnCellClick(int x, int y) {
  51. if (newGame) {
  52. field.initBombs(x, y);
  53. newGame = false;
  54. }
  55. if(field.isFlagged(x, y)) {
  56. buttons.at(x + y * field.getRows())->set_active(true);
  57. }
  58. else {
  59. field.openCell(x, y);
  60. if(field.isBomb(x, y)) {
  61. openBombs();
  62. }
  63. }
  64. }
  65. void MainWindow::openBombs() {
  66. for(int i=0; i < field.getCols() * field.getRows(); i++) {
  67. int x = i % field.getCols();
  68. int y = i / field.getCols();
  69. buttons.at(i)->set_sensitive(false);
  70. if(field.isBomb(x, y)) {
  71. if(field.isFlagged(x, y)) {
  72. auto imgFlagBomb = std::make_shared<Gtk::Image>();
  73. imgFlagBomb->set(m_textureFlagBomb);
  74. buttons.at(i)->set_child(*imgFlagBomb);
  75. }
  76. else {
  77. auto imgBomb = std::make_shared<Gtk::Image>();
  78. imgBomb->set(m_textureBomb);
  79. buttons.at(i)->set_child(*imgBomb);
  80. }
  81. buttons.at(i)->set_active(true);
  82. }
  83. }
  84. }
  85. void MainWindow::updateCell(int x, int y) {
  86. int pos = x + y * field.getRows();
  87. if(field.isOpened(x, y)) {
  88. if (field.bombsNearby(x, y) > 0) {
  89. switch(field.bombsNearby(x, y)) {
  90. case 1:
  91. buttons.at(pos)->get_style_context()->add_class("label-1");
  92. break;
  93. case 2:
  94. buttons.at(pos)->get_style_context()->add_class("label-2");
  95. break;
  96. case 3:
  97. buttons.at(pos)->get_style_context()->add_class("label-3");
  98. break;
  99. case 4:
  100. buttons.at(pos)->get_style_context()->add_class("label-4");
  101. break;
  102. case 5:
  103. buttons.at(pos)->get_style_context()->add_class("label-5");
  104. break;
  105. case 6:
  106. buttons.at(pos)->get_style_context()->add_class("label-6");
  107. break;
  108. case 7:
  109. buttons.at(pos)->get_style_context()->add_class("label-7");
  110. break;
  111. case 8:
  112. buttons.at(pos)->get_style_context()->add_class("label-8");
  113. break;
  114. }
  115. buttons.at(pos)->set_label(Glib::ustring::format(field.bombsNearby(x, y)));
  116. }
  117. buttons.at(pos)->set_active(true);
  118. buttons.at(pos)->set_sensitive(false);
  119. }
  120. }
  121. // void MainWindow::ShowGameWonAnimation() {
  122. // // Limit the number of confetti images to 10
  123. // int confettiCount = 10;
  124. // for (int i = 0; i < confettiCount; ++i) {
  125. // Glib::signal_timeout().connect_once([this]() {
  126. // auto confetti = Gtk::make_managed<Gtk::Image>();
  127. // confetti->set_from_resource("/mineSweeper/confetti");
  128. // // Randomize position on the grid or overlay.
  129. // grid->attach(*confetti, rand() % COLS, rand() % COLS);
  130. // grid->queue_draw();
  131. // }, i * 100); // Add confetti with a delay of 100ms each
  132. // }
  133. // }
  134. // bool MainWindow::AllCellsOpened()
  135. // {
  136. // for(int i=0; i<COLS * COLS; i++) {
  137. // if (!buttons[i]->get_active())
  138. // return false;
  139. // }
  140. // return true;
  141. // }
  142. void MainWindow::gameOver() {
  143. clockSignalConn.disconnect();
  144. std::cout << "Signal gameOver emmited\n";
  145. }
  146. bool MainWindow::updateClockLabel()
  147. {
  148. ++m_elapsedTime;
  149. int deciseconds = m_elapsedTime % 10;
  150. int seconds = (m_elapsedTime / 10) % 60;
  151. int minutes = (m_elapsedTime /600) % 60;
  152. Glib::ustring msg = Glib::ustring::compose("Elapsed time: %1:%2.%3", \
  153. Glib::ustring::format(std::setfill(L'0'), std::setw(2), minutes), \
  154. Glib::ustring::format(std::setfill(L'0'), std::setw(2), seconds), \
  155. Glib::ustring::format(std::setfill(L'0'), std::setw(1), deciseconds));
  156. clockLabel.set_label(msg);
  157. return true;
  158. }
  159. MainWindow::MainWindow()
  160. {
  161. // ApplyStyles(); // Load the CSS file
  162. m_elapsedTime = 0;
  163. newGame = true;
  164. set_title("MineSweeper");
  165. set_default_size(400, 400);
  166. set_resizable(false);
  167. boxV = Gtk::Box(Gtk::Orientation::VERTICAL);
  168. boxH = Gtk::Box(Gtk::Orientation::HORIZONTAL);
  169. boxH.set_hexpand(true);
  170. boxV.append(boxH);
  171. boxH.set_expand(true);
  172. Gtk::Label labelMines;
  173. labelMines.set_margin_top(12);
  174. labelMines.set_margin_start(12);
  175. labelMines.set_label(Glib::ustring::compose("Total mines: %1", field.getTotalMines()));
  176. //labelMines.set_hexpand(true);
  177. Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field.getRemainingFlags());
  178. flagLabel = Gtk::Label(msg);
  179. flagLabel.set_margin_top(12);
  180. flagLabel.set_margin_start(12);
  181. flagLabel.set_margin_end(12);
  182. //flagLabel.set_hexpand(true);
  183. clockLabel.set_margin_top(12);
  184. clockLabel.set_margin_start(12);
  185. clockLabel.set_margin_end(12);
  186. clockLabel.set_hexpand(true);
  187. Glib::ustring clockmsg = Glib::ustring::compose("Elapsed time: 00:00.0");
  188. clockLabel.set_label(clockmsg);
  189. boxH.append(labelMines);
  190. boxH.append(clockLabel);
  191. boxH.append(flagLabel);
  192. //TODO check if it's okay to mix std::shared_ptr with Gdk::ptr
  193. m_textureBomb = Gdk::Texture::create_from_resource("/minesweeper/bomb-solid");
  194. m_textureFlag = Gdk::Texture::create_from_resource("/minesweeper/flag-solid");
  195. m_textureFlagBomb = Gdk::Texture::create_from_resource("/minesweeper/flag-bomb");
  196. // bombPix.set_from_resource("/minesweeper/bomb-solid");
  197. auto css_provider = Gtk::CssProvider::create();
  198. css_provider->load_from_data(
  199. ".label-1 { font-weight: bold; font-size: 1.5em; color: Blue; }\
  200. .label-2 { font-weight: bold; font-size: 1.5em; color: Green; }\
  201. .label-3 { font-weight: bold; font-size: 1.5em; color: Darkorange; }\
  202. .label-4 { font-weight: bold; font-size: 1.5em; color: Purple; }\
  203. .label-5 { font-weight: bold; font-size: 1.5em; color: Red; }\
  204. .label-6 { font-weight: bold; font-size: 1.5em; color: Salmon; }\
  205. .label-7 { font-weight: bold; font-size: 1.5em; color: Turquoise; }\
  206. .label-8 { font-weight: bold; font-size: 1.5em; color: Magenta; }");
  207. auto display = Gdk::Display::get_default();
  208. Gtk::StyleContext::add_provider_for_display(display, css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
  209. for (int i = 0; i < field.getCols() * field.getRows(); i++) {
  210. auto button = std::make_shared<Gtk::ToggleButton>();
  211. button->set_size_request(50, 40);
  212. button->set_sensitive(true);
  213. button->set_active(false);
  214. int x = i % field.getCols();
  215. int y = i / field.getRows();
  216. button->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::OnCellClick), x, y));
  217. //button->get_style_context()->add_class("fixed-button");
  218. auto gesture = Gtk::GestureClick::create();
  219. gesture->set_button(3);
  220. gesture->signal_released().connect(sigc::bind(sigc::mem_fun(*this, \
  221. &MainWindow::OnCellRightClick), i));
  222. button->add_controller(gesture);
  223. buttons.push_back(button);
  224. grid.attach(*button, x, y);
  225. }
  226. field.openCellSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateCell)));
  227. field.remainingFlagsSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateFlagsLabel)));
  228. field.gameOverSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::gameOver)));
  229. //newGameButton.set_label("New");
  230. //newGameButton.add_css_class("suggested-action");
  231. //newGameButton.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnNewButtonClick));
  232. //optionButton.set_icon_name("open-menu");
  233. //if (clockSignalConn.connected()) clockSignalConn.disconnect();
  234. //elapsedTime = 0;
  235. clockSignalConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::updateClockLabel), 100);
  236. //}
  237. //create the minefield
  238. //field = new MineField(COLS, MINES);
  239. //bar.pack_start(newGameButton);
  240. //bar.pack_end(optionButton);
  241. //grid.set_row_homogeneous(false);
  242. //grid.set_column_homogeneous(false);
  243. grid.set_margin(10);
  244. //grid.set_vexpand(true);
  245. //grid.set_hexpand(true);
  246. // grid.set_fill(false);
  247. boxV.append(grid);
  248. this->set_titlebar(bar);
  249. this->set_child(boxV);
  250. }
  251. int main(int argc, char **argv) {
  252. auto app = Gtk::Application::create("eu.minesweeper");
  253. return app->make_window_and_run<MainWindow>(argc, argv);
  254. }