#include "Painter.h"
#include "Window.h"
#include "Widget.h"
#include <assert.h>
#define DEBUG_WIDGET 0
#if DEBUG_WIDGET
# include <stdio.h>
# include <typeinfo>
#endif
bool c_useRetina = true;
float c_retinaScale = 2.0f;
BEGIN_NAMESPACE
Widget::Widget(Object* a_parent, const char* a_name)
: Widget(ObjectPtrCast<Widget>(a_parent), a_name)
{
}
Widget::Widget(const char* a_name, bool a_root)
: BaseT(nullptr, a_name)
{
assert(a_root);
m_layoutDirection = LP_Horizontal;
m_windowX = m_windowY = 0;
m_watchingMouse = false;
m_delayDelete = false;
m_hasUnmanagedDescendant = false;
m_x = m_y = 0;
m_goalWidth = m_goalHeight = 1;
layoutMargin = 5;
layoutSpacing = 5;
backgroundBrush = 0xF0F0F0;
flags = WF_None;
scale = 1.0f;
m_combinedScale = 1.0f;
}
Widget::Widget(Widget* a_parent, const char* a_name, LayoutPolicy a_layoutDirection, int a_x, int a_y, int a_width, int a_height)
: BaseT(a_parent ? a_parent : new Window(a_name, true), a_name), m_layoutDirection(a_layoutDirection)
{
// TODO: when automatically creating a parent window when parent is 0, we need
// a way to automatically destroy things - currently destruction is not well tested.
// Need to try create and destroy a bunch of widgets and see if the windows can be removed.
// May require adding a flag to say if we automatically created the parent window or not.
// Or perhaps using shared_ptr and then if the window has no children it destroys itself?
layoutMargin = 5;
layoutSpacing = 5;
backgroundBrush = 0xF0F0F0;
m_windowX = m_windowY = 0;
m_watchingMouse = false;
m_delayDelete = false;
m_hasUnmanagedDescendant = false;
scale = 1.0f;
Widget* widgetParent = parent<Widget>();
m_combinedScale = (widgetParent) ? widgetParent->m_combinedScale : 1.0f;
connect(scale.valueChanged, this, &Widget::updateScale);
setGeometry(a_x, a_y, a_width, a_height);
flags = WF_None;
if (m_layoutDirection == LP_Unmanaged)
setParentHasUnmanagedChild();
}
Widget::~Widget()
{
}
void Widget::updateScale(float ignored)
{
Widget* widgetParent = parent<Widget>();
m_combinedScale = (widgetParent) ? scale.value() * widgetParent->m_combinedScale : scale.value();
std::list<Widget*> widgetChildren = children<Widget>();
for (Widget* child : widgetChildren)
{
child->updateScale(0.0f);
}
}
void Widget::setParentHasUnmanagedChild()
{
Widget* widgetParent = parent<Widget>();
if (widgetParent)
widgetParent->setParentHasUnmanagedChild();
m_hasUnmanagedDescendant = true;
}
void Widget::childAdded(Object* a_object)
{
Widget* widgetParent = parent<Widget>();
if (widgetParent)
widgetParent->updateLayout();
else
updateLayout();
repaint();
}
void Widget::updateLayout()
{
std::list<Widget*> widgetChildren = children<Widget>();
// recalculate layout
int childCount = (int)widgetChildren.size();
if (childCount)
{
SizeOptions childTotalSize;
Vector<SizeOptions> childSizes;
childSizes.resize(childCount);
memset(&childTotalSize, 0, sizeof(childTotalSize));
int i = 0;
for (std::list<Widget*>::const_iterator it = widgetChildren.begin(); it != widgetChildren.end(); ++it)
{
(*it)->scaledSizeOptions(childSizes[i]);
childTotalSize.m_minimum.m_width += childSizes[i].m_minimum.m_width;
childTotalSize.m_minimum.m_height += childSizes[i].m_minimum.m_height;
childTotalSize.m_preferred.m_width += childSizes[i].m_preferred.m_width;
childTotalSize.m_preferred.m_height += childSizes[i].m_preferred.m_height;
childTotalSize.m_maximum.m_width += childSizes[i].m_maximum.m_width;
childTotalSize.m_maximum.m_height += childSizes[i].m_maximum.m_height;
i++;
}
int x = 0, y = 0, wid = width(), heig = height();
int extraSpaceForMarginsAndSpacing = (childCount - 1) * layoutSpacing() + layoutMargin() * 2;
// TODO: refactor the horz/vert cases to one set of code as mostly the same
if (m_layoutDirection == LP_Horizontal)
{
// horz
if ( wid > childTotalSize.m_maximum.m_width )
{
// TODO: need to do padding horizontally
wid = childTotalSize.m_maximum.m_width;
}
if ( wid < childTotalSize.m_minimum.m_width )
{
// TODO: can't meet the constraint
wid = childTotalSize.m_minimum.m_width;
}
if ( wid < extraSpaceForMarginsAndSpacing )
{
// TODO: can't meet the constraint
wid = extraSpaceForMarginsAndSpacing;
}
int w = wid - extraSpaceForMarginsAndSpacing;
int h = heig - layoutMargin() * 2;
int remainder = w - childTotalSize.m_preferred.m_width;
Vector<int> proposedChildWidths;
Vector<bool> childWidthDone;
int childWidthDoneCount = 0;
proposedChildWidths.resize(childCount);
childWidthDone.resize(childCount);
for (int i = 0; i < childCount; i++)
{
proposedChildWidths[i] = childSizes[i].m_preferred.m_width;
childWidthDone[i] = false;
}
while (abs(remainder) > (childCount-childWidthDoneCount))
{
int distributedRemainder = remainder / (childCount-childWidthDoneCount);
for (int i = 0; i < childCount; i++)
{
if (!childWidthDone[i]) {
if (remainder < 0) {
if (proposedChildWidths[i] + distributedRemainder < childSizes[i].m_minimum.m_width)
{
proposedChildWidths[i] = childSizes[i].m_minimum.m_width;
childWidthDone[i] = true;
childWidthDoneCount++;
} else {
proposedChildWidths[i] += distributedRemainder;
}
} else {
if (proposedChildWidths[i] + distributedRemainder > childSizes[i].m_maximum.m_width)
{
proposedChildWidths[i] = childSizes[i].m_maximum.m_width;
childWidthDone[i] = true;
childWidthDoneCount++;
} else {
proposedChildWidths[i] += distributedRemainder;
}
}
}
}
int newTotalProposedWidth = 0;
for (int i = 0; i < childCount; i++)
newTotalProposedWidth += proposedChildWidths[i];
remainder = w - newTotalProposedWidth;
if (childWidthDoneCount >= childCount)
break;
}
int i = 0;
y = x = layoutMargin();
for (std::list<Widget*>::const_iterator it = widgetChildren.begin(); it != widgetChildren.end(); ++it, x += proposedChildWidths[i] + layoutSpacing(), i++)
(*it)->setGeometry(x, y, proposedChildWidths[i], h);
}
else // if (m_layoutDirection == LP_Vertical)
{
// vert
if ( heig > childTotalSize.m_maximum.m_height )
{
// TODO: need to do padding horizontally
heig = childTotalSize.m_maximum.m_height;
}
if ( heig < childTotalSize.m_minimum.m_height )
{
// TODO: can't meet the constraint
heig = childTotalSize.m_minimum.m_height;
}
if ( heig < extraSpaceForMarginsAndSpacing )
{
// TODO: can't meet the constraint
heig = extraSpaceForMarginsAndSpacing;
}
int h = heig - extraSpaceForMarginsAndSpacing;
int w = wid - layoutMargin() * 2;
int remainder = h - childTotalSize.m_preferred.m_height;
Vector<int> proposedChildHeight;
Vector<bool> childHeightDone;
int childHeightDoneCount = 0;
proposedChildHeight.resize(childCount);
childHeightDone.resize(childCount);
for (int i = 0; i < childCount; i++)
{
proposedChildHeight[i] = childSizes[i].m_preferred.m_height;
childHeightDone[i] = false;
}
while (abs(remainder) > (childCount-childHeightDoneCount))
{
int distributedRemainder = remainder / (childCount-childHeightDoneCount);
for (int i = 0; i < childCount; i++)
{
if (!childHeightDone[i]) {
if (remainder < 0) {
if (proposedChildHeight[i] + distributedRemainder < childSizes[i].m_minimum.m_height)
{
proposedChildHeight[i] = childSizes[i].m_minimum.m_height;
childHeightDone[i] = true;
childHeightDoneCount++;
} else {
proposedChildHeight[i] += distributedRemainder;
}
} else {
if (proposedChildHeight[i] + distributedRemainder > childSizes[i].m_maximum.m_height)
{
proposedChildHeight[i] = childSizes[i].m_maximum.m_height;
childHeightDone[i] = true;
childHeightDoneCount++;
} else {
proposedChildHeight[i] += distributedRemainder;
}
}
}
}
int newTotalProposedHeight = 0;
for (int i = 0; i < childCount; i++)
newTotalProposedHeight += proposedChildHeight[i];
remainder = h - newTotalProposedHeight;
if (childHeightDoneCount >= childCount)
break;
}
int i = 0;
y = x = layoutMargin();
for (std::list<Widget*>::const_iterator it = widgetChildren.begin(); it != widgetChildren.end(); ++it, y += proposedChildHeight[i] + layoutSpacing(), i++)
(*it)->setGeometry(x, y, w, proposedChildHeight[i]);
}
}
}
void Widget::sizeOptions(SizeOptions& a_sizeOptions)
{
a_sizeOptions.m_minimum.m_width = 0;
a_sizeOptions.m_minimum.m_height = 0;
a_sizeOptions.m_preferred.m_width = 256;
a_sizeOptions.m_preferred.m_height = 256;
a_sizeOptions.m_maximum.m_width = 65536;
a_sizeOptions.m_maximum.m_height = 65536;
//return;
std::list<Widget*> widgetChildren = children<Widget>();
int childCount = (int)widgetChildren.size();
if (!childCount)
{
// TODO
// Bottom level widgets that have no children ought to implement sizeOptions
return;
}
SizeOptions childSizes;
if (m_layoutDirection == LP_Horizontal)
{
// horiz
a_sizeOptions.m_minimum.m_height = 0;
a_sizeOptions.m_preferred.m_height = 0;
a_sizeOptions.m_maximum.m_height = 65536;
a_sizeOptions.m_minimum.m_width = 0;
a_sizeOptions.m_preferred.m_width = 0;
a_sizeOptions.m_maximum.m_width = 0;
for (std::list<Widget*>::const_iterator it = widgetChildren.begin(); it != widgetChildren.end(); ++it)
{
(*it)->scaledSizeOptions(childSizes);
a_sizeOptions.m_minimum.m_width += childSizes.m_minimum.m_width;
a_sizeOptions.m_preferred.m_width += childSizes.m_preferred.m_width;
a_sizeOptions.m_maximum.m_width += childSizes.m_maximum.m_width;
a_sizeOptions.m_minimum.m_height = std::max(a_sizeOptions.m_minimum.m_height, childSizes.m_minimum.m_height);
a_sizeOptions.m_preferred.m_height += childSizes.m_preferred.m_height;
a_sizeOptions.m_maximum.m_height = std::min(a_sizeOptions.m_maximum.m_height, childSizes.m_maximum.m_height);
}
a_sizeOptions.m_preferred.m_height /= childCount; // average of preferred heights
int extraSpaceForMarginsAndSpacing = layoutMargin() * 2;
a_sizeOptions.m_minimum.m_height += extraSpaceForMarginsAndSpacing;
a_sizeOptions.m_preferred.m_height += extraSpaceForMarginsAndSpacing;
a_sizeOptions.m_maximum.m_height += extraSpaceForMarginsAndSpacing;
extraSpaceForMarginsAndSpacing += (childCount - 1) * layoutSpacing();
a_sizeOptions.m_minimum.m_width += extraSpaceForMarginsAndSpacing;
a_sizeOptions.m_preferred.m_width += extraSpaceForMarginsAndSpacing;
a_sizeOptions.m_maximum.m_width += extraSpaceForMarginsAndSpacing;
}
else // if (m_layoutDirection == LP_Vertical)
{
// vert
a_sizeOptions.m_minimum.m_width = 0;
a_sizeOptions.m_preferred.m_width = 0;
a_sizeOptions.m_maximum.m_width = 65536;
a_sizeOptions.m_minimum.m_height = 0;
a_sizeOptions.m_preferred.m_height = 0;
a_sizeOptions.m_maximum.m_height = 0;
for (std::list<Widget*>::const_iterator it = widgetChildren.begin(); it != widgetChildren.end(); ++it)
{
(*it)->scaledSizeOptions(childSizes);
a_sizeOptions.m_minimum.m_height += childSizes.m_minimum.m_height;
a_sizeOptions.m_preferred.m_height += childSizes.m_preferred.m_height;
a_sizeOptions.m_maximum.m_height += childSizes.m_maximum.m_height;
a_sizeOptions.m_minimum.m_width = std::max(a_sizeOptions.m_minimum.m_width, childSizes.m_minimum.m_width);
a_sizeOptions.m_preferred.m_width += childSizes.m_preferred.m_width;
a_sizeOptions.m_maximum.m_width = std::min(a_sizeOptions.m_maximum.m_width, childSizes.m_maximum.m_width);
}
a_sizeOptions.m_preferred.m_width /= childCount; // average of preferred heights
int extraSpaceForMarginsAndSpacing = layoutMargin() * 2;
a_sizeOptions.m_minimum.m_width += extraSpaceForMarginsAndSpacing;
a_sizeOptions.m_preferred.m_width += extraSpaceForMarginsAndSpacing;
a_sizeOptions.m_maximum.m_width += extraSpaceForMarginsAndSpacing;
extraSpaceForMarginsAndSpacing += (childCount - 1) * layoutSpacing();
a_sizeOptions.m_minimum.m_height += extraSpaceForMarginsAndSpacing;
a_sizeOptions.m_preferred.m_height += extraSpaceForMarginsAndSpacing;
a_sizeOptions.m_maximum.m_height += extraSpaceForMarginsAndSpacing;
}
// ensure min is less than max and clamp the preferred to the min and max
if ( a_sizeOptions.m_maximum.m_height < a_sizeOptions.m_minimum.m_height )
a_sizeOptions.m_maximum.m_height = a_sizeOptions.m_minimum.m_height = (a_sizeOptions.m_maximum.m_height + a_sizeOptions.m_minimum.m_height) / 2;
if ( a_sizeOptions.m_maximum.m_width < a_sizeOptions.m_minimum.m_width )
a_sizeOptions.m_maximum.m_width = a_sizeOptions.m_minimum.m_width = (a_sizeOptions.m_maximum.m_width + a_sizeOptions.m_minimum.m_width) / 2;
if ( a_sizeOptions.m_preferred.m_height < a_sizeOptions.m_minimum.m_height )
a_sizeOptions.m_preferred.m_height = a_sizeOptions.m_minimum.m_height;
if ( a_sizeOptions.m_preferred.m_width < a_sizeOptions.m_minimum.m_width )
a_sizeOptions.m_preferred.m_width = a_sizeOptions.m_minimum.m_width;
if ( a_sizeOptions.m_preferred.m_height > a_sizeOptions.m_maximum.m_height )
a_sizeOptions.m_preferred.m_height = a_sizeOptions.m_maximum.m_height;
if ( a_sizeOptions.m_preferred.m_width > a_sizeOptions.m_maximum.m_width )
a_sizeOptions.m_preferred.m_width = a_sizeOptions.m_maximum.m_width;
// We are the topLevel widget before the window widget
Widget* widgetParent = parent<Widget>();
if (widgetParent && !widgetParent->parent<Widget>())
{
Rectangle rect = widgetParent->rectangle();
a_sizeOptions.m_maximum = rect.m_size;
}
}
void Widget::setGeometry(int a_x, int a_y, int a_width, int a_height)
{
m_windowX = m_x = a_x;
m_windowY = m_y = a_y;
m_goalWidth = a_width;// / 2.0;// * m_combinedScale;// / 2.0;
m_goalHeight = a_height;// / 2.0;// * m_combinedScale;// / 2.0;
Widget* widgetParent = parent<Widget>();
if (widgetParent)
{
if (c_useRetina)
{
m_goalWidth *= 2;
m_goalHeight *= 2;
}
//m_goalWidth = (a_width / c_retinaScale) * 2.0;
//m_goalHeight = (a_height / c_retinaScale) * 2.0;
m_windowX = widgetParent->m_windowX + a_x;
m_windowY = widgetParent->m_windowY + a_y;
updateTarget(); // update target buffer
}
// TODO: if a child geometry changes, does that bubble up to the parent?
// If so, layout updates need to ascend up to the root parent, and then do a full re-layout all the way down
// TODO: also need to be careful. doing updateLayout will call setGeometry on widgets which will call updateLayout etc.
// Also in the constructor, it calls setGeometry and it also does this before the widget it added to the parent's children
// Adding a child widget causes a full re-layout from the root down
// TODO: setGeometry on the root (ie: window) should re-size the underlying window. possibly need a virtual function for this
updateLayout();
}
TimerId Widget::startTimer(int a_milliSeconds)
{
Widget* widgetParent = parent<Widget>();
if (widgetParent)
return widgetParent->startTimer(a_milliSeconds);
return 0;
}
void Widget::killTimer(TimerId a_timerId)
{
Widget* widgetParent = parent<Widget>();
if (widgetParent)
widgetParent->killTimer(a_timerId);
}
void Widget::eraseBackground(int i)
{
Painter p(this);
p.reset();
/*
p.setBrush(backgroundBrush());
#if DEBUG_WIDGET
printf("draw rect: %i %i %i %i\n", 0, 0, width(), height());
#endif
p.drawRectangle(0, 0, width(), height());
*/
}
int Widget::width()
{
if (c_useRetina)
return targetBuffer().m_width / 2;
return targetBuffer().m_width;// * 2;
}
int Widget::height()
{
if (c_useRetina)
return targetBuffer().m_height / 2;
return targetBuffer().m_height;// * 2;
}
void Widget::sizeEvent(SizeEvent& a_event)
{
}
void Widget::paintEvent(PaintEvent& a_event)
{
eraseBackground();
}
void Widget::glPaint()
{
}
void Widget::timerEvent(TimerEvent& a_event)
{
}
void Widget::keyEvent(KeyEvent& a_event)
{
}
void Widget::mouseEvent(MouseEvent& a_event)
{
}
void Widget::mouseEnterEvent(MouseEvent& a_event)
{
}
void Widget::mouseLeaveEvent(MouseEvent& a_event)
{
}
void Widget::wheelEvent(WheelEvent& a_event)
{
}
void Widget::updateTarget()
{
Widget* widgetParent = parent<Widget>();
/*
if (widgetParent)
{
PixelBuffer& parentTarget = widgetParent->targetBuffer();
m_goalWidth = clamp(m_goalWidth, 0, parentTarget.m_width);
m_goalHeight = clamp(m_goalHeight, 0, parentTarget.m_height);
if (parentTarget.m_isRetina)
{
m_target.m_width = clamp(parentTarget.m_width - m_x*2 - 1, 0, m_goalWidth);
m_target.m_height = clamp(parentTarget.m_height - m_y*2 - 1, 0, m_goalHeight);
}
else
{
m_target.m_width = clamp(parentTarget.m_width - m_x - 1, 0, m_goalWidth);
m_target.m_height = clamp(parentTarget.m_height - m_y - 1, 0, m_goalHeight);
}
}
*/
if (m_layoutDirection == LP_Unmanaged)
{
m_target.m_width = m_goalWidth; // FIXME: still needs to be clamped though
m_target.m_height = m_goalHeight; // ditto
//m_target.m_width = clamp(m_goalWidth, 0, m_target.m_width);
//m_target.m_height = clamp(m_goalHeight, 0, m_target.m_height);
}
else if (widgetParent)
{
PixelBuffer& parentTarget = widgetParent->targetBuffer();
m_target.m_width = clamp(parentTarget.m_width - m_x - 1, 0, m_goalWidth);
m_target.m_height = clamp(parentTarget.m_height - m_y - 1, 0, m_goalHeight);
// m_goalWidth = clamp(m_goalWidth, 0, parentTarget.m_width - m_x - 1);
// m_goalHeight = clamp(m_goalHeight, 0, parentTarget.m_height - m_y - 1);
//m_target.m_width = clamp(m_goalWidth, 0, parentTarget.m_width - m_x - 1);
//m_target.m_height = clamp(m_goalHeight, 0, parentTarget.m_height - m_y - 1);
}
int maxWidth = m_target.m_width - m_x - 1;
int maxHeight = m_target.m_height - m_y - 1;
if (widgetParent)
{
PixelBuffer& parentTarget = widgetParent->targetBuffer();
m_target.m_pixels = parentTarget.m_pixels + m_y * (parentTarget.m_strideBytes/4) + m_x;
m_target.m_strideBytes = parentTarget.m_strideBytes;
m_target.m_format = parentTarget.m_format;
m_target.m_isRetina = parentTarget.m_isRetina;
maxWidth = parentTarget.m_width - m_x - 1;
maxHeight = parentTarget.m_height - m_y - 1;
#if USE_RETINA
if (c_useRetina)
{
maxWidth = parentTarget.m_width - m_x*2 - 1;
maxHeight = parentTarget.m_height - m_y*2 - 1;
//m_target.m_pixels = parentTarget.m_pixels + int(m_y * c_retinaScale) * (parentTarget.m_strideBytes/4) + int(m_x * c_retinaScale);
m_target.m_pixels = parentTarget.m_pixels + int(m_y * 2.0) * (parentTarget.m_strideBytes/4) + int(m_x * 2.0);
}
#endif
}
else
{
m_target.m_isRetina = false;
m_target.m_pixels = m_target.m_pixels + m_y * (m_target.m_strideBytes/4) + m_x;
}
if (m_layoutDirection != LP_Unmanaged)
{
m_target.m_width = clamp(m_target.m_width, 0, maxWidth);
m_target.m_height = clamp(m_target.m_height, 0, maxHeight);
}
}
void Widget::repaint()
{
Rectangle rectangle = { { { 0, 0 } }, { { width(), height() } } };
update(rectangle);
}
void Widget::update(Rectangle& a_rectangle)
{
Widget* widgetParent = parent<Widget>();
if (widgetParent)
{
a_rectangle.m_x += m_x;
a_rectangle.m_y += m_y;
widgetParent->update(a_rectangle); // This recursively calculates m_windowX and m_windowY
// When this gets up to the top level widget it will be a window object with overloaded update function
}
}
void Widget::event(Event& a_event)
{
a_event.m_commonEvent.reject();
switch (a_event.m_type)
{
case Event::ET_TimerEvent:
timerEvent(a_event.m_timerEvent);
break;
case Event::ET_PaintEvent:
if (flags() == WF_EraseBackground)
eraseBackground();
paintEvent(a_event.m_paintEvent);
break;
case Event::ET_SizeEvent:
if (parent<Widget>())
updateTarget();
sizeEvent(a_event.m_sizeEvent);
break;
default:
break;
}
std::list<Widget*> widgetChildren = children<Widget>();
/*
// Code if not dealing with unmanaged layouts
for (std::list<Widget*>::const_iterator it = widgetChildren.begin(); it != widgetChildren.end(); ++it)
{
#if DEBUG_WIDGET
printf("event, child class: %s\n", typeid(*(*it)).name());
#endif
(*it)->event(a_event);
if (a_event.m_commonEvent.m_accepted)
return;
}
*/
// Code to deal with event propogation with unmanaged layouts
// The order depends on event type. paint events go dirst to managed, then the unmanaged
// layout widgets are drawn last. For input events, the managed widgets are processed first.
if (a_event.m_type == Event::ET_PaintEvent)
{
std::vector<Widget*> unmanagedWidgets;
for (std::list<Widget*>::const_iterator it = widgetChildren.begin(); it != widgetChildren.end(); ++it)
{
if ((*it)->m_hasUnmanagedDescendant)
{
unmanagedWidgets.push_back(*it);
}
else
{
(*it)->event(a_event);
if (a_event.m_commonEvent.m_accepted)
return;
}
}
for (Widget* w : unmanagedWidgets)
{
w->event(a_event);
if (a_event.m_commonEvent.m_accepted)
return;
}
}
else
{
std::vector<Widget*> managedWidgets;
for (std::list<Widget*>::const_iterator it = widgetChildren.begin(); it != widgetChildren.end(); ++it)
{
if ((*it)->m_hasUnmanagedDescendant)
{
(*it)->event(a_event);
if (a_event.m_commonEvent.m_accepted)
return;
}
else
{
managedWidgets.push_back(*it);
}
}
for (Widget* w : managedWidgets)
{
w->event(a_event);
if (a_event.m_commonEvent.m_accepted)
return;
}
}
bool mouseInside = false;
switch (a_event.m_type)
{
case Event::ET_MouseEvent:
mouseInside = ((a_event.m_mouseEvent.m_position.m_x > m_windowX)
&& (a_event.m_mouseEvent.m_position.m_y > m_windowY)
&& (a_event.m_mouseEvent.m_position.m_x < (m_windowX + width()))
&& (a_event.m_mouseEvent.m_position.m_y < (m_windowY + height())));
if (m_mouseEntered && !mouseInside)
{
mouseLeaveEvent(a_event.m_mouseEvent);
}
if (!m_mouseEntered && mouseInside)
{
mouseEnterEvent(a_event.m_mouseEvent);
}
m_mouseEntered = mouseInside;
if (mouseInside || m_watchingMouse )
{
MouseEvent pushEvent = a_event.m_mouseEvent;
a_event.m_mouseEvent.m_x = (pushEvent.m_x - m_windowX);
a_event.m_mouseEvent.m_y = (pushEvent.m_y - m_windowY);
a_event.m_mouseEvent.m_oldX = (pushEvent.m_oldX - m_windowX);
a_event.m_mouseEvent.m_oldY = (pushEvent.m_oldY - m_windowY);
//a_event.m_mouseEvent.m_x = (pushEvent.m_x - m_windowX) * c_retinaScale;
//a_event.m_mouseEvent.m_y = (pushEvent.m_y - m_windowY) * c_retinaScale;
//a_event.m_mouseEvent.m_oldX = (pushEvent.m_oldX - m_windowX) * c_retinaScale;
//a_event.m_mouseEvent.m_oldY = (pushEvent.m_oldY - m_windowY) * c_retinaScale;
//a_event.m_mouseEvent.m_x = (pushEvent.m_x * 2.0f / c_retinaScale) - m_windowX;
//a_event.m_mouseEvent.m_y = (pushEvent.m_y * 2.0f / c_retinaScale) - m_windowY;
//a_event.m_mouseEvent.m_oldX = (pushEvent.m_oldX * 2.0f / c_retinaScale) - m_windowX;
//a_event.m_mouseEvent.m_oldY = (pushEvent.m_oldY * 2.0f / c_retinaScale) - m_windowY;
if (!a_event.m_mouseEvent.m_oldButtons && a_event.m_mouseEvent.m_buttons)
m_watchingMouse = true;
if (!a_event.m_mouseEvent.m_buttons)
m_watchingMouse = false;
mouseEvent(a_event.m_mouseEvent);
a_event.m_mouseEvent = pushEvent; // pop
}
break;
case Event::ET_WheelEvent:
wheelEvent(a_event.m_wheelEvent);
break;
case Event::ET_KeyEvent:
keyEvent(a_event.m_keyEvent);
break;
default:
break;
}
if (!parent())
{
deleteDelayDeleteWidgets();
}
}
void Widget::delayDelete()
{
m_delayDelete = true;
}
void Widget::collectDelayDeleteWidgets(std::vector<Widget*>& a_widgetsToBeDeleted) const
{
std::list<Widget*> widgetChildren = children<Widget>();
for (std::list<Widget*>::const_iterator it = widgetChildren.begin(); it != widgetChildren.end(); ++it)
{
(*it)->collectDelayDeleteWidgets(a_widgetsToBeDeleted);
if ((*it)->m_delayDelete)
{
a_widgetsToBeDeleted.emplace_back(*it);
}
}
}
void Widget::deleteDelayDeleteWidgets()
{
std::vector<Widget*> widgetsToBeDeleted;
collectDelayDeleteWidgets(widgetsToBeDeleted);
for (auto w : widgetsToBeDeleted)
{
delete w;
}
}
void Widget::scaledSizeOptions(SizeOptions& a_sizeOptions)
{
sizeOptions(a_sizeOptions);
a_sizeOptions.m_minimum.m_width *= m_combinedScale;
a_sizeOptions.m_minimum.m_height *= m_combinedScale;
a_sizeOptions.m_preferred.m_width *= m_combinedScale;
a_sizeOptions.m_preferred.m_height *= m_combinedScale;
a_sizeOptions.m_maximum.m_width *= m_combinedScale;
a_sizeOptions.m_maximum.m_height *= m_combinedScale;
}
END_NAMESPACE