Commit 70f60446 authored by talljosh's avatar talljosh

Merge branch 'topic/default/talljosh-support-pygame2' into 'branch/default'

Topic/default/talljosh support pygame2

See merge request !5
pygame<2
pygame
twisted>=15.0
simplejson
PySide2
......
......@@ -40,7 +40,7 @@ if __name__ == '__main__':
long_description = 'Trosnoth is a fast-paced open source territory control team platform game.' ,
install_requires = [
'pygame<2',
'pygame',
'twisted>=15.0',
'simplejson',
'PySide2',
......
......@@ -188,6 +188,8 @@ class PygameRunnerAPI(Protocol):
coroutine: Callable[[], Awaitable[T]],
size: Optional[Tuple[int, int]] = None,
full_screen: Optional[bool] = None,
scaled: Optional[bool] = None,
*,
target_frame_rate: float = 60,
hide_qt: bool = True,
) -> T:
......@@ -208,6 +210,9 @@ class PygameRunnerAPI(Protocol):
will be shown in full-screen mode. Note that if full_screen
is True and size is not a supported full-screen size, a
suitable size will be automatically chosen.
:param scaled: If provided, controls whether the window will be
scaled to be visible on higher resolution monitors. May have
no effect if full_screen is True.
:param target_frame_rate: This value controls the length of
delay between each frame of the event loop. Expressed in
units of frames per second.
......@@ -222,7 +227,12 @@ class PygameRunnerAPI(Protocol):
raise NotImplementedError
def resize_window(
self, window_size: Tuple[int, int], full_screen: Optional[bool] = None) -> None:
self,
window_size: Tuple[int, int],
full_screen: Optional[bool] = None,
scaled: Optional[bool] = None,
from_event=False,
) -> None:
'''
Resizes the currently showing Pygame window.
......@@ -230,6 +240,10 @@ class PygameRunnerAPI(Protocol):
:param full_screen: If provided, controls whether the window
will be shown in full-screen mode. If not provided, the
current value will be used.
:param scaled: If provided, controls whether the window will be
scaled to be visible on higher resolution monutors.
:param from_event: Should be True iff this call is in response
to a VIDEORESIZE event.
:raises:
PygameWindowNotOpen: if the Pygame window is not open
'''
......@@ -238,9 +252,10 @@ class PygameRunnerAPI(Protocol):
def launch_application(
self,
coroutine: Callable[[], Awaitable[T]],
*,
size: Tuple[int, int],
full_screen: bool,
scaled: bool,
*,
target_frame_rate: float = 60,
) -> T:
'''
......@@ -257,6 +272,9 @@ class PygameRunnerAPI(Protocol):
full-screen mode. Note that if full_screen is true and size
is not a supported full-screen size, a suitable size will be
automatically chosen.
:param scaled: controls whether the window will be scaled to be
visible on higher resolution monitors. May have no effect
if full_screen is True.
:param target_frame_rate: This value controls the length of
delay between each frame of the event loop. Expressed in
units of frames per second.
......@@ -275,6 +293,7 @@ class PygameRunner(PygameRunnerAPI):
def __init__(self):
self.full_screen_requested = False
self.last_screen_size = (800, 600)
self.scaled_requested = False
self.on_resize = Event([])
self.on_tick = Event(['delta_t'])
self.on_pygame_event = Event(['event'])
......@@ -297,26 +316,53 @@ class PygameRunner(PygameRunnerAPI):
return surface.get_size()
def resize_window(
self, window_size: Tuple[int, int], full_screen: Optional[bool] = None) -> None:
self,
window_size: Tuple[int, int],
full_screen: Optional[bool] = None,
scaled: Optional[bool] = None,
from_event=False,
) -> None:
if not self.is_showing():
raise PygameWindowNotOpen('No pygame window currently open')
if full_screen is None:
full_screen = self.full_screen_requested
self.set_display_mode(window_size, full_screen)
if scaled is None:
scaled = self.scaled_requested
self.set_display_mode(window_size, full_screen, scaled, from_event=from_event)
self.on_resize()
def set_display_mode(self, size, full_screen):
def set_display_mode(self, size, full_screen, scaled=False, from_event=False):
if pygame.vernum[0] >= 2 and from_event:
self.last_screen_size = size
self.full_screen_requested = full_screen
self.scaled_requested = scaled
if (
size == self.last_screen_size and
full_screen == self.full_screen_requested and
scaled == self.scaled_requested and
self.is_showing()):
return
self.last_screen_size = size
self.full_screen_requested = full_screen
self.scaled_requested = scaled
kwargs = {}
if full_screen:
flags = pygame.FULLSCREEN | pygame.DOUBLEBUF | pygame.HWSURFACE
else:
flags = pygame.RESIZABLE
if pygame.vernum[0] >= 2:
# Ask for vertical sync if possible
kwargs['vsync'] = True
if scaled and not full_screen:
flags |= pygame.SCALED
pygame.display.init()
self.set_default_icon()
return pygame.display.set_mode(size, flags)
return pygame.display.set_mode(size, flags, **kwargs)
def set_default_icon(self):
icon = pygame.image.load(str(ICON_FILE))
......@@ -327,9 +373,15 @@ class PygameRunner(PygameRunnerAPI):
pygame.display.set_icon(icon)
async def show_window(
self, coroutine: Callable[[], Awaitable[T]], size: Optional[Tuple[int, int]] = None,
full_screen: Optional[bool] = None, target_frame_rate: float = 60,
hide_qt: bool = True) -> T:
self,
coroutine: Callable[[], Awaitable[T]],
size: Optional[Tuple[int, int]] = None,
full_screen: Optional[bool] = None,
scaled: Optional[bool] = None,
*,
target_frame_rate: float = 60,
hide_qt: bool = True
) -> T:
if self.is_showing():
raise PygameWindowAlreadyOpen('Pygame window is already showing')
......@@ -338,7 +390,9 @@ class PygameRunner(PygameRunnerAPI):
size = self.last_screen_size
if full_screen is None:
full_screen = self.full_screen_requested
screen = self.set_display_mode(size, full_screen)
if scaled is None:
scaled = self.scaled_requested
screen = self.set_display_mode(size, full_screen, scaled)
try:
if hide_qt:
......@@ -380,7 +434,7 @@ class PygameRunner(PygameRunnerAPI):
if event.type == pygame.QUIT:
return
if event.type == pygame.VIDEORESIZE:
self.resize_window(event.size)
self.resize_window(event.size, from_event=True)
try:
self.on_tick(now - last_time)
......@@ -400,13 +454,20 @@ class PygameRunner(PygameRunnerAPI):
await asyncio.sleep(max(0.001, target_frame_interval - processing_time))
def launch_application(
self, coroutine: Callable[[], Awaitable[T]], *,
size: Tuple[int, int], full_screen: bool, target_frame_rate: float = 60) -> T:
self,
coroutine: Callable[[],
Awaitable[T]],
size: Tuple[int, int],
full_screen: bool,
scaled: bool,
*,
target_frame_rate: float = 60,
) -> T:
pygame.init()
pygame.display.init()
try:
return run_async_main_function(functools.partial(
self.show_window, coroutine, size=size, full_screen=full_screen,
self.show_window, coroutine, size, full_screen, scaled,
target_frame_rate=target_frame_rate, hide_qt=False))
finally:
pygame.quit()
......
......@@ -31,14 +31,15 @@ NAMED = {
-1: 'L.Click', -2: 'M.Click', -3: 'R.Click',
pygame.K_BACKSPACE: 'Backspace', pygame.K_BREAK: 'Break',
pygame.K_CAPSLOCK: 'Capslock', pygame.K_CLEAR: 'Clear', pygame.K_DELETE:
pygame.K_CAPSLOCK: 'Capslock', pygame.K_CLEAR: 'Clear',
pygame.K_DELETE:
'Del', pygame.K_DOWN: 'Down', pygame.K_END: 'End', pygame.K_ESCAPE:
'Escape', pygame.K_EURO: 'Euro', pygame.K_F1: 'F1', pygame.K_F2: 'F2',
pygame.K_F3: 'F3', pygame.K_F4: 'F4', pygame.K_F5: 'F5', pygame.K_F6:
'F6', pygame.K_F7: 'F7', pygame.K_F8: 'F8', pygame.K_F9: 'F9',
pygame.K_F10: 'F10', pygame.K_F11: 'F11', pygame.K_F12: 'F12',
pygame.K_F13: 'F13', pygame.K_F14: 'F14', pygame.K_F15: 'F15',
pygame.K_FIRST: 'First', pygame.K_HELP: 'Help', pygame.K_HOME: 'Home',
pygame.K_HELP: 'Help', pygame.K_HOME: 'Home',
pygame.K_INSERT: 'Ins', pygame.K_LALT: 'L.Alt', pygame.K_LCTRL:
'L.Ctrl', pygame.K_LEFT: 'Left', pygame.K_LMETA: 'L.Meta',
pygame.K_LSHIFT: 'L.Shift', pygame.K_LSUPER: 'L.Super', pygame.K_MENU:
......@@ -51,15 +52,6 @@ NAMED = {
pygame.K_SCROLLOCK: 'Scrolllock', pygame.K_SYSREQ: 'SysRq', pygame.K_TAB:
'Tab', pygame.K_UP: 'Up', pygame.K_SPACE: 'Space',
pygame.K_a: 'a', pygame.K_b: 'b', pygame.K_c: 'c', pygame.K_d: 'd',
pygame.K_e: 'e', pygame.K_f: 'f', pygame.K_g: 'g', pygame.K_h: 'h',
pygame.K_i: 'i', pygame.K_j: 'j', pygame.K_k: 'k', pygame.K_l: 'l',
pygame.K_m: 'm', pygame.K_n: 'n', pygame.K_o: 'o', pygame.K_p: 'p',
pygame.K_q: 'q', pygame.K_r: 'r', pygame.K_s: 's', pygame.K_t: 't',
pygame.K_u: 'u', pygame.K_v: 'v', pygame.K_w: 'w', pygame.K_x: 'x',
pygame.K_y: 'y', pygame.K_z: 'z', pygame.K_0: '0', pygame.K_1: '1',
pygame.K_2: '2', pygame.K_3: '3', pygame.K_4: '4', pygame.K_5: '5',
pygame.K_6: '6', pygame.K_7: '7', pygame.K_8: '8', pygame.K_9: '9',
pygame.K_KP0: 'keypad-0', pygame.K_KP1: 'keypad-1', pygame.K_KP2:
'keypad-2', pygame.K_KP3: 'keypad-3', pygame.K_KP4: 'keypad-4',
pygame.K_KP5: 'keypad-5', pygame.K_KP6: 'keypad-6', pygame.K_KP7:
......@@ -68,18 +60,15 @@ NAMED = {
pygame.K_KP_EQUALS: 'keypad equals', pygame.K_KP_MINUS: 'keypad minus',
pygame.K_KP_MULTIPLY: 'keypad asterisk', pygame.K_KP_PERIOD:
'keypad full stop', pygame.K_KP_PLUS: 'keypad plus',
pygame.K_AMPERSAND: '&', pygame.K_ASTERISK: '*', pygame.K_AT: '@',
pygame.K_BACKQUOTE: '`', pygame.K_BACKSLASH: '\\', pygame.K_CARET: '^',
pygame.K_COLON: ':', pygame.K_COMMA: ',', pygame.K_DOLLAR: '$',
pygame.K_EQUALS: '=', pygame.K_EXCLAIM: '!', pygame.K_GREATER: '>',
pygame.K_LESS: '<', pygame.K_HASH: '#', pygame.K_LEFTBRACKET: '[',
pygame.K_LEFTPAREN: '(', pygame.K_MINUS: '-', pygame.K_PERIOD: '.',
pygame.K_PLUS: '+', pygame.K_QUOTE: "'", pygame.K_RIGHTBRACKET: ']',
pygame.K_RIGHTPAREN: ')', pygame.K_SEMICOLON: ';', pygame.K_SLASH: '/',
pygame.K_UNDERSCORE: '_'
}
try:
NAMED[pygame.K_AC_BACK] = '←'
NAMED[pygame.K_CURRENCYSUBUNIT] = 'Cents'
except AttributeError:
# These symbols don't exist in pygame 1
pass
KMOD_NAMES = ((pygame.KMOD_CTRL, 'Ctrl'), (pygame.KMOD_ALT, 'Alt'),
(pygame.KMOD_META, 'Meta'), (pygame.KMOD_SHIFT, 'Shift'))
......@@ -112,11 +101,19 @@ class KeyboardMapping(collections.UserDict):
# Update from string.
unmappedKeys = dict(self.virtualKeys)
for record in string.split('\n'):
lines = string.split('\n')
if lines[0] == '0:pygame2':
lines.pop(0)
load_map = lambda x: x
else:
load_map = convert_from_pygame1
for record in lines:
if record == '':
continue
key, vk = record.split(':')
self.data[int(key)] = vk
self.data[load_map(int(key))] = vk
if vk in unmappedKeys:
del unmappedKeys[vk]
......@@ -130,6 +127,7 @@ class KeyboardMapping(collections.UserDict):
Returns a configuration string for this keyboard mapping.
'''
records = ['%d:%s' % item for item in self.data.items()]
records.insert(0, '0:pygame2')
return '\n'.join(records)
def save(self, filename=None):
......@@ -146,3 +144,27 @@ class KeyboardMapping(collections.UserDict):
if v == action:
return k
raise KeyError(action)
PYGAME1_TO_PYGAME2 = {
318: 1073741896, 301: 1073741881, 12: 1073741980, 274: 1073741905, 279: 1073741901,
321: 1073742004, 282: 1073741882, 291: 1073741891, 292: 1073741892, 293: 1073741893,
294: 1073741928, 295: 1073741929, 296: 1073741930, 283: 1073741883,
284: 1073741884, 285: 1073741885, 286: 1073741886, 287: 1073741887,
288: 1073741888, 289: 1073741889, 290: 1073741890, 315: 1073741941,
278: 1073741898, 277: 1073741897, 256: 1073741922, 257: 1073741913,
258: 1073741914, 259: 1073741915, 260: 1073741916, 261: 1073741917,
262: 1073741918, 263: 1073741919, 264: 1073741920, 265: 1073741921,
267: 1073741908, 271: 1073741912, 272: 1073741927, 269: 1073741910,
268: 1073741909, 266: 1073741923, 270: 1073741911, 308: 1073742050,
306: 1073742048, 276: 1073741904, 310: 1073742051, 304: 1073742049,
311: 1073742051, 319: 1073741942, 313: 1073742081, 300: 1073741907,
281: 1073741902, 280: 1073741899, 19: 1073741896, 320: 1073741926,
316: 1073741894, 307: 1073742054, 305: 1073742052, 275: 1073741903,
309: 1073742055, 303: 1073742053, 312: 1073742055, 302: 1073741895,
317: 1073741978, 273: 1073741906,
}
def convert_from_pygame1(key):
return PYGAME1_TO_PYGAME2.get(key, key)
......@@ -123,7 +123,7 @@ class TrosnothAppEventListener:
def apply_display_settings(self):
display_settings = self.app.settings.display
get_pygame_runner().resize_window(*display_settings.get_size_and_full_screen())
get_pygame_runner().resize_window(*display_settings.get_video_parameters())
class TrosnothApp(MultiWindowApplication):
......
......@@ -28,13 +28,12 @@ class SoloGameClosed(Exception):
def launch_solo_game(**kwargs):
with new_console_context():
size, full_screen = ClientSettings.get().display.get_size_and_full_screen()
params = ClientSettings.get().display.get_video_parameters()
try:
get_pygame_runner().launch_application(
functools.partial(
launch_solo_game_async, return_when_level_completes=False, **kwargs),
size=size,
full_screen=full_screen,
*params,
)
except (UserClosedPygameWindow, SoloGameClosed):
pass
......
......@@ -223,12 +223,12 @@ class DisplaySettings(SettingsBase):
self._force_windowed = True
try:
if pygame_runner.is_showing() and pygame_runner.is_full_screen():
pygame_runner.resize_window(*self.get_size_and_full_screen())
pygame_runner.resize_window(*self.get_video_parameters())
yield
finally:
self._force_windowed = already_forced
if pygame_runner.is_showing():
pygame_runner.resize_window(*self.get_size_and_full_screen())
pygame_runner.resize_window(*self.get_video_parameters())
def parse_size_string(self, size_string):
if size_string and 'x' in size_string:
......@@ -256,16 +256,31 @@ class DisplaySettings(SettingsBase):
self.data['show_timings'] = str(self.show_timings)
self.data['show_range'] = str(self.show_range)
def get_size_and_full_screen(self):
def get_video_parameters(self):
if self.full_screen and not self._force_windowed:
allowed_modes = self.get_available_resolutions()
if self.full_screen_size not in allowed_modes:
return max(allowed_modes), True
return self.full_screen_size, True
return max(allowed_modes), True, False
return self.full_screen_size, True, False
if self.size == (0, 0):
self.size = (1000, 750)
return self.size, False
# For high resolution monitors, just give a scaled window
if pygame.vernum[0] > 1:
display_width = 0 # Unknown
pygame.display.init()
if pygame.display.get_surface():
modes = pygame.display.list_modes()
if modes != -1 and modes:
display_width = modes[0][0]
else:
display_width = pygame.display.Info().current_w
if display_width > 2000:
return (1920, 1200), False, True
return self.size, False, False
def get_available_resolutions(self):
pygame.display.init()
......
......@@ -146,9 +146,11 @@ class ShotSprite(object):
self.drawLines(screen, area, self.colour, points, thickness=6)
def drawLines(self, screen, area, colour, points, thickness):
rect = pygame.Rect(points[0], (0, 0))
rect = pygame.Rect(points[0], (thickness, thickness))
for point in points[1:]:
rect.union_ip(point, (0, 0))
rect.union_ip(point, (thickness, thickness))
rect.left -= thickness // 2
rect.top -= thickness // 2
if not rect.colliderect(area):
return
......
......@@ -211,11 +211,10 @@ def run_in_pygame(fn):
return await fn(*args, **kwargs)
from trosnoth.settings import ClientSettings
size, full_screen = ClientSettings.get().display.get_size_and_full_screen()
params = ClientSettings.get().display.get_video_parameters()
return await pygame_runner.show_window(
functools.partial(fn, *args, **kwargs),
size=size,
full_screen=full_screen,
*params,
)
return wrapper
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment