1from gi.repository import Gtk
2
3from pychess.Utils.const import UNDOABLE_STATES, PRACTICE_GOAL_REACHED
4from pychess.Utils.Cord import Cord
5from pychess.Utils.LearnModel import learn2str, LESSON, PUZZLE
6from pychess.perspectives.learn.PuzzlesPanel import start_puzzle_from
7from pychess.perspectives.learn.EndgamesPanel import start_endgame_from
8from pychess.perspectives.learn.LessonsPanel import start_lesson_from
9from pychess.widgets import preferencesDialog
10
11HINT, MOVE, RETRY, CONTINUE, BACK_TO_MAINLINE, NEXT = range(6)
12
13
14css = """
15@define-color error_fg_color rgb (235, 235, 235);
16@define-color error_bg_color rgb (223, 56, 44);
17
18
19.error {
20    background-image: -gtk-gradient (linear, left top, left bottom,
21                                     from (shade (@error_bg_color, 1.04)),
22                                     to (shade (@error_bg_color, 0.96)));
23    border-style: solid;
24    border-width: 1px;
25
26    color: @error_fg_color;
27
28    border-color: shade (@error_bg_color, 0.8);
29    border-bottom-color: shade (@error_bg_color, 0.75);
30
31    box-shadow: inset 1px 0 shade (@error_bg_color, 1.08),
32                inset -1px 0 shade (@error_bg_color, 1.08),
33                inset 0 1px shade (@error_bg_color, 1.1),
34                inset 0 -1px shade (@error_bg_color, 1.04);
35}
36"""
37
38
39def add_provider(widget):
40    screen = widget.get_screen()
41    style = widget.get_style_context()
42    provider = Gtk.CssProvider()
43    provider.load_from_data(css.encode('utf-8'))
44    style.add_provider_for_screen(screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
45
46
47class LearnInfoBar(Gtk.InfoBar):
48    def __init__(self, gamemodel, boardcontrol, annotation_panel):
49        Gtk.InfoBar.__init__(self)
50        self.connect("realize", add_provider)
51
52        self.content_area = self.get_content_area()
53        self.action_area = self.get_action_area()
54
55        self.gamemodel = gamemodel
56        self.boardcontrol = boardcontrol
57        self.boardview = boardcontrol.view
58        self.annotation_panel = annotation_panel
59
60        self.gamemodel.connect("game_changed", self.on_game_changed)
61        self.gamemodel.connect("goal_checked", self.on_goal_checked)
62        self.connect("response", self.on_response)
63
64        self.your_turn()
65
66    def clear(self):
67        for item in self.content_area:
68            self.content_area.remove(item)
69
70        for item in self.action_area:
71            self.action_area.remove(item)
72
73    def your_turn(self, shown_board=None):
74        self.clear()
75        self.set_message_type(Gtk.MessageType.QUESTION)
76        self.content_area.add(Gtk.Label(_("Your turn.")))
77        self.add_button(_("Hint"), HINT)
78        self.add_button(_("Best move"), MOVE)
79        self.show_all()
80
81    def get_next_puzzle(self):
82        self.clear()
83        self.set_message_type(Gtk.MessageType.INFO)
84        if self.gamemodel.learn_type in (LESSON, PUZZLE) and self.gamemodel.current_index + 1 == self.gamemodel.game_count:
85            self.content_area.add(Gtk.Label(_("Well done! %s completed." % learn2str[self.gamemodel.learn_type])))
86        else:
87            if "FEN" in self.gamemodel.tags:
88                self.content_area.add(Gtk.Label(_("Well done!")))
89            self.add_button(_("Next"), NEXT)
90        self.show_all()
91        preferencesDialog.SoundTab.playAction("puzzleSuccess")
92
93        self.gamemodel.solved = True
94
95    def opp_turn(self):
96        self.clear()
97        self.set_message_type(Gtk.MessageType.INFO)
98        self.add_button(_("Continue"), CONTINUE)
99
100        # disable playing
101        self.boardcontrol.game_preview = True
102        self.show_all()
103
104    def retry(self):
105        self.clear()
106        self.set_message_type(Gtk.MessageType.ERROR)
107        self.content_area.add(Gtk.Label(_("Not the best move!")))
108        self.add_button(_("Retry"), RETRY)
109
110        # disable playing
111        self.boardcontrol.game_preview = True
112
113        # disable retry button until engine thinking on next move
114        if self.gamemodel.practice_game and self.gamemodel.status not in UNDOABLE_STATES:
115            self.set_response_sensitive(RETRY, False)
116        self.show_all()
117
118    def back_to_mainline(self):
119        self.clear()
120        self.set_message_type(Gtk.MessageType.INFO)
121        self.content_area.add(Gtk.Label(_("Cool! Now let see how it goes in the main line.")))
122        self.add_button(_("Back to main line"), BACK_TO_MAINLINE)
123
124        # disable playing
125        self.boardcontrol.game_preview = True
126        self.show_all()
127
128    def on_response(self, widget, response):
129        if response in (HINT, MOVE):
130            if self.gamemodel.lesson_game:
131                next_move = self.gamemodel.getMoveAtPly(self.boardview.shown, self.boardview.shown_variation_idx)
132                hints = {self.boardview.shown: ((next_move.as_uci(),),)}
133            else:
134                hints = self.gamemodel.hints
135
136            if self.boardview.shown in hints:
137                if self.boardview.arrows:
138                    self.boardview.arrows.clear()
139                if self.boardview.circles:
140                    self.boardview.circles.clear()
141
142                hint = hints[self.boardview.shown][0][0]
143                cord0 = Cord(hint[0], int(hint[1]), "G")
144                cord1 = Cord(hint[2], int(hint[3]), "G")
145                if response == HINT:
146                    self.boardview.circles.add(cord0)
147                    self.boardview.redrawCanvas()
148                else:
149                    self.boardview.arrows.add((cord0, cord1))
150                    self.boardview.redrawCanvas()
151            else:
152                # TODO:
153                print("No hint available yet!", self.gamemodel.ply, self.boardview.shown)
154
155        elif response == RETRY:
156            self.your_turn()
157
158            if self.gamemodel.practice_game:
159                me_played_last_move = self.gamemodel.boards[-1].color != self.gamemodel.boards[0].color
160                moves = 1 if self.gamemodel.status in UNDOABLE_STATES and me_played_last_move else 2
161                self.gamemodel.undoMoves(moves)
162
163            elif self.gamemodel.lesson_game:
164                prev_board = self.gamemodel.getBoardAtPly(
165                    self.boardview.shown - 1,
166                    variation=self.boardview.shown_variation_idx)
167
168                self.annotation_panel.choices_enabled = False
169
170                self.boardview.setShownBoard(prev_board)
171                # We have to fix show_variation_index here, unless
172                # after removing the variation it will be invalid!
173                for vari in self.gamemodel.variations:
174                    if prev_board in vari:
175                        break
176                self.boardview.shown_variation_idx = self.gamemodel.variations.index(vari)
177
178                self.annotation_panel.choices_enabled = True
179
180            self.boardcontrol.game_preview = False
181
182        elif response == CONTINUE:
183            self.your_turn()
184            self.boardview.showNext()
185            self.boardcontrol.game_preview = False
186
187        elif response == BACK_TO_MAINLINE:
188            self.opp_turn()
189            self.boardview.backToMainLine()
190            self.boardcontrol.game_preview = False
191
192        elif response == NEXT:
193            if self.gamemodel.puzzle_game:
194                if self.gamemodel.from_lesson:
195                    start_lesson_from(self.gamemodel.source, self.gamemodel.current_index + 1)
196                else:
197                    start_puzzle_from(self.gamemodel.source, self.gamemodel.current_index + 1)
198            elif self.gamemodel.end_game:
199                start_endgame_from(self.gamemodel.source)
200            elif self.gamemodel.lesson_game:
201                start_lesson_from(self.gamemodel.source, self.gamemodel.current_index + 1)
202            else:
203                print(self.gamemodel.__dir__())
204
205    def opp_choice_selected(self, board):
206        self.your_turn()
207        self.boardcontrol.game_preview = False
208
209    def on_game_changed(self, gamemodel, ply):
210        if gamemodel.practice_game:
211            if len(gamemodel.moves) % 2 == 0:
212                # engine moved, we can enable retry
213                self.set_response_sensitive(RETRY, True)
214                return
215
216    def on_goal_checked(self, gamemodel):
217        if gamemodel.status in UNDOABLE_STATES and self.gamemodel.end_game:
218            self.get_next_puzzle()
219
220        elif gamemodel.reason == PRACTICE_GOAL_REACHED:
221            self.get_next_puzzle()
222
223        elif gamemodel.failed_playing_best:
224            self.retry()
225
226        else:
227            self.your_turn()
228