Source code for albow.extended_widgets

# -*- coding: UTF-8 -*-
# extended_widgets.py
# Moved albow related stuff from mceutils.
from controls import ValueDisplay
from dialogs import alert, ask, Dialog
from controls import Button, Label, ValueButton, CheckBox, AttrRef
from widget import Widget
import root
from layout import Column, Row
from translate import _
from menu import Menu
from fields import FloatField, IntField, TextFieldWrapped, TextField
from datetime import timedelta, datetime


[docs]class HotkeyColumn(Widget): is_gl_container = True #-# Translation live update preparation def __init__(self, items, keysColumn=None, buttonsColumn=None, item_spacing=None, translateButtons=True): """:items iterable containing iterables composed with the hotkey, the label of the button and the binding :keysColumn iterable :buttonsColumn iterable containing Button widgets :item_spacing int :translateButtons bool or iterable of int If bool, all the buttons in :items will be translated (True) or not (False). If iterable, the elements must be (signed) ints corresponding to the indexes of the buttons to be translated in :items. The buttons not referenced in an iterable :translateButtons will not be translated. """ self.items = items self.item_spacing = item_spacing self.keysColumn = keysColumn self.buttonsColumn = buttonsColumn self.translateButtons = translateButtons Widget.__init__(self) self.buildWidgets()
[docs] def set_update_ui(self, v): if v: self.buildWidgets()
[docs] def buildWidgets(self): keysColumn = self.keysColumn buttonsColumn = self.buttonsColumn items = self.items item_spacing = self.item_spacing if keysColumn is None or True: keysColumn = [] if buttonsColumn is None or True: buttonsColumn = [] labels = [] for w in self.subwidgets: for _w in w.subwidgets: w.remove(_w) self.remove(w) for i, t in enumerate(items): if type(self.translateButtons) is bool: trn = not self.translateButtons elif type(self.translateButtons) in (list, tuple): trn = not i in self.translateButtons if len(t) == 3: (hotkey, title, action) = t tooltipText = None else: (hotkey, title, action, tooltipText) = t if isinstance(title, (str, unicode)): button = Button(title, action=action, doNotTranslate=trn) else: button = ValueButton(ref=title, action=action, width=200, doNotTranslate=trn) button.anchor = self.anchor label = Label(hotkey, width=100, margin=button.margin) label.anchor = "wh" label.height = button.height labels.append(label) if tooltipText: button.tooltipText = tooltipText keysColumn.append(label) buttonsColumn.append(button) self.buttons = list(buttonsColumn) #.# if item_spacing == None: buttonsColumn = Column(buttonsColumn) else: buttonsColumn = Column(buttonsColumn, spacing=item_spacing) #.# buttonsColumn.anchor = self.anchor #.# if item_spacing == None: keysColumn = Column(keysColumn) else: keysColumn = Column(keysColumn, spacing=item_spacing) commandRow = Row((keysColumn, buttonsColumn)) self.labels = labels self.add(commandRow) self.shrink_wrap() self.invalidate() #-#
[docs]class ChoiceButton(ValueButton): align = "c" choose = None def __init__(self, choices, scrolling=True, scroll_items=30, **kw): # passing an empty list of choices is ill-advised if 'choose' in kw: self.choose = kw.pop('choose') self.doNotTranslate = kw.get('doNotTranslate', False) #-# Translation live update preparation self.scrolling = scrolling self.scroll_items = scroll_items self.choices = choices or ["[UNDEFINED]"] ValueButton.__init__(self, action=self.showMenu, **kw) self.calc_width() #-# self.choiceIndex = 0 #-# Translation live update preparation
[docs] def set_update_ui(self, v): ValueButton.set_update_ui(self, v) self.menu.set_update_ui(v)
[docs] def calc_width(self): widths = [self.font.size(_(c, self.doNotTranslate))[0] for c in self.choices] + [self.width] if len(widths): self.width = max(widths) + self.margin * 2
[docs] def calc_size(self): ValueButton.calc_size(self) self.calc_width() #-#
[docs] def showMenu(self): choiceIndex = self.menu.present(self, (0, 0)) if choiceIndex != -1: self.choiceIndex = choiceIndex if self.choose: self.choose()
[docs] def get_value(self): return self.selectedChoice
@property def selectedChoice(self): if self.choiceIndex >= len(self.choices) or self.choiceIndex < 0: return "" return self.choices[self.choiceIndex] @selectedChoice.setter def selectedChoice(self, val): idx = self.choices.index(val) if idx != -1: self.choiceIndex = idx @property def choices(self): return self._choices @choices.setter def choices(self, ch): self._choices = ch self.menu = Menu("", [(name, "pickMenu") for name in self._choices], self.scrolling, self.scroll_items, doNotTranslate=self.doNotTranslate)
[docs]def CheckBoxLabel(title, *args, **kw): tooltipText = kw.pop('tooltipText', None) l_kw = {'margin': 0} b_kw = {'margin': 0} expand = kw.pop('expand', 'none') r_kw = {} if expand != 'none': r_kw['expand'] = expand align = kw.pop('align', None) if align: r_kw['align'] = align cb = CheckBox(*args, **kw) lab = Label(title, fg_color=cb.fg_color) lab.mouse_down = cb.mouse_down if tooltipText: cb.tooltipText = tooltipText lab.tooltipText = tooltipText class CBRow(Row): margin = 0 @property def value(self): return self.checkbox.value @value.setter def value(self, val): self.checkbox.value = val row = CBRow((Column((lab,), **l_kw), Column((cb,), **b_kw)), **r_kw) row.checkbox = cb return row
[docs]def FloatInputRow(title, *args, **kw): return Row((Label(title, tooltipText=kw.get('tooltipText')), FloatField(*args, **kw)))
[docs]def IntInputRow(title, *args, **kw): return Row((Label(title, tooltipText=kw.get('tooltipText')), IntField(*args, **kw)))
[docs]def TextInputRow(title, *args, **kw): return Row((Label(title, tooltipText=kw.get('tooltipText')), TextFieldWrapped(*args, **kw)))
[docs]def BasicTextInputRow(title, *args, **kw): return Row((Label(title, tooltipText=kw.get('tooltipText')), TextField(*args, **kw)))
[docs]def showProgress(progressText, progressIterator, cancel=False): """Show the progress for a long-running synchronous operation. progressIterator should be a generator-like object that can return either None, for an indeterminate indicator, A float value between 0.0 and 1.0 for a determinate indicator, A string, to update the progress info label or a tuple of (float value, string) to set the progress and update the label""" class ProgressWidget(Dialog): progressFraction = 0.0 firstDraw = False root = None def draw(self, surface): if self.root is None: self.root = self.get_root() Widget.draw(self, surface) frameStart = datetime.now() frameInterval = timedelta(0, 1, 0) / 2 amount = None try: while datetime.now() < frameStart + frameInterval: amount = progressIterator.next() if self.firstDraw is False: self.firstDraw = True break except StopIteration: self.dismiss() infoText = "" if amount is not None: if isinstance(amount, tuple): if len(amount) > 2: infoText = ": " + amount[2] amount, max = amount[:2] else: max = amount maxwidth = (self.width - self.margin * 2) if amount is None: self.progressBar.width = maxwidth self.progressBar.bg_color = (255, 255, 25, 255) elif isinstance(amount, basestring): self.statusText = amount else: self.progressAmount = amount if isinstance(amount, (int, float)): self.progressFraction = float(amount) / (float(max) or 1) self.progressBar.width = maxwidth * self.progressFraction self.statusText = str("{0} / {1}".format(amount, max)) else: self.statusText = str(amount) if infoText: self.statusText += infoText @property def estimateText(self): delta = (datetime.now() - self.startTime) progressPercent = (int(self.progressFraction * 10000)) left = delta * (10000 - progressPercent) / (progressPercent or 1) return _("Time left: {0}").format(left) def cancel(self): if cancel: self.dismiss(False) def idleevent(self, evt): self.invalidate() def key_down(self, event): pass def key_up(self, event): pass def mouse_up(self, event): try: if "SelectionTool" in str(self.root.editor.currentTool): if self.root.get_nudge_block().count > 0: self.root.get_nudge_block().mouse_up(event) except: pass widget = ProgressWidget() widget.progressText = _(progressText) widget.statusText = "" widget.progressAmount = 0.0 progressLabel = ValueDisplay(ref=AttrRef(widget, 'progressText'), width=550) statusLabel = ValueDisplay(ref=AttrRef(widget, 'statusText'), width=550) estimateLabel = ValueDisplay(ref=AttrRef(widget, 'estimateText'), width=550) progressBar = Widget(size=(550, 20), bg_color=(150, 150, 150, 255)) widget.progressBar = progressBar col = (progressLabel, statusLabel, estimateLabel, progressBar) if cancel: cancelButton = Button("Cancel", action=widget.cancel, fg_color=(255, 0, 0, 255)) col += (Column((cancelButton,), align="r"),) widget.add(Column(col)) widget.shrink_wrap() widget.startTime = datetime.now() if widget.present(): return widget.progressAmount else: return "Canceled"