mirror of
https://github.com/diamondburned/cchat-gtk.git
synced 2024-10-31 19:44:23 +00:00
141 lines
3.4 KiB
Go
141 lines
3.4 KiB
Go
package session
|
|
|
|
import (
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/drag"
|
|
"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
|
|
}
|
|
|
|
// Session returns the session row with the given ID. A nil Row is returned if
|
|
// none is found.
|
|
func (sl *List) Session(id string) *Row {
|
|
row, _ := sl.sessions[id]
|
|
return row
|
|
}
|
|
|
|
// AddSessionRow adds the given row as a session into the list.
|
|
func (sl *List) AddSessionRow(id string, row *Row) {
|
|
// !!! IMPORTANT !!! Guarantee that there is NO collision.
|
|
if _, ok := sl.sessions[id]; ok {
|
|
panic("BUG: Duplicate session; AddSessionRow caller did not check Session.")
|
|
}
|
|
|
|
// 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
|
|
|
|
// 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(targetID, movingID string) {
|
|
// Get the widget of the row that is moving.
|
|
var moving, ok = sl.sessions[movingID]
|
|
if !ok {
|
|
return // sometimes movingID might come from other services
|
|
}
|
|
|
|
// Find the current position of the row that we're moving the other one
|
|
// underneath of.
|
|
var rowix = drag.Find(sl.ListBox, targetID)
|
|
|
|
// Reorder the box.
|
|
sl.ListBox.Remove(moving)
|
|
sl.ListBox.Insert(moving, rowix)
|
|
}
|
|
|
|
func (sl *List) UnselectAll() {
|
|
sl.ListBox.UnselectAll()
|
|
}
|