1import sys
2import time
3
4from arcade.glui.dialog import Dialog
5from arcade.glui.opengl import gl
6from arcade.glui.render import Render
7from arcade.glui.state import State
8from arcade.resources import resources
9
10MAX_LINE = 30
11
12
13def show_exception():
14    import traceback
15
16    backtrace = traceback.format_exc()
17    State.get().dialog = ErrorDialog(sys.exc_info()[1], backtrace)
18    show_error_state = {"stop": False}
19    while not show_error_state["stop"]:
20
21        def input_func(button):
22            if button == "BACK":
23                show_error_state["stop"] = True
24
25        # FIXME
26        from arcade.glui.window import main_loop_iteration
27
28        if main_loop_iteration(input_func=input_func):
29            break
30    State.get().dialog.destroy()
31    State.get().dialog = None
32
33
34class ErrorDialog(Dialog):
35    def __init__(self, message, backtrace=None):
36        Dialog.__init__(self)
37        self.width = 16 / 9 * 2
38        self.height = 2.0
39        self.message = message
40        self.backtrace = backtrace
41        self.splitted = self.backtrace.split("\n")
42        if not self.splitted[-1]:
43            self.splitted = self.splitted[:-1]
44
45        self.background_color = (0.0, 0.0, 0.0, 1.0)
46        liberation_mono_bold = resources.resource_filename(
47            "LiberationMono-Regular.ttf"
48        )
49        self.detail_font = pygame.font.Font(
50            liberation_mono_bold, int(0.021 * Render.get().display_height)
51        )
52        self.guru_font = pygame.font.Font(
53            liberation_mono_bold, int(0.03 * Render.get().display_height)
54        )
55        self.start_time = time.time()
56
57    def render_content(self):
58        Render.get().dirty = True
59
60        # #x1 = -16 / 9 + 0.1
61        # x1 = 0.1
62        # #x2 = 16 / 9 - 0.1
63        # x2 = self.width - 0.1
64        # #y1 = 0.7
65        # #y2 = 0.9
66        # y1 = 1.6
67        # y2 = 1.9
68        x1 = 0
69        x2 = self.width
70        y1 = 1.7
71        y2 = 2.0
72        w = 0.03
73
74        # t = (pygame.time.get_ticks() - self.start_time) // 1000
75        alert_color = (1.0, 0.8, 0.0)
76        t = int((time.time() - self.start_time * 1.6))
77        if t % 2 == 0:
78            gl.glBegin(gl.GL_QUADS)
79            gl.glColor3f(*alert_color)
80            gl.glVertex2f(x1, y1)
81            gl.glVertex2f(x2, y1)
82            gl.glVertex2f(x2, y2)
83            gl.glVertex2f(x1, y2)
84            gl.glColor3f(0.0, 0.0, 0.0)
85            gl.glVertex2f(x1 + w, y1 + w)
86            gl.glVertex2f(x2 - w, y1 + w)
87            gl.glVertex2f(x2 - w, y2 - w)
88            gl.glVertex2f(x1 + w, y2 - w)
89            gl.glEnd()
90
91        text = "Software Failure.  Press BACKSPACE or back button to continue."
92        Render.get().text(text, self.guru_font, 0.2, 1.85, color=alert_color)
93        text = self.splitted[-1]
94        text = "Guru Meditation #{0}".format(text)
95        Render.get().text(text, self.guru_font, 0.2, 1.77, color=alert_color)
96
97        x = 0.2
98        y = 0.15
99
100        tw, th = Render.get().measure_text("M", self.detail_font)
101        y += th
102        lines = []
103        max_line_size = 129
104        for line in self.splitted:
105            line = line.rstrip()
106            while len(line) > max_line_size:
107                lines.append(line[:max_line_size])
108                line = line[max_line_size:]
109            lines.append(line)
110
111        for i, line in enumerate(reversed(lines)):
112            if i == MAX_LINE:
113                break
114            s = (MAX_LINE - i) / MAX_LINE
115            tw, th = Render.get().text(
116                line, self.detail_font, x, y, color=(s, s, s, 1.0)
117            )
118            y += th
119