1 // Aseprite
2 // Copyright (C) 2001-2018 David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include <cstdarg>
12 #include <cstdio>
13 #include <vector>
14
15 #include "base/bind.h"
16 #include "base/memory.h"
17 #include "base/string.h"
18 #include "ui/ui.h"
19
20 #include "app/app.h"
21 #include "app/console.h"
22 #include "app/context.h"
23 #include "app/modules/gui.h"
24 #include "app/ui/status_bar.h"
25 #include "ui/system.h"
26
27 namespace app {
28
29 using namespace ui;
30
31 static Window* wid_console = NULL;
32 static Widget* wid_view = NULL;
33 static Widget* wid_textbox = NULL;
34 static Widget* wid_cancel = NULL;
35 static int console_counter = 0;
36 static bool console_locked;
37 static bool want_close_flag = false;
38 static bool has_text = false;
39
Console(Context * ctx)40 Console::Console(Context* ctx)
41 : m_withUI(false)
42 {
43 if (!ui::is_ui_thread())
44 return;
45
46 if (ctx)
47 m_withUI = (ctx->isUIAvailable());
48 else
49 m_withUI =
50 (App::instance() &&
51 App::instance()->isGui() &&
52 Manager::getDefault() &&
53 Manager::getDefault()->getDisplay());
54
55 if (!m_withUI)
56 return;
57
58 if (console_counter == 0)
59 has_text = false;
60
61 console_counter++;
62 if (wid_console || console_counter > 1)
63 return;
64
65 Window* window = new Window(Window::WithTitleBar, "Errors Console");
66 Grid* grid = new Grid(1, false);
67 View* view = new View();
68 TextBox* textbox = new TextBox("", WORDWRAP);
69 Button* button = new Button("&Cancel");
70
71 // The "button" closes the console
72 button->processMnemonicFromText();
73 button->Click.connect(base::Bind<void>(&Window::closeWindow, window, button));
74
75 view->attachToView(textbox);
76
77 button->setMinSize(gfx::Size(60, 0));
78
79 grid->addChildInCell(view, 1, 1, HORIZONTAL | VERTICAL);
80 grid->addChildInCell(button, 1, 1, CENTER);
81 window->addChild(grid);
82
83 view->setVisible(false);
84 button->setFocusMagnet(true);
85 view->setExpansive(true);
86
87 wid_console = window;
88 wid_view = view;
89 wid_textbox = textbox;
90 wid_cancel = button;
91 console_locked = false;
92 want_close_flag = false;
93 }
94
~Console()95 Console::~Console()
96 {
97 if (!m_withUI)
98 return;
99
100 console_counter--;
101
102 if ((wid_console) && (console_counter == 0)) {
103 if (console_locked
104 && !want_close_flag
105 && wid_console->isVisible()) {
106 // Open in foreground
107 wid_console->openWindowInForeground();
108 }
109
110 delete wid_console; // window
111 wid_console = NULL;
112 want_close_flag = false;
113 }
114 }
115
hasText() const116 bool Console::hasText() const
117 {
118 return has_text;
119 }
120
printf(const char * format,...)121 void Console::printf(const char* format, ...)
122 {
123 has_text = true;
124
125 std::va_list ap;
126 va_start(ap, format);
127 std::string msg = base::string_vprintf(format, ap);
128 va_end(ap);
129
130 if (!m_withUI || !wid_console) {
131 fputs(msg.c_str(), stdout);
132 fflush(stdout);
133 return;
134 }
135
136 // Open the window
137 if (!wid_console->isVisible()) {
138 wid_console->openWindow();
139 ui::Manager::getDefault()->invalidate();
140 }
141
142 // Update the textbox
143 if (!console_locked) {
144 console_locked = true;
145
146 wid_view->setVisible(true);
147
148 wid_console->remapWindow();
149 wid_console->setBounds(gfx::Rect(0, 0, ui::display_w()*9/10, ui::display_h()*6/10));
150 wid_console->centerWindow();
151 wid_console->invalidate();
152 }
153
154 const std::string& text = wid_textbox->text();
155
156 std::string final;
157 if (!text.empty())
158 final += text;
159 final += msg;
160
161 wid_textbox->setText(final.c_str());
162 }
163
164 // static
showException(const std::exception & e)165 void Console::showException(const std::exception& e)
166 {
167 Console console;
168 if (typeid(e) == typeid(std::bad_alloc))
169 console.printf("There is not enough memory to complete the action.");
170 else
171 console.printf("A problem has occurred.\n\nDetails:\n%s\n", e.what());
172 }
173
174 } // namespace app
175