def test_aspect_ratio_is_set_in_constructor(self): card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.5) self.assertEqual([50, 100], card_widget.children[0].size) card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.25) self.assertEqual([25, 100], card_widget.children[0].size)
def _get_test_card(ratio=0.5): card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=ratio) card_widget.do_rotation = False card_widget.do_translation = False card_widget.do_scaling = False return card_widget
def test_visibility(self): card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.5) self.assertTrue(card_widget.visible) card_front_filename = card_widget.children[0].source card_widget.visible = False self.assertFalse(card_widget.visible) card_back_filename = card_widget.children[0].source self.assertNotEqual(card_front_filename, card_back_filename) card_widget.visible = True self.assertTrue(card_widget.visible) self.assertEqual(card_front_filename, card_widget.children[0].source)
def test_cannot_add_multiple_animations_for_the_same_card(self): animation_controller = AnimationController() card_widget = CardWidget(Card(Suit.SPADES, CardValue.QUEEN)) animation_controller.add_card_animation(card_widget, Animation(x=10)) with self.assertRaisesRegex(AssertionError, "already an animation for this CardWidget"): animation_controller.add_card_animation(card_widget, Animation(y=10))
def test_aspect_ratio_is_enforced(self): card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.5) card_widget.size = 10, 20 card_widget.size = 25, 50 card_widget.size = 26, 50 card_widget.size = 24, 50 with self.assertRaisesRegex(AssertionError, r"\(\[23, 50\], 0.5\)"): card_widget.size = 23, 50 with self.assertRaisesRegex(AssertionError, r"\(\[27, 50\], 0.5\)"): card_widget.size = 27, 50 card_widget.check_aspect_ratio(False) card_widget.size = 23, 50 card_widget.size = 27, 50
def _run_flip_animation_test(self, fix_center: bool): card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE)) self.render(card_widget) animation = card_widget.get_flip_animation(duration=1, fixed_center=fix_center) on_complete_callback = Mock() animation.bind(on_complete=on_complete_callback) self.assertTrue(card_widget.visible) on_complete_callback.assert_not_called() initial_size = card_widget.size initial_pos = card_widget.pos card_widget.check_aspect_ratio(False) animation.start(card_widget) self.advance_frames(5) on_complete_callback.assert_not_called() card_widget.center = 100, 100 self.wait_for_mock_callback(on_complete_callback) self.assertEqual(initial_size, card_widget.size) self.assertEqual(fix_center, initial_pos == card_widget.pos) self.assertFalse(card_widget.visible) animation = card_widget.get_flip_animation(duration=0.5, fixed_center=fix_center) on_complete_callback.reset_mock() animation.bind(on_complete=on_complete_callback) on_complete_callback.assert_not_called() animation.start(card_widget) self.wait_for_mock_callback(on_complete_callback) self.assertEqual(initial_size, card_widget.size) self.assertEqual(fix_center, initial_pos == card_widget.pos) self.assertTrue(card_widget.visible)
def test_can_only_add_animations_in_the_idle_state(self): animation_controller = AnimationController() animation = Animation(x=10) animation.bind( on_complete=lambda *_: animation_controller.add_card_animation( CardWidget(Card(Suit.SPADES, CardValue.QUEEN)), Animation(y=10))) card_widget = CardWidget(Card(Suit.SPADES, CardValue.QUEEN)) animation_controller.add_card_animation(card_widget, animation) self.assertFalse(animation_controller.is_running) animation_controller.start() self.assertTrue(animation_controller.is_running) with self.assertRaisesRegex(AssertionError, "add animations in the IDLE state: RUNNING"): animation_controller.add_card_animation( CardWidget(Card(Suit.SPADES, CardValue.QUEEN)), Animation(y=10)) with self.assertRaisesRegex(AssertionError, "add animations in the IDLE state: CANCELLED"): animation_controller.cancel()
def test_animate_one_card_no_callback(self): card_widget = CardWidget(Card(Suit.SPADES, CardValue.QUEEN)) card_widget.pos = 0, 0 float_layout = FloatLayout() float_layout.add_widget(card_widget) self.render(float_layout) self.assert_pixels_almost_equal([0, 0], card_widget.pos) animation_controller = AnimationController() animation = Animation(x=self.window.size[0], y=self.window.size[1]) on_complete_callback = Mock() animation.bind(on_complete=on_complete_callback) animation_controller.add_card_animation(card_widget, animation) self.assertFalse(animation_controller.is_running) animation_controller.start() self.assertTrue(animation_controller.is_running) self.wait_for_mock_callback(on_complete_callback) self.assertFalse(animation_controller.is_running) self.assert_pixels_almost_equal(self.window.size, card_widget.pos)
def test_cancel_two_cards_animation_with_callback(self): card_widget_1 = CardWidget(Card(Suit.SPADES, CardValue.QUEEN)) card_widget_1.pos = 0, 0 card_widget_2 = CardWidget(Card(Suit.SPADES, CardValue.KING)) card_widget_2.pos = self.window.size[0], 0 float_layout = FloatLayout() float_layout.add_widget(card_widget_1) float_layout.add_widget(card_widget_2) self.render(float_layout) self.assert_pixels_almost_equal([0, 0], card_widget_1.pos) self.assert_pixels_almost_equal([self.window.size[0], 0], card_widget_2.pos) animation_controller = AnimationController() animation_1 = Animation(x=self.window.size[0], y=self.window.size[1], duration=5) on_complete_callback_1 = Mock() animation_1.bind(on_complete=on_complete_callback_1) animation_controller.add_card_animation(card_widget_1, animation_1) animation_2 = Animation(x=0, y=self.window.size[1], duration=2 * animation_1.duration) on_complete_callback_2 = Mock() animation_2.bind(on_complete=on_complete_callback_2) animation_controller.add_card_animation(card_widget_2, animation_2) on_both_animations_complete_callback = Mock() self.assertFalse(animation_controller.is_running) animation_controller.start(on_both_animations_complete_callback) self.assertTrue(animation_controller.is_running) on_complete_callback_1.assert_not_called() on_complete_callback_2.assert_not_called() on_both_animations_complete_callback.assert_not_called() # Advance a couple of frames to move the cards a little bit, but not # complete any animation. self.advance_frames(5) self.assertNotEqual(0, card_widget_1.x) self.assertNotEqual(0, card_widget_1.y) self.assertNotEqual(self.window.size[0], card_widget_2.x) self.assertNotEqual(0, card_widget_2.y) # No callback should be called. on_complete_callback_1.assert_not_called() on_complete_callback_2.assert_not_called() on_both_animations_complete_callback.assert_not_called() # Cancel the animations. self.assertTrue(animation_controller.is_running) animation_controller.cancel() self.assertFalse(animation_controller.is_running) # All callbacks should be called. on_complete_callback_1.assert_called_once() on_complete_callback_2.assert_called_once() on_both_animations_complete_callback.assert_called_once() # Verify that the AnimationController can be reused. animation_controller.add_card_animation(card_widget_1, animation_1)
def test_can_only_cancel_in_running_state(self): with self.assertRaisesRegex(AssertionError, r"call cancel\(\) in the RUNNING state: IDLE"): AnimationController().cancel() animation_controller = AnimationController() animation = Animation(x=10) animation.bind(on_complete=lambda *_: animation_controller.cancel()) card_widget = CardWidget(Card(Suit.SPADES, CardValue.QUEEN)) animation_controller.add_card_animation(card_widget, animation) self.assertFalse(animation_controller.is_running) animation_controller.start() self.assertTrue(animation_controller.is_running) with self.assertRaisesRegex(AssertionError, r"cancel\(\) in the RUNNING state: CANCELLED"): animation_controller.cancel()
def test_animate_two_cards_with_callback(self): card_widget_1 = CardWidget(Card(Suit.SPADES, CardValue.QUEEN)) card_widget_1.pos = 0, 0 card_widget_2 = CardWidget(Card(Suit.SPADES, CardValue.KING)) card_widget_2.pos = self.window.size[0], 0 float_layout = FloatLayout() float_layout.add_widget(card_widget_1) float_layout.add_widget(card_widget_2) self.render(float_layout) self.assert_pixels_almost_equal([0, 0], card_widget_1.pos) self.assert_pixels_almost_equal([self.window.size[0], 0], card_widget_2.pos) animation_controller = AnimationController() animation_1 = Animation(x=self.window.size[0], y=self.window.size[1], duration=0.5) on_complete_callback_1 = Mock() animation_1.bind(on_complete=on_complete_callback_1) animation_controller.add_card_animation(card_widget_1, animation_1) animation_2 = Animation(x=0, y=self.window.size[1], duration=2 * animation_1.duration) on_complete_callback_2 = Mock() animation_2.bind(on_complete=on_complete_callback_2) animation_controller.add_card_animation(card_widget_2, animation_2) on_both_animations_complete_callback = Mock() self.assertFalse(animation_controller.is_running) animation_controller.start(on_both_animations_complete_callback) self.assertTrue(animation_controller.is_running) on_complete_callback_1.assert_not_called() on_complete_callback_2.assert_not_called() on_both_animations_complete_callback.assert_not_called() self.wait_for_mock_callback(on_complete_callback_1) self.assertTrue(animation_controller.is_running) self.assert_pixels_almost_equal(self.window.size, card_widget_1.pos) on_complete_callback_2.assert_not_called() on_both_animations_complete_callback.assert_not_called() self.wait_for_mock_callback(on_complete_callback_2) self.assertFalse(animation_controller.is_running) self.assert_pixels_almost_equal(self.window.size, card_widget_1.pos) self.assert_pixels_almost_equal([0, self.window.size[1]], card_widget_2.pos) on_both_animations_complete_callback.assert_called_once() # Verify that the AnimationController can be reused. self.assertFalse(animation_controller.is_running) animation_controller.add_card_animation(card_widget_1, animation_1)
def test_grayed_out(self): card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.5) self.assertFalse(card_widget.grayed_out) self.assertEqual(1.0, card_widget.opacity) card_widget.grayed_out = False self.assertFalse(card_widget.grayed_out) self.assertEqual(1.0, card_widget.opacity) card_widget.grayed_out = True self.assertTrue(card_widget.grayed_out) self.assertEqual(0.5, card_widget.opacity) card_widget.grayed_out = True self.assertTrue(card_widget.grayed_out) self.assertEqual(0.5, card_widget.opacity) card_widget.grayed_out = False self.assertFalse(card_widget.grayed_out) self.assertEqual(1.0, card_widget.opacity)
if self._closed: self._trump_card.rotation = 10 self._trump_card.center = self.to_parent( local_talon_pos[0] + self._talon_size[0] / 2, local_talon_pos[1] + self._talon_size[1] / 2, True) else: self._trump_card.rotation = 90 self._trump_card.pos = self.to_parent((self.width - height) / 2.0, (self.height - width) / 2.0, True) if __name__ == "__main__": RATIO = 10 talon_widget = TalonWidget(RATIO) talon_widget.pos = 50, 50 talon_widget.size = 1000, 1000 talon_widget.size_hint = None, None trump_card = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=RATIO) talon_widget.set_trump_card(trump_card) _card = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=RATIO) _card.visible = False talon_widget.push_card(_card) runTouchApp(talon_widget) # noinspection PyStringFormat print("(%.1f, (%d, %d), [%d, %d], (%.1f, %.1f), (%.1f, %.1f))" % ( RATIO, *talon_widget.size, *_card.size, *_card.pos, *trump_card.pos))
center_y=_float_layout.height / 4) + \ Animation(rotation=270) + \ Animation(center_x=_float_layout.width / 4 * 3, center_y=_float_layout.height / 4) + \ Animation(rotation=270 + 90) + \ Animation(center_x=_float_layout.width / 4 * 3, center_y=_float_layout.height / 4 * 3) + \ Animation(rotation=90) + \ Animation(center_x=_float_layout.width / 4, center_y=_float_layout.height / 4 * 3) + \ Animation(rotation=45) + \ Animation(center_x=_float_layout.width / 2, center_y=_float_layout.height / 2) + \ Animation(rotation=0) _card_widget = CardWidget(Card(Suit.SPADES, CardValue.QUEEN)) _card_widget.size_hint = None, None _card_widget.bind(on_double_tap=lambda *_: _animation_controller.start()) _float_layout.add_widget(_card_widget) def _reset_pos(): _card_widget.center = _float_layout.center _card_widget.visible = True _card_widget.rotation = 0 Clock.schedule_once( lambda _: _animation_controller.add_card_animation(_card_widget, _animation)) def _cancel():
def test_dragging_a_card_with_the_mouse(self): # pylint: disable=too-many-statements window = self.window on_card_moved_handler = Mock() # Place the card in the center of the window. card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.5, do_translation=True) min_dimension = min(window.width, window.height) card_widget.size = min_dimension / 4, min_dimension / 2 window_center = window.width / 2, window.height / 2 card_widget.center = window_center card_widget.bind(on_card_moved=on_card_moved_handler) # Place a second card under the first card. Only the first one will be moved # and it will be the only one triggering the on_card_moved event. another_card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.5) another_card_widget.size = card_widget.size another_card_widget.center = card_widget.center another_card_widget.bind(on_card_moved=on_card_moved_handler) float_layout = FloatLayout() float_layout.add_widget(another_card_widget) float_layout.add_widget(card_widget) self.render(float_layout) # Touch down on the card, nothing happens to the card. touch = UnitTestTouch(*card_widget.center) touch.touch_down() self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Drag in a random direction, check that the card moved accordingly. new_position = window.width / 3, window.height / 3 touch.touch_move(*new_position) self.assertAlmostEqual(new_position[0], card_widget.center_x) self.assertAlmostEqual(new_position[1], card_widget.center_y) on_card_moved_handler.assert_not_called() # Drag in another random direction, check that the card moved accordingly. new_position = window.width * 0.7, window.height * 0.45 touch.touch_move(*new_position) self.assertAlmostEqual(new_position[0], card_widget.center_x) self.assertAlmostEqual(new_position[1], card_widget.center_y) on_card_moved_handler.assert_not_called() # Touch up, nothing happens to the card. The on_card_moved event is # triggered. touch.touch_up() self.assertAlmostEqual(new_position[0], card_widget.center_x) self.assertAlmostEqual(new_position[1], card_widget.center_y) on_card_moved_handler.assert_called_once_with(card_widget, card_widget.center) on_card_moved_handler.reset_mock() # Move the card back to the window center. card_widget.center = window_center # CardWidget's position has changed, but was not dragged by the user. The # on_card_moved event should not trigger. on_card_moved_handler.assert_not_called() # A click on the card, without dragging should not trigger the on_card_moved # event. touch = UnitTestTouch(*card_widget.center) touch.touch_down() touch.touch_up() on_card_moved_handler.assert_not_called() # Touch down in the bottom left corner of the window, outside of the card. # Nothing happens to the card. touch = UnitTestTouch(window.width * 0.1, window.height * 0.1) self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Drag to the window center, on the card. Nothing happens to the card. touch.touch_move(*window_center) self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Drag further to the top right corner of the window. Nothing happens to the # card. touch.touch_move(window.width * 0.95, window.height * 0.95) self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Touch up. Nothing happens to the card. touch.touch_up() self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called()
def test_shadow(self): card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.5) self.assertTrue(card_widget.shadow) card_widget.shadow = 0 self.assertFalse(card_widget.shadow)
def test_create_widgets_for_all_cards(self): card_dict = CardWidget.create_widgets_for_all_cards() self.assertEqual(20, len(card_dict.keys())) for card, card_widget in card_dict.items(): self.assertEqual(card, card_widget.card)
def test_dragging_a_card_with_the_mouse_translations_disabled(self): window = self.window on_card_moved_handler = Mock() # Place the card in the center of the window. card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.5, do_translation=False) min_dimension = min(window.width, window.height) card_widget.size = min_dimension / 4, min_dimension / 2 window_center = window.width / 2, window.height / 2 card_widget.center = window_center card_widget.bind(on_card_moved=on_card_moved_handler) self.render(card_widget) # Touch down on the card, nothing happens to the card. touch = UnitTestTouch(*card_widget.center) touch.touch_down() self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Drag in a random direction, the card should not move. new_position = window.width / 3, window.height / 3 touch.touch_move(*new_position) self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Touch up, nothing happens to the card. touch.touch_up() self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Move the card to a new position. Since it was not dragged by the user, the # on_card_moved event should not trigger. card_widget.center = window.width / 3, window.height / 3 on_card_moved_handler.assert_not_called() # A click on the card, without dragging should not trigger the on_card_moved # event. card_widget.center = window_center touch = UnitTestTouch(*card_widget.center) touch.touch_down() touch.touch_up() on_card_moved_handler.assert_not_called() # Touch down in the bottom left corner of the window, outside of the card. # Nothing happens to the card. touch = UnitTestTouch(window.width * 0.1, window.height * 0.1) self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Drag to the window center, on the card. Nothing happens to the card. touch.touch_move(*window_center) self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Drag further to the top right corner of the window. Nothing happens to the # card. touch.touch_move(window.width * 0.95, window.height * 0.95) self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called() # Touch up. Nothing happens to the card. touch.touch_up() self.assertEqual(window_center, card_widget.center) on_card_moved_handler.assert_not_called()
def _init_cards(self): self._cards = CardWidget.create_widgets_for_all_cards( path=self._game_options.cards_path) for card_widget in self._cards.values(): card_widget.bind(on_card_moved=self._on_card_moved)
def _bind_card_action(self, card: CardWidget, action: PlayerAction) -> None: self._actions[card] = action card.bind(on_double_tap=self._card_action_callback)
def _run_test_on_double_tap_with_init_args(self, *args, **kwargs): """ The args passed to this function are forwarded to the constructor of the CardWidget used in the test. """ window = self.window # Place the card in the center of the window. card_widget = CardWidget(*args, **kwargs) min_dimension = min(window.width, window.height) card_widget.size = min_dimension / 4, min_dimension / 2 window_center = window.width / 2, window.height / 2 card_widget.center = window_center float_layout = FloatLayout() float_layout.add_widget(card_widget) self.render(float_layout) on_double_tap_handler = Mock() card_widget.bind(on_double_tap=on_double_tap_handler) # Normal click on the card does not trigger on_double_tap. touch = UnitTestTouch(*card_widget.center) touch.touch_down() touch.touch_up() on_double_tap_handler.assert_not_called() # Double click on the card triggers on_double_tap. touch.is_double_tap = True touch.touch_down() touch.touch_up() on_double_tap_handler.assert_called_once_with(card_widget) on_double_tap_handler.reset_mock() # Double click outside of the card does not trigger on_double_tap. touch = UnitTestTouch(0, 0) touch.is_double_tap = True touch.touch_down() touch.touch_up() on_double_tap_handler.assert_not_called() # Two cards on top of each other. Only the top one triggers on_double_tap. another_card_widget = CardWidget(Card(Suit.SPADES, CardValue.ACE), aspect_ratio=0.5) another_card_widget.size = card_widget.size another_card_widget.center = card_widget.center another_card_widget.bind(on_double_tap=on_double_tap_handler) float_layout.add_widget(another_card_widget) touch = UnitTestTouch(*card_widget.center) touch.is_double_tap = True touch.touch_down() touch.touch_up() on_double_tap_handler.assert_called_once_with(another_card_widget)