Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIL text provider: Ensure consistent text height to prevent text from bouncing when typing #8511

Merged
merged 2 commits into from Dec 26, 2023

Conversation

DexerBR
Copy link
Contributor

@DexerBR DexerBR commented Dec 14, 2023

When using the PIL text provider to render text, the height of the text will be computed incorrectly. When typing text, for example, the text will be "jumping/bouncing". The code in this PR gets the actual height of the font, in order to get a consistent height for the text, and prevent this type of behavior from occurring.

Before:

before.mp4

After:

after.mp4

Test code:

Note: Use "d" and "f" to change fonts.

import os
os.environ['KIVY_TEXT'] = 'pil'


from kivy.core.window import Window
from kivy.app import App, Builder
from kivy.base import EventLoop

Window.clearcolor = (1, 1, 1, 1)


class TestApp(App):

    
    def build(self):
        EventLoop.window.bind(on_keyboard=self._hook_keyboard)

        return Builder.load_string(r"""

BoxLayout:
    TextInput:
        id: ti
        foreground_color: (0, 0, 0, 1)
        cursor_width: dp(2)
        font_size: dp(50)
        
    Label:
        id: label_widget
        text: ti.text
        color: (0, 0, 0, 1)
        font_size: dp(50)
        text_size: self.width ,None
        size_hint_y: None
        height: self.texture_size[1]
        pos_hint: {"center_x": 0.5,"center_y": 0.5}
        markup: True

        canvas.before:
            Color:
                rgba: (0, 0, 1, 0.5)
            Rectangle:
                pos: self.pos
                size: self.size

""")
    

    def _hook_keyboard(self, window, key, keycode, text, modifiers):
        if text == 'd':
            self.root.ids.ti.font_name = self.root.ids.label_widget.font_name = get_next_font(self.root.ids.label_widget.font_name, 'left')
        if text == 'f':
            self.root.ids.ti.font_name = self.root.ids.label_widget.font_name = get_next_font(self.root.ids.label_widget.font_name, 'right')

def get_font_list():
    import pathlib

    def get_fonts(fonts_path):
        '''Get a list of all the fonts available on this system.
        '''

        if not fonts_path: return []
        font_list = []
        for fdir in fonts_path:
            font_list += pathlib.Path(fdir).rglob('*.ttf')
        
        nflist = []
        for i, x in enumerate(font_list):
            if not str(x).split('/')[-1].startswith('._'):
                nflist.append(str(x))
        
        return sorted([*set(nflist)])
    
    from os.path import join, dirname, abspath
    from kivy.core.text import Label as CoreLabel

    return get_fonts(fonts_path = \
        [abspath(join(dirname(__file__), '..', 'data', 'fonts'))] +\
        CoreLabel.get_system_fonts_dir()
        )

font_list = get_font_list()

def get_next_font(pfont_name, l_r):
    try:
        idx = font_list.index(pfont_name)
    except ValueError:
        return font_list[0]

    try:
        font_name = str(font_list[idx +\
                                (-1 if l_r == 'left' else 1)])
    except IndexError:
        font_name = font_list[0]
    return font_name

if __name__ == "__main__":
    TestApp().run()

This PR also removes the deprecated FreeTypeFont.getsize(). FreeTypeFont.getsize() is deprecated since version 9.2.0

Maintainer merge checklist

  • Title is descriptive/clear for inclusion in release notes.
  • Applied a Component: xxx label.
  • Applied the api-deprecation or api-break label.
  • Applied the release-highlight label to be highlighted in release notes.
  • Added to the milestone version it was merged into.
  • Unittests are included in PR.
  • Properly documented, including versionadded, versionchanged as needed.

@akshayaurora
Copy link
Member

@DexerBR we need the older getsize, cause kivy supports older versions of pillow too. Is the issue with ascent/descent a issue with older versions of get size too ?

@DexerBR
Copy link
Contributor Author

DexerBR commented Dec 15, 2023

@DexerBR we need the older getsize, cause kivy supports older versions of pillow too. Is the issue with ascent/descent a issue with older versions of get size too ?

Yes, this happens in previous versions. I tested version 8.0.0 (I couldn't install previous versions, apparently there is a problem with the wheels from previous versions of PIL).

This PR was also tested in version 8.0.0 of PIL, works fine

@akshayaurora
Copy link
Member

akshayaurora commented Dec 15, 2023

Btw, I just tested with SDL2 text provider and we have the same behaviour... As in the behaviour is consistent across providers.

We should treat this as a new feature ? Would make sense to add this as an optional feature that can be enabled but is disabled by default for consistency.

Update: I was typing ,Hello World d triggering the font change, sry. Doing more testing >_<

Copy link
Member

@misl6 misl6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless @akshayaurora found something else during the tests (so keeping it unmerged ATM), LGTM, thank you!

@misl6 misl6 added this to the 2.3.0 milestone Dec 17, 2023
@misl6 misl6 merged commit 5e5cfe4 into kivy:master Dec 26, 2023
36 checks passed
@DexerBR DexerBR deleted the pil_text_provider_fix branch December 26, 2023 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants