cchat-gtk/internal/ui/service/session/list.go

137 lines
3.1 KiB
Go

package session
import (
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
"github.com/gotk3/gotk3/gtk"
)
type ServiceController interface {
SessionSelected(*Row)
AuthenticateSession()
}
type List struct {
*gtk.ListBox
// This map isn't ordered, as we rely on the order that the widget was added
// into the ListBox.
sessions map[string]*Row
svcctrl ServiceController
}
var listCSS = primitives.PrepareClassCSS("session-list", `
.session-list {
border-radius: 0 0 14px 14px;
background-color: mix(@theme_bg_color, @theme_fg_color, 0.1);
box-shadow:
inset 0 10px 2px -10px alpha(#121212, 0.6),
inset 0 -10px 2px -10px alpha(#121212, 0.6);
}
`)
func NewList(svcctrl ServiceController) *List {
list, _ := gtk.ListBoxNew()
list.Add(NewAddButton()) // add button to LAST; keep it LAST.
list.Show()
listCSS(list)
// We can't do browse for the selection mode, as we need UnselectAll to
// work.
list.SetSelectionMode(gtk.SELECTION_SINGLE)
sl := &List{
ListBox: list,
sessions: map[string]*Row{},
svcctrl: svcctrl,
}
list.Connect("row-activated", func(l *gtk.ListBox, r *gtk.ListBoxRow) {
switch i, length := r.GetIndex(), len(sl.sessions); {
case i < 0:
return // lulwut
// If the selection IS the last button.
case i == length:
svcctrl.AuthenticateSession()
// If the selection is within range and is not the last button.
case i < length:
if row, ok := sl.sessions[primitives.GetName(r)]; ok {
row.Activate()
}
}
})
return sl
}
func (sl *List) Sessions() []*Row {
// We already know the size beforehand. Allocate it wisely.
var rows = make([]*Row, 0, len(sl.sessions))
// Loop over widget children.
primitives.EachChildren(sl.ListBox, func(i int, v interface{}) bool {
var id = primitives.GetName(v.(primitives.Namer))
if row, ok := sl.sessions[id]; ok {
rows = append(rows, row)
}
return false
})
return rows
}
func (sl *List) AddSessionRow(id string, row *Row) {
// Insert the row RIGHT BEFORE the add button.
sl.ListBox.Insert(row, len(sl.sessions))
// Set the map, which increases the length by 1.
sl.sessions[id] = row
// Bind the mover.
row.BindMover(id)
// Assert that a name can be obtained.
namer := primitives.Namer(row)
namer.SetName(id) // set ID here, get it in Move
}
func (sl *List) RemoveSessionRow(sessionID string) bool {
r, ok := sl.sessions[sessionID]
if ok {
delete(sl.sessions, sessionID)
sl.ListBox.Remove(r)
}
return ok
}
// MoveSession moves sessions around. This function must not touch the add
// button.
func (sl *List) MoveSession(id, movingID string) {
// Get the widget of the row that is moving.
var moving = sl.sessions[movingID]
// Find the current position of the row that we're moving the other one
// underneath of.
var rowix = -1
primitives.EachChildren(sl.ListBox, func(i int, v interface{}) bool {
// The obtained name will be the ID set in AddSessionRow.
if primitives.GetName(v.(primitives.Namer)) == id {
rowix = i
return true
}
return false
})
// Reorder the box.
sl.ListBox.Remove(moving)
sl.ListBox.Insert(moving, rowix)
}
func (sl *List) UnselectAll() {
sl.ListBox.UnselectAll()
}