def __init__(self, func, pos, size, text='', color=GREEN, anchor=CENTER, takeArg=False, enable=True, flags=0): """ Creates a clickable button. :param func: callback function with no arguments :param size: widget size. Can be a callable or a 2-tuple. :param pos: widget position. Can be a callable or a 2-tuple. :param anchor: widget anchor :param text: Text to be displayed on the button :param color: the natural color of the button :param flags: see BaseButton """ super().__init__(func, pos, size, anchor, flags) self.color = color self.hovered = False self.hover_enabled = True self.pressed = False self.takesArg = takeArg self._arg = None self._isEnabled = enable self.text = SimpleText(text, lambda: self.center, bw_contrasted(self.color), self.color, Font(self.height - 6, unit=Font.PIXEL))
def __init__(self, func, pos, size, min_=0, max_=100, step=1, color=BLUE, *, bg_color=LIGHT_GREY, show_val=True, interval=1, anchor=CENTER, inital=None, rounding=2, v_type=int): """ Creates a SlideBar. Use focus() when the user selects the bar and unfous() when he release the SB. :param size: widget size. Can be a callable or a 2-tuple. :param pos: widget position. Can be a callable or a 2-tuple. :param anchor: widget anchor :param show_val: if False, doesn't display the value on the cursor :param func: Callback function when a value is changed :param min_: The eminimum value of the picker :param max_: The maximum value of the picker :param step: The step :param color: color of the cursor :param bg_color: color of the background :param interval: minimum milisec elapsed between two calls to *func* :param inital: initial value for the SB :param rounding: number of digits to round values :param v_type: type of value. Can be float/int/Decimal/Fraction etc. you will have an object of this type using get() """ super().__init__(pos, size, anchor) self.color = color self.bg_color = bg_color self.func = func self._value = inital if inital is not None else min_ self.min = min_ self.max = max_ self.step = step self.show_val = show_val self.rounding = rounding self.v_type = v_type font = Font(self.height // 2) self.text_val = SimpleText(self.get, lambda: (self.value_px, self.centery), bw_contrasted(self.color), font) self.interval = interval
class RoundButton(Button): def __init__(self, func, pos, radius: int, text='', color=GREEN, anchor=CENTER, flags=0): super().__init__(func, pos, (radius * 2, radius * 2), text, color, anchor, flags) self.text = SimpleText(text, lambda: self.center, bw_contrasted(self.color), self.color, Font(self.height // 2, unit=Font.PIXEL)) def render(self, surf): """Draw the button on the surface.""" if not self.flags & self.NO_SHADOW: circle(surf, self.center + self._bg_delta, self.width / 2, LIGHT_GREY) circle(surf, self.center + self._front_delta, self.width / 2, self._get_color()) self.text.center = self.center + self._front_delta self.text.render(surf)
def __init__(self, parent, name, pos, size, anchor=TOPLEFT, item_size=20, color=CONCRETE, bg_color=WHITE, sep_color=CONCRETE): super().__init__(pos, size, anchor, item_size, sep_color) self.parent = parent self.title = SimpleText( name, pos ) #, color, bg_color, BoldFont(self.height, BoldFont.POINT), TOPLEFT) self.structure.append(self.title)
class SlideBar(BaseWidget): """ A slide bar to bick a value in a range. Don't forget to call focus() and unfocus() when the user click on the SlideBar """ def __init__(self, func, pos, size, min_=0, max_=100, step=1, color=BLUE, *, bg_color=LIGHT_GREY, show_val=True, interval=1, anchor=CENTER, inital=None, rounding=2, v_type=int): """ Creates a SlideBar. Use focus() when the user selects the bar and unfous() when he release the SB. :param size: widget size. Can be a callable or a 2-tuple. :param pos: widget position. Can be a callable or a 2-tuple. :param anchor: widget anchor :param show_val: if False, doesn't display the value on the cursor :param func: Callback function when a value is changed :param min_: The eminimum value of the picker :param max_: The maximum value of the picker :param step: The step :param color: color of the cursor :param bg_color: color of the background :param interval: minimum milisec elapsed between two calls to *func* :param inital: initial value for the SB :param rounding: number of digits to round values :param v_type: type of value. Can be float/int/Decimal/Fraction etc. you will have an object of this type using get() """ super().__init__(pos, size, anchor) self.color = color self.bg_color = bg_color self.func = func self._value = inital if inital is not None else min_ self.min = min_ self.max = max_ self.step = step self.show_val = show_val self.rounding = rounding self.v_type = v_type font = Font(self.height // 2) self.text_val = SimpleText(self.get, lambda: (self.value_px, self.centery), bw_contrasted(self.color), font) self.interval = interval def __repr__(self): # return f'SlideBar({self.min}:{self.max}:{self.step}; {super().__repr__()}, Value: {self.get()})' return 'SlideBar({}:{}:{}; {}, Value: {})'.format( self.min, self.max, self.step, super().__repr__(), self.get()) def get(self): """The current value of the bar""" return round(self.v_type(self._value), self.rounding) def set(self, value): """Set the value of the bar. If the value is out of bound, sets it to an extremum""" value = min(self.max, max(self.min, value)) self._value = value start_new_thread(self.func, (self.get(), )) def _start(self): """Starts checking if the SB is shifted""" # TODO : make an update method instead last_call = 42 while self._focus: sleep(1 / 100) mouse = pygame.mouse.get_pos() last_value = self.get() self.value_px = mouse[0] # we do not need to do anything when it the same value if self.get() == last_value: continue if last_call + self.interval / 1000 < time(): last_call = time() self.func(self.get()) def focus(self): """Gives the focus to the widget""" self._focus = True start_new_thread(SlideBar._start, (self, )) @property def value_px(self): """The position in pixels of the cursor""" step = self.w / (self.max - self.min) return self.x + step * ( self.get() - self.min ) # -self.min so self.x is the minimum possible place @value_px.setter def value_px(self, value): value = min(self.right, max(self.left, value)) delta_x = value - self.x prop = delta_x / self.width real = prop * (self.max - self.min) self._value = self.min + round(real / self.step) * self.step def render(self, display): """Renders the bar on the display""" # the bar bar_rect = pygame.Rect(0, 0, self.width, self.height // 3) bar_rect.center = self.center display.fill(self.bg_color, bar_rect) # the cursor circle(display, (self.value_px, self.centery), self.height // 2, self.color) # the value if self.show_val: self.text_val.render(display)
def __init__(self): super(Lamacorp, self).__init__() header_size = 60 h_color = BLUE nb_button = 8 button_size = lambda:(self.SCREEN_SIZE[0] - 40) / nb_button self.tab = None self.header = self.add(Rectangle((0, 0), lambda: (self.SCREEN_SIZE[0], header_size), h_color)) self.line = self.add(Line((0, header_size), lambda: (self.SCREEN_SIZE[0], header_size), GOLD)) self.title = self.add( SimpleText(self.NAME, (16, 8), GOLD, h_color, BoldFont(header_size - 16, Font.PIXEL, BoldFont.LIGHT), TOPLEFT) ) def get_funcs(color, i, row): def _pos(): return int(20 + button_size() * i), header_size + 8 + 38 * row def _size(): return int(button_size() - 6), 30 def _action(): rgb = name2rgb(color) rgb_light = mix(WHITESMOKE, rgb, 0.6) self.line.color = rgb_light self.BORDER_COLOR = rgb self.header.color = rgb self.title.bg_color = rgb self.die.color = 255 - rgb[0], 255 - rgb[1], 255 - rgb[2] self.title.color = WHITESMOKE self.choose_hint.text = str(color.hex).capitalize() self.choose_hint.color = rgb self.quit.color = rgb self.tab = color print(color, color.rgb, color.hex) text = texts[row][i % len(texts[row])] return _action, _pos, _size, text start = colour.Color("green"), colour.Color("#00caca") end = colour.Color('gold'), colour.Color('navy') texts = [ "That's some beautiful colors and buttons man ! :P Yolooo".split(), 'There is 64 differents types of buttons ! :o :P'.split() ] # the buttons for row in range(2): for i, color in enumerate(start[row].range_to(end[row], nb_button)): self.add(Button(*get_funcs(color, i, row), name2rgb(color), TOPLEFT, 4 * i + 32 * row)) self.die = self.add( RoundButton(pygame.display.iconify, lambda: self.SCREEN_SIZE + Sep(-10, -10), 40, 'Die', h_color, BOTTOMRIGHT), lambda: self.tab ) self.quit = self.add( RoundButton(quit, lambda: (self.SCREEN_SIZE[0] - 8, 8), header_size // 2 - 8, 'X', h_color, TOPRIGHT, Button.NO_MOVE | Button.NO_SHADOW) ) self.choose_hint = self.add( SimpleText('Choose your color !', lambda:(self.SCREEN_SIZE[0] // 2, (self.SCREEN_SIZE[1] + header_size) // 2), CONCRETE, self.BACKGROUND_COLOR, Font(50)), # lambda: False ) self.rounded = self.add( Rectangle((120, 40), (300, 300), color=(0, 0, 255, 120), style=Rectangle.ROUNDED) ) self.tect_box = self.add(InLineTextBox(lambda:(self.SCREEN_SIZE[0]//2, self.SCREEN_SIZE[1] - 50), (self.SCREEN_SIZE[0]//2), MIDNIGHT_BLUE)) self.add(Rectangle(self.tect_box.topleft, self.tect_box.size, GOLD, Rectangle.BORDER))
class Button(BaseButton): """A basic button.""" NO_MOVE = 4 NO_SHADOW = 8 NO_ROUNDING = 16 NO_HOVER = 32 def __init__(self, func, pos, size, text='', color=GREEN, anchor=CENTER, flags=0): """ Creates a clickable button. :param func: callback function with no arguments :param size: widget size. Can be a callable or a 2-tuple. :param pos: widget position. Can be a callable or a 2-tuple. :param anchor: widget anchor :param text: Text to be displayed on the button :param color: the natural color of the button :param flags: see BaseButton """ super().__init__(func, pos, size, anchor, flags) self.color = color self.hovered = False self.hover_enabled = True self.pressed = False self.text = SimpleText(text, lambda: self.center, bw_contrasted(self.color), self.color, Font(self.height - 6, unit=Font.PIXEL)) def _get_color(self): """Return the color of the button, depending on its state""" if self.clicked and self.hovered: # the mouse is over the button color = mix(self.color, BLACK, 0.8) elif self.hovered and not self.flags & self.NO_HOVER: color = mix(self.color, BLACK, 0.93) else: color = self.color self.text.bg_color = color return color @property def _front_delta(self): """Return the offset of the colored part.""" if self.flags & self.NO_MOVE: return Separator(0, 0) if self.clicked and self.hovered: # the mouse is over the button delta = 2 elif self.hovered and not self.flags & self.NO_HOVER: delta = 0 else: delta = 0 return Separator(delta, delta) @property def _bg_delta(self): """Return the offset of the shadow.""" if self.flags and self.NO_MOVE: return Separator(2, 2) if self.clicked and self.hovered: # the mouse is over the button delta = 2 elif self.hovered and not self.flags & self.NO_HOVER: delta = 2 else: delta = 2 return Separator(delta, delta) def update(self, event_or_list): """Update the button with the events.""" for e in super().update(event_or_list): if e.type == MOUSEBUTTONDOWN: if e.pos in self: self.click() else: self.release(force_no_call=True) elif e.type == MOUSEBUTTONUP: self.release(force_no_call=e.pos not in self) elif e.type == MOUSEMOTION: if e.pos in self: self.hovered = True else: self.hovered = False def render(self, surf): """Render the button on a surface.""" pos, size = self.topleft, self.size if not self.flags & self.NO_SHADOW: if self.flags & self.NO_ROUNDING: pygame.draw.rect(surf, LIGHT_GREY, (pos + self._bg_delta, size)) else: roundrect(surf, (pos + self._bg_delta, size), LIGHT_GREY + (100,), 5) if self.flags & self.NO_ROUNDING: pygame.draw.rect(surf, self._get_color(), (pos + self._front_delta, size)) else: roundrect(surf, (pos + self._front_delta, size), self._get_color(), 5) self.text.center = self.center + self._front_delta self.text.render(surf)
def __init__(self, func, pos, radius: int, text='', color=GREEN, anchor=CENTER, flags=0): super().__init__(func, pos, (radius * 2, radius * 2), text, color, anchor, flags) self.text = SimpleText(text, lambda: self.center, bw_contrasted(self.color), self.color, Font(self.height // 2, unit=Font.PIXEL))
class Button(BaseButton): """A basic button.""" NO_MOVE = 4 NO_SHADOW = 8 NO_ROUNDING = 16 NO_HOVER = 32 def __init__(self, func, pos, size, text='', color=GREEN, anchor=CENTER, takeArg=False, enable=True, flags=0): """ Creates a clickable button. :param func: callback function with no arguments :param size: widget size. Can be a callable or a 2-tuple. :param pos: widget position. Can be a callable or a 2-tuple. :param anchor: widget anchor :param text: Text to be displayed on the button :param color: the natural color of the button :param flags: see BaseButton """ super().__init__(func, pos, size, anchor, flags) self.color = color self.hovered = False self.hover_enabled = True self.pressed = False self.takesArg = takeArg self._arg = None self._isEnabled = enable self.text = SimpleText(text, lambda: self.center, bw_contrasted(self.color), self.color, Font(self.height - 6, unit=Font.PIXEL)) @property def isEnabled(self): return self._isEnabled @isEnabled.setter def isEnabled(self, value): if not isinstance(value, bool): raise TypeError("Value must be a boolean type. Got " + str(type(value)) + " instead.") @property def arg(self): return self._arg @arg.setter def arg(self, value): if self.takesArg == False: raise KeyError("This button does not take arguments") else: self._arg = value def click(self, force_no_call=False, milis=None): """ Call when the button is pressed. This start the callback function in a thread If :milis is given, will release the button after :milis miliseconds Completely overridden because the super class's method did not take arguments """ if not self.isEnabled: return False if self.clicked: return False if not force_no_call and self.flags & self.CALL_ON_PRESS: if self.flags & self.THREADED_CALL: if self.takesArg: start_new_thread(self.func, self.arg) else: start_new_thread(self.func, ()) else: if (self.takesArg): self.func(self.arg) else: self.func() BaseWidget.click() if milis is not None: start_new_thread(self.release, (), {'milis': milis}) def _get_color(self): """Return the color of the button, depending on its state""" if self.clicked and self.hovered: # the mouse is over the button color = mix(self.color, BLACK, 0.8) elif self.hovered and not self.flags & self.NO_HOVER: color = mix(self.color, BLACK, 0.93) else: color = self.color self.text.bg_color = color return color @property def _front_delta(self): """Return the offset of the colored part.""" if self.flags & self.NO_MOVE: return Separator(0, 0) if self.clicked and self.hovered: # the mouse is over the button delta = 2 elif self.hovered and not self.flags & self.NO_HOVER: delta = 0 else: delta = 0 return Separator(delta, delta) @property def _bg_delta(self): """Return the offset of the shadow.""" if self.flags and self.NO_MOVE: return Separator(2, 2) if self.clicked and self.hovered: # the mouse is over the button delta = 2 elif self.hovered and not self.flags & self.NO_HOVER: delta = 2 else: delta = 2 return Separator(delta, delta) def update(self, event_or_list): """Update the button with the events.""" for e in super().update(event_or_list): if e.type == MOUSEBUTTONDOWN: if e.pos in self: self.click() else: self.release(force_no_call=True) elif e.type == MOUSEBUTTONUP: self.release(force_no_call=e.pos not in self) elif e.type == MOUSEMOTION: if e.pos in self: self.hovered = True else: self.hovered = False def render(self, surf): """Render the button on a surface.""" pos, size = self.topleft, self.size if not self.flags & self.NO_SHADOW: if self.flags & self.NO_ROUNDING: pygame.draw.rect(surf, LIGHT_GREY, (pos + self._bg_delta, size)) else: roundrect(surf, (pos + self._bg_delta, size), LIGHT_GREY + (100, ), 5) if self.flags & self.NO_ROUNDING: pygame.draw.rect(surf, self._get_color(), (pos + self._front_delta, size)) else: roundrect(surf, (pos + self._front_delta, size), self._get_color(), 5) self.text.center = self.center + self._front_delta self.text.render(surf)