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