ChessPositionWidget.cc
Go to the documentation of this file.
1 // cwchessboard -- A C++ chessboard tool set for gtkmm
2 //
3 //! @file ChessPositionWidget.cc This file contains the implementation of class ChessPositionWidget.
4 //
5 // Copyright (C) 2008, by
6 //
7 // Carlo Wood, Run on IRC <carlo@alinoe.com>
8 // RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt
9 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 2 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 
24 #ifndef USE_PCH
25 #include "sys.h"
26 #include <gtkmm/radioaction.h>
27 #include <gtkmm/stock.h>
28 #endif
29 
30 #include "ChessPositionWidget.h"
31 #include "CwChessboardCodes.h"
32 
33 using namespace cwchess;
34 
35 namespace cwmm {
36 
37 bool ChessPositionWidget::execute(Move const& move)
38 {
39  Code code(piece_at(move.from()).code());
40  if (code.is_a(pawn))
41  {
42  EnPassant const& en_passant(this->en_passant());
43  if (en_passant.exists() && en_passant.index() == move.to())
44  set_square(en_passant.pawn_index().col(), en_passant.pawn_index().row(), empty_square);
45  }
46  bool result = ChessPosition::execute(move);
47  set_square(move.from().col(), move.from().row(), empty_square);
48  if (move.is_promotion())
49  code = move.promotion_type();
50  set_square(move.to().col(), move.to().row(), code);
51  uint8_t col_diff = move.to().col() - move.from().col();
52  if (code.is_a(king) && col_diff && !(col_diff & 1))
53  {
54  IndexData rook_from_data = { static_cast<uint8_t>(move.from()() - 4 + 7 * (2 + move.to()() - move.from()()) / 4) };
55  IndexData rook_to_data = { static_cast<uint8_t>(move.from()() + (move.to()() - move.from()()) / 2) };
56  Index rook_from(rook_from_data);
57  Index rook_to(rook_to_data);
58  set_square(rook_from.col(), rook_from.row(), empty_square);
59  set_square(rook_to.col(), rook_to.row(), (code.color() == white) ? ::white_rook : ::black_rook);
60  }
61  set_active_turn_indicator(to_move().is_white());
62 }
63 
64 void ChessPositionWidget::sync(void)
65 {
66  // Clear the board.
67  for (Index index = index_begin; index != index_end; ++index)
68  set_square(index.col(), index.row(), empty_square);
69 
70  // Set up a new position.
71  for (Index index = index_begin; index != index_end; ++index)
72  set_square(index.col(), index.row(), piece_at(index).code());
73 
74  // Draw the correct turn indicator.
75  set_active_turn_indicator(to_move().is_white());
76 }
77 
78 bool ChessPositionWidget::load_FEN(std::string const& FEN)
79 {
80  cwchess::ChessPosition tmp(*static_cast<ChessPosition*>(this));
81  bool result = tmp.load_FEN(FEN);
82  if (result)
83  set_position(tmp);
84  return result;
85 }
86 
87 bool ChessPositionWidget::popup_menu(GdkEventButton* event, int col, int row)
88 {
89  DoutEntering(dc::notice|dc::clipboard, "ChessPositionWidget::popup_menu(" << col << ", " << row << ")");
90  M_placepiece_index = cwchess::Index(col, row);
91  if (M_MenuPopup)
92  {
93  M_refActionGroup->get_action("PlacepieceBlackPawn")->set_sensitive(row != 0 && row != 7);
94  M_refActionGroup->get_action("PlacepieceWhitePawn")->set_sensitive(row != 0 && row != 7);
95  M_refActionGroup->get_action("PlacepieceBlackKing")->set_sensitive(!all(cwchess::black_king).test());
96  M_refActionGroup->get_action("PlacepieceWhiteKing")->set_sensitive(!all(cwchess::white_king).test());
97  if (to_move().is_white())
98  M_refToMoveWhite_action->set_active(true);
99  else
100  M_refToMoveBlack_action->set_active(true);
101  Piece const& piece(piece_at(M_placepiece_index));
102  M_refActionGroup->get_action("PlacepieceNothing")->set_visible(piece != nothing);
103  bool can_be_taken_en_passant =
104  (piece == cwchess::white_pawn && M_placepiece_index.row() == 3&&
105  piece_at(M_placepiece_index + south.offset) == nothing&&
106  piece_at(M_placepiece_index + 2 * south.offset) == nothing) ||
107  (piece == cwchess::black_pawn && M_placepiece_index.row() == 4&&
108  piece_at(M_placepiece_index + north.offset) == nothing&&
109  piece_at(M_placepiece_index + 2 * north.offset) == nothing);
110  M_refActionGroup->get_action("AllowEnPassantCapture")->set_visible(can_be_taken_en_passant);
111  if (can_be_taken_en_passant)
112  {
113  M_AllowEnPassantCapture_connection.block();
114  M_refAllowEnPassantCapture_action->set_active(en_passant().exists() && en_passant().pawn_index() == M_placepiece_index);
115  M_AllowEnPassantCapture_connection.unblock();
116  }
117  bool is_castle_piece =
118  (piece == cwchess::white_king && M_placepiece_index == ie1) ||
119  (piece == cwchess::black_king && M_placepiece_index == ie8) ||
120  (piece == cwchess::white_rook && (M_placepiece_index == ia1 || M_placepiece_index == ih1)) ||
121  (piece == cwchess::black_rook && (M_placepiece_index == ia8 || M_placepiece_index == ih8));
122  M_refActionGroup->get_action("PieceHasMoved")->set_visible(is_castle_piece);
123  if (is_castle_piece)
124  {
125  M_PieceHasMoved_connection.block();
126  M_refPieceHasMoved_action->set_active(has_moved(M_placepiece_index));
127  M_PieceHasMoved_connection.unblock();
128  }
129  update_paste_status();
130  M_MenuPopup->popup(event->button, event->time);
131  return true; // Signal that popup() was called.
132  }
133  return false;
134 }
135 
136 void ChessPositionWidget::on_menu_placepiece_black_pawn(void)
137 {
138  place(cwchess::black_pawn, M_placepiece_index);
139 }
140 
141 void ChessPositionWidget::on_menu_placepiece_black_rook(void)
142 {
143  place(cwchess::black_rook, M_placepiece_index);
144 }
145 
146 void ChessPositionWidget::on_menu_placepiece_black_knight(void)
147 {
148  place(cwchess::black_knight, M_placepiece_index);
149 }
150 
151 void ChessPositionWidget::on_menu_placepiece_black_bishop(void)
152 {
153  place(cwchess::black_bishop, M_placepiece_index);
154 }
155 
156 void ChessPositionWidget::on_menu_placepiece_black_queen(void)
157 {
158  place(cwchess::black_queen, M_placepiece_index);
159 }
160 
161 void ChessPositionWidget::on_menu_placepiece_black_king(void)
162 {
163  place(cwchess::black_king, M_placepiece_index);
164 }
165 
166 void ChessPositionWidget::on_menu_placepiece_white_pawn(void)
167 {
168  place(cwchess::white_pawn, M_placepiece_index);
169 }
170 
171 void ChessPositionWidget::on_menu_placepiece_white_rook(void)
172 {
173  place(cwchess::white_rook, M_placepiece_index);
174 }
175 
176 void ChessPositionWidget::on_menu_placepiece_white_knight(void)
177 {
178  place(cwchess::white_knight, M_placepiece_index);
179 }
180 
181 void ChessPositionWidget::on_menu_placepiece_white_bishop(void)
182 {
183  place(cwchess::white_bishop, M_placepiece_index);
184 }
185 
186 void ChessPositionWidget::on_menu_placepiece_white_queen(void)
187 {
188  place(cwchess::white_queen, M_placepiece_index);
189 }
190 
191 void ChessPositionWidget::on_menu_placepiece_white_king(void)
192 {
193  place(cwchess::white_king, M_placepiece_index);
194 }
195 
196 void ChessPositionWidget::on_menu_placepiece_nothing(void)
197 {
198  place(cwchess::Code(), M_placepiece_index);
199 }
200 
201 void ChessPositionWidget::on_menu_allow_en_passant_capture(void)
202 {
203  bool en_passant_allowed = en_passant().exists() && en_passant().pawn_index() == M_placepiece_index;
204  reset_en_passant();
205  if (!en_passant_allowed)
206  {
207  Index passed_square(M_placepiece_index);
208  if (piece_at(M_placepiece_index) == black)
209  passed_square += north.offset;
210  else
211  passed_square += south.offset;
212  set_en_passant(passed_square);
213  }
214 }
215 
216 void ChessPositionWidget::on_menu_piece_has_moved(void)
217 {
218  if (has_moved(M_placepiece_index))
219  clear_has_moved(M_placepiece_index);
220  else
221  set_has_moved(M_placepiece_index);
222 }
223 
224 void ChessPositionWidget::on_menu_copy_FEN(void)
225 {
226  DoutEntering(dc::clipboard, "ChessPositionWidget::on_menu_copy_FEN");
227  Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
228  std::list<Gtk::TargetEntry> targets;
229  targets.push_back(Gtk::TargetEntry("UTF8_STRING"));
230  Glib::ustring clipboard_store = FEN();
231  // Set the content of the clipboard here, because I'm not sure if set() can cause an immediate call to on_clipboard_get.
232  M_clipboard_content = clipboard_store;
233  // This call can clear M_clipboard_content (because it calls ChessPositionWidget::on_clipboard_clear if it was called before.
234  if (!refClipboard->set(targets,
235  sigc::mem_fun(*this,& ChessPositionWidget::on_clipboard_get),
236  sigc::mem_fun(*this,& ChessPositionWidget::on_clipboard_clear)))
237  g_warning("ChessPositionWidget::on_menu_copy_FEN(): setting the clipboard data failed.");
238  // Therefore we set the clipboard content again, here.
239  M_clipboard_content = clipboard_store;
240  Dout(dc::clipboard, "Storing \"" << M_clipboard_content << "\".");
241 }
242 
243 void ChessPositionWidget::on_menu_paste_FEN(void)
244 {
245  DoutEntering(dc::clipboard, "ChessPositionWidget::on_menu_paste_FEN");
246  Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
247  refClipboard->request_text(sigc::mem_fun(*this,& ChessPositionWidget::on_clipboard_received));
248 }
249 
250 void ChessPositionWidget::on_clipboard_get(Gtk::SelectionData& selection_data, guint)
251 {
252  std::string const target = selection_data.get_target();
253 
254  DoutEntering(dc::clipboard, "ChessPositionWidget::on_clipboard_get(...) with target data \"" << target << "\".");
255 
256  if (target == "UTF8_STRING")
257  {
258  Dout(dc::clipboard, "Passing back \"" << M_clipboard_content << "\".");
259  selection_data.set_text(M_clipboard_content);
260  }
261  else
262  g_warning("ChessPositionWidget::on_clipboard_get(): Unexpected clipboard target format.");
263 }
264 
265 void ChessPositionWidget::on_clipboard_clear(void)
266 {
267  DoutEntering(dc::clipboard, "ChessPositionWidget::on_clipboard_clear()");
268  M_clipboard_content.clear();
269 }
270 
271 void ChessPositionWidget::on_clipboard_received(Glib::ustring const& text)
272 {
273  DoutEntering(dc::clipboard, "ChessPositionWidget::on_clipboard_received(\"" << text << "\").");
274 
275  if (!load_FEN(text) && !M_trying_primary)
276  {
277  Dout(dc::clipboard, "No FEN in CLIPBOARD. Trying PRIMARY.");
278  Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
279  M_trying_primary = true;
280  refClipboard->request_text(sigc::mem_fun(*this,& ChessPositionWidget::on_clipboard_received));
281  }
282  else
283  M_trying_primary = false;
284 }
285 
286 void ChessPositionWidget::update_paste_status(void)
287 {
288  DoutEntering(dc::clipboard, "ChessPositionWidget::update_paste_status()");
289  M_refActionGroup->get_action("PasteFEN")->set_sensitive(false);
290  Dout(dc::clipboard, "paste disabled.");
291  Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
292  refClipboard->request_targets(sigc::mem_fun(*this,& ChessPositionWidget::on_clipboard_received_targets));
293 }
294 
295 void ChessPositionWidget::on_clipboard_received_targets(Glib::StringArrayHandle const& targets_array)
296 {
297  DoutEntering(dc::clipboard, "ChessPositionWidget::on_clipboard_received_targets(...).");
298 
299  typedef std::list<Glib::ustring> targets_type;
300  targets_type targets = targets_array;
301  if (std::find(targets.begin(), targets.end(), "UTF8_STRING") != targets.end())
302  {
303  Dout(dc::clipboard, "Target found; paste enabled.");
304  M_refActionGroup->get_action("PasteFEN")->set_sensitive(true);
305  }
306 }
307 
308 void ChessPositionWidget::on_menu_swap_colors(void)
309 {
310  swap_colors();
311 }
312 
313 void ChessPositionWidget::on_menu_initial_position(void)
314 {
315  initial_position();
316 }
317 
318 void ChessPositionWidget::on_menu_clear_board(void)
319 {
320  clear();
321 }
322 
323 void ChessPositionWidget::on_menu_to_move_white(void)
324 {
325  to_move(white);
326 }
327 
328 void ChessPositionWidget::on_menu_to_move_black(void)
329 {
330  to_move(black);
331 }
332 
333 void ChessPositionWidget::initialize_menus(void)
334 {
335  DoutEntering(dc::notice, "ChessPositionWidget::initialize_menus");
336 
337  M_refIconFactory = Gtk::IconFactory::create();
338  M_refIconFactory->add_default();
339 
340  GdkColor light_square_color;
341  get_light_square_color(light_square_color);
342 
343  int color_count = 0;
344  for (bool iswhite = false; color_count < 2; ++color_count, iswhite = true)
345  {
346  using namespace cwchess;
347  Type type(nothing);
348  do
349  {
350  Glib::RefPtr<Gdk::Pixmap> icon_pixmap = Gdk::Pixmap::create(M_drawable->get_window(), 16, 16);
351  Cairo::RefPtr<Cairo::Context> cairo_context = icon_pixmap->create_cairo_context();
352  cairo_t* cr = cairo_context->cobj();
353  cairo_set_source_rgb(cr, light_square_color.red / 65535.0, light_square_color.green / 65535.0, light_square_color.blue / 65535.0);
354  cairo_paint(cr);
355  std::string icon_str(iswhite ? "white_" : "black_");
356  switch (type())
357  {
358  case nothing_bits:
359  icon_str += "nothing";
360  break;
361  case pawn_bits:
362  draw_pawn(cr, 8, 8, 16, iswhite);
363  icon_str += "pawn";
364  break;
365  case rook_bits:
366  draw_rook(cr, 8, 8, 16, iswhite);
367  icon_str += "rook";
368  break;
369  case knight_bits:
370  draw_knight(cr, 8, 8, 16, iswhite);
371  icon_str += "knight";
372  break;
373  case bishop_bits:
374  draw_bishop(cr, 8, 8, 16, iswhite);
375  icon_str += "bishop";
376  break;
377  case queen_bits:
378  draw_queen(cr, 8, 8, 16, iswhite);
379  icon_str += "queen";
380  break;
381  case king_bits:
382  draw_king(cr, 8, 8, 16, iswhite);
383  icon_str += "king";
384  break;
385  }
386  icon_str += "_icon";
387  Glib::RefPtr<Gdk::Pixbuf> icon_pixbuf = Gdk::Pixbuf::create(Glib::RefPtr<Gdk::Drawable>::cast_static(icon_pixmap), 0, 0, 16, 16);
388  M_refIconFactory->add(Gtk::StockID(icon_str.c_str()), Gtk::IconSet(icon_pixbuf));
389 
390  do { TypeData type_data = { static_cast<uint8_t>(type() + 1) }; type = type_data; } while (type() == 4);
391  }
392  while (type() != 8);
393  }
394 
395  M_refActionGroup = Gtk::ActionGroup::create();
396  M_refActionGroup->add(Gtk::Action::create("PlacepieceMenu", "Placepiece Menu"));
397  M_refActionGroup->add(Gtk::Action::create("PlacepieceBlackPawn", Gtk::StockID("black_pawn_icon"), "Black Pawn"),
398  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_black_pawn));
399  M_refActionGroup->add(Gtk::Action::create("PlacepieceBlackRook", Gtk::StockID("black_rook_icon"), "Black Rook"),
400  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_black_rook));
401  M_refActionGroup->add(Gtk::Action::create("PlacepieceBlackKnight", Gtk::StockID("black_knight_icon"), "Black Knight"),
402  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_black_knight));
403  M_refActionGroup->add(Gtk::Action::create("PlacepieceBlackBishop", Gtk::StockID("black_bishop_icon"), "Black Bishop"),
404  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_black_bishop));
405  M_refActionGroup->add(Gtk::Action::create("PlacepieceBlackQueen", Gtk::StockID("black_queen_icon"), "Black Queen"),
406  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_black_queen));
407  M_refActionGroup->add(Gtk::Action::create("PlacepieceBlackKing", Gtk::StockID("black_king_icon"), "Black King"),
408  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_black_king));
409  M_refActionGroup->add(Gtk::Action::create("PlacepieceWhitePawn", Gtk::StockID("white_pawn_icon"), "White Pawn"),
410  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_white_pawn));
411  M_refActionGroup->add(Gtk::Action::create("PlacepieceWhiteRook", Gtk::StockID("white_rook_icon"), "White Rook"),
412  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_white_rook));
413  M_refActionGroup->add(Gtk::Action::create("PlacepieceWhiteKnight", Gtk::StockID("white_knight_icon"), "White Knight"),
414  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_white_knight));
415  M_refActionGroup->add(Gtk::Action::create("PlacepieceWhiteBishop", Gtk::StockID("white_bishop_icon"), "White Bishop"),
416  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_white_bishop));
417  M_refActionGroup->add(Gtk::Action::create("PlacepieceWhiteQueen", Gtk::StockID("white_queen_icon"), "White Queen"),
418  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_white_queen));
419  M_refActionGroup->add(Gtk::Action::create("PlacepieceWhiteKing", Gtk::StockID("white_king_icon"), "White King"),
420  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_white_king));
421  M_refActionGroup->add(Gtk::Action::create("PlacepieceNothing", Gtk::StockID("black_nothing_icon"), "Clear square"),
422  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_placepiece_nothing));
423  M_refAllowEnPassantCapture_action = Gtk::ToggleAction::create("AllowEnPassantCapture", "Allow e.p. capture");
424  M_refActionGroup->add(M_refAllowEnPassantCapture_action);
425  M_AllowEnPassantCapture_connection =
426  M_refAllowEnPassantCapture_action->signal_toggled().connect(sigc::mem_fun(*this,& ChessPositionWidget::on_menu_allow_en_passant_capture));
427  M_refPieceHasMoved_action = Gtk::ToggleAction::create("PieceHasMoved", "Has moved");
428  M_refActionGroup->add(M_refPieceHasMoved_action);
429  M_PieceHasMoved_connection =
430  M_refPieceHasMoved_action->signal_toggled().connect(sigc::mem_fun(*this,& ChessPositionWidget::on_menu_piece_has_moved));
431  M_refActionGroup->add(Gtk::Action::create("CopyFEN", Gtk::Stock::COPY, "Copy FEN"),
432  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_copy_FEN));
433  M_refActionGroup->add(Gtk::Action::create("PasteFEN", Gtk::Stock::PASTE, "Paste FEN"),
434  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_paste_FEN));
435  M_refActionGroup->add(Gtk::Action::create("SwapColors", "Swap colors"),
436  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_swap_colors));
437  M_refActionGroup->add(Gtk::Action::create("InitialPosition", "Initial position"),
438  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_initial_position));
439  M_refActionGroup->add(Gtk::Action::create("ClearBoard", "Clear board"),
440  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_clear_board));
441  Gtk::RadioAction::Group group_to_move;
442  M_refToMoveWhite_action = Gtk::RadioAction::create(group_to_move, "ToMoveWhite", "White to play");
443  M_refActionGroup->add(M_refToMoveWhite_action,
444  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_to_move_white));
445  M_refToMoveBlack_action = Gtk::RadioAction::create(group_to_move, "ToMoveBlack", "Black to play");
446  M_refActionGroup->add(M_refToMoveBlack_action,
447  sigc::mem_fun(*this,& ChessPositionWidget::on_menu_to_move_black));
448 
449  M_refUIManager = Gtk::UIManager::create();
450  M_refUIManager->insert_action_group(M_refActionGroup);
451 
452  //add_accel_group(M_refUIManager->get_accel_group());
453 
454  //Layout the actions in a menubar and toolbar:
455  Glib::ustring ui_info =
456  "<ui>"
457  " <popup name='PopupMenu'>"
458  " <menuitem action='PlacepieceWhitePawn'/>"
459  " <menuitem action='PlacepieceWhiteRook'/>"
460  " <menuitem action='PlacepieceWhiteKnight'/>"
461  " <menuitem action='PlacepieceWhiteBishop'/>"
462  " <menuitem action='PlacepieceWhiteQueen'/>"
463  " <menuitem action='PlacepieceWhiteKing'/>"
464  " <separator/>"
465  " <menuitem action='PlacepieceBlackPawn'/>"
466  " <menuitem action='PlacepieceBlackRook'/>"
467  " <menuitem action='PlacepieceBlackKnight'/>"
468  " <menuitem action='PlacepieceBlackBishop'/>"
469  " <menuitem action='PlacepieceBlackQueen'/>"
470  " <menuitem action='PlacepieceBlackKing'/>"
471  " <separator/>"
472  " <menuitem action='AllowEnPassantCapture'/>"
473  " <menuitem action='PieceHasMoved'/>"
474  " <menuitem action='PlacepieceNothing'/>"
475  " <separator/>"
476  " <menuitem action='ToMoveWhite'/>"
477  " <menuitem action='ToMoveBlack'/>"
478  " <separator/>"
479  " <menuitem action='CopyFEN'/>"
480  " <menuitem action='PasteFEN'/>"
481  " <menuitem action='SwapColors'/>"
482  " <menuitem action='InitialPosition'/>"
483  " <menuitem action='ClearBoard'/>"
484  " </popup>"
485  "</ui>";
486 #ifdef GLIBMM_EXCEPTIONS_ENABLED
487  try
488  {
489  M_refUIManager->add_ui_from_string(ui_info);
490  }
491  catch(const Glib::Error& ex)
492  {
493  std::cerr << "building menus failed: " << ex.what();
494  }
495 #else
496  std::auto_ptr<Glib::Error> ex;
497  M_refUIManager->add_ui_from_string(ui_info, ex);
498  if(ex.get())
499  {
500  std::cerr << "building menus failed: " << ex->what();
501  }
502 #endif //GLIBMM_EXCEPTIONS_ENABLED
503 
504  // Get the menu:
505  M_MenuPopup = dynamic_cast<Gtk::Menu*>(M_refUIManager->get_widget("/PopupMenu"));
506  if (!M_MenuPopup)
507  g_warning("menu not found");
508  else
509  M_MenuPopup->signal_deactivate().connect(sigc::mem_fun(this,& ChessPositionWidget::popup_deactivated));
510 }
511 
512 void ChessPositionWidget::popup_deactivated(void)
513 {
514  Dout(dc::notice, "Calling ChessPositionWidget::popup_deactivated()");
515  hide_cursor();
516 }
517 
518 bool ChessPositionWidget::on_button_press_event(GdkEventButton* event)
519 {
520 #ifdef CWDEBUG
521  if (debug::channels::dc::event.is_on())
522  Dout(dc::event, "Entering ChessPositionWidget::on_button_press_event(" << event << ")");
523  else
524  Dout(dc::notice|dc::clipboard, "Entering ChessPositionWidget::on_button_press_event()");
525  debug::Indent __cwmm_chesspositionwidget_debug_indent(2);
526 #endif
527 
528  // Find the square under the mouse, if any.
529  gint col = x2col(event->x);
530  gint row = y2row(event->y);
531 
532  // Ignore button presses outside the chessboard.
533  if (!is_inside_board(col, row))
534  return false;
535 
536  // Inform the user that a button press event occured.
537  if (on_button_press(col, row, event))
538  return true;
539 
540  // If the edit mode isn't one of the builtin modes, then we're done.
541  // We're also done if it was a double click.
542  if (event->type != GDK_BUTTON_PRESS ||
543  (M_widget_mode != mode_edit_position && M_widget_mode != mode_edit_game))
544  return false;
545 
546  // Handle picking up a piece.
547  if (event->button == 1)
548  {
549  M_floating_piece_handle = -1;
550  code_t code = get_square(col, row);
551  // Ignore clicks on empty squares.
552  // The least significant bit reflects the color of the piece. A code <= 1 means an empty square.
553  if (code > 1)
554  {
555  bool pickup = true;
556  if (M_widget_mode == mode_edit_position)
557  {
558  // Remove the piece under the mouse pointer.
559  place(Code(), Index(col, row));
560  }
561  else // M_widget_mode == mode_edit_game
562  {
563  // Remember were the piece came from if we're going to do a move.
564  M_move_from = Index(col, row);
565  if (piece_at(M_move_from).color() != to_move())
566  // Refuse to pick up a piece of the wrong color.
567  pickup = false;
568  else
569  {
570  // Erase the piece in the widget only.
571  set_square(col, row, empty_square);
572  }
573  }
574  if (pickup)
575  {
576  // Put the piece under the mouse pointer.
577  double hsside = 0.5 * sside();
578  double fraction = hsside - (gint)hsside;
579  M_floating_piece_handle = add_floating_piece(code, event->x - fraction, event->y - fraction, TRUE);
580  M_signal_picked_up.emit(M_move_from,* this);
581  // We picked up a piece; the event was handled.
582  return true;
583  }
584  }
585  }
586  // Handle placing new pieces.
587  else if (event->button == 3 && M_widget_mode == mode_edit_position)
588  {
589  if (popup_menu(event, col, row))
590  return true; // Ignore the event completely: we won't get a release event either.
591  }
592 
593  // Returning FALSE means that the next event handler will be called.
594  return false;
595 }
596 
597 bool ChessPositionWidget::on_button_release_event(GdkEventButton* event)
598 {
599 #ifdef CWDEBUG
600  if (debug::channels::dc::event.is_on())
601  Dout(dc::event, "Entering ChessPositionWidget::on_button_release_event(" << event << ")");
602  else
603  Dout(dc::notice, "Entering ChessPositionWidget::on_button_release_event()");
604  debug::Indent __cwmm_chesspositionwidget_debug_indent(2);
605 #endif
606 
607  // Find the square under the mouse, if any.
608  gint col = x2col(event->x);
609  gint row = y2row(event->y);
610 
611  // Inform the user that a button press event occured.
612  if (!is_inside_board(col, row))
613  col = row = -1;
614  if (on_button_release(col, row, event))
615  return true;
616 
617  // If the edit mode isn't one of the builtin modes, then we're done.
618  if (M_widget_mode != mode_edit_position && M_widget_mode != mode_edit_game)
619  return false;
620 
621  // Handle dropping a piece.
622  if (event->button == 1 && M_floating_piece_handle != -1)
623  {
624  if (M_widget_mode == mode_edit_game || col != -1)
625  {
626  // Get the code of the floating piece.
627  code_t code = get_floating_piece(M_floating_piece_handle);
628  if (M_widget_mode == mode_edit_position)
629  {
630  // Put the piece on the new square.
631  place(cwchess::Code(code), cwchess::Index(col, row));
632  }
633  else // M_widget_mode == mode_edit_game
634  {
635  // Where are we trying to move to?
636  cwchess::Index to(col, row);
637  if (to == M_move_from || col == -1)
638  {
639  // The piece was put back where it was picked up. Just draw it again in the widget and do nothing.
640  set_square(M_move_from.col(), M_move_from.row(), code);
641  }
642  else
643  {
644  // Create the move object.
645  cwchess::Move move(M_move_from, to, cwchess::nothing);
646  cwchess::Piece piece(piece_at(M_move_from));
647  cwchess::Color color(piece.color());
648  if (((color == cwchess::black && row == 0) || (color == cwchess::white && row == 7)) && piece.code().is_a(cwchess::pawn))
649  move. set_promotion(M_promotion->type(this, move));
650  if (legal(move))
651  {
652  cwchess::ChessPosition previous_position(*this);
653  execute(move);
654  M_signal_moved.emit(move, previous_position,* this);
655  }
656  else
657  {
658  // The move was illegal. Just draw the piece back where it was and do nothing.
659  set_square(M_move_from.col(), M_move_from.row(), code);
660  M_signal_illegal.emit(move,* this);
661  }
662  }
663  }
664  }
665  // Remove the floating piece.
666  remove_floating_piece(M_floating_piece_handle);
667  M_floating_piece_handle = -1;
668  M_signal_dropped.emit(col, row,* this);
669  // We just dropped the piece; the event was handled.
670  return true;
671  }
672 
673  return false;
674 }
675 
676 } // namespace cwmm
677 
CodeData const black_pawn
A constant representing a black pawn.
Definition: Code.h:66
IndexData const index_begin
A constant representing the& #39;first&#39; index.
Definition: Index.h:184
A namespace for all chess related objects that are not related to the GUI.
Definition: Array.h:39
bool load_FEN(std::string const& FEN)
Read a FEN code.
CwChessboardCode const empty_square
CodeData const white_queen
A constant representing a white queen.
Definition: Code.h:62
bool execute(Move const& move)
Execute move move.
ColorData const white
A constant representing the color white.
Definition: Color.h:55
IndexData const ia1
A constant representing the index to square a1.
Definition: Index.h:53
IndexData const ih1
A constant representing the index to square h1.
Definition: Index.h:67
A chess move in a particular chess position.
Definition: Move.h:44
TypeData const pawn
A constant representing a pawn.
Definition: Type.h:65
TypeData const king
A constant representing a king.
Definition: Type.h:69
CodeData const black_queen
A constant representing a black queen;.
Definition: Code.h:74
uint8_t const bishop_bits
The underlaying integral value of type& #39;bishop&#39;.
Definition: Type.h:57
IndexData const ih8
A constant representing the index to square h8.
Definition: Index.h:179
IndexData const ia8
A constant representing the index to square a8.
Definition: Index.h:165
The POD base type of class Index.
Definition: Index.h:45
CodeData const black_rook
A constant representing a black rook;.
Definition: Code.h:68
bool is_promotion(void) const
Return TRUE if this move is a pawn promotion.
Definition: Move.h:98
A chess piece type.
Definition: Type.h:87
An object representing en passant information.
Definition: EnPassant.h:49
This file contains the declaration of class ChessPositionWidget.
The index of a chess square.
Definition: Index.h:211
int col(void) const
Returns the column.
Definition: Index.h:337
CodeData const white_rook
A constant representing a white rook.
Definition: Code.h:56
A particular piece on the board.
Definition: Piece.h:45
Index index(void) const
Return the index of the square that was passed.
Definition: EnPassant.h:85
bool is_a(Type const& type) const
Returns TRUE if the type is equal.
Definition: Code.h:163
uint8_t const king_bits
The underlaying integral value of type& #39;king&#39;.
Definition: Type.h:56
Index pawn_index(void) const
Return the index of the pawn that just advanced two squares.
Definition: EnPassant.h:95
CodeData const black_bishop
A constant representing a black bishop;.
Definition: Code.h:72
Index from(void) const
Return the square the piece moves from.
Definition: Move.h:101
CwChessboardCode code_t
A code to specify a chess piece.
int row(void) const
Returns the row.
Definition: Index.h:334
Color color(void) const
Return the color of the piece.
Definition: Piece.h:112
A namespace for all gtkmm related objects.
A chess position.
Definition: ChessPosition.h:50
A chess piece type including color.
Definition: Code.h:92
Index to(void) const
Return the square the piece moves to.
Definition: Move.h:104
CodeData const black_king
A constant representing a black king;.
Definition: Code.h:76
TypeData const nothing
A constant representing the absence of a piece.
Definition: Type.h:63
CodeData const white_pawn
A constant representing a white pawn.
Definition: Code.h:54
bool exists(void) const
Return TRUE if the last move was a pawn advancing two squares.
Definition: EnPassant.h:79
CodeData const black_knight
A constant representing a black knight;.
Definition: Code.h:70
A color (black or white).
Definition: Color.h:67
CodeData const white_king
A constant representing a white king.
Definition: Code.h:64
IndexData const index_end
A constant representing& #39;one past the end&#39;.
Definition: Index.h:186
IndexData const ie8
A constant representing the index to square e8.
Definition: Index.h:173
uint8_t const knight_bits
The underlaying integral value of type& #39;knight&#39;.
Definition: Type.h:55
This file contains the definitions of the CwChessboardCode constants.
The POD base type of class Type.
Definition: Type.h:49
uint8_t const queen_bits
The underlaying integral value of type& #39;queen&#39;.
Definition: Type.h:59
Type promotion_type(void) const
Return the promotion type. Returns empty if this isn&#39;t a promotion.
Definition: Move.h:107
CodeData const white_bishop
A constant representing a white bishop.
Definition: Code.h:60
CodeData const white_knight
A constant representing a white knight.
Definition: Code.h:58
IndexData const ie1
A constant representing the index to square e1.
Definition: Index.h:61
uint8_t const nothing_bits
The underlaying integral value of type& #39;nothing&#39;.
Definition: Type.h:53
uint8_t const pawn_bits
The underlaying integral value of type& #39;pawn&#39;.
Definition: Type.h:54
Code code(void) const
The code of this piece.
Definition: Piece.h:121
uint8_t const rook_bits
The underlaying integral value of type& #39;rook&#39;.
Definition: Type.h:58
ColorData const black
A constant representing the color black.
Definition: Color.h:53

Copyright © 2006 - 2010 Carlo Wood.  All rights reserved.