2011-08-28 15:17:58 +02:00
|
|
|
/*
|
2012-01-02 17:58:37 +01:00
|
|
|
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
|
2011-08-28 15:17:58 +02:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2011-08-14 04:09:11 +02:00
|
|
|
#include "uiwidget.h"
|
|
|
|
#include "uimanager.h"
|
2011-08-26 17:06:52 +02:00
|
|
|
#include "uianchorlayout.h"
|
2011-11-16 00:47:32 +01:00
|
|
|
#include "uitranslator.h"
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2011-08-15 16:06:15 +02:00
|
|
|
#include <framework/core/eventdispatcher.h>
|
|
|
|
#include <framework/otml/otmlnode.h>
|
|
|
|
#include <framework/graphics/graphics.h>
|
2011-12-03 22:41:37 +01:00
|
|
|
#include <framework/platform/platformwindow.h>
|
2012-01-04 11:26:58 +01:00
|
|
|
#include <framework/graphics/texturemanager.h>
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2011-08-22 14:44:26 +02:00
|
|
|
UIWidget::UIWidget()
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2011-11-17 18:43:41 +01:00
|
|
|
m_lastFocusReason = Fw::ActiveFocusReason;
|
2011-08-28 18:02:26 +02:00
|
|
|
m_states = Fw::DefaultState;
|
2012-02-03 06:25:01 +01:00
|
|
|
m_clickTimer.stop();
|
2012-02-06 13:53:28 +01:00
|
|
|
m_autoRepeatDelay = 500;
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
initBaseStyle();
|
|
|
|
initText();
|
|
|
|
initImage();
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidget::~UIWidget()
|
2011-08-22 21:39:46 +02:00
|
|
|
{
|
2012-02-05 23:42:35 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if(!m_destroyed)
|
|
|
|
logWarning("widget '", m_id, "' was not explicitly destroyed");
|
|
|
|
#endif
|
2011-08-14 16:09:26 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::draw()
|
2011-11-03 10:59:11 +01:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
drawSelf();
|
|
|
|
drawChildren();
|
2011-11-03 10:59:11 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::drawSelf()
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-01-04 11:26:58 +01:00
|
|
|
// draw style components in order
|
2012-03-20 16:17:10 +01:00
|
|
|
if(m_backgroundColor.aF() != 0.0f) {
|
2012-01-10 23:13:40 +01:00
|
|
|
Rect backgroundDestRect = m_rect;
|
|
|
|
backgroundDestRect.expand(-m_borderWidth.top, -m_borderWidth.right, -m_borderWidth.bottom, -m_borderWidth.left);
|
|
|
|
drawBackground(m_rect);
|
|
|
|
}
|
|
|
|
|
2012-01-04 11:26:58 +01:00
|
|
|
drawImage(m_rect);
|
2012-01-21 02:01:11 +01:00
|
|
|
drawBorder(m_rect);
|
2012-01-04 11:26:58 +01:00
|
|
|
drawIcon(m_rect);
|
|
|
|
drawText(m_rect);
|
2011-11-03 10:59:11 +01:00
|
|
|
}
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::drawChildren()
|
2011-11-03 10:59:11 +01:00
|
|
|
{
|
2011-08-22 21:13:52 +02:00
|
|
|
// draw children
|
2011-08-14 04:09:11 +02:00
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
2012-01-10 23:13:40 +01:00
|
|
|
// render only visible children with a valid rect inside parent rect
|
2012-01-04 11:26:58 +01:00
|
|
|
if(child->isExplicitlyVisible() &&
|
|
|
|
child->getRect().isValid() &&
|
2012-01-10 23:13:40 +01:00
|
|
|
child->getOpacity() > 0.0f &&
|
|
|
|
child->getRect().intersects(m_rect)) {
|
2011-08-22 21:13:52 +02:00
|
|
|
// store current graphics opacity
|
2012-01-10 23:13:40 +01:00
|
|
|
float oldOpacity = g_painter.getOpacity();
|
2011-08-22 21:13:52 +02:00
|
|
|
|
|
|
|
// decrease to self opacity
|
2011-08-14 19:45:25 +02:00
|
|
|
if(child->getOpacity() < oldOpacity)
|
2011-12-07 01:31:55 +01:00
|
|
|
g_painter.setOpacity(child->getOpacity());
|
2011-08-14 19:45:25 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
child->draw();
|
2011-08-14 19:45:25 +02:00
|
|
|
|
2011-08-20 22:30:41 +02:00
|
|
|
// debug draw box
|
2012-01-09 19:45:28 +01:00
|
|
|
if(g_ui.isDrawingDebugBoxes()) {
|
2012-03-20 16:17:10 +01:00
|
|
|
g_painter.setColor(Color::green);
|
2012-01-09 19:45:28 +01:00
|
|
|
g_painter.drawBoundingRect(child->getRect());
|
|
|
|
}
|
2012-03-20 16:17:10 +01:00
|
|
|
//g_fonts.getDefaultFont()->renderText(child->getId(), child->getPosition() + Point(2, 0), Color::red);
|
2011-08-20 22:30:41 +02:00
|
|
|
|
2011-12-07 01:31:55 +01:00
|
|
|
g_painter.setOpacity(oldOpacity);
|
2011-08-14 19:45:25 +02:00
|
|
|
}
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::addChild(const UIWidgetPtr& child)
|
2012-01-04 11:26:58 +01:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
if(!child) {
|
|
|
|
logWarning("attempt to add a null child into a UIWidget");
|
|
|
|
return;
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
|
|
|
|
2012-02-20 03:27:08 +01:00
|
|
|
if(child->isDestroyed()) {
|
|
|
|
logWarning("attemp to add a destroyed child into a UIWidget");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(hasChild(child)) {
|
|
|
|
logWarning("attempt to add a child again into a UIWidget");
|
|
|
|
return;
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
|
|
|
|
m_children.push_back(child);
|
|
|
|
child->setParent(asUIWidget());
|
|
|
|
|
|
|
|
// create default layout
|
|
|
|
if(!m_layout)
|
|
|
|
m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(asUIWidget()));
|
|
|
|
|
|
|
|
// add to layout and updates it
|
|
|
|
m_layout->addWidget(child);
|
|
|
|
|
|
|
|
// update new child states
|
|
|
|
child->updateStates();
|
|
|
|
updateChildrenIndexStates();
|
2012-02-07 20:21:53 +01:00
|
|
|
|
|
|
|
g_ui.onWidgetAppear(child);
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::insertChild(int index, const UIWidgetPtr& child)
|
2012-01-04 11:26:58 +01:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
if(!child) {
|
|
|
|
logWarning("attempt to insert a null child into a UIWidget");
|
|
|
|
return;
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(hasChild(child)) {
|
|
|
|
logWarning("attempt to insert a child again into a UIWidget");
|
|
|
|
return;
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
|
|
|
|
index = index <= 0 ? (m_children.size() + index) : index-1;
|
|
|
|
|
2012-02-20 03:27:08 +01:00
|
|
|
if(!(index >= 0 && (uint)index <= m_children.size())) {
|
|
|
|
logTraceError("attemp to insert a child in an invalid index");
|
|
|
|
return;
|
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
|
|
|
|
// retrieve child by index
|
|
|
|
auto it = m_children.begin() + index;
|
|
|
|
m_children.insert(it, child);
|
|
|
|
child->setParent(asUIWidget());
|
|
|
|
|
|
|
|
// create default layout if needed
|
|
|
|
if(!m_layout)
|
|
|
|
m_layout = UIAnchorLayoutPtr(new UIAnchorLayout(asUIWidget()));
|
|
|
|
|
|
|
|
// add to layout and updates it
|
|
|
|
m_layout->addWidget(child);
|
|
|
|
|
|
|
|
// update new child states
|
|
|
|
child->updateStates();
|
|
|
|
updateChildrenIndexStates();
|
2012-02-07 20:21:53 +01:00
|
|
|
|
|
|
|
g_ui.onWidgetAppear(child);
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
void UIWidget::removeChild(UIWidgetPtr child)
|
2012-01-04 11:26:58 +01:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
// remove from children list
|
|
|
|
if(hasChild(child)) {
|
|
|
|
// defocus if needed
|
|
|
|
bool focusAnother = false;
|
|
|
|
if(m_focusedChild == child) {
|
|
|
|
focusChild(nullptr, Fw::ActiveFocusReason);
|
|
|
|
focusAnother = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(isChildLocked(child))
|
|
|
|
unlockChild(child);
|
|
|
|
|
|
|
|
auto it = std::find(m_children.begin(), m_children.end(), child);
|
|
|
|
m_children.erase(it);
|
|
|
|
|
|
|
|
// reset child parent
|
|
|
|
assert(child->getParent() == asUIWidget());
|
|
|
|
child->setParent(nullptr);
|
|
|
|
|
|
|
|
m_layout->removeWidget(child);
|
|
|
|
|
|
|
|
// update child states
|
|
|
|
child->updateStates();
|
|
|
|
updateChildrenIndexStates();
|
|
|
|
|
|
|
|
if(focusAnother && !m_focusedChild)
|
|
|
|
focusPreviousChild(Fw::ActiveFocusReason);
|
2012-02-07 20:21:53 +01:00
|
|
|
|
|
|
|
g_ui.onWidgetDisappear(child);
|
2012-01-10 23:13:40 +01:00
|
|
|
} else
|
2012-03-18 14:34:39 +01:00
|
|
|
logError("attempt to remove an unknown child from a UIWidget");
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
|
|
|
|
void UIWidget::focusChild(const UIWidgetPtr& child, Fw::FocusReason reason)
|
2011-08-30 01:40:56 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-19 05:12:53 +01:00
|
|
|
if(child == m_focusedChild)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(child && !hasChild(child)) {
|
2012-01-19 05:12:53 +01:00
|
|
|
logError("attempt to focus an unknown child in a UIWidget");
|
2012-01-10 23:13:40 +01:00
|
|
|
return;
|
|
|
|
}
|
2011-11-16 22:00:40 +01:00
|
|
|
|
2012-01-19 05:12:53 +01:00
|
|
|
UIWidgetPtr oldFocused = m_focusedChild;
|
|
|
|
m_focusedChild = child;
|
2012-01-10 23:13:40 +01:00
|
|
|
|
2012-01-19 05:12:53 +01:00
|
|
|
if(child) {
|
|
|
|
child->setLastFocusReason(reason);
|
|
|
|
child->updateState(Fw::FocusState);
|
|
|
|
child->updateState(Fw::ActiveState);
|
|
|
|
}
|
2011-11-16 22:00:40 +01:00
|
|
|
|
2012-01-19 05:12:53 +01:00
|
|
|
if(oldFocused) {
|
|
|
|
oldFocused->setLastFocusReason(reason);
|
|
|
|
oldFocused->updateState(Fw::FocusState);
|
|
|
|
oldFocused->updateState(Fw::ActiveState);
|
2011-11-16 22:00:40 +01:00
|
|
|
}
|
2012-02-06 02:44:47 +01:00
|
|
|
|
|
|
|
onChildFocusChange(child, oldFocused, reason);
|
2011-11-16 22:00:40 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::focusNextChild(Fw::FocusReason reason)
|
2012-01-05 03:42:17 +01:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidgetPtr toFocus;
|
|
|
|
UIWidgetList rotatedChildren(m_children);
|
2012-01-05 03:42:17 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(m_focusedChild) {
|
|
|
|
auto focusedIt = std::find(rotatedChildren.begin(), rotatedChildren.end(), m_focusedChild);
|
|
|
|
if(focusedIt != rotatedChildren.end()) {
|
|
|
|
std::rotate(rotatedChildren.begin(), focusedIt, rotatedChildren.end());
|
|
|
|
rotatedChildren.pop_front();
|
|
|
|
}
|
2012-01-05 03:42:17 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// finds next child to focus
|
|
|
|
for(const UIWidgetPtr& child : rotatedChildren) {
|
|
|
|
if(child->isFocusable() && child->isExplicitlyEnabled() && child->isVisible()) {
|
|
|
|
toFocus = child;
|
|
|
|
break;
|
|
|
|
}
|
2012-01-05 03:42:17 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(toFocus)
|
|
|
|
focusChild(toFocus, reason);
|
2012-01-05 19:02:27 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::focusPreviousChild(Fw::FocusReason reason)
|
2012-01-05 19:02:27 +01:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidgetPtr toFocus;
|
|
|
|
UIWidgetList rotatedChildren(m_children);
|
|
|
|
std::reverse(rotatedChildren.begin(), rotatedChildren.end());
|
2012-01-05 19:02:27 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(m_focusedChild) {
|
|
|
|
auto focusedIt = std::find(rotatedChildren.begin(), rotatedChildren.end(), m_focusedChild);
|
|
|
|
if(focusedIt != rotatedChildren.end()) {
|
|
|
|
std::rotate(rotatedChildren.begin(), focusedIt, rotatedChildren.end());
|
|
|
|
rotatedChildren.pop_front();
|
|
|
|
}
|
|
|
|
}
|
2011-11-16 22:00:40 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// finds next child to focus
|
|
|
|
for(const UIWidgetPtr& child : rotatedChildren) {
|
|
|
|
if(child->isFocusable() && child->isExplicitlyEnabled() && child->isVisible()) {
|
|
|
|
toFocus = child;
|
|
|
|
break;
|
2011-11-16 22:00:40 +01:00
|
|
|
}
|
2011-08-30 01:40:56 +02:00
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
|
|
|
|
if(toFocus)
|
|
|
|
focusChild(toFocus, reason);
|
2011-08-30 01:40:56 +02:00
|
|
|
}
|
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
void UIWidget::lowerChild(UIWidgetPtr child)
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
if(!child)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// remove and push child again
|
|
|
|
auto it = std::find(m_children.begin(), m_children.end(), child);
|
2012-02-20 03:27:08 +01:00
|
|
|
if(it == m_children.end()) {
|
|
|
|
logTraceError("cannot find child");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
m_children.erase(it);
|
|
|
|
m_children.push_front(child);
|
|
|
|
updateChildrenIndexStates();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::raiseChild(UIWidgetPtr child)
|
2011-08-26 17:06:52 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(!child)
|
2011-12-01 23:25:32 +01:00
|
|
|
return;
|
2012-01-10 23:13:40 +01:00
|
|
|
|
|
|
|
// remove and push child again
|
|
|
|
auto it = std::find(m_children.begin(), m_children.end(), child);
|
2012-02-20 03:27:08 +01:00
|
|
|
if(it == m_children.end()) {
|
|
|
|
logTraceError("cannot find child");
|
|
|
|
return;
|
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
m_children.erase(it);
|
|
|
|
m_children.push_back(child);
|
|
|
|
updateChildrenIndexStates();
|
2011-08-26 17:06:52 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::moveChildToIndex(const UIWidgetPtr& child, int index)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(!child)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// remove and push child again
|
|
|
|
auto it = std::find(m_children.begin(), m_children.end(), child);
|
2012-02-20 03:27:08 +01:00
|
|
|
if(it == m_children.end()) {
|
|
|
|
logTraceError("cannot find child");
|
|
|
|
return;
|
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
m_children.erase(it);
|
|
|
|
m_children.insert(m_children.begin() + index - 1, child);
|
|
|
|
updateChildrenIndexStates();
|
2011-08-26 17:06:52 +02:00
|
|
|
}
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::lockChild(const UIWidgetPtr& child)
|
2011-08-26 17:06:52 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(!child)
|
2011-11-17 21:40:31 +01:00
|
|
|
return;
|
|
|
|
|
2012-02-20 03:27:08 +01:00
|
|
|
if(!hasChild(child)) {
|
|
|
|
logTraceError("cannot find child");
|
|
|
|
return;
|
|
|
|
}
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// prevent double locks
|
|
|
|
if(isChildLocked(child))
|
|
|
|
unlockChild(child);
|
2011-08-22 21:13:52 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// disable all other children
|
|
|
|
for(const UIWidgetPtr& otherChild : m_children) {
|
|
|
|
if(otherChild == child)
|
|
|
|
child->setEnabled(true);
|
|
|
|
else
|
|
|
|
otherChild->setEnabled(false);
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
|
|
|
|
m_lockedChildren.push_front(child);
|
|
|
|
|
|
|
|
// lock child focus
|
|
|
|
if(child->isFocusable())
|
|
|
|
focusChild(child, Fw::ActiveFocusReason);
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::unlockChild(const UIWidgetPtr& child)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(!child)
|
2011-08-26 17:06:52 +02:00
|
|
|
return;
|
|
|
|
|
2012-02-20 03:27:08 +01:00
|
|
|
if(!hasChild(child)) {
|
|
|
|
logTraceError("cannot find child");
|
|
|
|
return;
|
|
|
|
}
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
auto it = std::find(m_lockedChildren.begin(), m_lockedChildren.end(), child);
|
|
|
|
if(it == m_lockedChildren.end())
|
|
|
|
return;
|
2011-08-21 21:43:05 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
m_lockedChildren.erase(it);
|
|
|
|
|
|
|
|
// find new child to lock
|
|
|
|
UIWidgetPtr lockedChild;
|
|
|
|
if(m_lockedChildren.size() > 0) {
|
|
|
|
lockedChild = m_lockedChildren.front();
|
|
|
|
assert(hasChild(lockedChild));
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
for(const UIWidgetPtr& otherChild : m_children) {
|
|
|
|
// lock new child
|
|
|
|
if(lockedChild) {
|
|
|
|
if(otherChild == lockedChild)
|
|
|
|
lockedChild->setEnabled(true);
|
|
|
|
else
|
|
|
|
otherChild->setEnabled(false);
|
|
|
|
}
|
|
|
|
// else unlock all
|
|
|
|
else
|
|
|
|
otherChild->setEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(lockedChild) {
|
|
|
|
if(lockedChild->isFocusable())
|
|
|
|
focusChild(lockedChild, Fw::ActiveFocusReason);
|
|
|
|
}
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::applyStyle(const OTMLNodePtr& styleNode)
|
2012-01-04 11:26:58 +01:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-16 09:26:57 +01:00
|
|
|
if(styleNode->size() == 0)
|
|
|
|
return;
|
|
|
|
|
2012-01-12 20:20:18 +01:00
|
|
|
m_loadingStyle = true;
|
2012-01-10 23:13:40 +01:00
|
|
|
try {
|
|
|
|
onStyleApply(styleNode->tag(), styleNode);
|
|
|
|
callLuaField("onStyleApply", styleNode->tag(), styleNode);
|
2012-01-04 11:26:58 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(m_firstOnStyle) {
|
|
|
|
callLuaField("onSetup");
|
|
|
|
// always focus new child
|
|
|
|
if(isFocusable() && isExplicitlyVisible() && isExplicitlyEnabled())
|
|
|
|
focus();
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
m_firstOnStyle = false;
|
2012-01-04 11:26:58 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
} catch(Exception& e) {
|
|
|
|
logError("Failed to apply style to widget '", m_id, "' style: ", e.what());
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
2012-01-12 20:20:18 +01:00
|
|
|
m_loadingStyle = false;
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
2012-02-07 20:21:53 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::addAnchor(Fw::AnchorEdge anchoredEdge, const std::string& hookedWidgetId, Fw::AnchorEdge hookedEdge)
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout())
|
|
|
|
anchorLayout->addAnchor(asUIWidget(), anchoredEdge, hookedWidgetId, hookedEdge);
|
2012-01-19 05:12:53 +01:00
|
|
|
else
|
|
|
|
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
2012-01-04 11:26:58 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::centerIn(const std::string& hookedWidgetId)
|
2012-01-04 11:26:58 +01:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout()) {
|
|
|
|
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorHorizontalCenter, hookedWidgetId, Fw::AnchorHorizontalCenter);
|
|
|
|
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorVerticalCenter, hookedWidgetId, Fw::AnchorVerticalCenter);
|
2012-01-19 05:12:53 +01:00
|
|
|
} else
|
|
|
|
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
2012-01-04 11:26:58 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::fill(const std::string& hookedWidgetId)
|
2012-01-02 23:09:49 +01:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout()) {
|
|
|
|
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorLeft, hookedWidgetId, Fw::AnchorLeft);
|
|
|
|
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorRight, hookedWidgetId, Fw::AnchorRight);
|
|
|
|
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorTop, hookedWidgetId, Fw::AnchorTop);
|
|
|
|
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorBottom, hookedWidgetId, Fw::AnchorBottom);
|
2012-01-19 05:12:53 +01:00
|
|
|
} else
|
|
|
|
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
2012-01-02 23:09:49 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::breakAnchors()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout())
|
|
|
|
anchorLayout->removeAnchors(asUIWidget());
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::updateParentLayout()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(UIWidgetPtr parent = getParent())
|
|
|
|
parent->updateLayout();
|
|
|
|
else
|
|
|
|
updateLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::updateLayout()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(m_layout)
|
|
|
|
m_layout->update();
|
|
|
|
|
|
|
|
// children can affect the parent layout
|
|
|
|
if(UIWidgetPtr parent = getParent())
|
|
|
|
if(UILayoutPtr parentLayout = parent->getLayout())
|
|
|
|
parentLayout->updateLater();
|
2012-01-02 23:09:49 +01:00
|
|
|
}
|
|
|
|
|
2011-08-29 16:14:21 +02:00
|
|
|
void UIWidget::lock()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2011-08-29 16:14:21 +02:00
|
|
|
if(UIWidgetPtr parent = getParent())
|
|
|
|
parent->lockChild(asUIWidget());
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::unlock()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2011-08-29 16:14:21 +02:00
|
|
|
if(UIWidgetPtr parent = getParent())
|
|
|
|
parent->unlockChild(asUIWidget());
|
|
|
|
}
|
|
|
|
|
2011-11-03 10:59:11 +01:00
|
|
|
void UIWidget::focus()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2011-11-16 22:00:40 +01:00
|
|
|
if(!m_focusable)
|
|
|
|
return;
|
2012-02-07 20:21:53 +01:00
|
|
|
|
2011-11-03 10:59:11 +01:00
|
|
|
if(UIWidgetPtr parent = getParent())
|
|
|
|
parent->focusChild(asUIWidget(), Fw::ActiveFocusReason);
|
|
|
|
}
|
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
void UIWidget::lower()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
UIWidgetPtr parent = getParent();
|
|
|
|
if(parent)
|
|
|
|
parent->lowerChild(asUIWidget());
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::raise()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
UIWidgetPtr parent = getParent();
|
|
|
|
if(parent)
|
|
|
|
parent->raiseChild(asUIWidget());
|
|
|
|
}
|
|
|
|
|
2012-01-02 23:09:49 +01:00
|
|
|
void UIWidget::grabMouse()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-02 23:09:49 +01:00
|
|
|
g_ui.setMouseReceiver(asUIWidget());
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::ungrabMouse()
|
|
|
|
{
|
|
|
|
if(g_ui.getMouseReceiver() == asUIWidget())
|
|
|
|
g_ui.resetMouseReceiver();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::grabKeyboard()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-02 23:09:49 +01:00
|
|
|
g_ui.setKeyboardReceiver(asUIWidget());
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::ungrabKeyboard()
|
|
|
|
{
|
|
|
|
if(g_ui.getKeyboardReceiver() == asUIWidget())
|
|
|
|
g_ui.resetKeyboardReceiver();
|
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::bindRectToParent()
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
Rect boundRect = m_rect;
|
|
|
|
UIWidgetPtr parent = getParent();
|
|
|
|
if(parent) {
|
|
|
|
Rect parentRect = parent->getRect();
|
2012-01-25 15:56:17 +01:00
|
|
|
boundRect.bind(parentRect);
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
setRect(boundRect);
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::destroy()
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
logWarning("attempt to destroy widget '", m_id, "' two times");
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-02-07 20:21:53 +01:00
|
|
|
m_destroyed = true;
|
2012-01-10 23:13:40 +01:00
|
|
|
setVisible(false);
|
|
|
|
setEnabled(false);
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-02-07 20:21:53 +01:00
|
|
|
g_ui.onWidgetDestroy(asUIWidget());
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// remove itself from parent
|
|
|
|
if(UIWidgetPtr parent = getParent()) {
|
2012-03-18 14:34:39 +01:00
|
|
|
assert(parent->hasChild(asUIWidget()));
|
|
|
|
parent->removeChild(asUIWidget());
|
2011-08-26 17:06:52 +02:00
|
|
|
}
|
2011-08-22 21:13:52 +02:00
|
|
|
|
2012-02-06 02:44:47 +01:00
|
|
|
destroyChildren();
|
2012-03-18 14:34:39 +01:00
|
|
|
m_focusedChild = nullptr;
|
2012-02-05 23:42:35 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
callLuaField("onDestroy");
|
2011-08-22 21:13:52 +02:00
|
|
|
|
2012-02-07 07:33:20 +01:00
|
|
|
releaseLuaFieldsTable();
|
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
auto self = asUIWidget();
|
2012-03-18 14:34:39 +01:00
|
|
|
g_lua.collectGarbage();
|
2012-02-06 20:19:47 +01:00
|
|
|
if(self != g_ui.getRootWidget()) {
|
2012-03-14 19:45:15 +01:00
|
|
|
g_eventDispatcher.scheduleEvent([self] {
|
2012-02-05 23:42:35 +01:00
|
|
|
g_lua.collectGarbage();
|
2012-02-07 20:21:53 +01:00
|
|
|
if(self->getUseCount() != 1)
|
|
|
|
logWarning("widget '", self->getId(), "' destroyed but still have ", self->getUseCount()-1, " reference(s) left");
|
2012-03-18 14:34:39 +01:00
|
|
|
}, 500);
|
2012-02-06 20:19:47 +01:00
|
|
|
}
|
2012-02-05 23:42:35 +01:00
|
|
|
#endif
|
2011-08-14 16:09:26 +02:00
|
|
|
}
|
|
|
|
|
2012-02-06 02:44:47 +01:00
|
|
|
void UIWidget::destroyChildren()
|
|
|
|
{
|
|
|
|
while(!m_children.empty())
|
|
|
|
getFirstChild()->destroy();
|
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setId(const std::string& id)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
m_id = id;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setParent(const UIWidgetPtr& parent)
|
2011-08-20 22:30:41 +02:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
// remove from old parent
|
|
|
|
UIWidgetPtr oldParent = getParent();
|
2011-08-20 22:30:41 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// the parent is already the same
|
|
|
|
if(oldParent == parent)
|
2011-08-26 17:06:52 +02:00
|
|
|
return;
|
2011-08-20 22:30:41 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidgetPtr self = asUIWidget();
|
|
|
|
if(oldParent && oldParent->hasChild(self))
|
|
|
|
oldParent->removeChild(self);
|
2011-08-20 22:30:41 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// reset parent
|
|
|
|
m_parent.reset();
|
2011-08-26 17:06:52 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// set new parent
|
|
|
|
if(parent) {
|
|
|
|
m_parent = parent;
|
2011-08-26 17:06:52 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// add to parent if needed
|
|
|
|
if(!parent->hasChild(self))
|
|
|
|
parent->addChild(self);
|
|
|
|
}
|
2011-08-20 22:30:41 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setLayout(const UILayoutPtr& layout)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
if(m_layout)
|
|
|
|
m_layout->disableUpdates();
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
layout->setParent(asUIWidget());
|
|
|
|
layout->disableUpdates();
|
2011-08-22 21:13:52 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
|
|
|
if(m_layout)
|
|
|
|
m_layout->removeWidget(child);
|
|
|
|
layout->addWidget(child);
|
2011-08-22 21:13:52 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
if(m_layout) {
|
|
|
|
m_layout->enableUpdates();
|
|
|
|
m_layout->setParent(nullptr);
|
|
|
|
m_layout->update();
|
2011-08-22 21:13:52 +02:00
|
|
|
}
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
layout->enableUpdates();
|
|
|
|
m_layout = layout;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setRect(const Rect& rect)
|
2011-08-29 04:18:13 +02:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
// only update if the rect really changed
|
|
|
|
Rect oldRect = m_rect;
|
|
|
|
if(rect == oldRect)
|
|
|
|
return;
|
2011-08-29 04:18:13 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
m_rect = rect;
|
2011-08-29 04:18:13 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// updates own layout
|
|
|
|
updateLayout();
|
2011-08-29 04:18:13 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// avoid massive update events
|
|
|
|
if(!m_updateEventScheduled) {
|
|
|
|
UIWidgetPtr self = asUIWidget();
|
2012-03-14 19:45:15 +01:00
|
|
|
g_eventDispatcher.addEvent([self, oldRect]() {
|
2012-01-10 23:13:40 +01:00
|
|
|
self->m_updateEventScheduled = false;
|
|
|
|
if(oldRect != self->getRect())
|
|
|
|
self->onGeometryChange(oldRect, self->getRect());
|
|
|
|
});
|
|
|
|
m_updateEventScheduled = true;
|
|
|
|
}
|
2011-08-29 04:18:13 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setStyle(const std::string& styleName)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
OTMLNodePtr styleNode = g_ui.getStyle(styleName);
|
|
|
|
if(!styleNode) {
|
|
|
|
logTraceError("unable to retrive style '", styleName, "': not a defined style");
|
2011-08-22 21:13:52 +02:00
|
|
|
return;
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
|
|
|
applyStyle(styleNode);
|
|
|
|
m_style = styleNode;
|
|
|
|
updateStyle();
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setStyleFromNode(const OTMLNodePtr& styleNode)
|
2011-11-11 21:26:10 +01:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
applyStyle(styleNode);
|
|
|
|
m_style = styleNode;
|
|
|
|
updateStyle();
|
2011-11-11 21:26:10 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setEnabled(bool enabled)
|
2011-08-14 16:09:26 +02:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
if(enabled != m_enabled) {
|
|
|
|
m_enabled = enabled;
|
2011-08-26 17:06:52 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
updateState(Fw::DisabledState);
|
|
|
|
updateState(Fw::ActiveState);
|
2012-02-09 19:38:50 +01:00
|
|
|
updateState(Fw::HoverState);
|
2011-08-14 16:09:26 +02:00
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
2011-08-14 16:09:26 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setVisible(bool visible)
|
|
|
|
{
|
|
|
|
if(m_visible != visible) {
|
|
|
|
m_visible = visible;
|
2011-08-20 22:30:41 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// hiding a widget make it lose focus
|
|
|
|
if(!visible && isFocused()) {
|
|
|
|
if(UIWidgetPtr parent = getParent())
|
|
|
|
parent->focusPreviousChild(Fw::ActiveFocusReason);
|
|
|
|
}
|
2011-08-26 17:06:52 +02:00
|
|
|
|
2012-02-07 20:21:53 +01:00
|
|
|
// visibility can change change parent layout
|
2012-01-23 14:47:15 +01:00
|
|
|
updateParentLayout();
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
updateState(Fw::ActiveState);
|
2012-02-09 19:38:50 +01:00
|
|
|
|
|
|
|
// visibility can change the current hovered widget
|
|
|
|
if(visible)
|
|
|
|
g_ui.onWidgetAppear(asUIWidget());
|
|
|
|
else
|
|
|
|
g_ui.onWidgetDisappear(asUIWidget());
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
|
|
|
}
|
2011-08-14 16:09:26 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setOn(bool on)
|
|
|
|
{
|
|
|
|
setState(Fw::OnState, on);
|
|
|
|
}
|
2011-08-14 16:09:26 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setChecked(bool checked)
|
|
|
|
{
|
|
|
|
if(setState(Fw::CheckedState, checked))
|
|
|
|
callLuaField("onCheckChange", checked);
|
|
|
|
}
|
2011-08-20 22:30:41 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setFocusable(bool focusable)
|
|
|
|
{
|
|
|
|
if(m_focusable != focusable) {
|
|
|
|
m_focusable = focusable;
|
2011-08-22 21:13:52 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
// make parent focus another child
|
|
|
|
if(!focusable && isFocused()) {
|
|
|
|
if(UIWidgetPtr parent = getParent())
|
|
|
|
parent->focusPreviousChild(Fw::ActiveFocusReason);
|
2011-08-22 21:13:52 +02:00
|
|
|
}
|
2011-08-14 16:09:26 +02:00
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
2011-08-29 20:38:01 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setPhantom(bool phantom)
|
|
|
|
{
|
|
|
|
m_phantom = phantom;
|
|
|
|
}
|
2011-08-29 20:38:01 +02:00
|
|
|
|
2012-01-20 02:16:10 +01:00
|
|
|
void UIWidget::setDragable(bool dragable)
|
|
|
|
{
|
|
|
|
m_dragable = dragable;
|
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
void UIWidget::setFixedSize(bool fixed)
|
|
|
|
{
|
|
|
|
m_fixedSize = fixed;
|
|
|
|
updateParentLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::setLastFocusReason(Fw::FocusReason reason)
|
|
|
|
{
|
|
|
|
m_lastFocusReason = reason;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UIWidget::isVisible()
|
|
|
|
{
|
|
|
|
if(!m_visible)
|
|
|
|
return false;
|
|
|
|
else if(UIWidgetPtr parent = getParent())
|
|
|
|
return parent->isVisible();
|
|
|
|
else
|
|
|
|
return asUIWidget() == g_ui.getRootWidget();
|
2011-08-29 20:38:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool UIWidget::isChildLocked(const UIWidgetPtr& child)
|
|
|
|
{
|
|
|
|
auto it = std::find(m_lockedChildren.begin(), m_lockedChildren.end(), child);
|
|
|
|
return it != m_lockedChildren.end();
|
2011-08-14 16:09:26 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
bool UIWidget::hasChild(const UIWidgetPtr& child)
|
|
|
|
{
|
|
|
|
auto it = std::find(m_children.begin(), m_children.end(), child);
|
|
|
|
if(it != m_children.end())
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-11-11 21:26:10 +01:00
|
|
|
int UIWidget::getChildIndex(const UIWidgetPtr& child)
|
|
|
|
{
|
|
|
|
int index = 1;
|
|
|
|
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
|
|
|
|
if(*it == child)
|
|
|
|
return index;
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
Rect UIWidget::getChildrenRect()
|
|
|
|
{
|
|
|
|
Rect rect = m_rect;
|
|
|
|
rect.expand(-m_padding.top, -m_padding.right, -m_padding.bottom, -m_padding.left);
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
UIAnchorLayoutPtr UIWidget::getAnchoredLayout()
|
|
|
|
{
|
|
|
|
UIWidgetPtr parent = getParent();
|
2012-01-19 05:12:53 +01:00
|
|
|
if(!parent)
|
2012-01-10 23:13:40 +01:00
|
|
|
return nullptr;
|
|
|
|
|
2012-01-19 05:12:53 +01:00
|
|
|
return parent->getLayout()->asUIAnchorLayout();
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
UIWidgetPtr UIWidget::getRootParent()
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2011-08-26 17:06:52 +02:00
|
|
|
if(UIWidgetPtr parent = getParent())
|
2012-01-10 23:13:40 +01:00
|
|
|
return parent->getRootParent();
|
2011-08-26 17:06:52 +02:00
|
|
|
else
|
2012-01-10 23:13:40 +01:00
|
|
|
return asUIWidget();
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidgetPtr UIWidget::getChildAfter(const UIWidgetPtr& relativeChild)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
auto it = std::find(m_children.begin(), m_children.end(), relativeChild);
|
|
|
|
if(it != m_children.end() && ++it != m_children.end())
|
|
|
|
return *it;
|
|
|
|
return nullptr;
|
|
|
|
}
|
2012-01-08 23:32:55 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidgetPtr UIWidget::getChildBefore(const UIWidgetPtr& relativeChild)
|
|
|
|
{
|
|
|
|
auto it = std::find(m_children.rbegin(), m_children.rend(), relativeChild);
|
|
|
|
if(it != m_children.rend() && ++it != m_children.rend())
|
|
|
|
return *it;
|
|
|
|
return nullptr;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidgetPtr UIWidget::getChildById(const std::string& childId)
|
2012-01-02 23:49:34 +01:00
|
|
|
{
|
2012-01-10 23:13:40 +01:00
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
|
|
|
if(child->getId() == childId)
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
2012-01-06 20:25:27 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidgetPtr UIWidget::getChildByPos(const Point& childPos)
|
|
|
|
{
|
|
|
|
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
|
2012-02-06 20:19:47 +01:00
|
|
|
const UIWidgetPtr& child = (*it);
|
|
|
|
if(child->isExplicitlyVisible() && child->containsPoint(childPos))
|
|
|
|
return child;
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
UIWidgetPtr UIWidget::getChildByIndex(int index)
|
|
|
|
{
|
|
|
|
index = index <= 0 ? (m_children.size() + index) : index-1;
|
|
|
|
if(index >= 0 && (uint)index < m_children.size())
|
|
|
|
return m_children.at(index);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
UIWidgetPtr UIWidget::recursiveGetChildById(const std::string& id)
|
|
|
|
{
|
|
|
|
UIWidgetPtr widget = getChildById(id);
|
|
|
|
if(!widget) {
|
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
|
|
|
widget = child->recursiveGetChildById(id);
|
|
|
|
if(widget)
|
|
|
|
break;
|
2012-01-06 20:25:27 +01:00
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
|
|
|
return widget;
|
|
|
|
}
|
2012-01-06 20:25:27 +01:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos)
|
|
|
|
{
|
2012-02-06 20:19:47 +01:00
|
|
|
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
|
|
|
|
const UIWidgetPtr& child = (*it);
|
2012-01-24 19:39:16 +01:00
|
|
|
if(child->isExplicitlyVisible() && child->containsPoint(childPos)) {
|
2012-02-07 20:21:53 +01:00
|
|
|
UIWidgetPtr subChild = child->recursiveGetChildByPos(childPos);
|
|
|
|
if(subChild)
|
2012-01-10 23:13:40 +01:00
|
|
|
return subChild;
|
2012-01-24 19:39:16 +01:00
|
|
|
else if(!child->isPhantom())
|
|
|
|
return child;
|
2012-01-10 23:13:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2012-02-07 01:41:53 +01:00
|
|
|
UIWidgetList UIWidget::recursiveGetChildrenByPos(const Point& childPos)
|
|
|
|
{
|
|
|
|
UIWidgetList children;
|
|
|
|
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
|
|
|
|
const UIWidgetPtr& child = (*it);
|
|
|
|
if(child->isExplicitlyVisible() && child->containsPoint(childPos)) {
|
|
|
|
UIWidgetList subChildren = child->recursiveGetChildrenByPos(childPos);
|
|
|
|
if(!subChildren.empty())
|
|
|
|
children.insert(children.end(), subChildren.begin(), subChildren.end());
|
|
|
|
else if(!child->isPhantom())
|
|
|
|
children.push_back(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return children;
|
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
UIWidgetPtr UIWidget::backwardsGetWidgetById(const std::string& id)
|
|
|
|
{
|
|
|
|
UIWidgetPtr widget = getChildById(id);
|
|
|
|
if(!widget) {
|
|
|
|
if(UIWidgetPtr parent = getParent())
|
|
|
|
widget = parent->backwardsGetWidgetById(id);
|
2012-01-02 23:49:34 +01:00
|
|
|
}
|
2012-01-10 23:13:40 +01:00
|
|
|
return widget;
|
2012-01-02 23:49:34 +01:00
|
|
|
}
|
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
|
2011-11-16 18:03:11 +01:00
|
|
|
bool UIWidget::setState(Fw::WidgetState state, bool on)
|
2011-11-16 00:47:32 +01:00
|
|
|
{
|
|
|
|
if(state == Fw::InvalidState)
|
2011-11-16 18:03:11 +01:00
|
|
|
return false;
|
2011-11-16 00:47:32 +01:00
|
|
|
|
|
|
|
int oldStates = m_states;
|
|
|
|
if(on)
|
|
|
|
m_states |= state;
|
|
|
|
else
|
|
|
|
m_states &= ~state;
|
|
|
|
|
2011-11-16 18:03:11 +01:00
|
|
|
if(oldStates != m_states) {
|
2011-11-16 00:47:32 +01:00
|
|
|
updateStyle();
|
2011-11-16 18:03:11 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2011-11-16 00:47:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool UIWidget::hasState(Fw::WidgetState state)
|
|
|
|
{
|
|
|
|
if(state == Fw::InvalidState)
|
|
|
|
return false;
|
|
|
|
return (m_states & state);
|
|
|
|
}
|
|
|
|
|
2011-08-28 18:02:26 +02:00
|
|
|
void UIWidget::updateState(Fw::WidgetState state)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2011-08-26 17:06:52 +02:00
|
|
|
bool newStatus = true;
|
|
|
|
bool oldStatus = hasState(state);
|
|
|
|
bool updateChildren = false;
|
2011-08-14 04:09:11 +02:00
|
|
|
|
2012-01-02 23:49:34 +01:00
|
|
|
switch(state) {
|
|
|
|
case Fw::ActiveState: {
|
|
|
|
UIWidgetPtr widget = asUIWidget();
|
|
|
|
UIWidgetPtr parent;
|
|
|
|
do {
|
|
|
|
parent = widget->getParent();
|
|
|
|
if(!widget->isExplicitlyEnabled() ||
|
2012-01-06 09:48:59 +01:00
|
|
|
((parent && parent->getFocusedChild() != widget))) {
|
2012-01-02 23:49:34 +01:00
|
|
|
newStatus = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while(widget = parent);
|
|
|
|
|
2012-02-09 19:38:50 +01:00
|
|
|
updateChildren = newStatus != oldStatus;
|
2012-01-02 23:49:34 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Fw::FocusState: {
|
|
|
|
newStatus = (getParent() && getParent()->getFocusedChild() == asUIWidget());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Fw::HoverState: {
|
2012-02-09 19:38:50 +01:00
|
|
|
updateChildren = true;
|
|
|
|
newStatus = (g_ui.getHoveredWidget() == asUIWidget() && isEnabled());
|
2012-01-02 23:49:34 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Fw::PressedState: {
|
2012-02-07 20:21:53 +01:00
|
|
|
newStatus = (g_ui.getPressedWidget() == asUIWidget());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Fw::DraggingState: {
|
|
|
|
newStatus = (g_ui.getDraggingWidget() == asUIWidget());
|
2012-01-02 23:49:34 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Fw::DisabledState: {
|
|
|
|
bool enabled = true;
|
|
|
|
UIWidgetPtr widget = asUIWidget();
|
|
|
|
do {
|
|
|
|
if(!widget->isExplicitlyEnabled()) {
|
|
|
|
enabled = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while(widget = widget->getParent());
|
|
|
|
newStatus = !enabled;
|
2012-02-09 19:38:50 +01:00
|
|
|
updateChildren = newStatus != oldStatus;
|
2012-01-02 23:49:34 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Fw::FirstState: {
|
|
|
|
newStatus = (getParent() && getParent()->getFirstChild() == asUIWidget());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Fw::MiddleState: {
|
|
|
|
newStatus = (getParent() && getParent()->getFirstChild() != asUIWidget() && getParent()->getLastChild() != asUIWidget());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Fw::LastState: {
|
|
|
|
newStatus = (getParent() && getParent()->getLastChild() == asUIWidget());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Fw::AlternateState: {
|
|
|
|
newStatus = (getParent() && (getParent()->getChildIndex(asUIWidget()) % 2) == 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return;
|
2011-08-21 21:43:05 +02:00
|
|
|
}
|
|
|
|
|
2012-02-09 19:38:50 +01:00
|
|
|
if(updateChildren) {
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
for(const UIWidgetPtr& child : children)
|
|
|
|
child->updateState(state);
|
|
|
|
}
|
2012-02-07 20:21:53 +01:00
|
|
|
|
2012-02-09 19:38:50 +01:00
|
|
|
if(setState(state, newStatus)) {
|
2011-11-13 05:13:07 +01:00
|
|
|
if(state == Fw::FocusState) {
|
2012-03-14 19:45:15 +01:00
|
|
|
g_eventDispatcher.addEvent(std::bind(&UIWidget::onFocusChange, asUIWidget(), newStatus, m_lastFocusReason));
|
2011-11-13 05:13:07 +01:00
|
|
|
} else if(state == Fw::HoverState)
|
2012-03-14 19:45:15 +01:00
|
|
|
g_eventDispatcher.addEvent(std::bind(&UIWidget::onHoverChange, asUIWidget(), newStatus));
|
2011-08-26 17:06:52 +02:00
|
|
|
}
|
2011-08-21 21:43:05 +02:00
|
|
|
}
|
|
|
|
|
2011-08-26 17:06:52 +02:00
|
|
|
void UIWidget::updateStates()
|
2011-08-21 21:43:05 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-05 19:02:27 +01:00
|
|
|
for(int state = 1; state != Fw::LastWidgetState; state <<= 1)
|
2011-11-16 00:47:32 +01:00
|
|
|
updateState((Fw::WidgetState)state);
|
2011-08-21 21:43:05 +02:00
|
|
|
}
|
|
|
|
|
2012-01-02 23:49:34 +01:00
|
|
|
void UIWidget::updateChildrenIndexStates()
|
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-02 23:49:34 +01:00
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
|
|
|
child->updateState(Fw::FirstState);
|
|
|
|
child->updateState(Fw::MiddleState);
|
|
|
|
child->updateState(Fw::LastState);
|
|
|
|
child->updateState(Fw::AlternateState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-26 17:06:52 +02:00
|
|
|
void UIWidget::updateStyle()
|
2011-08-21 21:43:05 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2012-01-05 19:02:27 +01:00
|
|
|
if(m_loadingStyle && !m_updateStyleScheduled) {
|
|
|
|
UIWidgetPtr self = asUIWidget();
|
2012-03-14 19:45:15 +01:00
|
|
|
g_eventDispatcher.addEvent([self] {
|
2012-01-05 19:02:27 +01:00
|
|
|
self->m_updateStyleScheduled = false;
|
|
|
|
self->updateStyle();
|
|
|
|
});
|
|
|
|
m_updateStyleScheduled = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-08-26 17:06:52 +02:00
|
|
|
if(!m_style)
|
|
|
|
return;
|
2011-08-21 21:43:05 +02:00
|
|
|
|
2011-08-26 17:06:52 +02:00
|
|
|
OTMLNodePtr newStateStyle = OTMLNode::create();
|
2011-08-21 21:43:05 +02:00
|
|
|
|
2011-08-26 17:06:52 +02:00
|
|
|
// copy only the changed styles from default style
|
|
|
|
if(m_stateStyle) {
|
|
|
|
for(OTMLNodePtr node : m_stateStyle->children()) {
|
|
|
|
if(OTMLNodePtr otherNode = m_style->get(node->tag()))
|
|
|
|
newStateStyle->addChild(otherNode->clone());
|
2011-08-21 21:43:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-16 00:47:32 +01:00
|
|
|
// checks for states combination
|
|
|
|
for(const OTMLNodePtr& style : m_style->children()) {
|
|
|
|
if(boost::starts_with(style->tag(), "$")) {
|
|
|
|
std::string statesStr = style->tag().substr(1);
|
|
|
|
std::vector<std::string> statesSplit;
|
|
|
|
boost::split(statesSplit, statesStr, boost::is_any_of(std::string(" ")));
|
2011-08-21 21:43:05 +02:00
|
|
|
|
2011-11-16 00:47:32 +01:00
|
|
|
bool match = true;
|
|
|
|
for(std::string stateStr : statesSplit) {
|
|
|
|
if(stateStr.length() == 0)
|
|
|
|
continue;
|
2011-08-21 21:43:05 +02:00
|
|
|
|
2011-11-16 00:47:32 +01:00
|
|
|
bool notstate = (stateStr[0] == '!');
|
|
|
|
if(notstate)
|
|
|
|
stateStr = stateStr.substr(1);
|
2011-08-21 21:43:05 +02:00
|
|
|
|
2011-11-16 00:47:32 +01:00
|
|
|
bool stateOn = hasState(Fw::translateState(stateStr));
|
|
|
|
if((!notstate && !stateOn) || (notstate && stateOn))
|
|
|
|
match = false;
|
|
|
|
}
|
2011-08-23 03:08:36 +02:00
|
|
|
|
2011-11-16 00:47:32 +01:00
|
|
|
// merge states styles
|
2011-11-16 06:23:16 +01:00
|
|
|
if(match) {
|
2011-11-16 00:47:32 +01:00
|
|
|
newStateStyle->merge(style);
|
2011-11-16 06:23:16 +01:00
|
|
|
}
|
2011-11-16 00:47:32 +01:00
|
|
|
}
|
|
|
|
}
|
2011-08-21 21:43:05 +02:00
|
|
|
|
2011-11-16 22:00:40 +01:00
|
|
|
//TODO: prevent setting already set proprieties
|
|
|
|
|
2011-08-26 17:06:52 +02:00
|
|
|
applyStyle(newStateStyle);
|
|
|
|
m_stateStyle = newStateStyle;
|
2011-08-21 21:43:05 +02:00
|
|
|
}
|
|
|
|
|
2012-01-04 11:26:58 +01:00
|
|
|
void UIWidget::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
|
2011-08-22 21:13:52 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
if(m_destroyed)
|
|
|
|
return;
|
|
|
|
|
2011-08-26 17:06:52 +02:00
|
|
|
// first set id
|
|
|
|
if(const OTMLNodePtr& node = styleNode->get("id"))
|
|
|
|
setId(node->value());
|
2011-08-22 21:13:52 +02:00
|
|
|
|
2012-01-10 23:13:40 +01:00
|
|
|
parseBaseStyle(styleNode);
|
|
|
|
parseImageStyle(styleNode);
|
|
|
|
parseTextStyle(styleNode);
|
2011-08-22 21:13:52 +02:00
|
|
|
}
|
|
|
|
|
2012-01-05 03:42:17 +01:00
|
|
|
void UIWidget::onGeometryChange(const Rect& oldRect, const Rect& newRect)
|
2011-08-22 14:44:26 +02:00
|
|
|
{
|
2012-01-05 03:42:17 +01:00
|
|
|
callLuaField("onGeometryChange", oldRect, newRect);
|
2011-08-22 14:44:26 +02:00
|
|
|
}
|
|
|
|
|
2011-08-28 18:02:26 +02:00
|
|
|
void UIWidget::onFocusChange(bool focused, Fw::FocusReason reason)
|
2011-08-21 03:01:46 +02:00
|
|
|
{
|
2011-10-31 07:04:08 +01:00
|
|
|
callLuaField("onFocusChange", focused, reason);
|
2011-08-21 03:01:46 +02:00
|
|
|
}
|
|
|
|
|
2012-02-06 02:44:47 +01:00
|
|
|
void UIWidget::onChildFocusChange(const UIWidgetPtr& focusedChild, const UIWidgetPtr& unfocusedChild, Fw::FocusReason reason)
|
|
|
|
{
|
|
|
|
callLuaField("onChildFocusChange", focusedChild, unfocusedChild, reason);
|
|
|
|
}
|
|
|
|
|
2011-08-22 14:44:26 +02:00
|
|
|
void UIWidget::onHoverChange(bool hovered)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
2012-02-07 20:21:53 +01:00
|
|
|
callLuaField("onHoverChange", hovered);
|
2011-08-22 14:44:26 +02:00
|
|
|
}
|
|
|
|
|
2012-02-09 19:38:50 +01:00
|
|
|
bool UIWidget::onDragEnter(const Point& mousePos)
|
2012-01-20 02:16:10 +01:00
|
|
|
{
|
2012-02-09 19:38:50 +01:00
|
|
|
return callLuaField<bool>("onDragEnter", mousePos);
|
2012-01-20 02:16:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void UIWidget::onDragLeave(UIWidgetPtr droppedWidget, const Point& mousePos)
|
|
|
|
{
|
|
|
|
callLuaField("onDragLeave", droppedWidget, mousePos);
|
|
|
|
}
|
|
|
|
|
2012-02-07 01:41:53 +01:00
|
|
|
bool UIWidget::onDragMove(const Point& mousePos, const Point& mouseMoved)
|
|
|
|
{
|
|
|
|
return callLuaField("onDragMove", mousePos, mouseMoved);
|
|
|
|
}
|
|
|
|
|
2012-02-07 03:06:48 +01:00
|
|
|
bool UIWidget::onDrop(UIWidgetPtr draggedWidget, const Point& mousePos)
|
2012-01-20 02:16:10 +01:00
|
|
|
{
|
2012-02-07 03:06:48 +01:00
|
|
|
return callLuaField<bool>("onDrop", draggedWidget, mousePos);
|
2012-01-20 02:16:10 +01:00
|
|
|
}
|
|
|
|
|
2012-01-15 22:19:52 +01:00
|
|
|
bool UIWidget::onKeyText(const std::string& keyText)
|
2011-08-22 14:44:26 +02:00
|
|
|
{
|
2012-01-15 22:19:52 +01:00
|
|
|
return callLuaField<bool>("onKeyText", keyText);
|
2012-01-05 03:42:17 +01:00
|
|
|
}
|
|
|
|
|
2012-01-15 22:19:52 +01:00
|
|
|
bool UIWidget::onKeyDown(uchar keyCode, int keyboardModifiers)
|
2012-01-05 03:42:17 +01:00
|
|
|
{
|
2012-01-15 22:19:52 +01:00
|
|
|
return callLuaField<bool>("onKeyDown", keyCode, keyboardModifiers);
|
|
|
|
}
|
|
|
|
|
2012-02-06 13:53:28 +01:00
|
|
|
bool UIWidget::onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks)
|
2012-01-15 22:19:52 +01:00
|
|
|
{
|
2012-02-06 13:53:28 +01:00
|
|
|
return callLuaField<bool>("onKeyPress", keyCode, keyboardModifiers, autoRepeatTicks);
|
2012-01-15 22:19:52 +01:00
|
|
|
}
|
|
|
|
|
2012-01-17 07:24:58 +01:00
|
|
|
bool UIWidget::onKeyUp(uchar keyCode, int keyboardModifiers)
|
2012-01-15 22:19:52 +01:00
|
|
|
{
|
2012-01-17 07:24:58 +01:00
|
|
|
return callLuaField<bool>("onKeyUp", keyCode, keyboardModifiers);
|
2012-01-05 03:42:17 +01:00
|
|
|
}
|
2011-08-28 23:32:24 +02:00
|
|
|
|
2012-01-05 03:42:17 +01:00
|
|
|
bool UIWidget::onMousePress(const Point& mousePos, Fw::MouseButton button)
|
|
|
|
{
|
2012-02-03 06:25:01 +01:00
|
|
|
if(button == Fw::MouseLeftButton) {
|
|
|
|
if(m_clickTimer.running() && m_clickTimer.ticksElapsed() <= 500) {
|
2012-02-04 18:04:44 +01:00
|
|
|
if(onDoubleClick(mousePos))
|
2012-02-03 06:25:01 +01:00
|
|
|
return true;
|
|
|
|
m_clickTimer.stop();
|
|
|
|
} else
|
|
|
|
m_clickTimer.restart();
|
|
|
|
}
|
2012-02-07 05:55:20 +01:00
|
|
|
|
|
|
|
if(hasLuaField("onMousePress"))
|
|
|
|
return callLuaField<bool>("onMousePress", mousePos, button);
|
|
|
|
return true;
|
2012-01-05 03:42:17 +01:00
|
|
|
}
|
|
|
|
|
2012-01-24 19:39:16 +01:00
|
|
|
bool UIWidget::onMouseRelease(const Point& mousePos, Fw::MouseButton button)
|
2012-01-05 03:42:17 +01:00
|
|
|
{
|
2012-01-24 19:39:16 +01:00
|
|
|
return callLuaField<bool>("onMouseRelease", mousePos, button);
|
2012-01-05 03:42:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool UIWidget::onMouseMove(const Point& mousePos, const Point& mouseMoved)
|
|
|
|
{
|
|
|
|
return callLuaField<bool>("onMouseMove", mousePos, mouseMoved);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UIWidget::onMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction)
|
|
|
|
{
|
|
|
|
return callLuaField<bool>("onMouseWheel", mousePos, direction);
|
|
|
|
}
|
|
|
|
|
2012-02-06 02:44:47 +01:00
|
|
|
bool UIWidget::onClick(const Point& mousePos)
|
|
|
|
{
|
|
|
|
return callLuaField<bool>("onClick", mousePos);
|
|
|
|
}
|
|
|
|
|
2012-02-04 18:04:44 +01:00
|
|
|
bool UIWidget::onDoubleClick(const Point& mousePos)
|
2012-02-03 06:25:01 +01:00
|
|
|
{
|
2012-02-04 18:04:44 +01:00
|
|
|
return callLuaField<bool>("onDoubleClick", mousePos);
|
2012-02-03 06:25:01 +01:00
|
|
|
}
|
|
|
|
|
2012-01-15 22:19:52 +01:00
|
|
|
bool UIWidget::propagateOnKeyText(const std::string& keyText)
|
|
|
|
{
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
UIWidgetList children;
|
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
|
|
|
// events on hidden or disabled widgets are discarded
|
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// key events go only to containers or focused child
|
|
|
|
if(child->isFocused())
|
|
|
|
children.push_back(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
|
if(child->propagateOnKeyText(keyText))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return onKeyText(keyText);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UIWidget::propagateOnKeyDown(uchar keyCode, int keyboardModifiers)
|
|
|
|
{
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
UIWidgetList children;
|
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
|
|
|
// events on hidden or disabled widgets are discarded
|
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// key events go only to containers or focused child
|
|
|
|
if(child->isFocused())
|
|
|
|
children.push_back(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
|
if(child->propagateOnKeyDown(keyCode, keyboardModifiers))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return onKeyDown(keyCode, keyboardModifiers);
|
|
|
|
}
|
|
|
|
|
2012-02-06 13:53:28 +01:00
|
|
|
bool UIWidget::propagateOnKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks)
|
2012-01-05 03:42:17 +01:00
|
|
|
{
|
2011-08-14 04:09:11 +02:00
|
|
|
// do a backup of children list, because it may change while looping it
|
2011-08-26 17:06:52 +02:00
|
|
|
UIWidgetList children;
|
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
2011-08-22 21:13:52 +02:00
|
|
|
// events on hidden or disabled widgets are discarded
|
2011-08-21 03:01:46 +02:00
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
2011-08-14 04:09:11 +02:00
|
|
|
continue;
|
2011-08-14 16:09:26 +02:00
|
|
|
|
2011-08-14 04:09:11 +02:00
|
|
|
// key events go only to containers or focused child
|
2011-08-26 17:06:52 +02:00
|
|
|
if(child->isFocused())
|
|
|
|
children.push_back(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
2012-02-06 13:53:28 +01:00
|
|
|
if(child->propagateOnKeyPress(keyCode, keyboardModifiers, autoRepeatTicks))
|
2011-08-26 17:06:52 +02:00
|
|
|
return true;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
2011-08-22 14:44:26 +02:00
|
|
|
|
2012-02-06 20:19:47 +01:00
|
|
|
if(autoRepeatTicks == 0 || autoRepeatTicks >= m_autoRepeatDelay)
|
2012-02-06 13:53:28 +01:00
|
|
|
return onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks);
|
2012-02-06 20:19:47 +01:00
|
|
|
else
|
2012-02-06 13:53:28 +01:00
|
|
|
return false;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-17 07:24:58 +01:00
|
|
|
bool UIWidget::propagateOnKeyUp(uchar keyCode, int keyboardModifiers)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
|
|
|
// do a backup of children list, because it may change while looping it
|
2011-08-26 17:06:52 +02:00
|
|
|
UIWidgetList children;
|
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
2011-08-22 21:13:52 +02:00
|
|
|
// events on hidden or disabled widgets are discarded
|
2011-08-21 03:01:46 +02:00
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
2011-08-14 04:09:11 +02:00
|
|
|
continue;
|
2011-08-14 16:09:26 +02:00
|
|
|
|
2011-08-26 17:06:52 +02:00
|
|
|
// key events go only to focused child
|
|
|
|
if(child->isFocused())
|
|
|
|
children.push_back(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
2012-01-17 07:24:58 +01:00
|
|
|
if(child->propagateOnKeyUp(keyCode, keyboardModifiers))
|
2011-08-26 17:06:52 +02:00
|
|
|
return true;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
2011-08-22 14:44:26 +02:00
|
|
|
|
2012-01-17 07:24:58 +01:00
|
|
|
return onKeyUp(keyCode, keyboardModifiers);
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-05 03:42:17 +01:00
|
|
|
bool UIWidget::propagateOnMousePress(const Point& mousePos, Fw::MouseButton button)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
|
|
|
// do a backup of children list, because it may change while looping it
|
2012-01-19 05:12:53 +01:00
|
|
|
UIWidgetPtr clickedChild;
|
2011-08-26 17:06:52 +02:00
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
2011-08-22 21:13:52 +02:00
|
|
|
// events on hidden or disabled widgets are discarded
|
2011-08-21 03:01:46 +02:00
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
2011-08-14 04:09:11 +02:00
|
|
|
continue;
|
|
|
|
|
2011-08-14 16:09:26 +02:00
|
|
|
// mouse press events only go to children that contains the mouse position
|
2012-01-19 05:12:53 +01:00
|
|
|
if(child->containsPoint(mousePos) && child == getChildByPos(mousePos)) {
|
|
|
|
clickedChild = child;
|
|
|
|
break;
|
|
|
|
}
|
2011-08-26 17:06:52 +02:00
|
|
|
}
|
2011-08-14 16:09:26 +02:00
|
|
|
|
2012-01-19 05:12:53 +01:00
|
|
|
if(clickedChild) {
|
|
|
|
// focusable child gains focus when clicked
|
|
|
|
if(clickedChild->isFocusable())
|
|
|
|
focusChild(clickedChild, Fw::MouseFocusReason);
|
2011-08-26 17:06:52 +02:00
|
|
|
|
2012-01-19 05:12:53 +01:00
|
|
|
// stop propagating if the child accept the event
|
|
|
|
if(clickedChild->propagateOnMousePress(mousePos, button))
|
2011-08-26 17:06:52 +02:00
|
|
|
return true;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
2011-08-22 14:44:26 +02:00
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
// only non phatom widgets receives mouse events
|
2012-02-07 20:21:53 +01:00
|
|
|
if(!isPhantom())
|
|
|
|
return onMousePress(mousePos, button);
|
2012-01-19 05:12:53 +01:00
|
|
|
|
|
|
|
return false;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-24 19:39:16 +01:00
|
|
|
bool UIWidget::propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
|
|
|
// do a backup of children list, because it may change while looping it
|
2012-02-07 20:21:53 +01:00
|
|
|
UIWidgetPtr clickedChild;
|
2011-08-26 17:06:52 +02:00
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
2011-08-22 21:13:52 +02:00
|
|
|
// events on hidden or disabled widgets are discarded
|
2012-02-07 20:21:53 +01:00
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
2011-08-14 04:09:11 +02:00
|
|
|
continue;
|
2011-08-14 16:09:26 +02:00
|
|
|
|
2012-02-07 20:21:53 +01:00
|
|
|
// mouse press events only go to children that contains the mouse position
|
|
|
|
if(child->containsPoint(mousePos) && child == getChildByPos(mousePos)) {
|
|
|
|
clickedChild = child;
|
|
|
|
break;
|
|
|
|
}
|
2011-08-26 17:06:52 +02:00
|
|
|
}
|
|
|
|
|
2012-02-07 20:21:53 +01:00
|
|
|
if(clickedChild) {
|
|
|
|
if(clickedChild->propagateOnMouseRelease(mousePos, button))
|
2012-01-24 19:39:16 +01:00
|
|
|
return true;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
2012-01-05 03:42:17 +01:00
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
// only non phatom widgets receives mouse events
|
2012-02-07 20:21:53 +01:00
|
|
|
if(!isPhantom())
|
2012-02-08 21:46:25 +01:00
|
|
|
return onMouseRelease(mousePos, button);
|
2012-01-24 19:39:16 +01:00
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
return false;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-05 03:42:17 +01:00
|
|
|
bool UIWidget::propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
|
|
|
// do a backup of children list, because it may change while looping it
|
2011-08-26 17:06:52 +02:00
|
|
|
UIWidgetList children;
|
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
2011-08-22 21:13:52 +02:00
|
|
|
// events on hidden or disabled widgets are discarded
|
2011-08-21 03:01:46 +02:00
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
2011-08-14 04:09:11 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// mouse move events go to all children
|
2011-08-26 17:06:52 +02:00
|
|
|
children.push_back(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
2012-01-05 03:42:17 +01:00
|
|
|
if(child->propagateOnMouseMove(mousePos, mouseMoved))
|
2011-08-22 14:44:26 +02:00
|
|
|
return true;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
2011-08-22 14:44:26 +02:00
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
return onMouseMove(mousePos, mouseMoved);
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
|
|
|
|
2012-01-05 03:42:17 +01:00
|
|
|
bool UIWidget::propagateOnMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction)
|
2011-08-14 04:09:11 +02:00
|
|
|
{
|
|
|
|
// do a backup of children list, because it may change while looping it
|
2011-08-26 17:06:52 +02:00
|
|
|
UIWidgetList children;
|
|
|
|
for(const UIWidgetPtr& child : m_children) {
|
2011-08-22 21:13:52 +02:00
|
|
|
// events on hidden or disabled widgets are discarded
|
2011-08-21 03:01:46 +02:00
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
2011-08-14 04:09:11 +02:00
|
|
|
continue;
|
2011-08-14 16:09:26 +02:00
|
|
|
|
2011-08-14 04:09:11 +02:00
|
|
|
// mouse wheel events only go to children that contains the mouse position
|
2012-01-02 23:09:49 +01:00
|
|
|
if(child->containsPoint(mousePos) && child == getChildByPos(mousePos))
|
2011-08-26 17:06:52 +02:00
|
|
|
children.push_back(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
2012-01-05 03:42:17 +01:00
|
|
|
if(child->propagateOnMouseWheel(mousePos, direction))
|
2011-08-26 17:06:52 +02:00
|
|
|
return true;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|
2011-08-22 14:44:26 +02:00
|
|
|
|
2012-02-05 23:42:35 +01:00
|
|
|
// only non phatom widgets receives mouse events
|
2012-01-05 03:42:17 +01:00
|
|
|
if(!isPhantom())
|
|
|
|
return onMouseWheel(mousePos, direction);
|
|
|
|
else
|
|
|
|
return false;
|
2011-08-14 04:09:11 +02:00
|
|
|
}
|