1 /**********************************************************************
2  *
3  *   FreeDoko a Doppelkopf-Game
4  *
5  *   Copyright (C) 2001 – 2018 by Diether Knof and Borg Enders
6  *
7  *   This program is free software; you can redistribute it and/or
8  *   modify it under the terms of the GNU General Public License as
9  *   published by the Free Software Foundation; either version 2 of
10  *   the License, or (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *   You can find this license in the file 'gpl.txt'.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program; if not, write to the Free Software
20  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  *   MA  02111-1307  USA
22  *
23  *  Contact:
24  *    Diether Knof dknof@posteo.de
25  *
26  *********************************************************************/
27 
28 #include "constants.h"
29 
30 #ifdef USE_UI_GTKMM
31 
32 #include "party_settings.h"
33 #include "players.h"
34 #include "rules.h"
35 
36 #include "ui.h"
37 #include "main_window.h"
38 #include "bug_report.h"
39 #include "first_run.h"
40 #include "program_updated.h"
41 
42 #include "../../party/party.h"
43 #include "../../player/player.h"
44 #include "../../player/aiconfig.h"
45 #include "../../os/bug_report_replay.h"
46 #include "../../misc/preferences.h"
47 #include "../../utils/random.h"
48 
49 #include <gtkmm/radiobutton.h>
50 #include <gtkmm/spinbutton.h>
51 #include <gtkmm/frame.h>
52 #include <gtkmm/main.h>
53 #include <gtkmm/grid.h>
54 #include <gtkmm/filechooserdialog.h>
55 namespace UI_GTKMM_NS {
56 
57 /** constructor
58  **
59  ** @param    parent   the parent object
60  **/
PartySettings(Base * const parent)61 PartySettings::PartySettings(Base* const parent) :
62   Base(parent),
63   StickyDialog("FreeDoko – " + _("Window::party settings"),
64                *parent->ui->main_window, false)
65 {
66   this->ui->add_window(*this);
67 
68   this->init();
69 
70   this->signal_show().connect(sigc::mem_fun(*this, &PartySettings::update));
71   this->signal_key_press_event().connect(sigc::mem_fun(*this,
72                                                        &PartySettings::key_press));
73 
74   this->ui->bug_report->set_dnd_destination(*this);
75 } // PartySettings::PartySettings(Base* parent)
76 
77 /** destruktor
78  **/
79 PartySettings::~PartySettings() = default;
80 
81 /** create all subelements
82  **/
83 void
init()84 PartySettings::init()
85 {
86 #ifdef POSTPONED
87   auto& party = this->ui->party();
88 #else
89   auto& party = *::party;
90 #endif
91 
92   this->set_icon(this->ui->icon);
93 
94   this->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
95 
96   this->players = make_unique<Players>(this);
97   this->rules = make_unique<Rules>(this);
98 
99   this->load_bug_report_button
100     = Gtk::manage(new Gtk::Button(_("Button::load bug report")));
101   this->load_bug_report_button->set_image_from_icon_name("document-open");
102   this->load_bug_report_button->set_always_show_image();
103 #ifndef RELEASE
104   this->add_action_widget(*this->load_bug_report_button,
105                           Gtk::RESPONSE_NONE);
106 #endif
107   this->start_party_button
108     = Gtk::manage(new Gtk::Button(_("Button::start party")));
109   this->add_action_widget(*this->start_party_button, Gtk::RESPONSE_CLOSE);
110   this->start_party_button->set_can_default();
111 
112   this->close_button = add_close_button(*this);
113 
114   { // seed
115     this->seed_value = Gtk::manage(new Gtk::SpinButton(1, 0));
116     this->seed_value->set_value(0);
117     this->seed_value->set_range(0, Random::max_seed());
118     this->seed_value->set_increments(1, 1000);
119     this->seed_random = Gtk::manage(new Gtk::CheckButton(_("Button::random")));
120   } // seed
121   { // duration
122     this->rule_number_of_rounds_limited
123       = Gtk::manage(new Gtk::CheckButton(_(Rule::Type::number_of_rounds) + ":"));
124     this->rule_number_of_rounds
125       = Gtk::manage(new Gtk::SpinButton());
126     this->rule_number_of_rounds->set_increments(1, 10);
127     this->rule_points_limited
128       = Gtk::manage(new Gtk::CheckButton(_(Rule::Type::points) + ":"));
129     this->rule_points
130       = Gtk::manage(new Gtk::SpinButton());
131     this->rule_points->set_increments(1, 10);
132   } // duration
133   { // startplayer
134     this->startplayer_random = Gtk::manage(new Gtk::RadioButton(_("Button::random")));
135   } // startplayer
136 
137   this->configure_players
138     = Gtk::manage(new Gtk::Button(_("Button::configure players")));
139   this->configure_players->set_image_from_icon_name("face-smile");
140   this->configure_players->set_always_show_image();
141   this->configure_rules
142     = Gtk::manage(new Gtk::Button(_("Button::configure rules")));
143   this->configure_rules->set_image_from_icon_name("preferences-other");
144   this->configure_rules->set_always_show_image();
145 
146 
147   { // create the startplayer buttons
148     auto startplayer_group
149       = this->startplayer_random->get_group();
150     for (auto const& p : party.players()) {
151       this->startplayer.push_back(Gtk::manage(new Gtk::RadioButton(startplayer_group, p.name())));
152     }
153     { // the swap buttons
154 #ifdef WORKAROUND
155       // MS-Windows does not show the arrows
156 #include "arrows/arrow_lu.xpm"
157 #include "arrows/arrow_ur.xpm"
158 #include "arrows/arrow_rd.xpm"
159 #include "arrows/arrow_dl.xpm"
160       this->swap_players_buttons.push_back(Gtk::manage(new Gtk::Button()));
161       this->swap_players_buttons.back()->add(*Gtk::manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(arrow_lu_xpm))));
162       this->swap_players_buttons.push_back(Gtk::manage(new Gtk::Button()));
163       this->swap_players_buttons.back()->add(*Gtk::manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(arrow_ur_xpm))));
164       this->swap_players_buttons.push_back(Gtk::manage(new Gtk::Button()));
165       this->swap_players_buttons.back()->add(*Gtk::manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(arrow_rd_xpm))));
166       this->swap_players_buttons.push_back(Gtk::manage(new Gtk::Button()));
167       this->swap_players_buttons.back()->add(*Gtk::manage(new Gtk::Image(Gdk::Pixbuf::create_from_xpm_data(arrow_dl_xpm))));
168 
169       for (auto& b : this->swap_players_buttons)
170         b->set_relief(Gtk::RELIEF_NONE);
171 #else
172       this->swap_players_buttons.push_back(Gtk::manage(new Gtk::Button(Glib::ustring(1, static_cast<gunichar>(0x2196))))); // up left
173       this->swap_players_buttons.push_back(Gtk::manage(new Gtk::Button(Glib::ustring(1, static_cast<gunichar>(0x2197))))); // up right
174       this->swap_players_buttons.push_back(Gtk::manage(new Gtk::Button(Glib::ustring(1, static_cast<gunichar>(0x2199))))); // down right
175       this->swap_players_buttons.push_back(Gtk::manage(new Gtk::Button(Glib::ustring(1, static_cast<gunichar>(0x2198))))); // down left
176 #endif
177     } // the swap buttons
178   } // create the startplayer buttons
179   { // Layout
180     auto hbox = Gtk::manage(new Gtk::Box());
181     hbox->set_spacing(1 EM);
182     hbox->set_border_width(1 EM);
183     this->get_content_area()->add(*hbox);
184     { // actions
185       { // configure
186         auto vbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL, 1 EX));
187         vbox->set_homogeneous();
188         vbox->set_halign(Gtk::ALIGN_CENTER);
189         vbox->set_valign(Gtk::ALIGN_CENTER);
190 
191         vbox->add(*this->configure_rules);
192         vbox->add(*this->configure_players);
193         hbox->pack_end(*vbox, false, true);
194       } // configure
195 
196     } // actions
197 
198     { // settings
199       auto vbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL, 1 EX));
200       vbox->set_halign(Gtk::ALIGN_CENTER);
201       vbox->set_valign(Gtk::ALIGN_CENTER);
202 
203       { // seed
204         this->seed_frame = Gtk::manage(new Gtk::Frame(_("card distribution")));
205         auto grid = Gtk::manage(new Gtk::Grid());
206 
207         grid->set_halign(Gtk::ALIGN_CENTER);
208         grid->set_border_width(2 EX);
209         grid->set_row_spacing(1 EX);
210         grid->set_column_spacing(1 EM);
211 
212         auto label = Gtk::manage(new Gtk::Label(_("Label::seed") + ":"));
213         grid->attach(*label, 0, 0, 1, 1);
214         grid->attach(*this->seed_random, 1, 0, 1, 1);
215         grid->attach(*this->seed_value, 1, 1, 1, 1);
216         seed_frame->add(*grid);
217         vbox->add(*this->seed_frame);
218       } // seed
219 
220       { // duration
221         auto duration_frame = Gtk::manage(new Gtk::Frame(_("party duration")));
222 
223         auto grid = Gtk::manage(new Gtk::Grid());
224         grid->set_halign(Gtk::ALIGN_CENTER);
225         grid->set_border_width(2 EX);
226         grid->set_row_spacing(1 EX);
227         grid->set_column_spacing(1 EM);
228 
229         grid->attach(*this->rule_number_of_rounds_limited, 0, 0, 1, 1);
230         grid->attach(*this->rule_number_of_rounds, 1, 0, 1, 1);
231         grid->attach(*this->rule_points_limited, 0, 1, 1, 1);
232         grid->attach(*this->rule_points, 1, 1, 1, 1);
233         duration_frame->add(*grid);
234         vbox->add(*duration_frame);
235       } // duration
236 
237       { // startplayer
238         this->startplayer_frame
239           = Gtk::manage(new Gtk::Frame(_("startplayer")));
240         vbox->add(*this->startplayer_frame);
241 
242         auto grid = Gtk::manage(new Gtk::Grid());
243         grid->set_halign(Gtk::ALIGN_CENTER);
244         grid->set_row_homogeneous(true);
245         grid->set_column_homogeneous(true);
246         grid->set_border_width(2 EX);
247         grid->set_row_spacing(1 EX);
248         grid->set_column_spacing(1 EM);
249 
250         grid->attach(*this->startplayer_random, 1, 1, 1, 1);
251         grid->attach(*this->startplayer[0], 1, 2, 1, 1);
252         grid->attach(*this->startplayer[1], 0, 1, 1, 1);
253         grid->attach(*this->startplayer[2], 1, 0, 1, 1);
254         grid->attach(*this->startplayer[3], 2, 1, 1, 1);
255         grid->attach(*this->swap_players_buttons[0], 0, 2, 1, 1);
256         grid->attach(*this->swap_players_buttons[1], 0, 0, 1, 1);
257         grid->attach(*this->swap_players_buttons[2], 2, 0, 1, 1);
258         grid->attach(*this->swap_players_buttons[3], 2, 2, 1, 1);
259         this->startplayer_frame->add(*grid);
260       } // startplayer
261       hbox->pack_start(*vbox, true, true);
262     } // settings
263 
264   } // Layout
265 
266   { // signals
267     this->load_bug_report_button->signal_clicked().connect(sigc::mem_fun(*this,
268                                                                          &PartySettings::load_bug_report)
269                                                           );
270     this->start_party_button->signal_clicked().connect(sigc::mem_fun(*this,
271                                                                      &PartySettings::start_party_event)
272                                                       );
273 
274     this->seed_value->signal_value_changed().connect(sigc::mem_fun(*this, &PartySettings::seed_change_event));
275     this->seed_random->signal_toggled().connect(sigc::mem_fun(*this, &PartySettings::seed_change_event));
276     this->seed_random->signal_toggled().connect(sigc::mem_fun(*this,
277                                                               &PartySettings::seed_value_sensitivity_update)
278                                                );
279 
280     this->rule_number_of_rounds_limited->signal_toggled().connect(sigc::bind<int const>(sigc::mem_fun(*this, &PartySettings::rule_change), Rule::Type::number_of_rounds_limited));
281     this->rule_number_of_rounds->signal_value_changed().connect(sigc::bind<int const>(sigc::mem_fun(*this, &PartySettings::rule_change), Rule::Type::number_of_rounds));
282     this->rule_points_limited->signal_toggled().connect(sigc::bind<int const>(sigc::mem_fun(*this, &PartySettings::rule_change), Rule::Type::points_limited));
283     this->rule_points->signal_value_changed().connect(sigc::bind<int const>(sigc::mem_fun(*this, &PartySettings::rule_change), Rule::Type::points));
284 
285     this->startplayer_random->signal_toggled().connect(sigc::mem_fun(*this, &PartySettings::startplayer_change_event));
286     for (auto& p : this->startplayer)
287       p->signal_toggled().connect(sigc::mem_fun(*this, &PartySettings::startplayer_change_event));
288 
289     for (unsigned p = 0; p < this->swap_players_buttons.size(); ++p)
290       this->swap_players_buttons[p]->signal_clicked().connect(sigc::bind<unsigned const>(sigc::mem_fun(*this, &PartySettings::swap_players_event), p));
291 
292     this->configure_players->signal_clicked().connect(sigc::mem_fun0(*this->players,
293                                                                      &Gtk::Window::present)
294                                                      );
295     this->configure_rules->signal_clicked().connect(sigc::mem_fun0(*this->rules,
296                                                                    &Gtk::Window::present)
297                                                    );
298   } // signals
299 
300   this->show_all_children();
301   this->sensitivity_update();
302   this->update();
303 
304   party.signal_seed_changed().connect_back(*this, &PartySettings::update, this->disconnector_);
305   party.signal_startplayer_changed().connect_back(*this, &PartySettings::update, this->disconnector_);
306   party.rule().signal_changed().connect_back([this](auto type, auto old_value)
307                                              { this->rules_update();
308                                              this->rules->update(type); });
309 } // void PartySettings::init()
310 
311 /** get the party settings
312  **/
313 void
get()314 PartySettings::get()
315 {
316   if (::fast_play & FastPlay::party_start) {
317     ::fast_play.remove(FastPlay::party_start);
318     return ;
319   }
320 
321   auto& party = this->ui->party();
322   this->update();
323 
324   this->players->create_backup();
325   this->rules->create_backup();
326 
327   this->start_party_button->show();
328   this->start_party_button->grab_default();
329   this->start_party_button->grab_focus();
330 
331   this->present();
332   this->start_party_button->grab_focus();
333 
334   while (   !this->ui->thrower
335          && this->is_visible()
336          && (::game_status == GameStatus::party_new)) {
337     ::ui->wait();
338     if (::bug_report_replay
339         && ::bug_report_replay->auto_start_party())
340       break;
341   }
342 
343   if (::game_status == GameStatus::party_new) {
344     // set the seed
345     if (this->seed_random->get_active()) {
346       party.set_random_seed();
347     } else {
348       party.set_seed(this->seed_value->get_value());
349     }
350 
351     // set the startplayer
352     if (this->startplayer_random->get_active())
353       party.set_random_startplayer();
354     else
355       for (unsigned p = 0; p < party.players().size(); ++p)
356         if (this->startplayer[p]->get_active()) {
357           party.set_startplayer(p);
358           break;
359         }
360 
361     this->players->create_backup();
362     this->rules->create_backup();
363   } // if (::game_status == GameStatus::party_new)
364 
365   this->hide();
366 } // void PartySettings::get()
367 
368 /** show the window.
369  ** Shows/hides the action buttons
370  **/
371 void
on_show()372 PartySettings::on_show()
373 {
374 #ifdef GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
375   this->Dialog::on_show();
376 #endif
377 
378   if (this->ui->first_run_window)
379     this->ui->first_run_window->raise();
380   if (this->ui->program_updated_window)
381     this->ui->program_updated_window->raise();
382 
383   this->update();
384 } // void PartySettings::show()
385 
386 /** load the bug report
387  **/
388 void
load_bug_report()389 PartySettings::load_bug_report()
390 {
391   this->ui->bug_report->load_file_chooser->present();
392 } // void PartySettings::load_bug_report()
393 
394 /** update the sensitivity of all elements
395  **/
396 void
sensitivity_update()397 PartySettings::sensitivity_update()
398 {
399   auto sensitive = (::game_status == GameStatus::party_new);
400   if (sensitive)
401     this->seed_value_sensitivity_update();
402   else
403     this->seed_value->set_sensitive(false);
404 
405   this->seed_random->set_sensitive(sensitive);
406 
407   this->rule_number_of_rounds_limited->set_sensitive(sensitive);
408   this->rule_number_of_rounds->set_sensitive(sensitive);
409   this->rule_points_limited->set_sensitive(sensitive);
410   this->rule_points->set_sensitive(sensitive);
411 
412   for (auto& p : this->startplayer)
413     p->set_sensitive(sensitive);
414   this->startplayer_random->set_sensitive(sensitive);
415   for (auto p : this->swap_players_buttons)
416     p->set_sensitive(sensitive);
417 
418   this->players->sensitivity_update();
419   this->rules->sensitivity_update();
420 
421   this->load_bug_report_button->set_sensitive(sensitive);
422   this->start_party_button->set_sensitive(sensitive);
423 
424   if (::preferences(::Preferences::Type::additional_party_settings)) {
425     this->seed_frame->show();
426     this->startplayer_frame->show();
427   } else {
428     this->seed_frame->hide();
429     this->startplayer_frame->hide();
430   }
431 } // void PartySettings::sensitivity_update()
432 
433 /** update the sensitivity of 'seed_value'
434  **/
435 void
seed_value_sensitivity_update()436 PartySettings::seed_value_sensitivity_update()
437 {
438   switch (::game_status) {
439   case GameStatus::party_new:
440   case GameStatus::party_initial_loaded:
441     this->seed_value->set_sensitive(!(this->seed_random->get_active()));
442     break;
443   default:
444     this->seed_value->set_sensitive(false);
445     break;
446   } // switch (::game_status);
447 } // void PartySettings::seed_value_sensitivity_update()
448 
449 /** update the widgets
450  **/
451 void
update()452 PartySettings::update()
453 {
454   if (!this->is_visible())
455     return ;
456 
457   auto& party = this->ui->party();
458   this->sensitivity_update();
459 
460   switch (::game_status) {
461   case GameStatus::party_new:
462 #ifndef RELEASE
463     this->load_bug_report_button->show();
464 #endif
465     this->start_party_button->show();
466     this->close_button->hide();
467 
468     this->start_party_button->grab_default();
469     break;
470   default:
471     this->load_bug_report_button->hide();
472     this->start_party_button->hide();
473     this->close_button->show();
474 
475     this->close_button->grab_default();
476     break;
477   } // switch (::game_status)
478 
479   auto const random_seed = party.random_seed();
480   if (!random_seed)
481     this->seed_value->set_value(party.seed());
482   this->seed_random->set_active(random_seed);
483 
484   this->rules_update();
485 
486   if (party.random_startplayer())
487     this->startplayer_random->set_active(true);
488   else
489     this->startplayer[party.startplayer()]->set_active(true);
490 
491   for (auto& p : party.players()) {
492     this->name_update_local(p);
493   }
494   this->players->update();
495   this->rules->update_all();
496 } // void PartySettings::update()
497 
498 /** update the rules (value, sensitivity)
499  **/
500 void
rules_update()501 PartySettings::rules_update()
502 {
503   auto const& rule = this->ui->party().rule();
504 
505   this->rule_number_of_rounds_limited->set_active(rule(Rule::Type::number_of_rounds_limited));
506   this->rule_number_of_rounds_limited->set_sensitive(rule.dependencies(Rule::Type::number_of_rounds_limited));
507   this->rule_number_of_rounds->set_value(rule(Rule::Type::number_of_rounds));
508   this->rule_number_of_rounds->set_sensitive(rule(Rule::Type::number_of_rounds_limited));
509   this->rule_number_of_rounds->set_value(rule(Rule::Type::number_of_rounds));
510   {
511     auto const value = rule(Rule::Type::number_of_rounds);
512     this->rule_number_of_rounds->set_range(rule.min(Rule::Type::number_of_rounds),
513                                            rule.max(Rule::Type::number_of_rounds));
514     this->rule_number_of_rounds->set_value(value);
515   }
516 
517   this->rule_points_limited->set_active(rule(Rule::Type::points_limited));
518   this->rule_points_limited->set_sensitive(rule.dependencies(Rule::Type::points_limited));
519   this->rule_points->set_sensitive(true);
520   this->rule_points->set_value(rule(Rule::Type::points));
521   this->rule_points->set_sensitive(rule(Rule::Type::points_limited));
522   {
523     auto const value = rule(Rule::Type::points);
524     this->rule_points->set_range(rule.min(Rule::Type::points),
525                                  rule.max(Rule::Type::points));
526     this->rule_points->set_value(value);
527   }
528 } // void PartySettings::rules_update()
529 
530 /** the rules have been changed
531  **
532  ** @param    type        the type of the rule that has changed
533  **/
534 void
rule_change(int const type)535 PartySettings::rule_change(int const type)
536 {
537   auto& rule = this->ui->party().rule();
538   switch(type) {
539   case Rule::Type::number_of_rounds_limited:
540     rule.set(Rule::Type::number_of_rounds_limited,
541              this->rule_number_of_rounds_limited->get_active());
542     break;
543   case Rule::Type::number_of_rounds:
544     rule.set(Rule::Type::number_of_rounds,
545              this->rule_number_of_rounds->get_value_as_int());
546     break;
547   case Rule::Type::points_limited:
548     rule.set(Rule::Type::points_limited,
549              this->rule_points_limited->get_active());
550     break;
551   case Rule::Type::points:
552     rule.set(Rule::Type::points,
553              this->rule_points->get_value_as_int());
554     break;
555   default:
556     break;
557   } // switch(type)
558 } // void PartySettings::rule_change(int type)
559 
560 /** the players 'player_a' and 'player_b' have been swapped
561  **
562  ** @param    player_a   first player
563  ** @param    player_b   second player
564  **/
565 void
players_swapped(Player const & player_a,Player const & player_b)566 PartySettings::players_swapped(Player const& player_a,
567                                Player const& player_b)
568 {
569   this->name_update_local(player_a);
570   this->name_update_local(player_b);
571 
572   this->players->players_swapped(player_a, player_b);
573 } // void PartySettings::players_swapped(Player player_a, Player player_b)
574 
575 /** update 'player'
576  **
577  ** @param    player   player to update
578  **/
579 void
player_update(Player const & player)580 PartySettings::player_update(Player const& player)
581 {
582   if (::game_status <= GameStatus::party_new)
583     return ;
584 
585   this->name_update_local(player);
586   this->players->player_update(player);
587 } // void PartySettings::player_update(Player player)
588 
589 /** update the name of 'player'
590  **
591  ** @param    player   player with the new name
592  **/
593 void
name_update(Player const & player)594 PartySettings::name_update(Player const& player)
595 {
596   this->name_update_local(player);
597   this->players->name_update(player);
598 } // void PartySettings::name_update(Player const& player)
599 
600 /** update the name of 'player'
601  **
602  ** @param    player   player with the new name
603  **/
604 void
name_update_local(Player const & player)605 PartySettings::name_update_local(Player const& player)
606 {
607   Pango::FontDescription fd;
608   fd.set_weight(player.type() == Player::Type::human
609                 ? Pango::WEIGHT_BOLD
610                 : Pango::WEIGHT_NORMAL);
611   auto const playerno = this->ui->party().players().no(player);
612   DEBUG_ASSERTION((playerno < UINT_MAX),
613                   "PlayerSettings::name_update_local(player)\n"
614                   "  player '" << player.name() << "' not found in the party");
615   if (playerno >= 4)
616     return ;
617 
618   this->startplayer[playerno]->get_child()->override_font(fd);
619 
620   this->startplayer[playerno]->set_label(player.name());
621 } // void PartySettings::name_update_local(Player player)
622 
623 /** update the voice of 'player'
624  **
625  ** @param    player   player with the new voice
626  **/
627 void
voice_update(Player const & player)628 PartySettings::voice_update(Player const& player)
629 {
630   this->players->voice_update(player);
631 } // void PartySettings::voice_update(Player player)
632 
633 /** update the aiconfig
634  **
635  ** @param    aiconfig   changed aiconfig
636  **/
637 void
aiconfig_update(Aiconfig const & aiconfig)638 PartySettings::aiconfig_update(Aiconfig const& aiconfig)
639 {
640   this->players->aiconfig_update(aiconfig);
641 } // void PartySettings::aiconfig_update(Aiconfig aiconfig)
642 
643 /** a new party is started
644  **/
645 void
start_party_event()646 PartySettings::start_party_event()
647 {
648   this->hide();
649   ::game_status = GameStatus::party_new;
650 } // void PartySettings::start_party_event()
651 
652 /** the seed has changed
653  **/
654 void
seed_change_event()655 PartySettings::seed_change_event()
656 {
657   auto& party = this->ui->party();
658   // set the seed
659   if (this->seed_random->get_active())
660     party.set_random_seed();
661   else
662     party.set_seed(this->seed_value->get_value());
663 } // void PartySettings::seed_change_event()
664 
665 /** the startplayer has changed
666  **/
667 void
startplayer_change_event()668 PartySettings::startplayer_change_event()
669 {
670   auto& party = this->ui->party();
671   // set the startplayer
672   if (this->startplayer_random->get_active())
673     party.set_random_startplayer();
674   else
675     for (unsigned p = 0; p < party.players().size(); ++p)
676       if (this->startplayer[p]->get_active()) {
677         party.set_startplayer(p);
678         break;
679       }
680 } // void PartySettings::startplayer_change_event()
681 
682 /** players shall be swapped
683  **
684  ** @param    p   player to swap with the following
685  **/
686 void
swap_players_event(unsigned const p)687 PartySettings::swap_players_event(unsigned const p)
688 {
689   auto& party = this->ui->party();
690   party.players().swap(p, (p + 1) % party.players().size());
691 } // void PartySettings::swap_players_event(unsigned p)
692 
693 /** a key has been pressed
694  **
695  ** @param    key   the key
696  **
697  ** @return   whether the key was used
698  **/
699 bool
key_press(GdkEventKey * const key)700 PartySettings::key_press(GdkEventKey* const key)
701 {
702   bool used = false;
703 
704   if ((key->state & ~GDK_SHIFT_MASK) == 0) {
705     switch (key->keyval) {
706     case GDK_KEY_p: // show the players
707       this->players->present();
708       used = true;
709       break;
710     case GDK_KEY_r: // show the rules
711       this->rules->present();
712       used = true;
713       break;
714     } // switch (key->keyval)
715   } // if ((key->state & ~GDK_SHIFT_MASK) == 0)
716 
717   return (used || this->ui->key_press(key));
718 } // bool PartySettings::key_press(GdkEventKey* key)
719 
720 } // namespace UI_GTKMM_NS
721 
722 #endif // #ifdef USE_UI_GTKMM
723