diff --git a/elements/basic/list.go b/elements/basic/list.go index 90fad97..13551e1 100644 --- a/elements/basic/list.go +++ b/elements/basic/list.go @@ -11,11 +11,15 @@ import "git.tebibyte.media/sashakoshka/tomo/elements/core" type List struct { *core.Core core core.CoreControl + enabled bool selected bool + pressed bool + contentHeight int forcedMinimumWidth int forcedMinimumHeight int + selectedEntry int scroll int entries []ListEntry @@ -28,7 +32,7 @@ type List struct { // NewList creates a new list element with the specified entries. func NewList (entries ...ListEntry) (element *List) { - element = &List { } + element = &List { enabled: true, selectedEntry: -1 } element.Core, element.core = core.NewCore(element) element.entries = make([]ListEntry, len(entries)) @@ -71,16 +75,16 @@ func (element *List) HandleMouseDown (x, y int, button tomo.Button) { if !element.enabled { return } if !element.selected { element.Select() } if button != tomo.ButtonLeft { return } - - // if element.core.HasImage() { - // element.draw() - // element.core.DamageAll() - // } + element.pressed = true + if element.selectUnderMouse(x, y) && element.core.HasImage() { + element.draw() + element.core.DamageAll() + } } func (element *List) HandleMouseUp (x, y int, button tomo.Button) { if button != tomo.ButtonLeft { return } - // element.pressed = false + element.pressed = false // if element.core.HasImage() { // element.draw() // element.core.DamageAll() @@ -95,7 +99,15 @@ func (element *List) HandleMouseUp (x, y int, button tomo.Button) { // } } -func (element *List) HandleMouseMove (x, y int) { } +func (element *List) HandleMouseMove (x, y int) { + if element.pressed { + if element.selectUnderMouse(x, y) && element.core.HasImage() { + element.draw() + element.core.DamageAll() + } + } +} + func (element *List) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } func (element *List) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { @@ -324,6 +336,32 @@ func (element *List) Replace (index int, entry ListEntry) { } } +func (element *List) selectUnderMouse (x, y int) (updated bool) { + bounds := element.Bounds() + mousePoint := image.Pt(x, y) + dot := image.Pt ( + bounds.Min.X + theme.Padding() / 2, + bounds.Min.Y - element.scroll + theme.Padding() / 2) + + newlySelectedEntryIndex := -1 + for index, entry := range element.entries { + entryPosition := dot + dot.Y += entry.Bounds().Dy() + if entryPosition.Y > bounds.Max.Y { break } + if mousePoint.In(entry.Bounds().Add(entryPosition)) { + newlySelectedEntryIndex = index + break + } + } + + if element.selectedEntry == newlySelectedEntryIndex { return false } + element.selectedEntry = newlySelectedEntryIndex + if element.onSelectedEntryChange != nil { + element.onSelectedEntryChange(element.selectedEntry) + } + return true +} + func (element *List) resizeEntryToFit (entry ListEntry) (resized ListEntry) { entry.Collapse(element.forcedMinimumWidth) return entry @@ -332,7 +370,6 @@ func (element *List) resizeEntryToFit (entry ListEntry) (resized ListEntry) { func (element *List) updateMinimumSize () { element.contentHeight = 0 for _, entry := range element.entries { - element.contentHeight += theme.Padding() element.contentHeight += entry.Bounds().Dy() } @@ -340,11 +377,18 @@ func (element *List) updateMinimumSize () { minimumHeight := element.forcedMinimumHeight if minimumWidth == 0 { - + minimumWidth = theme.Padding() + for _, entry := range element.entries { + entryWidth := entry.Bounds().Dx() + if entryWidth > minimumWidth { + minimumWidth = entryWidth + } + } + minimumWidth += theme.Padding() } if minimumHeight == 0 { - minimumHeight = element.contentHeight + minimumHeight = element.contentHeight + theme.Padding() * 2 } element.core.SetMinimumSize(minimumWidth, minimumHeight) @@ -359,27 +403,21 @@ func (element *List) draw () { bounds) dot := image.Point { - bounds.Min.X + theme.Padding(), - bounds.Min.Y - element.scroll, + bounds.Min.X, + bounds.Min.Y - element.scroll + theme.Padding() / 2, } for index, entry := range element.entries { - dot.Y += theme.Padding() entryPosition := dot dot.Y += entry.Bounds().Dy() if dot.Y < bounds.Min.Y { continue } if entryPosition.Y > bounds.Max.Y { break } - selectionMarkerBounds := image.Rect ( - theme.Padding() / 2, - entryPosition.Y - theme.Padding() / 2, - bounds.Dx() - theme.Padding() / 2, - entryPosition.Y + entry.Bounds().Dy() + - theme.Padding() / 2) - artist.FillRectangle ( - element, - theme.ListEntryPattern(element.selectedEntry == index), - selectionMarkerBounds) - + if element.selectedEntry == index { + artist.FillRectangle ( + element, + theme.ListEntryPattern(true), + entry.Bounds().Add(entryPosition)) + } entry.Draw ( element, entryPosition, element.selectedEntry == index && element.selected) diff --git a/elements/basic/listentry.go b/elements/basic/listentry.go index 45a021c..e74b665 100644 --- a/elements/basic/listentry.go +++ b/elements/basic/listentry.go @@ -33,13 +33,20 @@ func (entry *ListEntry) Collapse (width int) { } func (entry *ListEntry) updateBounds () { + padding := theme.Padding() + entry.bounds = image.Rectangle { } - entry.bounds.Max.Y = entry.drawer.LineHeight().Round() + entry.bounds.Max.Y = entry.drawer.LineHeight().Round() + padding if entry.forcedMinimumWidth > 0 { - entry.bounds.Max.X = entry.drawer.LayoutBounds().Dx() + entry.bounds.Max.X = entry.forcedMinimumWidth + } else { + entry.bounds.Max.X = + entry.drawer.LayoutBounds().Dx() + padding * 2 } - entry.textPoint = image.Pt(0, 0).Sub(entry.drawer.LayoutBounds().Min) + entry.textPoint = + image.Pt(padding, padding / 2). + Sub(entry.drawer.LayoutBounds().Min) } func (entry *ListEntry) Draw ( diff --git a/elements/testing/artist.go b/elements/testing/artist.go index 220a236..dfd2b77 100644 --- a/elements/testing/artist.go +++ b/elements/testing/artist.go @@ -28,7 +28,7 @@ func (element *Artist) Resize (width, height int) { element.core.AllocateCanvas(width, height) bounds := element.Bounds() element.cellBounds.Max.X = bounds.Dx() / 4 - element.cellBounds.Max.Y = (bounds.Dy() - 48) / 5 + element.cellBounds.Max.Y = (bounds.Dy() - 48) / 6 drawStart := time.Now() @@ -128,6 +128,17 @@ func (element *Artist) Resize (width, height int) { drawTime.Milliseconds(), drawTime.Microseconds()))) textDrawer.Draw(element, uhex(0xFFFFFFFF), image.Pt(8, bounds.Max.Y - 24)) + + // 0, 5 + artist.FillRectangle ( + element, + artist.QuadBeveled { + artist.NewUniform(hex(0x880000FF)), + artist.NewUniform(hex(0x00FF00FF)), + artist.NewUniform(hex(0x0000FFFF)), + artist.NewUniform(hex(0xFF00FFFF)), + }, + element.cellAt(0, 5)) } func (element *Artist) lines (weight int, bounds image.Rectangle) { diff --git a/theme/list.go b/theme/list.go index c6c1d5f..52f22a8 100644 --- a/theme/list.go +++ b/theme/list.go @@ -14,9 +14,25 @@ var listPattern = artist.NewMultiBordered ( artist.Stroke { Pattern: artist.NewUniform(hex(0x999C99FF)) }) -var listEntryPattern = artist.NewUniform(hex(0x999C99FF)) +var listEntryPattern = artist.NewMultiBordered ( + artist.Stroke { Weight: 1, Pattern: artist.QuadBeveled { + artist.NewUniform(hex(0x999C99FF)), + strokePattern, + artist.NewUniform(hex(0x999C99FF)), + strokePattern, + }}, + artist.Stroke { Pattern: artist.NewUniform(hex(0x999C99FF)) }) -var selectedListEntryPattern = accentPattern +var selectedListEntryPattern = artist.NewMultiBordered ( + artist.Stroke { Weight: 1, Pattern: strokePattern }, + artist.Stroke { + Weight: 1, + Pattern: artist.Beveled { + Highlight: artist.NewUniform(hex(0x3b534eFF)), + Shadow: artist.NewUniform(hex(0x97a09cFF)), + }, + }, + artist.Stroke { Pattern: artist.NewUniform(hex(0x97a09cFF)) }) func ListPattern () (pattern artist.Pattern) { return listPattern