File: filled_container_demo.py

package info (click to toggle)
python-enable 4.3.0-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 7,280 kB
  • ctags: 13,899
  • sloc: cpp: 48,447; python: 28,502; ansic: 9,004; makefile: 315; sh: 44
file content (177 lines) | stat: -rw-r--r-- 5,781 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
"""
Shows how to implement a simple drag operation with transitory visual
side-effects that get cleaned up when the drag completes.  There is a
filled container that contains two filled circles, each of which has a
different kind of "shadow" object that it dynamically adds to the
container when the user clicks and drags the circle around.  Because
the shadow objects are "first-class" components in the filled container,
and because containers default to auto-sizing around their components,
the container stretches to the minimum bounding box of its components
as the user drags the circles around.
"""
from numpy import array

from traits.api import Any, Enum, Float, Instance, Tuple
from enable.example_support import DemoFrame, demo_main
from enable.api import Container, Component, Pointer, str_to_font, Window


class MyFilledContainer(Container):

    fit_window = False
    border_width = 2
    resizable = ""
    _font = Any

    def _draw_container_mainlayer(self, gc, view_bounds, mode="default"):
        'Draws a filled container with the word "Container" in the center'
        if not self._font:
            self._font = str_to_font(None, None, "modern 10")

        with gc:
            gc.set_fill_color(self.bgcolor_)
            gc.rect(self.x, self.y, self.width, self.height)
            gc.draw_path()
            self._draw_border(gc)
            gc.set_font(self._font)
            gc.set_fill_color((1.0, 1.0, 1.0, 1.0))
            tx, ty, tw, th = gc.get_text_extent("Container")
            tx = self.x + self.width / 2.0 - tw / 2.0
            ty = self.y + self.height / 2.0 - th / 2.0
            gc.show_text_at_point("Container", tx, ty)

        return


class Circle(Component):
    """
    The circle moves with the mouse cursor but leaves a translucent version of
    itself in its original position until the mouse button is released.
    """
    color = (0.6, 0.7, 1.0, 1.0)
    bgcolor = "none"

    normal_pointer = Pointer("arrow")
    moving_pointer = Pointer("hand")

    prev_x = Float
    prev_y = Float

    shadow_type = Enum("light", "dashed")
    shadow = Instance(Component)

    resizable = ""

    def __init__(self, **traits):
        Component.__init__(self, **traits)
        self.pointer = self.normal_pointer
        return

    def _draw_mainlayer(self, gc, view_bounds=None, mode="default"):
        with gc:
            gc.set_fill_color(self.color)
            dx, dy = self.bounds
            x, y = self.position
            radius = min(dx / 2.0, dy / 2.0)
            gc.arc(x + dx / 2.0, y + dy / 2.0, radius, 0.0, 2 * 3.14159)
            gc.fill_path()
        return

    def normal_left_down(self, event):
        self.event_state = "moving"
        self.pointer = self.moving_pointer
        event.window.set_mouse_owner(self, event.net_transform())

        # Create our shadow
        if self.shadow_type == "light":
            klass = LightCircle
        else:
            klass = DashedCircle
        self.shadow = klass(bounds=self.bounds, position=self.position,
                            color=(1.0, 1.0, 1.0, 1.0))
        self.container.insert(0, self.shadow)
        x, y = self.position
        self.prev_x = event.x
        self.prev_y = event.y
        return

    def moving_mouse_move(self, event):
        self.position = [self.x + (event.x - self.prev_x),
                         self.y + (event.y - self.prev_y)]
        self.prev_x = event.x
        self.prev_y = event.y
        self.request_redraw()
        return

    def moving_left_up(self, event):
        self.event_state = "normal"
        self.pointer = self.normal_pointer
        event.window.set_mouse_owner(None)
        event.window.redraw()
        # Remove our shadow
        self.container.remove(self.shadow)
        return

    def moving_mouse_leave(self, event):
        self.moving_left_up(event)
        return


class LightCircle(Component):

    color = Tuple
    bgcolor = "none"
    radius = Float(1.0)
    resizable = ""

    def _draw_mainlayer(self, gc, view_bounds=None, mode="default"):
        with gc:
            gc.set_fill_color(self.color[0:3] + (self.color[3] * 0.3,))
            dx, dy = self.bounds
            x, y = self.position
            radius = min(dx / 2.0, dy / 2.0)
            gc.arc(x + dx / 2.0, y + dy / 2.0, radius, 0.0, 2 * 3.14159)
            gc.fill_path()
        return


class DashedCircle(Component):

    color = Tuple
    bgcolor = "none"
    radius = Float(1.0)
    line_dash = array([2.0, 2.0])
    resizable = ""

    def _draw_mainlayer(self, gc, view_bounds=None, mode="default"):
        with gc:
            gc.set_fill_color(self.color)
            dx, dy = self.bounds
            x, y = self.position
            radius = min(dx / 2.0, dy / 2.0)
            gc.arc(x + dx / 2.0, y + dy / 2.0, radius, 0.0, 2 * 3.14159)
            gc.set_stroke_color(self.color[0:3] + (self.color[3] * 0.8,))
            gc.set_line_dash(self.line_dash)
            gc.stroke_path()
        return


class MyFrame(DemoFrame):

    def _create_window(self):
        circle1 = Circle(bounds=[75, 75], position=[50, 50],
                         shadow_type="dashed")
        circle2 = Circle(bounds=[75, 75], position=[200, 50],
                         shadow_type="light")
        container = MyFilledContainer(bounds=[500, 500],
                                      bgcolor=(0.5, 0.5, 0.5, 1.0))
        container.auto_size = True
        container.add(circle1)
        container.add(circle2)
        return Window(self, -1, component=container)


if __name__ == "__main__":
    # Save demo so that it doesn't get garbage collected when run within
    # existing event loop (i.e. from ipython).
    demo = demo_main(MyFrame, title="Click and drag to move the circles")