Ajout du GUI
This commit is contained in:
449
kivy/core/window/window_pygame.py
Normal file
449
kivy/core/window/window_pygame.py
Normal file
@@ -0,0 +1,449 @@
|
||||
'''
|
||||
Window Pygame: windowing provider based on Pygame
|
||||
|
||||
.. warning::
|
||||
|
||||
Pygame has been deprecated and will be removed in the release after Kivy
|
||||
1.11.0.
|
||||
'''
|
||||
|
||||
__all__ = ('WindowPygame', )
|
||||
|
||||
# fail early if possible
|
||||
import pygame
|
||||
|
||||
from kivy.compat import PY2
|
||||
from kivy.core.window import WindowBase
|
||||
from kivy.core import CoreCriticalException
|
||||
from os import environ
|
||||
from os.path import exists, join
|
||||
from kivy.config import Config
|
||||
from kivy import kivy_data_dir
|
||||
from kivy.base import ExceptionManager
|
||||
from kivy.logger import Logger
|
||||
from kivy.base import stopTouchApp, EventLoop
|
||||
from kivy.utils import platform, deprecated
|
||||
from kivy.resources import resource_find
|
||||
|
||||
try:
|
||||
android = None
|
||||
if platform == 'android':
|
||||
import android
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# late binding
|
||||
glReadPixels = GL_RGBA = GL_UNSIGNED_BYTE = None
|
||||
|
||||
|
||||
class WindowPygame(WindowBase):
|
||||
|
||||
@deprecated(
|
||||
msg='Pygame has been deprecated and will be removed after 1.11.0')
|
||||
def __init__(self, *largs, **kwargs):
|
||||
super(WindowPygame, self).__init__(*largs, **kwargs)
|
||||
|
||||
def create_window(self, *largs):
|
||||
# ensure the mouse is still not up after window creation, otherwise, we
|
||||
# have some weird bugs
|
||||
self.dispatch('on_mouse_up', 0, 0, 'all', [])
|
||||
|
||||
# force display to show (available only for fullscreen)
|
||||
displayidx = Config.getint('graphics', 'display')
|
||||
if 'SDL_VIDEO_FULLSCREEN_HEAD' not in environ and displayidx != -1:
|
||||
environ['SDL_VIDEO_FULLSCREEN_HEAD'] = '%d' % displayidx
|
||||
|
||||
# init some opengl, same as before.
|
||||
self.flags = pygame.HWSURFACE | pygame.OPENGL | pygame.DOUBLEBUF
|
||||
|
||||
# right now, activate resizable window only on linux.
|
||||
# on window / macosx, the opengl context is lost, and we need to
|
||||
# reconstruct everything. Check #168 for a state of the work.
|
||||
if platform in ('linux', 'macosx', 'win') and \
|
||||
Config.getboolean('graphics', 'resizable'):
|
||||
self.flags |= pygame.RESIZABLE
|
||||
|
||||
try:
|
||||
pygame.display.init()
|
||||
except pygame.error as e:
|
||||
raise CoreCriticalException(e.message)
|
||||
|
||||
multisamples = Config.getint('graphics', 'multisamples')
|
||||
|
||||
if multisamples > 0:
|
||||
pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLEBUFFERS, 1)
|
||||
pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLESAMPLES,
|
||||
multisamples)
|
||||
pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE, 16)
|
||||
pygame.display.gl_set_attribute(pygame.GL_STENCIL_SIZE, 1)
|
||||
pygame.display.set_caption(self.title)
|
||||
|
||||
if self.position == 'auto':
|
||||
self._pos = None
|
||||
elif self.position == 'custom':
|
||||
self._pos = self.left, self.top
|
||||
else:
|
||||
raise ValueError('position token in configuration accept only '
|
||||
'"auto" or "custom"')
|
||||
|
||||
if self._fake_fullscreen:
|
||||
if not self.borderless:
|
||||
self.fullscreen = self._fake_fullscreen = False
|
||||
elif not self.fullscreen or self.fullscreen == 'auto':
|
||||
self.borderless = self._fake_fullscreen = False
|
||||
|
||||
if self.fullscreen == 'fake':
|
||||
self.borderless = self._fake_fullscreen = True
|
||||
Logger.warning("The 'fake' fullscreen option has been "
|
||||
"deprecated, use Window.borderless or the "
|
||||
"borderless Config option instead.")
|
||||
|
||||
if self.fullscreen == 'fake' or self.borderless:
|
||||
Logger.debug('WinPygame: Set window to borderless mode.')
|
||||
|
||||
self.flags |= pygame.NOFRAME
|
||||
# If no position set in borderless mode, we always need
|
||||
# to set the position. So use 0, 0.
|
||||
if self._pos is None:
|
||||
self._pos = (0, 0)
|
||||
environ['SDL_VIDEO_WINDOW_POS'] = '%d,%d' % self._pos
|
||||
|
||||
elif self.fullscreen in ('auto', True):
|
||||
Logger.debug('WinPygame: Set window to fullscreen mode')
|
||||
self.flags |= pygame.FULLSCREEN
|
||||
|
||||
elif self._pos is not None:
|
||||
environ['SDL_VIDEO_WINDOW_POS'] = '%d,%d' % self._pos
|
||||
|
||||
# never stay with a None pos, application using w.center will be fired.
|
||||
self._pos = (0, 0)
|
||||
|
||||
# prepare keyboard
|
||||
repeat_delay = int(Config.get('kivy', 'keyboard_repeat_delay'))
|
||||
repeat_rate = float(Config.get('kivy', 'keyboard_repeat_rate'))
|
||||
pygame.key.set_repeat(repeat_delay, int(1000. / repeat_rate))
|
||||
|
||||
# set window icon before calling set_mode
|
||||
try:
|
||||
filename_icon = self.icon or Config.get('kivy', 'window_icon')
|
||||
if filename_icon == '':
|
||||
logo_size = 32
|
||||
if platform == 'macosx':
|
||||
logo_size = 512
|
||||
elif platform == 'win':
|
||||
logo_size = 64
|
||||
filename_icon = 'kivy-icon-{}.png'.format(logo_size)
|
||||
filename_icon = resource_find(
|
||||
join(kivy_data_dir, 'logo', filename_icon))
|
||||
self.set_icon(filename_icon)
|
||||
except:
|
||||
Logger.exception('Window: cannot set icon')
|
||||
|
||||
# try to use mode with multisamples
|
||||
try:
|
||||
self._pygame_set_mode()
|
||||
except pygame.error as e:
|
||||
if multisamples:
|
||||
Logger.warning('WinPygame: Video: failed (multisamples=%d)' %
|
||||
multisamples)
|
||||
Logger.warning('WinPygame: trying without antialiasing')
|
||||
pygame.display.gl_set_attribute(
|
||||
pygame.GL_MULTISAMPLEBUFFERS, 0)
|
||||
pygame.display.gl_set_attribute(
|
||||
pygame.GL_MULTISAMPLESAMPLES, 0)
|
||||
multisamples = 0
|
||||
try:
|
||||
self._pygame_set_mode()
|
||||
except pygame.error as e:
|
||||
raise CoreCriticalException(e.message)
|
||||
else:
|
||||
raise CoreCriticalException(e.message)
|
||||
|
||||
if pygame.RESIZABLE & self.flags:
|
||||
self._pygame_set_mode()
|
||||
|
||||
info = pygame.display.Info()
|
||||
self._size = (info.current_w, info.current_h)
|
||||
# self.dispatch('on_resize', *self._size)
|
||||
|
||||
# in order to debug futur issue with pygame/display, let's show
|
||||
# more debug output.
|
||||
Logger.debug('Window: Display driver ' + pygame.display.get_driver())
|
||||
Logger.debug('Window: Actual window size: %dx%d',
|
||||
info.current_w, info.current_h)
|
||||
if platform != 'android':
|
||||
# unsupported platform, such as android that doesn't support
|
||||
# gl_get_attribute.
|
||||
Logger.debug(
|
||||
'Window: Actual color bits r%d g%d b%d a%d',
|
||||
pygame.display.gl_get_attribute(pygame.GL_RED_SIZE),
|
||||
pygame.display.gl_get_attribute(pygame.GL_GREEN_SIZE),
|
||||
pygame.display.gl_get_attribute(pygame.GL_BLUE_SIZE),
|
||||
pygame.display.gl_get_attribute(pygame.GL_ALPHA_SIZE))
|
||||
Logger.debug(
|
||||
'Window: Actual depth bits: %d',
|
||||
pygame.display.gl_get_attribute(pygame.GL_DEPTH_SIZE))
|
||||
Logger.debug(
|
||||
'Window: Actual stencil bits: %d',
|
||||
pygame.display.gl_get_attribute(pygame.GL_STENCIL_SIZE))
|
||||
Logger.debug(
|
||||
'Window: Actual multisampling samples: %d',
|
||||
pygame.display.gl_get_attribute(pygame.GL_MULTISAMPLESAMPLES))
|
||||
super(WindowPygame, self).create_window()
|
||||
|
||||
# set mouse visibility
|
||||
self._set_cursor_state(self.show_cursor)
|
||||
|
||||
# if we are on android platform, automatically create hooks
|
||||
if android:
|
||||
from kivy.support import install_android
|
||||
install_android()
|
||||
|
||||
def close(self):
|
||||
pygame.display.quit()
|
||||
super(WindowPygame, self).close()
|
||||
|
||||
def on_title(self, instance, value):
|
||||
if self.initialized:
|
||||
pygame.display.set_caption(self.title)
|
||||
|
||||
def set_icon(self, filename):
|
||||
if not exists(filename):
|
||||
return False
|
||||
try:
|
||||
if platform == 'win':
|
||||
try:
|
||||
if self._set_icon_win(filename):
|
||||
return True
|
||||
except:
|
||||
# fallback on standard loading then.
|
||||
pass
|
||||
|
||||
# for all others platform, or if the ico is not available, use the
|
||||
# default way to set it.
|
||||
self._set_icon_standard(filename)
|
||||
super(WindowPygame, self).set_icon(filename)
|
||||
except:
|
||||
Logger.exception('WinPygame: unable to set icon')
|
||||
|
||||
def _set_icon_standard(self, filename):
|
||||
if PY2:
|
||||
try:
|
||||
im = pygame.image.load(filename)
|
||||
except UnicodeEncodeError:
|
||||
im = pygame.image.load(filename.encode('utf8'))
|
||||
else:
|
||||
im = pygame.image.load(filename)
|
||||
if im is None:
|
||||
raise Exception('Unable to load window icon (not found)')
|
||||
pygame.display.set_icon(im)
|
||||
|
||||
def _set_icon_win(self, filename):
|
||||
# ensure the window ico is ended by ico
|
||||
if not filename.endswith('.ico'):
|
||||
filename = '{}.ico'.format(filename.rsplit('.', 1)[0])
|
||||
if not exists(filename):
|
||||
return False
|
||||
|
||||
import win32api
|
||||
import win32gui
|
||||
import win32con
|
||||
hwnd = pygame.display.get_wm_info()['window']
|
||||
icon_big = win32gui.LoadImage(
|
||||
None, filename, win32con.IMAGE_ICON,
|
||||
48, 48, win32con.LR_LOADFROMFILE)
|
||||
icon_small = win32gui.LoadImage(
|
||||
None, filename, win32con.IMAGE_ICON,
|
||||
16, 16, win32con.LR_LOADFROMFILE)
|
||||
win32api.SendMessage(
|
||||
hwnd, win32con.WM_SETICON, win32con.ICON_SMALL, icon_small)
|
||||
win32api.SendMessage(
|
||||
hwnd, win32con.WM_SETICON, win32con.ICON_BIG, icon_big)
|
||||
return True
|
||||
|
||||
def _set_cursor_state(self, value):
|
||||
pygame.mouse.set_visible(value)
|
||||
|
||||
def screenshot(self, *largs, **kwargs):
|
||||
global glReadPixels, GL_RGBA, GL_UNSIGNED_BYTE
|
||||
filename = super(WindowPygame, self).screenshot(*largs, **kwargs)
|
||||
if filename is None:
|
||||
return None
|
||||
if glReadPixels is None:
|
||||
from kivy.graphics.opengl import (glReadPixels, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE)
|
||||
width, height = self.system_size
|
||||
data = glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE)
|
||||
data = bytes(bytearray(data))
|
||||
surface = pygame.image.fromstring(data, (width, height), 'RGBA', True)
|
||||
pygame.image.save(surface, filename)
|
||||
Logger.debug('Window: Screenshot saved at <%s>' % filename)
|
||||
return filename
|
||||
|
||||
def flip(self):
|
||||
pygame.display.flip()
|
||||
super(WindowPygame, self).flip()
|
||||
|
||||
@deprecated
|
||||
def toggle_fullscreen(self):
|
||||
if self.flags & pygame.FULLSCREEN:
|
||||
self.flags &= ~pygame.FULLSCREEN
|
||||
else:
|
||||
self.flags |= pygame.FULLSCREEN
|
||||
self._pygame_set_mode()
|
||||
|
||||
def mainloop(self):
|
||||
for event in pygame.event.get():
|
||||
|
||||
# kill application (SIG_TERM)
|
||||
if event.type == pygame.QUIT:
|
||||
if self.dispatch('on_request_close'):
|
||||
continue
|
||||
EventLoop.quit = True
|
||||
self.close()
|
||||
|
||||
# mouse move
|
||||
elif event.type == pygame.MOUSEMOTION:
|
||||
x, y = event.pos
|
||||
self.mouse_pos = x, self.system_size[1] - y
|
||||
# don't dispatch motion if no button are pressed
|
||||
if event.buttons == (0, 0, 0):
|
||||
continue
|
||||
self._mouse_x = x
|
||||
self._mouse_y = y
|
||||
self._mouse_meta = self.modifiers
|
||||
self.dispatch('on_mouse_move', x, y, self.modifiers)
|
||||
|
||||
# mouse action
|
||||
elif event.type in (pygame.MOUSEBUTTONDOWN,
|
||||
pygame.MOUSEBUTTONUP):
|
||||
self._pygame_update_modifiers()
|
||||
x, y = event.pos
|
||||
btn = 'left'
|
||||
if event.button == 3:
|
||||
btn = 'right'
|
||||
elif event.button == 2:
|
||||
btn = 'middle'
|
||||
elif event.button == 4:
|
||||
btn = 'scrolldown'
|
||||
elif event.button == 5:
|
||||
btn = 'scrollup'
|
||||
elif event.button == 6:
|
||||
btn = 'scrollright'
|
||||
elif event.button == 7:
|
||||
btn = 'scrollleft'
|
||||
eventname = 'on_mouse_down'
|
||||
if event.type == pygame.MOUSEBUTTONUP:
|
||||
eventname = 'on_mouse_up'
|
||||
self._mouse_x = x
|
||||
self._mouse_y = y
|
||||
self._mouse_meta = self.modifiers
|
||||
self._mouse_btn = btn
|
||||
self._mouse_down = eventname == 'on_mouse_down'
|
||||
self.dispatch(eventname, x, y, btn, self.modifiers)
|
||||
|
||||
# joystick action
|
||||
elif event.type == pygame.JOYAXISMOTION:
|
||||
self.dispatch('on_joy_axis', event.joy, event.axis,
|
||||
event.value)
|
||||
|
||||
elif event.type == pygame.JOYHATMOTION:
|
||||
self.dispatch('on_joy_hat', event.joy, event.hat, event.value)
|
||||
|
||||
elif event.type == pygame.JOYBALLMOTION:
|
||||
self.dispatch('on_joy_ball', event.joy, event.ballid,
|
||||
event.rel[0], event.rel[1])
|
||||
|
||||
elif event.type == pygame.JOYBUTTONDOWN:
|
||||
self.dispatch('on_joy_button_down', event.joy, event.button)
|
||||
|
||||
elif event.type == pygame.JOYBUTTONUP:
|
||||
self.dispatch('on_joy_button_up', event.joy, event.button)
|
||||
|
||||
# keyboard action
|
||||
elif event.type in (pygame.KEYDOWN, pygame.KEYUP):
|
||||
self._pygame_update_modifiers(event.mod)
|
||||
# atm, don't handle keyup
|
||||
if event.type == pygame.KEYUP:
|
||||
self.dispatch('on_key_up', event.key,
|
||||
event.scancode)
|
||||
continue
|
||||
|
||||
# don't dispatch more key if down event is accepted
|
||||
if self.dispatch('on_key_down', event.key,
|
||||
event.scancode, event.unicode,
|
||||
self.modifiers):
|
||||
continue
|
||||
self.dispatch('on_keyboard', event.key,
|
||||
event.scancode, event.unicode,
|
||||
self.modifiers)
|
||||
|
||||
# video resize
|
||||
elif event.type == pygame.VIDEORESIZE:
|
||||
self._size = event.size
|
||||
self.update_viewport()
|
||||
|
||||
elif event.type == pygame.VIDEOEXPOSE:
|
||||
self.canvas.ask_update()
|
||||
|
||||
# ignored event
|
||||
elif event.type == pygame.ACTIVEEVENT:
|
||||
pass
|
||||
|
||||
# drop file (pygame patch needed)
|
||||
elif event.type == pygame.USEREVENT and \
|
||||
hasattr(pygame, 'USEREVENT_DROPFILE') and \
|
||||
event.code == pygame.USEREVENT_DROPFILE:
|
||||
drop_x, drop_y = pygame.mouse.get_pos()
|
||||
self.dispatch('on_drop_file', event.filename, drop_x, drop_y)
|
||||
|
||||
'''
|
||||
# unhandled event !
|
||||
else:
|
||||
Logger.debug('WinPygame: Unhandled event %s' % str(event))
|
||||
'''
|
||||
if not pygame.display.get_active():
|
||||
pygame.time.wait(100)
|
||||
|
||||
#
|
||||
# Pygame wrapper
|
||||
#
|
||||
def _pygame_set_mode(self, size=None):
|
||||
if size is None:
|
||||
size = self.size
|
||||
if self.fullscreen == 'auto':
|
||||
pygame.display.set_mode((0, 0), self.flags)
|
||||
else:
|
||||
pygame.display.set_mode(size, self.flags)
|
||||
|
||||
def _pygame_update_modifiers(self, mods=None):
|
||||
# Available mod, from dir(pygame)
|
||||
# 'KMOD_ALT', 'KMOD_CAPS', 'KMOD_CTRL', 'KMOD_LALT',
|
||||
# 'KMOD_LCTRL', 'KMOD_LMETA', 'KMOD_LSHIFT', 'KMOD_META',
|
||||
# 'KMOD_MODE', 'KMOD_NONE'
|
||||
if mods is None:
|
||||
mods = pygame.key.get_mods()
|
||||
self._modifiers = []
|
||||
if mods & (pygame.KMOD_SHIFT | pygame.KMOD_LSHIFT):
|
||||
self._modifiers.append('shift')
|
||||
if mods & (pygame.KMOD_ALT | pygame.KMOD_LALT):
|
||||
self._modifiers.append('alt')
|
||||
if mods & (pygame.KMOD_CTRL | pygame.KMOD_LCTRL):
|
||||
self._modifiers.append('ctrl')
|
||||
if mods & (pygame.KMOD_META | pygame.KMOD_LMETA):
|
||||
self._modifiers.append('meta')
|
||||
|
||||
def request_keyboard(
|
||||
self, callback, target, input_type='text', keyboard_suggestions=True
|
||||
):
|
||||
keyboard = super(WindowPygame, self).request_keyboard(
|
||||
callback, target, input_type, keyboard_suggestions)
|
||||
if android and not self.allow_vkeyboard:
|
||||
android.show_keyboard(target, input_type)
|
||||
return keyboard
|
||||
|
||||
def release_keyboard(self, *largs):
|
||||
super(WindowPygame, self).release_keyboard(*largs)
|
||||
if android:
|
||||
android.hide_keyboard()
|
||||
return True
|
||||
Reference in New Issue
Block a user