1#!/usr/bin/env python3 2 3""" 4Widgets that don't really fit into any of the other categories. 5""" 6 7import pyglet 8import autoprop 9 10from vecrec import Vector, Rect 11from glooey import drawing 12from glooey.widget import Widget 13from glooey.images import Background 14from glooey.text import Label 15from glooey.helpers import * 16 17@autoprop 18class Spacer(Widget): 19 20 def __init__(self, min_width=0, min_height=0): 21 super().__init__() 22 self._min_width = min_width 23 self._min_height = min_height 24 25 def do_claim(self): 26 return self._min_width, self._min_height 27 28 29@autoprop 30class Placeholder(Widget): 31 custom_color = 'green' 32 custom_alignment = 'fill' 33 34 def __init__(self, min_width=0, min_height=0, color=None, align=None): 35 super().__init__() 36 self._color = color or self.custom_color 37 self._min_width = min_width 38 self._min_height = min_height 39 self.vertex_list = None 40 self.alignment = align or self.custom_alignment 41 42 def do_claim(self): 43 return self._min_width, self._min_height 44 45 def do_regroup(self): 46 if self.vertex_list is not None: 47 self.batch.migrate( 48 self.vertex_list, pyglet.gl.GL_LINES, 49 self.group, self.batch) 50 51 def do_draw(self): 52 if self.vertex_list is None: 53 self.vertex_list = self.batch.add( 54 12, pyglet.gl.GL_LINES, self.group, 'v2f', 'c4B') 55 56 # Shrink the rectangle by half-a-pixel so there's no ambiguity about 57 # where the line should be drawn. (The problem is that the widget rect 58 # is always rounded to the nearest pixel, but OpenGL doesn't seem 59 # deterministic about which side of the pixel it draws the line on.) 60 rect = self.rect.get_shrunk(0.5) 61 top_left = rect.top_left 62 top_right = rect.top_right 63 bottom_left = rect.bottom_left 64 bottom_right = rect.bottom_right 65 66 # Originally I used GL_LINE_STRIP, but I couldn't figure out how to 67 # stop the place holders from connecting to each other (i.e. I couldn't 68 # figure out how to break the line strip). Now I'm just using GL_LINES 69 # instead. 70 71 self.vertex_list.vertices = ( 72 # The outline. Add one to the bottom right coordinate. I 73 # don't know why this is necessary, but without it the pixel in 74 # the bottom-right corner doesn't get filled in. 75 bottom_left.tuple + (bottom_right + (1,0)).tuple + 76 bottom_right.tuple + top_right.tuple + 77 top_right.tuple + top_left.tuple + 78 top_left.tuple + bottom_left.tuple + 79 80 # The cross 81 bottom_left.tuple + top_right.tuple + 82 bottom_right.tuple + top_left.tuple 83 ) 84 color = drawing.Color.from_anything(self.color) 85 self.vertex_list.colors = 12 * color.tuple 86 87 def do_undraw(self): 88 if self.vertex_list is not None: 89 self.vertex_list.delete() 90 self.vertex_list = None 91 92 def get_color(self): 93 return self._color 94 95 def set_color(self, new_color): 96 self._color = new_color 97 self._draw() 98 99 def get_min_width(self): 100 return self._min_width 101 102 def set_min_width(self, new_width): 103 self._min_width = new_width 104 self._repack() 105 106 def get_min_height(self): 107 return self._min_height 108 109 def set_min_height(self, new_height): 110 self._min_height = new_height 111 self._repack() 112 113 114@autoprop 115class EventLogger(Placeholder): 116 117 def on_click(self, widget): 118 print(f'{self}.on_click(widget={widget})') 119 120 def on_double_click(self, widget): 121 print(f'{self}.on_double_click(widget={widget})') 122 123 def on_rollover(self, widget, new_state, old_state): 124 print(f'{self}.on_rollover(new_state={new_state}, old_state={old_state})') 125 126 def on_mouse_press(self, x, y, button, modifiers): 127 super().on_mouse_press(x, y, button, modifiers) 128 print(f'{self}.on_mouse_press(x={x}, y={y}, button={button}, modifiers={modifiers})') 129 130 def on_mouse_release(self, x, y, button, modifiers): 131 super().on_mouse_release(x, y, button, modifiers) 132 print(f'{self}.on_mouse_release(x={x}, y={y}, button={button}, modifiers={modifiers})') 133 134 def on_mouse_hold(self, dt): 135 print(f'{self}.on_mouse_hold(dt={dt})') 136 137 def on_mouse_motion(self, x, y, dx, dy): 138 super().on_mouse_motion(x, y, dx, dy) 139 print(f'{self}.on_mouse_motion(x={x}, y={y}, dx={dx}, dy={dy})') 140 141 def on_mouse_enter(self, x, y): 142 super().on_mouse_enter(x, y) 143 print(f'{self}.on_mouse_enter(x={x}, y={y})') 144 145 def on_mouse_leave(self, x, y): 146 super().on_mouse_leave(x, y) 147 print(f'{self}.on_mouse_leave(x={x}, y={y})') 148 149 def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): 150 super().on_mouse_drag(x, y, dx, dy, buttons, modifiers) 151 print(f'{self}.on_mouse_drag(x={x}, y={y}, dx={dx}, dy={dy}, buttons={buttons}, modifiers={modifiers})') 152 153 def on_mouse_drag_enter(self, x, y): 154 super().on_mouse_drag_enter(x, y) 155 print(f'{self}.on_mouse_drag_enter(x={x}, y={y})') 156 157 def on_mouse_drag_leave(self, x, y): 158 super().on_mouse_drag_leave(x, y) 159 print(f'{self}.on_mouse_drag_leave(x={x}, y={y})') 160 161 def on_mouse_scroll(self, x, y, scroll_x, scroll_y): 162 super().on_mouse_scroll(x, y, scroll_x, scroll_y) 163 print(f'{self}.on_mouse_scroll(x={x}, y={y}, scroll_x={scroll_x}, scroll_y={scroll_y})') 164 165 166@autoprop 167class LoremIpsum(Label): 168 169 def __init__(self, num_sentences=None, num_paragraphs=None, line_wrap=300, **style): 170 text = drawing.lorem_ipsum(num_sentences, num_paragraphs) 171 super().__init__(text, line_wrap=line_wrap, **style) 172 173 174@autoprop 175class FillBar(Widget): 176 Base = Background 177 Fill = Background 178 179 def __init__(self, fraction_filled=0): 180 super().__init__() 181 182 self._base = self.Base() 183 self._fill = self.Fill() 184 self._fill_fraction = fraction_filled 185 self._fill_group = None 186 187 self._attach_child(self._base) 188 self._attach_child(self._fill) 189 190 def do_claim(self): 191 min_width = max(self.base.claimed_width, self.fill.claimed_width) 192 min_height = max(self.base.claimed_height, self.fill.claimed_height) 193 return min_width, min_height 194 195 def do_resize(self): 196 self._update_fill() 197 198 def do_regroup_children(self): 199 base_layer = pyglet.graphics.OrderedGroup(1, self.group) 200 fill_layer = pyglet.graphics.OrderedGroup(2, self.group) 201 202 self._fill_group = drawing.ScissorGroup(parent=fill_layer) 203 self._update_fill() 204 205 self._base._regroup(base_layer) 206 self._fill._regroup(self._fill_group) 207 208 def do_draw(self): 209 self._update_fill() 210 211 def get_fill(self): 212 return self._fill 213 214 def get_base(self): 215 return self._base 216 217 def get_fraction_filled(self): 218 return self._fill_fraction 219 220 def set_fraction_filled(self, new_fraction): 221 self._fill_fraction = new_fraction 222 self._update_fill() 223 224 def _update_fill(self): 225 if self._fill_group and self.fill.rect: 226 self._fill_group.rect = self.fill.rect.copy() 227 self._fill_group.rect.width *= self._fill_fraction 228 229 230