Prevent image stretching in Kivy canvas - kivy

The situation
I've made a Widget in Kivy in order to animate an image.
<AnimatedImage>:
pos_hint: root.pos_hint
size: root.size
size_hint: .3, .3
canvas:
Rectangle:
source: 'images/image.png'
pos: self.pos[0], self.pos[1]
size: root.size[0], 435. / 770 * root.size[0]
As you can see in the last line, I used the image ratio to calculate the rectangle size.
The problem
I would like to load different images and size the widget in adjustment.
What didn't work
Using Image instead of Widget. I was not able to animate the Image size_hint using Animation object.
Thanks!

Related

Make an image in Kivy exactly the same size as the widget bounding box

I'm having trouble in Kivy setting an image size. I want to keep the aspect ratio fixed but I also want to position things precisely over the top of the image.
To do this, I make a RelativeLayout that has the same size and position as the image. However, when I check the size of the layout, it is always slightly larger than the displayed image. Making precise alignment very difficult. The wiki mentions something like this:
By default, the image is centered and fits inside the widget bounding box. If you don’t want that, you can set allow_stretch to True and keep_ratio to False.
They also include code if you want to make the image slightly larger than the containing widget:
<-FullImage>:
canvas:
Color:
rgb: (1, 1, 1)
Rectangle:
texture: self.texture
size: self.width + 20, self.height + 20
pos: self.x - 10, self.y - 10
But nothing about making them exactly the same size!? Surely I should be able to dictate the containing widgets size so the aspect ratio etc. is exactly as required.
I have tried many things but whatever I try, I cannot get the outside edges of the displayed image and a layout to coincide.
Does anyone have any experience with this?
Apologies, I have discovered the problem, the images had a transparent border that I wasn't aware of (the images were passed on to me from elsewhere) I have removed this and it has solved the problem.

Transparent animated graphics in Kivy

I am new to Kivy and want to create a widge graphic image of a tank with a transparent cutout that "fills" with another graphic image of the product. How do I stack 2 graphic images, one with a transparent layer, on top of one another to get this effect? I have created this with a circle/rectangle and fill color, but I want both a custom foreground image and a custom fill image.
You can stack Image widgets by simply placing them at the same position. For example, in kv you can do:
FloatLayout:
Image:
source: 'fill.png'
size_hint: 0.25, 0.25
pos_hint: {'center_x':0.5, 'center_y':0.5}
allow_stretch: True
Image:
source: 'tank.png'
size_hint: 0.25, 0.25
pos_hint: {'center_x':0.5, 'center_y':0.5}
allow_stretch: True
This will show the tank.png with the fill.png showing through any transparent areas of tank.png.

Wrong Kivy widget positions on Surface Pro4

I am relatively new in Kivy. Having studied quite a bit on my laptop, everything works fine until i started working on my surface pro 4. All my buttons were placed in wrong positions, irrespective of how I specify the position, pos or pos_hint, eg:
the window
above is the window that appears when the following code is run:
<Button>:
color: .8, .9, 0, 1
font_size: 31
size_hint: .4, .3
<FloatLayout>
Button:
text: 'button1'
pos_hint: {'x':0, 'top': 1}
Button:
text: 'button2'
pos_hint: {'right': 1, 'y': 0}
could this be due to issues with OpenGL on surface pro 4 or could I have done something totally dumb?
After going through the documentation, I was able to locate the config.ini file on my c: drive and changed the rotation value from 90 to 0. rotation = 0 and my widgets are placed as expected. Kudos to the Kivy.org team, great documentation.

rotate entire widget, not only its canvas

In this example, we can see a rotation of the canvas. But clicking the button's corners isn't registered. How can I rotate the entire button?
You can probably override its collide_point method to account for the rotation by transforming the touch coordinates.
If you use the widget system (e.g. putting the Button in a Scatter), the collision is taken care of for you.
Based on inclement's answer, I've created a button on a scatter layout, which has its hitbox set correctly.
from kivy.app import App
from kivy.lang import Builder
kv = '''
FloatLayout:
ScatterLayout:
size_hint: None, None
size: 200, 200
pos_hint: {'center_x': .5, 'center_y': .5}
rotation: 45
do_rotation: False
do_scale: False
do_translation: False
Button:
text: 'hello world'
'''
class RotationApp(App):
def build(self):
return Builder.load_string(kv)
RotationApp().run()
I used scatter layout instead of scatter, because it passes its size to children widgets. The do_x: False aren't needed in this example, because button intercepts touching events, but if I placed a label, it would move on touch.

Dynamically resizing a Label within a Scrollview?

Let's say you have a setup like the following:
ScrollView:
size_hint: (1, 0.5)
Label:
size_hint: (1, None)
Initially, the Label has no content/text. If I understand correctly, when the objects are created, the Label's height is None.
When the app is run, the Label's text property is set to multiple lines of text, which should push the content of the Label outside the boundaries of the ScrollView. However, for scrolling to happen, it seems that the Label's y dimension/height has to be dynamically resized.
What is the best way to dynamically resize the height of the Label in accordance with the Label's new content such that a scrolling action can occur?
The actual text is displayed in a Rectangle whose size is not coupled to the Label size by default. When the amount of text is large, this grows larger and can exceed the Label bounds, but does not resize the label.
The relevant property controlling the real size of the displayed text is Label.text_size. To get the behaviour you want, you can simply do:
ScrollView:
size_hint: (1, 0.5)
Label:
size_hint: (1, None)
height: self.text_size[1]
This binds the height of the label to track the height of the displayed text, and so should give you the behaviour you want.
As a side note, it's often useful to change or watch text_size. For instance, to make the text wrap at the edges of the Label rather than relying on manual newlines, you can set text_size: self.size which means the text will be automatically wrapped if its width would exceed the label width. This is also important if working with halign or valign, which control the text position within its texture and not within the label itself - those properties will have no visible effect unless you manually set text_size to (again) something larger than the space the text actually takes up.
Edit: As per your comments below, here's an example of a Label in one of my apps, which grows vertically if the length of text increases (so the user can scroll), but also automatically wraps text when its width is greater than the label width. It seems I actually did this by putting the Label in a GridLayout, which I vaguely remember was important for some reason.
GridLayout:
cols: 1
spacing: 10
size_hint_y: None
height: thetb.texture_size[1]
Label:
id: thetb
text: 'whatever'
text_size: self.width, None
size_hint: (1, None)
size: self.parent.width, self.texture_size[1]
You can see I use text_size to control the text boundingbox (so it wraps at the label edges), but bind the GridLayout height to really track the texture_size height. The GridLayout is placed in the ScrollView, and I get exactly the behaviour I think you want.

Resources