/********************************************************************** * * FreeDoko a Doppelkopf-Game * * Copyright (C) 2001-2007 by Diether Knof and Borg Enders * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You can find this license in the file 'gpl.txt'. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Contact: * Diether Knof dknof@gmx.de * Borg Enders borg@borgsoft.de * *********************************************************************/ #include "constants.h" #ifdef USE_UI_GTKMM #include "reservation.h" #include "table.h" #include "name.h" #include "icongroup.h" #include "ui.h" #include "main_window.h" #include "utils.h" #include "widgets/stock_button.h" #include "../../party/rule.h" #include "../../game/game.h" #include "../../player/player.h" #include "../../basistypes.h" #include "../../os/bug_report_replay.h" #include "../../utils/string.h" #include #include #include #include #include #include namespace UI_GTKMM_NS { /** ** constructor ** ** @param table the table ** @param player corresponding player ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.0 **/ Reservation::Reservation(Table* const table, Player const* const player) : HTIN(table, player), Gtk::StickyDialog("Reservation", *(parent->ui->main_window), false), announce_button(NULL), notebook(NULL), swines_button(NULL), hyperswines_button(NULL), gametype_buttons(), marriage_selector_buttons() { this->ui->add_window(*this); this->signal_realize().connect(sigc::mem_fun(*this, &Reservation::init)); return ; } // Reservation::Reservation(Table* const table, Player const& player) /** ** Destruktor ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.5.4 **/ Reservation::~Reservation() { return ; } // Reservation::~Reservation() /** ** create all subelements ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.5.4 **/ void Reservation::init() { this->set_icon(this->ui->icon); if (this->player->game().humanno() <= 1) this->ui->translations->add(*this, ::translation("~reservation")); else this->ui->translations->add(*this, ::translation("~reservation (%sname%)", this->player->name())); this->set_position(Gtk::WIN_POS_CENTER_ON_PARENT); this->announce_button = Gtk::manage(new Gtk::StockButton(Gtk::Stock::OK, "reservation announce")); this->ui->translations->add(*this->announce_button, ::translation("reservation announce")); this->add_action_widget(*this->announce_button, Gtk::RESPONSE_ACCEPT); this->notebook = Gtk::manage(new Gtk::Notebook()); this->notebook->set_tab_pos(Gtk::POS_LEFT); this->notebook->signal_switch_page().connect(sigc::mem_fun(*this, &Reservation::switch_page_event)); this->swines_button = Gtk::manage(new Gtk::CheckButton("swines")); this->ui->translations->add(*this->swines_button, ::translation("swines")); this->hyperswines_button = Gtk::manage(new Gtk::CheckButton("hyperswines")); this->ui->translations->add(*this->hyperswines_button, ::translation("hyperswines")); this->announce_button->grab_default(); this->get_vbox()->add(*(this->notebook)); { // create the buttons Gtk::RadioButton::Group gametype_group; for (int g = GAMETYPE::FIRST; g <= GAMETYPE::LAST; g++) { this->gametype_buttons.push_back(Gtk::manage(new Gtk::RadioButton(gametype_group, "type"))); this->gametype_buttons.back()->set_data("gametype", new GameType(GameType(g))); this->ui->translations->add(*this->gametype_buttons.back(), ::translation(static_cast(g))); this->gametype_buttons.back()->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &Reservation::gametype_changed), g)); } // for (g \in GAMETYPE) Gtk::RadioButton::Group marriage_selector_group; for (int m = MARRIAGE_SELECTOR::FIRST; m <= MARRIAGE_SELECTOR::LAST; m++) { this->marriage_selector_buttons.push_back(Gtk::manage(new Gtk::RadioButton(marriage_selector_group, "selector"))); this->marriage_selector_buttons.back()->set_data("selector", new MarriageSelector(MarriageSelector(m))); this->ui->translations->add(*(this->marriage_selector_buttons.back()), ::translation(static_cast(m))); } // for (m \in MARRIAGE_SELECTOR) } // create the buttons { // set the pages of the notebook { // General Gtk::Alignment* alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER, 0, 0)); alignment->set_border_width(2 ex); Gtk::Label* label = Gtk::manage(new Gtk::Label("general")); this->ui->translations->add(*label, ::translation("GameType::Group::general")); this->notebook->append_page(*alignment, *label); Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox(false, 1 ex)); alignment->add(*hbox); Gtk::VBox* vbox = NULL; { // the swines vbox = Gtk::manage(new Gtk::VBox(false, 10)); hbox->add(*vbox); { Gtk::Alignment* alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, 0, 0)); alignment->add(*this->swines_button); vbox->add(*alignment); } { Gtk::Alignment* alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, 0, 0)); vbox->add(*this->hyperswines_button); vbox->add(*alignment); } } // the swines { // gametypes vbox = Gtk::manage(new Gtk::VBox(false, 10)); hbox->add(*vbox); vbox->add(*this->gametype_buttons[GAMETYPE::NORMAL]); vbox->add(*this->gametype_buttons[GAMETYPE::THROWN_NINES]); vbox->add(*this->gametype_buttons[GAMETYPE::THROWN_KINGS]); vbox->add(*this->gametype_buttons[GAMETYPE::THROWN_NINES_AND_KINGS]); vbox->add(*this->gametype_buttons[GAMETYPE::FOX_HIGHEST_TRUMP]); vbox->add(*this->gametype_buttons[GAMETYPE::POVERTY]); } // gametypes { // marriage selectors vbox = Gtk::manage(new Gtk::VBox(false, 10)); hbox->add(*vbox); vbox->add(*this->gametype_buttons[GAMETYPE::MARRIAGE]); vbox->add(*indent(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_FOREIGN])); vbox->add(*indent(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_TRUMP])); vbox->add(*indent(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_COLOR])); vbox->add(*indent(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_CLUB])); vbox->add(*indent(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_SPADE])); vbox->add(*indent(*this->marriage_selector_buttons[MARRIAGE_SELECTOR::FIRST_HEART])); } // marriage selectors } // General { // Solo Gtk::Alignment* alignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER, 0, 0)); alignment->set_border_width(2 ex); Gtk::Label* label = Gtk::manage(new Gtk::Label("solo")); this->ui->translations->add(*label, ::translation("GameType::Group::solo")); this->notebook->append_page(*alignment, *label); Gtk::Table* table = Gtk::manage(new Gtk::Table(4, 3)); table->set_row_spacings(10); table->set_col_spacings(10); alignment->add(*table); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_CLUB]), 0, 1, 0, 1); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_SPADE]), 0, 1, 1, 2); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_HEART]), 0, 1, 2, 3); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_DIAMOND]), 0, 1, 3, 4); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_MEATLESS]), 1, 2, 0, 1); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_JACK]), 1, 2, 1, 2); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_QUEEN]), 1, 2, 2, 3); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_KING]), 1, 2, 3, 4); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_QUEEN_JACK]), 2, 3, 0, 1); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_KING_JACK]), 2, 3, 1, 2); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_KING_QUEEN]), 2, 3, 2, 3); table->attach(*(this->gametype_buttons[GAMETYPE::SOLO_KOEHLER]), 2, 3, 3, 4); } // Solo } // set the pages of the notebook { // signals this->announce_button->signal_clicked().connect(sigc::mem_fun(*this, &Gtk::Widget::hide) ); this->swines_button->signal_toggled().connect(sigc::mem_fun(*this, &Reservation::check_poverty)); } // signals this->show_all_children(); return ; } // void Reservation::init() /** ** gets a reservation ** ** @param - ** ** @return reservation ** ** @author Diether Knof ** ** @version 0.6.0 **/ ::Reservation Reservation::get() { this->realize(); this->notebook->set_current_page(0); this->sensitivity_update(); this->set_default(); { // adjust some translations this->ui->translations->change(*this->gametype_buttons[GAMETYPE::THROWN_NINES], ::translation("GameType::%tnumber% nines", ::translation(DK::Utils::String::to_string(this->ui->game().rule()(Rule::MIN_NUMBER_OF_THROWING_NINES))))); this->ui->translations->change(*this->gametype_buttons[GAMETYPE::THROWN_KINGS], ::translation("GameType::%tnumber% kings", ::translation(DK::Utils::String::to_string(this->ui->game().rule()(Rule::MIN_NUMBER_OF_THROWING_KINGS))))); this->ui->translations->change(*this->gametype_buttons[GAMETYPE::THROWN_NINES_AND_KINGS], ::translation("GameType::%tnumber% nines and kings", ::translation(DK::Utils::String::to_string(this->ui->game().rule()(Rule::MIN_NUMBER_OF_THROWING_NINES_AND_KINGS))))); if (this->player->hand().numberofclubqueens() == this->player->game().rule()(Rule::NUMBER_OF_SAME_CARDS)) this->ui->translations->change(*this->gametype_buttons[GAMETYPE::NORMAL], ::translation(::GAMETYPE::MARRIAGE_SILENT)); else this->ui->translations->change(*this->gametype_buttons[GAMETYPE::NORMAL], ::translation(::GAMETYPE::NORMAL)); } // adjust some translations this->present(); while (!this->ui->thrower && this->is_visible()) ::ui->wait(); this->ui->game().set_type(GAMETYPE::NORMAL); ::Reservation reservation; { // set the reservation for (vector::iterator widget = this->gametype_buttons.begin(); widget != this->gametype_buttons.end(); widget++) if ((*widget)->get_active()) reservation.game_type = *(static_cast((*widget)->get_data("gametype"))); if (reservation.game_type == GAMETYPE::MARRIAGE) { for (vector::iterator widget = this->marriage_selector_buttons.begin(); widget != this->marriage_selector_buttons.end(); widget++) if ((*widget)->get_active()) reservation.marriage_selector = *(static_cast((*widget)->get_data("selector"))); } // if (reservation.game_type == GAMETYPE::MARRIAGE) reservation.swines = this->swines_button->get_active(); reservation.hyperswines = this->hyperswines_button->get_active(); } // set the reservation this->hide(); return reservation; } // ::Reservation Reservation::get() /** ** nothing ** ** @param update whether to update the area ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.0 **/ void Reservation::draw(bool const update) { // this function is needed because it is virtual in base class 'HTIN' return ; } // void Reservation::draw(bool update) /** ** set to default values ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.0 **/ void Reservation::set_default() { ::Reservation const reservation = this->player->reservation_get_default(); this->sensitivity_update(); this->swines_button->set_active(reservation.swines); this->hyperswines_button->set_active(reservation.hyperswines); // special case: with swines announced the player does not have a poverty if ( (reservation.game_type == GAMETYPE::POVERTY) && (this->player->hand().numberofpovertycards() > Rule::MAX_NUMBER_OF_POVERTY_TRUMPS) ) this->swines_button->set_active(false); this->gametype_buttons[reservation.game_type]->set_active(); this->marriage_selector_buttons[reservation.marriage_selector]->set_active(); this->name().draw(true); this->table().name(this->player->game().startplayer()).draw(true); { // switch to the game type from the bug report replay if ( ::bug_report_replay && (::bug_report_replay->soloplayer_no() == this->player->no() )) { this->gametype_buttons[::bug_report_replay->game_type()]->set_active(); if (GAMETYPE::is_solo(::bug_report_replay->game_type())) this->notebook->set_current_page(1); if (::bug_report_replay->game_type() == GAMETYPE::MARRIAGE) this->marriage_selector_buttons[::bug_report_replay->marriage_selector()]->set_active(); } } // switch to the game type from the bug report replay return ; } // void Reservation::set_default() /** ** update the sensitivity ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.5.4 **/ void Reservation::sensitivity_update() { if (!this->is_realized()) return ; if (::game_status != GAMESTATUS::GAME_RESERVATION) return ; ::Rule const& rule = this->player->game().rule(); //::Player const& player = this->player->game().player_current(); ::Player const& player = *(this->player); ::Hand const& hand = player.hand(); if (rule(Rule::SWINES) && !rule(Rule::SWINE_ONLY_SECOND)) this->swines_button->show(); else this->swines_button->hide(); this->swines_button->set_sensitive(hand.has_swines()); if (rule(Rule::HYPERSWINES)) this->hyperswines_button->show(); else this->hyperswines_button->hide(); this->hyperswines_button->set_sensitive(hand.has_hyperswines()); for (vector::iterator widget = this->gametype_buttons.begin(); widget != this->gametype_buttons.end(); widget++) if (rule(*(static_cast((*widget)->get_data("gametype"))))) (*widget)->show(); else (*widget)->hide(); if (rule(Rule::SOLO)) this->notebook->get_nth_page(1)->show(); else this->notebook->get_nth_page(1)->hide(); for (vector::iterator widget = this->marriage_selector_buttons.begin(); widget != this->marriage_selector_buttons.end(); widget++) if (rule(*(static_cast((*widget)->get_data("selector"))))) (*widget)->show(); else (*widget)->hide(); this->gametype_buttons[GAMETYPE::THROWN_NINES]->set_sensitive((hand.numberofnines() >= rule(Rule::MIN_NUMBER_OF_THROWING_NINES)) && rule(GAMETYPE::THROWN_NINES)); this->gametype_buttons[GAMETYPE::THROWN_KINGS]->set_sensitive((hand.numberofkings() >= rule(Rule::MIN_NUMBER_OF_THROWING_KINGS)) && rule(GAMETYPE::THROWN_KINGS)); this->gametype_buttons[GAMETYPE::THROWN_NINES_AND_KINGS]->set_sensitive((hand.numberofnines() + hand.numberofkings() >= rule(Rule::MIN_NUMBER_OF_THROWING_NINES_AND_KINGS)) && rule(GAMETYPE::THROWN_NINES_AND_KINGS)); this->gametype_buttons[GAMETYPE::POVERTY]->set_sensitive(hand.has_poverty()); { // look, whether there is a card that is higher than the fox unsigned c; for (c = 0; c < player.hand().cardsnumber(); c++) // check with diamond ten because of swines! if ( Card(Card::DIAMOND, Card::TEN).less(player.hand().card(c)) && !player.hand().card(c).istrumpace()) break; this->gametype_buttons[GAMETYPE::FOX_HIGHEST_TRUMP]->set_sensitive((c == player.hand().cardsnumber()) && rule(GAMETYPE::POVERTY)); } // look, whether there is a card that is higher than the fox this->gametype_buttons[GAMETYPE::MARRIAGE]->set_sensitive((hand.numberofclubqueens() == rule(Rule::NUMBER_OF_SAME_CARDS))); for (vector::iterator widget = this->marriage_selector_buttons.begin(); widget != this->marriage_selector_buttons.end(); widget++) { bool const selected = this->gametype_buttons[GAMETYPE::MARRIAGE]->get_active(); (*widget)->set_sensitive(selected); //this->gametype_buttons[GAMETYPE::MARRIAGE]->sensitive()); } this->check_poverty(); return ; } // void Reservation::sensitivity_update() /** ** the gametype has changed ** ** @param gametype new game type ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.0 **/ void Reservation::gametype_changed(int const gametype) { if (gametype == GAMETYPE::MARRIAGE) { bool const selected = this->gametype_buttons[gametype]->get_active(); for (vector::iterator widget = this->marriage_selector_buttons.begin(); widget != this->marriage_selector_buttons.end(); widget++) (*widget)->set_sensitive(selected); } // if (gametype == GAMETYPE::MARRIAGE) // '::party.game()' here, because the game has to be changed, // 'this->player->game()' is a const game GameType const old_gametype = this->player->game().type(); this->ui->game().set_type(static_cast(gametype)); this->ui->game().players_hands_sort(); this->icongroup().draw_team(true); this->name().draw(true); this->table().name(this->player->game().startplayer()).draw(true); // update the swines if ( this->ui->game().rule()(Rule::SWINES) && (old_gametype != gametype) && ( GAMETYPE::is_color_solo(old_gametype) || GAMETYPE::is_color_solo(static_cast(gametype))) ) { ::Hand const& hand = this->player->hand(); this->swines_button->set_sensitive(hand.has_swines()); this->swines_button->set_active(hand.has_swines() && this->ui->game().rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN)); this->hyperswines_button->set_sensitive(hand.has_hyperswines()); this->hyperswines_button->set_active(hand.has_hyperswines() && this->ui->game().rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN)); } // if (gametype has changed to/from color solo) return ; } // void Reservation::gametype_changed(int const gametype) /** ** check, whether a poverty is valid ** (because of rules: poverty fox do not count, poverty fox shift extra) ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Reservation::check_poverty() { // special case: with swines announced the player does not have a poverty if (!(this->player->hand().numberofpovertycards() > Rule::MAX_NUMBER_OF_POVERTY_TRUMPS) ) return ; if (this->swines_button->get_active()) { this->gametype_buttons[GAMETYPE::POVERTY]->set_sensitive(false); if (this->gametype_buttons[GAMETYPE::POVERTY]->get_active()) this->gametype_buttons[GAMETYPE::NORMAL]->set_active(); } else { // if (this->swines_button->active()) this->gametype_buttons[GAMETYPE::POVERTY]->set_sensitive(true); } // if (this->swines_button->active()) return ; } // void Reservation::check_poverty() /** ** page change ** if the user switches to the first page, activate the default reservation ** ** @param page the new page ** @param pageno the number of the page ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.4 **/ void Reservation::switch_page_event(GtkNotebookPage* page, guint pageno) { #ifdef WORKAROUND // else the 'this->is_visible()' segfaults when starting a new tournament if (::game_status != GAMESTATUS::GAME_RESERVATION) return ; #endif if (!this->is_visible()) return ; if (pageno == 0) { this->ui->game().set_type(GAMETYPE::NORMAL); this->set_default(); } // if (pageno == 0) return ; } // void Reservation::switch_page_event(GtkNotebookPage*, guint pageno) } // namespace UI_GTKMM_NS #endif // #ifdef USE_UI_GTKMM