All elements has common thing, like area for clicking. I need
to create base class for them.
There must me method to set their parents.
I need to put elements somewhere.
Best solution is to create GUI window.
Window is a container. In future it will be easy to create for example tab control.
Window will have invisible `root` element, all elements in window
will be his children and grand children.
Base class for all GUI elements
class slGUIElement : public slUserData, public slHierarchy, public slGUICommon
{
protected:
slGUIWindow* m_window = 0;
public:
slGUIElement();
virtual ~slGUIElement();
slGUIWindow* GetWindow() { return m_window; }
slVec4f m_margin;
slVec2f m_scroll = 0.f;
slVec2f m_scrollLimit = 0.f;
enum Alignment
{
LeftTop,
Top,
RightTop,
Right,
RightBottom,
Bottom,
LeftBottom,
Left,
Center
};
Alignment m_alignment = Alignment::LeftTop;
virtual void OnMouseEnter();
virtual void OnMouseLeave();
virtual void OnClickLMB();
virtual void OnClickRMB();
virtual void OnClickMMB();
virtual void OnClickX1MB();
virtual void OnClickX2MB();
virtual void OnReleaseLMB();
virtual void OnReleaseRMB();
virtual void OnReleaseMMB();
virtual void OnReleaseX1MB();
virtual void OnReleaseX2MB();
// Make this element last for drawing, first for input.
// It will be like on top of all other elements.
// It's just changing the order.
virtual void ToTop();
};
It easy to create this class with one method SetParent.
If add something like AddChild it will add chaos in the code.
Better to call
object->SetParent(o);
Return to slGUIElement
I want to use C# WPF thing like margin (I saw it there).
When margin is (0,0,0,0) then all parent area will be filled by this element.
When window will be resized, it will be easy to recalculate all rectangles.
I not used this before. I think, and I hope, result will be very good, everything
will be fast, not much chaos in the code, easy to modify.
Updating GUI (detection all that mouse moves and other things)
will be in frameworks Update.
Need to update window by window.
Update from last window to first, because drawing will be from first to last,
and last window is top window. We want to click that window who on top.
void slFrameworkImpl::UpdateGUI()
{
if (m_GUIWindows.m_head)
{
// reset it here, it will set in Update if cursor in window rect
m_GUIState.m_windowUnderCursor = 0;
auto last = m_GUIWindows.m_head;
auto curr = last->m_left;
while (1)
{
if(curr->m_data->IsVisible() && !m_GUIState.m_windowUnderCursor)
{
curr->m_data->Update(&m_input);
}
if (curr == last)
break;
curr = curr->m_left;
}
}
}
Update window
void _slGUIWindow_UpdateElement(slInputData* in, slGUIElement* e)
{
e->Update(in);
if (e->GetChildren()->m_head)
{
auto children = e->GetChildren();
if (children->m_head)
{
auto curr = children->m_head;
auto last = curr->m_left;
while (1)
{
_slGUIWindow_UpdateElement(in, dynamic_cast<slGUIElement*>(curr->m_data));
if (curr == last)
break;
curr = curr->m_right;
}
}
}
}
void slGUIWindow::Update(slInputData* input)
{
if (slMath::pointInRect(input->mousePosition, m_activeRect))
{
g_framework->m_GUIState.m_windowUnderCursor = this;
_slGUIWindow_UpdateElement(input, m_rootElement);
}
}
void _slGUIWindow_DrawElement(slGS* gs, slGUIElement* e, float dt)
{
e->Draw(gs, dt);
if (e->GetChildren()->m_head)
{
auto children = e->GetChildren();
if (children->m_head)
{
auto curr = children->m_head;
auto last = curr->m_left;
while (1)
{
_slGUIWindow_DrawElement(gs, dynamic_cast<slGUIElement*>(curr->m_data), dt);
if (curr == last)
break;
curr = curr->m_right;
}
}
}
}
void slGUIWindow::Draw(slGS* gs, float dt)
{
gs->DrawGUIRectangle(m_buildRect, ColorWhite, ColorLime, 0, 0);
_slGUIWindow_DrawElement(gs, m_rootElement, dt);
}
In window draw its background (DrawGUIRectangle)
Rebuilding works in same way.
In framework add new method
void slFramework::DrawGUI(slGS* gs)
{
if (g_framework->m_GUIWindows.m_head)
{
auto last = g_framework->m_GUIWindows.m_head;
auto curr = last->m_left;
while (1)
{
if (curr->m_data->IsVisible())
{
curr->m_data->Draw(gs, g_framework->m_deltaTime);
}
if (curr == last)
break;
curr = curr->m_left;
}
}
}
Try to draw
auto guiWindow = slFramework::SummonGUIWindow();
guiWindow->SetPositionAndSize(slVec2f(100.f, 100.f), slVec2f(300.f));
slFramework::RebuildGUI();
...
// in main loop
slFramework::DrawGUI(app.m_gs);
Thats all. Window need a lot of things, I not wrote many of them.
I will finish it (maybe will add moving) and will start to adding buttons.