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()
}
}