aboutsummaryrefslogtreecommitdiff
path: root/src/light.h
Commit message (Collapse)AuthorAge
* Update Copyright YearsSfan52013-02-24
|
* Change Minetest-c55 to MinetestPilzAdam2013-02-24
|
* Smooth day-night transitionsPerttu Ahola2012-12-02
|
* Optimize headersPerttu Ahola2012-06-17
|
* Switch the license to be LGPLv2/later, with small parts still remaining as ↵Perttu Ahola2012-06-05
| | | | GPLv2/later, by agreement of major contributors
* Node placement / mineral / serialization / iron freq / node_dig callbackKahrl2012-01-22
| | | | | | | | - Node placement code moved to Lua - Mineral system removed (added default:stone_with_coal and default:stone_with_iron). - MapBlock and MapNode serialization updated. - Mapgen: Frequency of iron increased. - node_dig callback and related changes.
* all kinds of tweaking and fixingPerttu Ahola2011-02-04
|
* minecraft-style water done (but no texture animation or sound)Perttu Ahola2011-01-17
|
* day/night working client sidePerttu Ahola2010-12-19
|
* before daynight mesh cachePerttu Ahola2010-12-18
|
* before adding day/night lightingPerttu Ahola2010-12-18
| | | | | --HG-- rename : data/light.png => data/cloud.png
* license stuffPerttu Ahola2010-11-29
| | | | | --HG-- rename : src/licensecomment.txt => licensecomment.txt
* Initial filesPerttu Ahola2010-11-27
f='#n214'>214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
/*
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), 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;
					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()) + 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);
}