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