0

I have a Kivy carousel that is supposed to look like a baby book. Each slide has a float on it and each float has a picture, a label and some text. There are several problems, the text spills onto neighbouring slides, I can't get it to wrap and/or resize itself to stay in its float on its slide.

I have read lots of documentation and tried lots of things with pos_hint and size_hint, and text_size and size, but nothing is working as I expect. See for example this and this and this and this.

Wide view showing all text

Narrow view showing no wrapping, no resizing, and text spilling

The code is below. It is long but most of it is just adding widgets to parent widgets.

import kivy 
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout 
from kivy.uix.label import Label
from kivy.uix.image import AsyncImage 
from kivy.uix.carousel import Carousel 

def render_kivy_carousel(): 
    # Set the windows background colour.
    Window.clearcolor = (1, 1, 0, 1)
    # Create the book renditions root widget.
    bkr = Carousel() 
    bkr.width = 100
    bkr.loop = True
    # Add the page widgets.

    """PAGE 1
    """
    # Create the pages base widget
    flo = FloatLayout()

    # Build the image
    image = AsyncImage(source='https://wallpaperaccess.com/full/195082.jpg',
                allow_stretch = True,
                keep_ratio = True,
                size_hint = (0.5, 0.5),
                pos_hint = {'x': 0.25, 'y': 0.25},)
    flo.add_widget(image)

    # Build the label
    label = Label(text='Bee',
                color=(0,0,0,1),
                font_size=60,
                size_hint=(0.25, 0.25),
                pos_hint={'bottom': 1, 'left': 1},)
    flo.add_widget(label)
    
    # Build the text
    text = Label(text='The bee buzzes looking for flowers',
                color=(0,0,0,1),
                font_size=20,
                size_hint=(0.25, 0.25),
                pos_hint={'top': 1, 'right': 1},)
    flo.add_widget(text)
    bkr.add_widget(flo)

    """PAGE 2
    """
    # Create the pages base widget
    flo = FloatLayout()

    # Build the image
    image = AsyncImage(source='https://i.pinimg.com/originals/60/5b/c0/605bc0c0ef2645b43d64300bb2d82ed1.jpg',
                allow_stretch = True,
                keep_ratio = True,
                size_hint = (0.5, 0.5),
                pos_hint = {'x': 0.25, 'y': 0.25},)
    flo.add_widget(image)

    # Build the label
    label = Label(text='Beetle',
                color=(0,0,0,1),
                font_size=60,
                size_hint=(0.25, 0.25),
                pos_hint={'bottom': 1, 'left': 1},)
    flo.add_widget(label)
    
    # Build the text
    text = Label(text='The beetle looks at the sky',
                color=(0,0,0,1),
                font_size=20,
                size_hint=(0.25, 0.25),
                pos_hint={'top': 1, 'right': 1},)
    flo.add_widget(text)
    bkr.add_widget(flo)

    """PAGE 3
    """
    # Create the pages base widget
    flo = FloatLayout()

    # Build the image
    image = AsyncImage(source='https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQac3tmjWwO-o62Cm3iUAby6EVLWNG226UOJQ&usqp=CAU',
                allow_stretch = True,
                keep_ratio = True,
                size_hint = (0.5, 0.5),
                pos_hint = {'x': 0.25, 'y': 0.25},)
    flo.add_widget(image)

    # Build the label
    label = Label(text='Butterfly',
                color=(0,0,0,1),
                font_size=60,
                size_hint=(0.25, 0.25),
                pos_hint={'bottom': 1, 'left': 1},)
    flo.add_widget(label)
    
    # Build the text
    text = Label(text='The butterfly flaps its wings',
                color=(0,0,0,1),
                font_size=20,
                size_hint=(0.25, 0.25),
                pos_hint={'top': 1, 'right': 1},)
    flo.add_widget(text)
    bkr.add_widget(flo)

    # Return the root widget
    return bkr

# Create the App class 
class BookletApp(App): 
    def build(self): 
        return render_kivy_carousel()

# Run the App 
if __name__ == '__main__': 
    BookletApp().run()

Can someone please let me know the correct way to do this. What I want is for text to stay within its float on its slide, and to do this by wrapping and/or resizing/scaling with the window/slide.

Thanks

Mark Kortink
  • 1,770
  • 4
  • 21
  • 36
  • There is no `left` or `bottom` keys for `size_hint`. See the [documentation](https://kivy.org/doc/stable/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos_hint). – John Anderson Sep 17 '20 at 13:46
  • Oops, I meant `pos_hint`. – John Anderson Sep 17 '20 at 16:58
  • Use a kv rule for your label classes, with `text_size: self.size` – inclement Sep 17 '20 at 18:41
  • @inclement I could but given I call the render_kivy_carousel() function I am not sure how to structure the kv file. Can you post a sample kv file that solves the problem above with my code? – Mark Kortink Sep 17 '20 at 22:03
  • @John Anderson yes it does, see the float documentation https://kivy.org/doc/stable/api-kivy.uix.floatlayout.html – Mark Kortink Sep 17 '20 at 22:08
  • There is no `left` or `bottom` keys for `pos_hint`. Read the link that you posted and follow the `pos_hint` link there (which takes you to my posted link). The valid keys are ‘x’, ‘right’, ‘center_x’, ‘y’, ‘top’, ‘center_y’, and `pos`. There is no `left` or `bottom`. For `left` you should use `x`, and for `bottom` you should use `y`. – John Anderson Sep 17 '20 at 22:33

1 Answers1

0

I have concocted two widgets that inherit from standard Kivy widgets and have the desired behaviour. This may not be the best way to do it but it works.

Text Wrapping Widget This widget acts like a "text box" and the text inside it wraps. You can replace Button with Label but buttons have more functionality. All the attributes and methods of Button are available.

from kivy.uix.button import Button
...
class WrapBox(Button):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.bind(
            width=lambda *x:
                self.setter('text_size')(self, (self.width, None)),
            texture_size=lambda *x: 
                self.setter('height')(self, self.texture_size[1]))
...
txtbox = WrapBox(text='wrap me up in your love baby')
txtbox.color = (0,0,0,1)
txtbox.font_size = 60

Text Resizing Widget This widget acts like a "text box" and the text inside it resizes as the window it is in resizes. As you can see the underlying widget is actually an Image drawn from the texture in a Button. All the attributes and methods of Button are available.

from kivy.uix.image import Image
from kivy.uix.button import Button
...
class ResizeBox(Image):
    text = StringProperty('')
    def on_text(self, *args):
        # Just get large texture:
        lbl = Button(text=self.text)
        # Value that'll give texture bigger than screen size
        # Small values result in blur.
        lbl.font_size = '1000dp'  
        lbl.texture_update()
        # Set it to image, it'll be scaled to image size automatically
        self.texture = lbl.texture
...
txtbox = ResizeBox(text='resize me with your love baby')
txtbox.color = (0,0,0,1)
txtbox.font_size = 60

Wrapped and Resized

Mark Kortink
  • 1,770
  • 4
  • 21
  • 36