HomeForumSourceResearchGuide
Sign in to contribute to source. how it works
Component ui.ScrollBar by barry
expand copy to clipboardexpand
const int SCR_BUTTON_HEIGHT = 20
const int SCR_BUTTON_WIDTH = 20

const int SLIDER_MIN_HEIGHT = 20

const int WIDTH = 20

component provides ScrollBar requires io.Output out, data.IntUtil iu {
	
	int width = WIDTH
	int height
	
	Color scrollButtonColor = new Color(185, 185, 200, 255)
	Color scrollButtonLineColor = new Color(140, 140, 165, 255)
	Color scrollButtonArrowColor = new Color(100, 100, 135, 255)
	Color scrollBarColor = new Color(220, 220, 235, 255)
	Color scrollSliderColor = new Color(195, 195, 210, 255)

	int scroll

	int scrollAmount = 10
	int maxScroll = 0

	int sliderHeight = 0
	int sliderY = 0

	bool dragging = false
	int dragOffset = 0

	void updateScrollBarV(int max)
		{
		//update scroll bounds, and potentially position, assuming our content could have gotten larger or smaller since we last checked...
		
		if (max > 0)
			{
			maxScroll = max
			
			if (maxScroll > (height - (SCR_BUTTON_HEIGHT*2)))
				{
				sliderHeight = SLIDER_MIN_HEIGHT
				}
				else
				{
				sliderHeight = (height - (SCR_BUTTON_HEIGHT*2)) - maxScroll
				
				if (sliderHeight < SLIDER_MIN_HEIGHT) sliderHeight = SLIDER_MIN_HEIGHT
				}
			
			if (scroll > maxScroll)
				{
				scroll = maxScroll
				emitevent scrollMoved()
				}
			}
			else
			{
			sliderHeight = 0
			maxScroll = 0
			sliderY = 0
			scroll = 0
			
			emitevent scrollMoved()
			}
		}
	
	void ScrollBar:setMaxValue(int v)
		{
		updateScrollBarV(v)
		postRepaint()
		}

	void ScrollBar:setLength(int h)
		{
		height = h
		}
	
	void ScrollBar:setIncrement(int v)
		{
		if (v < maxScroll)
			{
			scrollAmount = v
			}
		}
	
	void ScrollBar:setScrollPos(int v)
		{
		if (v <= maxScroll)
			{
			scroll = v
			postRepaint()
			}
		}
	
	int ScrollBar:getScrollPos()
		{
		return scroll
		}

	void ScrollBar:setFocus()
		{
		//pass-through to content
		}

	bool ScrollBar:recvFocus()
		{
		//pass-through to content
		return false
		}

	void ScrollBar:loseFocus()
		{
		//pass-through to content
		}

	Rect ScrollBar:getBounds()
		{
		return new Rect(xPosition, yPosition, width, height)
		}

	void ScrollBar:mouseDown(int x, int y, int button)
		{
		//if on slider, enter dragging mode
		if (x >= width-SCR_BUTTON_WIDTH && x <= width)
			{
			if (y >= sliderY && y <= sliderY + sliderHeight)
				{
				//we track the click-down position relative to the edge of the slider, otherwise the slider's edge with jump to the mouse pointer
				dragging = true
				dragOffset = y - sliderY
				}
			}
		}

	void ScrollBar:mouseMove(int x, int y)
		{
		//if in dragging mode, move slider and update scroll view
		if (dragging)
			{
			int sliderMinY = SCR_BUTTON_HEIGHT
			int sliderMaxY = ((height) - (SCR_BUTTON_HEIGHT)) - sliderHeight

			int startScroll = scroll

			if (y > dragOffset)
				y = y - dragOffset
				else
				y = 0

			if (y < sliderMinY) y = sliderMinY
			if (y > sliderMaxY) y = sliderMaxY

			int sliderNewY = y

			int percent = (sliderNewY - SCR_BUTTON_HEIGHT) * 100 / ((height - (SCR_BUTTON_HEIGHT*2)) - sliderHeight)

			scroll = (percent * maxScroll) / 100

			if (scroll != startScroll)
				emitevent scrollMoved()
			
			postRepaint()
			}
		}
	
	void ScrollBar:mouseUp(int x, int y, int button)
		{
		dragging = false
		}
	
	void ScrollBar:click(int x, int y, int button)
		{
		//somewhere on the vertical scroll bar
		if (y >= 0 && y <= SCR_BUTTON_HEIGHT)
			{
			//scroll up button
			if (scroll > 0)
				{
				if (scroll < scrollAmount)
					scroll = 0
					else
					scroll -= scrollAmount
				
				emitevent scrollMoved()
				postRepaint()
				}
			}
			else if (y >= height - SCR_BUTTON_HEIGHT && y <= height)
			{
			//scroll down button
			if (scroll < maxScroll)
				{
				if (scroll + scrollAmount > maxScroll)
					scroll = maxScroll
					else
					scroll += scrollAmount
				
				emitevent scrollMoved()
				postRepaint()
				}
			}
			//only do this if the mouse position is not over the slider...
			else if ((y < sliderY || y > sliderY + sliderHeight) && (y > SCR_BUTTON_HEIGHT) && (y < height - SCR_BUTTON_HEIGHT))
			{
			//the scroll bar area - click-jump to this scroll position...
			// - we do this by calculating the percentage within the scroll bar, and converting to a percentage within the content
			int percent = (y - SCR_BUTTON_HEIGHT) * 100 / (height - (SCR_BUTTON_HEIGHT*2))

			scroll = (percent * maxScroll) / 100
			
			emitevent scrollMoved()
			postRepaint()
			}
		}
	
	void ScrollBar:postRepaint()
		{
		emitevent repaint()
		}
	
	void ScrollBar:paint(Canvas c)
		{
		//vertical scroll bar
		// - up button (rect)
		c.rect(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH), yPosition, SCR_BUTTON_WIDTH, SCR_BUTTON_HEIGHT, scrollButtonColor))
		c.rectOutline(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH), yPosition, SCR_BUTTON_WIDTH, SCR_BUTTON_HEIGHT, scrollButtonLineColor))
		// - up button (arrow)
		c.rect(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH) + 4, yPosition + SCR_BUTTON_HEIGHT - 8, SCR_BUTTON_WIDTH-8, 2, scrollButtonArrowColor))
		c.rect(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH) + 6, yPosition + SCR_BUTTON_HEIGHT - 12, SCR_BUTTON_WIDTH-12, 2, scrollButtonArrowColor))
		c.rect(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH) + 8, yPosition + SCR_BUTTON_HEIGHT - 16, SCR_BUTTON_WIDTH-16, 2, scrollButtonArrowColor))
		// - scroll slider pipe
		c.rect(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH), yPosition + SCR_BUTTON_HEIGHT, SCR_BUTTON_WIDTH, height-(SCR_BUTTON_HEIGHT*2), scrollBarColor))
		c.line(new Line2D(xPosition + (width-SCR_BUTTON_WIDTH), yPosition + SCR_BUTTON_HEIGHT, xPosition + (width-SCR_BUTTON_WIDTH), yPosition + (height-SCR_BUTTON_HEIGHT), scrollButtonLineColor))
		c.line(new Line2D(xPosition + (width-1), yPosition + SCR_BUTTON_HEIGHT, xPosition + (width-1), yPosition + (height-SCR_BUTTON_HEIGHT), scrollButtonLineColor))
		// - down button (rect)
		c.rect(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH), yPosition + (height-SCR_BUTTON_HEIGHT), SCR_BUTTON_WIDTH, SCR_BUTTON_HEIGHT, scrollButtonColor))
		c.rectOutline(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH), yPosition + (height-SCR_BUTTON_HEIGHT), SCR_BUTTON_WIDTH, SCR_BUTTON_HEIGHT, scrollButtonLineColor))
		// - down button (arrow)
		c.rect(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH) + 4, yPosition + (height-SCR_BUTTON_HEIGHT) + 6, SCR_BUTTON_WIDTH-8, 2, scrollButtonArrowColor))
		c.rect(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH) + 6, yPosition + (height-SCR_BUTTON_HEIGHT) + 10, SCR_BUTTON_WIDTH-12, 2, scrollButtonArrowColor))
		c.rect(new Rect2D(xPosition + (width-SCR_BUTTON_WIDTH) + 8, yPosition + (height-SCR_BUTTON_HEIGHT) + 14, SCR_BUTTON_WIDTH-16, 2, scrollButtonArrowColor))
		
		//slider - calculate position
		// - we do this by calculating the position of its top edge, as a percentage of (scroll slider pipe height - slider height)
		if (sliderHeight != 0)
			{
			int percent = scroll * 100 / maxScroll

			//calculate top-edge position
			int availableHeight = (height - ((SCR_BUTTON_HEIGHT*2))) - sliderHeight
			sliderY = ((percent * availableHeight) / 100) + SCR_BUTTON_HEIGHT

			c.rect(new Rect2D(xPosition + 1, yPosition + sliderY, WIDTH-2, sliderHeight, scrollSliderColor))
			}
		}
	
	void ScrollBar:setPosition(int x, int y)
		{
		xPosition = x
		yPosition = y
		}
	
	Point ScrollBar:getPosition()
		{
		return new Point(xPosition, yPosition)
		}

	WH ScrollBar:getPreferredSize()
		{
		return new WH(width, height)
		}
	
	void ScrollBar:setDisabled(bool d)
		{
		disabled = d
		postRepaint()
		}
	
	}
Revision history
To propose a new revision to this entity, use dana source put -uc your/new/version.dn -n ui.ScrollBar -m "reason for update" -u yourUsername
Version 1 (this version) by barry
Notes for this version: Standard Library Initialisation