1
0
Fork 0
mirror of https://github.com/diamondburned/cchat-gtk.git synced 2024-11-17 03:32:56 +00:00
cchat-gtk/internal/ui/messages/container/container.go

158 lines
4.7 KiB
Go
Raw Normal View History

2020-06-06 07:44:36 +00:00
package container
import (
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-gtk/internal/ui/messages/input"
"github.com/diamondburned/cchat-gtk/internal/ui/messages/message"
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
2020-07-16 05:41:21 +00:00
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu"
"github.com/diamondburned/cchat-gtk/internal/ui/rich/labeluri"
"github.com/diamondburned/handy"
2020-06-06 07:44:36 +00:00
"github.com/gotk3/gotk3/gtk"
)
// BacklogLimit is the maximum number of messages to store in the container at
// once.
const BacklogLimit = 35
type MessageRow interface {
2020-06-06 07:44:36 +00:00
message.Container
// Attach should only be called once.
Row() *gtk.ListBoxRow
// AttachMenu should override the stored constructor.
AttachMenu(items []menu.Item) // save memory
// MenuItems returns the list of attached menu items.
MenuItems() []menu.Item
// SetReferenceHighlighter sets the reference highlighter into the message.
SetReferenceHighlighter(refer labeluri.ReferenceHighlighter)
}
type PresendMessageRow interface {
MessageRow
2020-06-06 07:44:36 +00:00
message.PresendContainer
}
// Container is a generic messages container for children messages for children
// packages.
2020-06-06 07:44:36 +00:00
type Container interface {
gtk.IWidget
2020-11-06 04:01:00 +00:00
// Reset resets the message container to its original state.
Reset()
// CreateMessageUnsafe creates a new message and returns the index that is
// the location the message is added to.
CreateMessageUnsafe(cchat.MessageCreate)
UpdateMessageUnsafe(cchat.MessageUpdate)
DeleteMessageUnsafe(cchat.MessageDelete)
2020-08-20 23:53:13 +00:00
// FirstMessage returns the first message in the buffer. Nil is returned if
// there's nothing.
FirstMessage() MessageRow
// AddPresendMessage adds and displays an unsent message.
AddPresendMessage(msg input.PresendMessage) PresendMessageRow
// LatestMessageFrom returns the last message ID with that author.
LatestMessageFrom(authorID string) (msgID string, ok bool)
// Message finds and returns the message, if any.
Message(id cchat.ID, nonce string) MessageRow
// Highlight temporarily highlights the given message for a short while.
Highlight(msg MessageRow)
2020-08-20 23:53:13 +00:00
// UI methods.
SetFocusHAdjustment(*gtk.Adjustment)
SetFocusVAdjustment(*gtk.Adjustment)
2020-06-06 07:44:36 +00:00
}
// Controller is for menu actions.
type Controller interface {
// Connector is used for button press events to unselect messages.
primitives.Connector
// BindMenu expects the controller to add actioner into the message.
BindMenu(MessageRow)
2020-07-03 03:22:48 +00:00
// Bottomed returns whether or not the message scroller is at the bottom.
Bottomed() bool
// AuthorEvent is called on message create/update. This is used to update
// the typer state.
AuthorEvent(a cchat.Author)
// SelectMessage is called when a message is selected.
SelectMessage(list *ListStore, msg MessageRow)
// UnselectMessage is called when the message selection is cleared.
UnselectMessage()
}
// Constructor is an interface for making custom message implementations which
// allows ListContainer to generically work with.
type Constructor interface {
NewMessage(cchat.MessageCreate) MessageRow
NewPresendMessage(input.PresendMessage) PresendMessageRow
2020-06-07 04:27:28 +00:00
}
const ColumnSpacing = 8
2020-06-07 04:27:28 +00:00
// ListContainer is an implementation of Container, which allows flexible
2020-06-06 07:44:36 +00:00
// message grids.
type ListContainer struct {
*handy.Clamp
*ListStore
2020-07-03 03:22:48 +00:00
Controller
2020-06-07 04:27:28 +00:00
}
// messageRow w/ required internals
type messageRow struct {
MessageRow
presend message.PresendContainer // this shouldn't be here but i'm lazy
}
var _ Container = (*ListContainer)(nil)
2020-06-06 07:44:36 +00:00
func NewListContainer(constr Constructor, ctrl Controller) *ListContainer {
listStore := NewListStore(constr, ctrl)
listStore.ListBox.Show()
clamp := handy.ClampNew()
clamp.SetMaximumSize(800)
clamp.SetTighteningThreshold(600)
clamp.SetHExpand(true)
clamp.SetVExpand(true)
clamp.Add(listStore.ListBox)
clamp.Show()
return &ListContainer{
Clamp: clamp,
ListStore: listStore,
2020-07-03 03:22:48 +00:00
Controller: ctrl,
2020-06-06 07:44:36 +00:00
}
}
2020-11-06 03:23:06 +00:00
// CreateMessageUnsafe inserts a message. It does not clean up old messages.
func (c *ListContainer) CreateMessageUnsafe(msg cchat.MessageCreate) {
// Insert the message first.
c.ListStore.CreateMessageUnsafe(msg)
2020-11-06 03:23:06 +00:00
}
2020-11-06 03:23:06 +00:00
// CleanMessages cleans up the oldest messages if the user is scrolled to the
// bottom. True is returned if there were changes.
func (c *ListContainer) CleanMessages() bool {
// Determine if the user is scrolled to the bottom for cleaning up.
2020-10-24 21:58:48 +00:00
if c.Bottomed() {
// Clean up the backlog.
2020-11-06 03:23:06 +00:00
if delta := c.MessagesLen() - BacklogLimit; delta > 0 {
c.DeleteEarliest(delta)
return true
}
}
2020-11-06 03:23:06 +00:00
return false
}
func (c *ListContainer) SetFocusHAdjustment(adj *gtk.Adjustment) {
c.ListBox.SetFocusHAdjustment(adj)
}
func (c *ListContainer) SetFocusVAdjustment(adj *gtk.Adjustment) {
c.ListBox.SetFocusVAdjustment(adj)
}