1#!/usr/bin/env python
2
3"""Demonstrates basic use of IncrementalTextLayout and Caret.
4
5A simple widget-like system is created in this example supporting keyboard and
6mouse focus.
7"""
8
9__docformat__ = 'restructuredtext'
10__version__ = '$Id: $'
11
12import pyglet
13
14
15class Rectangle:
16    """Draws a rectangle into a batch."""
17    def __init__(self, x1, y1, x2, y2, batch):
18        self.vertex_list = batch.add(4, pyglet.gl.GL_QUADS, None,
19                                     ('v2i', [x1, y1, x2, y1, x2, y2, x1, y2]),
20                                     ('c4B', [200, 200, 220, 255] * 4))
21
22
23class TextWidget:
24    def __init__(self, text, x, y, width, batch):
25        self.document = pyglet.text.document.UnformattedDocument(text)
26        self.document.set_style(0, len(self.document.text), dict(color=(0, 0, 0, 255)))
27        font = self.document.get_font()
28        height = font.ascent - font.descent
29
30        self.layout = pyglet.text.layout.IncrementalTextLayout(
31            self.document, width, height, multiline=False, batch=batch)
32        self.caret = pyglet.text.caret.Caret(self.layout)
33
34        self.layout.x = x
35        self.layout.y = y
36
37        # Rectangular outline
38        pad = 2
39        self.rectangle = Rectangle(x - pad, y - pad,
40                                   x + width + pad, y + height + pad, batch)
41
42    def hit_test(self, x, y):
43        return (0 < x - self.layout.x < self.layout.width and
44                0 < y - self.layout.y < self.layout.height)
45
46
47class Window(pyglet.window.Window):
48    def __init__(self, *args, **kwargs):
49        super(Window, self).__init__(400, 140, caption='Text entry')
50
51        self.batch = pyglet.graphics.Batch()
52        self.labels = [
53            pyglet.text.Label('Name', x=10, y=100, anchor_y='bottom',
54                              color=(0, 0, 0, 255), batch=self.batch),
55            pyglet.text.Label('Species', x=10, y=60, anchor_y='bottom',
56                              color=(0, 0, 0, 255), batch=self.batch),
57            pyglet.text.Label('Special abilities', x=10, y=20,
58                              anchor_y='bottom', color=(0, 0, 0, 255),
59                              batch=self.batch)
60        ]
61        self.widgets = [
62            TextWidget('', 200, 100, self.width - 210, self.batch),
63            TextWidget('', 200, 60, self.width - 210, self.batch),
64            TextWidget('', 200, 20, self.width - 210, self.batch)
65        ]
66        self.text_cursor = self.get_system_mouse_cursor('text')
67
68        self.focus = None
69        self.set_focus(self.widgets[0])
70
71    def on_resize(self, width, height):
72        super(Window, self).on_resize(width, height)
73        for widget in self.widgets:
74            widget.width = width - 110
75
76    def on_draw(self):
77        pyglet.gl.glClearColor(1, 1, 1, 1)
78        self.clear()
79        self.batch.draw()
80
81    def on_mouse_motion(self, x, y, dx, dy):
82        for widget in self.widgets:
83            if widget.hit_test(x, y):
84                self.set_mouse_cursor(self.text_cursor)
85                break
86        else:
87            self.set_mouse_cursor(None)
88
89    def on_mouse_press(self, x, y, button, modifiers):
90        for widget in self.widgets:
91            if widget.hit_test(x, y):
92                self.set_focus(widget)
93                break
94        else:
95            self.set_focus(None)
96
97        if self.focus:
98            self.focus.caret.on_mouse_press(x, y, button, modifiers)
99
100    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
101        if self.focus:
102            self.focus.caret.on_mouse_drag(x, y, dx, dy, buttons, modifiers)
103
104    def on_text(self, text):
105        if self.focus:
106            self.focus.caret.on_text(text)
107
108    def on_text_motion(self, motion):
109        if self.focus:
110            self.focus.caret.on_text_motion(motion)
111
112    def on_text_motion_select(self, motion):
113        if self.focus:
114            self.focus.caret.on_text_motion_select(motion)
115
116    def on_key_press(self, symbol, modifiers):
117        if symbol == pyglet.window.key.TAB:
118            if modifiers & pyglet.window.key.MOD_SHIFT:
119                direction = -1
120            else:
121                direction = 1
122
123            if self.focus in self.widgets:
124                i = self.widgets.index(self.focus)
125            else:
126                i = 0
127                direction = 0
128
129            self.set_focus(self.widgets[(i + direction) % len(self.widgets)])
130
131        elif symbol == pyglet.window.key.ESCAPE:
132            pyglet.app.exit()
133
134    def set_focus(self, focus):
135        if focus is self.focus:
136            return
137
138        if self.focus:
139            self.focus.caret.visible = False
140            self.focus.caret.mark = self.focus.caret.position = 0
141
142        self.focus = focus
143        if self.focus:
144            self.focus.caret.visible = True
145
146
147window = Window(resizable=True)
148pyglet.app.run()
149