CONSOLE: new module console

Martin Gerhardy 2020-01-22 20:34:23 +01:00
parent 2ef6d7b386
commit 88360b34a4
27 changed files with 343 additions and 86 deletions

View File

@ -196,6 +196,9 @@ find_host_program(GIT_EXECUTABLE NAMES ${GIT_BINARY} git)
find_host_program(HG_EXECUTABLE NAMES ${HG_BINARY} hg)
check_include_files("uuid/uuid.h" HAVE_UUID_H)
set(CURSES_NEED_NCURSES True)
find_package(Curses)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# These includes are needed to let the include for IMPLICIT_DEPENDS for shaders work

View File

@ -22,6 +22,7 @@
#cmakedefine HAVE_POSTGRES 1
#cmakedefine HAVE_UUID_H 1
#cmakedefine HAVE_SYS_TIME_H 1
#cmakedefine CURSES_HAVE_NCURSES_H 1
#cmakedefine OPENCL_LIBRARY "@OPENCL_LIBRARY@"
#cmakedefine BASE_URL "@BASE_URL@"

View File

@ -3,6 +3,7 @@
# files will not get copied
add_subdirectory(core)
add_subdirectory(console)
add_subdirectory(http)
add_subdirectory(commonlua)
add_subdirectory(mail)

View File

@ -60,7 +60,7 @@ set(FILES
)
set(LIB backend)
engine_add_module(TARGET ${LIB} SRCS ${SRCS} FILES ${FILES} DEPENDENCIES eventmgr poi ai stock shared http)
engine_add_module(TARGET ${LIB} SRCS ${SRCS} FILES ${FILES} DEPENDENCIES eventmgr poi ai stock shared http console)
generate_db_models(${LIB} ${CMAKE_CURRENT_SOURCE_DIR}/tables.tbl BackendModels.h)
set(TEST_FILES

View File

@ -333,10 +333,6 @@ bool ServerLoop::init() {
uv_signal_start(_signal, signalCallback, SIGHUP);
uv_signal_start(_signal, signalCallback, SIGINT);
if (!_input.init(_loop)) {
Log::warn("Could not init console input");
}
// init the network last...
if (!_network->init()) {
Log::error("Failed to init the network");
@ -361,7 +357,6 @@ void ServerLoop::shutdown() {
_dbHandler->shutdown();
_metricMgr->shutdown();
_volumeCache->shutdown();
_input.shutdown();
_network->shutdown();
_httpServer->shutdown();
if (_loop != nullptr) {

View File

@ -6,7 +6,7 @@
#include "core/EventBus.h"
#include "core/Trace.h"
#include "core/Input.h"
#include "console/Input.h"
#include "core/EventBus.h"
#include "core/IComponent.h"
#include "network/ServerNetwork.h"
@ -38,7 +38,6 @@ private:
eventmgr::EventMgrPtr _eventMgr;
persistence::DBHandlerPtr _dbHandler;
stock::StockDataProviderPtr _stockDataProvider;
core::Input _input;
MetricMgrPtr _metricMgr;
io::FilesystemPtr _filesystem;
persistence::PersistenceMgrPtr _persistenceMgr;

View File

@ -0,0 +1,18 @@
set(SRCS
Input.cpp Input.h
CursesConsole.cpp CursesConsole.h
CursesApp.cpp CursesApp.h
)
set(LIB console)
set(LIBS core util)
if (CURSES_FOUND)
list(APPEND LIBS ${CURSES_LIBRARIES})
endif()
engine_add_module(TARGET ${LIB} SRCS ${SRCS} DEPENDENCIES ${LIBS})
if (CURSES_FOUND)
target_include_directories(${LIB} PRIVATE ${CURSES_INCLUDE_DIRS})
endif()

View File

@ -0,0 +1,42 @@
/**
* @file
*/
#include "CursesApp.h"
namespace console {
CursesApp::CursesApp(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider, size_t threadPoolSize) :
Super(metric, filesystem, eventBus, timeProvider, threadPoolSize) {
}
CursesApp::~CursesApp() {
}
core::AppState CursesApp::onConstruct() {
const core::AppState state = Super::onConstruct();
_console.construct();
return state;
}
core::AppState CursesApp::onInit() {
const core::AppState state = Super::onInit();
if (!_console.init()) {
return core::AppState::InitFailure;
}
return state;
}
core::AppState CursesApp::onCleanup() {
const core::AppState state = Super::onCleanup();
_console.shutdown();
return state;
}
core::AppState CursesApp::onRunning() {
const core::AppState state = Super::onRunning();
_console.update(_deltaFrameMillis);
return state;
}
}

View File

@ -0,0 +1,25 @@
/**
* @file
*/
#include "core/CommandlineApp.h"
#include "CursesConsole.h"
namespace console {
class CursesApp : public core::CommandlineApp {
private:
using Super = core::CommandlineApp;
CursesConsole _console;
public:
CursesApp(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider, size_t threadPoolSize = 1);
virtual ~CursesApp();
core::AppState onConstruct() override;
core::AppState onInit() override;
core::AppState onCleanup() override;
core::AppState onRunning() override;
};
}

View File

@ -0,0 +1,132 @@
/**
* @file
*/
#include "CursesConsole.h"
#include "core/App.h"
#include <SDL_stdinc.h>
#include "engine-config.h"
#ifdef CURSES_HAVE_NCURSES_H
#include <ncurses.h>
#include <signal.h>
#endif
namespace console {
CursesConsole::CursesConsole() :
Super() {
#ifdef CURSES_HAVE_NCURSES_H
_useOriginalLogFunction = false;
#endif
_consoleMarginLeft = 1;
_consoleMarginLeftBehindPrompt = 1;
_consoleActive = true;
}
void CursesConsole::update(uint32_t deltaTime) {
Super::update(deltaTime);
#ifdef CURSES_HAVE_NCURSES_H
int key = getch();
while (key != ERR) {
if (key == KEY_ENTER || key == '\n') {
executeCommandLine();
} else if (key == KEY_CTAB || key == '\t') {
autoComplete();
} else if (key == KEY_RESIZE) {
clear();
refresh();
} else if (key == KEY_BACKSPACE || key == 8 || key == 127) {
cursorDelete();
} else if (key == KEY_LEFT) {
cursorLeft();
} else if (key == KEY_PPAGE) {
scrollPageUp();
} else if (key == KEY_NPAGE) {
scrollPageDown();
} else if (key == KEY_HOME) {
_cursorPos = 0;
} else if (key == KEY_RIGHT) {
cursorRight();
} else if (key == KEY_END) {
_cursorPos = _commandLine.size();
} else if (key == KEY_UP) {
cursorUp();
} else if (key == KEY_DC) {
cursorDelete(false);
} else if (key == KEY_IC) {
_overwrite ^= true;
} else if (key == KEY_DOWN) {
cursorDown();
} else if (key >= 32 && key < 127) {
const char buf[] = { (char)key, '\0' };
insertText(buf);
}
key = getch();
}
#endif
const math::Rect<int> rect(0, 0, COLS - 1, LINES - 1);
render(rect, (long)deltaTime);
}
void CursesConsole::drawString(int x, int y, const glm::ivec4& color, const char* str, int len) {
#ifdef CURSES_HAVE_NCURSES_H
mvaddnstr(y, x, str, len);
#endif
}
int CursesConsole::lineHeight() {
return 1;
}
glm::ivec2 CursesConsole::stringSize(const char* s, int length) {
return glm::ivec2(core_min(length, (int)strlen(s)), lineHeight());
}
void CursesConsole::afterRender(const math::Rect<int> &rect) {
#ifdef CURSES_HAVE_NCURSES_H
clrtoeol();
refresh();
#endif
}
void CursesConsole::beforeRender(const math::Rect<int> &) {
}
bool CursesConsole::init() {
#ifdef CURSES_HAVE_NCURSES_H
// Start curses mode
initscr();
// We get F1, F2 etc..
keypad(stdscr, TRUE);
// Don't echo() while we do getch
noecho();
// non-blocking input
nodelay(stdscr, TRUE);
// enable the cursor
curs_set(0);
if (has_colors()) {
start_color();
use_default_colors();
init_pair(1, COLOR_RED, -1);
init_pair(2, COLOR_GREEN, -1);
init_pair(3, COLOR_YELLOW, -1);
init_pair(4, COLOR_BLUE, -1);
init_pair(5, COLOR_CYAN, -1);
init_pair(6, COLOR_MAGENTA, -1);
init_pair(7, -1, -1);
}
#endif
return true;
}
void CursesConsole::shutdown() {
#ifdef CURSES_HAVE_NCURSES_H
refresh();
endwin();
#endif
}
}

View File

@ -0,0 +1,29 @@
/**
* @file
*/
#pragma once
#include "util/Console.h"
namespace console {
class CursesConsole : public util::Console {
private:
using Super = util::Console;
protected:
void drawString(int x, int y, const glm::ivec4& color, const char* str, int len) override;
int lineHeight() override;
glm::ivec2 stringSize(const char* s, int length) override;
void afterRender(const math::Rect<int> &rect) override;
void beforeRender(const math::Rect<int> &rect) override;
public:
CursesConsole();
virtual ~CursesConsole() {}
bool init() override;
void update(uint32_t deltaTime);
void shutdown() override;
};
}

View File

@ -7,7 +7,7 @@
#include "core/command/CommandHandler.h"
#include <string.h>
namespace core {
namespace console {
bool Input::init(uv_loop_t* loop) {
_tty.data = this;

View File

@ -6,7 +6,7 @@
#include <uv.h>
namespace core {
namespace console {
/**
* @brief Non-blocking console input reading e.g. for dedicated server command line

View File

@ -32,14 +32,13 @@ set(SRCS
Color.cpp Color.h
Common.h Common.cpp
Concurrency.h Concurrency.cpp
ConsoleApp.h ConsoleApp.cpp
CommandlineApp.h CommandlineApp.cpp
Enum.h
EventBus.cpp EventBus.h
GameConfig.h
GLM.cpp GLM.h
Hash.h
IComponent.h
Input.cpp Input.h
Log.cpp Log.h
MD5.cpp MD5.h
PoolAllocator.h

View File

@ -2,19 +2,19 @@
* @file
*/
#include "ConsoleApp.h"
#include "CommandlineApp.h"
#include "core/Var.h"
namespace core {
ConsoleApp::ConsoleApp(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider, size_t threadPoolSize) :
CommandlineApp::CommandlineApp(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider, size_t threadPoolSize) :
Super(metric, filesystem, eventBus, timeProvider, threadPoolSize) {
}
ConsoleApp::~ConsoleApp() {
CommandlineApp::~CommandlineApp() {
}
AppState ConsoleApp::onConstruct() {
AppState CommandlineApp::onConstruct() {
const core::AppState state = Super::onConstruct();
registerArg("--trace").setDescription("Change log level to trace");

View File

@ -4,18 +4,18 @@
#pragma once
#include "App.h"
#include "core/App.h"
namespace core {
class ConsoleApp : public App {
class CommandlineApp : public core::App {
private:
using Super = core::App;
public:
ConsoleApp(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider, size_t threadPoolSize = 1);
virtual ~ConsoleApp();
CommandlineApp(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider, size_t threadPoolSize = 1);
virtual ~CommandlineApp();
virtual AppState onConstruct() override;
virtual core::AppState onConstruct() override;
};
}

View File

@ -5,7 +5,7 @@
#pragma once
#include <benchmark/benchmark.h>
#include "core/ConsoleApp.h"
#include "core/CommandlineApp.h"
#include "core/io/Filesystem.h"
#include "core/EventBus.h"
#include "core/TimeProvider.h"
@ -14,14 +14,14 @@ namespace core {
class AbstractBenchmark : public benchmark::Fixture {
private:
class BenchmarkApp: public core::ConsoleApp {
class BenchmarkApp: public core::CommandlineApp {
friend class AbstractBenchmark;
protected:
using Super = core::ConsoleApp;
using Super = core::CommandlineApp;
AbstractBenchmark* _benchmark = nullptr;
public:
BenchmarkApp(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider, AbstractBenchmark* benchmark);
~BenchmarkApp();
virtual ~BenchmarkApp();
virtual core::AppState onInit() override;
virtual core::AppState onCleanup() override;

View File

@ -6,7 +6,7 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "core/ConsoleApp.h"
#include "core/CommandlineApp.h"
#include "core/collection/Map.h"
#include "core/EventBus.h"
#include "core/io/Filesystem.h"
@ -81,18 +81,18 @@ inline ::std::ostream& operator<<(::std::ostream& os, const glm::tvec1<T, P>& ve
class AbstractTest: public testing::Test {
private:
class TestApp: public core::ConsoleApp {
class TestApp: public core::CommandlineApp {
friend class AbstractTest;
private:
using Super = core::ConsoleApp;
using Super = core::CommandlineApp;
protected:
AbstractTest* _test = nullptr;
public:
TestApp(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider, AbstractTest* test);
~TestApp();
AppState onInit() override;
AppState onCleanup() override;
core::AppState onInit() override;
core::AppState onCleanup() override;
};
protected:

View File

@ -17,12 +17,6 @@
namespace util {
namespace {
static const char* historyFilename = "history";
static const std::string consolePrompt = "> ";
static const std::string consoleCursor = ".";
static const int consoleMarginLeft = 5;
static const int consoleMarginLeftBehindPrompt = 13;
static const char colorMark = '^';
static const glm::ivec4 colors[MAX_COLORS] = {
glm::ivec4(255, 255, 255, 255),
@ -47,24 +41,6 @@ static const ConsoleColor priorityColors[SDL_NUM_LOG_PRIORITIES] = {
static_assert(SDL_arraysize(priorityColors) == SDL_NUM_LOG_PRIORITIES, "Priority count doesn't match");
}
std::string getColor(ConsoleColor color) {
core_assert(color >= 0 && color <= (int)SDL_arraysize(colors));
std::string s;
s += colorMark;
s += std::to_string((int)color);
return s;
}
static inline bool isColor(const char *cstr) {
static const char maxColor = MAX_COLORS + '0';
return cstr[0] == colorMark && cstr[1] >= '0' && cstr[1] <= maxColor;
}
static inline void skipColor(const char **cstr) {
static_assert((int)MAX_COLORS < 10, "max colors must not exceed one ascii char for encoding");
*cstr += 2;
}
Console::Console() :
_mainThread(std::this_thread::get_id()) {
SDL_LogGetOutputFunction(&_logFunction, &_logUserData);
@ -75,6 +51,24 @@ Console::~Console() {
SDL_LogSetOutputFunction(_logFunction, _logUserData);
}
std::string Console::getColor(ConsoleColor color) {
core_assert(color >= 0 && color <= (int)SDL_arraysize(colors));
std::string s;
s += _colorMark;
s += std::to_string((int)color);
return s;
}
bool Console::isColor(const char *cstr) {
static const char maxColor = MAX_COLORS + '0';
return cstr[0] == _colorMark && cstr[1] >= '0' && cstr[1] <= maxColor;
}
void Console::skipColor(const char **cstr) {
static_assert((int)MAX_COLORS < 10, "max colors must not exceed one ascii char for encoding");
*cstr += 2;
}
void Console::construct() {
_autoEnable = core::Var::get("ui_autoconsole", "false", "Activate console on output");
core::Command::registerCommand("toggleconsole", [&] (const core::CmdArgs& args) { toggle(); }).setHelp("Toggle the in-game console");
@ -83,7 +77,7 @@ void Console::construct() {
bool Console::init() {
const io::FilesystemPtr& fs = io::filesystem();
const std::string& content = fs->load("%s", historyFilename);
const std::string& content = fs->load("%s", _historyFilename);
core::string::splitString(content, _history, "\n");
_historyPos = _history.size();
Log::info("Loaded %i history entries", _historyPos);
@ -99,7 +93,7 @@ void Console::shutdown() {
}
const io::FilesystemPtr& fs = io::filesystem();
if (!fs->write(historyFilename, content)) {
if (!fs->write(_historyFilename, content)) {
Log::warn("Failed to write the history");
} else {
Log::debug("Wrote the history");
@ -131,7 +125,7 @@ bool Console::onKeyPress(int32_t key, int16_t modifier) {
} else if (key == SDLK_e) {
_cursorPos = _commandLine.size();
} else if (key == SDLK_c) {
_messages.push_back(consolePrompt + _commandLine);
_messages.push_back(_consolePrompt + _commandLine);
clearCommandLine();
} else if (key == SDLK_d) {
toggle();
@ -212,7 +206,7 @@ bool Console::onKeyPress(int32_t key, int16_t modifier) {
}
void Console::executeCommandLine() {
_messages.push_back(consolePrompt + _commandLine);
_messages.push_back(_consolePrompt + _commandLine);
_scrollPos = 0;
if (_commandLine.empty()) {
return;
@ -426,7 +420,7 @@ void Console::autoComplete() {
_commandLine.insert(cmdEraseIndex, matches.front());
}
} else {
_messages.push_back(consolePrompt + _commandLine);
_messages.push_back(_consolePrompt + _commandLine);
std::sort(begin(matches), end(matches), [](const std::string& v1, const std::string& v2) {
return v1 < v2;
});
@ -544,7 +538,9 @@ void Console::addLogLine(int category, SDL_LogPriority priority, const char *mes
if (hasColor) {
skipColor(&message);
}
_logFunction(_logUserData, category, priority, message);
if (_useOriginalLogFunction) {
_logFunction(_logUserData, category, priority, message);
}
}
bool Console::toggle() {
@ -609,6 +605,7 @@ void Console::render(const math::Rect<int> &rect, long deltaFrame) {
const int lineH = lineHeight();
_maxLines = (rect.getMaxZ() - rect.getMinZ()) / lineH;
if (_maxLines <= 0) {
afterRender(rect);
return;
}
const int maxY = _messages.size() * lineH;
@ -617,19 +614,19 @@ void Console::render(const math::Rect<int> &rect, long deltaFrame) {
MessagesIter i = _messages.rbegin();
std::advance(i, _scrollPos);
for (int y = startY; i != _messages.rend(); ++i) {
if (y < 0) {
if (y < rect.getMinZ()) {
break;
}
const glm::ivec2& size = stringSize(i->c_str(), i->length());
y -= size.y;
drawString(consoleMarginLeft, y, *i, i->length());
drawString(_consoleMarginLeft, y, *i, i->length());
}
drawString(consoleMarginLeft, startY, consolePrompt, consolePrompt.length());
drawString(consoleMarginLeft + consoleMarginLeftBehindPrompt, startY, _commandLine, _commandLine.length());
drawString(_consoleMarginLeft, startY, _consolePrompt, _consolePrompt.length());
drawString(_consoleMarginLeft + _consoleMarginLeftBehindPrompt, startY, _commandLine, _commandLine.length());
if (_cursorBlink) {
const glm::ivec2& l = stringSize(_commandLine.c_str(), _cursorPos);
drawString(consoleMarginLeft + consoleMarginLeftBehindPrompt + l.x, startY, consoleCursor, consoleCursor.length());
drawString(_consoleMarginLeft + _consoleMarginLeftBehindPrompt + l.x, startY, _consoleCursor, _consoleCursor.length());
}
afterRender(rect);

View File

@ -9,6 +9,7 @@
#include <vector>
#include <string>
#include "core/Var.h"
#include "core/Assert.h"
#include "core/IComponent.h"
#include "math/Rect.h"
#include "core/collection/ConcurrentQueue.h"
@ -28,6 +29,20 @@ protected:
typedef Messages::const_reverse_iterator MessagesIter;
Messages _messages;
int _consoleMarginLeft = 5;
int _consoleMarginLeftBehindPrompt = 13;
const char* _historyFilename = "history";
std::string _consolePrompt = "> ";
std::string _consoleCursor = ".";
char _colorMark = '^';
std::string getColor(ConsoleColor color);
bool isColor(const char *cstr);
void skipColor(const char **cstr);
/**
* @brief Data structure to store a log entry call from a different thread.
*/
@ -85,6 +100,7 @@ protected:
// commandline character will get overwritten if this is true
bool _overwrite = false;
bool _cursorBlink = false;
bool _useOriginalLogFunction = true;
int _frame = 0;
int _cursorPos = 0;
int _scrollPos = 0;

View File

@ -4,14 +4,14 @@
#pragma once
#include "core/ConsoleApp.h"
#include "console/CursesApp.h"
#include "backend/loop/ServerLoop.h"
#include "core/TimeProvider.h"
#include "http/HttpServer.h"
class Server: public core::ConsoleApp {
class Server: public console::CursesApp {
private:
using Super = core::ConsoleApp;
using Super = console::CursesApp;
backend::ServerLoopPtr _serverLoop;
public:
Server(const metric::MetricPtr& metric, const backend::ServerLoopPtr& serverLoop,

View File

@ -3,4 +3,4 @@ set(SRCS
TestHttpServer.h TestHttpServer.cpp
)
engine_add_executable(TARGET ${PROJECT_NAME} SRCS ${SRCS} NOINSTALL)
engine_target_link_libraries(TARGET ${PROJECT_NAME} DEPENDENCIES core http)
engine_target_link_libraries(TARGET ${PROJECT_NAME} DEPENDENCIES core console http)

View File

@ -4,9 +4,9 @@
#pragma once
#include "core/ConsoleApp.h"
#include "core/CommandlineApp.h"
#include "http/HttpServer.h"
#include "core/Input.h"
#include "console/Input.h"
#include <uv.h>
/**
@ -14,11 +14,11 @@
*
* See e.g. https://github.com/zardus/preeny and https://lolware.net/2015/04/28/nginx-fuzzing.html
*/
class TestHttpServer: public core::ConsoleApp {
class TestHttpServer: public core::CommandlineApp {
private:
using Super = core::ConsoleApp;
using Super = core::CommandlineApp;
http::HttpServer _server;
core::Input _input;
console::Input _input;
uv_loop_t *_loop = nullptr;
core::VarPtr _exitAfterRequest;
int _remainingFrames = 0;

View File

@ -4,7 +4,7 @@
#pragma once
#include "core/ConsoleApp.h"
#include "core/CommandlineApp.h"
#include "Types.h"
#include <simplecpp.h>
#include <vector>
@ -25,9 +25,9 @@
* @ingroup Tools
* @ingroup Compute
*/
class ComputeShaderTool: public core::ConsoleApp {
class ComputeShaderTool: public core::CommandlineApp {
private:
using Super = core::ConsoleApp;
using Super = core::CommandlineApp;
protected:
std::string _namespaceSrc;
std::string _sourceDirectory;

View File

@ -5,7 +5,7 @@
#pragma once
#include <map>
#include "core/ConsoleApp.h"
#include "core/CommandlineApp.h"
#include "core/Tokenizer.h"
#include "Table.h"
@ -15,9 +15,9 @@
*
* @ingroup Tools
*/
class DatabaseTool: public core::ConsoleApp {
class DatabaseTool: public core::CommandlineApp {
private:
using Super = core::ConsoleApp;
using Super = core::CommandlineApp;
protected:
std::string _tableFile;
std::string _targetFile;

View File

@ -4,7 +4,7 @@
#pragma once
#include "core/ConsoleApp.h"
#include "core/CommandlineApp.h"
#include "Types.h"
/**
@ -12,9 +12,9 @@
*
* @ingroup Tools
*/
class ShaderTool: public core::ConsoleApp {
class ShaderTool: public core::CommandlineApp {
private:
using Super = core::ConsoleApp;
using Super = core::CommandlineApp;
protected:
ShaderStruct _shaderStruct;
std::string _namespaceSrc;

View File

@ -4,7 +4,7 @@
#pragma once
#include "core/ConsoleApp.h"
#include "core/CommandlineApp.h"
#include "ui/turbobadger/TurboBadger.h"
#include "ui/turbobadger/UIDummies.h"
@ -13,9 +13,9 @@
*
* @ingroup Tools
*/
class UITool: public core::ConsoleApp {
class UITool: public core::CommandlineApp {
private:
using Super = core::ConsoleApp;
using Super = core::CommandlineApp;
DummyRenderer _renderer;
tb::TBWidget _root;
public: