class LUIKeyMarker(LUIObject): def __init__(self, parent=None, key=u"A"): LUIObject.__init__(self) self.bgLeft = LUISprite(self, "Keymarker_Left", "skin") self.bgMid = LUISprite(self, "Keymarker", "skin") self.bgRight = LUISprite(self, "Keymarker_Right", "skin") self.label = LUILabel(parent=self, text=key, shadow=True) self.label.centered = (True, True) self.label.margin = (-3, 0, 0, -1) self.margin = (-1, 0, 0, -1) self.set_key(key) if parent is not None: self.parent = parent self.fit_to_children() def set_key(self, key): self.label.set_text(key) self.width = self.label.width + self.bgLeft.width + self.bgRight.width + 7 self.bgMid.width = self.width - self.bgLeft.width - self.bgRight.width self.bgMid.left = self.bgLeft.width self.bgRight.left = self.bgMid.width + self.bgMid.left self.fit_to_children()
def _render_options(self, options): visible = min(4, len(options)) offsetTop = 6 self.layout.height = visible * 30 + offsetTop + 11 self.container.height = visible * 30 + offsetTop + 1 self.layout.update_layout() self.container.remove_all_children() currentY = offsetTop for optId, optVal in options: optContainer = LUIObject(self.container, x=0, y=currentY, w=self.container.width - 30, h=30) optBg = LUISprite(optContainer, "blank", "skin") optBg.width = self.container.width optBg.height = optContainer.height optBg.color = (0,0,0,0) optBg.bind("mouseover", self._on_opt_over) optBg.bind("mouseout", self._on_opt_out) optBg.bind("click", partial(self._on_opt_click, optId)) optBg.solid = True optLabel = LUILabel(parent=optContainer, text=unicode(optVal), shadow=True) optLabel.top = 5 optLabel.left = 8 if optId == self.selectbox.get_selected_option(): optLabel.color = (0.6, 0.9, 0.4, 1.0) divider = LUISprite(optContainer, "SelectdropDivider", "skin") divider.top = 30 - divider.height / 2 divider.width = self.container.width currentY += 30
def _render_options(self, options): """ Internal method to update the options """ num_visible_options = min(30, len(options)) offset_top = 6 self._layout.height = num_visible_options * 30 + offset_top + 11 self._container.height = num_visible_options * 30 + offset_top + 1 self._container.remove_all_children() current_y = offset_top for opt_id, opt_val in options: opt_container = LUIObject(self._container, x=0, y=current_y, w=self._container.width - 30, h=30) opt_bg = LUISprite(opt_container, "blank", "skin") opt_bg.width = self._container.width opt_bg.height = opt_container.height opt_bg.color = (0,0,0,0) opt_bg.bind("mouseover", self._on_opt_over) opt_bg.bind("mouseout", self._on_opt_out) opt_bg.bind("mousedown", lambda *args: self.request_focus()) opt_bg.bind("click", partial(self._on_opt_click, opt_id)) opt_bg.solid = True opt_label = LUILabel(parent=opt_container, text=unicode(opt_val)) opt_label.top = 8 opt_label.left = 8 if opt_id == self._selectbox.selected_option: opt_label.color = (0.6, 0.9, 0.4, 1.0) divider = LUISprite(opt_container, "SelectdropDivider", "skin") divider.top = 30 - divider.height / 2 divider.width = self._container.width current_y += 30
def __init__(self, parent=None, width=200, value=50, show_label=True): """ Constructs a new progress bar. If show_label is True, a label indicating the current progress is shown """ LUIObject.__init__(self) self.set_width(width) self._bg_layout = LUIHorizontalStretchedLayout(parent=self, prefix="ProgressbarBg", width="100%") self._fg_left = LUISprite(self, "ProgressbarFg_Left", "skin") self._fg_mid = LUISprite(self, "ProgressbarFg", "skin") self._fg_right = LUISprite(self, "ProgressbarFg_Right", "skin") self._fg_finish = LUISprite(self, "ProgressbarFg_Finish", "skin") self._show_label = show_label self._progress_pixel = 0 self._fg_finish.right = 0 if self._show_label: self._progress_label = LUILabel(parent=self, text=u"33 %") self._progress_label.centered = (True, True) self.set_value(value) self._update_progress() if parent is not None: self.parent = parent
class LUIProgressbar(LUIObject): def __init__(self, parent=None, width=200, value=50, show_label=True): LUIObject.__init__(self, x=0, y=0, w=width, h=0) self.bgLeft = LUISprite(self, "ProgressbarBg_Left", "skin") self.bgMid = LUISprite(self, "ProgressbarBg", "skin") self.bgRight = LUISprite(self, "ProgressbarBg_Right", "skin") self.bgMid.width = self.width - self.bgLeft.width - self.bgRight.width self.bgMid.left = self.bgLeft.width self.bgRight.left = self.bgMid.width + self.bgMid.left self.fgLeft = LUISprite(self, "ProgressbarFg_Left", "skin") self.fgMid = LUISprite(self, "ProgressbarFg", "skin") self.fgRight = LUISprite(self, "ProgressbarFg_Right", "skin") self.fgFinish = LUISprite(self, "ProgressbarFg_Finish", "skin") self.showLabel = show_label self.progressPixel = 0 self.fgFinish.right = 0 self.fit_to_children() if self.showLabel: self.progressLabel = LUILabel(parent=self, text=u"33 %", shadow=True) self.progressLabel.centered = (True, False) self.progressLabel.top = -1 self.set_value(value) self._update_progress() if parent is not None: self.parent = parent def set_value(self, val): val = max(0, min(100, val)) self.progressPixel = int(val / 100.0 * self.width) self._update_progress() def _update_progress(self): self.fgFinish.hide() if self.progressPixel <= self.fgLeft.width + self.fgRight.width: self.fgMid.hide() self.fgRight.left = self.fgLeft.width else: self.fgMid.show() self.fgMid.left = self.fgLeft.width self.fgMid.width = self.progressPixel - self.fgRight.width - self.fgLeft.width self.fgRight.left = self.fgMid.left + self.fgMid.width if self.progressPixel >= self.width - self.fgRight.width: self.fgFinish.show() self.fgFinish.right = -(self.width - self.progressPixel) self.fgFinish.clip_bounds = (0, self.width - self.progressPixel, 0, 0) if self.showLabel: percentage = self.progressPixel / self.width * 100.0 self.progressLabel.set_text(unicode(int(percentage)) + u" %")
class LUICheckbox(LUIObject): """ This is a simple checkbox, including a Label. The checkbox can either be checked or unchecked. """ def __init__(self, checked=False, label=u"Checkbox", **kwargs): """ Constructs a new checkbox with the given label and state. """ LUIObject.__init__(self, x=0, y=0, w=0, h=0, solid=True) LUIInitialState.init(self, kwargs) self.checkboxSprite = LUISprite(self, "Checkbox_Default", "skin") self.label = LUILabel(parent=self, text=label, shadow=True, left=self.checkboxSprite.width + 6) self.label.top = self.label.height - self.checkboxSprite.height self.label.bind("resized", self._on_label_resized) self.fit_to_children() self.checked = checked self._update_sprite() def _on_label_resized(self, event): """ Internal handler when the text of the label got changed """ self.fit_to_children() def on_click(self, event): """ Internal onclick handler. Do not override """ self.checked = not self.checked self.trigger_event("changed") self._update_sprite() def on_mousedown(self, event): """ Internal mousedown handler. Do not override """ self.checkboxSprite.color = (0.86,0.86,0.86,1.0) def on_mouseup(self, event): """ Internal on_mouseup handler. Do not override """ self.checkboxSprite.color = (1,1,1,1) def get_checked(self): """ Returns a boolean wheter the checkbox is currently checked """ return self.checked def toggle_checked(self): """ Toggles the checkbox state """ self.set_checked(not self.get_checked()) def set_checked(self, checked): """ Sets the checkbox state """ self.checked = checked self._update_sprite() def get_label(self): """ Returns a handle to the label, so it can be modified (e.g. change its text) """ return self.label def _update_sprite(self): """ Internal method to update the sprites """ img = "Checkbox_Checked" if self.checked else "Checkbox_Default" self.checkboxSprite.set_texture(img, "skin")
def __init__(self, parent=None, width=200, placeholder=u"Enter some text ..", value=u"", **kwargs): """ Constructs a new input field. An input field always needs a width specified """ LUIObject.__init__(self, x=0, y=0, solid=True) self.set_width(width) self._layout = LUIHorizontalStretchedLayout(parent=self, prefix="InputField", width="100%") # Container for the text self._text_content = LUIObject(self) self._text_content.margin = (5, 7, 5, 7) self._text_content.clip_bounds = (0, 0, 0, 0) self._text_content.set_size("100%", "100%") # Scroller for the text, so we can move right and left self._text_scroller = LUIObject(parent=self._text_content) self._text_scroller.center_vertical = True self._text = LUILabel(parent=self._text_scroller, text=u"") # Cursor for the current position self._cursor = LUISprite(self._text_scroller, "blank", "skin", x=0, y=0, w=2, h=15) self._cursor.color = (0.5, 0.5, 0.5) self._cursor.margin.top = 2 self._cursor.z_offset = 20 self._cursor_index = 0 self._cursor.hide() self._value = value # Placeholder text, shown when out of focus and no value exists self._placeholder = LUILabel(parent=self._text_content, text=placeholder, shadow=False, center_vertical=True, alpha=0.2) # Various states self._tickrate = 1.0 self._tickstart = 0.0 self._render_text() if parent is not None: self.parent = parent LUIInitialState.init(self, kwargs)
def __init__(self, parent=None, width=200, value=50, show_label=True): LUIObject.__init__(self, x=0, y=0, w=width, h=0) self.bgLeft = LUISprite(self, "ProgressbarBg_Left", "skin") self.bgMid = LUISprite(self, "ProgressbarBg", "skin") self.bgRight = LUISprite(self, "ProgressbarBg_Right", "skin") self.bgMid.width = self.width - self.bgLeft.width - self.bgRight.width self.bgMid.left = self.bgLeft.width self.bgRight.left = self.bgMid.width + self.bgMid.left self.fgLeft = LUISprite(self, "ProgressbarFg_Left", "skin") self.fgMid = LUISprite(self, "ProgressbarFg", "skin") self.fgRight = LUISprite(self, "ProgressbarFg_Right", "skin") self.fgFinish = LUISprite(self, "ProgressbarFg_Finish", "skin") self.showLabel = show_label self.progressPixel = 0 self.fgFinish.right = 0 self.fit_to_children() if self.showLabel: self.progressLabel = LUILabel(parent=self, text=u"33 %", shadow=True) self.progressLabel.centered = (True, False) self.progressLabel.top = -1 self.set_value(value) self._update_progress() if parent is not None: self.parent = parent
def __init__(self, parent=None, width=100.0, filled=False, min_value=0, max_value=1.0, precision=2, value=None): LUIObject.__init__(self, x=0, y=0, w=width, h=0) LUICallback.__init__(self) max_numbers_before = max(len(str(int(max_value))), len(str(int(min_value)))) number_space_required = max_numbers_before if precision > 0: number_space_required += 1 + precision pixels_per_number = 7 self.precision = precision self.slider = LUISlider(self, width=width - pixels_per_number * number_space_required - 5, filled=filled, min_value=min_value, max_value=max_value, value=value) self.label = LUILabel(parent=self, shadow=True, text=u"1.23") self.label.right = 0 self.label.top = self.label.height - self.slider.height self.label.color = (1,1,1,0.5) self.slider.add_change_callback(self._on_slider_changed) self.slider.add_change_callback(self._trigger_callback) self._on_slider_changed(self.slider, self.slider.get_value()) if parent is not None: self.parent = parent self.fit_to_children()
def __init__(self, parent=None, width=100.0, filled=False, min_value=0, max_value=1.0, precision=2, value=None): LUIObject.__init__(self, x=0, y=0, w=width, h=0) LUICallback.__init__(self) max_numbers_before = max(len(str(int(max_value))), len(str(int(min_value)))) number_space_required = max_numbers_before if precision > 0: number_space_required += 1 + precision pixels_per_number = 7 self.precision = precision self.slider = LUISlider( self, width=width - pixels_per_number * number_space_required - 5, filled=filled, min_value=min_value, max_value=max_value, value=value, ) self.label = LUILabel(parent=self, shadow=True, text=u"1.23") self.label.right = 0 self.label.top = self.label.height - self.slider.height self.label.color = (1, 1, 1, 0.5) self.slider.add_change_callback(self._on_slider_changed) self.slider.add_change_callback(self._trigger_callback) self._on_slider_changed(self.slider, self.slider.get_value()) if parent is not None: self.parent = parent self.fit_to_children()
def __init__(self, parent=None, group=None, value=None, active=False, label=u"Radiobox", **kwargs): """ Constructs a new radiobox. group should be a handle to a LUIRadioboxGroup. value will be the value returned by group.value, in case the box was selected. By default, the radiobox is not active. """ assert group is not None, "LUIRadiobox needs a LUIRadioboxGroup!" LUIObject.__init__(self, x=0, y=0, solid=True) self._sprite = LUISprite(self, "Radiobox_Default", "skin") self._label = LUILabel(parent=self, text=label, margin=(0, 0, 0, 23), center_vertical=True) self._value = value self._active = False self._hovered = False self._group = group self._group.register_box(self) if active: self.set_active() if parent: self.parent = parent LUIInitialState.init(self, kwargs)
def __init__(self, parent=None, key=u"A", instruction=u"Instruction"): LUIObject.__init__(self) self.marker = LUIKeyMarker(parent=self, key=key) self.instructionLabel = LUILabel(parent=self, text=instruction, shadow=True) self.instructionLabel.centered = (False, True) self.instructionLabel.margin.top = -4 self.set_key(key)
def __init__(self, parent=None, width=200, value=50, show_label=True): """ Constructs a new progress bar. If show_label is True, a label indicating the current progress is shown """ LUIObject.__init__(self) self.set_width(width) self._bg_layout = LUIHorizontalStretchedLayout( parent=self, prefix="ProgressbarBg", width="100%") self._fg_left = LUISprite(self, "ProgressbarFg_Left", "skin") self._fg_mid = LUISprite(self, "ProgressbarFg", "skin") self._fg_right = LUISprite(self, "ProgressbarFg_Right", "skin") self._fg_finish = LUISprite(self, "ProgressbarFg_Finish", "skin") self._show_label = show_label self._progress_pixel = 0 self._fg_finish.right = 0 if self._show_label: self._progress_label = LUILabel(parent=self, text=u"33 %") self._progress_label.centered = (True, True) self.set_value(value) self._update_progress() if parent is not None: self.parent = parent
def __init__(self, parent=None, key=u"A"): LUIObject.__init__(self) self.bgLeft = LUISprite(self, "Keymarker_Left", "skin") self.bgMid = LUISprite(self, "Keymarker", "skin") self.bgRight = LUISprite(self, "Keymarker_Right", "skin") self.label = LUILabel(parent=self, text=key, shadow=True) self.label.centered = (True, True) self.label.margin = (-3, 0, 0, -1) self.margin = (-1, 0, 0, -1) self.set_key(key) if parent is not None: self.parent = parent self.fit_to_children()
def add(self, header, frame): # header if isinstance(header, str): header = LUILabel(text = header) self.header_bar.add(header, "?") self.header_to_frame[header] = frame header.solid = True header.bind("click", self._change_to_tab) # Frame frame.parent = self.main_frame frame.width = "100%" frame.height = "100%" # Put frame in front if self.current_frame is None: self.current_frame = frame self.current_frame.show() else: frame.hide()
def add(self, header, frame): # header if isinstance(header, str): header = LUILabel(text=header) self.header_bar.add(header, "?") self.header_to_frame[header] = frame header.solid = True header.bind("click", self._change_to_tab) # Frame frame.parent = self.main_frame frame.width = "100%" frame.height = "100%" # Put frame in front if self.current_frame is None: self.current_frame = frame self.current_frame.show() else: frame.hide()
def __init__(self, parent=None, width=200, placeholder=u"Enter some text ..", value=u""): LUIObject.__init__(self, x=0, y=0, w=width, h=0) LUICallback.__init__(self) self.bgLeft = LUISprite(self, "InputField_Left", "skin") self.bgMid = LUISprite(self, "InputField", "skin") self.bgRight = LUISprite(self, "InputField_Right", "skin") self.textContent = LUIObject(self) self.textContent.margin = (5, 8, 5, 8) self.textContent.clip_bounds = (0, 0, 0, 0) self.textContent.height = self.bgMid.height - 10 self.textContent.width = self.width - 16 self.textScroller = LUIObject(parent=self.textContent, x=0, y=0) self.text = LUILabel(parent=self.textScroller, text=u"", shadow=True) self.cursor = LUISprite(self.textScroller, "blank", "skin", x=0, y=0, w=2, h=15.0) self.cursor.color = (0.5, 0.5, 0.5) self.cursor.margin_top = 3 self.cursor.z_offset = 20 self.cursor_index = 0 self.cursor.hide() self.value = value self.placeholder = LUILabel(parent=self.textContent, text=placeholder, shadow=False) self.placeholder.color = (1, 1, 1, 0.5) self.bgMid.width = self.width - self.bgLeft.width - self.bgRight.width self.bgMid.left = self.bgLeft.width self.bgRight.left = self.bgMid.width + self.bgMid.left if len(self.value) > 0: self.placeholder.hide() self.tickrate = 1.0 self.tickstart = 0.0 self.fit_to_children() self._render_text() if parent is not None: self.parent = parent
def add(self, *args, **kwargs): """ Appends a new text. The arguments are equal to the arguments of LUILabel. The arguments shouldn't contain information about the placement like top_left, or center_vertical, since the labels are placed at explicit positions. """ self._last_size = kwargs.get("font_size", 14) label = LUILabel(parent=self, left=self._cursor.x, top=self._cursor.y, *args, **kwargs) # This is a bit of a hack, we should use a horizontal layout, but we # don't for performance reasons. self._cursor.x += label.text_handle.width
def __init__(self, checked=False, label=u"Checkbox", **kwargs): """ Constructs a new checkbox with the given label and state. """ LUIObject.__init__(self, x=0, y=0, w=0, h=0, solid=True) LUIInitialState.init(self, kwargs) self.checkboxSprite = LUISprite(self, "Checkbox_Default", "skin") self.label = LUILabel(parent=self, text=label, shadow=True, left=self.checkboxSprite.width + 6) self.label.top = self.label.height - self.checkboxSprite.height self.label.bind("resized", self._on_label_resized) self.fit_to_children() self.checked = checked self._update_sprite()
def __init__(self, parent=None, width=200, placeholder=u"Enter some text ..", value=u"", **kwargs): """ Constructs a new input field. An input field always needs a width specified """ LUIObject.__init__(self, x=0, y=0, solid=True) self.set_width(width) self._layout = LUIHorizontalStretchedLayout(parent=self, prefix="InputField", width="100%") # Container for the text self._text_content = LUIObject(self) self._text_content.margin = (5, 7, 5, 7) self._text_content.clip_bounds = (0,0,0,0) self._text_content.set_size("100%", "100%") # Scroller for the text, so we can move right and left self._text_scroller = LUIObject(parent=self._text_content) self._text_scroller.center_vertical = True self._text = LUILabel(parent=self._text_scroller, text=u"") # Cursor for the current position self._cursor = LUISprite(self._text_scroller, "blank", "skin", x=0, y=0, w=2, h=15) self._cursor.color = (0.5, 0.5, 0.5) self._cursor.margin.top = 2 self._cursor.z_offset = 20 self._cursor_index = 0 self._cursor.hide() self._value = value # Placeholder text, shown when out of focus and no value exists self._placeholder = LUILabel(parent=self._text_content, text=placeholder, shadow=False, center_vertical=True, alpha=0.2) # Various states self._tickrate = 1.0 self._tickstart = 0.0 self._render_text() if parent is not None: self.parent = parent LUIInitialState.init(self, kwargs)
def _render_options(self, options): """ Internal method to update the options """ num_visible_options = min(30, len(options)) offset_top = 6 self._layout.height = num_visible_options * 30 + offset_top + 11 self._container.height = num_visible_options * 30 + offset_top + 1 self._container.remove_all_children() current_y = offset_top for opt_id, opt_val in options: opt_container = LUIObject(self._container, x=0, y=current_y, w=self._container.width - 30, h=30) opt_bg = LUISprite(opt_container, "blank", "skin") opt_bg.width = self._container.width opt_bg.height = opt_container.height opt_bg.color = (0, 0, 0, 0) opt_bg.bind("mouseover", self._on_opt_over) opt_bg.bind("mouseout", self._on_opt_out) opt_bg.bind("mousedown", lambda *args: self.request_focus()) opt_bg.bind("click", partial(self._on_opt_click, opt_id)) opt_bg.solid = True opt_label = LUILabel(parent=opt_container, text=opt_val.encode('utf-8')) opt_label.top = 8 opt_label.left = 8 if opt_id == self._selectbox.selected_option: opt_label.color = (0.6, 0.9, 0.4, 1.0) divider = LUISprite(opt_container, "SelectdropDivider", "skin") divider.top = 30 - divider.height / 2 divider.width = self._container.width current_y += 30
def __init__(self, checked=False, label=u"Checkbox", **kwargs): """ Constructs a new checkbox with the given label and state. By default, the checkbox is not checked. """ LUIObject.__init__(self, x=0, y=0, solid=True) self._checked = checked self._checkbox_sprite = LUISprite(self, "Checkbox_Default", "skin") self._label = LUILabel(parent=self, text=label, margin=(0, 0, 0, 25), center_vertical=True, alpha=0.4) self._hovered = False LUIInitialState.init(self, kwargs)
def add(self, *args, **kwargs): """ Appends a new text. The arguments are equal to the arguments of LUILabel. The arguments shouldn't contain information about the placement like top_left, or center_vertical. """ if "font_size" in kwargs: self._last_size = kwargs["font_size"] else: self._last_size = 14 label = LUILabel(parent=self, left=self._cursor.x, top=self._cursor.y, *args, **kwargs) # This is a bit of a hack, we should use a horizontal layout, but we don't # for performance reasons. self._cursor.x += label.text_handle.width
def __init__(self, parent=None, group=None, value=None, text=u"Radiobox"): LUIObject.__init__(self) LUICallback.__init__(self) self.radiobox = LUIRadiobox(parent=self, group=group, value=value) self.label = LUILabel(parent=self, text=text, shadow=True) self.label.bind("click", self.radiobox.on_click) self.label.bind("mousedown", self.radiobox.on_mousedown) self.label.bind("mouseup", self.radiobox.on_mouseup) self.radiobox.add_change_callback(self._trigger_callback) if parent is not None: self.parent = parent self.label.left = self.radiobox.width + 6 self.label.top = self.label.height - self.radiobox.height self.fit_to_children()
def __init__(self, group=None, value=None, active=False, label=u"Radiobox", **kwargs): LUIObject.__init__(self, x=0, y=0, w=0, h=0, solid=True) LUIInitialState.init(self, kwargs) self.sprite = LUISprite(self, "Radiobox_Default", "skin") self.label = LUILabel(parent=self, text=label, shadow=True, left=self.sprite.width+6) self.label.top = self.label.height - self.sprite.height self.label.bind("resized", self._on_label_resized) self.fit_to_children() self.group = group self.group.register_box(self) self.active = False self.value = value if active: self.set_active()
def __init__(self, width=200, options=None, selectedOption=None, **kwargs): LUIObject.__init__(self, x=0, y=0, w=width+4, h=0, solid=True) LUIInitialState.init(self, kwargs) LUICallback.__init__(self) # The selectbox has a small border, to correct this we move it self.margin_left = -2 self.bgLeft = LUISprite(self, "Selectbox_Left", "skin") self.bgMid = LUISprite(self, "Selectbox", "skin") self.bgRight = LUISprite(self, "Selectbox_Right", "skin") self.bgMid.width = self.width - self.bgLeft.width - self.bgRight.width self.bgMid.left = self.bgLeft.width self.bgRight.left = self.bgMid.width + self.bgMid.left self.bgRight.z_offset = 1 self.labelContainer = LUIObject(self, x=10, y=6, w=width - 20 - self.bgRight.width, h=self.bgMid.height - 6) self.labelContainer.clip_bounds = (0,0,0,0) self.label = LUILabel(parent=self.labelContainer, text=u"Select an option ..", shadow=True) self.bgRight.bind("mouseover", self._knob_mouseover) self.bgRight.bind("mouseout", self._knob_mouseout) self.bgRight.bind("click", self.on_click) self.bgRight.bind("click", self.on_click) self.fit_to_children() self.dropMenu = UISelectdrop(parent=self, width=width) self.dropMenu.top = self.bgMid.height - 7 self.dropMenu.topmost = True self.dropOpen = False self.dropMenu.hide() self.options = [] self.currentOptionId = None if options is not None: self.options = options self._select_option(selectedOption)
def __init__(self, text=u"Button", template="ButtonDefault", **kwargs): """ Constructs a new button. The template controls which sprites to use. If the template is "ButtonDefault" for example, the sprites "ButtonDefault_Left", "ButtonDefault" and "ButtonDefault_Right" will be used. The sprites used when the button is pressed should be named "ButtonDefaultFocus_Left" and so on then. If an explicit width is set on the button, the button will stick to that width, otherwise it will automatically resize to fit the label """ LUIObject.__init__(self, x=0, y=0, solid=True) self._template = template self._layout = LUIHorizontalStretchedLayout(parent=self, prefix=self._template, width="100%") self._label = LUILabel(parent=self, text=text) self._label.z_offset = 1 self._label.center_vertical = True self._label.margin = 0, 20, 0, 20 self.margin.left = -1 LUIInitialState.init(self, kwargs)
def __init__(self, width=200, options=None, selected_option=None, **kwargs): """ Constructs a new selectbox with a given width """ LUIObject.__init__(self, x=0, y=0, w=width + 4, solid=True) LUIInitialState.init(self, kwargs) # The selectbox has a small border, to correct this we move it self.margin.left = -2 self._bg_layout = LUIHorizontalStretchedLayout(parent=self, prefix="Selectbox", width="100%") self._label_container = LUIObject(self, x=10, y=0) self._label_container.set_size("100%", "100%") self._label_container.clip_bounds = (0, 0, 0, 0) self._label = LUILabel(parent=self._label_container, text=u"Select an option ..") self._label.center_vertical = True self._drop_menu = LUISelectdrop(parent=self, width=width) self._drop_menu.top = self._bg_layout._sprite_right.height - 7 self._drop_menu.topmost = True self._drop_open = False self._drop_menu.hide() self._options = [] self._current_option_id = None if options is not None: self._options = options self._select_option(selected_option)
f = DemoFramework() f.prepare_demo("LUILabel") # Constructor f.add_constructor_parameter("text", "u'Label'") f.add_constructor_parameter("shadow", "True") f.add_constructor_parameter("font_size", "14") f.add_constructor_parameter("font", "'label'") # Functions f.add_public_function("get_text", [], "string") f.add_public_function("set_text", [("text", "string")]) f.add_property("text", "string") f.add_property("text_handle", "LUIText") # Events f.construct_sourcecode("LUILabel") # Create a new label label = LUILabel(parent=f.get_widget_node(), text="This is a fancy label") f.set_actions({ "Set Random Text": lambda: label.set_text(unicode(random.randint(100, 10000))), "Set Random Color": lambda: label.set_color(random.random(), random.random(), random.random(), 1) }) run()
class LUISelectbox(LUIObject, LUICallback): def __init__(self, width=200, options=None, selectedOption=None, **kwargs): LUIObject.__init__(self, x=0, y=0, w=width+4, h=0, solid=True) LUIInitialState.init(self, kwargs) LUICallback.__init__(self) # The selectbox has a small border, to correct this we move it self.margin_left = -2 self.bgLeft = LUISprite(self, "Selectbox_Left", "skin") self.bgMid = LUISprite(self, "Selectbox", "skin") self.bgRight = LUISprite(self, "Selectbox_Right", "skin") self.bgMid.width = self.width - self.bgLeft.width - self.bgRight.width self.bgMid.left = self.bgLeft.width self.bgRight.left = self.bgMid.width + self.bgMid.left self.bgRight.z_offset = 1 self.labelContainer = LUIObject(self, x=10, y=6, w=width - 20 - self.bgRight.width, h=self.bgMid.height - 6) self.labelContainer.clip_bounds = (0,0,0,0) self.label = LUILabel(parent=self.labelContainer, text=u"Select an option ..", shadow=True) self.bgRight.bind("mouseover", self._knob_mouseover) self.bgRight.bind("mouseout", self._knob_mouseout) self.bgRight.bind("click", self.on_click) self.bgRight.bind("click", self.on_click) self.fit_to_children() self.dropMenu = UISelectdrop(parent=self, width=width) self.dropMenu.top = self.bgMid.height - 7 self.dropMenu.topmost = True self.dropOpen = False self.dropMenu.hide() self.options = [] self.currentOptionId = None if options is not None: self.options = options self._select_option(selectedOption) def get_selected_option(self): return self.currentOptionId def _render_options(self): self.dropMenu._render_options(self.options) def set_options(self, options): self.options = options self.currentOptionId = None self._render_options() def _select_option(self, optid): self.label.color = (1,1,1,1) for optID, optVal in self.options: if optID == optid: self.label.set_text(optVal) self.currentOptionId = optID return self.label.color = (1,1,1,0.5) def _knob_mouseover(self, event): self.bgRight.color = (0.9,0.9,0.9,1.0) def _knob_mouseout(self, event): self.bgRight.color = (1,1,1,1.0) def on_click(self, event): self.request_focus() if self.dropOpen: self._close_drop() else: self._open_drop() def on_mousedown(self, event): self.bgLeft.color = (0.9,0.9,0.9,1.0) self.bgMid.color = (0.9,0.9,0.9,1.0) def on_mouseup(self, event): self.bgLeft.color = (1,1,1,1.0) self.bgMid.color = (1,1,1,1.0) def _open_drop(self): if not self.dropOpen: self._render_options() self.dropMenu.show() self.request_focus() self.dropOpen = True def _close_drop(self): if self.dropOpen: self.dropMenu.hide() self.dropOpen = False def _on_option_selected(self, optid): self._select_option(optid) self._close_drop() def on_blur(self, event): self._close_drop()
class LUIInputField(LUIObject): """ Simple input field, accepting text input. This input field supports entering text and navigating. Selecting text is (currently) not supported. The input field also supports various keyboard shortcuts: [pos1] Move to the beginning of the text [end] Move to the end of the text [arrow_left] Move one character to the left [arrow_right] Move one character to the right [ctrl] + [arrow_left] Move to the left, skipping over words [ctrl] + [arrow_right] Move to the right, skipping over words [escape] Un-focus input element """ re_skip = re.compile("\W*\w+\W") def __init__(self, parent=None, width=200, placeholder=u"Enter some text ..", value=u"", **kwargs): """ Constructs a new input field. An input field always needs a width specified """ LUIObject.__init__(self, x=0, y=0, solid=True) self.set_width(width) self._layout = LUIHorizontalStretchedLayout(parent=self, prefix="InputField", width="100%") # Container for the text self._text_content = LUIObject(self) self._text_content.margin = (5, 7, 5, 7) self._text_content.clip_bounds = (0,0,0,0) self._text_content.set_size("100%", "100%") # Scroller for the text, so we can move right and left self._text_scroller = LUIObject(parent=self._text_content) self._text_scroller.center_vertical = True self._text = LUILabel(parent=self._text_scroller, text=u"") # Cursor for the current position self._cursor = LUISprite(self._text_scroller, "blank", "skin", x=0, y=0, w=2, h=15) self._cursor.color = (0.5, 0.5, 0.5) self._cursor.margin.top = 2 self._cursor.z_offset = 20 self._cursor_index = 0 self._cursor.hide() self._value = value # Placeholder text, shown when out of focus and no value exists self._placeholder = LUILabel(parent=self._text_content, text=placeholder, shadow=False, center_vertical=True, alpha=0.2) # Various states self._tickrate = 1.0 self._tickstart = 0.0 self._render_text() if parent is not None: self.parent = parent LUIInitialState.init(self, kwargs) @property def value(self): """ Returns the value of the input field """ return self._value @value.setter def value(self, new_value): """ Sets the value of the input field """ self._value = unicode(new_value) self._render_text() self.trigger_event("changed", self._value) def clear(self): """ Clears the input value """ self.value = u"" @property def cursor_pos(self): """ Set the cursor position """ return self._cursor_index @cursor_pos.setter def cursor_pos(self, pos): """ Set the cursor position """ if pos >= 0: self._cursor_index = max(0, min(len(self._value), pos)) else: self._cursor_index = max(len(self._value) + pos + 1, 0) self._reset_cursor_tick() self._render_text() def on_tick(self, event): """ Tick handler, gets executed every frame """ frame_time = globalClock.get_frame_time() - self._tickstart show_cursor = frame_time % self._tickrate < 0.5 * self._tickrate if show_cursor: self._cursor.color = (0.5, 0.5, 0.5, 1) else: self._cursor.color = (1, 1, 1, 0) def on_click(self, event): """ Internal on click handler """ self.request_focus() def on_mousedown(self, event): """ Internal mousedown handler """ local_x_offset = self._text.text_handle.get_relative_pos(event.coordinates).x self.cursor_pos = self._text.text_handle.get_char_index(local_x_offset) def _reset_cursor_tick(self): """ Internal method to reset the cursor tick """ self._tickstart = globalClock.get_frame_time() def on_focus(self, event): """ Internal focus handler """ self._cursor.show() self._placeholder.hide() self._reset_cursor_tick() self._layout.color = (0.9, 0.9, 0.9, 1) def on_keydown(self, event): """ Internal keydown handler. Processes the special keys, and if none are present, redirects the event """ key_name = event.message if key_name == "backspace": self._value = self._value[:max(0, self._cursor_index - 1)] + self._value[self._cursor_index:] self.cursor_pos -= 1 self.trigger_event("changed", self._value) elif key_name == "delete": post_value = self._value[min(len(self._value), self._cursor_index + 1):] self._value = self._value[:self._cursor_index] + post_value self.cursor_pos = self._cursor_index self.trigger_event("changed", self._value) elif key_name == "arrow_left": if event.get_modifier_state("alt") or event.get_modifier_state("ctrl"): self.cursor_skip_left() else: self.cursor_pos -= 1 elif key_name == "arrow_right": if event.get_modifier_state("alt") or event.get_modifier_state("ctrl"): self.cursor_skip_right() else: self.cursor_pos += 1 elif key_name == "escape": self.blur() elif key_name == "home": self.cursor_pos = 0 elif key_name == "end": self.cursor_pos = len(self.value) self.trigger_event(key_name, self._value) def on_keyrepeat(self, event): """ Internal keyrepeat handler """ self.on_keydown(event) def on_textinput(self, event): """ Internal textinput handler """ self._value = self._value[:self._cursor_index] + event.message + \ self._value[self._cursor_index:] self.cursor_pos = self._cursor_index + len(event.message) self.trigger_event("changed", self._value) def on_blur(self, event): """ Internal blur handler """ self._cursor.hide() if len(self._value) < 1: self._placeholder.show() self._layout.color = (1, 1, 1, 1) def _render_text(self): """ Internal method to render the text """ self._text.set_text(self._value) self._cursor.left = self._text.left + \ self._text.text_handle.get_char_pos(self._cursor_index) + 1 max_left = self.width - 15 if self._value: self._placeholder.hide() else: if not self.focused: self._placeholder.show() # Scroll if the cursor is outside of the clip bounds rel_pos = self.get_relative_pos(self._cursor.get_abs_pos()).x if rel_pos >= max_left: self._text_scroller.left = min(0, max_left - self._cursor.left) if rel_pos <= 0: self._text_scroller.left = min(0, - self._cursor.left - rel_pos) def cursor_skip_left(self): """ Moves the cursor to the left, skipping the previous word """ left_hand_str = ''.join(reversed(self.value[0:self.cursor_pos])) match = self.re_skip.match(left_hand_str) if match is not None: self.cursor_pos -= match.end() - 1 else: self.cursor_pos = 0 def cursor_skip_right(self): """ Moves the cursor to the right, skipping the next word """ right_hand_str = self.value[self.cursor_pos:] match = self.re_skip.match(right_hand_str) if match is not None: self.cursor_pos += match.end() - 1 else: self.cursor_pos = len(self.value)
class LUIInputField(LUIObject, LUICallback): def __init__(self, parent=None, width=200, placeholder=u"Enter some text ..", value=u""): LUIObject.__init__(self, x=0, y=0, w=width, h=0) LUICallback.__init__(self) self.bgLeft = LUISprite(self, "InputField_Left", "skin") self.bgMid = LUISprite(self, "InputField", "skin") self.bgRight = LUISprite(self, "InputField_Right", "skin") self.textContent = LUIObject(self) self.textContent.margin = (5, 8, 5, 8) self.textContent.clip_bounds = (0, 0, 0, 0) self.textContent.height = self.bgMid.height - 10 self.textContent.width = self.width - 16 self.textScroller = LUIObject(parent=self.textContent, x=0, y=0) self.text = LUILabel(parent=self.textScroller, text=u"", shadow=True) self.cursor = LUISprite(self.textScroller, "blank", "skin", x=0, y=0, w=2, h=15.0) self.cursor.color = (0.5, 0.5, 0.5) self.cursor.margin_top = 3 self.cursor.z_offset = 20 self.cursor_index = 0 self.cursor.hide() self.value = value self.placeholder = LUILabel(parent=self.textContent, text=placeholder, shadow=False) self.placeholder.color = (1, 1, 1, 0.5) self.bgMid.width = self.width - self.bgLeft.width - self.bgRight.width self.bgMid.left = self.bgLeft.width self.bgRight.left = self.bgMid.width + self.bgMid.left if len(self.value) > 0: self.placeholder.hide() self.tickrate = 1.0 self.tickstart = 0.0 self.fit_to_children() self._render_text() if parent is not None: self.parent = parent def _set_cursor_pos(self, pos): self.cursor_index = max(0, min(len(self.value), pos)) self._reset_cursor_tick() def on_tick(self, event): frametime = globalClock.getFrameTime() - self.tickstart show_cursor = frametime % self.tickrate < 0.5 * self.tickrate if show_cursor: self.cursor.color = (0.5, 0.5, 0.5, 1) else: self.cursor.color = (1, 1, 1, 0) def _add_text(self, text): self.value = self.value[: self.cursor_index] + text + self.value[self.cursor_index :] self._set_cursor_pos(self.cursor_index + len(text)) self._render_text() def on_click(self, event): self.request_focus() def on_mousedown(self, event): local_x_offset = self.text.text.get_relative_pos(event.coordinates).x self._set_cursor_pos(self.text.text.get_char_index(local_x_offset)) self._render_text() def _reset_cursor_tick(self): self.tickstart = globalClock.getFrameTime() def on_focus(self, event): self.cursor.show() self.placeholder.hide() self._reset_cursor_tick() self.bgLeft.color = (0.9, 0.9, 0.9, 1) self.bgMid.color = (0.9, 0.9, 0.9, 1) self.bgRight.color = (0.9, 0.9, 0.9, 1) def on_keydown(self, event): key_name = event.get_message() if key_name == "backspace": self.value = self.value[: max(0, self.cursor_index - 1)] + self.value[self.cursor_index :] self._set_cursor_pos(self.cursor_index - 1) self._trigger_callback(self.value) self._render_text() elif key_name == "delete": self.value = self.value[: self.cursor_index] + self.value[min(len(self.value), self.cursor_index + 1) :] self._set_cursor_pos(self.cursor_index) self._trigger_callback(self.value) self._render_text() elif key_name == "arrow_left": self._set_cursor_pos(self.cursor_index - 1) self._render_text() elif key_name == "arrow_right": self._set_cursor_pos(self.cursor_index + 1) self._render_text() def on_keyrepeat(self, event): self.on_keydown(event) def on_textinput(self, event): self._add_text(event.get_message()) self._trigger_callback(self.value) def on_blur(self, event): self.cursor.hide() if len(self.value) < 1: self.placeholder.show() self.bgLeft.color = (1, 1, 1, 1) self.bgMid.color = (1, 1, 1, 1) self.bgRight.color = (1, 1, 1, 1) def get_value(self): return self.value def set_value(self, value): self.value = value # QUESTION: Should we trigger a callback when the user changes the value hisself? self._trigger_callback(self.value) self._render_text() def _render_text(self): self.text.set_text(self.value) self.cursor.left = self.text.left + self.text.text.get_char_pos(self.cursor_index) + 1 max_left = self.width - 20 # Scroll if the cursor is outside of the clip bounds relX = self.get_relative_pos(self.cursor.get_abs_pos()).x if relX >= max_left: self.textScroller.left = min(0, max_left - self.cursor.left) if relX <= 0: self.textScroller.left = min(0, -self.cursor.left - relX)
class LUIProgressbar(LUIObject): """ A simple progress bar """ def __init__(self, parent=None, width=200, value=50, show_label=True): """ Constructs a new progress bar. If show_label is True, a label indicating the current progress is shown """ LUIObject.__init__(self) self.set_width(width) self._bg_layout = LUIHorizontalStretchedLayout( parent=self, prefix="ProgressbarBg", width="100%") self._fg_left = LUISprite(self, "ProgressbarFg_Left", "skin") self._fg_mid = LUISprite(self, "ProgressbarFg", "skin") self._fg_right = LUISprite(self, "ProgressbarFg_Right", "skin") self._fg_finish = LUISprite(self, "ProgressbarFg_Finish", "skin") self._show_label = show_label self._progress_pixel = 0 self._fg_finish.right = 0 if self._show_label: self._progress_label = LUILabel(parent=self, text=u"33 %") self._progress_label.centered = (True, True) self.set_value(value) self._update_progress() if parent is not None: self.parent = parent def get_value(self): """ Returns the current value of the progress bar """ return (self._progress_pixel / self.width * 100.0) def set_value(self, val): """ Sets the value of the progress bar """ val = max(0, min(100, val)) self._progress_pixel = int(val / 100.0 * self.width) self._update_progress() value = property(get_value, set_value) def _update_progress(self): """ Internal method to update the progressbar """ self._fg_finish.hide() if self._progress_pixel <= self._fg_left.width + self._fg_right.width: self._fg_mid.hide() self._fg_right.left = self._fg_left.width else: self._fg_mid.show() self._fg_mid.left = self._fg_left.width self._fg_mid.width = self._progress_pixel - self._fg_right.width - self._fg_left.width self._fg_right.left = self._fg_mid.left + self._fg_mid.width if self._progress_pixel >= self.width - self._fg_right.width: self._fg_finish.show() self._fg_finish.right = - (self.width - self._progress_pixel) self._fg_finish.clip_bounds = (0, self.width - self._progress_pixel, 0, 0) if self._show_label: percentage = self._progress_pixel / self.width * 100.0 self._progress_label.set_text(unicode(int(percentage)) + u" %")
f.add_constructor_parameter("show_label", "False") # Functions f.add_public_function("get_value", [], "float") f.add_public_function("set_value", [("value", "float")]) f.add_property("value", "float") # Events f.construct_sourcecode("LUIProgressbar") # Create the checkbox layout = LUIVerticalLayout(parent=f.get_widget_node(), spacing=10) LUILabel(parent=layout.cell(), text="This is a progressbar:", color=(1, 1, 1, 0.4)) bar = LUIProgressbar(parent=layout.cell(), width=200.0) LUILabel(parent=layout.cell(), text="You can control it with this slider:", color=(1, 1, 1, 0.4)) slider = LUISlider(parent=layout.cell(), width=200.0, filled=True) slider.bind("changed", lambda event: bar.set_value(slider.value * 100.0)) f.set_actions({ "Set to 30%": lambda: bar.set_value(30), }) run()
def __init__(self, parent=None): LUIPopup.__init__(self, parent=parent, width=240, height=146) LUICallback.__init__(self) self.field = LUIObject(self.content, x=0, y=0, w=128, h=128) self.fieldBG = LUISprite(self.field, "blank", "skin") self.fieldBG.size = (128, 128) self.fieldBG.color = (0.2, 0.6, 1.0) self.fieldFG = LUISprite(self.field, "ColorpickerFieldOverlay", "skin") self.fieldFG.pos = (-2, 0) self.fieldBG.bind("mousedown", self._start_field_dragging) self.fieldBG.bind("mouseup", self._stop_field_dragging) self.fieldHandle = LUISprite(self.field, "ColorpickerFieldHandle", "skin") self.fieldHandle.bind("mousedown", self._start_field_dragging) self.fieldHandle.bind("mouseup", self._stop_field_dragging) self.fieldDragging = False self.hueSlider = LUIObject(self.content, x=140, y=0, w=40, h=128) self.hueSliderFG = LUISprite(self.hueSlider, "ColorpickerHueSlider", "skin") self.hueHandle = LUISprite(self.hueSlider, "ColorpickerHueHandle", "skin") self.hueHandle.left = (self.hueSliderFG.width - self.hueHandle.width) / 2.0 self.hueHandle.top = 50 self.hueDragging = False self.hueSlider.bind("mousedown", self._start_hue_dragging) self.hueSlider.bind("mouseup", self._stop_hue_dragging) self.labels = LUIVerticalLayout(self.content, width=40) self.labels.pos = (177, 42) colors = [u"R", u"G", u"B"] self.colorLabels = [] for color in colors: label = LUILabel(text=color, shadow=True) label.color = (1, 1, 1, 0.3) valueLabel = LUILabel(text=u"255", shadow=True) valueLabel.right = 0 self.labels.add(label, valueLabel) self.colorLabels.append(valueLabel) self.activeColor = LUIObject(self.content, x=177, y=0) self.activeColorBG = LUISprite(self.activeColor, "blank", "skin") self.activeColorFG = LUISprite(self.activeColor, "ColorpickerActiveColorOverlay", "skin") self.activeColorBG.size = (40, 40) self.activeColorBG.pos = (2, 0) self.activeColorBG.color = (0.2, 0.6, 1.0, 1.0) self.closeButton = LUIButton(parent=self.content, text=u"Done", width=45, template="ButtonGreen") self.closeButton.left = 177 self.closeButton.top = 98 self.closeButton.bind("click", self._close_popup) self._set_hue(0.5) self._set_sat_val(0.5, 0.5) self.widget = parent
skin = LUIMetroSkin() base.win.set_clear_color(Vec4(1)) else: skin = LUIDefaultSkin() base.win.set_clear_color(Vec4(0.1, 0.0, 0.0, 1)) skin.load() # Initialize LUI region = LUIRegion.make("LUI", base.win) handler = LUIInputHandler() base.mouseWatcher.attach_new_node(handler) region.set_input_handler(handler) # Title title_label = LUILabel(parent=region.root, text="LUI Console Example", font_size=40, font="header", pos=(25, 17)) # Container container = LUIFrame(parent = region.root, width=700, height=500, style=LUIFrame.FS_sunken, margin=30, top=50) text_container = LUIScrollableRegion(parent=container, width=675, height=440, padding=0) base.win.set_clear_color(Vec4(0.1, 0.1, 0.1, 1.0)) layout = LUIVerticalLayout(parent=text_container.content_node) def send_command(event): """ Called when the user presses enter in the input field, submits the command and prints something on the console """ label = LUIFormattedLabel()
# Constructor f.add_constructor_parameter("filled", "False") f.add_constructor_parameter("min_value", "0.0") f.add_constructor_parameter("max_value", "0.0") f.add_constructor_parameter("value", "None") # Functions f.add_public_function("get_value", [], "float") f.add_public_function("set_value", [("value", "float")]) f.add_property("value", "float") # Events f.add_event("changed") f.construct_sourcecode("LUISlider") # Create the checkbox layout = LUIVerticalLayout(parent=f.get_widget_node(), spacing=10) LUILabel(parent=layout.cell(), text="This is a filled slider:", color=(1, 1, 1, 0.4)) slider = LUISlider(parent=layout.cell(), width=200.0) LUILabel(parent=layout.cell(), text="This is a regular slider:", color=(1, 1, 1, 0.4)) slider_nofill = LUISlider(parent=layout.cell(), width=200.0, filled=False) f.set_actions({ "Set to 30%": lambda: slider.set_value(0.3), }) run()
def add_event(self, event_name): label = LUILabel(text=event_name) label.color = (1, 1, 1, 0.5) self._events_layout.add(label) self.update_layouts()
# label_tl = LUILabel(parent=container, text="Top Left", top_left=(0,0)) # label_tr = LUILabel(parent=container, text="Top Right", top_right=(0,0)) # label_bl = LUILabel(parent=container, text="Bottom Left", bottom_left=(0,0)) # label_br = LUILabel(parent=container, text="Bottom Right", bottom_right=(0,0)) # button = LUIButton(parent=container, top_left=(0, 0), text="Well this one .. is a long button! (A really long one!) ............ really long!") # button.bind("click", lambda event: button.set_text("Hello!")) container.size = 300, 300 # group = LUIRadioboxGroup() # box = LUIRadiobox(parent=container, group=group, top=50) # box2 = LUICheckbox(parent=container, top=100) layout = LUIVerticalLayout(parent=container) # layout.height = 280 # layout.width = 300 LUILabel(parent=layout.cell(), text="Hello") LUILabel(parent=layout.cell(), text="World") LUILabel(parent=layout.cell(100), text="100px row") LUILabel(parent=layout.cell(), text="Next") LUIButton(parent=layout.cell(), text="SomeButton") LUILabel(parent=layout.cell('*'), text="Fill column") LUILabel(parent=layout.cell(), text="Last column") for i in range(5): base.graphicsEngine.render_frame() region.root.ls() s.run()
# Constructor f.add_constructor_parameter("width", "200") f.add_constructor_parameter("height", "200") f.add_constructor_parameter("innerPadding", "5") f.add_constructor_parameter("scrollable", "False") f.add_constructor_parameter("style", "UIFrame.Raised") # Functions # Events f.construct_sourcecode("LUIFrame") # Construct a new frame frame = LUIFrame(parent=f.get_widget_node()) layout = LUIVerticalLayout(parent=frame, spacing=5) layout.add(LUILabel(text="This is some frame ..", color=(0.2, 0.6, 1.0, 1.0), font_size=20)) layout.add(LUILabel(text="It can contain arbitrary elements.")) layout.add(LUILabel(text="For example this button:")) layout.add(LUIButton(text="Fancy button")) # frame.fit_to_children() f.set_actions({ "Resize to 300x160": lambda: frame.set_size(300, 160), "Fit to children": lambda: frame.clear_size(), }) run()
def add_event(self, event_name): label = LUILabel(text=event_name) label.color = (1,1,1,0.5) self.eventsLayout.add_row(label) self.update_layouts()
from DemoFramework import DemoFramework from LUILabel import LUILabel import random f = DemoFramework() f.prepare_demo("LUILabel") # Constructor f.add_constructor_parameter("text", "u'Label'") f.add_constructor_parameter("shadow", "True") f.add_constructor_parameter("font_size", "14") f.add_constructor_parameter("font", "'label'") # Functions f.add_public_function("get_text", [], "string") f.add_public_function("set_text", [("text", "string")]) # Events f.construct_sourcecode("LUILabel") # Create a new label label = LUILabel(parent=f.get_widget_node(), text="This is a fancy label") f.set_actions({ "Set Random Text": lambda: label.set_text(unicode(random.randint(100, 10000))), }) run()
def __init__(self, parent=None): LUIPopup.__init__(self, parent=parent, width=240, height=146) LUICallback.__init__(self) self.field = LUIObject(self.content, x=0, y=0, w=128, h=128) self.fieldBG = LUISprite(self.field, "blank", "skin") self.fieldBG.size = (128, 128) self.fieldBG.color = (0.2, 0.6, 1.0) self.fieldFG = LUISprite(self.field, "ColorpickerFieldOverlay", "skin") self.fieldFG.pos = (-2, 0) self.fieldBG.bind("mousedown", self._start_field_dragging) self.fieldBG.bind("mouseup", self._stop_field_dragging) self.fieldHandle = LUISprite(self.field, "ColorpickerFieldHandle", "skin") self.fieldHandle.bind("mousedown", self._start_field_dragging) self.fieldHandle.bind("mouseup", self._stop_field_dragging) self.fieldDragging = False self.hueSlider = LUIObject(self.content, x=140, y=0, w=40, h=128) self.hueSliderFG = LUISprite(self.hueSlider, "ColorpickerHueSlider", "skin") self.hueHandle = LUISprite(self.hueSlider, "ColorpickerHueHandle", "skin") self.hueHandle.left = (self.hueSliderFG.width - self.hueHandle.width) / 2.0 self.hueHandle.top = 50 self.hueDragging = False self.hueSlider.bind("mousedown", self._start_hue_dragging) self.hueSlider.bind("mouseup", self._stop_hue_dragging) self.labels = LUIVerticalLayout(self.content, width=40) self.labels.pos = (177, 42) colors = [u"R", u"G", u"B"] self.colorLabels = [] for color in colors: label = LUILabel(text=color, shadow=True) label.color = (1, 1, 1, 0.3) valueLabel = LUILabel(text=u"255", shadow=True) valueLabel.right = 0 self.labels.add_row(label, valueLabel) self.colorLabels.append(valueLabel) self.activeColor = LUIObject(self.content, x=177, y=0) self.activeColorBG = LUISprite(self.activeColor, "blank", "skin") self.activeColorFG = LUISprite(self.activeColor, "ColorpickerActiveColorOverlay", "skin") self.activeColorBG.size = (40, 40) self.activeColorBG.pos = (2, 0) self.activeColorBG.color = (0.2, 0.6, 1.0, 1.0) self.closeButton = LUIButton(parent=self.content, text=u"Done", width=45, template="ButtonMagic") self.closeButton.left = 177 self.closeButton.top = 98 self.closeButton.bind("click", self._close_popup) self._set_hue(0.5) self._set_sat_val(0.5, 0.5) self.widget = parent
class LUIInputField(LUIObject): """ Simple input field """ def __init__(self, parent=None, width=200, placeholder=u"Enter some text ..", value=u"", **kwargs): """ Constructs a new input field. An input field always needs a width specified """ LUIObject.__init__(self, x=0, y=0, solid=True) self.set_width(width) self._layout = LUIHorizontalStretchedLayout(parent=self, prefix="InputField", width="100%") # Container for the text self._text_content = LUIObject(self) self._text_content.margin = (5, 7, 5, 7) self._text_content.clip_bounds = (0,0,0,0) self._text_content.set_size("100%", "100%") # Scroller for the text, so we can move right and left self._text_scroller = LUIObject(parent=self._text_content) self._text_scroller.center_vertical = True self._text = LUILabel(parent=self._text_scroller, text=u"") # Cursor for the current position self._cursor = LUISprite(self._text_scroller, "blank", "skin", x=0, y=0, w=2, h=15) self._cursor.color = (0.5, 0.5, 0.5) self._cursor.margin.top = 2 self._cursor.z_offset = 20 self._cursor_index = 0 self._cursor.hide() self._value = value # Placeholder text, shown when out of focus and no value exists self._placeholder = LUILabel(parent=self._text_content, text=placeholder, shadow=False, center_vertical=True, alpha=0.2) # Various states self._tickrate = 1.0 self._tickstart = 0.0 self._render_text() if parent is not None: self.parent = parent LUIInitialState.init(self, kwargs) def get_value(self): """ Returns the value of the input field """ return self._value def set_value(self, value): """ Sets the value of the input field """ self._value = unicode(value) self.trigger_event("changed", self._value) self._render_text() value = property(get_value, set_value) def clear(self): """ Clears the input value """ self.value = u"" def _set_cursor_pos(self, pos): """ Internal method to set the cursor position """ self._cursor_index = max(0, min(len(self._value), pos)) self._reset_cursor_tick() def on_tick(self, event): """ Tick handler, gets executed every frame """ frametime = globalClock.get_frame_time() - self._tickstart show_cursor = frametime % self._tickrate < 0.5 * self._tickrate if show_cursor: self._cursor.color = (0.5,0.5,0.5,1) else: self._cursor.color = (1,1,1,0) def _add_text(self, text): """ Internal method to append text """ self._value = self._value[:self._cursor_index] + text + self._value[self._cursor_index:] self._set_cursor_pos(self._cursor_index + len(text)) self._render_text() def on_click(self, event): """ Internal on click handler """ self.request_focus() def on_mousedown(self, event): """ Internal mousedown handler """ local_x_offset = self._text.text_handle.get_relative_pos(event.coordinates).x self._set_cursor_pos(self._text.text_handle.get_char_index(local_x_offset)) self._render_text() def _reset_cursor_tick(self): """ Internal method to reset the cursor tick """ self._tickstart = globalClock.getFrameTime() def on_focus(self, event): """ Internal focus handler """ self._cursor.show() self._placeholder.hide() self._reset_cursor_tick() self._layout.color = (0.9,0.9,0.9,1) def on_keydown(self, event): """ Internal keydown handler """ key_name = event.message if key_name == "backspace": self._value = self._value[:max(0, self._cursor_index - 1)] + self._value[self._cursor_index:] self._set_cursor_pos(self._cursor_index - 1) self.trigger_event("changed", self._value) self._render_text() elif key_name == "delete": self._value = self._value[:self._cursor_index] + self._value[min(len(self._value), self._cursor_index + 1):] self._set_cursor_pos(self._cursor_index) self.trigger_event("changed", self._value) self._render_text() elif key_name == "arrow_left": self._set_cursor_pos(self._cursor_index - 1) self._render_text() elif key_name == "arrow_right": self._set_cursor_pos(self._cursor_index + 1) self._render_text() self.trigger_event(key_name, self._value) def on_keyrepeat(self, event): """ Internal keyrepeat handler """ self.on_keydown(event) def on_textinput(self, event): """ Internal textinput handler """ self._add_text(event.message) self.trigger_event("changed", self._value) def on_blur(self, event): """ Internal blur handler """ self._cursor.hide() if len(self._value) < 1: self._placeholder.show() self._layout.color = (1,1,1,1) def _render_text(self): """ Internal method to render the text """ self._text.set_text(self._value) self._cursor.left = self._text.left + self._text.text_handle.get_char_pos(self._cursor_index) + 1 max_left = self.width - 15 if self._value: self._placeholder.hide() else: if not self.focused: self._placeholder.show() # Scroll if the cursor is outside of the clip bounds rel_pos = self.get_relative_pos(self._cursor.get_abs_pos()).x if rel_pos >= max_left: self._text_scroller.left = min(0, max_left - self._cursor.left) if rel_pos <= 0: self._text_scroller.left = min(0, - self._cursor.left - rel_pos)
# Constructor f.add_constructor_parameter("text", "Label") f.add_constructor_parameter("shadow", "True") f.add_constructor_parameter("font_size", "14") f.add_constructor_parameter("font", "'label'") # Functions f.add_public_function("get_text", [], "string") f.add_public_function("set_text", [("text", "string")]) f.add_property("text", "string") f.add_property("text_handle", "LUIText") # Events f.construct_sourcecode("LUILabel") # Create a new label label = LUILabel(parent=f.get_widget_node(), text="This is a fancy label") f.set_actions({ "Set Random Text": lambda: label.set_text(str(random.randint(100, 10000))), "Set Random Color": lambda: label.set_color(random.random(), random.random(), random.random(), 1) }) run()
class LUIInputField(LUIObject): """ Simple input field, accepting text input. This input field supports entering text and navigating. Selecting text is (currently) not supported. The input field also supports various keyboard shortcuts: [pos1] Move to the beginning of the text [end] Move to the end of the text [arrow_left] Move one character to the left [arrow_right] Move one character to the right [ctrl] + [arrow_left] Move to the left, skipping over words [ctrl] + [arrow_right] Move to the right, skipping over words [escape] Un-focus input element """ re_skip = re.compile("\W*\w+\W") def __init__(self, parent=None, width=200, placeholder=u"Enter some text ..", value=u"", **kwargs): """ Constructs a new input field. An input field always needs a width specified """ LUIObject.__init__(self, x=0, y=0, solid=True) self.set_width(width) self._layout = LUIHorizontalStretchedLayout(parent=self, prefix="InputField", width="100%") # Container for the text self._text_content = LUIObject(self) self._text_content.margin = (5, 7, 5, 7) self._text_content.clip_bounds = (0, 0, 0, 0) self._text_content.set_size("100%", "100%") # Scroller for the text, so we can move right and left self._text_scroller = LUIObject(parent=self._text_content) self._text_scroller.center_vertical = True self._text = LUILabel(parent=self._text_scroller, text=u"") # Cursor for the current position self._cursor = LUISprite(self._text_scroller, "blank", "skin", x=0, y=0, w=2, h=15) self._cursor.color = (0.5, 0.5, 0.5) self._cursor.margin.top = 2 self._cursor.z_offset = 20 self._cursor_index = 0 self._cursor.hide() self._value = value # Placeholder text, shown when out of focus and no value exists self._placeholder = LUILabel(parent=self._text_content, text=placeholder, shadow=False, center_vertical=True, alpha=0.2) # Various states self._tickrate = 1.0 self._tickstart = 0.0 self._render_text() if parent is not None: self.parent = parent LUIInitialState.init(self, kwargs) @property def value(self): """ Returns the value of the input field """ return self._value @value.setter def value(self, new_value): """ Sets the value of the input field """ if sys.version_info[0] < 3: self._value = unicode(new_value) else: self._value = str(new_value) self._render_text() self.trigger_event("changed", self._value) def clear(self): """ Clears the input value """ self.value = u"" @property def cursor_pos(self): """ Set the cursor position """ return self._cursor_index @cursor_pos.setter def cursor_pos(self, pos): """ Set the cursor position """ if pos >= 0: self._cursor_index = max(0, min(len(self._value), pos)) else: self._cursor_index = max(len(self._value) + pos + 1, 0) self._reset_cursor_tick() self._render_text() def on_tick(self, event): """ Tick handler, gets executed every frame """ frame_time = globalClock.get_frame_time() - self._tickstart show_cursor = frame_time % self._tickrate < 0.5 * self._tickrate if show_cursor: self._cursor.color = (0.5, 0.5, 0.5, 1) else: self._cursor.color = (1, 1, 1, 0) def on_click(self, event): """ Internal on click handler """ self.request_focus() def on_mousedown(self, event): """ Internal mousedown handler """ local_x_offset = self._text.text_handle.get_relative_pos( event.coordinates).x self.cursor_pos = self._text.text_handle.get_char_index(local_x_offset) def _reset_cursor_tick(self): """ Internal method to reset the cursor tick """ self._tickstart = globalClock.get_frame_time() def on_focus(self, event): """ Internal focus handler """ self._cursor.show() self._placeholder.hide() self._reset_cursor_tick() self._layout.color = (0.9, 0.9, 0.9, 1) def on_keydown(self, event): """ Internal keydown handler. Processes the special keys, and if none are present, redirects the event """ key_name = event.message if key_name == "backspace": self._value = self._value[:max(0, self._cursor_index - 1)] + self._value[self. _cursor_index:] self.cursor_pos -= 1 self.trigger_event("changed", self._value) elif key_name == "delete": post_value = self._value[min(len(self._value), self._cursor_index + 1):] self._value = self._value[:self._cursor_index] + post_value self.cursor_pos = self._cursor_index self.trigger_event("changed", self._value) elif key_name == "arrow_left": if event.get_modifier_state("alt") or event.get_modifier_state( "ctrl"): self.cursor_skip_left() else: self.cursor_pos -= 1 elif key_name == "arrow_right": if event.get_modifier_state("alt") or event.get_modifier_state( "ctrl"): self.cursor_skip_right() else: self.cursor_pos += 1 elif key_name == "escape": self.blur() elif key_name == "home": self.cursor_pos = 0 elif key_name == "end": self.cursor_pos = len(self.value) self.trigger_event(key_name, self._value) def on_keyrepeat(self, event): """ Internal keyrepeat handler """ self.on_keydown(event) def on_textinput(self, event): """ Internal textinput handler """ self._value = self._value[:self._cursor_index] + event.message + \ self._value[self._cursor_index:] self.cursor_pos = self._cursor_index + len(event.message) self.trigger_event("changed", self._value) def on_blur(self, event): """ Internal blur handler """ self._cursor.hide() if len(self._value) < 1: self._placeholder.show() self._layout.color = (1, 1, 1, 1) def _render_text(self): """ Internal method to render the text """ self._text.set_text(self._value) self._cursor.left = self._text.left + \ self._text.text_handle.get_char_pos(self._cursor_index) + 1 max_left = self.width - 15 if self._value: self._placeholder.hide() else: if not self.focused: self._placeholder.show() # Scroll if the cursor is outside of the clip bounds rel_pos = self.get_relative_pos(self._cursor.get_abs_pos()).x if rel_pos >= max_left: self._text_scroller.left = min(0, max_left - self._cursor.left) if rel_pos <= 0: self._text_scroller.left = min(0, -self._cursor.left - rel_pos) def cursor_skip_left(self): """ Moves the cursor to the left, skipping the previous word """ left_hand_str = ''.join(reversed(self.value[0:self.cursor_pos])) match = self.re_skip.match(left_hand_str) if match is not None: self.cursor_pos -= match.end() - 1 else: self.cursor_pos = 0 def cursor_skip_right(self): """ Moves the cursor to the right, skipping the next word """ right_hand_str = self.value[self.cursor_pos:] match = self.re_skip.match(right_hand_str) if match is not None: self.cursor_pos += match.end() - 1 else: self.cursor_pos = len(self.value)
class LUIProgressbar(LUIObject): """ A simple progress bar """ def __init__(self, parent=None, width=200, value=50, show_label=True): """ Constructs a new progress bar. If show_label is True, a label indicating the current progress is shown """ LUIObject.__init__(self) self.set_width(width) self._bg_layout = LUIHorizontalStretchedLayout(parent=self, prefix="ProgressbarBg", width="100%") self._fg_left = LUISprite(self, "ProgressbarFg_Left", "skin") self._fg_mid = LUISprite(self, "ProgressbarFg", "skin") self._fg_right = LUISprite(self, "ProgressbarFg_Right", "skin") self._fg_finish = LUISprite(self, "ProgressbarFg_Finish", "skin") self._show_label = show_label self._progress_pixel = 0 self._fg_finish.right = 0 if self._show_label: self._progress_label = LUILabel(parent=self, text=u"33 %") self._progress_label.centered = (True, True) self.set_value(value) self._update_progress() if parent is not None: self.parent = parent def get_value(self): """ Returns the current value of the progress bar """ return (self._progress_pixel / self.width * 100.0) def set_value(self, val): """ Sets the value of the progress bar """ val = max(0, min(100, val)) self._progress_pixel = int(val / 100.0 * self.width) self._update_progress() value = property(get_value, set_value) def _update_progress(self): """ Internal method to update the progressbar """ self._fg_finish.hide() if self._progress_pixel <= self._fg_left.width + self._fg_right.width: self._fg_mid.hide() self._fg_right.left = self._fg_left.width else: self._fg_mid.show() self._fg_mid.left = self._fg_left.width self._fg_mid.width = self._progress_pixel - self._fg_right.width - self._fg_left.width self._fg_right.left = self._fg_mid.left + self._fg_mid.width if self._progress_pixel >= self.width - self._fg_right.width: self._fg_finish.show() self._fg_finish.right = -(self.width - self._progress_pixel) self._fg_finish.clip_bounds = (0, self.width - self._progress_pixel, 0, 0) if self._show_label: percentage = self._progress_pixel / self.width * 100.0 self._progress_label.set_text(unicode(int(percentage)) + u" %")
class LUIRadiobox(LUIObject): """ A radiobox which can be used in combination with a LUIRadioboxGroup """ def __init__(self, group=None, value=None, active=False, label=u"Radiobox", **kwargs): LUIObject.__init__(self, x=0, y=0, w=0, h=0, solid=True) LUIInitialState.init(self, kwargs) self.sprite = LUISprite(self, "Radiobox_Default", "skin") self.label = LUILabel(parent=self, text=label, shadow=True, left=self.sprite.width+6) self.label.top = self.label.height - self.sprite.height self.label.bind("resized", self._on_label_resized) self.fit_to_children() self.group = group self.group.register_box(self) self.active = False self.value = value if active: self.set_active() def _on_label_resized(self, event): """ Internal handler when the text of the label got changed """ self.fit_to_children() def on_click(self, event): """ Internal onclick handler. Do not override. """ self.set_active() def set_active(self): """ Internal function to set the radiobox active """ if self.group is not None: self.group.set_active(self) else: self._update_state(True) def get_value(self): """ Returns the value of the radiobox """ return self.value def get_label(self): """ Returns a handle to the label, so it can be modified (e.g. change its text) """ return self.label def _update_state(self, active): """ Internal method to update the state of the radiobox. Called by the LUIRadioboxGroup """ self.active = active self.trigger_event("changed") self._update_sprite() def on_mousedown(self, event): """ Internal onmousedown handler. Do not override. """ self.color = (0.86,0.86,0.86,1.0) def on_mouseup(self, event): """ Internal onmouseup handler. Do not override. """ self.color = (1,1,1,1) def _update_sprite(self): """ Internal function to update the sprite of the radiobox """ img = "Radiobox_Active" if self.active else "Radiobox_Default" self.sprite.set_texture(img, "skin")
def prepare_demo(self, demo_title=u"Some Demo"): # Background self._background = LUISprite(self._root, "res/DemoBackground.png") # Make the background solid and recieve events self._background.solid = True # Logo self._logo = LUISprite(self._root, "res/LUILogo.png") self._logo.top_left = 15, 20 # Title self._title_label = LUILabel(parent=self._root, text=demo_title, font_size=40, font="header", pos=(120, 27)) self._subtitle_label = LUILabel(parent=self._root, text="Widget Demo", font_size=14, font="default", pos=(121, 70), alpha=0.3) # Right bar self._right_bar = LUIVerticalLayout(parent=self._root) self._left_bar = LUIVerticalLayout(parent=self._root) self._right_bar.width = 350 self._right_bar.pos = (410, 120) self._right_bar.spacing = 10 self._left_bar.width = 350 self._left_bar.pos = (20, 120) self._left_bar.spacing = 10 # Public functions self._public_functions = LUIFrame(width=340, style=LUIFrame.FS_sunken) self._functions_label = LUILabel(text=U"Additional Public functions") self._functions_layout = LUIVerticalLayout( parent=self._public_functions) self._functions_layout.add(self._functions_label, 30) # Events self._events = LUIFrame(width=340, style=LUIFrame.FS_sunken) self._events_label = LUILabel(text=U"Additional Events") self._events_layout = LUIVerticalLayout(parent=self._events) self._events_layout.add(self._events_label, 30) # Actions self._actions = LUIFrame(width=340, style=LUIFrame.FS_sunken) self._actions_label = LUILabel(parent=self._actions, text=U"Demo-Actions") self._actions_select = LUISelectbox(parent=self._actions, width=225, top=30) self._actions_btn = LUIButton(parent=self._actions, right=0, top=30, text=u"Execute", template="ButtonGreen") self._actions_btn.bind("click", self._exec_action) # Properties self._properties = LUIFrame(width=340, style=LUIFrame.FS_sunken) self._properties_label = LUILabel(text=u"Additional Properties") self._properties_layout = LUIVerticalLayout(parent=self._properties) self._properties_layout.add(self._properties_label, 30) self._right_bar.add(self._actions) self._right_bar.add(self._public_functions) self._right_bar.add(self._properties) self._right_bar.add(self._events) # Widget self._widget_container = LUIFrame(width=360, height=250, style=LUIFrame.FS_sunken) self._widget_label = LUILabel(parent=self._widget_container, text=u"Widget Demo") self._left_bar.add(self._widget_container) # Source Code self._source_container = LUIFrame(width=360, height=190, style=LUIFrame.FS_sunken) self._source_label = LUILabel(parent=self._source_container, text=u"Default Constructor") self._copy_code_button = LUIButton(parent=self._source_container, text=u"Copy to Clipboard", template="ButtonGreen", bottom_right=(0, 0)) self._source_content = LUIObject(self._source_container) self._source_content.top = 40 self._left_bar.add(self._source_container) self._widget_node = LUIObject(self._widget_container, x=0, y=40)
class LUIInputField(LUIObject): """ Simple input field """ def __init__(self, parent=None, width=200, placeholder=u"Enter some text ..", value=u"", **kwargs): """ Constructs a new input field. An input field always needs a width specified """ LUIObject.__init__(self, x=0, y=0, solid=True) self.set_width(width) self._layout = LUIHorizontalStretchedLayout(parent=self, prefix="InputField", width="100%") # Container for the text self._text_content = LUIObject(self) self._text_content.margin = (5, 7, 5, 7) self._text_content.clip_bounds = (0, 0, 0, 0) self._text_content.set_size("100%", "100%") # Scroller for the text, so we can move right and left self._text_scroller = LUIObject(parent=self._text_content) self._text_scroller.center_vertical = True self._text = LUILabel(parent=self._text_scroller, text=u"") # Cursor for the current position self._cursor = LUISprite(self._text_scroller, "blank", "skin", x=0, y=0, w=2, h=15) self._cursor.color = (0.5, 0.5, 0.5) self._cursor.margin.top = 2 self._cursor.z_offset = 20 self._cursor_index = 0 self._cursor.hide() self._value = value # Placeholder text, shown when out of focus and no value exists self._placeholder = LUILabel(parent=self._text_content, text=placeholder, shadow=False, center_vertical=True, alpha=0.2) # Various states self._tickrate = 1.0 self._tickstart = 0.0 self._render_text() if parent is not None: self.parent = parent LUIInitialState.init(self, kwargs) def get_value(self): """ Returns the value of the input field """ return self._value def set_value(self, value): """ Sets the value of the input field """ self._value = unicode(value) self.trigger_event("changed", self._value) self._render_text() value = property(get_value, set_value) def clear(self): """ Clears the input value """ self.value = u"" def _set_cursor_pos(self, pos): """ Internal method to set the cursor position """ self._cursor_index = max(0, min(len(self._value), pos)) self._reset_cursor_tick() def on_tick(self, event): """ Tick handler, gets executed every frame """ frametime = globalClock.get_frame_time() - self._tickstart show_cursor = frametime % self._tickrate < 0.5 * self._tickrate if show_cursor: self._cursor.color = (0.5, 0.5, 0.5, 1) else: self._cursor.color = (1, 1, 1, 0) def _add_text(self, text): """ Internal method to append text """ self._value = self._value[:self._cursor_index] + text + self._value[ self._cursor_index:] self._set_cursor_pos(self._cursor_index + len(text)) self._render_text() def on_click(self, event): """ Internal on click handler """ self.request_focus() def on_mousedown(self, event): """ Internal mousedown handler """ local_x_offset = self._text.text_handle.get_relative_pos( event.coordinates).x self._set_cursor_pos( self._text.text_handle.get_char_index(local_x_offset)) self._render_text() def _reset_cursor_tick(self): """ Internal method to reset the cursor tick """ self._tickstart = globalClock.getFrameTime() def on_focus(self, event): """ Internal focus handler """ self._cursor.show() self._placeholder.hide() self._reset_cursor_tick() self._layout.color = (0.9, 0.9, 0.9, 1) def on_keydown(self, event): """ Internal keydown handler """ key_name = event.message if key_name == "backspace": self._value = self._value[:max(0, self._cursor_index - 1)] + self._value[self. _cursor_index:] self._set_cursor_pos(self._cursor_index - 1) self.trigger_event("changed", self._value) self._render_text() elif key_name == "delete": self._value = self._value[:self._cursor_index] + self._value[ min(len(self._value), self._cursor_index + 1):] self._set_cursor_pos(self._cursor_index) self.trigger_event("changed", self._value) self._render_text() elif key_name == "arrow_left": self._set_cursor_pos(self._cursor_index - 1) self._render_text() elif key_name == "arrow_right": self._set_cursor_pos(self._cursor_index + 1) self._render_text() self.trigger_event(key_name, self._value) def on_keyrepeat(self, event): """ Internal keyrepeat handler """ self.on_keydown(event) def on_textinput(self, event): """ Internal textinput handler """ self._add_text(event.message) self.trigger_event("changed", self._value) def on_blur(self, event): """ Internal blur handler """ self._cursor.hide() if len(self._value) < 1: self._placeholder.show() self._layout.color = (1, 1, 1, 1) def _render_text(self): """ Internal method to render the text """ self._text.set_text(self._value) self._cursor.left = self._text.left + self._text.text_handle.get_char_pos( self._cursor_index) + 1 max_left = self.width - 15 if self._value: self._placeholder.hide() else: if not self.focused: self._placeholder.show() # Scroll if the cursor is outside of the clip bounds rel_pos = self.get_relative_pos(self._cursor.get_abs_pos()).x if rel_pos >= max_left: self._text_scroller.left = min(0, max_left - self._cursor.left) if rel_pos <= 0: self._text_scroller.left = min(0, -self._cursor.left - rel_pos)