Browse Source

Add IGUIScrollbar implementation with variable bar sizes (#8507)

stujones11 4 years ago
parent
commit
b917ea4723

+ 1 - 0
build/android/jni/Android.mk

@@ -185,6 +185,7 @@ LOCAL_SRC_FILES := \
 		jni/src/gui/guiKeyChangeMenu.cpp          \
 		jni/src/gui/guiPasswordChange.cpp         \
 		jni/src/gui/guiPathSelectMenu.cpp         \
+		jni/src/gui/guiScrollBar.cpp              \
 		jni/src/gui/guiTable.cpp                  \
 		jni/src/gui/guiVolumeChange.cpp           \
 		jni/src/gui/intlGUIEditBox.cpp            \

+ 1 - 0
src/gui/CMakeLists.txt

@@ -7,6 +7,7 @@ set(gui_SRCS
 	${CMAKE_CURRENT_SOURCE_DIR}/guiKeyChangeMenu.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/guiPathSelectMenu.cpp
+	${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/intlGUIEditBox.cpp

+ 8 - 4
src/gui/guiEditBoxWithScrollbar.cpp

@@ -13,7 +13,6 @@
 #include "porting.h"
 #include "Keycodes.h"
 
-
 /*
 todo:
 optional scrollbars [done]
@@ -76,7 +75,8 @@ GUIEditBoxWithScrollBar::~GUIEditBoxWithScrollBar()
 	if (m_operator)
 		m_operator->drop();
 
-	m_vscrollbar->remove();
+	if (m_vscrollbar)
+		m_vscrollbar->drop();
 }
 
 
@@ -1400,7 +1400,9 @@ void GUIEditBoxWithScrollBar::createVScrollBar()
 
 	irr::core::rect<s32> scrollbarrect = m_frame_rect;
 	scrollbarrect.UpperLeftCorner.X += m_frame_rect.getWidth() - m_scrollbar_width;
-	m_vscrollbar = Environment->addScrollBar(false, scrollbarrect, getParent(), getID());
+	m_vscrollbar = new guiScrollBar(Environment, getParent(), -1,
+			scrollbarrect, false, true);
+
 	m_vscrollbar->setVisible(false);
 	m_vscrollbar->setSmallStep(1);
 	m_vscrollbar->setLargeStep(1);
@@ -1422,6 +1424,7 @@ void GUIEditBoxWithScrollBar::updateVScrollBar()
 		if (scrollymax != m_vscrollbar->getMax()) {
 			// manage a newline or a deleted line
 			m_vscrollbar->setMax(scrollymax);
+			m_vscrollbar->setPageSize(s32(getTextDimension().Height));
 			calculateScrollPos();
 		} else {
 			// manage a newline or a deleted line
@@ -1436,6 +1439,7 @@ void GUIEditBoxWithScrollBar::updateVScrollBar()
 		s32 scrollymax = getTextDimension().Height - m_frame_rect.getHeight();
 		if (scrollymax != m_vscrollbar->getMax()) {
 			m_vscrollbar->setMax(scrollymax);
+			m_vscrollbar->setPageSize(s32(getTextDimension().Height));
 		}
 
 		if (!m_vscrollbar->isVisible()) {
@@ -1448,10 +1452,10 @@ void GUIEditBoxWithScrollBar::updateVScrollBar()
 			m_vscroll_pos = 0;
 			m_vscrollbar->setPos(0);
 			m_vscrollbar->setMax(1);
+			m_vscrollbar->setPageSize(s32(getTextDimension().Height));
 		}
 	}
 
-
 }
 
 //! set true if this editbox is writable

+ 2 - 2
src/gui/guiEditBoxWithScrollbar.h

@@ -7,7 +7,7 @@
 
 #include "IGUIEditBox.h"
 #include "IOSOperator.h"
-#include "IGUIScrollBar.h"
+#include "guiScrollBar.h"
 #include <vector>
 
 using namespace irr;
@@ -187,7 +187,7 @@ protected:
 	core::rect<s32> m_current_text_rect, m_frame_rect; // temporary values
 
 	u32 m_scrollbar_width;
-	IGUIScrollBar *m_vscrollbar;
+	guiScrollBar *m_vscrollbar;
 	bool m_writable;
 
 	bool m_bg_color_used;

+ 442 - 0
src/gui/guiScrollBar.cpp

@@ -0,0 +1,442 @@
+/*
+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), desired_pos(0), last_change(0), 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;
+					desired_pos = getPosFromMousePos(p);
+					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;
+
+				if (dragged_by_slider)
+					setPos(new_pos);
+				else
+					desired_pos = 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::OnPostRender(u32 timeMs)
+{
+	if (is_dragging && !dragged_by_slider && tray_clicked &&
+			timeMs > last_change + 200) {
+		last_change = timeMs;
+		const s32 old_pos = scroll_pos;
+
+		if (desired_pos >= scroll_pos + large_step)
+			setPos(scroll_pos + large_step);
+		else if (desired_pos <= scroll_pos - large_step)
+			setPos(scroll_pos - large_step);
+		else if (desired_pos >= scroll_pos - large_step &&
+				desired_pos <= scroll_pos + large_step)
+			setPos(desired_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);
+		}
+	}
+}
+
+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()) + 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) * 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);
+}
+
+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 = (border_size != 0);
+	up_button->setVisible(visible);
+	down_button->setVisible(visible);
+}

+ 71 - 0
src/gui/guiScrollBar.h

@@ -0,0 +1,71 @@
+/*
+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.
+*/
+
+#pragma once
+
+#include "irrlichttypes_extrabloated.h"
+
+using namespace irr;
+using namespace gui;
+
+class guiScrollBar : public IGUIElement
+{
+public:
+	guiScrollBar(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
+			core::rect<s32> rectangle, bool horizontal, bool auto_scale);
+
+	virtual void draw();
+	virtual void updateAbsolutePosition();
+	virtual bool OnEvent(const SEvent &event);
+	virtual void OnPostRender(u32 timeMs);
+
+	s32 getMax() const { return max_pos; }
+	s32 getMin() const { return min_pos; }
+	s32 getLargeStep() const { return large_step; }
+	s32 getSmallStep() const { return small_step; }
+	s32 getPos() const;
+
+	void setMax(const s32 &max);
+	void setMin(const s32 &min);
+	void setSmallStep(const s32 &step);
+	void setLargeStep(const s32 &step);
+	void setPos(const s32 &pos);
+	void setPageSize(const s32 &size);
+
+private:
+	void refreshControls();
+	s32 getPosFromMousePos(const core::position2di &p) const;
+	f32 range() const { return f32(max_pos - min_pos); }
+
+	IGUIButton *up_button;
+	IGUIButton *down_button;
+	bool is_dragging;
+	bool is_horizontal;
+	bool is_auto_scaling;
+	bool dragged_by_slider;
+	bool tray_clicked;
+	s32 scroll_pos;
+	s32 draw_center;
+	s32 thumb_size;
+	s32 min_pos;
+	s32 max_pos;
+	s32 small_step;
+	s32 large_step;
+	s32 desired_pos;
+	u32 last_change;
+	s32 drag_offset;
+	s32 page_size;
+	s32 border_size;
+
+	core::rect<s32> slider_rect;
+	video::SColor current_icon_color;
+};

+ 5 - 4
src/gui/guiTable.cpp

@@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <cstring>
 #include <IGUISkin.h>
 #include <IGUIFont.h>
-#include <IGUIScrollBar.h>
 #include "client/renderingengine.h"
 #include "debug.h"
 #include "log.h"
@@ -62,12 +61,12 @@ GUITable::GUITable(gui::IGUIEnvironment *env,
 	}
 
 	const s32 s = skin->getSize(gui::EGDS_SCROLLBAR_SIZE);
-	m_scrollbar = Environment->addScrollBar(false,
+	m_scrollbar = new guiScrollBar(Environment, this, -1,
 			core::rect<s32>(RelativeRect.getWidth() - s,
 					0,
 					RelativeRect.getWidth(),
 					RelativeRect.getHeight()),
-			this, -1);
+			false, true);
 	m_scrollbar->setSubElement(true);
 	m_scrollbar->setTabStop(false);
 	m_scrollbar->setAlignment(gui::EGUIA_LOWERRIGHT, gui::EGUIA_LOWERRIGHT,
@@ -99,7 +98,8 @@ GUITable::~GUITable()
 	if (m_font)
 		m_font->drop();
 
-	m_scrollbar->remove();
+	if (m_scrollbar)
+		m_scrollbar->drop();
 }
 
 GUITable::Option GUITable::splitOption(const std::string &str)
@@ -1075,6 +1075,7 @@ void GUITable::updateScrollBar()
 	m_scrollbar->setMax(scrollmax);
 	m_scrollbar->setSmallStep(m_rowheight);
 	m_scrollbar->setLargeStep(2 * m_rowheight);
+	m_scrollbar->setPageSize(totalheight);
 }
 
 void GUITable::sendTableEvent(s32 column, bool doubleclick)

+ 2 - 1
src/gui/guiTable.h

@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <iostream>
 
 #include "irrlichttypes_extrabloated.h"
+#include "guiScrollBar.h"
 
 class ISimpleTextureSource;
 
@@ -198,7 +199,7 @@ protected:
 	video::SColor m_highlight_text = video::SColor(255, 255, 255, 255);
 	s32 m_rowheight = 1;
 	gui::IGUIFont *m_font = nullptr;
-	gui::IGUIScrollBar *m_scrollbar = nullptr;
+	guiScrollBar *m_scrollbar = nullptr;
 
 	// Allocated strings and images
 	std::vector<core::stringw> m_strings;

+ 9 - 1
src/gui/intlGUIEditBox.cpp

@@ -113,6 +113,9 @@ intlGUIEditBox::~intlGUIEditBox()
 
 	if (Operator)
 		Operator->drop();
+
+	if (m_vscrollbar)
+		m_vscrollbar->drop();
 }
 
 
@@ -1479,7 +1482,9 @@ void intlGUIEditBox::createVScrollBar()
 
 	irr::core::rect<s32> scrollbarrect = FrameRect;
 	scrollbarrect.UpperLeftCorner.X += FrameRect.getWidth() - m_scrollbar_width;
-	m_vscrollbar = Environment->addScrollBar(false, scrollbarrect, getParent(), getID());
+	m_vscrollbar = new guiScrollBar(Environment, getParent(), -1,
+			scrollbarrect, false, true);
+
 	m_vscrollbar->setVisible(false);
 	m_vscrollbar->setSmallStep(3 * fontHeight);
 	m_vscrollbar->setLargeStep(10 * fontHeight);
@@ -1501,6 +1506,7 @@ void intlGUIEditBox::updateVScrollBar()
 		if (scrollymax != m_vscrollbar->getMax()) {
 			// manage a newline or a deleted line
 			m_vscrollbar->setMax(scrollymax);
+			m_vscrollbar->setPageSize(s32(getTextDimension().Height));
 			calculateScrollPos();
 		} else {
 			// manage a newline or a deleted line
@@ -1513,6 +1519,7 @@ void intlGUIEditBox::updateVScrollBar()
 		s32 scrollymax = getTextDimension().Height - FrameRect.getHeight();
 		if (scrollymax != m_vscrollbar->getMax()) {
 			m_vscrollbar->setMax(scrollymax);
+			m_vscrollbar->setPageSize(s32(getTextDimension().Height));
 		}
 
 		if (!m_vscrollbar->isVisible() && MultiLine) {
@@ -1527,6 +1534,7 @@ void intlGUIEditBox::updateVScrollBar()
 			VScrollPos = 0;
 			m_vscrollbar->setPos(0);
 			m_vscrollbar->setMax(1);
+			m_vscrollbar->setPageSize(s32(getTextDimension().Height));
 			m_vscrollbar->setVisible(false);
 		}
 	}

+ 2 - 2
src/gui/intlGUIEditBox.h

@@ -10,7 +10,7 @@
 #include <IGUIEditBox.h>
 #include "irrArray.h"
 #include "IOSOperator.h"
-#include "IGUIScrollBar.h"
+#include "guiScrollBar.h"
 
 namespace irr
 {
@@ -198,7 +198,7 @@ namespace gui
 		core::rect<s32> CurrentTextRect = core::rect<s32>(0,0,1,1);
 		core::rect<s32> FrameRect; // temporary values
 		u32 m_scrollbar_width;
-		IGUIScrollBar *m_vscrollbar;
+		guiScrollBar *m_vscrollbar;
 		bool m_writable;
 
 	};