mirror of https://github.com/liamg/aminal.git
520 lines
18 KiB
Go
520 lines
18 KiB
Go
package gui
|
|
|
|
import (
|
|
"github.com/go-gl/gl/all-core/gl"
|
|
"github.com/go-gl/glfw/v3.2/glfw"
|
|
)
|
|
|
|
const (
|
|
scrollbarVertexShaderSource = `
|
|
#version 330 core
|
|
layout (location = 0) in vec2 position;
|
|
uniform vec2 resolution;
|
|
|
|
void main() {
|
|
// convert from window coordinates to GL coordinates
|
|
vec2 glCoordinates = ((position / resolution) * 2.0 - 1.0) * vec2(1, -1);
|
|
|
|
gl_Position = vec4(glCoordinates, 0.0, 1.0);
|
|
}` + "\x00"
|
|
|
|
scrollbarFragmentShaderSource = `
|
|
#version 330 core
|
|
uniform vec4 inColor;
|
|
out vec4 outColor;
|
|
void main() {
|
|
outColor = inColor;
|
|
}` + "\x00"
|
|
|
|
NumberOfVertexValues = 100
|
|
)
|
|
|
|
var (
|
|
scrollbarColor_Bg = [3]float32{float32(241) / float32(255), float32(241) / float32(255), float32(241) / float32(255)}
|
|
scrollbarColor_ThumbNormal = [3]float32{float32(193) / float32(255), float32(193) / float32(255), float32(193) / float32(255)}
|
|
scrollbarColor_ThumbHover = [3]float32{float32(168) / float32(255), float32(168) / float32(255), float32(168) / float32(255)}
|
|
scrollbarColor_ThumbClicked = [3]float32{float32(120) / float32(255), float32(120) / float32(255), float32(120) / float32(255)}
|
|
|
|
scrollbarColor_ButtonNormalBg = [3]float32{float32(241) / float32(255), float32(241) / float32(255), float32(241) / float32(255)}
|
|
scrollbarColor_ButtonNormalFg = [3]float32{float32(80) / float32(255), float32(80) / float32(255), float32(80) / float32(255)}
|
|
|
|
scrollbarColor_ButtonHoverBg = [3]float32{float32(210) / float32(255), float32(210) / float32(255), float32(210) / float32(255)}
|
|
scrollbarColor_ButtonHoverFg = [3]float32{float32(80) / float32(255), float32(80) / float32(255), float32(80) / float32(255)}
|
|
|
|
scrollbarColor_ButtonDisabledBg = [3]float32{float32(241) / float32(255), float32(241) / float32(255), float32(241) / float32(255)}
|
|
scrollbarColor_ButtonDisabledFg = [3]float32{float32(163) / float32(255), float32(163) / float32(255), float32(163) / float32(255)}
|
|
|
|
scrollbarColor_ButtonClickedBg = [3]float32{float32(120) / float32(255), float32(120) / float32(255), float32(120) / float32(255)}
|
|
scrollbarColor_ButtonClickedFg = [3]float32{float32(255) / float32(255), float32(255) / float32(255), float32(255) / float32(255)}
|
|
)
|
|
|
|
type scrollbarPart int
|
|
|
|
const (
|
|
None scrollbarPart = iota
|
|
UpperArrow
|
|
UpperSpace // the space between upper arrow and thumb
|
|
Thumb
|
|
BottomSpace // the space between thumb and bottom arrow
|
|
BottomArrow
|
|
)
|
|
|
|
type ScreenRectangle struct {
|
|
left, top float32 // upper left corner in pixels relative to the window (in pixels)
|
|
right, bottom float32
|
|
}
|
|
|
|
func (sr *ScreenRectangle) width() float32 {
|
|
return sr.right - sr.left
|
|
}
|
|
|
|
func (sr *ScreenRectangle) height() float32 {
|
|
return sr.bottom - sr.top
|
|
}
|
|
|
|
func (sr *ScreenRectangle) isInside(x float32, y float32) bool {
|
|
return x >= sr.left && x < sr.right &&
|
|
y >= sr.top && y < sr.bottom
|
|
}
|
|
|
|
type scrollbar struct {
|
|
program uint32
|
|
vbo uint32
|
|
vao uint32
|
|
uniformLocationResolution int32
|
|
uniformLocationInColor int32
|
|
|
|
position ScreenRectangle // relative to the window's top left corner, in pixels
|
|
positionUpperArrow ScreenRectangle // relative to the control's top left corner
|
|
positionBottomArrow ScreenRectangle
|
|
positionThumb ScreenRectangle
|
|
|
|
scrollPosition int
|
|
maxScrollPosition int
|
|
|
|
thumbIsDragging bool
|
|
startedDraggingAtPosition int // scrollPosition when the dragging was started
|
|
startedDraggingAtThumbTop float32 // sb.positionThumb.top when the dragging was started
|
|
offsetInThumbY float32 // y offset inside the thumb of the dragging point
|
|
scrollPositionDelta int
|
|
|
|
upperArrowIsDown bool
|
|
bottomArrowIsDown bool
|
|
|
|
upperArrowFg []float32
|
|
upperArrowBg []float32
|
|
bottomArrowFg []float32
|
|
bottomArrowBg []float32
|
|
thumbColor []float32
|
|
}
|
|
|
|
// Returns the vertical scrollbar width in pixels
|
|
func getDefaultScrollbarWidth() int {
|
|
return 13
|
|
}
|
|
|
|
func createScrollbarProgram() (uint32, error) {
|
|
vertexShader, err := compileShader(scrollbarVertexShaderSource, gl.VERTEX_SHADER)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer gl.DeleteShader(vertexShader)
|
|
|
|
fragmentShader, err := compileShader(scrollbarFragmentShaderSource, gl.FRAGMENT_SHADER)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer gl.DeleteShader(fragmentShader)
|
|
|
|
prog := gl.CreateProgram()
|
|
gl.AttachShader(prog, vertexShader)
|
|
gl.AttachShader(prog, fragmentShader)
|
|
gl.LinkProgram(prog)
|
|
|
|
return prog, nil
|
|
}
|
|
|
|
func newScrollbar() (*scrollbar, error) {
|
|
prog, err := createScrollbarProgram()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var vbo uint32
|
|
var vao uint32
|
|
|
|
gl.GenBuffers(1, &vbo)
|
|
gl.GenVertexArrays(1, &vao)
|
|
|
|
gl.BindVertexArray(vao)
|
|
|
|
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
|
gl.BufferData(gl.ARRAY_BUFFER, NumberOfVertexValues*4, nil, gl.DYNAMIC_DRAW) // only reserve the space
|
|
|
|
gl.VertexAttribPointer(0, 2, gl.FLOAT, false, 2*4, nil)
|
|
gl.EnableVertexAttribArray(0)
|
|
|
|
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
|
|
gl.BindVertexArray(0)
|
|
|
|
result := &scrollbar{
|
|
program: prog,
|
|
vbo: vbo,
|
|
vao: vao,
|
|
uniformLocationResolution: gl.GetUniformLocation(prog, gl.Str("resolution\x00")),
|
|
uniformLocationInColor: gl.GetUniformLocation(prog, gl.Str("inColor\x00")),
|
|
|
|
position: ScreenRectangle{
|
|
right: 0,
|
|
bottom: 0,
|
|
left: 0,
|
|
top: 0,
|
|
},
|
|
|
|
scrollPosition: 0,
|
|
maxScrollPosition: 0,
|
|
|
|
thumbIsDragging: false,
|
|
upperArrowIsDown: false,
|
|
bottomArrowIsDown: false,
|
|
}
|
|
|
|
result.recalcElementPositions()
|
|
result.resetElementColors(-1, -1) // (-1, -1) ensures that no part is hovered by the mouse
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (sb *scrollbar) Free() {
|
|
if sb.program != 0 {
|
|
gl.DeleteProgram(sb.program)
|
|
sb.program = 0
|
|
}
|
|
|
|
if sb.vbo != 0 {
|
|
gl.DeleteBuffers(1, &sb.vbo)
|
|
sb.vbo = 0
|
|
}
|
|
|
|
if sb.vao != 0 {
|
|
gl.DeleteBuffers(1, &sb.vao)
|
|
sb.vao = 0
|
|
}
|
|
}
|
|
|
|
// Recalc positions of the scrollbar elements according to current
|
|
func (sb *scrollbar) recalcElementPositions() {
|
|
arrowHeight := sb.position.width()
|
|
|
|
sb.positionUpperArrow = ScreenRectangle{
|
|
left: 0,
|
|
top: 0,
|
|
right: sb.position.width(),
|
|
bottom: arrowHeight,
|
|
}
|
|
|
|
sb.positionBottomArrow = ScreenRectangle{
|
|
left: sb.positionUpperArrow.left,
|
|
top: sb.position.height() - arrowHeight,
|
|
right: sb.positionUpperArrow.right,
|
|
bottom: sb.position.height(),
|
|
}
|
|
thumbHeight := sb.position.width()
|
|
thumbTop := arrowHeight
|
|
if sb.maxScrollPosition != 0 {
|
|
thumbTop += (float32(sb.scrollPosition) * (sb.position.height() - thumbHeight - arrowHeight*2)) / float32(sb.maxScrollPosition)
|
|
}
|
|
|
|
sb.positionThumb = ScreenRectangle{
|
|
left: 2,
|
|
top: thumbTop,
|
|
right: sb.position.width() - 2,
|
|
bottom: thumbTop + thumbHeight,
|
|
}
|
|
}
|
|
|
|
func (sb *scrollbar) resize(gui *GUI) {
|
|
sb.position.left = float32(gui.width) - float32(getDefaultScrollbarWidth())*gui.dpiScale
|
|
sb.position.top = float32(0.0)
|
|
sb.position.right = float32(gui.width)
|
|
sb.position.bottom = float32(gui.height - 1)
|
|
|
|
sb.recalcElementPositions()
|
|
gui.terminal.NotifyDirty()
|
|
}
|
|
|
|
func (sb *scrollbar) render(gui *GUI) {
|
|
var savedProgram int32
|
|
gl.GetIntegerv(gl.CURRENT_PROGRAM, &savedProgram)
|
|
defer gl.UseProgram(uint32(savedProgram))
|
|
|
|
gl.UseProgram(sb.program)
|
|
gl.Uniform2f(sb.uniformLocationResolution, float32(gui.width), float32(gui.height))
|
|
gl.BindVertexArray(sb.vao)
|
|
gl.BindBuffer(gl.ARRAY_BUFFER, sb.vbo)
|
|
defer func() {
|
|
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
|
|
gl.BindVertexArray(0)
|
|
}()
|
|
|
|
// Draw background
|
|
gl.Uniform4f(sb.uniformLocationInColor, scrollbarColor_Bg[0], scrollbarColor_Bg[1], scrollbarColor_Bg[2], 1.0)
|
|
borderVertices := [...]float32{
|
|
sb.position.left, sb.position.top,
|
|
sb.position.right, sb.position.top,
|
|
sb.position.right, sb.position.bottom,
|
|
|
|
sb.position.right, sb.position.bottom,
|
|
sb.position.left, sb.position.bottom,
|
|
sb.position.left, sb.position.top,
|
|
}
|
|
gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(borderVertices)*4, gl.Ptr(&borderVertices[0]))
|
|
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(borderVertices)/2))
|
|
|
|
// Draw upper arrow
|
|
// Upper arrow background
|
|
gl.Uniform4f(sb.uniformLocationInColor, sb.upperArrowBg[0], sb.upperArrowBg[1], sb.upperArrowBg[2], 1.0)
|
|
upperArrowBgVertices := [...]float32{
|
|
sb.position.left + sb.positionUpperArrow.left, sb.position.top + sb.positionUpperArrow.top,
|
|
sb.position.left + sb.positionUpperArrow.right, sb.position.top + sb.positionUpperArrow.top,
|
|
sb.position.left + sb.positionUpperArrow.right, sb.position.top + sb.positionUpperArrow.bottom,
|
|
|
|
sb.position.left + sb.positionUpperArrow.right, sb.position.top + sb.positionUpperArrow.bottom,
|
|
sb.position.left + sb.positionUpperArrow.left, sb.position.top + sb.positionUpperArrow.bottom,
|
|
sb.position.left + sb.positionUpperArrow.left, sb.position.top + sb.positionUpperArrow.top,
|
|
}
|
|
gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(upperArrowBgVertices)*4, gl.Ptr(&upperArrowBgVertices[0]))
|
|
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(upperArrowBgVertices)/2))
|
|
|
|
// Upper arrow foreground
|
|
gl.Uniform4f(sb.uniformLocationInColor, sb.upperArrowFg[0], sb.upperArrowFg[1], sb.upperArrowFg[2], 1.0)
|
|
upperArrowFgVertices := [...]float32{
|
|
sb.position.left + sb.positionUpperArrow.left + sb.positionUpperArrow.width()/2.0, sb.position.top + sb.positionUpperArrow.top + sb.positionUpperArrow.height()/3.0,
|
|
sb.position.left + sb.positionUpperArrow.left + sb.positionUpperArrow.width()*2.0/3.0, sb.position.top + sb.positionUpperArrow.top + sb.positionUpperArrow.height()/2.0,
|
|
sb.position.left + sb.positionUpperArrow.left + sb.positionUpperArrow.width()/3.0, sb.position.top + sb.positionUpperArrow.top + sb.positionUpperArrow.height()/2.0,
|
|
}
|
|
gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(upperArrowFgVertices)*4, gl.Ptr(&upperArrowFgVertices[0]))
|
|
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(upperArrowFgVertices)/2))
|
|
|
|
// Draw bottom arrow
|
|
// Bottom arrow background
|
|
gl.Uniform4f(sb.uniformLocationInColor, sb.bottomArrowBg[0], sb.bottomArrowBg[1], sb.bottomArrowBg[2], 1.0)
|
|
bottomArrowBgVertices := [...]float32{
|
|
sb.position.left + sb.positionBottomArrow.left, sb.position.top + sb.positionBottomArrow.top,
|
|
sb.position.left + sb.positionBottomArrow.right, sb.position.top + sb.positionBottomArrow.top,
|
|
sb.position.left + sb.positionBottomArrow.right, sb.position.top + sb.positionBottomArrow.bottom,
|
|
|
|
sb.position.left + sb.positionBottomArrow.right, sb.position.top + sb.positionBottomArrow.bottom,
|
|
sb.position.left + sb.positionBottomArrow.left, sb.position.top + sb.positionBottomArrow.bottom,
|
|
sb.position.left + sb.positionBottomArrow.left, sb.position.top + sb.positionBottomArrow.top,
|
|
}
|
|
gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(bottomArrowBgVertices)*4, gl.Ptr(&bottomArrowBgVertices[0]))
|
|
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(bottomArrowBgVertices)/2))
|
|
|
|
// Bottom arrow foreground
|
|
gl.Uniform4f(sb.uniformLocationInColor, sb.bottomArrowFg[0], sb.bottomArrowFg[1], sb.bottomArrowFg[2], 1.0)
|
|
bottomArrowFgVertices := [...]float32{
|
|
sb.position.left + sb.positionBottomArrow.left + sb.positionBottomArrow.width()/3.0, sb.position.top + sb.positionBottomArrow.top + sb.positionBottomArrow.height()/2.0,
|
|
sb.position.left + sb.positionBottomArrow.left + sb.positionBottomArrow.width()*2.0/3.0, sb.position.top + sb.positionBottomArrow.top + sb.positionBottomArrow.height()/2.0,
|
|
sb.position.left + sb.positionBottomArrow.left + sb.positionBottomArrow.width()/2.0, sb.position.top + sb.positionBottomArrow.top + sb.positionBottomArrow.height()*2.0/3.0,
|
|
}
|
|
gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(bottomArrowFgVertices)*4, gl.Ptr(&bottomArrowFgVertices[0]))
|
|
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(bottomArrowFgVertices)/2))
|
|
|
|
// Draw thumb
|
|
gl.Uniform4f(sb.uniformLocationInColor, sb.thumbColor[0], sb.thumbColor[1], sb.thumbColor[2], 1.0)
|
|
thumbVertices := [...]float32{
|
|
sb.position.left + sb.positionThumb.left, sb.position.top + sb.positionThumb.top,
|
|
sb.position.left + sb.positionThumb.right, sb.position.top + sb.positionThumb.top,
|
|
sb.position.left + sb.positionThumb.right, sb.position.top + sb.positionThumb.bottom,
|
|
|
|
sb.position.left + sb.positionThumb.right, sb.position.top + sb.positionThumb.bottom,
|
|
sb.position.left + sb.positionThumb.left, sb.position.top + sb.positionThumb.bottom,
|
|
sb.position.left + sb.positionThumb.left, sb.position.top + sb.positionThumb.top,
|
|
}
|
|
gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(thumbVertices)*4, gl.Ptr(&thumbVertices[0]))
|
|
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(thumbVertices)/2))
|
|
|
|
gui.terminal.NotifyDirty()
|
|
}
|
|
|
|
func (sb *scrollbar) setPosition(max int, position int) {
|
|
if max <= 0 {
|
|
max = position
|
|
}
|
|
|
|
if position > max {
|
|
position = max
|
|
}
|
|
|
|
sb.maxScrollPosition = max
|
|
sb.scrollPosition = position
|
|
|
|
sb.recalcElementPositions()
|
|
}
|
|
|
|
func (sb *scrollbar) mouseHitTest(px float64, py float64) scrollbarPart {
|
|
// convert to local coordinates
|
|
mouseX := float32(px - float64(sb.position.left))
|
|
mouseY := float32(py - float64(sb.position.top))
|
|
|
|
result := None
|
|
|
|
if sb.positionUpperArrow.isInside(mouseX, mouseY) {
|
|
result = UpperArrow
|
|
} else if sb.positionBottomArrow.isInside(mouseX, mouseY) {
|
|
result = BottomArrow
|
|
} else if sb.positionThumb.isInside(mouseX, mouseY) {
|
|
result = Thumb
|
|
} else {
|
|
// construct UpperSpace
|
|
pos := ScreenRectangle{
|
|
left: sb.positionThumb.left,
|
|
top: sb.positionUpperArrow.bottom,
|
|
right: sb.positionThumb.right,
|
|
bottom: sb.positionThumb.top,
|
|
}
|
|
|
|
if pos.isInside(mouseX, mouseY) {
|
|
result = UpperSpace
|
|
}
|
|
|
|
// now update it to be BottomSpace
|
|
pos.top = sb.positionThumb.bottom
|
|
pos.bottom = sb.positionBottomArrow.top
|
|
if pos.isInside(mouseX, mouseY) {
|
|
result = BottomSpace
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (sb *scrollbar) isMouseInside(px float64, py float64) bool {
|
|
return sb.position.isInside(float32(px), float32(py))
|
|
}
|
|
|
|
func (sb *scrollbar) mouseButtonCallback(g *GUI, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey, mouseX float64, mouseY float64) {
|
|
if button == glfw.MouseButtonLeft {
|
|
if action == glfw.Press {
|
|
switch sb.mouseHitTest(mouseX, mouseY) {
|
|
case UpperArrow:
|
|
sb.upperArrowIsDown = true
|
|
g.terminal.ScreenScrollUp(1)
|
|
|
|
case UpperSpace:
|
|
g.terminal.ScrollPageUp()
|
|
|
|
case Thumb:
|
|
sb.thumbIsDragging = true
|
|
sb.startedDraggingAtPosition = sb.scrollPosition
|
|
sb.startedDraggingAtThumbTop = sb.positionThumb.top
|
|
sb.offsetInThumbY = float32(mouseY) - sb.position.top - sb.positionThumb.top
|
|
sb.scrollPositionDelta = 0
|
|
|
|
case BottomSpace:
|
|
g.terminal.ScrollPageDown()
|
|
|
|
case BottomArrow:
|
|
sb.bottomArrowIsDown = true
|
|
g.terminal.ScreenScrollDown(1)
|
|
}
|
|
} else if action == glfw.Release {
|
|
if sb.thumbIsDragging {
|
|
sb.thumbIsDragging = false
|
|
}
|
|
|
|
if sb.upperArrowIsDown {
|
|
sb.upperArrowIsDown = false
|
|
}
|
|
|
|
if sb.bottomArrowIsDown {
|
|
sb.bottomArrowIsDown = false
|
|
}
|
|
}
|
|
|
|
g.terminal.NotifyDirty()
|
|
}
|
|
|
|
sb.resetElementColors(mouseX, mouseY)
|
|
}
|
|
|
|
func (sb *scrollbar) mouseMoveCallback(g *GUI, px float64, py float64) {
|
|
sb.resetElementColors(px, py)
|
|
|
|
if sb.thumbIsDragging {
|
|
py -= float64(sb.position.top)
|
|
|
|
minThumbTop := sb.positionUpperArrow.bottom
|
|
maxThumbTop := sb.positionBottomArrow.top - sb.positionThumb.height()
|
|
|
|
newThumbTop := float32(py) - sb.offsetInThumbY
|
|
|
|
newPositionDelta := int((float32(sb.maxScrollPosition) * (newThumbTop - minThumbTop - sb.startedDraggingAtThumbTop)) / (maxThumbTop - minThumbTop))
|
|
|
|
if newPositionDelta > sb.scrollPositionDelta {
|
|
scrollLines := newPositionDelta - sb.scrollPositionDelta
|
|
g.logger.Debugf("old position: %d, new position delta: %d, scroll down %d lines", sb.scrollPosition, newPositionDelta, scrollLines)
|
|
g.terminal.ScreenScrollDown(uint16(scrollLines))
|
|
sb.scrollPositionDelta = newPositionDelta
|
|
} else if newPositionDelta < sb.scrollPositionDelta {
|
|
scrollLines := sb.scrollPositionDelta - newPositionDelta
|
|
g.logger.Debugf("old position: %d, new position delta: %d, scroll up %d lines", sb.scrollPosition, newPositionDelta, scrollLines)
|
|
g.terminal.ScreenScrollUp(uint16(scrollLines))
|
|
sb.scrollPositionDelta = newPositionDelta
|
|
}
|
|
|
|
sb.recalcElementPositions()
|
|
g.logger.Debugf("new thumbTop: %f, fact thumbTop: %f, position: %d", newThumbTop, sb.positionThumb.top, sb.scrollPosition)
|
|
}
|
|
|
|
g.terminal.NotifyDirty()
|
|
}
|
|
|
|
func (sb *scrollbar) resetElementColors(mouseX float64, mouseY float64) {
|
|
part := sb.mouseHitTest(mouseX, mouseY)
|
|
|
|
if sb.scrollPosition == 0 {
|
|
sb.upperArrowBg = scrollbarColor_ButtonDisabledBg[:]
|
|
sb.upperArrowFg = scrollbarColor_ButtonDisabledFg[:]
|
|
} else if sb.upperArrowIsDown {
|
|
sb.upperArrowFg = scrollbarColor_ButtonClickedFg[:]
|
|
sb.upperArrowBg = scrollbarColor_ButtonClickedBg[:]
|
|
} else if part == UpperArrow {
|
|
sb.upperArrowFg = scrollbarColor_ButtonHoverFg[:]
|
|
sb.upperArrowBg = scrollbarColor_ButtonHoverBg[:]
|
|
} else {
|
|
sb.upperArrowFg = scrollbarColor_ButtonNormalFg[:]
|
|
sb.upperArrowBg = scrollbarColor_ButtonNormalBg[:]
|
|
}
|
|
|
|
if sb.scrollPosition == sb.maxScrollPosition {
|
|
sb.bottomArrowBg = scrollbarColor_ButtonDisabledBg[:]
|
|
sb.bottomArrowFg = scrollbarColor_ButtonDisabledFg[:]
|
|
} else if sb.bottomArrowIsDown {
|
|
sb.bottomArrowFg = scrollbarColor_ButtonClickedFg[:]
|
|
sb.bottomArrowBg = scrollbarColor_ButtonClickedBg[:]
|
|
} else if part == BottomArrow {
|
|
sb.bottomArrowFg = scrollbarColor_ButtonHoverFg[:]
|
|
sb.bottomArrowBg = scrollbarColor_ButtonHoverBg[:]
|
|
} else {
|
|
sb.bottomArrowFg = scrollbarColor_ButtonNormalFg[:]
|
|
sb.bottomArrowBg = scrollbarColor_ButtonNormalBg[:]
|
|
}
|
|
|
|
if sb.thumbIsDragging {
|
|
sb.thumbColor = scrollbarColor_ThumbClicked[:]
|
|
} else if part == Thumb {
|
|
sb.thumbColor = scrollbarColor_ThumbHover[:]
|
|
} else {
|
|
sb.thumbColor = scrollbarColor_ThumbNormal[:]
|
|
}
|
|
}
|
|
|
|
func (sb *scrollbar) cursorEnterCallback(g *GUI, entered bool) {
|
|
if !entered {
|
|
sb.resetElementColors(-1, -1) // (-1, -1) ensures that no part is hovered by the mouse
|
|
g.terminal.NotifyDirty()
|
|
}
|
|
}
|