Skip to content

Commit

Permalink
Make keyboard resizable
Browse files Browse the repository at this point in the history
  • Loading branch information
anxuae committed Jun 5, 2021
1 parent 6133839 commit 350c19a
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 62 deletions.
68 changes: 68 additions & 0 deletions pygame_vkeyboard/examples/resize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env python
# coding: utf8

"""Simple keyboard usage using QWERTY layout and input text."""

# pylint: disable=import-error
import pygame
import pygame_vkeyboard as vkboard
# pylint: enable=import-error


def on_key_event(text):
""" Print the current text. """
print('Current text:', text)


def main(test=False):
""" Main program.
:param test: Indicate function is being tested
:type test: bool
:return: None
"""

# Init pygame
pygame.init()
screen = pygame.display.set_mode((500, 300), pygame.RESIZABLE)
screen.fill((100, 100, 100))

# Create keyboard
layout = vkboard.VKeyboardLayout(vkboard.VKeyboardLayout.QWERTY,
allow_special_chars=False,
allow_space=False)
keyboard = vkboard.VKeyboard(screen,
on_key_event,
layout,
renderer=vkboard.VKeyboardRenderer.DARK,
show_text=True,
joystick_navigation=True)

clock = pygame.time.Clock()

# Main loop
while True:
clock.tick(100) # Ensure not exceed 100 FPS

events = pygame.event.get()

for event in events:
if event.type == pygame.QUIT:
print("Average FPS: ", clock.get_fps())
exit()
if event.type == pygame.VIDEORESIZE:
screen.fill((100, 100, 100))

keyboard.update(events)
rects = keyboard.draw(screen)

# Flip only the updated area
pygame.display.update(rects)

# At first loop returns
if test:
break


if __name__ == '__main__':
main()
101 changes: 63 additions & 38 deletions pygame_vkeyboard/vkeyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ class VKeyboardLayout(object):

# TODO : Insert special characters layout which include number.
SPECIAL = [u'&é"\'(§è!çà)', u'°_-^$¨*ù`%£', u',;:=?.@+<>#', u'€[]{}/\\|']
"""Special characters layout. """

def __init__(self,
model,
Expand Down Expand Up @@ -211,7 +210,6 @@ def __init__(self,
self.size = None
self.rows = []
self.sprites = pygame.sprite.LayeredDirty()
self.key_size = key_size
self.padding = padding
self.height_ratio = height_ratio
self.selection = None
Expand All @@ -231,6 +229,17 @@ def __init__(self,
if height_ratio is not None and (height_ratio < 0.2 or height_ratio > 1):
raise ValueError('Surface height ratio shall be from 0.2 to 1')

self._key_size = key_size
self._key_size_computed = None

@property
def key_size(self):
return self._key_size or self._key_size_computed

@key_size.setter
def key_size(self, key_size):
self._key_size = key_size

def hide(self):
"""Hide all keys."""
for sprite in self.sprites:
Expand Down Expand Up @@ -310,18 +319,18 @@ def configure_bound(self, surface_size):
Size of the surface this layout will be rendered on.
"""
nb_rows = len(self.rows)
key_size_defined = self.key_size is not None
if self.key_size is None:
self.key_size = int(
if self._key_size is None:
self._key_size_computed = int(
(surface_size[0] - (self.padding * (self.max_length + 1)))
/ self.max_length)

height = self.key_size * nb_rows + self.padding * (nb_rows + 1)
if height > surface_size[1] * (self.height_ratio or 0.5):
self.key_size = int((surface_size[1] * (self.height_ratio or 0.5)
- (self.padding * (nb_rows + 1))) / nb_rows)
self._key_size_computed = int((surface_size[1] * (self.height_ratio or 0.5)
- (self.padding * (nb_rows + 1))) / nb_rows)
height = self.key_size * nb_rows + self.padding * (nb_rows + 1)
if key_size_defined:
if self._key_size:
self._key_size = self._key_size_computed
LOGGER.warning('Computed layout height outbound target surface,'
' reducing key_size to %spx', self.key_size)
elif self.height_ratio is not None:
Expand Down Expand Up @@ -505,31 +514,26 @@ def __init__(self,
if self.layout.allow_special_chars:
if not special_char_layout:
special_char_layout = VKeyboardLayout(
VKeyboardLayout.SPECIAL,
key_size=self.layout.key_size,
padding=self.layout.padding,
height_ratio=self.layout.height_ratio,
allow_uppercase=self.layout.allow_uppercase,
allow_special_chars=self.layout.allow_special_chars,
allow_space=self.layout.allow_space)
VKeyboardLayout.SPECIAL,
key_size=self.layout.key_size,
padding=self.layout.padding,
height_ratio=self.layout.height_ratio,
allow_uppercase=self.layout.allow_uppercase,
allow_special_chars=self.layout.allow_special_chars,
allow_space=self.layout.allow_space)
self.layouts.append(special_char_layout)

for layout in self.layouts:
layout.configure_special_keys(self)
layout.configure_renderer(self.renderer)
layout.sprites.add(self.background, layer=0)

synchronize_layouts(self.surface.get_size(), *self.layouts)
self.background.set_rect(*self.layout.position + self.layout.size)

# Setup the text input box
self.show_text = show_text
self.input = VTextInput((self.layout.position[0],
self.layout.position[1]
- self.layout.key_size),
(self.layout.size[0],
self.layout.key_size),
renderer=self.renderer)
self.input = VTextInput((0, 0), (10, 10), renderer=self.renderer)

self.resize(surface)

if self.show_text:
self.input.enable()

Expand All @@ -553,6 +557,36 @@ def set_layout(self, layout):
self.layout = layout
self.layout.show()

def set_eraser(self, surface):
"""Setup the surface used to hide/clear the keyboard.
"""
self.eraser = surface.copy()
for layout in self.layouts:
layout.sprites.clear(surface, self.eraser)

def resize(self, surface):
"""Resize the keyboard according to the surface size and the parameters
of the layout(s).
Parameters
----------
surface:
Surface this keyboard will be displayed at.
"""
synchronize_layouts(surface.get_size(), *self.layouts)
self.background.set_rect(*self.layout.position + self.layout.size)

for layout in self.layouts:
if layout.sprites.get_clip() != self.background.rect:
# Changing the clipping area will force update of all
# sprites without using "dirty mechanism"
layout.sprites.set_clip(self.background.rect)

self.input.set_line_rect(self.layout.position[0],
self.layout.position[1] - self.layout.key_size,
self.layout.size[0],
self.layout.key_size)

def set_text(self, text):
"""Set the current text in the internal buffer.
Expand Down Expand Up @@ -591,13 +625,6 @@ def get_rect(self):
rect = rect.union(self.input.get_rect())
return rect

def set_eraser(self, surface):
"""Setup the surface used to hide/clear the keyboard.
"""
self.eraser = surface.copy()
for layout in self.layouts:
layout.sprites.clear(surface, self.eraser)

def draw(self, surface=None, force=False):
"""Draw the virtual keyboard.
Expand Down Expand Up @@ -625,17 +652,15 @@ def draw(self, surface=None, force=False):
"""
surface = surface or self.surface

# Check if surface has been resized
if self.eraser and surface.get_rect() != self.eraser.get_rect():
force = True # To force creating new eraser
self.resize(surface)

# Setup eraser
if not self.eraser or force:
self.set_eraser(surface)

# Setup new the surface where to draw
for layout in self.layouts:
if layout.sprites.get_clip() != self.background.rect:
# Changing the clipping area will force update of all
# sprites without using "dirty mechanism"
layout.sprites.set_clip(self.background.rect)

rects = self.layout.sprites.draw(surface)
rects += self.input.draw(surface, force)

Expand Down
Loading

0 comments on commit 350c19a

Please sign in to comment.