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(4, 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
class LUISlider(LUIObject): """ Slider which can be used to control values """ def __init__(self, parent=None, filled=True, min_value=0.0, max_value=1.0, width=100.0, value=None, **kwargs): """ Constructs a new slider. If filled is True, the part behind the knob will be solid """ LUIObject.__init__(self, x=0, y=0, solid=True) self.set_width(width) self._knob = LUISprite(self, "SliderKnob", "skin") self._knob.z_offset = 2 self._knob.solid = True # Construct the background self._slider_bg = LUIHorizontalStretchedLayout(parent=self, prefix="SliderBg", center_vertical=True, width="100%", margin=(-1, 0, 0, 0)) self._filled = filled self._min_value = min_value self._max_value = max_value self._side_margin = self._knob.width / 4 self._effective_width = self.width - 2 * self._side_margin if self._filled: self._slider_fill = LUIObject(self) self._fill_left = LUISprite(self._slider_fill, "SliderBgFill_Left", "skin") self._fill_mid = LUISprite(self._slider_fill, "SliderBgFill", "skin") self._fill_mid.left = self._fill_left.width self._slider_fill.z_offset = 1 self._slider_fill.center_vertical = True if parent is not None: self.parent = parent # Handle various events self._knob.bind("mousedown", self._start_drag) self._knob.bind("mousemove", self._update_drag) self._knob.bind("mouseup", self._stop_drag) self._knob.bind("keydown", self._on_keydown) self._knob.bind("blur", self._stop_drag) self._knob.bind("keyrepeat", self._on_keydown) self._drag_start_pos = None self._dragging = False self._drag_start_val = 0 self.current_val = 10 # Set initial value if value is None: self.set_value((self._min_value + self._max_value) / 2.0) else: self.set_value(value) self._update_knob() LUIInitialState.init(self, kwargs) def on_click(self, event): """ Internal on click handler """ # I don't like this behaviour # relative_pos = self.get_relative_pos(event.coordinates) # if not self._dragging: # self._set_current_val(relative_pos.x) def _update_knob(self): """ Internal method to update the slider knob """ self._knob.left = self.current_val - (self._knob.width / 2) + self._side_margin if self._filled: self._fill_mid.width = self.current_val - self._fill_left.width + self._side_margin def _set_current_val(self, pixels): """ Internal method to set the current value in pixels """ pixels = max(0, min(self._effective_width, pixels)) self.current_val = pixels self.trigger_event("changed") self._update_knob() def _start_drag(self, event): """ Internal drag start handler """ self._knob.request_focus() if not self._dragging: self._drag_start_pos = event.coordinates self._dragging = True self._drag_start_val = self.current_val self._knob.color = (0.8, 0.8, 0.8, 1.0) def set_value(self, value): """ Sets the value of the slider, should be between minimum and maximum. """ scaled = (float(value) - float(self._min_value)) \ / (float(self._max_value) - float(self._min_value)) \ * self._effective_width self._set_current_val(scaled) def get_value(self): """ Returns the current value of the slider """ return (self.current_val / float(self._effective_width)) \ * (float(self._max_value) - float(self._min_value)) \ + self._min_value value = property(get_value, set_value) def _on_keydown(self, event): """ Internal keydown handler """ if event.message == "arrow_right": self._set_current_val(self.current_val + 2) elif event.message == "arrow_left": self._set_current_val(self.current_val - 2) elif event.message == "escape": self.current_val = self._drag_start_val self._stop_drag(event) self._update_knob() def _update_drag(self, event): """ Internal drag handler """ if self._dragging: dragOffset = event.coordinates.x - self._drag_start_pos.x finalValue = self._drag_start_val + dragOffset self._set_current_val(finalValue) def _stop_drag(self, event): """ Internal drag stop handelr """ self._drag_start_pos = None self._dragging = False self._drag_start_val = self.current_val self._knob.color = (1, 1, 1, 1)
class DemoFramework: """ This is a small helper class to setup common stuff for the demos """ def __init__(self): base.win.set_clear_color(Vec4(0, 0, 0, 1)) self.skin = LUIDefaultSkin() self.skin.load() # Construct the LUIRegion region = LUIRegion.make("LUI", base.win) handler = LUIInputHandler() base.mouseWatcher.attach_new_node(handler) region.set_input_handler(handler) self.root = region.root() self.constructorParams = [] 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.bind("click", lambda event: self.background.request_focus()) self.background.solid = True # Logo self.logo = LUISprite(self.root, "res/LUILogo.png") self.logo.top = 15 self.logo.left = 20 # Title self.titleLabel = LUILabel(parent=self.root, text=demo_title, font_size=40, font="header") self.titleLabel.pos = (120, 20) self.subtitleLabel = LUILabel(parent=self.root, text="Widget Demo", font_size=14, font="default") self.subtitleLabel.pos = (121, 65) self.subtitleLabel.color = (1,1,1,0.5) # Right bar self.rightBar = LUIVerticalLayout(parent=self.root, width=350, spacing=20) self.rightBar.pos = (410, 120) # Constructor parameters # self.constructorParameters = LUIFrame(width=340, style=LUIFrame.Sunken) # self.constructorLabel = LUILabel(parent=self.constructorParameters, text=u"Additional Constructor Parameters") # self.constructorLayout = UIVerticalLayout(parent=self.constructorParameters, spacing=10, use_dividers=True) # self.constructorLayout.top = 30 # Public functions self.publicFunctions = LUIFrame(width=340, style=LUIFrame.Sunken) self.functionsLabel = LUILabel(parent=self.publicFunctions, text=U"Additional Public functions") self.functionsLayout = LUIVerticalLayout(parent=self.publicFunctions,spacing=10, use_dividers=True) self.functionsLayout.top = 30 # Events self.events = LUIFrame(width=340,style=LUIFrame.Sunken) self.eventsLabel = LUILabel(parent=self.events, text=U"Additional Events") self.eventsLayout = LUIVerticalLayout(parent=self.events, spacing=10, use_dividers=True) self.eventsLayout.top = 30 # Actions self.actions = LUIFrame(width=340,style=LUIFrame.Sunken, height=80) self.actionsLabel = LUILabel(parent=self.actions, text=U"Demo-Actions") self.actionsSelect = LUISelectbox(parent=self.actions, width=245, top=30) self.actionsBtn = LUIButton(parent=self.actions, right=0, top=30, text=u"Execute", template="ButtonMagic") self.actionsBtn.bind("click", self._exec_action) self.rightBar.add_row(self.actions) # self.rightBar.add_row(self.constructorParameters) self.rightBar.add_row(self.publicFunctions) self.rightBar.add_row(self.events) # Widget self.widgetContainer = LUIFrame(parent=self.root, width=360, height=250, style=LUIFrame.Sunken) self.widgetLabel = LUILabel(parent=self.widgetContainer, text=u"Widget Demo") self.widgetContainer.left = 26 self.widgetContainer.top = 120 # Source Code self.sourceContainer = LUIFrame(parent=self.root, width=360, height=200, style=LUIFrame.Sunken) self.sourceLabel = LUILabel(parent=self.sourceContainer, text=u"Default Constructor") self.copyCodeButton = LUIButton(parent=self.sourceContainer, text=u"Copy to Clipboard", template="ButtonMagic", right=-5, bottom=-5) self.sourceContainer.left = 26 self.sourceContainer.top = 390 self.sourceContent = LUIObject(self.sourceContainer) self.sourceContent.top = 40 self.widgetNode = LUIObject(self.widgetContainer, x=0, y=40) def _exec_action(self, event): selected = self.actionsSelect.get_selected_option() if selected is not None: selected() def set_actions(self, actions): opts = [] for name, action in actions.items(): opts.append((action, name)) self.actionsSelect.set_options(opts) def add_public_function(self, name, parameters=None, return_type="void"): label = LUIFormattedLabel() label.add_text(text=return_type + " ", color = (102/255.0, 217/255.0, 239/255.0)) label.add_text(text=name + " ", color = (166/255.0, 226/255.0, 46/255.0)) label.add_text(text="( ", color=(0.9,0.9,0.9)) if parameters is not None: for index, (pname, ptype) in enumerate(parameters): label.add_text(text=pname, color=(255/255.0, 151/255.0, 31/255.0)) label.add_text(text=" : ", color=(0.9,0.9,0.9)) label.add_text(text=ptype, color=(102/255.0, 217/255.0, 239/255.0)) if index < len(parameters) - 1: label.add_text(text=",", color=(0.9,0.9,0.9)) label.add_text(text=" )", color=(0.9,0.9,0.9)) self.functionsLayout.add_row(label) self.update_layouts() def add_constructor_parameter(self, name, default): # label = UIFormattedLabel() # label.add_text(text=name, color=(255/255.0, 151/255.0, 31/255.0)) # label.add_text(text=" = ", color=(249/255.0, 38/255.0, 114/255.0)) # label.add_text(text=default, color=(153/255.0, 129/255.0, 255/255.0)) # self.constructorLayout.add_row(label) self.constructorParams.append((name, default)) self.update_layouts() 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() def update_layouts(self): self.publicFunctions.fit_height_to_children() # self.constructorParameters.fit_height_to_children() self.events.fit_height_to_children() self.rightBar.update() def construct_sourcecode(self, classname): self.sourceContent.remove_all_children() label = LUIFormattedLabel(parent=self.sourceContent) label.add_text(text="element ", color=(0.9,0.9,0.9)) label.add_text(text="= ", color=(249/255.0, 38/255.0, 114/255.0)) label.add_text(text=classname, color=(166/255.0, 226/255.0, 46/255.0)) label.add_text(text="(", color=(0.9,0.9,0.9)) for index, (pname, pvalue) in enumerate(self.constructorParams): label.br() label.add_text(text=" " * 15) label.add_text(text=pname, color=(255/255.0, 151/255.0, 31/255.0)) label.add_text(text=" = ") label.add_text(text=pvalue, color=(153/255.0, 129/255.0, 255/255.0)) if index < len(self.constructorParams) - 1: label.add_text(text=",") label.add_text(text=")") self.sourceContent.fit_height_to_children() self.sourceContainer.fit_height_to_children() self.sourceContainer.height += 40 def get_widget_node(self): return self.widgetNode
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()