or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

3d-models.mdapp-clock.mdaudio-video.mdgraphics-rendering.mdgui.mdimages-textures.mdindex.mdinput-devices.mdmath.mdopengl.mdresource-management.mdsprites-shapes.mdtext-rendering.mdwindowing.md
IMPROVEMENTS.md

gui.mddocs/

0

# GUI Widgets

1

2

Interactive UI components: buttons, sliders, text entry, and containers.

3

4

## Quick Reference

5

6

```python

7

from pyglet import gui

8

9

# Frame (manages widget events)

10

frame = gui.Frame(window)

11

12

# Button

13

button = gui.PushButton(x=100, y=100, pressed=pressed_img, unpressed=unpressed_img)

14

frame.add_widget(button)

15

16

@button.event

17

def on_press():

18

print("Button pressed!")

19

20

# Slider

21

slider = gui.Slider(x=100, y=50, base=base_img, knob=knob_img)

22

frame.add_widget(slider)

23

24

@slider.event

25

def on_change(value):

26

print(f"Value: {value}")

27

28

# Text entry

29

text_entry = gui.TextEntry('Initial text', x=100, y=150, width=200)

30

frame.add_widget(text_entry)

31

```

32

33

## Frame

34

35

```python

36

class pyglet.gui.Frame:

37

"""Container managing widget event dispatching"""

38

__init__(window, enable=True, cell_size=64, order=0)

39

40

# Methods

41

def add_widget(widget)

42

def remove_widget(widget)

43

44

# Properties

45

enable: bool # Enable/disable event handling

46

widgets: list # All managed widgets

47

```

48

49

## Buttons

50

51

```python

52

class pyglet.gui.PushButton(WidgetBase):

53

"""Clickable button"""

54

__init__(x, y, pressed, unpressed, hover=None, batch=None, group=None)

55

56

# Properties

57

value: bool # Current pressed state

58

enabled: bool

59

60

# Events

61

@button.event

62

def on_press():

63

"""Button pressed"""

64

65

@button.event

66

def on_release():

67

"""Button released"""

68

69

class pyglet.gui.ToggleButton(PushButton):

70

"""Button with on/off state"""

71

# Same as PushButton but maintains toggle state

72

```

73

74

## Slider

75

76

```python

77

class pyglet.gui.Slider(WidgetBase):

78

"""Horizontal slider"""

79

__init__(x, y, base, knob, edge=0, batch=None, group=None)

80

81

# Properties

82

value: float # 0.0 to 1.0

83

min, max: float # Value range

84

enabled: bool

85

86

# Events

87

@slider.event

88

def on_change(value):

89

"""Value changed"""

90

```

91

92

## Text Entry

93

94

```python

95

class pyglet.gui.TextEntry(WidgetBase):

96

"""Single-line text input"""

97

__init__(text, x, y, width, color=(255,255,255,255), text_color=(0,0,0,255),

98

caret_color=(0,0,0), batch=None, group=None)

99

100

# Properties

101

text: str

102

focus: bool # Has keyboard focus

103

enabled: bool

104

105

# Events

106

@text_entry.event

107

def on_commit(text):

108

"""Enter pressed"""

109

```

110

111

## NinePatch

112

113

```python

114

class pyglet.gui.NinePatch:

115

"""Scalable UI element from 9-slice image"""

116

__init__(texture_region, left, right, top, bottom)

117

118

def get_subregion(x, y, width, height) -> TextureRegion

119

```

120

121

## Widget Base

122

123

All widgets inherit from:

124

125

```python

126

class pyglet.gui.WidgetBase:

127

"""Base widget class"""

128

129

# Properties

130

x, y: int

131

width, height: int

132

enabled: bool

133

batch: Batch

134

group: Group

135

136

# Events

137

def on_mouse_press(x, y, button, modifiers)

138

def on_mouse_release(x, y, button, modifiers)

139

def on_mouse_drag(x, y, dx, dy, buttons, modifiers)

140

def on_mouse_motion(x, y, dx, dy)

141

```

142

143

## Examples

144

145

### Button Grid

146

```python

147

from pyglet import gui, image, graphics

148

149

window = pyglet.window.Window()

150

batch = graphics.Batch()

151

frame = gui.Frame(window)

152

153

# Load button images

154

pressed = image.load('button_pressed.png')

155

unpressed = image.load('button_unpressed.png')

156

157

# Create button grid

158

buttons = []

159

for row in range(3):

160

for col in range(3):

161

x = 50 + col * 120

162

y = 400 - row * 80

163

button = gui.PushButton(x, y, pressed, unpressed, batch=batch)

164

button.id = row * 3 + col

165

frame.add_widget(button)

166

buttons.append(button)

167

168

@button.event

169

def on_press(btn=button):

170

print(f"Button {btn.id} pressed")

171

172

@window.event

173

def on_draw():

174

window.clear()

175

batch.draw()

176

177

pyglet.app.run()

178

```

179

180

### Volume Slider

181

```python

182

slider = gui.Slider(x=100, y=100, base=base_img, knob=knob_img, batch=batch)

183

frame.add_widget(slider)

184

185

@slider.event

186

def on_change(value):

187

# value is 0.0 to 1.0

188

music_player.volume = value

189

volume_label.text = f"Volume: {int(value * 100)}%"

190

```

191

192

### Text Input Dialog

193

```python

194

text_entry = gui.TextEntry(

195

'Enter name...',

196

x=100, y=200, width=300,

197

batch=batch

198

)

199

frame.add_widget(text_entry)

200

text_entry.focus = True

201

202

@text_entry.event

203

def on_commit(text):

204

print(f"Submitted: {text}")

205

text_entry.text = '' # Clear

206

207

@window.event

208

def on_key_press(symbol, modifiers):

209

if symbol == pyglet.window.key.ESCAPE:

210

text_entry.focus = False

211

```

212

213

### Custom Widget

214

```python

215

class CustomButton(gui.WidgetBase):

216

def __init__(self, x, y, width, height, text):

217

super().__init__(x, y, width, height)

218

self.text = text

219

self.pressed = False

220

221

# Create visual elements

222

self.bg = pyglet.shapes.Rectangle(

223

x, y, width, height,

224

color=(100, 100, 200)

225

)

226

self.label = pyglet.text.Label(

227

text,

228

x=x + width//2, y=y + height//2,

229

anchor_x='center', anchor_y='center'

230

)

231

232

def on_mouse_press(self, x, y, button, modifiers):

233

if self._check_hit(x, y):

234

self.pressed = True

235

self.bg.color = (150, 150, 255)

236

self.dispatch_event('on_press')

237

238

def on_mouse_release(self, x, y, button, modifiers):

239

if self.pressed:

240

self.pressed = False

241

self.bg.color = (100, 100, 200)

242

243

def _check_hit(self, x, y):

244

return (self.x <= x <= self.x + self.width and

245

self.y <= y <= self.y + self.height)

246

247

CustomButton.register_event_type('on_press')

248

```

249

250

## Common Patterns

251

252

### Menu System

253

```python

254

class Menu:

255

def __init__(self, window):

256

self.window = window

257

self.frame = gui.Frame(window)

258

self.batch = pyglet.graphics.Batch()

259

self.buttons = []

260

261

def add_button(self, text, callback, y_offset):

262

# Create button (simplified)

263

button = gui.PushButton(

264

x=window.width // 2 - 100,

265

y=window.height // 2 + y_offset,

266

pressed=pressed_img,

267

unpressed=unpressed_img,

268

batch=self.batch

269

)

270

button.callback = callback

271

self.frame.add_widget(button)

272

self.buttons.append(button)

273

274

@button.event

275

def on_press():

276

callback()

277

278

def draw(self):

279

self.batch.draw()

280

281

# Usage

282

menu = Menu(window)

283

menu.add_button("Start", lambda: print("Start game"), 50)

284

menu.add_button("Options", lambda: print("Options"), 0)

285

menu.add_button("Quit", lambda: pyglet.app.exit(), -50)

286

```

287

288

## Performance Tips

289

290

1. **Use batching**: Add widgets to a Batch

291

2. **Frame overhead**: Frame uses spatial hashing for efficient hit testing

292

3. **Disable when hidden**: Set `enabled=False` on hidden widgets

293

4. **Custom widgets**: Inherit from WidgetBase for consistency

294

295

## Common Issues

296

297

1. **Events not firing**: Ensure widget added to Frame

298

2. **Z-order**: Later widgets drawn on top

299

3. **Focus**: Only one TextEntry can have focus

300

4. **Hit testing**: Widgets use rectangular bounds

301

5. **Image requirements**: Button needs at least pressed/unpressed images

302