|
Last 3 elements: static text, list box and slider.
Static text is just element with text, nothing special. I add only
draw limit - for making animation like this
List box
Simple list box, add item, remove item, select one item, or multiple items.
class slGUIListBoxTextDrawCallback : public slGUIDrawTextCallback
{
friend class slGUIListBox;
slGUIListBox* m_lb = 0;
slGUIFont* m_defaultFont = 0;
slGUIFont* m_currFont = 0;
public:
slGUIListBoxTextDrawCallback();
virtual ~slGUIListBoxTextDrawCallback() {}
virtual slGUIFont* OnFont(uint32_t r, char32_t) override;
virtual slColor* OnColor(uint32_t r, char32_t) override;
};
struct slGUIListBoxItem
{
slString m_text;
uint32_t m_id = 0;
void* m_data = 0;
bool m_isSelected = false;
};
class slGUIListBox : public slGUIElement
{
slGUIListBoxTextDrawCallback m_listBoxTextDrawCallback;
slArray<slGUIListBoxItem*> m_items;
float m_lineHeight = 0.f;
size_t m_firstItemIndexForDraw = 0;
size_t m_numberOfVisibleLines = 0;
public:
slGUIListBox(slGUIWindow*, const slVec2f& position, const slVec2f& size);
virtual ~slGUIListBox();
virtual void Rebuild() final;
virtual void Update() final;
virtual void Draw(slGS* gs, float dt) final;
virtual void UpdateContentSize() final;
slGUIListBoxItem* AddItem(const char32_t*, uint32_t id, void* data);
void RemoveItem(slGUIListBoxItem*);
slArray<slGUIListBoxItem*>* GetItems() { return &m_items; }
bool m_drawItemBG = true;
bool m_multiSelect = false;
// return true if need to select
virtual bool OnSelect(slGUIListBoxItem*) { return true; }
// return true if need to deselect
virtual bool OnDeSelect(slGUIListBoxItem*) { return true; }
};
Implementation
slGUIListBox::slGUIListBox(slGUIWindow* w, const slVec2f& position, const slVec2f& size)
:
slGUIElement::slGUIElement(w, position, size)
{
m_flags |= slGUICommon::flag_wheelScroll;
m_listBoxTextDrawCallback.m_lb = this;
m_textDrawCallback = dynamic_cast<slGUIDrawTextCallback*>(&m_listBoxTextDrawCallback);
}
slGUIListBox::~slGUIListBox()
{
for (size_t i = 0; i < m_items.m_size; ++i)
{
slDestroy(m_items.m_data[i]);
}
}
void slGUIListBox::Rebuild()
{
slGUIElement::Rebuild();
m_lineHeight = 0.f;
const char32_t b[] = { U"X#$@WHM_" };
for (int i = 0; i < 9; ++i)
{
slGUIFont* font = m_textDrawCallback->OnFont(0, b[i]);
if (font->GetMaxSize().y > m_lineHeight)
m_lineHeight = (float)font->GetMaxSize().y;
}
m_numberOfVisibleLines = 0;
if (m_lineHeight && (m_buildRect.w - m_buildRect.y))
{
m_numberOfVisibleLines = (size_t)ceilf((m_buildRect.w - m_buildRect.y) / m_lineHeight);
}
}
void slGUIListBox::UpdateContentSize()
{
m_contentSize.x = m_baseRect.z - m_baseRect.x;
m_contentSize.y = 0.f;
if (m_items.m_size)
{
m_contentSize.y = (float)(m_items.m_size)*m_lineHeight;
// + when scroll to bottom there is must 1 line be visible
m_contentSize.y += (m_baseRect.w - m_baseRect.y) - m_lineHeight;
}
UpdateScrollLimit();
}
void slGUIListBox::Update()
{
slGUIElement::Update();
// find m_firstItemIndexForDraw, use only m_v_scroll
slVec2f pos;
pos.x = m_buildRect.x;
pos.y = m_buildRect.y - 0.f;
pos.y += (m_lineHeight * (float)m_firstItemIndexForDraw);
uint32_t itemsSize = m_items.m_size + m_numberOfVisibleLines;
if (pos.y < (m_buildRect.y - m_lineHeight - m_lineHeight))
{
float d = (m_buildRect.y - m_lineHeight - m_lineHeight) - pos.y;
int dd = (int)ceilf(d / m_lineHeight);
m_firstItemIndexForDraw += dd;
uint32_t lastIndex = itemsSize - m_items.m_size;
if (m_numberOfVisibleLines > lastIndex)
m_numberOfVisibleLines = lastIndex;
}
else if (pos.y > (m_buildRect.y - m_lineHeight - m_lineHeight))
{
if (m_firstItemIndexForDraw)
{
float d = pos.y - (m_buildRect.y - m_lineHeight - m_lineHeight);
int dd = (int)ceilf(d / m_lineHeight);
if ((size_t)dd < m_firstItemIndexForDraw)
m_firstItemIndexForDraw -= dd;
else
m_firstItemIndexForDraw = 0;
}
}
}
void slGUIListBox::Draw(slGS* gs, float dt)
{
if (IsEnabled())
{
gs->SetScissorRect(m_clipRect, 0);
if (IsDrawBG())
gs->DrawGUIRectangle(m_buildRect, m_style->m_staticTextBGColor, m_style->m_staticTextBGColor, 0, 0);
}
if (m_items.m_size)
{
uint32_t index = m_firstItemIndexForDraw;
slVec2f pos;
pos.x = m_buildRect.x;
pos.y = m_buildRect.y - m_scroll.y;
pos.y += (m_lineHeight * (float)index);
uint32_t itemsSize = m_items.m_size + m_numberOfVisibleLines;
if (pos.y < (m_baseRect.y - m_lineHeight - m_lineHeight))
{
++m_firstItemIndexForDraw;
uint32_t lastIndex = itemsSize - m_items.m_size;
if (m_numberOfVisibleLines > lastIndex)
m_numberOfVisibleLines = lastIndex;
}
else if (pos.y > (m_baseRect.y - m_lineHeight))
{
if (m_firstItemIndexForDraw)
--m_firstItemIndexForDraw;
}
for (uint32_t i = 0; i < m_numberOfVisibleLines + 4; ++i)
{
slVec4f r;
r.x = pos.x;
r.y = pos.y;
r.z = m_buildRect.z;
r.w = r.y + m_lineHeight;
slVec4f rClip = r;
if (rClip.y < m_clipRect.y)
rClip.y = m_clipRect.y;
if (m_drawItemBG)
{
slColor cc;
cc = m_style->m_listboxLine1BGColor;
if (index)
{
if ((index % 2) != 0)
cc = m_style->m_listboxLine2BGColor;
}
if (m_items.m_data[i]->m_isSelected)
cc = m_style->m_listboxSelectedLineBGColor;
gs->DrawGUIRectangle(r, cc, cc, 0, 0);
}
if (m_items.m_data[i]->m_text.size())
{
gs->DrawGUIText(
m_items.m_data[i]->m_text.c_str(),
m_items.m_data[i]->m_text.size(),
pos,
m_textDrawCallback);
}
if (slMath::pointInRect(slInput::GetData()->mousePosition, r))
{
if (slInput::IsLMBHit())
{
if (m_items.m_data[i]->m_isSelected)
{
if (OnDeSelect(m_items.m_data[i]))
{
m_items.m_data[i]->m_isSelected = false;
}
}
else
{
if (OnSelect(m_items.m_data[i]))
{
if (!m_multiSelect)
{
for (size_t i2 = 0; i2 < m_items.m_size; ++i2)
{
m_items.m_data[i2]->m_isSelected = false;
}
}
m_items.m_data[i]->m_isSelected = true;
}
}
}
}
pos.y = pos.y + m_lineHeight;
++index;
if (index >= itemsSize)
break;
}
}
}
slGUIListBoxItem* slGUIListBox::AddItem(const char32_t* t, uint32_t id, void* data)
{
slGUIListBoxItem* newItem = slCreate<slGUIListBoxItem>();
newItem->m_text = t;
newItem->m_data = data;
newItem->m_id = id;
m_items.push_back(newItem);
return newItem;
}
void slGUIListBox::RemoveItem(slGUIListBoxItem* it)
{
SL_ASSERT_ST(it);
m_items.erase_first(it);
slDestroy(it);
}
Slider
class slGUISlider : public slGUIElement
{
slGUISliderTextDrawCallback m_sliderTextDrawCallback;
float m_controlWidth = 10.f;
double m_valueFloat = 0.0;
uint32_t m_valueUint = 0;
int32_t m_valueInt = 0;
double m_valueMinFloat = 0.0;
double m_valueMaxFloat = 100.0;
uint32_t m_valueMinUint = 0;
uint32_t m_valueMaxUint = 100;
int32_t m_valueMinInt = -100;
int32_t m_valueMaxInt = 100;
slVec4f m_axisRect;
slVec4f m_axisRectFill;
float m_axisHeight = 5.f;
slVec4f m_controlRect;
bool m_isClicked = false;
float m_axisIndent = 15.f;
slString m_text;
void findAxisRectFill();
public:
slGUISlider(slGUIWindow*, const slVec2f& position, const slVec2f& size);
virtual ~slGUISlider();
virtual void Rebuild() final;
virtual void Update() final;
virtual void Draw(slGS* gs, float dt) final;
double* GetFloat() { return &m_valueFloat; }
uint32_t* GetUint() { return &m_valueUint; }
int32_t* GetInt() { return &m_valueInt; }
enum class ValueType
{
Float,
Uint,
Int
};
ValueType m_valueType = ValueType::Float;
void SetMinMaxFloat(double mn, double mx) { m_valueMinFloat = mn; m_valueMaxFloat = mx; }
void SetMinMaxUint(uint32_t mn, uint32_t mx) { m_valueMinUint = mn; m_valueMaxUint = mx; }
void SetMinMaxInt(int32_t mn, int32_t mx) { m_valueMinInt = mn; m_valueMaxInt = mx; }
bool m_drawText = true;
// will call m_text.pop_back(); number of times
uint32_t m_truncateFloatByThisNumOfChars = 10;
};
Code
slGUISlider::slGUISlider(slGUIWindow* w, const slVec2f& position, const slVec2f& size)
:
slGUIElement(w, position, size)
{
m_sliderTextDrawCallback.m_slider = this;
m_textDrawCallback = dynamic_cast<slGUIDrawTextCallback*>(&m_sliderTextDrawCallback);
SetDrawBG(false);
}
slGUISlider::~slGUISlider(){}
void slGUISlider::Update()
{
slGUIElement::Update();
if (m_window->GetRootElement()->m_scrollDelta.y)
Rebuild();
if (!m_isClicked)
{
if (slMath::pointInRect(slInput::GetData()->mousePosition, m_controlRect))
{
if (slInput::IsLMBHit())
m_isClicked = true;
}
}
else
{
if (slInput::IsKeyHit(slInput::KEY_ESCAPE))
m_isClicked = false;
else if (slInput::IsLMBRelease())
m_isClicked = false;
else
{
m_valueFloat += (double)slInput::GetData()->mouseMoveDelta.x;
m_valueInt += (int32_t)slInput::GetData()->mouseMoveDelta.x;
m_valueUint += (uint32_t)slInput::GetData()->mouseMoveDelta.x;
if (m_valueFloat < m_valueMinFloat) m_valueFloat = m_valueMinFloat;
if (m_valueFloat > m_valueMaxFloat) m_valueFloat = m_valueMaxFloat;
if (m_valueInt < m_valueMinInt) m_valueInt = m_valueMinInt;
if (m_valueInt > m_valueMaxInt) m_valueInt = m_valueMaxInt;
if (m_valueUint < m_valueMinUint) m_valueUint = m_valueMinUint;
if (m_valueUint > m_valueMaxUint) m_valueUint = m_valueMaxUint;
findAxisRectFill();
}
}
}
void slGUISlider::Rebuild()
{
slGUIElement::Rebuild();
auto H = m_buildRect.w - m_buildRect.y;
m_axisRect.x = m_buildRect.x + m_axisIndent;
m_axisRect.z = m_buildRect.z - m_axisIndent;
m_axisRect.y = m_buildRect.y + (H * 0.5f);
m_axisRect.y -= m_axisHeight * 0.5f;
m_axisRect.w = m_axisRect.y + m_axisHeight;
findAxisRectFill();
}
void slGUISlider::Draw(slGS* gs, float dt)
{
gs->SetScissorRect(m_clipRect, 0);
gs->DrawGUIRectangle(m_axisRect, m_style->m_sliderAxisEmtpyColor, m_style->m_sliderAxisEmtpyColor, 0, 0);
gs->DrawGUIRectangle(m_axisRectFill, m_style->m_sliderAxisFillColor, m_style->m_sliderAxisFillColor, 0, 0);
gs->DrawGUIRectangle(m_controlRect, m_style->m_sliderControlColor, m_style->m_sliderControlColor, 0, 0);
if (m_drawText)
{
slGUIElement* parent = dynamic_cast<slGUIElement*>(GetParent());
if (parent && m_text.size())
{
gs->SetScissorRect(parent->m_clipRect, 0);
slVec2f textPosition;
textPosition.x = m_buildRect.z;
textPosition.y = m_axisRect.y - m_axisHeight;
gs->DrawGUIText(
m_text.c_str(),
m_text.size(),
textPosition,
m_textDrawCallback);
}
}
}
void slGUISlider::findAxisRectFill()
{
m_axisRectFill = m_axisRect;
auto axisWidth = m_axisRect.z - m_axisRect.x;
float D = 0.f;
m_text.clear();
switch (m_valueType)
{
case slGUISlider::ValueType::Float:
{
m_text.append(m_valueFloat);
for (uint32_t i = 0; i < m_truncateFloatByThisNumOfChars; ++i)
{
m_text.pop_back();
}
double len = m_valueMaxFloat - m_valueMinFloat;
if (len != 0.0)
{
double M = 1.f / len;
double V = abs(m_valueMinFloat - m_valueFloat);
D = V * M;
}
}break;
case slGUISlider::ValueType::Uint:
{
m_text.append(m_valueUint);
uint32_t len = m_valueMaxUint - m_valueMinUint;
}break;
case slGUISlider::ValueType::Int:
{
m_text.append(m_valueInt);
int32_t len = m_valueMaxInt - m_valueMinInt;
}break;
}
m_axisRectFill.z = m_axisRectFill.x + (axisWidth * D);
m_controlRect.x = m_buildRect.x + m_axisIndent - (m_controlWidth *0.5f);
m_controlRect.y = m_buildRect.y;
m_controlRect.z = m_controlRect.x + m_controlWidth;
m_controlRect.w = m_buildRect.w;
m_controlRect.x += m_axisRectFill.z - m_axisRectFill.x;
m_controlRect.z += m_axisRectFill.z - m_axisRectFill.x;
}
Download
|
|