lua console and some changes

This commit is contained in:
Eduardo Bart 2011-08-20 17:30:41 -03:00
parent 033f14780d
commit 38529ea837
70 changed files with 672 additions and 305 deletions

View File

@ -84,11 +84,11 @@ SET(SOURCES
src/framework/net/rsa.cpp
# framework util
src/framework/util/logger.cpp
src/framework/util/color.cpp
src/framework/util/translator.cpp
# framework core
src/framework/core/logger.cpp
src/framework/core/configs.cpp
src/framework/core/resourcemanager.cpp
src/framework/core/eventdispatcher.cpp

View File

@ -0,0 +1,74 @@
Console = { }
local console
local logLocked = false
function Console.onLog(level, message, time)
-- avoid logging while reporting logs (would cause a infinite loop)
if not logLocked then
logLocked = true
local color
if level == LogDebug then
color = '#5555ff'
elseif level == LogInfo then
color = '#55ff55'
elseif level == LogWarning then
color = '#ffff00'
else
color = '#ff0000'
end
Console.addLine(message, color)
logLocked = false
end
end
function Console.addLine(text, color)
-- create new label
local label = UILabel.create()
label:setStyle('ConsoleLabel')
label:setText(text)
label:setForegroundColor(color)
console:insertChild(label, -1)
end
function Console.create()
console = loadUI("/console/console.otui")
rootWidget:addChild(console)
console:hide()
Logger.setOnLog(Console.onLog)
Logger.fireOldMessages()
end
function Console.destroy()
console:destroy()
console = nil
end
function Console.show()
console.parent:lockChild(console)
console.visible = true
end
function Console.hide()
console.parent:unlockChild(console)
console.visible = false
end
function Console.executeCommand(command)
Console.addLine(">> " .. command, "#ffffff")
local func, err = loadstring("return (" .. command .. ")", "@")
if func then
local ok, ret = pcall(func)
if ok then
Logger.log(LogDebug, "=> " .. tostring(ret))
else
Logger.log(LogError, 'command failed: ' .. ret)
end
else
Logger.log(LogError, 'incorrect lua syntax: ' .. err:sub(5))
end
end

View File

@ -0,0 +1,17 @@
Module
name: console
description: Console for executing lua functions
author: OTClient team
website: https://github.com/edubart/otclient
version: 0.2
autoLoad: true
dependencies:
- core
onLoad: |
require 'console'
Console.create()
return true
onUnload: |
Console.destroy()

View File

@ -0,0 +1,35 @@
ConsoleLabel < UILabel
font: terminus-14px-bold
height: 16
anchors.bottom: next.top
anchors.left: parent.left
anchors.right: parent.right
margin.left: 2
RectPanel
id: consolePanel
background-color: #000000
opacity: 216
anchors.fill: parent
UILabel
size: 18 20
anchors.bottom: parent.bottom
anchors.left: parent.left
margin.left: 2
font: terminus-14px-bold
text: >>
UILineEdit
id: commandBox
height: 20
anchors.bottom: parent.bottom
anchors.left: prev.right
anchors.right: parent.right
margin.left: 2
font: terminus-14px-bold
onAction: |
function(self)
Console.executeCommand(self:getText())
self:clearText()
end

View File

@ -6,3 +6,11 @@ AnchorLeft = 3
AnchorRight = 4
AnchorVerticalCenter = 5
AnchorHorizontalCenter = 6
LogDebug = 0
LogInfo = 1
LogWarning = 2
LogError = 3
LogFatal = 4
EmptyFunction = function() end

View File

@ -11,45 +11,48 @@ function MessageBox.create(title, text, flags)
-- create messagebox window
local window = UIWindow.create()
window.id = "messageBoxWindow"
window.title = title
window:setStyle('Window')
window:setId("messageBoxWindow")
window:setTitle(title)
window:centerIn("parent")
rootWidget:addChild(window)
window:lock()
rootWidget:lockChild(window)
-- create messagebox label
local label = UILabel.create()
label.id = "messageBoxLabel"
label.text = text
label:addAnchor(AnchorHorizontalCenter, window.id, AnchorHorizontalCenter)
label:addAnchor(AnchorTop, window.id, AnchorTop)
label:setStyle('Label')
label:setId("messageBoxLabel")
label:setText(text)
label:addAnchor(AnchorHorizontalCenter, window:getId(), AnchorHorizontalCenter)
label:addAnchor(AnchorTop, window:getId(), AnchorTop)
label:setMargin(27, 0)
label:resizeToText()
window:addChild(label)
-- set window size based on label size
window.width = label.width + 60
window.height = label.height + 64
window:setWidth(label:getWidth() + 60)
window:setHeight(label:getHeight() + 64)
-- setup messagebox first button
local button1 = UIButton.create()
button1.id = "messageBoxButton1"
button1:addAnchor(AnchorBottom, window.id, AnchorBottom)
button1:addAnchor(AnchorRight, window.id, AnchorRight)
button1:setStyle('Button')
button1:setId("messageBoxButton1")
button1:addAnchor(AnchorBottom, window:getId(), AnchorBottom)
button1:addAnchor(AnchorRight, window:getId(), AnchorRight)
button1:setMargin(10)
button1.width = 64
button1:setWidth(64)
window:addChild(button1)
if flags == MessageBoxOk then
button1.text = "Ok"
box.onOk = createEmptyFunction()
button1:setText("Ok")
box.onOk = EmptyFunction
button1.onClick = function()
box.onOk()
box:destroy()
end
elseif flags == MessageBoxCancel then
button1.text = "Cancel"
box.onCancel = createEmptyFunction()
button1:setText("Cancel")
box.onCancel = EmptyFunction
button1.onClick = function()
box.onCancel()
box:destroy()

View File

@ -1,5 +1,7 @@
function createEmptyFunction()
local emptyFunction = function() end
return emptyFunction
function print(...)
local msg = ""
for i,v in ipairs(arg) do
msg = msg .. tostring(v) .. "\t"
end
Logger.log(LogInfo, msg)
end

View File

@ -1,19 +1,19 @@
function UIWidget:setMargin(...)
local params = {...}
if #params == 1 then
self.marginTop = params[1]
self.marginRight = params[1]
self.marginBottom = params[1]
self.marginLeft = params[1]
self:setMarginTop(params[1])
self:setMarginRight(params[1])
self:setMarginBottom(params[1])
self:setMarginLeft(params[1])
elseif #params == 2 then
self.marginTop = params[1]
self.marginRight = params[2]
self.marginBottom = params[1]
self.marginLeft = params[2]
self:setMarginTop(params[1])
self:setMarginRight(params[2])
self:setMarginBottom(params[1])
self:setMarginLeft(params[2])
elseif #params == 4 then
self.marginTop = params[1]
self.marginRight = params[2]
self.marginBottom = params[3]
self.marginLeft = params[4]
self:setMarginTop(params[1])
self:setMarginRight(params[2])
self:setMarginBottom(params[3])
self:setMarginLeft(params[4])
end
end

View File

@ -11,6 +11,7 @@ Module
importFont('helvetica-12px-bold')
importFont('helvetica-12px')
importFont('helvetica-14px-bold')
importFont('terminus-14px-bold')
setDefaultFont('helvetica-12px')
return true

View File

@ -0,0 +1,9 @@
Font
name: terminus-14px-bold
height: 16
spacing: 0 0
top margin: 2
texture: terminus-14px-bold.png
glyph size: 16 16
fixed glyph width: 8

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,6 +1,6 @@
Button < UIButton
font: helvetica-11px-bold
font-color: #f0ad4dff
color: #f0ad4dff
size: 106 24
border-image:
source: /core_ui/images/button.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

View File

@ -1,5 +1,8 @@
Label < UILabel
font: helvetica-12px
color: #ffffff
LargerLabel < Label
font: helvetica-12px-bold
color: #ffffff

View File

@ -1,4 +1,5 @@
LineEdit < UILineEdit
font: helvetica-12px
size: 86 20
text-margin: 3
border-image:

View File

@ -12,4 +12,4 @@ RoundedPanel < Panel
border: 4
RectPanel < UIWidget
image: /core_ui/images/emptyrect.png
image: /core_ui/images/empty_rect.png

View File

@ -1,4 +1,5 @@
Window < UIWindow
font: helvetica-12px-bold
size: 200 200
head:
height: 20
@ -18,4 +19,3 @@ Window < UIWindow
MainWindow < Window
anchors.centerIn: parent
onLoad: function(self) self:lock() end

View File

@ -3,7 +3,7 @@ GFX = { }
function GFX.fadeIn(widget, time, elapsed)
if not elapsed then elapsed = 0 end
if not time then time = 250 end
widget.opacity = math.min((255*elapsed)/time, 255)
widget:setOpacity(math.min((255*elapsed)/time, 255))
if elapsed < time then
scheduleEvent(function()
GFX.fadeIn(widget, time, elapsed + 30)
@ -14,7 +14,7 @@ end
function GFX.fadeOut(widget, time, elapsed)
if not elapsed then elapsed = 0 end
if not time then time = 250 end
widget.opacity = (255*(time - elapsed))/time
widget:setOpacity((255*(time - elapsed))/time)
if elapsed < time then
scheduleEvent(function()
GFX.fadeOut(widget, time, elapsed + 30)

View File

@ -31,8 +31,8 @@ function EnterGame_connectToLoginServer()
end
local enterGameWindow = rootWidget:getChild("enterGameWindow")
local account = enterGameWindow:getChild("accountNameLineEdit").text
local password = enterGameWindow:getChild("accountPasswordLineEdit").text
local account = enterGameWindow:getChild("accountNameLineEdit"):getText()
local password = enterGameWindow:getChild("accountPasswordLineEdit"):getText()
protocolLogin:login(account, password)
enterGameWindow:destroy()

View File

@ -50,4 +50,4 @@ MainWindow
anchors.bottom: parent.bottom
margin.bottom: 16
margin.right: 16
onClick: function(self) GFX.fadeOut(self.parent) end
onClick: function(self) GFX.fadeOut(self:getParent()) end

View File

@ -58,4 +58,4 @@ MainWindow
anchors.top: parent.top
margin.top: 191
margin.left: 188
onClick: function(self) self.parent:destroy() end
onClick: function(self) self:getParent():destroy() end

View File

@ -113,4 +113,4 @@ MainWindow
anchors.bottom: parent.bottom
margin.right: 10
margin.bottom: 13
onClick: function(self) self.parent:destroy() end
onClick: function(self) self:getParent():destroy() end

View File

@ -3,6 +3,14 @@
//namespace fw {
enum LogLevel {
LogDebug = 0,
LogInfo,
LogWarning,
LogError,
LogFatal
};
enum AlignmentFlag {
AlignLeft = 1,
AlignRight = 2,

View File

@ -5,17 +5,20 @@
Configs g_configs;
bool Configs::load(const std::string& fileName)
bool Configs::load(const std::string& file)
{
m_fileName = fileName;
m_fileName = file;
if(!g_resources.fileExists(file))
return false;
try {
OTMLDocumentPtr doc = OTMLDocument::parse(fileName);
OTMLDocumentPtr doc = OTMLDocument::parse(file);
for(const OTMLNodePtr& child : doc->children())
m_confsMap[child->tag()] = child->value();
return true;
} catch(std::exception& e) {
logError("ERROR: could not load configurations: ", e.what());
logError("could not load configurations: ", e.what());
return false;
}
}

View File

@ -6,7 +6,7 @@
class Configs
{
public:
bool load(const std::string& fileName);
bool load(const std::string& file);
bool save();
void set(const std::string& key, const std::string& value) { m_confsMap[key] = value; }

View File

@ -0,0 +1,52 @@
#include "logger.h"
#include "eventdispatcher.h"
Logger g_logger;
Logger::Logger() : m_terminated(false)
{
}
void Logger::log(LogLevel level, std::string message)
{
const static std::string logPrefixes[] = { "", "", "WARNING: ", "ERROR: ", "FATAL ERROR: " };
if(!m_terminated) {
message.insert(0, logPrefixes[level]);
std::cout << message << std::endl;
std::size_t now = std::time(NULL);
m_logMessages.push_back(LogMessage(level, message, now));
if(m_onLog)
g_dispatcher.addEvent(std::bind(m_onLog, level, message, now));
}
if(level == LogFatal) {
m_terminated = true;
exit(-1);
}
}
void Logger::logFunc(LogLevel level, const std::string& message, std::string prettyFunction)
{
std::stringstream ss;
prettyFunction = prettyFunction.substr(0, prettyFunction.find_first_of('('));
if(prettyFunction.find_last_of(' ') != std::string::npos)
prettyFunction = prettyFunction.substr(prettyFunction.find_last_of(' ') + 1);
if(!prettyFunction.empty())
ss << "[" << prettyFunction << "] ";
ss << message;
log(level, ss.str());
}
void Logger::fireOldMessages()
{
if(m_onLog) {
for(const LogMessage& logMessage : m_logMessages)
g_dispatcher.addEvent(std::bind(m_onLog, logMessage.level, logMessage.message, logMessage.when));
}
}

View File

@ -0,0 +1,49 @@
#ifndef LOGGER_H
#define LOGGER_H
#include "../util/tools.h"
#include <vector>
#include <functional>
struct LogMessage {
LogMessage(LogLevel level, const std::string& message, std::size_t when) : level(level), message(message), when(when) { }
LogLevel level;
std::string message;
std::size_t when;
};
class Logger
{
typedef std::function<void(LogLevel, std::string, std::size_t)> OnLogCallback;
public:
Logger();
void log(LogLevel level, std::string message);
void logFunc(LogLevel level, const std::string& message, std::string prettyFunction);
void fireOldMessages();
void setOnLog(const OnLogCallback& onLog) { m_onLog = onLog; }
private:
std::vector<LogMessage> m_logMessages;
OnLogCallback m_onLog;
bool m_terminated;
};
extern Logger g_logger;
// specialized logging
#define logDebug(...) g_logger.log(LogDebug, fw::mkstr(__VA_ARGS__))
#define logInfo(...) g_logger.log(LogInfo, fw::mkstr(__VA_ARGS__))
#define logWarning(...) g_logger.log(LogWarning, fw::mkstr(__VA_ARGS__))
#define logError(...) g_logger.log(LogError, fw::mkstr(__VA_ARGS__))
#define logFatal(...) g_logger.log(LogFatal, fw::mkstr(__VA_ARGS__))
#define logTrace() g_logger.logFunc(LogDebug, "", __PRETTY_FUNCTION__)
#define logTraceDebug(...) g_logger.logFunc(LogDebug, fw::mkstr(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTraceInfo(...) g_logger.logFunc(LogInfo, fw::mkstr(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTraceWarning(...) g_logger.logFunc(LogWarning, fw::mkstr(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTraceError(...) g_logger.logFunc(LogError, fw::mkstr(__VA_ARGS__), __PRETTY_FUNCTION__)
#endif

View File

@ -54,7 +54,7 @@ bool Module::load()
logInfo("Loaded module '", m_name, "'");
return true;
} catch(std::exception& e) {
logError("ERROR: failed to load module '", m_name, "': ", e.what());
logError("failed to load module '", m_name, "': ", e.what());
return false;
}
}

View File

@ -38,7 +38,7 @@ bool ModuleManager::discoverModule(const std::string& file)
module->discover(moduleNode);
m_modules.push_back(module);
} catch(std::exception& e) {
logError("ERROR: failed to load module from '", file, "': ", e.what());
logError("failed to load module from '", file, "': ", e.what());
return false;
}
return true;

View File

@ -30,14 +30,14 @@ void ResourceManager::init(const char* argv0)
}
if(!found)
logFatal("FATAL ERROR: could not find modules directory");
logFatal("could not find modules directory");
// setup write directory
std::string dir = g_platform.getAppUserDir();
if(g_resources.setWriteDir(dir))
g_resources.addToSearchPath(dir);
else
logError("ERROR: could not setup write directory");
logError("could not setup write directory");
}
void ResourceManager::terminate()

View File

@ -41,13 +41,15 @@
// additional utilities
#include "util/types.h"
#include "util/tools.h"
#include "util/logger.h"
#include "util/translator.h"
#include "util/point.h"
#include "util/color.h"
#include "util/rect.h"
#include "util/size.h"
// logger
#include "core/logger.h"
// easy typing for _1, _2, ...
using namespace std::placeholders;

View File

@ -18,8 +18,11 @@ void Font::load(const OTMLNodePtr& fontNode)
if(!m_texture)
throw std::runtime_error("failed to load texture for font");
// auto calculate widths
calculateGlyphsWidthsAutomatically(glyphSize);
if(OTMLNodePtr node = fontNode->get("fixed glyph width")) {
for(int glyph = m_firstGlyph; glyph < 256; ++glyph)
m_glyphsSize[glyph] = Size(node->value<int>(), m_glyphHeight);
} else
calculateGlyphsWidthsAutomatically(glyphSize);
// read custom widths
if(OTMLNodePtr node = fontNode->get("glyph widths")) {

View File

@ -34,7 +34,7 @@ bool FontManager::importFont(std::string fontFile)
return true;
} catch(std::exception& e) {
logError("ERROR: could not load font from '", fontFile, "': ", e.what());
logError("could not load font from '", fontFile, "': ", e.what());
return false;
}
}
@ -64,6 +64,6 @@ FontPtr FontManager::getDefaultFont()
{
// default font should always exists, otherwise the app may crash
if(!m_defaultFont)
logFatal("FATAL ERROR: no default font to display, cannot continue to run");
logFatal("no default font to display, cannot continue to run");
return m_defaultFont;
}

View File

@ -194,8 +194,7 @@ void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords,
stopDrawing();
}
void Graphics::drawFilledRect(const Rect& screenCoords,
const Color& color)
void Graphics::drawFilledRect(const Rect& screenCoords)
{
assert(!m_drawing);
@ -208,8 +207,6 @@ void Graphics::drawFilledRect(const Rect& screenCoords,
int top = screenCoords.top();
int left = screenCoords.left();
glPushAttrib(GL_CURRENT_BIT);
glColor4ubv(color.rgbaPtr());
glDisable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
@ -220,12 +217,10 @@ void Graphics::drawFilledRect(const Rect& screenCoords,
glEnd();
glEnable(GL_TEXTURE_2D);
glPopAttrib();
}
void Graphics::drawBoundingRect(const Rect& screenCoords,
const Color& color,
int innerLineWidth)
{
assert(!m_drawing);
@ -239,8 +234,6 @@ void Graphics::drawBoundingRect(const Rect& screenCoords,
int top = screenCoords.top();
int left = screenCoords.left();
glPushAttrib(GL_CURRENT_BIT);
glColor4ubv(color.rgbaPtr());
glDisable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
@ -270,7 +263,6 @@ void Graphics::drawBoundingRect(const Rect& screenCoords,
glEnd();
glEnable(GL_TEXTURE_2D);
glPopAttrib();
}
void Graphics::bindColor(const Color& color)

View File

@ -45,11 +45,9 @@ public:
const TexturePtr& texture,
const Rect& textureCoords);
void drawFilledRect(const Rect& screenCoords,
const Color& color);
void drawFilledRect(const Rect& screenCoords);
void drawBoundingRect(const Rect& screenCoords,
const Color& color = Color::green,
int innerLineWidth = 1);
const Size& getScreenSize() const { return m_screenSize; }

View File

@ -35,7 +35,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
// checks texture max size
if(width > maxTexSize || height > maxTexSize) {
logError("ERROR: loading texture with size ", width, "x", height, " failed, "
logError("loading texture with size ", width, "x", height, " failed, "
"the maximum size allowed by the graphics card is ", maxTexSize, "x", maxTexSize, ",",
"to prevent crashes the texture will be displayed as a blank texture");
return 0;

View File

@ -31,7 +31,7 @@ TexturePtr TextureManager::getTexture(const std::string& textureFile)
g_resources.loadFile(textureFile, fin);
texture = loadPNG(fin);
} catch(std::exception& e) {
logError("ERROR: unable to load texture '",textureFile,"': ", e.what());
logError("unable to load texture '",textureFile,"': ", e.what());
}
}

View File

@ -10,51 +10,71 @@ void LuaInterface::registerFunctions()
// UIWidget
g_lua.registerClass<UIWidget>();
g_lua.bindClassStaticFunction<UIWidget>("create", &UIWidget::create);
g_lua.bindClassMemberFunction("destroy", &UIWidget::destroy);
g_lua.bindClassMemberFunction("addChild", &UIWidget::addChild);
g_lua.bindClassMemberField<UIWidget>("id", &UIWidget::getId, &UIWidget::setId);
g_lua.bindClassMemberField<UIWidget>("enabled", &UIWidget::isEnabled, &UIWidget::setEnabled);
g_lua.bindClassMemberField<UIWidget>("visible", &UIWidget::isVisible, &UIWidget::setVisible);
g_lua.bindClassMemberField<UIWidget>("width", &UIWidget::getWidth, &UIWidget::setWidth);
g_lua.bindClassMemberField<UIWidget>("height", &UIWidget::getHeight, &UIWidget::setHeight);
g_lua.bindClassMemberField<UIWidget>("parent", &UIWidget::getParent, &UIWidget::setParent);
g_lua.bindClassMemberField<UIWidget>("color", &UIWidget::getColor, &UIWidget::setColor);
g_lua.bindClassMemberField<UIWidget>("opacity", &UIWidget::getOpacity, &UIWidget::setOpacity);
g_lua.bindClassMemberField<UIWidget>("marginTop", &UIWidget::getMarginTop, &UIWidget::setMarginTop);
g_lua.bindClassMemberField<UIWidget>("marginBottom", &UIWidget::getMarginBottom, &UIWidget::setMarginBottom);
g_lua.bindClassMemberField<UIWidget>("marginLeft", &UIWidget::getMarginLeft, &UIWidget::setMarginLeft);
g_lua.bindClassMemberField<UIWidget>("marginRight", &UIWidget::getMarginRight, &UIWidget::setMarginRight);
g_lua.bindClassMemberFunction<UIWidget>("getId", &UIWidget::getId);
g_lua.bindClassMemberFunction<UIWidget>("setId", &UIWidget::setId);
g_lua.bindClassMemberFunction<UIWidget>("isEnabled", &UIWidget::isEnabled);
g_lua.bindClassMemberFunction<UIWidget>("setEnabled", &UIWidget::setEnabled);
g_lua.bindClassMemberFunction<UIWidget>("isVisible", &UIWidget::isVisible);
g_lua.bindClassMemberFunction<UIWidget>("setVisible", &UIWidget::setVisible);
g_lua.bindClassMemberFunction<UIWidget>("getWidth", &UIWidget::getWidth);
g_lua.bindClassMemberFunction<UIWidget>("setWidth", &UIWidget::setWidth);
g_lua.bindClassMemberFunction<UIWidget>("getHeight", &UIWidget::getHeight);
g_lua.bindClassMemberFunction<UIWidget>("setHeight", &UIWidget::setHeight);
g_lua.bindClassMemberFunction<UIWidget>("getParent", &UIWidget::getParent);
g_lua.bindClassMemberFunction<UIWidget>("setParent", &UIWidget::setParent);
g_lua.bindClassMemberFunction<UIWidget>("getBackgroundColor", &UIWidget::getBackgroundColor);
g_lua.bindClassMemberFunction<UIWidget>("setBackgroundColor", &UIWidget::setBackgroundColor);
g_lua.bindClassMemberFunction<UIWidget>("getForegroundColor", &UIWidget::getForegroundColor);
g_lua.bindClassMemberFunction<UIWidget>("setForegroundColor", &UIWidget::setForegroundColor);
g_lua.bindClassMemberFunction<UIWidget>("getOpacity", &UIWidget::getOpacity);
g_lua.bindClassMemberFunction<UIWidget>("setOpacity", &UIWidget::setOpacity);
g_lua.bindClassMemberFunction<UIWidget>("setStyle", &UIWidget::setStyle);
g_lua.bindClassMemberFunction<UIWidget>("getMarginTop", &UIWidget::getMarginTop);
g_lua.bindClassMemberFunction<UIWidget>("setMarginTop", &UIWidget::setMarginTop);
g_lua.bindClassMemberFunction<UIWidget>("getMarginBottom", &UIWidget::getMarginBottom);
g_lua.bindClassMemberFunction<UIWidget>("setMarginBottom", &UIWidget::setMarginBottom);
g_lua.bindClassMemberFunction<UIWidget>("getMarginLeft", &UIWidget::getMarginLeft);
g_lua.bindClassMemberFunction<UIWidget>("setMarginLeft", &UIWidget::setMarginLeft);
g_lua.bindClassMemberFunction<UIWidget>("getMarginRight", &UIWidget::getMarginRight);
g_lua.bindClassMemberFunction<UIWidget>("setMarginRight", &UIWidget::setMarginRight);
g_lua.bindClassMemberFunction<UIWidget>("hide", &UIWidget::hide);
g_lua.bindClassMemberFunction<UIWidget>("show", &UIWidget::show);
g_lua.bindClassMemberFunction<UIWidget>("fill", &UIWidget::fill);
g_lua.bindClassMemberFunction<UIWidget>("centerIn", &UIWidget::centerIn);
g_lua.bindClassMemberFunction<UIWidget>("addAnchor", &UIWidget::addAnchor);
g_lua.bindClassMemberFunction<UIWidget>("getChild", &UIWidget::getChildById);
g_lua.bindClassMemberFunction<UIWidget>("insertChild", &UIWidget::insertChild);
g_lua.bindClassMemberFunction<UIWidget>("removeChild", &UIWidget::removeChild);
g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild);
g_lua.bindClassMemberFunction<UIWidget>("lock", &UIWidget::lock);
g_lua.bindClassMemberFunction<UIWidget>("hide", &UIWidget::hide);
g_lua.bindClassMemberFunction<UIWidget>("show", &UIWidget::show);
g_lua.bindClassMemberFunction<UIWidget>("lockChild", &UIWidget::lockChild);
g_lua.bindClassMemberFunction<UIWidget>("destroy", &UIWidget::destroy);
// UILabel
g_lua.registerClass<UILabel, UIWidget>();
g_lua.bindClassStaticFunction<UILabel>("create", &UILabel::create);
g_lua.bindClassMemberField("text", &UILabel::getText, &UILabel::setText);
g_lua.bindClassMemberFunction<UILabel>("getText", &UILabel::getText);
g_lua.bindClassMemberFunction<UILabel>("setText", &UILabel::setText);
g_lua.bindClassMemberFunction("resizeToText", &UILabel::resizeToText);
// UIButton
g_lua.registerClass<UIButton, UIWidget>();
g_lua.bindClassStaticFunction<UIButton>("create", &UIButton::create);
g_lua.bindClassMemberField("text", &UIButton::getText, &UIButton::setText);
g_lua.bindClassMemberFunction<UIButton>("getText", &UIButton::getText);
g_lua.bindClassMemberFunction<UIButton>("setText", &UIButton::setText);
// UILineEdit
g_lua.registerClass<UILineEdit, UIWidget>();
g_lua.bindClassStaticFunction<UILineEdit>("create", &UILineEdit::create);
g_lua.bindClassMemberField("text", &UILineEdit::getText, &UILineEdit::setText);
g_lua.bindClassMemberFunction<UILineEdit>("getText", &UILineEdit::getText);
g_lua.bindClassMemberFunction<UILineEdit>("setText", &UILineEdit::setText);
g_lua.bindClassMemberFunction<UILineEdit>("clearText", &UILineEdit::clearText);
// UIWindow
g_lua.registerClass<UIWindow, UIWidget>();
g_lua.bindClassStaticFunction<UIWindow>("create", &UIWindow::create);
g_lua.bindClassMemberField("title", &UIWindow::getTitle, &UIWindow::setTitle);
g_lua.bindClassMemberFunction<UIWindow>("getTitle", &UIWindow::getTitle);
g_lua.bindClassMemberFunction<UIWindow>("setTitle", &UIWindow::setTitle);
// Protocol
g_lua.registerClass<Protocol>();
@ -64,6 +84,12 @@ void LuaInterface::registerFunctions()
g_lua.bindClassStaticFunction<Configs>("set", std::bind(&Configs::set, &g_configs, _1, _2));
g_lua.bindClassStaticFunction<Configs>("get", std::bind(&Configs::get, &g_configs, _1));
// Logger
g_lua.registerClass<Logger>();
g_lua.bindClassStaticFunction<Logger>("log", std::bind(&Logger::log, &g_logger, _1, _2));
g_lua.bindClassStaticFunction<Logger>("fireOldMessages", std::bind(&Logger::fireOldMessages, &g_logger));
g_lua.bindClassStaticFunction<Logger>("setOnLog", std::bind(&Logger::setOnLog, &g_logger, _1));
// global functions
g_lua.bindGlobalFunction("importFont", std::bind(&FontManager::importFont, &g_fonts, _1));
g_lua.bindGlobalFunction("importStyles", std::bind(&UIManager::importStyles, &g_ui, _1));

View File

@ -422,7 +422,7 @@ int LuaInterface::protectedCall(int numArgs, int requestedResults)
throw LuaException("attempt to call a non function value", 0);
}
} catch(LuaException &e) {
logError(e.what());
logError("protected lua call failed: ", e.what());
}
// pushes nil values if needed
@ -457,7 +457,7 @@ int LuaInterface::luaScriptLoader(lua_State* L)
g_lua.loadScript(fileName);
return 1;
} catch(LuaException& e) {
logError("ERROR: failed to load script file '", fileName, "' :'", e.what());
logError("failed to load script file '", fileName, "' :'", e.what());
return 0;
}
}
@ -489,7 +489,7 @@ int LuaInterface::luaCppFunctionCallback(lua_State* L)
numRets = (*(funcPtr->get()))(&g_lua);
assert(numRets == g_lua.stackSize());
} catch(LuaException &e) {
logError(e.what());
logError("lua cpp callback failed: ", e.what());
}
return numRets;

View File

@ -7,10 +7,10 @@ LuaObject::LuaObject() : m_fieldsTableRef(-1)
LuaObject::~LuaObject()
{
luaReleaseFieldsTable();
releaseLuaFieldsTable();
}
void LuaObject::luaReleaseFieldsTable()
void LuaObject::releaseLuaFieldsTable()
{
if(m_fieldsTableRef != -1)
g_lua.unref(m_fieldsTableRef);

View File

@ -15,6 +15,8 @@ public:
/// @return the number of results
template<typename... T>
int callLuaField(const std::string& field, const T&... args);
template<typename R, typename... T>
R callLuaField(const std::string& field, const T&... args);
/// Sets a field in this lua object
template<typename T>
@ -25,7 +27,7 @@ public:
T getLuaField(const std::string& key);
/// Release fields table reference
void luaReleaseFieldsTable();
void releaseLuaFieldsTable();
/// Sets a field from this lua object, the value must be on the stack
void luaSetField(const std::string& key);
@ -61,12 +63,28 @@ int LuaObject::callLuaField(const std::string& field, const T&... args) {
g_lua.pushObject(asLuaObject());
g_lua.getField(field);
// the first argument is always this object (self)
g_lua.insert(-2);
g_lua.polymorphicPush(args...);
return g_lua.protectedCall(1 + sizeof...(args));
if(!g_lua.isNil()) {
// the first argument is always this object (self)
g_lua.insert(-2);
g_lua.polymorphicPush(args...);
return g_lua.protectedCall(1 + sizeof...(args));
} else {
g_lua.pop(2);
}
}
return 0;
}
template<typename R, typename... T>
R LuaObject::callLuaField(const std::string& field, const T&... args) {
R result;
int rets = callLuaField(field, args...);
if(rets > 0) {
assert(rets == 1);
result = g_lua.polymorphicPop<R>();
} else
return 0;
result = R();
return result;
}
template<typename T>

View File

@ -42,6 +42,20 @@ bool luavalue_cast(int index, double& d)
return true;
}
// size_t
void push_luavalue(std::size_t s)
{
push_luavalue((double)s);
}
bool luavalue_cast(int index, std::size_t& s)
{
double d;
bool ret = luavalue_cast(index, d);
s = d;
return ret;
}
// string
void push_luavalue(const char* cstr)
{

View File

@ -18,6 +18,10 @@ bool luavalue_cast(int index, int& i);
void push_luavalue(double d);
bool luavalue_cast(int index, double& d);
// size_t
void push_luavalue(std::size_t s);
bool luavalue_cast(int index, std::size_t& s);
// string
void push_luavalue(const char* cstr);
void push_luavalue(const std::string& str);
@ -131,7 +135,7 @@ bool luavalue_cast(int index, std::function<void(Args...)>& func) {
"did you forget to hold a reference for that function?", 0);
}
} catch(std::exception& e) {
logError(e.what());
logError("lua function callback failed: ", e.what());
}
};
return true;
@ -165,7 +169,7 @@ luavalue_cast(int index, std::function<Ret(Args...)>& func) {
"did you forget to hold a reference for that function?", 0);
}
} catch(std::exception& e) {
logError(e.what());
logError("lua function callback failed: ", e.what());
}
return Ret();
};

View File

@ -67,7 +67,7 @@ void Protocol::internalRecvData(uint8* buffer, uint16 size)
uint32 checksum = getAdlerChecksum(m_inputMessage.getBuffer() + InputMessage::DATA_POS, m_inputMessage.getMessageSize() - InputMessage::CHECKSUM_LENGTH);
if(m_inputMessage.getU32() != checksum) {
// error
logError("ERROR: got a network message with invalid checksum");
logError("got a network message with invalid checksum");
return;
}
}
@ -93,7 +93,7 @@ bool Protocol::xteaDecrypt(InputMessage& inputMessage)
// FIXME: this function has not been tested yet
uint16 messageSize = inputMessage.getMessageSize() - InputMessage::CHECKSUM_LENGTH;
if(messageSize % 8 != 0) {
logError("ERROR: invalid encrypted network message");
logError("invalid encrypted network message");
return false;
}
@ -116,7 +116,7 @@ bool Protocol::xteaDecrypt(InputMessage& inputMessage)
int tmp = inputMessage.getU16();
if(tmp > inputMessage.getMessageSize() - 4) {
logDebug("ERROR: invalid decrypted a network message");
logError("invalid decrypted a network message");
return false;
}

View File

@ -6,7 +6,6 @@
class OTMLDocument : public OTMLNode
{
public:
OTMLDocument() { }
virtual ~OTMLDocument() { }
/// Create a new OTML document for filling it with nodes
@ -24,6 +23,9 @@ public:
/// Save this document to a file
bool save(const std::string& fileName);
private:
OTMLDocument() { }
};
#endif

View File

@ -161,7 +161,6 @@ enum PlatformEventType {
EventMouseLeftButton = 32,
EventMouseRightButton = 64,
EventMouseMidButton = 128,
EventTextEnter = 256,
EventKeyDown = EventKeyboardAction | EventDown,
EventKeyUp = EventKeyboardAction | EventUp,
EventMouseMove = EventMouseAction | 512,

View File

@ -217,17 +217,17 @@ void Platform::init(PlatformListener* platformListener, const char *appName)
// open display
x11.display = XOpenDisplay(0);
if(!x11.display)
logFatal("FATAL ERROR: Failed to open X display");
logFatal("Failed to open X display");
// check if GLX is supported on this display
if(!glXQueryExtension(x11.display, 0, 0))
logFatal("FATAL ERROR: GLX not supported");
logFatal("GLX not supported");
// retrieve GLX version
int glxMajor;
int glxMinor;
if(!glXQueryVersion(x11.display, &glxMajor, &glxMinor))
logFatal("FATAL ERROR: Unable to query GLX version");
logFatal("Unable to query GLX version");
logInfo("GLX version ",glxMajor,".",glxMinor);
// clipboard related atoms
@ -313,6 +313,7 @@ void Platform::poll()
inputEvent.ctrl = (event.xkey.state & ControlMask);
inputEvent.shift = (event.xkey.state & ShiftMask);
inputEvent.alt = (event.xkey.state & Mod1Mask);
inputEvent.keychar = 0;
// fire enter text event
if(event.type == KeyPress && !inputEvent.ctrl && !inputEvent.alt) {
@ -325,7 +326,7 @@ void Platform::poll()
}
if(len > 0 &&
// for some reason these keys produces characters and we don't want that
// these keys produces characters that we don't want to capture
keysym != XK_BackSpace &&
keysym != XK_Return &&
keysym != XK_Delete &&
@ -333,10 +334,7 @@ void Platform::poll()
(uchar)(buf[0]) >= 32
) {
//logDebug("char: ", buf[0], " code: ", (uint)buf[0]);
inputEvent.type = EventTextEnter;
inputEvent.keychar = buf[0];
inputEvent.keycode = KC_UNKNOWN;
m_listener->onPlatformEvent(inputEvent);
}
}
@ -344,13 +342,19 @@ void Platform::poll()
event.xkey.state &= ~(ShiftMask | LockMask);
len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, 0);
// fire key up/down event
if(x11.keyMap.find(keysym) != x11.keyMap.end()) {
inputEvent.keycode = x11.keyMap[keysym];
inputEvent.type = (event.type == KeyPress) ? EventKeyDown : EventKeyUp;
if(inputEvent.keychar == 0)
inputEvent.keychar = (len > 0) ? buf[0] : 0;
if(x11.keyMap.find(keysym) != x11.keyMap.end())
inputEvent.keycode = x11.keyMap[keysym];
else
inputEvent.keycode = KC_UNKNOWN;
inputEvent.keycode = x11.keyMap[keysym];
inputEvent.type = (event.type == KeyPress) ? EventKeyDown : EventKeyUp;
if(inputEvent.keycode != KC_UNKNOWN || inputEvent.keychar != 0)
m_listener->onPlatformEvent(inputEvent);
}
break;
}
case ButtonPress:
@ -480,12 +484,12 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i
// choose OpenGL, RGBA, double buffered, visual
x11.visual = glXChooseVisual(x11.display, DefaultScreen(x11.display), attrList);
if(!x11.visual)
logFatal("FATAL ERROR: RGBA/Double buffered visual not supported");
logFatal("RGBA/Double buffered visual not supported");
// create GLX context
x11.glxContext = glXCreateContext(x11.display, x11.visual, 0, GL_TRUE);
if(!x11.glxContext)
logFatal("FATAL ERROR: Unable to create GLX context");
logFatal("Unable to create GLX context");
// color map
x11.colormap = XCreateColormap(x11.display,
@ -518,7 +522,7 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i
&wa);
if(!x11.window)
logFatal("FATAL ERROR: Unable to create X window");
logFatal("Unable to create X window");
// create input context (to have better key input handling)
if(XSupportsLocale()) {
@ -530,11 +534,11 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i
XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, x11.window, NULL);
if(!x11.xic)
logError("ERROR: Unable to create the input context");
logError("Unable to create the input context");
} else
logError("ERROR: Failed to open an input method");
logError("Failed to open an input method");
} else
logError("ERROR: X11 does not support the current locale");
logError("X11 does not support the current locale");
if(!x11.xic)
logWarning("Input of special keys maybe messed up because we couldn't create an input context");
@ -823,6 +827,6 @@ std::string Platform::getAppUserDir()
std::stringstream sdir;
sdir << PHYSFS_getUserDir() << "." << x11.appName;
if((mkdir(sdir.str().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST))
logError("ERROR: Couldn't create directory for saving configuration file. (",sdir.str(),")");
logError("Couldn't create directory for saving configuration file. (",sdir.str(),")");
return sdir.str();
}

View File

@ -9,7 +9,8 @@ enum UIWidgetType {
UITypeButton,
UITypeLineEdit,
UITypeWindow,
UITypeList
UITypeList,
UITypeConsole
};
enum FocusReason {

View File

@ -13,6 +13,7 @@ class UILabel;
class UIButton;
class UILineEdit;
class UIWindow;
class UIConsole;
typedef std::shared_ptr<UIWidget> UIWidgetPtr;
typedef std::weak_ptr<UIWidget> UIWidgetWeakPtr;
@ -25,5 +26,6 @@ typedef std::shared_ptr<UILabel> UILabelPtr;
typedef std::shared_ptr<UIButton> UIButtonPtr;
typedef std::shared_ptr<UILineEdit> UILineEditPtr;
typedef std::shared_ptr<UIWindow> UIWindowPtr;
typedef std::shared_ptr<UIConsole> UIConsolePtr;
#endif

View File

@ -8,23 +8,32 @@ bool UIAnchorLayout::addAnchor(const UIWidgetPtr& anchoredWidget, AnchorPoint an
/*
if(!anchorLineWidget) {
logError("ERROR: could not find the widget to anchor on, wrong id?");
logError("could not find the widget to anchor on, wrong id?");
return false;
}
*/
// we can never anchor with itself
if(anchoredWidget == anchorLineWidget) {
logError("ERROR: anchoring with itself is not possible");
logError("anchoring with itself is not possible");
return false;
}
// we must never anchor to an anchor child
if(anchoredWidget && hasWidgetInAnchorTree(anchorLineWidget, anchoredWidget)) {
logError("ERROR: anchors is miss configured, you must never make an anchor chains in loops");
logError("anchors is miss configured, you must never make an anchor chains in loops");
return false;
}
// avoid duplicated anchors
for(auto it = m_anchors.begin(); it != m_anchors.end(); ++it) {
const UIAnchor& otherAnchor = *it;
if(otherAnchor.getAnchoredWidget() == anchoredWidget && otherAnchor.getAnchoredEdge() == anchoredEdge) {
m_anchors.erase(it);
break;
}
}
// setup the anchor
m_anchors.push_back(anchor);

View File

@ -3,6 +3,7 @@
#include <framework/graphics/font.h>
#include <framework/otml/otmlnode.h>
#include <framework/luascript/luainterface.h>
#include <framework/graphics/graphics.h>
UIButton::UIButton(): UIWidget(UITypeButton)
{
@ -25,8 +26,8 @@ void UIButton::loadStyleFromOTML(const OTMLNodePtr& styleNode)
for(int i=0; i<3; ++i) {
m_statesStyle[i].image = m_image;
m_statesStyle[i].color = m_color;
m_statesStyle[i].fontColor = m_fontColor;
m_statesStyle[i].color = m_backgroundColor;
m_statesStyle[i].foregroundColor = m_foregroundColor;
m_statesStyle[i].textTranslate = Point(0,0);
}
@ -40,8 +41,8 @@ void UIButton::loadStyleFromOTML(const OTMLNodePtr& styleNode)
m_text = styleNode->valueAt("text", fw::empty_string);
if(OTMLNodePtr node = styleNode->get("onClick")) {
g_lua.loadFunction(node->value<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
luaSetField("onClick");
g_lua.loadFunction(node->value(), "@" + node->source() + "[" + node->tag() + "]");
luaSetField(node->tag());
}
}
@ -52,20 +53,24 @@ void UIButton::loadStateStyle(ButtonStateStyle& stateStyle, const OTMLNodePtr& s
if(OTMLNodePtr node = stateStyleNode->get("image"))
stateStyle.image = Image::loadFromOTML(node);
stateStyle.textTranslate = stateStyleNode->valueAt("text-translate", Point());
stateStyle.color = stateStyleNode->valueAt("font-color", m_fontColor);
stateStyle.color = stateStyleNode->valueAt("color", m_color);
stateStyle.color = stateStyleNode->valueAt("font-color", m_foregroundColor);
stateStyle.color = stateStyleNode->valueAt("color", m_backgroundColor);
}
void UIButton::render()
{
UIWidget::render();
const ButtonStateStyle& currentStyle = m_statesStyle[m_state];
Rect textRect = getGeometry();
if(currentStyle.image)
if(currentStyle.image) {
g_graphics.bindColor(currentStyle.color);
currentStyle.image->draw(textRect);
}
textRect.translate(currentStyle.textTranslate);
getFont()->renderText(m_text, textRect, AlignCenter, currentStyle.fontColor);
m_font->renderText(m_text, textRect, AlignCenter, currentStyle.foregroundColor);
}
void UIButton::onHoverChange(UIHoverEvent& event)

View File

@ -8,7 +8,7 @@ class UIButton : public UIWidget
struct ButtonStateStyle {
ImagePtr image;
Point textTranslate;
Color fontColor;
Color foregroundColor;
Color color;
};

View File

@ -10,7 +10,6 @@ UILabel::UILabel() : UIWidget(UITypeLabel)
UILabelPtr UILabel::create()
{
UILabelPtr label(new UILabel);
label->setStyle("Label");
return label;
}
@ -23,17 +22,23 @@ void UILabel::loadStyleFromOTML(const OTMLNodePtr& styleNode)
if(styleNode->hasChildAt("align"))
m_align = fw::translateAlignment(styleNode->valueAt("align"));
// auto resize if no size supplied
if(!m_text.empty() && !getGeometry().isValid())
resizeToText();
// auto resize if needed
if(!m_text.empty() && !m_rect.isValid()) {
Size textSize = m_font->calculateTextRectSize(m_text);
if(m_rect.width() <= 0)
m_rect.setWidth(textSize.width());
if(m_rect.height() <= 0)
m_rect.setHeight(textSize.height());
}
}
void UILabel::render()
{
m_font->renderText(m_text, m_rect, m_align, m_fontColor);
UIWidget::render();
m_font->renderText(m_text, m_rect, m_align, m_foregroundColor);
}
void UILabel::resizeToText()
{
resize(getFont()->calculateTextRectSize(m_text));
resize(m_font->calculateTextRectSize(m_text));
}

View File

@ -12,6 +12,8 @@ UILineEdit::UILineEdit() : UIWidget(UITypeLabel)
m_textHorizontalMargin = 3;
m_focusable = true;
blinkCursor();
m_onAction = [this]() { this->callLuaField("onAction"); };
}
UILineEditPtr UILineEdit::create()
@ -26,6 +28,11 @@ void UILineEdit::loadStyleFromOTML(const OTMLNodePtr& styleNode)
UIWidget::loadStyleFromOTML(styleNode);
setText(styleNode->valueAt("text", getText()));
if(OTMLNodePtr node = styleNode->get("onAction")) {
g_lua.loadFunction(node->value(), "@" + node->source() + "[" + node->tag() + "]");
luaSetField(node->tag());
}
}
void UILineEdit::render()
@ -53,7 +60,7 @@ void UILineEdit::render()
cursorRect = Rect(m_drawArea.left()-1, m_drawArea.top(), 1, m_font->getGlyphHeight());
else
cursorRect = Rect(m_glyphsCoords[m_cursorPos-1].right(), m_glyphsCoords[m_cursorPos-1].top(), 1, m_font->getGlyphHeight());
g_graphics.drawFilledRect(cursorRect, m_color);
g_graphics.drawFilledRect(cursorRect);
} else if(ticks - m_cursorTicks >= 2*delay) {
m_cursorTicks = ticks;
}
@ -255,7 +262,7 @@ void UILineEdit::setCursorPos(int pos)
}
}
void UILineEdit::enableCursor(bool enable)
void UILineEdit::setCursorEnabled(bool enable)
{
if(enable) {
m_cursorPos = 0;
@ -357,7 +364,10 @@ void UILineEdit::onKeyPress(UIKeyEvent& event)
setCursorPos(0);
else if(event.keyCode() == KC_END) // move cursor to last character
setCursorPos(m_text.length());
else if(event.keyChar() != 0) {
else if(event.keyCode() == KC_RETURN) {
if(m_onAction)
m_onAction();
} else if(event.keyChar() != 0) {
if(event.keyCode() != KC_TAB && event.keyCode() != KC_RETURN)
appendCharacter(event.keyChar());
else

View File

@ -18,8 +18,9 @@ public:
void setText(const std::string& text);
void setAlign(AlignmentFlag align);
void setCursorPos(int pos);
void enableCursor(bool enable = true);
void setCursorEnabled(bool enable = true);
void clearText() { setText(""); }
void moveCursor(bool right);
void appendCharacter(char c);
void removeCharacter(bool right);
@ -45,6 +46,7 @@ private:
int m_startRenderPos;
int m_cursorTicks;
int m_textHorizontalMargin;
SimpleCallback m_onAction;
std::vector<Rect> m_glyphsCoords;
std::vector<Rect> m_glyphsTexCoords;

View File

@ -97,7 +97,7 @@ bool UIManager::importStyles(const std::string& file)
importStyleFromOTML(styleNode);
return true;
} catch(std::exception& e) {
logError("ERROR: failed to import ui styles from '", file, "':\n", e.what());
logError("failed to import ui styles from '", file, "':\n", e.what());
return false;
}
}
@ -118,7 +118,7 @@ void UIManager::importStyleFromOTML(const OTMLNodePtr& styleNode)
auto it = m_styles.find(name);
if(it != m_styles.end())
logWarning("WARNING: style '", name, "' is being redefined");
logWarning("style '", name, "' is being redefined");
OTMLNodePtr style = getStyle(base)->clone();
style->merge(styleNode);
@ -158,11 +158,9 @@ UIWidgetPtr UIManager::loadUI(const std::string& file)
}
}
// schedule onLoad events
widget->load();
return widget;
} catch(std::exception& e) {
logError("ERROR: failed to load ui from '", file, "':\n", e.what());
logError("failed to load ui from '", file, "':\n", e.what());
return nullptr;
}
}

View File

@ -21,8 +21,8 @@ UIWidget::UIWidget(UIWidgetType type)
m_updateScheduled = false;
m_opacity = 255;
m_marginLeft = m_marginRight = m_marginTop = m_marginBottom = 0;
m_color = Color::white;
m_fontColor = Color::white;
m_backgroundColor = Color::white;
m_foregroundColor = Color::white;
// generate an unique id, this is need because anchored layouts find widgets by id
static unsigned long id = 1;
@ -33,13 +33,12 @@ UIWidget::~UIWidget()
{
//logTraceDebug(m_id);
if(!m_destroyed)
logWarning("WARNING: widget '", m_id, "' was destructed without being explicit destroyed");
logWarning("widget '", m_id, "' was destructed without being explicit destroyed");
}
UIWidgetPtr UIWidget::create()
{
UIWidgetPtr widget(new UIWidget);
//widget->setStyle("Widget");
return widget;
}
@ -48,6 +47,8 @@ void UIWidget::destroy()
//TODO: onDestroy event
// destroy only once
if(!m_destroyed) {
releaseLuaFieldsTable();
// clear additional reference
m_lockedWidgets.clear();
m_focusedChild.reset();
@ -68,7 +69,7 @@ void UIWidget::destroy()
m_enabled = false;
m_visible = false;
} else
logWarning("WARNING: attempt to destroy widget '", m_id, "' again");
logWarning("attempt to destroy widget '", m_id, "' again");
}
void UIWidget::destroyCheck()
@ -81,21 +82,7 @@ void UIWidget::destroyCheck()
// check for leaks upon widget destruction
if(realUseCount > 0)
logWarning("WARNING: destroyed widget with id '",m_id,"', but it still have ",realUseCount," references left");
}
void UIWidget::load()
{
for(const UIWidgetPtr& child : m_children)
child->load();
// schedule onLoad
UIWidgetPtr self = asUIWidget();
g_dispatcher.addEvent([self]() {
// this widget could be destroyed before the event happens
if(!self->isDestroyed())
self->callLuaField("onLoad");
});
logWarning("destroyed widget with id '",m_id,"', but it still have ",realUseCount," references left");
}
void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
@ -120,12 +107,12 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
setFont(g_fonts.getFont(node->value()));
}
// font color
else if(node->tag() == "font-color") {
setFontColor(node->value<Color>());
else if(node->tag() == "color") {
setForegroundColor(node->value<Color>());
}
// color
else if(node->tag() == "color") {
setColor(node->value<Color>());
else if(node->tag() == "background-color") {
setBackgroundColor(node->value<Color>());
}
// opacity
else if(node->tag() == "opacity") {
@ -197,9 +184,6 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
luaSetField("onLoad");
}
}
if(!m_font)
m_font = g_fonts.getDefaultFont();
}
void UIWidget::render()
@ -215,9 +199,13 @@ void UIWidget::render()
if(child->getOpacity() < oldOpacity)
g_graphics.setOpacity(child->getOpacity());
g_graphics.bindColor(child->getColor());
g_graphics.bindColor(child->getBackgroundColor());
child->render();
// debug draw box
//g_graphics.bindColor(Color::green);
//g_graphics.drawBoundingRect(child->getGeometry());
g_graphics.setOpacity(oldOpacity);
}
}
@ -227,8 +215,10 @@ void UIWidget::updateGeometry()
{
assert(!m_destroyed);
if(UILayoutPtr layout = getLayout())
if(UILayoutPtr layout = getLayout()) {
layout->updateWidget(asUIWidget());
layout->updateWidgetChildren(asUIWidget());
}
}
void UIWidget::setParent(const UIWidgetPtr& parent)
@ -260,7 +250,7 @@ void UIWidget::setStyle(const std::string& styleName)
// forces layout recalculation
updateGeometry();
} catch(std::exception& e) {
logError("ERROR: couldn't change widget '", m_id, "' style: ", e.what());
logError("couldn't change widget '", m_id, "' style: ", e.what());
}
}
@ -287,15 +277,6 @@ void UIWidget::setGeometry(const Rect& rect)
}
}
void UIWidget::lock()
{
assert(!m_destroyed);
UIWidgetPtr parent = getParent();
if(parent)
parent->lockChild(asUIWidget());
}
bool UIWidget::isEnabled()
{
if(!m_enabled)
@ -401,7 +382,7 @@ UIWidgetPtr UIWidget::getChildByPos(const Point& childPos)
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
const UIWidgetPtr& widget = (*it);
if(widget->getGeometry().contains(childPos))
if(widget->isVisible() && widget->getGeometry().contains(childPos))
return widget;
}
@ -533,14 +514,40 @@ void UIWidget::addChild(const UIWidgetPtr& childToAdd)
m_children.push_back(childToAdd);
childToAdd->setParent(asUIWidget());
// updates child position
childToAdd->updateGeometry();
// updates geometry
updateGeometry();
// focus it if there is no focused child yet
if(!m_focusedChild && childToAdd->isFocusable())
focusChild(childToAdd, ActiveFocusReason);
}
void UIWidget::insertChild(const UIWidgetPtr& childToInsert, int index)
{
assert(!m_destroyed);
if(!childToInsert)
return;
assert(!hasChild(childToInsert));
if(index < 0)
index = m_children.size() + index -1;
assert((uint)index <= m_children.size());
auto it = m_children.begin() + index;
m_children.insert(it, childToInsert);
childToInsert->setParent(asUIWidget());
// updates geometry
updateGeometry();
// focus it if there is no focused child yet
if(!m_focusedChild && childToInsert->isFocusable())
focusChild(childToInsert, ActiveFocusReason);
}
void UIWidget::removeChild(const UIWidgetPtr& childToRemove)
{
assert(!m_destroyed);
@ -612,6 +619,9 @@ void UIWidget::lockChild(const UIWidgetPtr& childToLock)
}
m_lockedWidgets.push_front(childToLock);
// move locked child to top
moveChildToTop(childToLock);
}
void UIWidget::unlockChild(const UIWidgetPtr& childToUnlock)
@ -619,21 +629,21 @@ void UIWidget::unlockChild(const UIWidgetPtr& childToUnlock)
assert(hasChild(childToUnlock));
auto it = std::find(m_lockedWidgets.begin(), m_lockedWidgets.end(), childToUnlock);
if(it != m_lockedWidgets.end()) {
if(it != m_lockedWidgets.end())
m_lockedWidgets.erase(it);
UIWidgetPtr newLockedWidget;
if(m_lockedWidgets.size() > 0)
newLockedWidget = m_lockedWidgets.front();
for(const UIWidgetPtr& child : m_children) {
if(newLockedWidget) {
if(child == newLockedWidget)
child->setEnabled(true);
else
child->setEnabled(false);
} else
UIWidgetPtr newLockedWidget;
if(m_lockedWidgets.size() > 0)
newLockedWidget = m_lockedWidgets.front();
for(const UIWidgetPtr& child : m_children) {
if(newLockedWidget) {
if(child == newLockedWidget)
child->setEnabled(true);
}
else
child->setEnabled(false);
} else
child->setEnabled(true);
}
}

View File

@ -15,12 +15,12 @@ public:
static UIWidgetPtr create();
/// Must be called just after the widget creation
virtual void setup() { }
/// Remove this widget from parent then destroy it and its children
virtual void destroy();
/// Called after the widget is loaded from OTML file, to execute onLoad event
virtual void load();
/// Load style from otml node
virtual void loadStyleFromOTML(const OTMLNodePtr& styleNode);
@ -50,8 +50,8 @@ public:
void setImage(const ImagePtr& image) { m_image = image; }
virtual void setFont(const FontPtr& font) { m_font = font; }
void setOpacity(int opacity) { m_opacity = opacity; }
void setColor(const Color& color) { m_color = color; }
void setFontColor(const Color& color) { m_fontColor = color; }
void setBackgroundColor(const Color& color) { m_backgroundColor = color; }
void setForegroundColor(const Color& color) { m_foregroundColor = color; }
void setMarginLeft(int margin) { m_marginLeft = margin; updateGeometry(); }
void setMarginRight(int margin) { m_marginRight = margin; updateGeometry(); }
void setMarginTop(int margin) { m_marginTop = margin; updateGeometry(); }
@ -61,7 +61,6 @@ public:
void show() { setVisible(true); }
void disable() { setEnabled(false); }
void enable() { setEnabled(true); }
void lock();
bool isEnabled();
bool isExplicitlyEnabled() const { return m_enabled; }
@ -88,8 +87,8 @@ public:
ImagePtr getImage() const { return m_image; }
FontPtr getFont() const { return m_font; }
Color getFontColor() const { return m_fontColor; }
Color getColor() const { return m_color; }
Color getForegroundColor() const { return m_foregroundColor; }
Color getBackgroundColor() const { return m_backgroundColor; }
int getOpacity() const { return m_opacity; }
int getMarginLeft() const { return m_marginLeft; }
int getMarginRight() const { return m_marginRight; }
@ -108,6 +107,7 @@ public:
UIWidgetPtr backwardsGetWidgetById(const std::string& id);
void addChild(const UIWidgetPtr& childToAdd);
void insertChild(const UIWidgetPtr& childToInsert, int index);
void removeChild(const UIWidgetPtr& childToRemove);
void focusChild(const UIWidgetPtr& childToFocus, FocusReason reason);
void focusNextChild(FocusReason reason);
@ -169,8 +169,8 @@ protected:
ImagePtr m_image;
FontPtr m_font;
int m_opacity;
Color m_color;
Color m_fontColor;
Color m_backgroundColor;
Color m_foregroundColor;
int m_marginLeft;
int m_marginRight;
int m_marginTop;

View File

@ -55,7 +55,7 @@ void UIWindow::render()
headTextRect.addLeft(-m_headMargin);
else if(m_titleAlign & AlignRight)
headTextRect.addRight(-m_headMargin);
m_font->renderText(m_title, headTextRect, m_titleAlign, m_fontColor);
m_font->renderText(m_title, headTextRect, m_titleAlign, m_foregroundColor);
}
// draw window body

View File

@ -2,7 +2,7 @@
#define COLOR_H
#include "types.h"
#include <sstream>
#include "tools.h"
typedef uint32 RGBA;
@ -69,10 +69,19 @@ inline std::istream& operator>>(std::istream& in, Color& color)
using namespace std;
if(in.get() == '#') {
uint32 tmp;
in >> hex >> tmp;
color.setABGR(tmp);
in >> dec;
std::string tmp;
in >> tmp;
if(tmp.length() == 6 || tmp.length() == 8) {
color.setRed((uint8)fw::hex2dec(tmp.substr(0, 2)));
color.setGreen((uint8)fw::hex2dec(tmp.substr(2, 2)));
color.setBlue((uint8)fw::hex2dec(tmp.substr(4, 2)));
if(tmp.length() == 8)
color.setAlpha((uint8)fw::hex2dec(tmp.substr(6, 2)));
else
color.setAlpha(255);
} else
in.seekg(-tmp.length()-1, ios_base::cur);
}
return in;
}

View File

@ -1,19 +0,0 @@
#include "logger.h"
#include <cstdlib>
void Logger::log(LogLevel level, const std::string& message, std::string prettyFunction)
{
if(!prettyFunction.empty()) {
prettyFunction = prettyFunction.substr(0, prettyFunction.find_first_of('('));
if(prettyFunction.find_last_of(' ') != std::string::npos)
prettyFunction = prettyFunction.substr(prettyFunction.find_last_of(' ') + 1);
if(!prettyFunction.empty())
std::cout << "[" << prettyFunction << "] ";
}
std::cout << message << std::endl;
if(level == LogFatal)
exit(-1);
}

View File

@ -1,33 +0,0 @@
#ifndef LOGGER_H
#define LOGGER_H
#include "tools.h"
//TODO: a real logger
class Logger
{
public:
enum LogLevel {
LogDebug = 0,
LogInfo,
LogWarning,
LogError,
LogFatal
};
static void log(LogLevel level, const std::string& message, std::string prettyFunction = "");
};
// specialized logging
#define logDebug(...) Logger::log(Logger::LogDebug, fw::mkstr(__VA_ARGS__))
#define logInfo(...) Logger::log(Logger::LogInfo, fw::mkstr(__VA_ARGS__))
#define logWarning(...) Logger::log(Logger::LogWarning, fw::mkstr(__VA_ARGS__))
#define logError(...) Logger::log(Logger::LogError, fw::mkstr(__VA_ARGS__))
#define logFatal(...) Logger::log(Logger::LogFatal, fw::mkstr(__VA_ARGS__))
#define logTrace() Logger::log(Logger::LogDebug, "", __PRETTY_FUNCTION__)
#define logTraceDebug(...) Logger::log(Logger::LogDebug, fw::mkstr(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTraceInfo(...) Logger::log(Logger::LogInfo, fw::mkstr(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTraceWarning(...) log(Logger::LogWarning, fw::mkstr(__VA_ARGS__), __PRETTY_FUNCTION__)
#define logTraceError(...) Logger::log(Logger::LogError, fw::mkstr(__VA_ARGS__), __PRETTY_FUNCTION__)
#endif

View File

@ -197,7 +197,7 @@ R unsafe_cast(const T& t, R def = R()) {
try {
return safe_cast<R,T>(t);
} catch(bad_cast& e) {
println(e.what());
println("CAST ERROR: ", e.what());
return def;
}
}
@ -212,6 +212,21 @@ T fromstring(const std::string& str, T def = T()) {
return unsafe_cast<T, std::string>(str, def);
}
inline std::string dec2hex(unsigned int num) {
std::string str;
std::ostringstream o;
o << std::hex << num;
str = o.str();
return str;
}
inline unsigned int hex2dec(const std::string& str) {
unsigned int num;
std::istringstream i(str);
i >> std::hex >> num;
return num;
}
// an empty string to use anywhere needed
const static std::string empty_string;

View File

@ -60,8 +60,15 @@ void Creature::draw(int x, int y)
}
Rect healthRect = Rect(x - 14, y - 11, 27, 4);
g_graphics.drawBoundingRect(healthRect, Color::black);
g_graphics.drawFilledRect(healthRect.expanded(-1), healthColor);
g_graphics.bindColor(Color::black);
g_graphics.drawBoundingRect(healthRect);
g_graphics.bindColor(healthColor);
g_graphics.drawFilledRect(healthRect.expanded(-1));
// restore white color
g_graphics.bindColor(Color::white);
}
const ThingAttributes& Creature::getAttributes()

View File

@ -34,7 +34,7 @@ bool DatManager::load(const std::string& file)
return true;
} catch(std::exception& e) {
logError("ERROR: failed to load dat from '", file, "': ", e.what());
logError("failed to load dat from '", file, "': ", e.what());
return false;
}
}

View File

@ -48,9 +48,12 @@ void Map::draw(int x, int y)
}
// debug draws
g_graphics.drawBoundingRect(Rect(7*32, 5*32, 32, 32), Color::red);
g_graphics.bindColor(Color::red);
g_graphics.drawBoundingRect(Rect(7*32, 5*32, 32, 32));
m_framebuffer->unbind();
g_graphics.bindColor(Color::white);
m_framebuffer->draw(Rect(x, y, g_graphics.getScreenSize()));
}

View File

@ -10,16 +10,16 @@ SpriteManager::SpriteManager()
m_signature = 0;
}
bool SpriteManager::load(const std::string &filename)
bool SpriteManager::load(const std::string& file)
{
try {
g_resources.loadFile(filename, m_fin);
g_resources.loadFile(file, m_fin);
m_signature = fw::getu32(m_fin);
m_spritesCount = fw::getu16(m_fin);
m_sprites.resize(m_spritesCount);
return true;
} catch(std::exception& e) {
logError(e.what());
logError("faile to load sprites from '", file, "': ", e.what());
return false;
}
}

View File

@ -14,7 +14,7 @@ class SpriteManager
public:
SpriteManager();
bool load(const std::string& filename);
bool load(const std::string& file);
void unload();
uint32 getSignature() { return m_signature; }

View File

@ -92,7 +92,7 @@ void OTClient::run()
m_running = true;
if(g_ui.getRootWidget()->getChildCount() == 0) {
logError("ERROR: there is no root widgets to display, the app will close");
logError("there is no root widgets to display, the app will close");
m_stopping = true;
}
@ -251,7 +251,7 @@ void OTClient::saveConfigurations()
// saves user configuration
if(!g_configs.save())
logError("ERROR: configurations are lost because it couldn't be saved");
logError("configurations are lost because it couldn't be saved");
}
void OTClient::onClose()
@ -270,28 +270,43 @@ void OTClient::onResize(const Size& size)
void OTClient::onPlatformEvent(const PlatformEvent& event)
{
g_ui.inputEvent(event);
bool fireUi = true;
if(event.type == EventKeyDown) {
if(!event.ctrl) {
if(!event.ctrl && !event.alt && !event.shift) {
if(event.keycode == KC_UP)
g_game.walk(DIRECTION_NORTH);
if(event.keycode == KC_RIGHT)
else if(event.keycode == KC_RIGHT)
g_game.walk(DIRECTION_EAST);
if(event.keycode == KC_DOWN)
else if(event.keycode == KC_DOWN)
g_game.walk(DIRECTION_SOUTH);
if(event.keycode == KC_LEFT)
else if(event.keycode == KC_LEFT)
g_game.walk(DIRECTION_WEST);
}
else {
else if(event.ctrl && !event.alt && !event.shift) {
if(event.keycode == KC_UP)
g_game.turn(DIRECTION_NORTH);
if(event.keycode == KC_RIGHT)
else if(event.keycode == KC_RIGHT)
g_game.turn(DIRECTION_EAST);
if(event.keycode == KC_DOWN)
else if(event.keycode == KC_DOWN)
g_game.turn(DIRECTION_SOUTH);
if(event.keycode == KC_LEFT)
else if(event.keycode == KC_LEFT)
g_game.turn(DIRECTION_WEST);
else if(event.keycode == KC_APOSTROPHE) {
// TODO: move these events to lua
UIWidgetPtr console = g_ui.getRootWidget()->getChildById("consolePanel");
if(!console->isVisible()) {
g_ui.getRootWidget()->lockChild(console);
console->setVisible(true);
} else {
g_ui.getRootWidget()->unlockChild(console);
console->setVisible(false);
}
fireUi = false;
}
}
}
if(fireUi)
g_ui.inputEvent(event);
}

View File

@ -1,6 +1,7 @@
#ifndef OTCLIENT_H
#define OTCLIENT_H
#include <framework/ui/declarations.h>
#include <framework/platform/platformlistener.h>
class OTClient : public PlatformListener