Scrolling can have windows and elements.
What I need for this? I am not sure, but what I found out:
Element must have information about scrolling, 2D vector, because we can
scroll in vertical and horizontal directions,
and limit.
//I moved it from slGUIElement to slGUICommon
slVec2f m_scroll = 0.f;
slVec2f m_scrollLimit = 0.f;
If we don't have limit, we can scroll too much and elements will go out of window\element.
For calculating limit we need to know the size of element (build rect), and the size of
its children (not grandchildren)
// Size of element + all children (not grandchildren). It like AABB. find maximum x and y.
// Size of window with all elements.
// Use it for scrolling
slVec2f m_contentSize;
I think, content size should be found for every GUI element type in unique way,
but of course they have something common. I think I need to add new method in slGUICommon
void slGUIRootElement::UpdateContentSize()
{
slVec2f LB;
if (GetChildren()->m_head)
{
auto children = GetChildren();
if (children->m_head)
{
auto curr = children->m_head;
auto last = curr->m_left;
while (1)
{
slGUIElement* child = dynamic_cast<slGUIElement*>(curr->m_data);
if (child->m_baseRect.z > LB.x) LB.x = child->m_baseRect.z;
if (child->m_baseRect.w > LB.y) LB.y = child->m_baseRect.w;
if (curr == last)
break;
curr = curr->m_right;
}
}
}
m_contentSize.x = LB.x - m_baseRect.x;
m_contentSize.y = LB.y - m_baseRect.y;
slGUICommon::UpdateScrollLimit();
//printf("SIZE: %f %f\n", m_contentSize.x, m_contentSize.y);
//printf("LIMIT: %f %f\n", m_scrollLimit.x, m_scrollLimit.y);
}
Call this method when rebuild window
void _slGUIWindow_RebuildElement(slGUIElement* e)
{
e->Rebuild();
if (e->GetChildren()->m_head){
...
}
e->UpdateContentSize(); // here
}
Looks like everyting is ok. Now, I will put button below window,
and will try to use mouse wheel to scroll window
I needed to add
slVec4f m_baseRect;
into slGUICommon, now slGUIElement::Rebuild method will be use this object.
For scrolling I need to update m_buildRect every frame, and create it from m_baseRect
I moved code for m_buildRect m_clipRect m_activeRect into Update
And there is scrolling (vertical)
void slGUIElement::Update(slInputData* id)
{
slGUICommon::Update(id);
// maybe here callback
// OnRects(); or OnRebuild();
m_buildRect = m_baseRect;
// usuially m_clipRect is == m_baseRect;
m_clipRect = m_buildRect;
slGUIElement* parent = dynamic_cast<slGUIElement*>(GetParent());
if (parent)
{
m_buildRect.x -= parent->m_scroll.x;
m_buildRect.y -= parent->m_scroll.y;
m_buildRect.z -= parent->m_scroll.x;
m_buildRect.w -= parent->m_scroll.y;
m_clipRect = m_buildRect;
// but parent has own clip rect
if (m_clipRect.x < parent->m_clipRect.x)
m_clipRect.x = parent->m_clipRect.x;
if (m_clipRect.y < parent->m_clipRect.y)
m_clipRect.y = parent->m_clipRect.y;
if (m_clipRect.z > parent->m_clipRect.z)
m_clipRect.z = parent->m_clipRect.z;
if (m_clipRect.w > parent->m_clipRect.w)
m_clipRect.w = parent->m_clipRect.w;
}
m_activeRect = m_clipRect;
if (IsCursorInRect())
{
if (id->mouseWheelDelta < 0.f)
{
m_scrollTarget.y += 10.f;
if (m_scrollTarget.y > m_scrollLimit.y)
m_scrollTarget.y = m_scrollLimit.y;
}
else if (id->mouseWheelDelta > 0.f)
{
m_scrollTarget.y -= 10.f;
if (m_scrollTarget.y < 0.f)
m_scrollTarget.y = 0.f;
}
}
m_scroll.y = slMath::lerp1(m_scroll.y, m_scrollTarget.y, 0.1f);
Rebuild();
}
I am not sure about how it will work, especially if
in window add list box
Another thing to do is to add scrollbar. I don't want to do it now,
I want to finish this simple GUI.
Checkbox, radio button
It's almost like button. I need to add default icons.
What is icons? I think, its same with font, image and UV coordinates.
But, actually I can just use font...I need to create picture.
Now add new default font
slArray<slGUIFont*> m_defaultFonts; // now use this
add
enum class slGUIDefaultFont
{
Text,
Icons
};
change method
slGUIFont* slFramework::GetDefaultFont(const slGUIDefaultFont& t)
{
SL_ASSERT_ST(g_framework->m_defaultFonts.m_size);
switch (t)
{
case slGUIDefaultFont::Icons:
case slGUIDefaultFont::Text:
return g_framework->m_defaultFonts.m_data[(uint32_t)t];
default:
slLog::PrintWarning("%s : not implemented\n", SL_FUNCTION);
break;
}
return g_framework->m_defaultFonts.m_data[0];
}
Modify slFramework::InitDefaultFonts
void slFramework::InitDefaultFonts(slGS* gs)
{
static bool isInit = false;
if (!isInit)
{
auto getImage = [](uint8_t* buf, uint32_t sz)->slImage* {
for (uint32_t i = 0; i < slFramework::GetImageLoadersNum(); ++i)
{
auto il = slFramework::GetImageLoader(i);
for (uint32_t o = 0; o < il->GetSupportedFilesCount(); ++o)
{
auto str = il->GetSupportedFileExtension(o);
if (str == U"png")
{
return il->Load("something/file.png", buf, sz);
}
}
}
return 0;
};
auto getTexture = [gs](slImage* img)->slTexture* {
slTextureInfo ti;
slTexture* t = gs->SummonTexture(img, ti);
SLSAFE_DESTROY(img);
return t;
};
slImage* img = getImage(g_defaultFontPNG, 9065);
if (!img)
return;
slTexture* myFontTexture = getTexture(img);
if (!myFontTexture)
return;