Completed
Pull Request — master (#192)
by Marek
01:39
created

pygameui.Application.Application.__init__()   A

Complexity

Conditions 2

Size

Total Lines 34
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 31
nop 3
dl 0
loc 34
rs 9.1359
c 0
b 0
f 0
1
#
2
#  Copyright 2001 - 2016 Ludek Smid [http://www.ospace.net/]
3
#
4
#  This file is part of Pygame.UI.
5
#
6
#  Pygame.UI is free software; you can redistribute it and/or modify
7
#  it under the terms of the Lesser GNU General Public License as published by
8
#  the Free Software Foundation; either version 2.1 of the License, or
9
#  (at your option) any later version.
10
#
11
#  Pygame.UI is distributed in the hope that it will be useful,
12
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
#  Lesser GNU General Public License for more details.
15
#
16
#  You should have received a copy of the Lesser GNU General Public License
17
#  along with Pygame.UI; if not, write to the Free Software
18
#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
#
20
21
import pygame
22
import pygame, pygame.time, pygame.mouse
23
24
import SkinableTheme
25
from Tooltip import Tooltip
26
import Const
27
28
# enable only if you want OpenGL support
29
#try:
30
#    from OpenGL.GL import *
31
#    from OpenGL.GLU import *
32
#except ImportError:
33
#    pass
34
35
def noop():
36
    pass
37
38
class Application:
39
40
    def __init__(self, update = noop, theme = SkinableTheme):
41
        self.theme = theme
42
        self.theme.init()
43
        self.updateFunc = update
44
        self.showBackground = True
45
        self.background = None
46
        self.redrawWidgets = {}
47
        self.cursorPos = (0, 0)
48
        self.windowSurfaceFlags = 0
49
        # status bar widget
50
        self.statusBar = None
51
        self.statusBarText = None
52
        # internal properties
53
        self.locale = 'en'
54
        self.windows = []
55
        self.focusedWindow = None
56
        self.activeWidget = None
57
        self.mouseOverWidget = None
58
        self.mouseOverCount = 0
59
        self.mouseOverThreshold = 3
60
        self.mouseLMBDouble = 0
61
        self.mouseRMBDouble = 0
62
        self.keyEvt = None
63
        self.keyCount = 0
64
        self.tooltip = Tooltip(self)
65
        self.focusedWidget = None
66
        self.cursorOn = 0
67
        self.cursorCount = 0
68
        self._fullUpdate = False
69
        # setup timer
70
        try:
71
             pygame.time.set_timer(Const.TIMEREVENT, 80)
72
        except pygame.error:
73
            pass
74
75
    def getApp(self):
76
        return self
77
78
    def processEvent(self, evt):
79
        if evt.type == pygame.VIDEOEXPOSE:
80
            self.performFullUpdate()
81
        #
82
        if not pygame.key.get_focused():
83
            return Const.NoEvent
84
        elif evt.type == Const.TIMEREVENT:
85
            # tooltips
86
            self.mouseOverCount += 1
87
            if self.mouseOverCount == self.mouseOverThreshold:
88
                # show tooltip
89
                if self.mouseOverWidget:
90
                    self.tooltip.title = self.mouseOverWidget.tooltipTitle
91
                    self.tooltip.text = self.mouseOverWidget.tooltip
92
                    self.tooltip.rect = pygame.Rect(pygame.mouse.get_pos(), (100, 100))
93
            # cursor
94
            self.cursorCount += 1
95
            if self.cursorCount == 5:
96
                self.cursorOn = not self.cursorOn
97
                self.cursorCount = 0
98
                if self.focusedWidget:
99
                    self.focusedWidget.onCursorChanged()
100
            # keyboard repeat
101
            if self.keyEvt:
102
                self.keyCount += 1
103
                if self.keyCount == 6:
104
                    self.processEvent(self.keyEvt)
105
                    self.keyCount = 4
106
            return Const.NoEvent
107
        elif evt.type == pygame.MOUSEBUTTONDOWN:
108
            # mouse wheel
109
            if evt.button == 4 or evt.button == 5:
110
                # TODO find window to deliver mouse wheel events to
111
                if self.focusedWindow:
112
                    if self.focusedWindow.rect.collidepoint(evt.pos):
113
                        if evt.button == 4:
114
                            return self.focusedWindow.processMWUp(evt)
115
                        elif evt.button == 5:
116
                            return self.focusedWindow.processMWDown(evt)
117
                else:
118
                    return evt
119
                return Const.NoEvent
120
            # TODO double click
121
            # check if focused window is top level one
122
            if self.focusedWindow != self.windows[-1]:
123
                window = self.focusedWindow
124
                self.focusWindowAt(evt)
125
                # consume event, when focus has been changed
126
                if self.focusedWindow != window:
127
                    return Const.NoEvent
128
            # left and right mouse button
129
            if self.focusedWindow:
130
                if self.focusedWindow.rect.collidepoint(evt.pos):
131
                    if evt.button == 1:
132
                        return self.focusedWindow.processMB1Down(evt)
133
                    elif evt.button == 3:
134
                        return self.focusedWindow.processMB3Down(evt)
135
                elif self.focusedWindow.modal:
136
                    return Const.NoEvent
137
                elif self.focusedWindow.looseFocusClose:
138
                    self.focusedWindow.hide()
139
                    return self.focusWindowAt(evt)
140
                else:
141
                    return self.focusWindowAt(evt)
142
            else:
143
                return self.focusWindowAt(evt)
144
            return evt
145
        elif evt.type == pygame.MOUSEBUTTONUP:
146
            # left and right mouse button
147
            if self.focusedWindow and self.focusedWindow.rect.collidepoint(evt.pos):
148
                if evt.button == 1:
149
                    return self.focusedWindow.processMB1Up(evt)
150
                elif evt.button == 3:
151
                    return self.focusedWindow.processMB3Up(evt)
152
            return evt
153
        elif evt.type == pygame.MOUSEMOTION:
154
            if self.mouseOverCount < self.mouseOverThreshold:
155
                # just moving across widget does not trigger tooltip
156
                self.mouseOverCount = 0
157
            self.cursorPos = evt.pos
158
            if self.focusedWindow:
159
                return self.focusedWindow.processMMotion(evt)
160
            return evt
161
        elif evt.type == pygame.KEYDOWN:
162
            self.keyEvt = evt
163
            self.keyCount = 0
164
            if self.focusedWidget:
165
                evt = self.focusedWidget.processKeyDown(evt)
166
            if evt != Const.NoEvent and self.focusedWindow:
167
                evt = self.focusedWindow.processKeyDown(evt)
168
            return evt
169
        elif evt.type == pygame.KEYUP:
170
            self.keyEvt = None
171
            if self.focusedWidget:
172
                evt = self.focusedWidget.processKeyUp(evt)
173
            if evt != Const.NoEvent and self.focusedWindow:
174
                evt = self.focusedWindow.processKeyUp(evt)
175
            return evt
176
        else:
177
            return evt
178
179
    def registerWindow(self, window):
180
        self.windows.append(window)
181
        self._fullUpdate = True
182
183
    def unregisterWindow(self, window):
184
        if window == self.focusedWindow:
185
            self.focusedWindow.hide()
186
        self.windows.remove(window)
187
        self._fullUpdate = True
188
189
    def moveWindowToFront(self, window):
190
        self.focusWindow(window)
191
        if window in self.windows:
192
            self.windows.remove(window)
193
        self.windows.append(window)
194
        self.performFullUpdate()
195
196
    def focusWindow(self, window):
197
        if self.focusedWindow:
198
            self.focusedWindow.focused = 0
199
        self.focusedWindow = window
200
        self.setFocus(None)
201
        if self.focusedWindow:
202
            self.focusedWindow.focused = 1
203
204
    def hideWindow(self, window):
205
        window.visible = 0
206
        self.performFullUpdate()
207
        self._fullUpdate = True
208
        if self.focusedWindow == window:
209
            self.focusedWindow.focused = 0
210
            self.focusedWindow = None
211
            # also unfocus widget
212
            self.setFocus(None)
213
            # find new window to focus
214
            index = len(self.windows) - 1
215
            while index >= 0:
216
                window = self.windows[index]
217
                if window.visible:
218
                    window.toFront()
219
                    return
220
                index -= 1
221
222
    def focusWindowAt(self, evt):
223
        # find window which has been clicked in
224
        index = len(self.windows) - 1
225
        while index >= 0:
226
            window = self.windows[index]
227
            if window.visible and window.rect.collidepoint(evt.pos):
228
                window.toFront()
229
                return Const.NoEvent
230
            index -= 1
231
        return evt
232
233
    def setFocus(self, widget):
234
        if self.focusedWidget != widget:
235
            if self.focusedWidget:
236
                self.focusedWidget.onFocusLost()
237
            self.focusedWidget = widget
238
            if widget:
239
                widget.onFocusGained()
240
241
    def setMouseOver(self, widget):
242
        if self.mouseOverWidget != widget:
243
            if self.mouseOverWidget:
244
                self.mouseOverWidget.onMouseOut()
245
                self.tooltip.text = None
246
                self.tooltip.title = None
247
                self.performFullUpdate()
248
            self.mouseOverWidget = widget
249
            self.mouseOverCount = 0
250
            if widget:
251
                widget.onMouseOver()
252
                self.tooltip.text = None
253
                self.tooltip.title = None
254
                self.performFullUpdate()
255
                widget.parent.setTempStatus(widget.statustip)
256
                return
257
            self.setTempStatus(None)
258
259
    def setStatus(self, text):
260
        self.statusBarText = text
261
        if self.statusBar:
262
            self.statusBar.text = text
263
        self.update()
264
265
    def setTempStatus(self, text):
266
        if self.statusBar:
267
            if text:
268
                self.statusBar.text = text
269
            else:
270
                self.statusBar.text = self.statusBarText
271
272
    def draw(self, surface):
273
        """Draw all windows onto supplied surface."""
274
        if self.showBackground:
275
            surface.blit(self.background, (0, 0))
276
        changed = []
277
        #@print "App Draw"
278
        for window in self.windows:
279
            if window.visible:
280
                if self.showBackground:
281
                    window._fullUpdate = True
282
                rect = window.draw(surface)
283
                #@print " ", window, rect
284
                if rect: changed.append(rect)
285
                window.__dict__['_changeReported'] = 0
286
            else:
287
                #@print " ", window, "invisible"
288
                pass
289
        if self.tooltip.title or self.tooltip.text:
290
            title, body = self.theme.drawTooltip(surface, self.tooltip)
291
            changed.append(title)
292
            changed.append(body)
293
        self.tooltip.__dict__['_changeReported'] = 0
294
        self.redrawWidgets = {}
295
        #@print "CHANGED", changed
296
        if self._fullUpdate or self.showBackground:
297
            #@print "FULL UPDATE"
298
            self._fullUpdate = False
299
            return [pygame.display.get_surface().get_rect()]
300
        return changed
301
302
    def drawOpenGL(self):
303
        for window in self.windows:
304
            if window.visible:
305
                window.draw(None)
306
                bitmap = pygame.image.tostring(window.surface, "RGBA", 1)
307
                width, height = window.surface.get_size()
308
                scrW, scrH = pygame.display.get_surface().get_size()
309
                x, y = window.rect.bottomleft
310
                glRasterPos2i(x, scrH - y)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable glRasterPos2i does not seem to be defined.
Loading history...
311
                glDrawPixels(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable glDrawPixels does not seem to be defined.
Loading history...
312
                    width, height,
313
                    GL_RGBA,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable GL_RGBA does not seem to be defined.
Loading history...
314
                    GL_UNSIGNED_BYTE,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable GL_UNSIGNED_BYTE does not seem to be defined.
Loading history...
315
                    bitmap,
316
                )
317
        glFlush()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable glFlush does not seem to be defined.
Loading history...
318
319
    def performFullUpdate(self):
320
        for window in self.windows:
321
            window._fullUpdate = True
322
323
    def drawCursor(self, surface):
324
        self.theme.drawCursor(surface, self.cursorPos)
325
326
    def update(self):
327
        if self.updateFunc:
328
            self.updateFunc()
329
330
    def redraw(self, widget, redrawParent = 0):
331
        self.redrawWidgets[widget] = None
332
333
    def needsUpdate(self):
334
        return len(self.redrawWidgets) > 0
335
336
    def exitLocal(self):
337
        evt = pygame.event.Event(Const.USEREVENT)
338
        evt.action = "localExit"
339
        pygame.event.post(evt)
340
341
    def exit(self):
342
        pygame.event.post(pygame.event.Event(pygame.QUIT))
343
344
    def processAction(self, actionName, data = None, widget = None):
345
        """ There are no application wide actions supported yet."""
346
        return
347