Created
July 31, 2015 17:37
-
-
Save kived/7cdcf5182388207a4974 to your computer and use it in GitHub Desktop.
Kivy: SizedLabel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SizedLabel(Label): | |
max_lines = BoundedNumericProperty(3, min=1) | |
sizetext = StringProperty('') | |
auto_wrap = BooleanProperty(True) | |
auto_height = BooleanProperty(False) | |
outline_color = ListProperty([0.0] * 4) | |
line_threshold = ListProperty((36, 80, 124,)) | |
resize_text = BooleanProperty(True) | |
resize_text_down_only = BooleanProperty(False) | |
wordsep_re = re.compile( | |
r'([^\s\w]*\w+[^0-9\W] -(?=\W)|' # keep en-dashes | |
r'\s+|' # any whitespace | |
r'[^\s\w]*\w+[^0-9\W]-(?=\w+[^0-9\W])|' # hyphenated words | |
r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash | |
wordsep_re_uni = re.compile(wordsep_re.pattern, re.U) | |
def __init__(self, **kwargs): | |
super(SizedLabel, self).__init__(**kwargs) | |
self.halign = 'center' | |
#self.bind(on_size=self.text_size) | |
self.wrapper = textwrap.TextWrapper(break_long_words=False, expand_tabs=False) | |
self.trigger_sizetext = Clock.create_trigger(self.update_sizetext, -1) | |
self.bind(sizetext=self.trigger_sizetext, size=self.trigger_sizetext) | |
self.trigger_sizetext() | |
def get_max_lines(self, height): | |
height_lines = 99999 | |
if height < self.line_threshold[0]: | |
height_lines = 1 | |
elif height < self.line_threshold[1]: | |
height_lines = 2 | |
elif height < self.line_threshold[2]: | |
height_lines = 3 | |
return min(height_lines, self.max_lines) | |
def update_sizetext(self, *_args): | |
if not self.width or not self.height: | |
return | |
cw = self.width - max(8, self.width * 0.08) | |
ch = self.height - max(8, self.height * 0.08) | |
text = ' '.join(self.sizetext.strip().split()) | |
max_lines = self.get_max_lines(ch) | |
num_lines = min(max_lines, text.count(' ') + 1) | |
self.text = text | |
if self.resize_text: | |
self.font_size = 16 | |
self.texture_update() | |
if not text or not ch: | |
return | |
ts = self.texture_size | |
sr = [[float(ts[0]) / ts[1], text, 1, float(ts[0]), float(ts[1])]] | |
if self.auto_wrap and num_lines > 1: | |
label = self._label | |
wrapper = self.wrapper | |
wrap = wrapper._wrap_chunks | |
join = '\n'.join | |
text = text.translate(wrapper.whitespace_trans if isinstance(text, str) else wrapper.unicode_whitespace_trans) | |
stext = filter(None, (self.wordsep_re if isinstance(text, str) else self.wordsep_re_uni).split(text)) | |
for wrapper.width in reversed(range(int(len(text) / (num_lines + 1)), int(len(text) * 0.75 + 0.5))[1:]): | |
wrapped = wrap(stext[:]) | |
lines = len(wrapped) | |
if lines > num_lines: | |
break | |
ltext = join(wrapped) | |
self.text = ltext | |
label.refresh() | |
size = label.texture.size | |
sr.append([float(size[0]) / size[1], ltext, lines, size[0], size[1]]) | |
cr = float(cw) / ch | |
och = ch | |
sr = sorted(sr, key=lambda a: abs(cr - a[0])) | |
for _i, v in enumerate(sr): | |
_ratio, text, lines, width, height = v | |
self.text = text | |
if not self.auto_height: | |
ch = och * (float(lines) / max_lines) | |
else: | |
ch = och | |
upsize = ch / height | |
if width * upsize > cw: | |
# skip any options which require resizing | |
continue | |
self.resize_text_method(upsize) | |
self.texture_update() | |
return | |
# well, there weren't any options without resizing | |
_ratio, text, lines, width, height = max(sr, key=lambda a: a[2] * 2 - abs(cr - a[0])) | |
self.text = text | |
upsize = cw / width | |
self.resize_text_method(upsize) | |
self.texture_update() | |
def resize_text_method(self, upsize): | |
if upsize > 0 and self.resize_text: | |
if self.resize_text_down_only: | |
if upsize < 1: | |
self.font_size *= upsize | |
else: | |
self.font_size *= upsize |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment