123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /*
- Copyright (C) 2002-2013 Nikolaus Gebhardt
- This file is part of the "Irrlicht Engine".
- For conditions of distribution and use, see copyright notice in irrlicht.h
- Modified 2019.05.01 by stujones11, Stuart Jones <stujones111@gmail.com>
- This is a heavily modified copy of the Irrlicht CGUIScrollBar class
- which includes automatic scaling of the thumb slider and hiding of
- the arrow buttons where there is insufficient space.
- */
- #include "guiScrollBar.h"
- #include <IGUIButton.h>
- #include <IGUISkin.h>
- GUIScrollBar::GUIScrollBar(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
- core::rect<s32> rectangle, bool horizontal, bool auto_scale) :
- IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle),
- up_button(nullptr), down_button(nullptr), is_dragging(false),
- is_horizontal(horizontal), is_auto_scaling(auto_scale),
- dragged_by_slider(false), tray_clicked(false), scroll_pos(0),
- draw_center(0), thumb_size(0), min_pos(0), max_pos(100), small_step(10),
- large_step(50), drag_offset(0), page_size(100), border_size(0)
- {
- refreshControls();
- setNotClipped(false);
- setTabStop(true);
- setTabOrder(-1);
- setPos(0);
- }
- bool GUIScrollBar::OnEvent(const SEvent &event)
- {
- if (isEnabled()) {
- switch (event.EventType) {
- case EET_KEY_INPUT_EVENT:
- if (event.KeyInput.PressedDown) {
- const s32 old_pos = scroll_pos;
- bool absorb = true;
- switch (event.KeyInput.Key) {
- case KEY_LEFT:
- case KEY_UP:
- setPos(scroll_pos - small_step);
- break;
- case KEY_RIGHT:
- case KEY_DOWN:
- setPos(scroll_pos + small_step);
- break;
- case KEY_HOME:
- setPos(min_pos);
- break;
- case KEY_PRIOR:
- setPos(scroll_pos - large_step);
- break;
- case KEY_END:
- setPos(max_pos);
- break;
- case KEY_NEXT:
- setPos(scroll_pos + large_step);
- break;
- default:
- absorb = false;
- }
- if (scroll_pos != old_pos) {
- SEvent e;
- e.EventType = EET_GUI_EVENT;
- e.GUIEvent.Caller = this;
- e.GUIEvent.Element = nullptr;
- e.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
- Parent->OnEvent(e);
- }
- if (absorb)
- return true;
- }
- break;
- case EET_GUI_EVENT:
- if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED) {
- if (event.GUIEvent.Caller == up_button)
- setPos(scroll_pos - small_step);
- else if (event.GUIEvent.Caller == down_button)
- setPos(scroll_pos + small_step);
- SEvent e;
- e.EventType = EET_GUI_EVENT;
- e.GUIEvent.Caller = this;
- e.GUIEvent.Element = nullptr;
- e.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
- Parent->OnEvent(e);
- return true;
- } else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
- if (event.GUIEvent.Caller == this)
- is_dragging = false;
- break;
- case EET_MOUSE_INPUT_EVENT: {
- const core::position2di p(event.MouseInput.X, event.MouseInput.Y);
- bool is_inside = isPointInside(p);
- switch (event.MouseInput.Event) {
- case EMIE_MOUSE_WHEEL:
- if (Environment->hasFocus(this)) {
- s8 d = event.MouseInput.Wheel < 0 ? -1 : 1;
- s8 h = is_horizontal ? 1 : -1;
- setPos(getPos() + (d * small_step * h));
- SEvent e;
- e.EventType = EET_GUI_EVENT;
- e.GUIEvent.Caller = this;
- e.GUIEvent.Element = nullptr;
- e.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
- Parent->OnEvent(e);
- return true;
- }
- break;
- case EMIE_LMOUSE_PRESSED_DOWN: {
- if (is_inside) {
- is_dragging = true;
- dragged_by_slider = slider_rect.isPointInside(p);
- core::vector2di corner = slider_rect.UpperLeftCorner;
- drag_offset = is_horizontal ? p.X - corner.X : p.Y - corner.Y;
- tray_clicked = !dragged_by_slider;
- if (tray_clicked) {
- const s32 new_pos = getPosFromMousePos(p);
- const s32 old_pos = scroll_pos;
- setPos(new_pos);
- // drag in the middle
- drag_offset = thumb_size / 2;
- // report the scroll event
- if (scroll_pos != old_pos && Parent) {
- SEvent e;
- e.EventType = EET_GUI_EVENT;
- e.GUIEvent.Caller = this;
- e.GUIEvent.Element = nullptr;
- e.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
- Parent->OnEvent(e);
- }
- }
- Environment->setFocus(this);
- return true;
- }
- break;
- }
- case EMIE_LMOUSE_LEFT_UP:
- case EMIE_MOUSE_MOVED: {
- if (!event.MouseInput.isLeftPressed())
- is_dragging = false;
- if (!is_dragging) {
- if (event.MouseInput.Event == EMIE_MOUSE_MOVED)
- break;
- return is_inside;
- }
- if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
- is_dragging = false;
- // clang-format off
- if (!dragged_by_slider) {
- if (is_inside) {
- dragged_by_slider = slider_rect.isPointInside(p);
- tray_clicked = !dragged_by_slider;
- }
- if (!dragged_by_slider) {
- tray_clicked = false;
- if (event.MouseInput.Event == EMIE_MOUSE_MOVED)
- return is_inside;
- }
- }
- // clang-format on
- const s32 new_pos = getPosFromMousePos(p);
- const s32 old_pos = scroll_pos;
- setPos(new_pos);
- if (scroll_pos != old_pos && Parent) {
- SEvent e;
- e.EventType = EET_GUI_EVENT;
- e.GUIEvent.Caller = this;
- e.GUIEvent.Element = nullptr;
- e.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED;
- Parent->OnEvent(e);
- }
- return is_inside;
- }
- default:
- break;
- }
- } break;
- default:
- break;
- }
- }
- return IGUIElement::OnEvent(event);
- }
- void GUIScrollBar::draw()
- {
- if (!IsVisible)
- return;
- IGUISkin *skin = Environment->getSkin();
- if (!skin)
- return;
- video::SColor icon_color = skin->getColor(
- isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL);
- if (icon_color != current_icon_color)
- refreshControls();
- slider_rect = AbsoluteRect;
- skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR), slider_rect,
- &AbsoluteClippingRect);
- if (core::isnotzero(range())) {
- if (is_horizontal) {
- slider_rect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X +
- draw_center - thumb_size / 2;
- slider_rect.LowerRightCorner.X =
- slider_rect.UpperLeftCorner.X + thumb_size;
- } else {
- slider_rect.UpperLeftCorner.Y = AbsoluteRect.UpperLeftCorner.Y +
- draw_center - thumb_size / 2;
- slider_rect.LowerRightCorner.Y =
- slider_rect.UpperLeftCorner.Y + thumb_size;
- }
- skin->draw3DButtonPaneStandard(this, slider_rect, &AbsoluteClippingRect);
- }
- IGUIElement::draw();
- }
- void GUIScrollBar::updateAbsolutePosition()
- {
- IGUIElement::updateAbsolutePosition();
- refreshControls();
- setPos(scroll_pos);
- }
- s32 GUIScrollBar::getPosFromMousePos(const core::position2di &pos) const
- {
- s32 w, p;
- s32 offset = dragged_by_slider ? drag_offset : thumb_size / 2;
- if (is_horizontal) {
- w = RelativeRect.getWidth() - border_size * 2 - thumb_size;
- p = pos.X - AbsoluteRect.UpperLeftCorner.X - border_size - offset;
- } else {
- w = RelativeRect.getHeight() - border_size * 2 - thumb_size;
- p = pos.Y - AbsoluteRect.UpperLeftCorner.Y - border_size - offset;
- }
- return core::isnotzero(range()) ? s32(f32(p) / f32(w) * range() + 0.5f) + min_pos : 0;
- }
- void GUIScrollBar::setPos(const s32 &pos)
- {
- s32 thumb_area = 0;
- s32 thumb_min = 0;
- if (is_horizontal) {
- thumb_min = RelativeRect.getHeight();
- thumb_area = RelativeRect.getWidth() - border_size * 2;
- } else {
- thumb_min = RelativeRect.getWidth();
- thumb_area = RelativeRect.getHeight() - border_size * 2;
- }
- if (is_auto_scaling)
- thumb_size = s32(thumb_area /
- (f32(page_size) / f32(thumb_area + border_size * 2)));
- thumb_size = core::s32_clamp(thumb_size, thumb_min, thumb_area);
- scroll_pos = core::s32_clamp(pos, min_pos, max_pos);
- f32 f = core::isnotzero(range()) ? (f32(thumb_area) - f32(thumb_size)) / range()
- : 1.0f;
- draw_center = s32((f32(scroll_pos - min_pos) * f) + (f32(thumb_size) * 0.5f)) +
- border_size;
- }
- void GUIScrollBar::setSmallStep(const s32 &step)
- {
- small_step = step > 0 ? step : 10;
- }
- void GUIScrollBar::setLargeStep(const s32 &step)
- {
- large_step = step > 0 ? step : 50;
- }
- void GUIScrollBar::setMax(const s32 &max)
- {
- max_pos = max;
- if (min_pos > max_pos)
- min_pos = max_pos;
- bool enable = core::isnotzero(range());
- up_button->setEnabled(enable);
- down_button->setEnabled(enable);
- setPos(scroll_pos);
- }
- void GUIScrollBar::setMin(const s32 &min)
- {
- min_pos = min;
- if (max_pos < min_pos)
- max_pos = min_pos;
- bool enable = core::isnotzero(range());
- up_button->setEnabled(enable);
- down_button->setEnabled(enable);
- setPos(scroll_pos);
- }
- void GUIScrollBar::setPageSize(const s32 &size)
- {
- page_size = size;
- setPos(scroll_pos);
- }
- void GUIScrollBar::setArrowsVisible(ArrowVisibility visible)
- {
- arrow_visibility = visible;
- refreshControls();
- }
- s32 GUIScrollBar::getPos() const
- {
- return scroll_pos;
- }
- void GUIScrollBar::refreshControls()
- {
- IGUISkin *skin = Environment->getSkin();
- IGUISpriteBank *sprites = nullptr;
- current_icon_color = video::SColor(255, 255, 255, 255);
- if (skin) {
- sprites = skin->getSpriteBank();
- current_icon_color =
- skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL
- : EGDC_GRAY_WINDOW_SYMBOL);
- }
- if (is_horizontal) {
- s32 h = RelativeRect.getHeight();
- border_size = RelativeRect.getWidth() < h * 4 ? 0 : h;
- if (!up_button) {
- up_button = Environment->addButton(
- core::rect<s32>(0, 0, h, h), this);
- up_button->setSubElement(true);
- up_button->setTabStop(false);
- }
- if (sprites) {
- up_button->setSpriteBank(sprites);
- up_button->setSprite(EGBS_BUTTON_UP,
- s32(skin->getIcon(EGDI_CURSOR_LEFT)),
- current_icon_color);
- up_button->setSprite(EGBS_BUTTON_DOWN,
- s32(skin->getIcon(EGDI_CURSOR_LEFT)),
- current_icon_color);
- }
- up_button->setRelativePosition(core::rect<s32>(0, 0, h, h));
- up_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT,
- EGUIA_LOWERRIGHT);
- if (!down_button) {
- down_button = Environment->addButton(
- core::rect<s32>(RelativeRect.getWidth() - h, 0,
- RelativeRect.getWidth(), h),
- this);
- down_button->setSubElement(true);
- down_button->setTabStop(false);
- }
- if (sprites) {
- down_button->setSpriteBank(sprites);
- down_button->setSprite(EGBS_BUTTON_UP,
- s32(skin->getIcon(EGDI_CURSOR_RIGHT)),
- current_icon_color);
- down_button->setSprite(EGBS_BUTTON_DOWN,
- s32(skin->getIcon(EGDI_CURSOR_RIGHT)),
- current_icon_color);
- }
- down_button->setRelativePosition(
- core::rect<s32>(RelativeRect.getWidth() - h, 0,
- RelativeRect.getWidth(), h));
- down_button->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT,
- EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
- } else {
- s32 w = RelativeRect.getWidth();
- border_size = RelativeRect.getHeight() < w * 4 ? 0 : w;
- if (!up_button) {
- up_button = Environment->addButton(
- core::rect<s32>(0, 0, w, w), this);
- up_button->setSubElement(true);
- up_button->setTabStop(false);
- }
- if (sprites) {
- up_button->setSpriteBank(sprites);
- up_button->setSprite(EGBS_BUTTON_UP,
- s32(skin->getIcon(EGDI_CURSOR_UP)),
- current_icon_color);
- up_button->setSprite(EGBS_BUTTON_DOWN,
- s32(skin->getIcon(EGDI_CURSOR_UP)),
- current_icon_color);
- }
- up_button->setRelativePosition(core::rect<s32>(0, 0, w, w));
- up_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT,
- EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
- if (!down_button) {
- down_button = Environment->addButton(
- core::rect<s32>(0, RelativeRect.getHeight() - w,
- w, RelativeRect.getHeight()),
- this);
- down_button->setSubElement(true);
- down_button->setTabStop(false);
- }
- if (sprites) {
- down_button->setSpriteBank(sprites);
- down_button->setSprite(EGBS_BUTTON_UP,
- s32(skin->getIcon(EGDI_CURSOR_DOWN)),
- current_icon_color);
- down_button->setSprite(EGBS_BUTTON_DOWN,
- s32(skin->getIcon(EGDI_CURSOR_DOWN)),
- current_icon_color);
- }
- down_button->setRelativePosition(
- core::rect<s32>(0, RelativeRect.getHeight() - w, w,
- RelativeRect.getHeight()));
- down_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT,
- EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
- }
- bool visible;
- if (arrow_visibility == DEFAULT)
- visible = (border_size != 0);
- else if (arrow_visibility == HIDE) {
- visible = false;
- border_size = 0;
- } else {
- visible = true;
- if (is_horizontal)
- border_size = RelativeRect.getHeight();
- else
- border_size = RelativeRect.getWidth();
- }
- up_button->setVisible(visible);
- down_button->setVisible(visible);
- }
|