1// Aseprite
2// Copyright (C) 2020-2022 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#ifndef ENABLE_SCRIPTING
13 #error ENABLE_SCRIPTING must be defined
14#endif
15
16#include "app/ui/devconsole_view.h"
17
18#include "app/app.h"
19#include "app/app_menus.h"
20#include "app/ui/skin/skin_theme.h"
21#include "app/ui/workspace.h"
22#include "fmt/format.h"
23#include "ui/entry.h"
24#include "ui/message.h"
25#include "ui/system.h"
26#include "ui/textbox.h"
27#include "ui/view.h"
28#include "ver/info.h"
29
30namespace app {
31
32using namespace ui;
33using namespace app::skin;
34
35class DevConsoleView::CommmandEntry : public Entry {
36public:
37 CommmandEntry() : Entry(256, "") {
38 setFocusStop(true);
39 setFocusMagnet(true);
40 }
41
42 obs::signal<void(const std::string&)> ExecuteCommand;
43
44protected:
45 bool onProcessMessage(Message* msg) override {
46 switch (msg->type()) {
47 case kKeyDownMessage:
48 if (hasFocus()) {
49 KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
50 KeyScancode scancode = keymsg->scancode();
51
52 switch (scancode) {
53 case kKeyEnter:
54 case kKeyEnterPad: {
55 std::string cmd = text();
56 ExecuteCommand(cmd);
57 setText("");
58 return true;
59 }
60 }
61 }
62 break;
63 }
64 return Entry::onProcessMessage(msg);
65 }
66};
67
68DevConsoleView::DevConsoleView()
69 : Box(VERTICAL)
70 , m_textBox(fmt::format("Welcome to {} v{} Console\n(Experimental)",
71 get_app_name(), get_app_version()), LEFT)
72 , m_label(">")
73 , m_entry(new CommmandEntry)
74 , m_engine(App::instance()->scriptEngine())
75{
76 m_engine->setDelegate(this);
77
78 addChild(&m_view);
79 addChild(&m_bottomBox);
80
81 m_bottomBox.addChild(&m_label);
82 m_bottomBox.addChild(m_entry);
83
84 m_view.attachToView(&m_textBox);
85 m_view.setExpansive(true);
86
87 m_entry->setExpansive(true);
88 m_entry->ExecuteCommand.connect(&DevConsoleView::onExecuteCommand, this);
89
90 InitTheme.connect(
91 [this]{
92 auto theme = SkinTheme::get(this);
93 m_view.setStyle(theme->styles.workspaceView());
94 });
95 initTheme();
96}
97
98DevConsoleView::~DevConsoleView()
99{
100 m_engine->setDelegate(nullptr);
101
102 // m_document->remove_observer(this);
103 // delete m_editor;
104}
105
106std::string DevConsoleView::getTabText()
107{
108 return "Console";
109}
110
111TabIcon DevConsoleView::getTabIcon()
112{
113 return TabIcon::NONE;
114}
115
116gfx::Color DevConsoleView::getTabColor()
117{
118 return gfx::ColorNone;
119}
120
121WorkspaceView* DevConsoleView::cloneWorkspaceView()
122{
123 return new DevConsoleView();
124}
125
126void DevConsoleView::onWorkspaceViewSelected()
127{
128 m_entry->requestFocus();
129}
130
131bool DevConsoleView::onCloseView(Workspace* workspace, bool quitting)
132{
133 workspace->removeView(this);
134 return true;
135}
136
137void DevConsoleView::onTabPopup(Workspace* workspace)
138{
139 Menu* menu = AppMenus::instance()->getTabPopupMenu();
140 if (!menu)
141 return;
142
143 menu->showPopup(mousePosInDisplay(), display());
144}
145
146bool DevConsoleView::onProcessMessage(Message* msg)
147{
148 return Box::onProcessMessage(msg);
149}
150
151void DevConsoleView::onExecuteCommand(const std::string& cmd)
152{
153 m_engine->printLastResult();
154 m_engine->evalCode(cmd);
155}
156
157void DevConsoleView::onConsoleError(const char* text)
158{
159 onConsolePrint(text);
160}
161
162void DevConsoleView::onConsolePrint(const char* text)
163{
164 if (text)
165 m_textBox.setText(m_textBox.text() + "\n" + text);
166}
167
168} // namespace app
169