… | |
… | |
154 | |
154 | |
155 | $self->{imagebox}->remove ($_) for $self->{imagebox}->get_children; |
155 | $self->{imagebox}->remove ($_) for $self->{imagebox}->get_children; |
156 | $self->{imagebox}->add (gtk::image_from_data undef); |
156 | $self->{imagebox}->add (gtk::image_from_data undef); |
157 | $self->{imagebox}->show_all; |
157 | $self->{imagebox}->show_all; |
158 | |
158 | |
|
|
159 | if ($user->has_pic) { |
159 | # the big picture... |
160 | # the big picture... |
160 | appwin::userpic ($user->{name}, sub { |
161 | appwin::userpic ($user->{name}, sub { |
161 | return unless $self->{imagebox}; |
162 | return unless $self->{imagebox}; |
162 | if ($_[0]) { |
163 | if ($_[0]) { |
163 | $self->{imagebox}->remove ($_) for $self->{imagebox}->get_children; |
164 | $self->{imagebox}->remove ($_) for $self->{imagebox}->get_children; |
164 | $self->{imagebox}->add (gtk::image_from_data $_[0]); |
165 | $self->{imagebox}->add (gtk::image_from_data $_[0]); |
165 | $self->{imagebox}->show_all; |
166 | $self->{imagebox}->show_all; |
|
|
167 | } |
166 | } |
168 | }); |
167 | }); |
169 | } |
168 | } |
170 | } |
169 | |
171 | |
170 | $self->{clock}->configure (@{$rules}{qw(timesys time interval count)}); |
172 | $self->{clock}->configure (@{$rules}{qw(timesys time interval count)}); |
171 | } |
173 | } |
172 | |
174 | |
… | |
… | |
197 | $self = $self->SUPER::new(@_); |
199 | $self = $self->SUPER::new(@_); |
198 | |
200 | |
199 | $self->listen($self->{conn}); |
201 | $self->listen($self->{conn}); |
200 | |
202 | |
201 | $self->{window} = new Gtk2::Window 'toplevel'; |
203 | $self->{window} = new Gtk2::Window 'toplevel'; |
202 | my $title = $self->{channel} ? $self->owner->as_string." ".$self->opponent_string : "Game Window"; |
|
|
203 | $self->{window}->set_title("KGS Game $title"); |
|
|
204 | gtk::state $self->{window}, "game::window", undef, window_size => [600, 500]; |
204 | gtk::state $self->{window}, "game::window", undef, window_size => [600, 500]; |
205 | |
205 | |
206 | $self->{window}->signal_connect(delete_event => sub { |
206 | $self->{window}->signal_connect(delete_event => sub { |
207 | $self->part; |
207 | $self->part; |
208 | $self->destroy; |
208 | $self->destroy; |
… | |
… | |
244 | $self->{boardbox}->pack_start((my $aspect_frame = new Gtk2::AspectFrame "", 0.5, 0.5, 1, 0), 1, 1, 0); |
244 | $self->{boardbox}->pack_start((my $aspect_frame = new Gtk2::AspectFrame "", 0.5, 0.5, 1, 0), 1, 1, 0); |
245 | $aspect_frame->set (border_width => 0, shadow_type => 'none', label_xalign => 0.5); |
245 | $aspect_frame->set (border_width => 0, shadow_type => 'none', label_xalign => 0.5); |
246 | $self->{board_label} = $aspect_frame->get_label_widget; |
246 | $self->{board_label} = $aspect_frame->get_label_widget; |
247 | |
247 | |
248 | $aspect_frame->add($self->{canvas} = new Gtk2::DrawingArea); |
248 | $aspect_frame->add($self->{canvas} = new Gtk2::DrawingArea); |
249 | $self->{canvas}->double_buffered (0) if $::config->{conserve_memory}; |
249 | $self->{canvas}->double_buffered (0);# if $::config->{conserve_memory}; |
250 | |
250 | |
251 | $self->{canvas}->signal_connect(configure_event => \&configure_event, $self); |
251 | $self->{canvas}->signal_connect(configure_event => \&configure_event, $self); |
252 | $self->{canvas}->signal_connect(expose_event => \&expose_event, $self); |
252 | $self->{canvas}->signal_connect(expose_event => \&expose_event, $self); |
253 | |
253 | |
254 | # RIGHT PANE |
254 | # RIGHT PANE |
… | |
… | |
283 | |
283 | |
284 | sub event_update_users { |
284 | sub event_update_users { |
285 | my ($self, $add, $update, $remove) = @_; |
285 | my ($self, $add, $update, $remove) = @_; |
286 | |
286 | |
287 | $self->{userlist}->update ($add, $update, $remove); |
287 | $self->{userlist}->update ($add, $update, $remove); |
|
|
288 | |
|
|
289 | my %important; |
|
|
290 | $important{$self->{user1}{name}}++; |
|
|
291 | $important{$self->{user2}{name}}++; |
|
|
292 | $important{$self->{user3}{name}}++; |
|
|
293 | |
|
|
294 | if (my @users = grep $important{$_->{name}}, @$add) { |
|
|
295 | $self->{text}->append_text ("\n<header>Joins:</header>"); |
|
|
296 | $self->{text}->append_text (" <user>" . $_->as_string . "</user>") for @users; |
|
|
297 | } |
|
|
298 | if (my @users = grep $important{$_->{name}}, @$remove) { |
|
|
299 | $self->{text}->append_text ("\n<header>Parts:</header>"); |
|
|
300 | $self->{text}->append_text (" <user>" . $_->as_string . "</user>") for @users; |
|
|
301 | } |
|
|
302 | |
288 | } |
303 | } |
289 | |
304 | |
290 | sub join { |
305 | sub join { |
291 | my ($self) = @_; |
306 | my ($self) = @_; |
292 | return if $self->{joined}; |
307 | return if $self->{joined}; |
… | |
… | |
316 | sub expose_event { |
331 | sub expose_event { |
317 | my ($widget, $event, $self) = @_; |
332 | my ($widget, $event, $self) = @_; |
318 | |
333 | |
319 | $self->{pixbuf} or return; |
334 | $self->{pixbuf} or return; |
320 | |
335 | |
321 | my $area = $event->area; |
|
|
322 | |
|
|
323 | $self->redraw ($area); |
336 | $self->redraw ($event->area->values); |
324 | |
337 | |
325 | 0; |
338 | 0; |
326 | } |
339 | } |
327 | |
340 | |
328 | # something Gtk2 fixed |
341 | # something Gtk2 fixed |
… | |
… | |
462 | } |
475 | } |
463 | |
476 | |
464 | sub repaint_board { |
477 | sub repaint_board { |
465 | my ($self) = @_; |
478 | my ($self) = @_; |
466 | my $canvas = $self->{canvas}; |
479 | my $canvas = $self->{canvas}; |
467 | my $expose_area = undef; |
|
|
468 | |
480 | |
469 | return $expose_area unless $self->{board}; |
481 | return unless $self->{board}; |
470 | |
482 | |
471 | my ($w, $h) = ($canvas->allocation->values)[2,3]; |
483 | my ($w, $h) = ($canvas->allocation->values)[2,3]; |
472 | |
484 | |
473 | die "FATAL: board aspect ratio != 1" unless $w == $h; |
485 | die "FATAL: board aspect ratio != 1" unless $w == $h; |
474 | |
486 | |
… | |
… | |
494 | if ($self->{background}) { |
506 | if ($self->{background}) { |
495 | if ($oldboard = $self->{board_shown}) { |
507 | if ($oldboard = $self->{board_shown}) { |
496 | $pixbuf = $self->{pixbuf}; |
508 | $pixbuf = $self->{pixbuf}; |
497 | } else { |
509 | } else { |
498 | $pixbuf = $self->{background}->copy; |
510 | $pixbuf = $self->{background}->copy; |
499 | $expose_area = new Gtk2::Gdk::Rectangle 0, 0, $s, $s; |
511 | $self->{canvas}->queue_draw_area (0, 0, $s, $s); |
500 | } |
512 | } |
501 | } else { |
513 | } else { |
502 | $expose_area = new Gtk2::Gdk::Rectangle 0, 0, $s, $s; |
514 | $self->{canvas}->queue_draw_area (0, 0, $s, $s); |
503 | |
515 | |
504 | my ($bw, $bh) = ($::board_img->get_width, $::board_img->get_height); |
516 | my ($bw, $bh) = ($::board_img->get_width, $::board_img->get_height); |
505 | |
517 | |
506 | if ($s < $bw && $s < $bh) { |
518 | if ($s < $bw && $s < $bh) { |
507 | $pixbuf = new_pixbuf $s, $s, 0; |
519 | $pixbuf = new_pixbuf $s, $s, 0; |
… | |
… | |
593 | |
605 | |
594 | if ($oldboard) { |
606 | if ($oldboard) { |
595 | next if $old == $mark; # no change |
607 | next if $old == $mark; # no change |
596 | |
608 | |
597 | $self->{background}->copy_area (@$area, $pixbuf, $dx, $dy); |
609 | $self->{background}->copy_area (@$area, $pixbuf, $dx, $dy); |
598 | $expose_area = $expose_area |
|
|
599 | ? $expose_area->union (new Gtk2::Gdk::Rectangle @$area) |
|
|
600 | : new Gtk2::Gdk::Rectangle @$area; |
|
|
601 | } |
610 | } |
602 | |
611 | |
603 | if ($mark) { |
612 | if ($mark) { |
604 | my $pb = $self->create_stack($mark, $edge, $rand); |
613 | my $pb = $self->create_stack($mark, $edge, $rand); |
605 | |
614 | |
… | |
… | |
618 | pixbuf_text $pixbuf, $white, |
627 | pixbuf_text $pixbuf, $white, |
619 | $k[$x], $k[$y], $ofs * 0.7, |
628 | $k[$x], $k[$y], $ofs * 0.7, |
620 | $self->{board}{label}[$x-1][$y-1]; |
629 | $self->{board}{label}[$x-1][$y-1]; |
621 | } |
630 | } |
622 | } |
631 | } |
|
|
632 | |
|
|
633 | if ($oldboard) { |
|
|
634 | $self->redraw (@$area); |
|
|
635 | } |
623 | } |
636 | } |
624 | } |
637 | } |
625 | |
638 | |
626 | $self->{board_shown} = Storable::dclone $self->{board}; |
639 | $self->{board_shown} = Storable::dclone $self->{board}; |
627 | #d# save |
|
|
628 | #Storable::nstore { board => $self->{board}, size => $self->{size}, path => $self->{path}}, "testboard.storable"; |
|
|
629 | |
|
|
630 | $expose_area; |
|
|
631 | } |
640 | } |
632 | |
641 | |
633 | sub redraw { |
642 | sub redraw { |
634 | my ($self, $area) = @_; |
643 | my ($self, $x, $y, $w, $h) = @_; |
635 | |
644 | |
636 | if ($area && $self->{pixbuf}) { |
645 | if ($self->{pixbuf}) { |
637 | my ($x, $y, $w, $h) = $area->values; |
|
|
638 | |
|
|
639 | $self->{canvas}->window->draw_pixbuf ($self->{canvas}->style->white_gc, $self->{pixbuf}, |
646 | $self->{canvas}->window->draw_pixbuf ($self->{canvas}->style->white_gc, $self->{pixbuf}, |
640 | $x, $y, $x, $y, $w, $h, |
647 | $x, $y, $x, $y, $w, $h, |
641 | "normal", 0, 0); |
648 | "normal", 0, 0); |
642 | $self->{canvas}->window->draw_rectangle ($self->{canvas}->style->black_gc, 0, |
649 | $self->{canvas}->window->draw_rectangle ($self->{canvas}->style->black_gc, 0, |
643 | $x - 1, $y - 1, $w + 2, $h + 2) if $::DEBUG_EXPOSE; |
650 | $x - 1, $y - 1, $w + 2, $h + 2) if $::DEBUG_EXPOSE; |
… | |
… | |
646 | |
653 | |
647 | sub update_board { |
654 | sub update_board { |
648 | my ($self) = @_; |
655 | my ($self) = @_; |
649 | return unless $self->{path}; |
656 | return unless $self->{path}; |
650 | |
657 | |
651 | #$self->{update_board_cb} ||= add Glib::Idle sub { |
|
|
652 | my $move = int $self->{moveadj}->get_value; |
658 | my $move = int $self->{moveadj}->get_value; |
653 | |
659 | |
654 | warn "update_board called $move\n";#d# |
|
|
655 | |
|
|
656 | my $running = $move == @{$self->{path}}; |
660 | my $running = $move == @{$self->{path}}; |
657 | |
661 | |
658 | $self->{board_label}->set_text ("Move " . ($move - 1)); |
662 | $self->{board_label}->set_text ("Move " . ($move - 1)); |
659 | |
663 | |
660 | $self->{board} = new KGS::Game::Board $self->{size}; |
664 | $self->{board} = new KGS::Game::Board $self->{size}; |
661 | $self->{board}->interpret_path ([@{$self->{path}}[0 .. $move - 1]]); |
665 | $self->{board}->interpret_path ([@{$self->{path}}[0 .. $move - 1]]); |
662 | |
666 | |
663 | for my $colour (WHITE, BLACK) { |
667 | for my $colour (WHITE, BLACK) { |
664 | $self->{userpanel}[$colour]->set_state ( |
668 | $self->{userpanel}[$colour]->set_state ( |
665 | $self->{board}{captures}[$colour], |
669 | $self->{board}{captures}[$colour], |
666 | $self->{board}{timer}[$colour], |
670 | $self->{board}{timer}[$colour], |
667 | ($running && $self->{lastmove_colour} == !$colour) |
671 | ($running && $self->{lastmove_colour} == !$colour) |
668 | ? $self->{lastmove_time} : 0 |
672 | ? $self->{lastmove_time} : 0 |
669 | ); |
673 | ); |
670 | } |
|
|
671 | |
|
|
672 | $self->redraw ($self->repaint_board); |
|
|
673 | |
|
|
674 | # delete $self->{update_board_cb}; |
|
|
675 | #} |
674 | } |
|
|
675 | |
|
|
676 | $self->repaint_board; |
676 | } |
677 | } |
677 | |
678 | |
678 | sub event_update_tree { |
679 | sub event_update_tree { |
679 | my ($self) = @_; |
680 | my ($self) = @_; |
680 | |
681 | |
… | |
… | |
685 | my $pos = $self->{moveadj}->get_value; |
686 | my $pos = $self->{moveadj}->get_value; |
686 | my $move = scalar @{$self->{path}}; |
687 | my $move = scalar @{$self->{path}}; |
687 | |
688 | |
688 | $self->{moveadj}->upper ($move); |
689 | $self->{moveadj}->upper ($move); |
689 | |
690 | |
690 | warn "UPDATE_TREE $pos,$upper";#d# |
|
|
691 | $self->{moveadj}->changed; |
691 | $self->{moveadj}->changed; |
692 | if ($pos == $upper) { |
692 | if ($pos == $upper) { |
693 | $self->{moveadj}->value ($move); |
693 | $self->{moveadj}->value ($move); |
694 | $self->{moveadj}->value_changed; |
694 | $self->{moveadj}->value_changed; |
695 | } |
695 | } |
… | |
… | |
739 | } |
739 | } |
740 | |
740 | |
741 | sub event_part { |
741 | sub event_part { |
742 | my ($self) = @_; |
742 | my ($self) = @_; |
743 | $self->SUPER::event_part; |
743 | $self->SUPER::event_part; |
|
|
744 | $self->destroy; |
744 | } |
745 | } |
745 | |
746 | |
746 | sub event_move { |
747 | sub event_move { |
747 | my ($self, $pass) = @_; |
748 | my ($self, $pass) = @_; |
748 | sound::play 1, $pass ? "pass" : "move"; |
749 | sound::play 1, $pass ? "pass" : "move"; |
… | |
… | |
750 | |
751 | |
751 | sub event_update_game { |
752 | sub event_update_game { |
752 | my ($self) = @_; |
753 | my ($self) = @_; |
753 | $self->SUPER::event_update_game; |
754 | $self->SUPER::event_update_game; |
754 | |
755 | |
|
|
756 | my $title = $self->{channel} ? $self->owner->as_string . " " . $self->opponent_string : "Game Window"; |
|
|
757 | $self->{window}->set_title("KGS Game $title"); |
|
|
758 | $self->{title}->set_text ($title); |
|
|
759 | |
755 | $self->{user}[BLACK] = $self->{user1}; |
760 | $self->{user}[BLACK] = $self->{user1}; |
756 | $self->{user}[WHITE] = $self->{user2}; |
761 | $self->{user}[WHITE] = $self->{user2}; |
757 | |
762 | |
758 | # show board |
763 | # show board |
759 | |
764 | |
760 | $self->{left}->remove ($_) for $self->{left}->get_children; |
765 | $self->{left}->remove ($_) for $self->{left}->get_children; |
761 | if ($self->is_valid) { |
766 | if ($self->is_valid) { |
762 | $self->{left}->add ($self->{boardbox}); |
767 | $self->{left}->add ($self->{boardbox}); |
763 | (delete $self->{challenge})->destroy if $self->{challenge}; |
768 | (delete $self->{challenge})->destroy if $self->{challenge}; |
764 | } else { |
769 | } else { |
… | |
… | |
766 | } |
771 | } |
767 | $self->{left}->show_all; |
772 | $self->{left}->show_all; |
768 | |
773 | |
769 | # view text |
774 | # view text |
770 | |
775 | |
771 | $text = "\n<header>Game Update</header>"; |
776 | my @ga; |
772 | |
|
|
773 | $text .= "\nType: " . (util::toxml $gametype{$self->type}) |
777 | $ga[0] = "\nType: " . (util::toxml $gametype{$self->type}) |
774 | . " (" . (util::toxml $gameopt{$self->option}) . ")"; |
778 | . " (" . (util::toxml $gameopt{$self->option}) . ")"; |
775 | $text .= "\nFlags:"; |
779 | $ga[1] = "\nFlags:"; |
776 | $text .= " valid" if $self->is_valid; |
780 | $ga[1] .= " valid" if $self->is_valid; |
777 | $text .= " adjourned" if $self->is_adjourned; |
781 | $ga[1] .= " adjourned" if $self->is_adjourned; |
778 | $text .= " scored" if $self->is_scored; |
782 | $ga[1] .= " scored" if $self->is_scored; |
779 | $text .= " saved" if $self->is_saved; |
783 | $ga[1] .= " saved" if $self->is_saved; |
780 | |
784 | |
781 | $text .= "\nWhite: <user>" . (util::toxml $self->{user2}->as_string) . "</user>"; |
|
|
782 | $text .= "\nBlack: <user>" . (util::toxml $self->{user1}->as_string) . "</user>"; |
|
|
783 | $text .= "\nOwner: <user>" . (util::toxml $self->{user3}->as_string) . "</user>" if $self->{user3}->is_valid; |
785 | $ga[2] = "\nOwner: <user>" . (util::toxml $self->{user3}->as_string) . "</user>" if $self->{user3}->is_valid; |
|
|
786 | |
|
|
787 | $ga[3] = "\nPlayers: <user>" . (util::toxml $self->{user2}->as_string) . "</user>" |
|
|
788 | . " vs. <user>" . (util::toxml $self->{user1}->as_string) . "</user>" |
|
|
789 | if $self->is_valid; |
784 | |
790 | |
785 | if ($self->is_valid) { |
791 | if ($self->is_valid) { |
786 | $text .= "\nHandicap: " . $self->{handicap}; |
792 | $ga[4] = "\nHandicap: " . $self->{handicap}; |
787 | $text .= "\nKomi: " . $self->{komi}; |
793 | $ga[5] = "\nKomi: " . $self->{komi}; |
788 | $text .= "\nSize: " . $self->size_string; |
794 | $ga[6] = "\nSize: " . $self->size_string; |
789 | } |
795 | } |
790 | |
796 | |
791 | if ($self->is_scored) { |
797 | if ($self->is_scored) { |
792 | $text .= "\nResult: " . $self->score_string; |
798 | $ga[7] = "\nResult: " . $self->score_string; |
|
|
799 | } |
|
|
800 | |
|
|
801 | $text = "\n<infoblock><header>Game Update</header>"; |
|
|
802 | for (0..7) { |
|
|
803 | if ($self->{gatext}[$_] ne $ga[$_]) { |
|
|
804 | $text .= $ga[$_]; |
|
|
805 | } |
|
|
806 | } |
|
|
807 | $text .= "</infoblock>"; |
|
|
808 | |
|
|
809 | $self->{gatext} = \@ga; |
793 | } |
810 | |
794 | |
|
|
795 | $self->{text}->append_text ("<infoblock>$text</infoblock>"); |
811 | $self->{text}->append_text ($text); |
796 | } |
812 | } |
797 | |
813 | |
798 | sub event_update_rules { |
814 | sub event_update_rules { |
799 | my ($self, $rules) = @_; |
815 | my ($self, $rules) = @_; |
800 | |
816 | |
801 | $self->{userpanel}[$_]->configure ($self->{user}[$_], $rules) |
817 | $self->{userpanel}[$_]->configure ($self->{user}[$_], $rules) |
802 | for BLACK, WHITE; |
818 | for BLACK, WHITE; |
|
|
819 | |
|
|
820 | sound::play 3, "gamestart"; |
803 | |
821 | |
804 | my $text = "\n<header>Game Rules</header>"; |
822 | my $text = "\n<header>Game Rules</header>"; |
805 | |
823 | |
806 | $text .= "\nRuleset: " . $ruleset{$rules->{ruleset}}; |
824 | $text .= "\nRuleset: " . $ruleset{$rules->{ruleset}}; |
807 | |
825 | |
… | |
… | |
824 | } |
842 | } |
825 | |
843 | |
826 | sub inject_resign_game { |
844 | sub inject_resign_game { |
827 | my ($self, $msg) = @_; |
845 | my ($self, $msg) = @_; |
828 | |
846 | |
|
|
847 | sound::play 3, "resign"; |
|
|
848 | |
829 | $self->{text}->append_text ("\n<infoblock><header>Resign</header>" |
849 | $self->{text}->append_text ("\n<infoblock><header>Resign</header>" |
830 | . "\n<user>" |
850 | . "\n<user>" |
831 | . (util::toxml $self->{user}[$msg->{player}]->as_string) |
851 | . (util::toxml $self->{user}[$msg->{player}]->as_string) |
832 | . "</user> resigned.</infoblock>"); |
852 | . "</user> resigned.</infoblock>"); |
833 | } |
853 | } |