bool UIWidget::propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button) { // 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; // mouse release events go to all children children.push_back(child); } for(const UIWidgetPtr& child : children) { if(child->propagateOnMouseRelease(mousePos, button)) return true; } bool ret = onMouseRelease(mousePos, button); if(isPressed() && button == Fw::MouseLeftButton) setPressed(false); return ret; }
UIWidgetList UIWidget::recursiveGetChildren() { UIWidgetList children; for(const UIWidgetPtr& child : m_children) { UIWidgetList subChildren = child->recursiveGetChildren(); if(!subChildren.empty()) children.insert(children.end(), subChildren.begin(), subChildren.end()); children.push_back(child); } return children; }
bool UIWidget::propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved, UIWidgetList& widgetList) { for(auto it = m_children.begin(); it != m_children.end(); ++it) { const UIWidgetPtr& child = *it; if(child->isExplicitlyVisible() && child->isExplicitlyEnabled()) child->propagateOnMouseMove(mousePos, mouseMoved, widgetList); } widgetList.push_back(static_self_cast<UIWidget>()); return true; }
bool UIWidget::propagateOnKeyUp(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 focused child if(child->isFocused()) children.push_back(child); } for(const UIWidgetPtr& child : children) { if(child->propagateOnKeyUp(keyCode, keyboardModifiers)) return true; } return onKeyUp(keyCode, keyboardModifiers); }
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::propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved) { // 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; // mouse move events go to all children children.push_back(child); } for(const UIWidgetPtr& child : children) { if(child->propagateOnMouseMove(mousePos, mouseMoved)) return true; } if(!isPhantom()) return onMouseMove(mousePos, mouseMoved); else return false; }
bool UIWidget::propagateOnKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks) { // 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->propagateOnKeyPress(keyCode, keyboardModifiers, autoRepeatTicks)) return true; } if(autoRepeatTicks == 0 || autoRepeatTicks >= m_autoRepeatDelay) return onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks); else return false; }
UIWidgetList UIWidget::recursiveGetChildrenByMarginPos(const Point& childPos) { UIWidgetList children; if(!containsPaddingPoint(childPos)) return children; for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) { const UIWidgetPtr& child = (*it); if(child->isExplicitlyVisible() && child->containsMarginPoint(childPos)) { UIWidgetList subChildren = child->recursiveGetChildrenByMarginPos(childPos); if(!subChildren.empty()) children.insert(children.end(), subChildren.begin(), subChildren.end()); children.push_back(child); } } return children; }
bool UIWidget::propagateOnMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction) { // 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; // mouse wheel events only go to children that contains the mouse position if(child->containsPoint(mousePos) && child == getChildByPos(mousePos)) children.push_back(child); } for(const UIWidgetPtr& child : children) { if(child->propagateOnMouseWheel(mousePos, direction)) return true; } if(!isPhantom()) return onMouseWheel(mousePos, direction); else return false; }
bool UIWidget::propagateOnMouseEvent(const Point& mousePos, UIWidgetList& widgetList) { bool ret = false; if(containsPaddingPoint(mousePos)) { for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) { const UIWidgetPtr& child = *it; if(child->isExplicitlyEnabled() && child->isExplicitlyVisible() && child->containsPoint(mousePos)) { if(child->propagateOnMouseEvent(mousePos, widgetList)) { ret = true; break; } } } } widgetList.push_back(static_self_cast<UIWidget>()); if(!isPhantom()) ret = true; return ret; }
void UIManager::inputEvent(const InputEvent& event) { UIWidgetList widgetList; switch(event.type) { case Fw::KeyTextInputEvent: m_keyboardReceiver->propagateOnKeyText(event.keyText); break; case Fw::KeyDownInputEvent: m_keyboardReceiver->propagateOnKeyDown(event.keyCode, event.keyboardModifiers); break; case Fw::KeyPressInputEvent: m_keyboardReceiver->propagateOnKeyPress(event.keyCode, event.keyboardModifiers, event.autoRepeatTicks); break; case Fw::KeyUpInputEvent: m_keyboardReceiver->propagateOnKeyUp(event.keyCode, event.keyboardModifiers); break; case Fw::MousePressInputEvent: if(event.mouseButton == Fw::MouseLeftButton && m_mouseReceiver->isVisible()) { UIWidgetPtr pressedWidget = m_mouseReceiver->recursiveGetChildByPos(event.mousePos, false); if(pressedWidget && !pressedWidget->isEnabled()) pressedWidget = nullptr; updatePressedWidget(pressedWidget, event.mousePos); } m_mouseReceiver->propagateOnMouseEvent(event.mousePos, widgetList); for(const UIWidgetPtr& widget : widgetList) { widget->recursiveFocus(Fw::MouseFocusReason); if(widget->onMousePress(event.mousePos, event.mouseButton)) break; } break; case Fw::MouseReleaseInputEvent: { // release dragging widget bool accepted = false; if(m_draggingWidget && event.mouseButton == Fw::MouseLeftButton) accepted = updateDraggingWidget(nullptr, event.mousePos); if(!accepted) { m_mouseReceiver->propagateOnMouseEvent(event.mousePos, widgetList); // mouse release is always fired first on the pressed widget if(m_pressedWidget) { auto it = std::find(widgetList.begin(), widgetList.end(), m_pressedWidget); if(it != widgetList.end()) widgetList.erase(it); widgetList.push_front(m_pressedWidget); } for(const UIWidgetPtr& widget : widgetList) { if(widget->onMouseRelease(event.mousePos, event.mouseButton)) break; } } if(m_pressedWidget && event.mouseButton == Fw::MouseLeftButton) updatePressedWidget(nullptr, event.mousePos, !accepted); break; } case Fw::MouseMoveInputEvent: { // start dragging when moving a pressed widget if(m_pressedWidget && m_pressedWidget->isDraggable() && m_draggingWidget != m_pressedWidget) { // only drags when moving more than 4 pixels if((event.mousePos - m_pressedWidget->getLastClickPosition()).length() >= 4) updateDraggingWidget(m_pressedWidget, event.mousePos - event.mouseMoved); } // mouse move can change hovered widgets updateHoveredWidget(true); // first fire dragging move if(m_draggingWidget) { if(m_draggingWidget->onDragMove(event.mousePos, event.mouseMoved)) break; } m_mouseReceiver->propagateOnMouseMove(event.mousePos, event.mouseMoved, widgetList); for(const UIWidgetPtr& widget : widgetList) { if(widget->onMouseMove(event.mousePos, event.mouseMoved)) break; } break; } case Fw::MouseWheelInputEvent: m_rootWidget->propagateOnMouseEvent(event.mousePos, widgetList); for(const UIWidgetPtr& widget : widgetList) { if(widget->onMouseWheel(event.mousePos, event.wheelDirection)) break; } break; default: break; }; }
bool UIHorizontalLayout::internalUpdate() { UIWidgetPtr parentWidget = getParentWidget(); if(!parentWidget) return false; UIWidgetList widgets = parentWidget->getChildren(); if(m_alignRight) std::reverse(widgets.begin(), widgets.end()); bool changed = false; Rect paddingRect = parentWidget->getPaddingRect(); Point pos = (m_alignRight) ? paddingRect.topRight() : paddingRect.topLeft(); int preferredWidth = 0; int gap; for(const UIWidgetPtr& widget : widgets) { if(!widget->isExplicitlyVisible()) continue; Size size = widget->getSize(); gap = (m_alignRight) ? -(widget->getMarginRight()+widget->getWidth()) : widget->getMarginLeft(); pos.x += gap; preferredWidth += gap; if(widget->isFixedSize()) { if(widget->getTextAlign() & Fw::AlignTop) { pos.y = paddingRect.top() + widget->getMarginTop(); } else if(widget->getTextAlign() & Fw::AlignBottom) { pos.y = paddingRect.bottom() - widget->getHeight() - widget->getMarginBottom(); pos.y = std::max<int>(pos.y, paddingRect.top()); } else { // center it pos.y = paddingRect.top() + (paddingRect.height() - (widget->getMarginTop() + widget->getHeight() + widget->getMarginBottom()))/2; pos.y = std::max<int>(pos.y, paddingRect.top()); } } else { // expand height size.setHeight(paddingRect.height() - (widget->getMarginTop() + widget->getMarginBottom())); pos.y = paddingRect.top() + (paddingRect.height() - size.height())/2; } if(widget->setRect(Rect(pos - parentWidget->getVirtualOffset(), size))) changed = true; gap = (m_alignRight) ? -widget->getMarginLeft() : (widget->getWidth() + widget->getMarginRight()); gap += m_spacing; pos.x += gap; preferredWidth += gap; } preferredWidth -= m_spacing; preferredWidth += parentWidget->getPaddingLeft() + parentWidget->getPaddingRight(); if(m_fitChildren && preferredWidth != parentWidget->getWidth()) { // must set the preferred width later g_dispatcher.addEvent([=] { parentWidget->setWidth(preferredWidth); }); } return changed; }