Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gottadiveintopython/f8a620a4ced20dd4c6d450d09f696fc5 to your computer and use it in GitHub Desktop.
Save gottadiveintopython/f8a620a4ced20dd4c6d450d09f696fc5 to your computer and use it in GitHub Desktop.
getting familiar with size_hint_min #1
'''
CPython 3.8.12
pip install kivy[base]==2.1.0
pip install "asynckivy>=0.5,<0.6"
pip install git+https://github.com/gottadiveintopython/kivyx.uix.magnet#egg=kivyx.uix.magnet
'''
from kivy.config import Config
Config.set('graphics', 'width', 1280)
Config.set('graphics', 'height', 720)
# Config.set('graphics', 'maxfps', 30)
# Config.set('graphics', 'fullscreen', 1)
from kivy.app import App
from kivy.lang import Builder
from kivyx.uix.magnet import KXMagnet
KV_CODE = r'''
#:import sm kivy.uix.screenmanager
#:import KivyLexer kivy.extras.highlight.KivyLexer
BoxLayout:
orientation: 'vertical'
spacing: '20dp'
padding: '20dp'
BoxLayout:
id: btn_container
spacing: '20dp'
pos_hint: {'x': 0, 'y': 0, }
ScreenManager:
id: scrmgr
transition: sm.NoTransition()
canvas.before:
Color:
rgb: .5, .5, .5
Line:
points: (self.x, self.top, self.right, self.top, )
width: 2.
Screen:
name: 'desc'
Label:
id: desc_label
padding: dp(10), dp(10)
font_size: '30sp'
text_size: self.width, None
halign: 'center'
Screen:
name: 'code'
KXMagnet:
do_anim: False
CodeInput:
id: code
font_size: '24sp'
lexer: KivyLexer()
'''
class SampleApp(App):
def build(self):
return Builder.load_string(KV_CODE)
def on_start(self):
import asynckivy
asynckivy.start(self.main())
async def main(self):
from textwrap import dedent
from kivy.metrics import dp
from kivy.factory import Factory as F
import asynckivy as ak
ft = ak.fade_transition
ids = self.root.ids
btn_container = ids.btn_container
desc_label = ids.desc_label
await ak.n_frames(4)
async with ft(desc_label):
desc_label.text = "Let's say you want to put buttons in a row,"
await ak.sleep(1)
async with ft(btn_container):
for text in 'ABC':
btn = F.Button(text=text, font_size='30sp')
magnet = F.KXMagnet(do_anim=False)
magnet.add_widget(btn)
btn_container.add_widget(magnet)
await ak.sleep(1)
async with ft(desc_label):
desc_label.text = " and the text length of the buttons vary."
await ak.sleep(2)
async with ft(btn_container):
magnets = btn_container.children[::-1]
texts = ('A', 'python-for-android & buildozer & plyer & kivy-ios', 'C')
for magnet, text in zip(magnets, texts):
magnet.do_anim = True
magnet.children[0].text = text
await ak.sleep(2)
async with ft(desc_label):
desc_label.text = "In this situation, lots of people seem to like disabling size_hint, like this."
await ak.sleep(3)
async with ft(ids.scrmgr):
ids.scrmgr.current = 'code'
ids.code.text = dedent('''
<MyButton@Button>:
size_hint: None, None
width: self.texture_size[0] + dp(10)
height: self.texture_size[1] + dp(10)
BoxLayout:
id: button_container
size_hint_y: None
height: self.minimum_height
''')
await ak.sleep(1)
ids.code.parent.do_anim = True
for magnet in magnets:
magnet.size_hint = (None, None, )
ts = magnet.children[0].texture_size
magnet.width = ts[0] + dp(10)
magnet.height = ts[1] + dp(10)
btn_container.size_hint_y = None
bind_uid = btn_container.fbind('minimum_height', btn_container.setter("height"))
await ak.sleep(3)
async with ft(ids.scrmgr):
ids.scrmgr.current = 'desc'
desc_label.text = 'This works, but ends up leaving weird space on the right hand side.'
await ak.sleep(2)
filler = F.Widget(opacity=0)
btn_container.add_widget(filler)
await ak.one_frame()
with filler.canvas:
F.Color(0, .5, 0, 1)
F.Rectangle(pos=filler.pos, size=filler.size)
for __ in range(4):
await ak.animate(filler, opacity=1, d=.2)
await ak.animate(filler, opacity=0, d=.2)
await ak.animate(filler, opacity=1, d=.2)
await ak.sleep(2)
async with ft(self.root):
btn_container.remove_widget(filler)
desc_label.text = '''And what if the texture height of the buttons also vary ?'''
await ak.sleep(3)
magnets[2].children[0].text = 'multi\nline'
await ak.sleep(-1)
ts = magnets[2].children[0].texture_size
magnets[2].size = (ts[0] + dp(10), ts[1] + dp(10))
await ak.sleep(3)
async with ft(ids.scrmgr):
desc_label.text = '''If you want the all buttons to be the same height, your code would become like this.'''
await ak.sleep(3)
async with ft(ids.scrmgr):
ids.scrmgr.current = 'code'
ids.code.text = dedent('''
<MyButton@Button>:
size_hint_x: None
width: self.texture_size[0] + dp(10)
BoxLayout:
id: button_container
size_hint_y: None
height: max(c.texture_size[1] for c in self.children) + dp(10)
''')
await ak.sleep(2)
btn_container.unbind_uid('minimum_height', bind_uid)
def calc_height(boxlayout, children):
boxlayout.height = max(c.children[0].texture_size[1] for c in children) + dp(10)
bind_uid = btn_container.fbind('children', calc_height)
calc_height(btn_container, btn_container.children)
del calc_height
for magnet in magnets:
magnet.size_hint_y = 1
await ak.sleep(3)
async with ft(ids.scrmgr):
ids.scrmgr.current = 'desc'
desc_label.text = 'As you can see, you cannot rely on minimum_height in this method, which is annoying.'
await ak.sleep(4)
async with ft(ids.scrmgr):
desc_label.font_size = '60sp'
desc_label.text = 'size_hint_min solves all these problems.'
await ak.sleep(2)
async with ft(ids.scrmgr):
ids.scrmgr.current = 'code'
ids.code.text = dedent('''
<MyButton@Button>:
size_hin_min_x: self.texture_size[0] + dp(10)
size_hin_min_y: self.texture_size[1] + dp(10)
BoxLayout:
id: button_container
size_hint_y: None
height: self.minimum_height
''')
await ak.sleep(2)
btn_container.unbind_uid('children', bind_uid)
btn_container.bind(minimum_height=btn_container.setter("height"))
for magnet in magnets:
magnet.size_hint_x = 1
ts = magnet.children[0].texture_size
magnet.size_hint_min = (ts[0] + dp(10), ts[1] + dp(10))
await ak.sleep(3)
async with ft(ids.scrmgr):
ids.scrmgr.current = 'desc'
desc_label.text = 'size_hint_min makes your code clean.'
if __name__ == '__main__':
SampleApp().run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment