# -*- indent-tabs-mode: t -*- """ most basic widget for pudding """ __revision__ = '$Revision: 1.2 $' __doc_classes__ = [ 'SimpleLabel', 'Label', 'PrePostLabel', 'Input', 'Panel', 'Button', 'Console', 'Image', 'Logo', ] __doc_functions__ = [] import string from soya.pudding import ConstantError, EXPAND_BOTH, EXPAND_HORIZ, ANCHOR_ALL, ANCHOR_RIGHT, ANCHOR_BOTTOM, CLIP_NONE, CLIP_LEFT, CLIP_RIGHT from soya.pudding.core import Base, Control, TestControl, InputControl, _TestInputControl, TestContainer from soya.pudding.container import VerticalContainer from soya.pudding.core import LateBindingProperty import soya from soya.opengl import * from soya import sdlconst as sdl class Box(Control, InputControl): """ A simple graphical box that responds to user events, usefull for and descending other controls""" def __get_background_color__(self): return self._background_color def __set_background_color__(self, color): self._background_color = color def __get_border_color__(self): return self._border_color def __set_border_color__(self, color): self._border_color = color def __get_border_width__(self): return self._border_width def __set_border_width__(self, width): self._border_width = width background_color = LateBindingProperty('__get_background_color__', '__set_background_color__', doc = "background color of the box") border_color = LateBindingProperty('__get_border_color__', '__set_border_color__', doc = "border color of the box") border_width = LateBindingProperty('__get_border_width__', '__set_border_width__', doc = "border width") def __init__(self, parent=None, **kwargs): self._background_color = None self._border_color = None self._border_width = None Control.__init__(self, parent, **kwargs) InputControl.__init__(self) def process_event(self, event): """ use the InputControl class to process events """ return InputControl.process_event(self, event) def render_self(self): """ render the box with current settings """ soya.pudding.STYLE.draw_bordered_box(self.width, self.height, background = self.background_color, border = self.border_color, border_width = self.border_width) class TestBox(TestControl, _TestInputControl): klass = Box class SimpleLabel(Control): """ A simple, unresponsive label widget """ MAXLEN = 2000 def __get_label__(self): return self._text def __set_label__(self, label): self._text = label self.update() self.on_set_label() def __get_font__(self): return self._font def __set_font__(self, font): self._font = font def __get_color__(self): return self._color def __set_color__(self, color): self._color = color def __get_autosize__(self): return self._autosize def __set_autosize__(self, autosize): if autosize: self._autosize = True else: self._autosize = False def __get_clip__(self): return self._clip def __set_clip__(self, clip): if clip not in [CLIP_LEFT, CLIP_RIGHT]: raise ConstantError( 'clip must be soya.pudding.CLIP_LEFT or soya.pudding.CLIP_RIGHT') self._clip = clip def __get_wrap__(self): return self._wrap def __set_wrap__(self, wrap): self._wrap = wrap color = LateBindingProperty('__get_color__', '__set_color__', doc = "color of the text") label = LateBindingProperty('__get_label__', '__set_label__', doc = "text displayed") font = LateBindingProperty('__get_font__', '__set_font__' , doc = "font used for rendering") autosize = LateBindingProperty( '__get_autosize__', '__set_autosize__', doc = """should the label automatically adjust its size to accomodate all the text""") clip = LateBindingProperty('__get_clip__', '__set_clip__', doc = """if there is too much text do we clip the left or right. must be soya.pudding.core.[soya.pudding.CLIP_LEFT | soya.pudding.CLIP_RIGHT]""") wrap = LateBindingProperty('__get_wrap__', '__set_wrap__') ## end of properties def __init__(self, parent=None, label='', **kwargs): self._autosize = kwargs.get('autosize', True) self._wrap = False self._color = (1., 1., 1., 1.) self._font = soya.pudding.STYLE.default_font self._clip = CLIP_LEFT Control.__init__(self, parent, **kwargs) self.display_list = glGenLists(1) self._text = label self._display_text = '' self.update() def render_self(self): """ draw the text with the current settings """ soya.DEFAULT_MATERIAL.activate() glColor4f(*self._color) glDisable(GL_CULL_FACE) if self.needs_update: self._font.create_glyphs(self._display_text) glNewList(self.display_list, GL_COMPILE_AND_EXECUTE) self._font.draw(self._display_text, 0., 0., 0.) glEndList() self.needs_update = False else: glCallList(self.display_list) glDisable(GL_CULL_FACE) def set_display_text(self, text): """ get the text we should actually display. usefull if you want to add a constant string or perform some processing before the string gets wrapped or clipped or whatever """ self._display_text = text def update(self): """ refresh settings based on clip and autoresize etc """ if len(self._text) > SimpleLabel.MAXLEN: self._text = self._text[-SimpleLabel.MAXLEN:] self.needs_update = True self.set_display_text( self._text ) if self._wrap: max_width, height, self._display_text = \ self._font.wordwrap(self._display_text, self._width) if self._autosize: self.height = height self.text_width = max_width self.text_height = min(self.height, height) if height > self.height: lines_to_many = (height - self._height) / self._font.height self._display_text = "\n".join( self._display_text.split('\n')[int(lines_to_many):] ) elif self._autosize: self._width, self._height = \ self._font.get_print_size(self._display_text) self.text_width, self.text_height = self._width, self._height elif self._clip != CLIP_NONE: width, height = self._font.get_print_size(self._display_text) while width > self.width: if self._clip == CLIP_LEFT: self._display_text = self._display_text[1:] else: self._display_text = self._display_text[:-1] width, height = self._font.get_print_size(self._display_text) self.text_width, self.text_height = width, height def on_resize(self): """ update position with anchoring and apply wrapping/clipping """ self.do_anchoring() self.update() def on_set_label(self): """ event triggered when the label is changed """ pass class TestSimpleLabel(TestControl): klass = SimpleLabel def testSetLabel(self): """ testing setting label """ self.getControl().label = 'something' class Label(SimpleLabel, InputControl): """ Label with events. Created using SimpleLabel and InputControl with multiple inheritance """ def __init__(self, parent=None, label='', **kwargs): SimpleLabel.__init__(self, parent, label, **kwargs) InputControl.__init__(self) def process_event(self, event): """ let InputControl class deal with events """ return InputControl.process_event(self, event) class TestLabel(TestSimpleLabel, _TestInputControl): klass = Label class PrePostLabel(SimpleLabel): """ A label with static pre/post -fix """ def __get_pre__(self): return self._pre def __set_pre__(self, pre): self._pre = pre self.update() def __get_post__(self): return self._post def __set_post__(self, post): self._post = post self.update() pre = LateBindingProperty('__get_pre__' , '__set_pre__') post = LateBindingProperty('__get_post__' , '__set_post__') def __init__(self, parent=None, label='', pre='', post='', **kwargs): self._pre = pre self._post = post SimpleLabel.__init__(self, parent, label, **kwargs) def set_display_text(self, text): """ set the display text with the pre and post strings """ self._display_text = "%s%s%s" % (self._pre, text, self._post) class TestPrePostLabel(TestSimpleLabel): klass = Label def testSetPre(self): """ testing setting pre """ self.getControl().pre = 'something' def testSetPost(self): """ testing setting post """ self.getControl().post = 'something' class Button(Box): """ A simple button widget. The label is a child SimpleLabel widget. Note the on_click method provided""" def __get_label__(self): return self.label_control.label def __set_label__(self, val): self.label_control.label = val label = LateBindingProperty('__get_label__', '__set_label__', doc = "label on the button") def __init__(self, parent=None, label='button', width=None, height=None, **kwargs): self.label_control = SimpleLabel(label=label, autosize = True) if width is None: width = self.label_control.width + (self.label_control.font.width * 2) if height is None: height = self.label_control.height + (self.label_control.font.height / 2) Box.__init__(self, parent, width=width, height=height, **kwargs) self.child = self.label_control def __repr__(self): return "