Merge branch 'master' of github.com:edubart/otclient

master
Henrique 13 years ago
commit 8f27ff60ac

@ -128,8 +128,9 @@ SET(SOURCES
src/framework/ui/uibutton.cpp src/framework/ui/uibutton.cpp
src/framework/ui/uilineedit.cpp src/framework/ui/uilineedit.cpp
src/framework/ui/uiwindow.cpp src/framework/ui/uiwindow.cpp
src/framework/ui/uianchor.cpp src/framework/ui/uianchorlayout.cpp
src/framework/ui/uilist.cpp src/framework/ui/uiverticallayout.cpp
src/framework/ui/uilayout.cpp
) )
IF(WIN32) IF(WIN32)

@ -15,14 +15,16 @@ function Console.onLog(level, message, time)
if level == LogDebug then if level == LogDebug then
color = '#5555ff' color = '#5555ff'
elseif level == LogInfo then elseif level == LogInfo then
color = '#55ff55' color = '#5555ff'
elseif level == LogWarning then elseif level == LogWarning then
color = '#ffff00' color = '#ffff00'
else else
color = '#ff0000' color = '#ff0000'
end end
Console.addLine(message, color) if level ~= LogDebug then
Console.addLine(message, color)
end
logLocked = false logLocked = false
end end
@ -32,21 +34,21 @@ function Console.addLine(text, color)
-- create new label -- create new label
local label = UILabel.create() local label = UILabel.create()
label:setStyle('ConsoleLabel') console:insertChild(-2, label)
label:setId('consoleLabel' .. numLines)
label:setText(text) label:setText(text)
label:setForegroundColor(color) label:setForegroundColor(color)
console:insertChild(label, -1) label:setStyle('ConsoleLabel')
numLines = numLines + 1 numLines = numLines + 1
if numLines > maxLines then if numLines > maxLines then
local firstLine = console:getChildByIndex(0) local firstLabel = console:getChildByIndex(1)
firstLine:destroy() firstLabel:destroy()
end end
end end
function Console.create() function Console.create()
console = loadUI("/console/console.otui") console = UI.loadAndDisplay("/console/console.otui")
rootWidget:addChild(console)
console:hide() console:hide()
Logger.setOnLog(Console.onLog) Logger.setOnLog(Console.onLog)

@ -13,7 +13,9 @@ RectPanel
anchors.fill: parent anchors.fill: parent
UILabel UILabel
size: 18 20 id: commandSymbolLabel
size: 20 16
size fixed: true
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
margin.left: 2 margin.left: 2
@ -22,14 +24,13 @@ RectPanel
UILineEdit UILineEdit
id: commandBox id: commandBox
height: 20 height: 16
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: prev.right anchors.left: commandSymbolLabel.right
anchors.right: parent.right anchors.right: parent.right
margin.left: 4
font: terminus-14px-bold font: terminus-14px-bold
onAction: | onAction: |
function(self) function(self)
Console.executeCommand(self:getText()) Console.executeCommand(self:getText())
self:clearText() self:clearText()
end end

@ -13,10 +13,10 @@ Module
require 'constants' require 'constants'
require 'util' require 'util'
require 'widget' require 'widget'
require 'messagebox' require 'ui'
require 'messagebox/messagebox'
require 'dispatcher' require 'dispatcher'
rootWidget = getRootWidget()
return true return true
onUnload: | onUnload: |

@ -10,50 +10,33 @@ function MessageBox.create(title, text, flags)
setmetatable(box, MessageBox) setmetatable(box, MessageBox)
-- create messagebox window -- create messagebox window
local window = UIWindow.create() local window = UI.loadAndDisplayLocked('/core/messagebox/messagebox.otui')
window:setStyle('Window')
window:setId("messageBoxWindow")
window:setTitle(title) window:setTitle(title)
window:centerIn("parent")
rootWidget:addChild(window)
rootWidget:lockChild(window)
-- create messagebox label local label = window:getChildById('messageBoxLabel')
local label = UILabel.create()
label:setStyle('Label') label:setStyle('Label')
label:setId("messageBoxLabel")
label:setText(text) label:setText(text)
label:addAnchor(AnchorHorizontalCenter, window:getId(), AnchorHorizontalCenter)
label:addAnchor(AnchorTop, window:getId(), AnchorTop)
label:setMargin(27, 0)
label:resizeToText() label:resizeToText()
window:addChild(label)
-- set window size based on label size -- set window size based on label size
window:setWidth(label:getWidth() + 60) window:setWidth(label:getWidth() + 60)
window:setHeight(label:getHeight() + 64) window:setHeight(label:getHeight() + 64)
window:updateParentLayout()
-- setup messagebox first button -- setup messagebox first button
local button1 = UIButton.create() local buttonRight = window:getChildById('messageBoxRightButton')
button1:setStyle('Button')
button1:setId("messageBoxButton1")
button1:addAnchor(AnchorBottom, window:getId(), AnchorBottom)
button1:addAnchor(AnchorRight, window:getId(), AnchorRight)
button1:setMargin(10)
button1:setWidth(64)
window:addChild(button1)
if flags == MessageBoxOk then if flags == MessageBoxOk then
button1:setText("Ok") buttonRight:setText("Ok")
box.onOk = EmptyFunction box.onOk = EmptyFunction
button1.onClick = function() buttonRight.onClick = function()
box.onOk() box.onOk()
box:destroy() box:destroy()
end end
elseif flags == MessageBoxCancel then elseif flags == MessageBoxCancel then
button1:setText("Cancel") buttonRight:setText("Cancel")
box.onCancel = EmptyFunction box.onCancel = EmptyFunction
button1.onClick = function() buttonRight.onClick = function()
box.onCancel() box.onCancel()
box:destroy() box:destroy()
end end

@ -0,0 +1,21 @@
Window
id: messageBoxWindow
anchors.centerIn: parent
height: 80
width: 120
Label
id: messageBoxLabel
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
margin.top: 27
margin.bottom : 27
Button
id: messageBoxRightButton
anchors.bottom: parent.bottom
anchors.right: parent.right
margin.right: 10
margin.bottom: 10
width: 64
visible: true

@ -8,11 +8,6 @@ Module
dependencies: dependencies:
- core_fonts - core_fonts
onLoad: | onLoad: |
importStyles('buttons.otui') require 'ui'
importStyles('labels.otui')
importStyles('panels.otui')
importStyles('separators.otui')
importStyles('lineedits.otui')
importStyles('windows.otui')
return true return true

@ -11,7 +11,7 @@ Button < UIButton
source: /core_ui/images/button_hover.png source: /core_ui/images/button_hover.png
border: 5 border: 5
state.down: state.pressed:
text-translate: 1 1 text-translate: 1 1
border-image: border-image:
source: /core_ui/images/button_down.png source: /core_ui/images/button_down.png

@ -0,0 +1,5 @@
TextList < UIWidget
size: 200 200
border-image:
source: /core_ui/images/panel_flat.png
border: 4

@ -2,3 +2,4 @@ HorizontalSeparator < UIWidget
border-image: border-image:
source: /core_ui/images/horizontal_separator.png source: /core_ui/images/horizontal_separator.png
border.top: 2 border.top: 2
height: 2

@ -1,6 +1,8 @@
Window < UIWindow Window < UIWindow
font: helvetica-12px-bold font: helvetica-12px-bold
size: 200 200 size: 200 200
opacity: 255
background-color: #ffffff
head: head:
height: 20 height: 20
border-image: border-image:
@ -17,5 +19,8 @@ Window < UIWindow
border: 4 border: 4
border.top: 0 border.top: 0
state.pressed:
opacity: 192
MainWindow < Window MainWindow < Window
anchors.centerIn: parent anchors.centerIn: parent

@ -0,0 +1,30 @@
UI = { }
UI.root = getRootWidget()
function UI.loadAndDisplayLocked(otuiFile)
local widget = loadUI(otuiFile, UI.root)
UI.root:lockChild(widget)
return widget
end
function UI.loadAndDisplay(otuiFile)
local widget = loadUI(otuiFile, UI.root)
return widget
end
function UI.display(widget)
UI.root:addChild(widget)
end
function UI.displayLocked(widget)
UI.root:addChild(widget)
UI.root:lockChild(widget)
end
importStyles('styles/buttons.otui')
importStyles('styles/labels.otui')
importStyles('styles/panels.otui')
importStyles('styles/separators.otui')
importStyles('styles/lineedits.otui')
importStyles('styles/windows.otui')
importStyles('styles/listboxes.otui')

@ -2,7 +2,7 @@ function EnterGame_connectToLoginServer()
local protocolLogin = ProtocolLogin.create() local protocolLogin = ProtocolLogin.create()
local recreateEnterGame = function() local recreateEnterGame = function()
rootWidget:addChild(loadUI("/mainmenu/ui/entergamewindow.otui")) UI.loadAndDisplayLocked("/mainmenu/ui/entergamewindow.otui")
end end
local loadBox = displayCancelBox("Please wait", "Connecting..") local loadBox = displayCancelBox("Please wait", "Connecting..")
@ -30,7 +30,7 @@ function EnterGame_connectToLoginServer()
mainMenu:hide() mainMenu:hide()
end end
local enterGameWindow = rootWidget:getChildById("enterGameWindow") local enterGameWindow = UI.root:getChildById("enterGameWindow")
local account = enterGameWindow:getChildById("accountNameLineEdit"):getText() local account = enterGameWindow:getChildById("accountNameLineEdit"):getText()
local password = enterGameWindow:getChildById("accountPasswordLineEdit"):getText() local password = enterGameWindow:getChildById("accountPasswordLineEdit"):getText()
protocolLogin:login(account, password) protocolLogin:login(account, password)

@ -12,8 +12,7 @@ Module
require('entergame') require('entergame')
if not initialized then if not initialized then
mainMenu = loadUI("/mainmenu/ui/mainmenu.otui") mainMenu = UI.loadAndDisplay("/mainmenu/ui/mainmenu.otui")
getRootWidget():addChild(mainMenu)
initialized = true initialized = true
end end

@ -0,0 +1,34 @@
MainWindow
id: charactersWindow
title: Charlist
size: 200 250
TextList
id: charactersList
anchors.fill: parent
margin.top: 30
margin.bottom: 50
margin.left: 16
margin.right: 16
Button
id: buttonOk
text: Ok
width: 64
anchors.right: next.left
anchors.bottom: parent.bottom
margin.bottom: 16
margin.right: 16
Button
id: buttonCancel
text: Cancel
width: 64
anchors.right: parent.right
anchors.bottom: parent.bottom
margin.bottom: 16
margin.right: 16
onClick: |
function(self)
self:getParent():destroy()
end

@ -1,7 +1,8 @@
MenuButton < Button MenuButton < Button
anchors.top: prev.bottom margin.bottom: 11
anchors.horizontalCenter: parent.horizontalCenter margin.left: 20
margin.top: 10 margin.right: 20
Panel Panel
id: mainMenuBackground id: mainMenuBackground
@ -9,6 +10,7 @@ Panel
source: /mainmenu/ui/background.png source: /mainmenu/ui/background.png
smooth: true smooth: true
anchors.fill: parent anchors.fill: parent
focusable: false
RoundedPanel RoundedPanel
id: mainMenu id: mainMenu
@ -17,24 +19,20 @@ Panel
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
margin.left: 60 margin.left: 60
margin.bottom: 70 margin.bottom: 70
layout: verticalBox
MenuButton MenuButton
text: Enter Game text: Enter Game
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
margin.top: 18 margin.top: 18
onClick: | onClick: UI.loadAndDisplayLocked("/mainmenu/ui/entergamewindow.otui")
local enterGameWindow = loadUI("/mainmenu/ui/entergamewindow.otui")
rootWidget:addChild(enterGameWindow)
GFX.fadeIn(enterGameWindow)
MenuButton MenuButton
text: Options text: Options
onClick: rootWidget:addChild(loadUI("/mainmenu/ui/optionswindow.otui")) onClick: UI.loadAndDisplayLocked("/mainmenu/ui/optionswindow.otui")
MenuButton MenuButton
text: Info text: Info
onClick: rootWidget:addChild(loadUI("/mainmenu/ui/infowindow.otui")) onClick: UI.loadAndDisplayLocked("/mainmenu/ui/infowindow.otui")
MenuButton MenuButton
text: Exit text: Exit

@ -89,7 +89,7 @@ MainWindow
onClick: displayErrorBox("Error", "Not implemented yet") onClick: displayErrorBox("Error", "Not implemented yet")
Label Label
text: | text: |-
Show the most recent Show the most recent
Message of the Day Message of the Day
anchors.left: prev.right anchors.left: prev.right

@ -0,0 +1 @@
--UI.loadAndDisplayLocked('/mainmenu/ui/charlist.otui')

@ -0,0 +1,10 @@
Module
name: playground
autoLoad: true
dependencies:
- core
onLoad: |
require 'playground'
return true

@ -12,6 +12,7 @@ enum LogLevel {
}; };
enum AlignmentFlag { enum AlignmentFlag {
AlignNone = 0,
AlignLeft = 1, AlignLeft = 1,
AlignRight = 2, AlignRight = 2,
AlignTop = 4, AlignTop = 4,
@ -39,6 +40,45 @@ enum AnchorEdge {
AnchorHorizontalCenter, AnchorHorizontalCenter,
}; };
enum FocusReason {
MouseFocusReason = 0,
TabFocusReason,
ActiveFocusReason,
OtherFocusReason
};
enum MouseButton {
MouseNoButton = 0,
MouseLeftButton,
MouseRightButton,
MouseMidButton
};
enum MouseWheelDirection {
MouseNoWheel = 0,
MouseWheelUp,
MouseWheelDown
};
enum KeyboardModifier {
KeyboardNoModifier = 0,
KeyboardCtrlModifier = 1,
KeyboardAltModifier = 2,
KeyboardShiftModifier = 4
};
enum WidgetState {
DefaultState = 0,
ActiveState = 1,
FocusState = 2,
HoverState = 4,
PressedState = 8,
DisabledState = 16
//FirstState,
//MiddleState,
//LastState,
//AlternateState
};
//} //}

@ -20,7 +20,7 @@ void Logger::log(LogLevel level, std::string message)
m_logMessages.push_back(LogMessage(level, message, now)); m_logMessages.push_back(LogMessage(level, message, now));
if(m_onLog) if(m_onLog)
g_dispatcher.addEvent(std::bind(m_onLog, level, message, now)); m_onLog(level, message, now);
} }
if(level == LogFatal) { if(level == LogFatal) {
@ -46,7 +46,8 @@ void Logger::logFunc(LogLevel level, const std::string& message, std::string pre
void Logger::fireOldMessages() void Logger::fireOldMessages()
{ {
if(m_onLog) { if(m_onLog) {
for(const LogMessage& logMessage : m_logMessages) auto backup = m_logMessages;
g_dispatcher.addEvent(std::bind(m_onLog, logMessage.level, logMessage.message, logMessage.when)); for(const LogMessage& logMessage : backup)
m_onLog(logMessage.level, logMessage.message, logMessage.when);
} }
} }

@ -34,6 +34,7 @@
// boost utilities // boost utilities
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/any.hpp>
// global constants // global constants
#include "const.h" #include "const.h"

@ -60,10 +60,3 @@ FontPtr FontManager::getFont(const std::string& fontName)
return getDefaultFont(); return getDefaultFont();
} }
FontPtr FontManager::getDefaultFont()
{
// default font should always exists, otherwise the app may crash
if(!m_defaultFont)
logFatal("no default font to display, cannot continue to run");
return m_defaultFont;
}

@ -14,7 +14,7 @@ public:
bool fontExists(const std::string& fontName); bool fontExists(const std::string& fontName);
FontPtr getFont(const std::string& fontName); FontPtr getFont(const std::string& fontName);
FontPtr getDefaultFont(); FontPtr getDefaultFont() { return m_defaultFont; }
void setDefaultFont(const std::string& fontName) { m_defaultFont = getFont(fontName); } void setDefaultFont(const std::string& fontName) { m_defaultFont = getFont(fontName); }

@ -9,7 +9,7 @@ void LuaInterface::registerFunctions()
{ {
// UIWidget // UIWidget
g_lua.registerClass<UIWidget>(); g_lua.registerClass<UIWidget>();
g_lua.bindClassStaticFunction<UIWidget>("create", &UIWidget::create); g_lua.bindClassStaticFunction<UIWidget>("create", &UIWidget::create<UIWidget>);
g_lua.bindClassMemberFunction<UIWidget>("getId", &UIWidget::getId); g_lua.bindClassMemberFunction<UIWidget>("getId", &UIWidget::getId);
g_lua.bindClassMemberFunction<UIWidget>("setId", &UIWidget::setId); g_lua.bindClassMemberFunction<UIWidget>("setId", &UIWidget::setId);
g_lua.bindClassMemberFunction<UIWidget>("isEnabled", &UIWidget::isEnabled); g_lua.bindClassMemberFunction<UIWidget>("isEnabled", &UIWidget::isEnabled);
@ -39,41 +39,41 @@ void LuaInterface::registerFunctions()
g_lua.bindClassMemberFunction<UIWidget>("setMarginRight", &UIWidget::setMarginRight); g_lua.bindClassMemberFunction<UIWidget>("setMarginRight", &UIWidget::setMarginRight);
g_lua.bindClassMemberFunction<UIWidget>("hide", &UIWidget::hide); g_lua.bindClassMemberFunction<UIWidget>("hide", &UIWidget::hide);
g_lua.bindClassMemberFunction<UIWidget>("show", &UIWidget::show); 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>("getChildById", &UIWidget::getChildById); g_lua.bindClassMemberFunction<UIWidget>("getChildById", &UIWidget::getChildById);
g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex); g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex);
g_lua.bindClassMemberFunction<UIWidget>("getChildCount", &UIWidget::getChildCount);
g_lua.bindClassMemberFunction<UIWidget>("insertChild", &UIWidget::insertChild); g_lua.bindClassMemberFunction<UIWidget>("insertChild", &UIWidget::insertChild);
g_lua.bindClassMemberFunction<UIWidget>("removeChild", &UIWidget::removeChild); g_lua.bindClassMemberFunction<UIWidget>("removeChild", &UIWidget::removeChild);
g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild); g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild);
g_lua.bindClassMemberFunction<UIWidget>("lockChild", &UIWidget::lockChild); g_lua.bindClassMemberFunction<UIWidget>("lockChild", &UIWidget::lockChild);
g_lua.bindClassMemberFunction<UIWidget>("updateLayout", &UIWidget::updateLayout);
g_lua.bindClassMemberFunction<UIWidget>("updateParentLayout", &UIWidget::updateParentLayout);
g_lua.bindClassMemberFunction<UIWidget>("destroy", &UIWidget::destroy); g_lua.bindClassMemberFunction<UIWidget>("destroy", &UIWidget::destroy);
// UILabel // UILabel
g_lua.registerClass<UILabel, UIWidget>(); g_lua.registerClass<UILabel, UIWidget>();
g_lua.bindClassStaticFunction<UILabel>("create", &UILabel::create); g_lua.bindClassStaticFunction<UILabel>("create", &UIWidget::create<UILabel>);
g_lua.bindClassMemberFunction<UILabel>("getText", &UILabel::getText); g_lua.bindClassMemberFunction<UILabel>("getText", &UILabel::getText);
g_lua.bindClassMemberFunction<UILabel>("setText", &UILabel::setText); g_lua.bindClassMemberFunction<UILabel>("setText", &UILabel::setText);
g_lua.bindClassMemberFunction("resizeToText", &UILabel::resizeToText); g_lua.bindClassMemberFunction("resizeToText", &UILabel::resizeToText);
// UIButton // UIButton
g_lua.registerClass<UIButton, UIWidget>(); g_lua.registerClass<UIButton, UIWidget>();
g_lua.bindClassStaticFunction<UIButton>("create", &UIButton::create); g_lua.bindClassStaticFunction<UIButton>("create", &UIWidget::create<UIButton>);
g_lua.bindClassMemberFunction<UIButton>("getText", &UIButton::getText); g_lua.bindClassMemberFunction<UIButton>("getText", &UIButton::getText);
g_lua.bindClassMemberFunction<UIButton>("setText", &UIButton::setText); g_lua.bindClassMemberFunction<UIButton>("setText", &UIButton::setText);
// UILineEdit // UILineEdit
g_lua.registerClass<UILineEdit, UIWidget>(); g_lua.registerClass<UILineEdit, UIWidget>();
g_lua.bindClassStaticFunction<UILineEdit>("create", &UILineEdit::create); g_lua.bindClassStaticFunction<UILineEdit>("create", &UIWidget::create<UILineEdit>);
g_lua.bindClassMemberFunction<UILineEdit>("getText", &UILineEdit::getText); g_lua.bindClassMemberFunction<UILineEdit>("getText", &UILineEdit::getText);
g_lua.bindClassMemberFunction<UILineEdit>("setText", &UILineEdit::setText); g_lua.bindClassMemberFunction<UILineEdit>("setText", &UILineEdit::setText);
g_lua.bindClassMemberFunction<UILineEdit>("clearText", &UILineEdit::clearText); g_lua.bindClassMemberFunction<UILineEdit>("clearText", &UILineEdit::clearText);
// UIWindow // UIWindow
g_lua.registerClass<UIWindow, UIWidget>(); g_lua.registerClass<UIWindow, UIWidget>();
g_lua.bindClassStaticFunction<UIWindow>("create", &UIWindow::create); g_lua.bindClassStaticFunction<UIWindow>("create", &UIWidget::create<UIWindow>);
g_lua.bindClassMemberFunction<UIWindow>("getTitle", &UIWindow::getTitle); g_lua.bindClassMemberFunction<UIWindow>("getTitle", &UIWindow::getTitle);
g_lua.bindClassMemberFunction<UIWindow>("setTitle", &UIWindow::setTitle); g_lua.bindClassMemberFunction<UIWindow>("setTitle", &UIWindow::setTitle);
@ -95,7 +95,7 @@ void LuaInterface::registerFunctions()
g_lua.bindGlobalFunction("importFont", std::bind(&FontManager::importFont, &g_fonts, _1)); g_lua.bindGlobalFunction("importFont", std::bind(&FontManager::importFont, &g_fonts, _1));
g_lua.bindGlobalFunction("importStyles", std::bind(&UIManager::importStyles, &g_ui, _1)); g_lua.bindGlobalFunction("importStyles", std::bind(&UIManager::importStyles, &g_ui, _1));
g_lua.bindGlobalFunction("setDefaultFont", std::bind(&FontManager::setDefaultFont, &g_fonts, _1)); g_lua.bindGlobalFunction("setDefaultFont", std::bind(&FontManager::setDefaultFont, &g_fonts, _1));
g_lua.bindGlobalFunction("loadUI", std::bind(&UIManager::loadUI, &g_ui, _1)); g_lua.bindGlobalFunction("loadUI", std::bind(&UIManager::loadUI, &g_ui, _1, _2));
g_lua.bindGlobalFunction("getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui)); g_lua.bindGlobalFunction("getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui));
g_lua.bindGlobalFunction("addEvent", std::bind(&EventDispatcher::addEvent, &g_dispatcher, _1, false)); g_lua.bindGlobalFunction("addEvent", std::bind(&EventDispatcher::addEvent, &g_dispatcher, _1, false));
g_lua.bindGlobalFunction("scheduleEvent", std::bind(&EventDispatcher::scheduleEvent, &g_dispatcher, _1, _2)); g_lua.bindGlobalFunction("scheduleEvent", std::bind(&EventDispatcher::scheduleEvent, &g_dispatcher, _1, _2));

@ -50,6 +50,7 @@ public:
void hideMouseCursor(); void hideMouseCursor();
void showMouseCursor(); void showMouseCursor();
Point getMouseCursorPos();
/// Enable or disable vertical synchronization /// Enable or disable vertical synchronization
void setVerticalSync(bool enable); void setVerticalSync(bool enable);

@ -41,7 +41,7 @@ struct X11PlatformPrivate {
int lastTicks; int lastTicks;
std::string clipboardText; std::string clipboardText;
std::map<int, uchar> keyMap; std::map<int, uchar> keyMap;
PlatformListener* listener; PlatformEvent inputEvent;
} x11; } x11;
Platform g_platform; Platform g_platform;
@ -261,7 +261,7 @@ void Platform::terminate()
void Platform::poll() void Platform::poll()
{ {
XEvent event, peekevent; XEvent event, peekevent;
static PlatformEvent inputEvent; PlatformEvent& inputEvent = x11.inputEvent;
while(XPending(x11.display) > 0) { while(XPending(x11.display) > 0) {
XNextEvent(x11.display, &event); XNextEvent(x11.display, &event);
@ -336,14 +336,13 @@ void Platform::poll()
//logDebug("char: ", buf[0], " code: ", (uint)buf[0]); //logDebug("char: ", buf[0], " code: ", (uint)buf[0]);
inputEvent.keychar = buf[0]; inputEvent.keychar = buf[0];
} }
} } else {
//event.xkey.state &= ~(ShiftMask | LockMask);
// unmask Shift/Lock to get expected results len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, 0);
event.xkey.state &= ~(ShiftMask | LockMask);
len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, 0);
if(inputEvent.keychar == 0) if(len > 0 && (uchar)inputEvent.keychar >= 32)
inputEvent.keychar = (len > 0) ? buf[0] : 0; inputEvent.keychar = (len > 0) ? buf[0] : 0;
}
if(x11.keyMap.find(keysym) != x11.keyMap.end()) if(x11.keyMap.find(keysym) != x11.keyMap.end())
inputEvent.keycode = x11.keyMap[keysym]; inputEvent.keycode = x11.keyMap[keysym];
@ -734,6 +733,11 @@ void Platform::showMouseCursor()
} }
} }
Point Platform::getMouseCursorPos()
{
return x11.inputEvent.mousePos;
}
void Platform::setVerticalSync(bool enable) void Platform::setVerticalSync(bool enable)
{ {
typedef GLint (*glSwapIntervalProc)(GLint); typedef GLint (*glSwapIntervalProc)(GLint);

@ -1,39 +0,0 @@
#ifndef FRAMEWORK_UI_CONST_H
#define FRAMEWORK_UI_CONST_H
// namespace ui {
namespace UI {
enum FocusReason {
MouseFocusReason = 0,
TabFocusReason,
ActiveFocusReason,
OtherFocusReason
};
enum MouseButton {
MouseNoButton = 0,
MouseLeftButton,
MouseRightButton,
MouseMidButton
};
enum MouseWheelDirection {
MouseNoWheel = 0,
MouseWheelUp,
MouseWheelDown
};
enum KeyboardModifier {
KeyboardNoModifier = 0,
KeyboardCtrlModifier = 1,
KeyboardAltModifier = 2,
KeyboardShiftModifier = 4
};
}
// }
#endif

@ -2,16 +2,17 @@
#define FRAMEWORK_UI_DECLARATIONS_H #define FRAMEWORK_UI_DECLARATIONS_H
#include <framework/global.h> #include <framework/global.h>
#include "const.h"
#include <framework/platform/platformevent.h> #include <framework/platform/platformevent.h>
class UIManager; class UIManager;
class UIAnchor;
class UIWidget; class UIWidget;
class UILabel; class UILabel;
class UIButton; class UIButton;
class UILineEdit; class UILineEdit;
class UIWindow; class UIWindow;
class UILayout;
class UIVerticalLayout;
class UIAnchorLayout;
typedef std::shared_ptr<UIWidget> UIWidgetPtr; typedef std::shared_ptr<UIWidget> UIWidgetPtr;
typedef std::weak_ptr<UIWidget> UIWidgetWeakPtr; typedef std::weak_ptr<UIWidget> UIWidgetWeakPtr;
@ -20,8 +21,10 @@ typedef std::shared_ptr<UILabel> UILabelPtr;
typedef std::shared_ptr<UIButton> UIButtonPtr; typedef std::shared_ptr<UIButton> UIButtonPtr;
typedef std::shared_ptr<UILineEdit> UILineEditPtr; typedef std::shared_ptr<UILineEdit> UILineEditPtr;
typedef std::shared_ptr<UIWindow> UIWindowPtr; typedef std::shared_ptr<UIWindow> UIWindowPtr;
typedef std::shared_ptr<UILayout> UILayoutPtr;
typedef std::shared_ptr<UIVerticalLayout> UIVerticalLayoutPtr;
typedef std::shared_ptr<UIAnchorLayout> UIAnchorLayoutPtr;
typedef std::vector<UIAnchor> UIAnchorList;
typedef std::deque<UIWidgetPtr> UIWidgetList; typedef std::deque<UIWidgetPtr> UIWidgetList;
typedef std::deque<UIWidgetWeakPtr> UIWeakWidgetList; typedef std::deque<UIWidgetWeakPtr> UIWeakWidgetList;

@ -1,31 +0,0 @@
#include "uianchor.h"
#include "uiwidget.h"
UIAnchor::UIAnchor(AnchorEdge anchoredEdge, const std::string& hookedWidgetId, AnchorEdge hookedEdge) :
m_anchoredEdge(anchoredEdge), m_hookedWidgetId(hookedWidgetId), m_hookedEdge(hookedEdge) {
}
int UIAnchor::getHookedPoint() const {
UIWidgetPtr hookedWidget = getHookedWidget();
if(hookedWidget) {
switch(m_hookedEdge) {
case AnchorLeft:
return hookedWidget->getRect().left();
case AnchorRight:
return hookedWidget->getRect().right();
case AnchorTop:
return hookedWidget->getRect().top();
case AnchorBottom:
return hookedWidget->getRect().bottom();
case AnchorHorizontalCenter:
return hookedWidget->getRect().horizontalCenter();
case AnchorVerticalCenter:
return hookedWidget->getRect().verticalCenter();
default:
break;
}
}
return INVALID_POINT;
}

@ -1,29 +0,0 @@
#ifndef UIANCHOR_H
#define UIANCHOR_H
#include "declarations.h"
class UIAnchor
{
public:
enum {
INVALID_POINT = -999999
};
UIAnchor(AnchorEdge anchoredEdge, const std::string& hookedWidgetId, AnchorEdge hookedEdge);
AnchorEdge getAnchoredEdge() const { return m_anchoredEdge; }
UIWidgetPtr getHookedWidget() const { return m_hookedWidget.lock(); }
std::string getHookedWidgetId() const { return m_hookedWidgetId; }
int getHookedPoint() const;
void setHookedWidget(const UIWidgetPtr hookedWidget) { m_hookedWidget = hookedWidget; }
private:
AnchorEdge m_anchoredEdge;
UIWidgetWeakPtr m_hookedWidget;
std::string m_hookedWidgetId;
AnchorEdge m_hookedEdge;
};
#endif

@ -0,0 +1,190 @@
#include "uianchorlayout.h"
#include "uiwidget.h"
void UIAnchorGroup::addAnchor(const UIAnchor& anchor)
{
// duplicated anchors must be replaced
for(UIAnchor& other : m_anchors) {
if(other.getAnchoredEdge() == anchor.getAnchoredEdge()) {
other = anchor;
return;
}
}
m_anchors.push_back(anchor);
}
void UIAnchorLayout::addAnchor(const UIWidgetPtr& anchoredWidget, AnchorEdge anchoredEdge,
const std::string& hookedWidgetId, AnchorEdge hookedEdge)
{
if(!anchoredWidget)
return;
assert(anchoredWidget != getParentWidget());
UIAnchor anchor(anchoredEdge, hookedWidgetId, hookedEdge);
UIAnchorGroup& anchorGroup = m_anchorsGroups[anchoredWidget];
anchorGroup.addAnchor(anchor);
// layout must be updated because a new anchor got in
update();
}
void UIAnchorLayout::removeAnchors(const UIWidgetPtr& anchoredWidget)
{
m_anchorsGroups.erase(anchoredWidget);
update();
}
void UIAnchorLayout::centerIn(const UIWidgetPtr& anchoredWidget, const std::string& hookedWidgetId)
{
addAnchor(anchoredWidget, AnchorHorizontalCenter, hookedWidgetId, AnchorHorizontalCenter);
addAnchor(anchoredWidget, AnchorVerticalCenter, hookedWidgetId, AnchorVerticalCenter);
}
void UIAnchorLayout::fill(const UIWidgetPtr& anchoredWidget, const std::string& hookedWidgetId)
{
addAnchor(anchoredWidget, AnchorLeft, hookedWidgetId, AnchorLeft);
addAnchor(anchoredWidget, AnchorRight, hookedWidgetId, AnchorRight);
addAnchor(anchoredWidget, AnchorTop, hookedWidgetId, AnchorTop);
addAnchor(anchoredWidget, AnchorBottom, hookedWidgetId, AnchorBottom);
}
void UIAnchorLayout::update()
{
// reset all anchors groups update state
for(auto& it : m_anchorsGroups) {
UIAnchorGroup& anchorGroup = it.second;
anchorGroup.setUpdated(false);
}
// update all anchors
for(auto& it : m_anchorsGroups) {
const UIWidgetPtr& widget = it.first;
UIAnchorGroup& anchorGroup = it.second;
if(!anchorGroup.isUpdated())
updateWidget(widget, anchorGroup);
}
}
void UIAnchorLayout::addWidget(const UIWidgetPtr& widget)
{
update();
}
void UIAnchorLayout::removeWidget(const UIWidgetPtr& widget)
{
removeAnchors(widget);
}
void UIAnchorLayout::updateWidget(const UIWidgetPtr& widget, UIAnchorGroup& anchorGroup)
{
UIWidgetPtr parentWidget = getParentWidget();
Rect newRect = widget->getRect();
bool verticalMoved = false;
bool horizontalMoved = false;
// calculates new rect based on anchors
for(const UIAnchor& anchor : anchorGroup.getAnchors()) {
// skip invalid anchors
if(anchor.getHookedEdge() == AnchorNone)
continue;
// determine hooked widget
UIWidgetPtr hookedWidget;
if(parentWidget) {
if(anchor.getHookedWidgetId() == "parent")
hookedWidget = parentWidget;
else if(anchor.getHookedWidgetId() == "next")
hookedWidget = parentWidget->getChildAfter(widget);
else if(anchor.getHookedWidgetId() == "prev")
hookedWidget = parentWidget->getChildBefore(widget);
else
hookedWidget = parentWidget->getChildById(anchor.getHookedWidgetId());
}
// skip invalid anchors
if(!hookedWidget)
continue;
if(hookedWidget != getParentWidget()) {
// update this hooked widget anchors
auto it = m_anchorsGroups.find(hookedWidget);
if(it != m_anchorsGroups.end()) {
UIAnchorGroup& hookedAnchorGroup = it->second;
if(!hookedAnchorGroup.isUpdated())
updateWidget(hookedWidget, hookedAnchorGroup);
}
}
// determine hooked widget edge point
int point = 0;
switch(anchor.getHookedEdge()) {
case AnchorLeft:
point = hookedWidget->getRect().left();
break;
case AnchorRight:
point = hookedWidget->getRect().right();
break;
case AnchorTop:
point = hookedWidget->getRect().top();
break;
case AnchorBottom:
point = hookedWidget->getRect().bottom();
break;
case AnchorHorizontalCenter:
point = hookedWidget->getRect().horizontalCenter();
break;
case AnchorVerticalCenter:
point = hookedWidget->getRect().verticalCenter();
break;
default:
// must never happens
assert(false);
break;
}
switch(anchor.getAnchoredEdge()) {
case AnchorHorizontalCenter:
newRect.moveHorizontalCenter(point + widget->getMarginLeft() - widget->getMarginRight());
horizontalMoved = true;
break;
case AnchorLeft:
if(!horizontalMoved) {
newRect.moveLeft(point + widget->getMarginLeft());
horizontalMoved = true;
} else
newRect.setLeft(point + widget->getMarginLeft());
break;
case AnchorRight:
if(!horizontalMoved) {
newRect.moveRight(point - widget->getMarginRight());
horizontalMoved = true;
} else
newRect.setRight(point - widget->getMarginRight());
break;
case AnchorVerticalCenter:
newRect.moveVerticalCenter(point + widget->getMarginTop() - widget->getMarginBottom());
verticalMoved = true;
break;
case AnchorTop:
if(!verticalMoved) {
newRect.moveTop(point + widget->getMarginTop());
verticalMoved = true;
} else
newRect.setTop(point + widget->getMarginTop());
break;
case AnchorBottom:
if(!verticalMoved) {
newRect.moveBottom(point - widget->getMarginBottom());
verticalMoved = true;
} else
newRect.setBottom(point - widget->getMarginBottom());
break;
default:
break;
}
}
widget->setRect(newRect);
anchorGroup.setUpdated(true);
}

@ -0,0 +1,59 @@
#ifndef UIANCHORLAYOUT_H
#define UIANCHORLAYOUT_H
#include "uilayout.h"
class UIAnchor
{
public:
UIAnchor(AnchorEdge anchoredEdge, const std::string& hookedWidgetId, AnchorEdge hookedEdge) :
m_anchoredEdge(anchoredEdge), m_hookedEdge(hookedEdge), m_hookedWidgetId(hookedWidgetId) { }
AnchorEdge getAnchoredEdge() const { return m_anchoredEdge; }
std::string getHookedWidgetId() const { return m_hookedWidgetId; }
AnchorEdge getHookedEdge() const { return m_hookedEdge; }
private:
AnchorEdge m_anchoredEdge;
AnchorEdge m_hookedEdge;
std::string m_hookedWidgetId;
};
class UIAnchorGroup
{
public:
UIAnchorGroup() : m_updated(true) { }
void addAnchor(const UIAnchor& anchor);
const std::vector<UIAnchor>& getAnchors() const { return m_anchors; }
bool isUpdated() const { return m_updated; }
void setUpdated(bool updated) { m_updated = updated; }
private:
std::vector<UIAnchor> m_anchors;
bool m_updated;
};
class UIAnchorLayout : public UILayout
{
public:
UIAnchorLayout(UIWidgetPtr parentWidget) : UILayout(parentWidget) { }
void addAnchor(const UIWidgetPtr& anchoredWidget, AnchorEdge anchoredEdge,
const std::string& hookedWidgetId, AnchorEdge hookedEdge);
void removeAnchors(const UIWidgetPtr& anchoredWidget);
void centerIn(const UIWidgetPtr& anchoredWidget, const std::string& hookedWidgetId);
void fill(const UIWidgetPtr& anchoredWidget, const std::string& hookedWidgetId);
void update();
void addWidget(const UIWidgetPtr& widget);
void removeWidget(const UIWidgetPtr& widget);
UIAnchorLayoutPtr asUIAnchorLayout() { return std::static_pointer_cast<UIAnchorLayout>(shared_from_this()); }
private:
void updateWidget(const UIWidgetPtr& widget, UIAnchorGroup& anchorGroup);
std::map<UIWidgetPtr, UIAnchorGroup> m_anchorsGroups;
};
#endif

@ -5,96 +5,44 @@
#include <framework/luascript/luainterface.h> #include <framework/luascript/luainterface.h>
#include <framework/graphics/graphics.h> #include <framework/graphics/graphics.h>
UIButton::UIButton() void UIButton::setup()
{ {
m_state = ButtonUp; UIWidget::setup();
m_focusable = false; setFocusable(false);
// by default, all callbacks call lua fields // by default, all callbacks call lua fields
m_onClick = [this]() { this->callLuaField("onClick"); }; m_onClick = [this]() { this->callLuaField("onClick"); };
} }
UIButtonPtr UIButton::create()
{
UIButtonPtr button(new UIButton);
return button;
}
void UIButton::onStyleApply(const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleNode);
for(int i=0; i<3; ++i) {
m_statesStyle[i].image = m_image;
m_statesStyle[i].color = m_backgroundColor;
m_statesStyle[i].foregroundColor = m_foregroundColor;
m_statesStyle[i].textTranslate = Point(0,0);
}
if(OTMLNodePtr node = styleNode->get("state.up"))
loadStateStyle(m_statesStyle[ButtonUp], node);
if(OTMLNodePtr node = styleNode->get("state.hover"))
loadStateStyle(m_statesStyle[ButtonHover], node);
if(OTMLNodePtr node = styleNode->get("state.down"))
loadStateStyle(m_statesStyle[ButtonDown], node);
m_text = styleNode->valueAt("text", fw::empty_string);
if(OTMLNodePtr node = styleNode->get("onClick")) {
g_lua.loadFunction(node->value(), "@" + node->source() + "[" + node->tag() + "]");
luaSetField(node->tag());
}
}
void UIButton::loadStateStyle(ButtonStateStyle& stateStyle, const OTMLNodePtr& stateStyleNode)
{
if(OTMLNodePtr node = stateStyleNode->get("border-image"))
stateStyle.image = BorderImage::loadFromOTML(node);
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_foregroundColor);
stateStyle.color = stateStyleNode->valueAt("color", m_backgroundColor);
}
void UIButton::render() void UIButton::render()
{ {
UIWidget::render(); UIWidget::render();
Rect textRect = m_rect;
const ButtonStateStyle& currentStyle = m_statesStyle[m_state]; textRect.translate(m_textTranslate);
Rect textRect = getRect(); m_font->renderText(m_text, textRect, AlignCenter, m_foregroundColor);
if(currentStyle.image) {
g_graphics.bindColor(currentStyle.color);
currentStyle.image->draw(textRect);
}
textRect.translate(currentStyle.textTranslate);
m_font->renderText(m_text, textRect, AlignCenter, currentStyle.foregroundColor);
} }
void UIButton::onHoverChange(bool hovered) void UIButton::onStyleApply(const OTMLNodePtr& styleNode)
{ {
if(hovered && m_state == ButtonUp) UIWidget::onStyleApply(styleNode);
m_state = ButtonHover;
else if(m_state == ButtonHover)
m_state = ButtonUp;
}
bool UIButton::onMousePress(const Point& mousePos, UI::MouseButton button) for(OTMLNodePtr node : styleNode->children()) {
{ if(node->tag() == "text-translate") {
if(button == UI::MouseLeftButton) { m_textTranslate = node->value<Point>();
m_state = ButtonDown; } else if(node->tag() == "text") {
m_text = node->value();
} else if(node->tag() == "onClick") {
g_lua.loadFunction(node->value(), "@" + node->source() + "[" + node->tag() + "]");
luaSetField(node->tag());
}
} }
return true;
} }
bool UIButton::onMouseRelease(const Point& mousePos, UI::MouseButton button) bool UIButton::onMouseRelease(const Point& mousePos, MouseButton button)
{ {
if(m_state == ButtonDown) { if(isPressed()) {
if(m_onClick && getRect().contains(mousePos)) if(m_onClick && getRect().contains(mousePos))
m_onClick(); m_onClick();
m_state = (isHovered() && isEnabled()) ? ButtonHover : ButtonUp;
return true; return true;
} }
return false; return false;

@ -5,26 +5,8 @@
class UIButton : public UIWidget class UIButton : public UIWidget
{ {
struct ButtonStateStyle {
ImagePtr image;
Point textTranslate;
Color foregroundColor;
Color color;
};
enum ButtonState {
ButtonUp = 0,
ButtonDown,
ButtonHover
};
public: public:
UIButton(); virtual void setup();
static UIButtonPtr create();
virtual void onStyleApply(const OTMLNodePtr& styleNode);
void loadStateStyle(ButtonStateStyle& stateStyle, const OTMLNodePtr& stateStyleNode);
virtual void render(); virtual void render();
void setOnClick(const SimpleCallback& onClick) { m_onClick = onClick; } void setOnClick(const SimpleCallback& onClick) { m_onClick = onClick; }
@ -32,18 +14,15 @@ public:
SimpleCallback getOnClick() const { return m_onClick; } SimpleCallback getOnClick() const { return m_onClick; }
std::string getText() const { return m_text; } std::string getText() const { return m_text; }
ButtonState getState() const { return m_state; }
UIButtonPtr asUIButton() { return std::static_pointer_cast<UIButton>(shared_from_this()); } UIButtonPtr asUIButton() { return std::static_pointer_cast<UIButton>(shared_from_this()); }
protected: protected:
virtual void onHoverChange(bool hovered); virtual void onStyleApply(const OTMLNodePtr& styleNode);
virtual bool onMousePress(const Point& mousePos, UI::MouseButton button); virtual bool onMouseRelease(const Point& mousePos, MouseButton button);
virtual bool onMouseRelease(const Point& mousePos, UI::MouseButton button);
ButtonState m_state;
ButtonStateStyle m_statesStyle[3];
SimpleCallback m_onClick; SimpleCallback m_onClick;
Point m_textTranslate;
std::string m_text; std::string m_text;
}; };

@ -2,29 +2,27 @@
#include <framework/graphics/font.h> #include <framework/graphics/font.h>
#include <framework/otml/otmlnode.h> #include <framework/otml/otmlnode.h>
UILabel::UILabel() void UILabel::setup()
{ {
m_align = AlignLeft; UIWidget::setup();
m_focusable = false; setFocusable(false);
setAlign(AlignLeft);
} }
UILabelPtr UILabel::create() void UILabel::render()
{ {
UILabelPtr label(new UILabel); UIWidget::render();
return label; m_font->renderText(m_text, m_rect, m_align, m_foregroundColor);
} }
void UILabel::onStyleApply(const OTMLNodePtr& styleNode) void UILabel::setText(const std::string& text)
{ {
UIWidget::onStyleApply(styleNode); m_text = text;
m_text = styleNode->valueAt("text", m_text); // auto resize
if(!m_fixedSize)
if(styleNode->hasChildAt("align")) resizeToText();
m_align = fw::translateAlignment(styleNode->valueAt("align")); else if(!m_rect.isValid()) {
// auto resize if needed
if(!m_text.empty() && !m_rect.isValid()) {
Size textSize = m_font->calculateTextRectSize(m_text); Size textSize = m_font->calculateTextRectSize(m_text);
if(m_rect.width() <= 0) if(m_rect.width() <= 0)
m_rect.setWidth(textSize.width()); m_rect.setWidth(textSize.width());
@ -33,13 +31,19 @@ void UILabel::onStyleApply(const OTMLNodePtr& styleNode)
} }
} }
void UILabel::render() void UILabel::resizeToText()
{ {
UIWidget::render(); resize(m_font->calculateTextRectSize(m_text));
m_font->renderText(m_text, m_rect, m_align, m_foregroundColor);
} }
void UILabel::resizeToText() void UILabel::onStyleApply(const OTMLNodePtr& styleNode)
{ {
resize(m_font->calculateTextRectSize(m_text)); UIWidget::onStyleApply(styleNode);
for(const OTMLNodePtr& node : styleNode->children()) {
if(node->tag() == "text")
setText(node->value());
else if(node->tag() == "align")
setAlign(fw::translateAlignment(node->value()));
}
} }

@ -6,21 +6,20 @@
class UILabel : public UIWidget class UILabel : public UIWidget
{ {
public: public:
UILabel(); virtual void setup();
static UILabelPtr create();
virtual void onStyleApply(const OTMLNodePtr& styleNode);
virtual void render(); virtual void render();
void resizeToText(); void resizeToText();
void setText(const std::string& text) { m_text = text; } void setText(const std::string& text);
void setAlign(AlignmentFlag align) { m_align = align; } void setAlign(AlignmentFlag align) { m_align = align; }
std::string getText() const { return m_text; } std::string getText() const { return m_text; }
AlignmentFlag getAlign() const { return m_align; } AlignmentFlag getAlign() const { return m_align; }
protected:
virtual void onStyleApply(const OTMLNodePtr& styleNode);
private: private:
std::string m_text; std::string m_text;
AlignmentFlag m_align; AlignmentFlag m_align;

@ -0,0 +1 @@
#include "uilayout.h"

@ -0,0 +1,24 @@
#ifndef UILAYOUT_H
#define UILAYOUT_H
#include "declarations.h"
#include <framework/luascript/luaobject.h>
class UILayout : public LuaObject
{
public:
UILayout(UIWidgetPtr parentWidget) : m_parentWidget(parentWidget) { }
virtual void update() = 0;
virtual void addWidget(const UIWidgetPtr& widget) = 0;
virtual void removeWidget(const UIWidgetPtr& widget) = 0;
UIWidgetPtr getParentWidget() { return m_parentWidget.lock(); }
virtual UIAnchorLayoutPtr asUIAnchorLayout() { return nullptr; }
protected:
UIWidgetWeakPtr m_parentWidget;
};
#endif

@ -15,19 +15,10 @@ UILineEdit::UILineEdit()
m_onAction = [this]() { this->callLuaField("onAction"); }; m_onAction = [this]() { this->callLuaField("onAction"); };
} }
UILineEditPtr UILineEdit::create()
{
UILineEditPtr lineEdit(new UILineEdit);
return lineEdit;
}
void UILineEdit::render() void UILineEdit::render()
{ {
UIWidget::render(); UIWidget::render();
if(!m_rect.isValid())
return;
//TODO: text rendering could be much optimized by using vertex buffer or caching the render into a texture //TODO: text rendering could be much optimized by using vertex buffer or caching the render into a texture
int textLength = m_text.length(); int textLength = m_text.length();
@ -37,10 +28,10 @@ void UILineEdit::render()
g_graphics.drawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]); g_graphics.drawTexturedRect(m_glyphsCoords[i], texture, m_glyphsTexCoords[i]);
// render cursor // render cursor
if(isExplicitlyEnabled() && hasFocus() && m_cursorPos >= 0) { if(isExplicitlyEnabled() && isActive() && m_cursorPos >= 0) {
assert(m_cursorPos <= textLength); assert(m_cursorPos <= textLength);
// draw every 330ms // draw every 333ms
const int delay = 330; const int delay = 333;
int ticks = g_platform.getTicks(); int ticks = g_platform.getTicks();
if(ticks - m_cursorTicks <= delay) { if(ticks - m_cursorTicks <= delay) {
Rect cursorRect; Rect cursorRect;
@ -61,7 +52,7 @@ void UILineEdit::update()
int textLength = m_text.length(); int textLength = m_text.length();
// prevent glitches // prevent glitches
if(!m_rect.isValid()) if(m_rect.isEmpty())
return; return;
// map glyphs positions // map glyphs positions
@ -331,11 +322,14 @@ void UILineEdit::onStyleApply(const OTMLNodePtr& styleNode)
{ {
UIWidget::onStyleApply(styleNode); UIWidget::onStyleApply(styleNode);
setText(styleNode->valueAt("text", getText())); for(const OTMLNodePtr& node : styleNode->children()) {
if(node->tag() == "text") {
if(OTMLNodePtr node = styleNode->get("onAction")) { setText(node->value());
g_lua.loadFunction(node->value(), "@" + node->source() + "[" + node->tag() + "]"); setCursorPos(m_text.length());
luaSetField(node->tag()); } else if(node->tag() == "onAction") {
g_lua.loadFunction(node->value(), "@" + node->source() + "[" + node->tag() + "]");
luaSetField(node->tag());
}
} }
} }
@ -344,11 +338,11 @@ void UILineEdit::onGeometryUpdate(const Rect& oldRect, const Rect& newRect)
update(); update();
} }
void UILineEdit::onFocusChange(bool focused, UI::FocusReason reason) void UILineEdit::onFocusChange(bool focused, FocusReason reason)
{ {
if(focused) { if(focused) {
if(reason == UI::TabFocusReason) if(reason == TabFocusReason)
setCursorPos(0); setCursorPos(m_text.length());
else else
blinkCursor(); blinkCursor();
} }
@ -370,21 +364,21 @@ bool UILineEdit::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
setCursorPos(m_text.length()); setCursorPos(m_text.length());
else if(keyCode == KC_TAB) { else if(keyCode == KC_TAB) {
if(UIWidgetPtr parent = getParent()) if(UIWidgetPtr parent = getParent())
parent->focusNextChild(UI::TabFocusReason); parent->focusNextChild(TabFocusReason);
} else if(keyCode == KC_RETURN) { } else if(keyCode == KC_RETURN) {
if(m_onAction) if(m_onAction)
m_onAction(); m_onAction();
} else if(keyCode != 0) { } else if(keyChar != 0)
appendCharacter(keyChar); appendCharacter(keyChar);
} else else
return false; return false;
return true; return true;
} }
bool UILineEdit::onMousePress(const Point& mousePos, UI::MouseButton button) bool UILineEdit::onMousePress(const Point& mousePos, MouseButton button)
{ {
if(button == UI::MouseLeftButton) { if(button == MouseLeftButton) {
int pos = getTextPos(mousePos); int pos = getTextPos(mousePos);
if(pos >= 0) if(pos >= 0)
setCursorPos(pos); setCursorPos(pos);

@ -8,8 +8,6 @@ class UILineEdit : public UIWidget
public: public:
UILineEdit(); UILineEdit();
static UILineEditPtr create();
virtual void render(); virtual void render();
void update(); void update();
@ -31,9 +29,9 @@ public:
protected: protected:
virtual void onStyleApply(const OTMLNodePtr& styleNode); virtual void onStyleApply(const OTMLNodePtr& styleNode);
virtual void onGeometryUpdate(const Rect& oldRect, const Rect& newRect); virtual void onGeometryUpdate(const Rect& oldRect, const Rect& newRect);
virtual void onFocusChange(bool focused, UI::FocusReason reason); virtual void onFocusChange(bool focused, FocusReason reason);
virtual bool onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers); virtual bool onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers);
virtual bool onMousePress(const Point& mousePos, UI::MouseButton button); virtual bool onMousePress(const Point& mousePos, MouseButton button);
private: private:
void blinkCursor(); void blinkCursor();

@ -1,32 +0,0 @@
#include "uilist.h"
UIList::UIList()
{
}
void UIList::onStyleApply(const OTMLNodePtr& styleNode)
{
}
void UIList::render()
{
}
bool UIList::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
{
return false;
}
bool UIList::onMousePress(const Point& mousePos, UI::MouseButton button)
{
return false;
}
bool UIList::onMouseMove(const Point& mousePos, const Point& mouseMoved)
{
return false;
}

@ -1,23 +0,0 @@
#ifndef UILIST_H
#define UILIST_H
#include "uiwidget.h"
class UIList : public UIWidget
{
public:
UIList();
virtual void onStyleApply(const OTMLNodePtr& styleNode);
virtual void render();
protected:
virtual bool onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers);
virtual bool onMousePress(const Point& mousePos, UI::MouseButton button);
virtual bool onMouseMove(const Point& mousePos, const Point& mouseMoved);
private:
std::list<std::string> m_items;
};
#endif

@ -9,9 +9,9 @@ UIManager g_ui;
void UIManager::init() void UIManager::init()
{ {
// creates root widget // creates root widget
m_rootWidget = UIWidgetPtr(new UIWidget); m_rootWidget = UIWidget::create<UIWidget>();
m_rootWidget->setup();
m_rootWidget->setId("root"); m_rootWidget->setId("root");
m_rootWidget->setHovered(true);
m_rootWidget->resize(g_graphics.getScreenSize()); m_rootWidget->resize(g_graphics.getScreenSize());
} }
@ -30,7 +30,7 @@ void UIManager::render()
void UIManager::resize(const Size& size) void UIManager::resize(const Size& size)
{ {
if(m_rootWidget) if(m_rootWidget)
m_rootWidget->resize(size); m_rootWidget->resize(g_graphics.getScreenSize());
} }
void UIManager::inputEvent(const PlatformEvent& event) void UIManager::inputEvent(const PlatformEvent& event)
@ -38,13 +38,13 @@ void UIManager::inputEvent(const PlatformEvent& event)
// translate input event to ui events // translate input event to ui events
if(m_rootWidget) { if(m_rootWidget) {
if(event.type & EventKeyboardAction) { if(event.type & EventKeyboardAction) {
int keyboardModifiers = UI::KeyboardNoModifier; int keyboardModifiers = KeyboardNoModifier;
if(event.ctrl) if(event.ctrl)
keyboardModifiers |= UI::KeyboardCtrlModifier; keyboardModifiers |= KeyboardCtrlModifier;
if(event.shift) if(event.shift)
keyboardModifiers |= UI::KeyboardShiftModifier; keyboardModifiers |= KeyboardShiftModifier;
if(event.alt) if(event.alt)
keyboardModifiers |= UI::KeyboardAltModifier; keyboardModifiers |= KeyboardAltModifier;
if(event.type == EventKeyDown) if(event.type == EventKeyDown)
m_rootWidget->onKeyPress(event.keycode, event.keychar, keyboardModifiers); m_rootWidget->onKeyPress(event.keycode, event.keychar, keyboardModifiers);
@ -52,24 +52,25 @@ void UIManager::inputEvent(const PlatformEvent& event)
m_rootWidget->onKeyRelease(event.keycode, event.keychar, keyboardModifiers); m_rootWidget->onKeyRelease(event.keycode, event.keychar, keyboardModifiers);
} else if(event.type & EventMouseAction) { } else if(event.type & EventMouseAction) {
if(event.type == EventMouseMove) { if(event.type == EventMouseMove) {
m_rootWidget->updateState(HoverState);
m_rootWidget->onMouseMove(event.mousePos, event.mouseMoved); m_rootWidget->onMouseMove(event.mousePos, event.mouseMoved);
} }
else if(event.type & EventMouseWheel) { else if(event.type & EventMouseWheel) {
UI::MouseWheelDirection dir = UI::MouseNoWheel; MouseWheelDirection dir = MouseNoWheel;
if(event.type & EventDown) if(event.type & EventDown)
dir = UI::MouseWheelDown; dir = MouseWheelDown;
else if(event.type & EventUp) else if(event.type & EventUp)
dir = UI::MouseWheelUp; dir = MouseWheelUp;
m_rootWidget->onMouseWheel(event.mousePos, dir); m_rootWidget->onMouseWheel(event.mousePos, dir);
} else { } else {
UI::MouseButton button = UI::MouseNoButton; MouseButton button = MouseNoButton;
if(event.type & EventMouseLeftButton) if(event.type & EventMouseLeftButton)
button = UI::MouseLeftButton; button = MouseLeftButton;
else if(event.type & EventMouseMidButton) else if(event.type & EventMouseMidButton)
button = UI::MouseMidButton; button = MouseMidButton;
else if(event.type & EventMouseRightButton) else if(event.type & EventMouseRightButton)
button = UI::MouseRightButton; button = MouseRightButton;
if(event.type & EventDown) if(event.type & EventDown)
m_rootWidget->onMousePress(event.mousePos, button); m_rootWidget->onMousePress(event.mousePos, button);
@ -132,7 +133,7 @@ OTMLNodePtr UIManager::getStyle(const std::string& styleName)
return m_styles[styleName]; return m_styles[styleName];
} }
UIWidgetPtr UIManager::loadUI(const std::string& file) UIWidgetPtr UIManager::loadUI(const std::string& file, const UIWidgetPtr& parent)
{ {
try { try {
OTMLDocumentPtr doc = OTMLDocument::parse(file); OTMLDocumentPtr doc = OTMLDocument::parse(file);
@ -146,7 +147,7 @@ UIWidgetPtr UIManager::loadUI(const std::string& file)
else { else {
if(widget) if(widget)
throw std::runtime_error("cannot have multiple main widgets in .otui files"); throw std::runtime_error("cannot have multiple main widgets in .otui files");
widget = loadWidgetFromOTML(node); widget = loadWidgetFromOTML(node, parent);
} }
} }
@ -157,33 +158,29 @@ UIWidgetPtr UIManager::loadUI(const std::string& file)
} }
} }
UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode) UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent)
{ {
OTMLNodePtr styleNode = getStyle(widgetNode->tag())->clone(); OTMLNodePtr styleNode = getStyle(widgetNode->tag())->clone();
styleNode->merge(widgetNode); styleNode->merge(widgetNode);
std::string widgetType = styleNode->valueAt("__widgetType"); std::string widgetType = styleNode->valueAt("__widgetType");
UIWidgetPtr widget; // call widget creation from lua
if(widgetType == "UIWidget") //g_lua.getGlobalField(widgetType, "create");
widget = UIWidgetPtr(new UIWidget); g_lua.getGlobal(widgetType);
else if(widgetType == "UILabel") g_lua.getField("create");
widget = UIWidgetPtr(new UILabel); g_lua.remove(-2);
else if(widgetType == "UIButton") g_lua.protectedCall(0, 1);
widget = UIWidgetPtr(new UIButton);
else if(widgetType == "UILineEdit") UIWidgetPtr widget = g_lua.polymorphicPop<UIWidgetPtr>();
widget = UIWidgetPtr(new UILineEdit); if(parent)
else if(widgetType == "UIWindow") parent->addChild(widget);
widget = UIWidgetPtr(new UIWindow);
else widget->setStyleFromNode(styleNode);
throw OTMLException(styleNode, "cannot determine widget type");
widget->onStyleApply(styleNode);
widget->updateLayout();
for(const OTMLNodePtr& childNode : widgetNode->children()) { for(const OTMLNodePtr& childNode : widgetNode->children()) {
if(!childNode->isUnique()) if(!childNode->isUnique())
widget->addChild(loadWidgetFromOTML(childNode)); loadWidgetFromOTML(childNode, widget);
} }
return widget; return widget;

@ -19,8 +19,8 @@ public:
void importStyleFromOTML(const OTMLNodePtr& styleNode); void importStyleFromOTML(const OTMLNodePtr& styleNode);
OTMLNodePtr getStyle(const std::string& styleName); OTMLNodePtr getStyle(const std::string& styleName);
UIWidgetPtr loadUI(const std::string& file); UIWidgetPtr loadUI(const std::string& file, const UIWidgetPtr& parent = nullptr);
UIWidgetPtr loadWidgetFromOTML(const OTMLNodePtr& widgetNode); UIWidgetPtr loadWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent);
UIWidgetPtr getRootWidget() { return m_rootWidget; } UIWidgetPtr getRootWidget() { return m_rootWidget; }

@ -0,0 +1,37 @@
#include "uiverticallayout.h"
#include "uiwidget.h"
UIVerticalLayout::UIVerticalLayout(UIWidgetPtr parentWidget)
: UILayout(parentWidget)
{
}
void UIVerticalLayout::update()
{
UIWidgetPtr parentWidget = getParentWidget();
UIWidgetList widgets = parentWidget->getChildren();
Point pos = parentWidget->getPosition();
for(const UIWidgetPtr& widget : widgets) {
Size size = widget->getSize();
pos.y += widget->getMarginTop();
if(widget->isSizeFixed()) {
pos.x = parentWidget->getX() + (parentWidget->getWidth() - (widget->getMarginLeft() + widget->getWidth() + widget->getMarginRight()))/2;
pos.x = std::max(pos.x, parentWidget->getX());
} else {
size.setWidth(parentWidget->getWidth() - (widget->getMarginLeft() + widget->getMarginRight()));
pos.x = std::max(pos.x, parentWidget->getX() + (parentWidget->getWidth() - size.width())/2);
}
widget->setRect(Rect(pos, size));
pos.y += widget->getHeight() + widget->getMarginBottom();
}
}
void UIVerticalLayout::addWidget(const UIWidgetPtr& widget)
{
update();
}
void UIVerticalLayout::removeWidget(const UIWidgetPtr& widget)
{
update();
}

@ -0,0 +1,16 @@
#ifndef UIVERTICALLAYOUT_H
#define UIVERTICALLAYOUT_H
#include "uilayout.h"
class UIVerticalLayout : public UILayout
{
public:
UIVerticalLayout(UIWidgetPtr parentWidget);
virtual void update();
virtual void addWidget(const UIWidgetPtr& widget);
virtual void removeWidget(const UIWidgetPtr& widget);
};
#endif

File diff suppressed because it is too large Load Diff

@ -4,7 +4,6 @@
#include "declarations.h" #include "declarations.h"
#include <framework/luascript/luaobject.h> #include <framework/luascript/luaobject.h>
#include <framework/graphics/declarations.h> #include <framework/graphics/declarations.h>
#include <framework/otml/declarations.h>
class UIWidget : public LuaObject class UIWidget : public LuaObject
{ {
@ -12,59 +11,65 @@ public:
UIWidget(); UIWidget();
virtual ~UIWidget(); virtual ~UIWidget();
static UIWidgetPtr create() { return UIWidgetPtr(new UIWidget); } template<class T>
static std::shared_ptr<T> create() { auto t = std::shared_ptr<T>(new T); t->setup(); return t; }
/// Must be called just after the widget creation void destroy();
virtual void setup() { }
/// Remove this widget from parent then destroy it and its children virtual void setup();
virtual void destroy();
/// Draw widget on screen
virtual void render(); virtual void render();
void setEnabled(bool enable) { m_enabled = enable; } void setEnabled(bool enabled) { m_enabled = enabled; updateState(DisabledState); }
void setVisible(bool visible) { m_visible = visible; }
void setPressed(bool pressed) { m_pressed = pressed; updateState(PressedState); }
void setId(const std::string& id) { m_id = id; } void setId(const std::string& id) { m_id = id; }
void setFocusable(bool focusable) { m_focusable = focusable; } void setFocusable(bool focusable) { m_focusable = focusable; }
void setHovered(bool hovered) { m_hovered = hovered; }
void setVisible(bool visible) { m_visible = visible; }
void setParent(const UIWidgetPtr& parent);
void setStyle(const std::string& styleName); void setStyle(const std::string& styleName);
void setStyleFromNode(const OTMLNodePtr& styleNode);
void setLayout(const UILayoutPtr& layout) { m_layout = layout; }
void setParent(const UIWidgetPtr& parent);
void setRect(const Rect& rect); void setRect(const Rect& rect);
void setX(int x) { move(Point(x, getY())); } void setX(int x) { moveTo(Point(x, getY())); }
void setY(int y) { move(Point(getX(), y)); } void setY(int y) { moveTo(Point(getX(), y)); }
void setWidth(int width) { resize(Size(width, getHeight())); } void setWidth(int width) { resize(Size(width, getHeight())); }
void setHeight(int height) { resize(Size(getWidth(), height)); } void setHeight(int height) { resize(Size(getWidth(), height)); }
void resize(const Size& size) { setRect(Rect(getPosition(), size)); }
void move(const Point& pos) { setRect(Rect(pos, getSize())); }
void setImage(const ImagePtr& image) { m_image = image; } void setImage(const ImagePtr& image) { m_image = image; }
virtual void setFont(const FontPtr& font) { m_font = font; } virtual void setFont(const FontPtr& font) { m_font = font; }
void setOpacity(int opacity) { m_opacity = opacity; } void setOpacity(int opacity) { m_opacity = opacity; }
void setBackgroundColor(const Color& color) { m_backgroundColor = color; } void setBackgroundColor(const Color& color) { m_backgroundColor = color; }
void setForegroundColor(const Color& color) { m_foregroundColor = color; } void setForegroundColor(const Color& color) { m_foregroundColor = color; }
void setMarginLeft(int margin) { m_marginLeft = margin; updateLayout(); } void setMarginLeft(int margin) { m_marginLeft = margin; updateParentLayout(); }
void setMarginRight(int margin) { m_marginRight = margin; updateLayout(); } void setMarginRight(int margin) { m_marginRight = margin; updateParentLayout(); }
void setMarginTop(int margin) { m_marginTop = margin; updateLayout(); } void setMarginTop(int margin) { m_marginTop = margin; updateParentLayout(); }
void setMarginBottom(int margin) { m_marginBottom = margin; updateLayout(); } void setMarginBottom(int margin) { m_marginBottom = margin; updateParentLayout(); }
void setSizeFixed(bool fixed) { m_fixedSize = fixed; updateParentLayout(); }
void setLastFocusReason(FocusReason reason) { m_lastFocusReason = reason; }
void resize(const Size& size) { setRect(Rect(getPosition(), size)); }
void moveTo(const Point& pos) { setRect(Rect(pos, getSize())); }
void hide() { setVisible(false); } void hide() { setVisible(false); }
void show() { setVisible(true); } void show() { setVisible(true); }
void disable() { setEnabled(false); } void disable() { setEnabled(false); }
void enable() { setEnabled(true); } void enable() { setEnabled(true); }
bool isEnabled(); bool isActive() const { return hasState(ActiveState); }
bool isEnabled() const { return !hasState(DisabledState); }
bool isDisabled() const { return hasState(DisabledState); }
bool isFocused() const { return hasState(FocusState); }
bool isHovered() const { return hasState(HoverState); }
bool isPressed() const { return hasState(PressedState); }
bool isVisible();
bool isExplicitlyEnabled() const { return m_enabled; } bool isExplicitlyEnabled() const { return m_enabled; }
bool isExplicitlyVisible() const { return m_visible; } bool isExplicitlyVisible() const { return m_visible; }
bool isHovered() const { return m_hovered; }
bool isFocusable() const { return m_focusable; } bool isFocusable() const { return m_focusable; }
bool isDestroyed() const { return m_destroyed; } bool isSizeFixed() const { return m_fixedSize; }
bool hasChildren() const { return m_children.size() > 0; } bool hasChildren() const { return m_children.size() > 0; }
bool hasFocus();
bool hasChild(const UIWidgetPtr& child); bool hasChild(const UIWidgetPtr& child);
bool hasState(WidgetState state) const { return m_states & state; }
std::string getId() const { return m_id; } std::string getId() const { return m_id; }
int getChildCount() const { return m_children.size(); } int getChildCount() const { return m_children.size(); }
UILayoutPtr getLayout() const { return m_layout; }
UIWidgetPtr getParent() const { return m_parent.lock(); } UIWidgetPtr getParent() const { return m_parent.lock(); }
UIWidgetPtr getRootParent(); UIWidgetPtr getRootParent();
Point getPosition() const { return m_rect.topLeft(); } Point getPosition() const { return m_rect.topLeft(); }
@ -74,7 +79,6 @@ public:
int getY() const { return m_rect.y(); } int getY() const { return m_rect.y(); }
int getWidth() const { return m_rect.width(); } int getWidth() const { return m_rect.width(); }
int getHeight() const { return m_rect.height(); } int getHeight() const { return m_rect.height(); }
ImagePtr getImage() const { return m_image; } ImagePtr getImage() const { return m_image; }
FontPtr getFont() const { return m_font; } FontPtr getFont() const { return m_font; }
Color getForegroundColor() const { return m_foregroundColor; } Color getForegroundColor() const { return m_foregroundColor; }
@ -84,6 +88,7 @@ public:
int getMarginRight() const { return m_marginRight; } int getMarginRight() const { return m_marginRight; }
int getMarginTop() const { return m_marginTop; } int getMarginTop() const { return m_marginTop; }
int getMarginBottom() const { return m_marginBottom; } int getMarginBottom() const { return m_marginBottom; }
FocusReason getLastFocusReason() const { return m_lastFocusReason; }
UIWidgetList getChildren() const { return m_children; } UIWidgetList getChildren() const { return m_children; }
UIWidgetPtr getFocusedChild() const { return m_focusedChild; } UIWidgetPtr getFocusedChild() const { return m_focusedChild; }
@ -91,43 +96,34 @@ public:
UIWidgetPtr getChildBefore(const UIWidgetPtr& relativeChild); UIWidgetPtr getChildBefore(const UIWidgetPtr& relativeChild);
UIWidgetPtr getChildById(const std::string& childId); UIWidgetPtr getChildById(const std::string& childId);
UIWidgetPtr getChildByPos(const Point& childPos); UIWidgetPtr getChildByPos(const Point& childPos);
UIWidgetPtr getChildByIndex(int childIndex); UIWidgetPtr getChildByIndex(int index);
UIWidgetPtr recursiveGetChildById(const std::string& id); UIWidgetPtr recursiveGetChildById(const std::string& id);
UIWidgetPtr recursiveGetChildByPos(const Point& childPos); UIWidgetPtr recursiveGetChildByPos(const Point& childPos);
UIWidgetPtr backwardsGetWidgetById(const std::string& id); UIWidgetPtr backwardsGetWidgetById(const std::string& id);
void addChild(const UIWidgetPtr& childToAdd); void addChild(const UIWidgetPtr& child);
void insertChild(const UIWidgetPtr& childToInsert, int index); void insertChild(int index, const UIWidgetPtr& child);
void removeChild(const UIWidgetPtr& childToRemove); void removeChild(const UIWidgetPtr& child);
void focusChild(const UIWidgetPtr& childToFocus, UI::FocusReason reason); void focusChild(const UIWidgetPtr& child, FocusReason reason);
void focusNextChild(UI::FocusReason reason); void focusNextChild(FocusReason reason);
void moveChildToTop(const UIWidgetPtr& childToMove); void moveChildToTop(const UIWidgetPtr& child);
void lockChild(const UIWidgetPtr& childToLock); void lockChild(const UIWidgetPtr& child);
void unlockChild(const UIWidgetPtr& childToUnlock); void unlockChild(const UIWidgetPtr& child);
void updateParentLayout();
void updateLayout(); void updateLayout();
void updateChildrenLayout(); virtual void updateState(WidgetState state);
void updateStates();
bool addAnchor(AnchorEdge edge, const std::string& hookedWidgetId, AnchorEdge hookedEdge); virtual void updateStyle();
void centerIn(const std::string& hookedWidgetId); void applyStyle(const OTMLNodePtr& styleNode);
void fill(const std::string& hookedWidgetId);
UIWidgetPtr asUIWidget() { return std::static_pointer_cast<UIWidget>(shared_from_this()); } UIWidgetPtr asUIWidget() { return std::static_pointer_cast<UIWidget>(shared_from_this()); }
private: private:
void internalUpdateLayout(); void internalDestroy();
void internalUpdateChildrenLayout(); void internalDestroyCheck();
void addAnchoredWidget(const UIWidgetPtr& widget);
void recalculateAnchoredWidgets();
void clearAnchoredWidgets();
void computeAnchoredWidgets();
void resetLayoutUpdateState(bool resetOwn);
bool m_layoutUpdated;
bool m_updateEventScheduled; bool m_updateEventScheduled;
bool m_layoutUpdateScheduled;
bool m_childrenLayoutUpdateScheduled;
protected: protected:
/// Triggered when widget style is changed /// Triggered when widget style is changed
@ -135,7 +131,7 @@ protected:
/// Triggered when widget is moved or resized /// Triggered when widget is moved or resized
virtual void onGeometryUpdate(const Rect& oldRect, const Rect& newRect); virtual void onGeometryUpdate(const Rect& oldRect, const Rect& newRect);
/// Triggered when widget gets or loses focus /// Triggered when widget gets or loses focus
virtual void onFocusChange(bool focused, UI::FocusReason reason); virtual void onFocusChange(bool focused, FocusReason reason);
/// Triggered when the mouse enters or leaves widget area /// Triggered when the mouse enters or leaves widget area
virtual void onHoverChange(bool hovered); virtual void onHoverChange(bool hovered);
/// Triggered when user presses key while widget has focus /// Triggered when user presses key while widget has focus
@ -143,33 +139,33 @@ protected:
/// Triggered when user releases key while widget has focus /// Triggered when user releases key while widget has focus
virtual bool onKeyRelease(uchar keyCode, char keyChar, int keyboardModifiers); virtual bool onKeyRelease(uchar keyCode, char keyChar, int keyboardModifiers);
/// Triggered when a mouse button is pressed down while mouse pointer is inside widget area /// Triggered when a mouse button is pressed down while mouse pointer is inside widget area
virtual bool onMousePress(const Point& mousePos, UI::MouseButton button); virtual bool onMousePress(const Point& mousePos, MouseButton button);
/// Triggered when a mouse button is released /// Triggered when a mouse button is released
virtual bool onMouseRelease(const Point& mousePos, UI::MouseButton button); virtual bool onMouseRelease(const Point& mousePos, MouseButton button);
/// Triggered when mouse moves (even when the mouse is outside widget area) /// Triggered when mouse moves (even when the mouse is outside widget area)
virtual bool onMouseMove(const Point& mousePos, const Point& mouseMoved); virtual bool onMouseMove(const Point& mousePos, const Point& mouseMoved);
/// Triggered when mouse middle button wheels inside widget area /// Triggered when mouse middle button wheels inside widget area
virtual bool onMouseWheel(const Point& mousePos, UI::MouseWheelDirection direction); virtual bool onMouseWheel(const Point& mousePos, MouseWheelDirection direction);
friend class UIManager; friend class UIManager;
private:
void destroyCheck();
protected: protected:
std::string m_id;
FocusReason m_lastFocusReason;
bool m_enabled; bool m_enabled;
bool m_visible; bool m_visible;
bool m_hovered;
bool m_focusable; bool m_focusable;
bool m_destroyed; bool m_fixedSize;
bool m_pressed;
Rect m_rect; Rect m_rect;
UIAnchorList m_anchors; UILayoutPtr m_layout;
UIWeakWidgetList m_anchoredWidgets;
UIWidgetWeakPtr m_parent; UIWidgetWeakPtr m_parent;
UIWidgetList m_children; UIWidgetList m_children;
UIWidgetList m_lockedWidgets; UIWidgetList m_lockedChildren;
UIWidgetPtr m_focusedChild; UIWidgetPtr m_focusedChild;
std::string m_id; OTMLNodePtr m_style;
OTMLNodePtr m_stateStyle;
uint m_states;
// basic style components used by all widgets // basic style components used by all widgets
ImagePtr m_image; ImagePtr m_image;

@ -1,41 +1,16 @@
#include "uiwindow.h" #include "uiwindow.h"
#include <framework/graphics/borderimage.h> #include <framework/graphics/borderimage.h>
#include <framework/graphics/font.h> #include <framework/graphics/font.h>
#include <framework/graphics/graphics.h>
#include <framework/otml/otml.h> #include <framework/otml/otml.h>
UIWindow::UIWindow() void UIWindow::setup()
{ {
UIWidget::setup();
m_moving = false; m_moving = false;
} m_headHeight = 0;
m_headMargin = 0;
UIWindowPtr UIWindow::create() m_titleAlign = AlignCenter;
{
UIWindowPtr window(new UIWindow);
return window;
}
void UIWindow::onStyleApply(const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleNode);
if(OTMLNodePtr headNode = styleNode->get("head")) {
if(OTMLNodePtr node = headNode->get("border-image"))
m_headImage = BorderImage::loadFromOTML(node);
m_headHeight = headNode->valueAt("height", m_headImage->getDefaultSize().height());
m_headMargin = headNode->valueAt("margin", 0);
m_titleAlign = fw::translateAlignment(headNode->valueAt("text align", std::string("center")));
} else {
m_headHeight = 0;
m_headMargin = 0;
m_titleAlign = AlignCenter;
}
if(OTMLNodePtr bodyNode = styleNode->get("body")) {
if(OTMLNodePtr node = bodyNode->get("border-image"))
m_bodyImage = BorderImage::loadFromOTML(node);
}
m_title = styleNode->valueAt("title", fw::empty_string);
} }
void UIWindow::render() void UIWindow::render()
@ -45,6 +20,7 @@ void UIWindow::render()
headRect.setHeight(m_headHeight); headRect.setHeight(m_headHeight);
if(m_headImage && m_headHeight > 0) { if(m_headImage && m_headHeight > 0) {
g_graphics.bindColor(m_backgroundColor);
m_headImage->draw(headRect); m_headImage->draw(headRect);
// draw window head text // draw window head text
@ -59,13 +35,37 @@ void UIWindow::render()
// draw window body // draw window body
Rect bodyRect = getRect(); Rect bodyRect = getRect();
bodyRect.setTop(headRect.bottom() + 1); bodyRect.setTop(headRect.bottom() + 1);
if(m_bodyImage) if(m_bodyImage) {
g_graphics.bindColor(m_backgroundColor);
m_bodyImage->draw(bodyRect); m_bodyImage->draw(bodyRect);
}
// render children // render children
UIWidget::render(); UIWidget::render();
} }
void UIWindow::onStyleApply(const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleNode);
for(OTMLNodePtr node : styleNode->children()) {
if(node->tag() == "head") {
if(OTMLNodePtr cnode = node->get("border-image"))
m_headImage = BorderImage::loadFromOTML(cnode);
m_headHeight = node->valueAt("height", m_headImage->getDefaultSize().height());
m_headMargin = node->valueAt("margin", 0);
m_titleAlign = fw::translateAlignment(node->valueAt("text align", std::string("center")));
}
else if(node->tag() == "body") {
if(OTMLNodePtr cnode = node->get("border-image"))
m_bodyImage = BorderImage::loadFromOTML(cnode);
}
else if(node->tag() == "title") {
setTitle(node->value());
}
}
}
void UIWindow::onGeometryUpdate(const Rect& oldRect, const Rect& newRect) void UIWindow::onGeometryUpdate(const Rect& oldRect, const Rect& newRect)
{ {
// bind window rect to parent rect // bind window rect to parent rect
@ -87,18 +87,18 @@ void UIWindow::onGeometryUpdate(const Rect& oldRect, const Rect& newRect)
setRect(boundRect); setRect(boundRect);
} }
void UIWindow::onFocusChange(bool focused, UI::FocusReason reason) void UIWindow::onFocusChange(bool focused, FocusReason reason)
{ {
// when a window is focused it goes to the top // when a window is focused it goes to the top
if(UIWidgetPtr parent = getParent()) if(focused) {
parent->moveChildToTop(asUIWidget()); if(UIWidgetPtr parent = getParent())
parent->moveChildToTop(asUIWidget());
}
} }
bool UIWindow::onMousePress(const Point& mousePos, UI::MouseButton button) bool UIWindow::onMousePress(const Point& mousePos, MouseButton button)
{ {
Rect headRect = getRect(); if(!getChildByPos(mousePos)) {
headRect.setHeight(m_headHeight);
if(headRect.contains(mousePos)) {
m_moving = true; m_moving = true;
m_movingReference = mousePos - getRect().topLeft(); m_movingReference = mousePos - getRect().topLeft();
return true; return true;
@ -106,7 +106,7 @@ bool UIWindow::onMousePress(const Point& mousePos, UI::MouseButton button)
return UIWidget::onMousePress(mousePos, button); return UIWidget::onMousePress(mousePos, button);
} }
bool UIWindow::onMouseRelease(const Point& mousePos, UI::MouseButton button) bool UIWindow::onMouseRelease(const Point& mousePos, MouseButton button)
{ {
if(m_moving) { if(m_moving) {
m_moving = false; m_moving = false;
@ -118,7 +118,7 @@ bool UIWindow::onMouseRelease(const Point& mousePos, UI::MouseButton button)
bool UIWindow::onMouseMove(const Point& mousePos, const Point& mouseMoved) bool UIWindow::onMouseMove(const Point& mousePos, const Point& mouseMoved)
{ {
if(m_moving) { if(m_moving) {
move(mousePos - m_movingReference); moveTo(mousePos - m_movingReference);
return true; return true;
} }
return UIWidget::onMouseMove(mousePos, mouseMoved); return UIWidget::onMouseMove(mousePos, mouseMoved);

@ -6,21 +6,18 @@
class UIWindow : public UIWidget class UIWindow : public UIWidget
{ {
public: public:
UIWindow(); virtual void setup();
static UIWindowPtr create();
virtual void onStyleApply(const OTMLNodePtr& styleNode);
virtual void render(); virtual void render();
void setTitle(const std::string& title) { m_title = title; } void setTitle(const std::string& title) { m_title = title; }
std::string getTitle() const { return m_title; } std::string getTitle() const { return m_title; }
protected: protected:
virtual void onStyleApply(const OTMLNodePtr& styleNode);
virtual void onGeometryUpdate(const Rect& oldRect, const Rect& newRect); virtual void onGeometryUpdate(const Rect& oldRect, const Rect& newRect);
virtual void onFocusChange(bool focused, UI::FocusReason reason); virtual void onFocusChange(bool focused, FocusReason reason);
virtual bool onMousePress(const Point& mousePos, UI::MouseButton button); virtual bool onMousePress(const Point& mousePos, MouseButton button);
virtual bool onMouseRelease(const Point& mousePos, UI::MouseButton button); virtual bool onMouseRelease(const Point& mousePos, MouseButton button);
virtual bool onMouseMove(const Point& mousePos, const Point& mouseMoved); virtual bool onMouseMove(const Point& mousePos, const Point& mouseMoved);
private: private:

@ -9,7 +9,7 @@ typedef uint32 RGBA;
class Color class Color
{ {
public: public:
Color() : color(0xFFFFFFFF) { } Color() : color(0x0) { }
Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((a & 0xff)<<24) | ((b & 0xff)<<16) | ((g & 0xff)<<8) | (r & 0xff)) { } Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((a & 0xff)<<24) | ((b & 0xff)<<16) | ((g & 0xff)<<8) | (r & 0xff)) { }
Color(const Color& other) : color(other.color) { } Color(const Color& other) : color(other.color) { }
Color(RGBA rgba) : color(rgba) { } Color(RGBA rgba) : color(rgba) { }

@ -21,23 +21,26 @@ AlignmentFlag fw::translateAlignment(std::string aligment)
return AlignTopCenter; return AlignTopCenter;
else if(aligment == "bottom") else if(aligment == "bottom")
return AlignBottomCenter; return AlignBottomCenter;
else else if(aligment == "center")
return AlignCenter; return AlignCenter;
return AlignNone;
} }
AnchorEdge fw::translateAnchorEdge(const std::string& anchorPoint) AnchorEdge fw::translateAnchorEdge(std::string anchorEdge)
{ {
if(anchorPoint == "left") boost::to_lower(anchorEdge);
boost::erase_all(anchorEdge, " ");
if(anchorEdge == "left")
return AnchorLeft; return AnchorLeft;
else if(anchorPoint == "right") else if(anchorEdge == "right")
return AnchorRight; return AnchorRight;
else if(anchorPoint == "top") else if(anchorEdge == "top")
return AnchorTop; return AnchorTop;
else if(anchorPoint == "bottom") else if(anchorEdge == "bottom")
return AnchorBottom; return AnchorBottom;
else if(anchorPoint == "horizontalCenter") else if(anchorEdge == "horizontalcenter")
return AnchorHorizontalCenter; return AnchorHorizontalCenter;
else if(anchorPoint == "verticalCenter") else if(anchorEdge == "verticalcenter")
return AnchorVerticalCenter; return AnchorVerticalCenter;
return AnchorNone; return AnchorNone;
} }

@ -7,7 +7,7 @@
namespace fw { namespace fw {
AlignmentFlag translateAlignment(std::string aligment); AlignmentFlag translateAlignment(std::string aligment);
AnchorEdge translateAnchorEdge(const std::string& anchorPoint); AnchorEdge translateAnchorEdge(std::string anchorEdge);
}; };

@ -1,7 +1,8 @@
#include <otclient/otclient.h> #include <otclient/otclient.h>
#include <csignal>
#include <framework/core/eventdispatcher.h> #include <framework/core/eventdispatcher.h>
#include <csignal>
void signal_handler(int sig) void signal_handler(int sig)
{ {
static bool signaled = false; static bool signaled = false;

@ -296,10 +296,10 @@ void OTClient::onPlatformEvent(const PlatformEvent& event)
// TODO: move these events to lua // TODO: move these events to lua
UIWidgetPtr console = g_ui.getRootWidget()->getChildById("consolePanel"); UIWidgetPtr console = g_ui.getRootWidget()->getChildById("consolePanel");
if(!console->isExplicitlyVisible()) { if(!console->isExplicitlyVisible()) {
g_ui.getRootWidget()->focusChild(console, UI::ActiveFocusReason); g_ui.getRootWidget()->lockChild(console);
g_ui.getRootWidget()->moveChildToTop(console);
console->setVisible(true); console->setVisible(true);
} else { } else {
g_ui.getRootWidget()->unlockChild(console);
console->setVisible(false); console->setVisible(false);
} }
fireUi = false; fireUi = false;

Loading…
Cancel
Save