Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
diamondburned
GitHub Repository: diamondburned/gtkcord4
Path: blob/main/internal/sidebar/guilds/folderbutton.go
366 views
1
package guilds
2
3
import (
4
"context"
5
"fmt"
6
7
"github.com/diamondburned/arikawa/v3/discord"
8
"github.com/diamondburned/gotk4/pkg/gtk/v4"
9
"github.com/diamondburned/gotkit/components/onlineimage"
10
"github.com/diamondburned/gotkit/gtkutil/cssutil"
11
"github.com/diamondburned/gotkit/gtkutil/imgutil"
12
"libdb.so/dissent/internal/gtkcord"
13
"libdb.so/dissent/internal/sidebar/sidebutton"
14
)
15
16
// FolderButton is the folder icon containing the four guild icons.
17
type FolderButton struct {
18
*gtk.Button
19
// Main stack, switches between "guilds" and "folder"
20
MainStack *gtk.Stack
21
GuildGrid *gtk.Grid // contains 4 images always.
22
FolderIcon *gtk.Image
23
Images [4]*onlineimage.Avatar // first 4 of folder.Guilds
24
Mentions *sidebutton.MentionsIndicator
25
26
prov *gtk.CSSProvider
27
ctx context.Context
28
}
29
30
// [0] [1]
31
// [2] [3]
32
var folderIconMatrix = [4][2]int{
33
{0, 0},
34
{1, 0},
35
{0, 1},
36
{1, 1},
37
}
38
39
var folderButtonCSS = cssutil.Applier("guild-folderbutton", `
40
.guild-folderbutton {
41
padding: 0 12px; /* reset styling */
42
padding-top: 8px;
43
border: none;
44
border-radius: 0;
45
min-width: 0;
46
min-height: 0;
47
background: none;
48
}
49
.guild-foldericons {
50
transition: 200ms ease;
51
padding: 4px 0;
52
/* Super quirky hack to give bottom margin control to the Stack
53
* instead of the button. We make up for the negative margin in
54
* the button.
55
*/
56
margin-top: -4px;
57
margin-bottom: 4px;
58
border-radius: calc({$guild_icon_size} / 4);
59
}
60
.guild-foldericons:not(.guild-foldericons-collapsed) {
61
background-color: @theme_bg_color;
62
padding-bottom: 8px;
63
margin-bottom: 0px;
64
border-radius:
65
calc({$guild_icon_size} / 4)
66
calc({$guild_icon_size} / 4)
67
0 0;
68
}
69
.guild-foldericons > image {
70
color: rgb(88, 101, 242);
71
}
72
.guild-foldericons-collapsed {
73
background-color: rgba(88, 101, 242, 0.35);
74
}
75
.guild-foldericons image {
76
background: none;
77
}
78
.guild-folderbutton .guild-foldericons {
79
transition-property: all;
80
outline: 0px solid transparent;
81
}
82
.guild-folderbutton:hover .guild-foldericons.guild-foldericons-collapsed {
83
outline: 2px solid @theme_selected_bg_color;
84
}
85
`)
86
87
// NewFolderButton creates a new FolderButton.
88
func NewFolderButton(ctx context.Context) *FolderButton {
89
b := FolderButton{ctx: ctx}
90
b.FolderIcon = gtk.NewImageFromIconName("folder-visiting-symbolic")
91
b.FolderIcon.SetPixelSize(FolderSize)
92
93
b.GuildGrid = gtk.NewGrid()
94
b.GuildGrid.SetHAlign(gtk.AlignCenter)
95
b.GuildGrid.SetVAlign(gtk.AlignCenter)
96
b.GuildGrid.SetRowSpacing(4) // calculated from Discord
97
b.GuildGrid.SetRowHomogeneous(true)
98
b.GuildGrid.SetColumnSpacing(4)
99
b.GuildGrid.SetColumnHomogeneous(true)
100
101
for ix := range b.Images {
102
b.Images[ix] = onlineimage.NewAvatar(ctx, imgutil.HTTPProvider, FolderMiniSize)
103
b.Images[ix].SetText("#")
104
105
pos := folderIconMatrix[ix]
106
b.GuildGrid.Attach(b.Images[ix], pos[0], pos[1], 1, 1)
107
}
108
109
b.MainStack = gtk.NewStack()
110
b.MainStack.SetTransitionType(gtk.StackTransitionTypeSlideUp) // unsure
111
b.MainStack.SetSizeRequest(gtkcord.GuildIconSize, gtkcord.GuildIconSize)
112
b.MainStack.SetHAlign(gtk.AlignCenter)
113
b.MainStack.AddCSSClass("guild-foldericons")
114
b.MainStack.AddCSSClass("guild-foldericons-collapsed")
115
b.MainStack.AddChild(b.GuildGrid)
116
b.MainStack.AddChild(b.FolderIcon)
117
118
b.Mentions = sidebutton.NewMentionsIndicator()
119
b.Mentions.SetVAlign(gtk.AlignEnd)
120
b.Mentions.SetHAlign(gtk.AlignEnd)
121
122
overlay := gtk.NewOverlay()
123
overlay.SetChild(b.MainStack)
124
overlay.AddOverlay(b.Mentions)
125
126
b.Button = gtk.NewButton()
127
b.Button.SetHasFrame(false)
128
b.Button.SetChild(overlay)
129
130
folderButtonCSS(b)
131
return &b
132
}
133
134
// SetIcons sets the guild icons to be shown.
135
func (b *FolderButton) SetIcons(guildIDs []discord.GuildID) {
136
state := gtkcord.FromContext(b.ctx)
137
138
for ix, image := range b.Images {
139
if ix >= len(guildIDs) {
140
image.Hide()
141
continue
142
}
143
144
image.Show()
145
146
g, err := state.Cabinet.Guild(guildIDs[ix])
147
if err != nil {
148
image.SetText("?")
149
continue
150
}
151
152
image.SetText(g.Name)
153
image.SetFromURL(gtkcord.InjectSize(g.IconURL(), 64))
154
}
155
}
156
157
// SetRevealed sets what the FolderButton should show depending on if the folder
158
// is revealed/opened or not.
159
func (b *FolderButton) SetRevealed(revealed bool) {
160
if revealed {
161
b.MainStack.SetTransitionType(gtk.StackTransitionTypeSlideDown)
162
b.MainStack.SetVisibleChild(b.FolderIcon)
163
b.MainStack.RemoveCSSClass("guild-foldericons-collapsed")
164
} else {
165
b.MainStack.SetTransitionType(gtk.StackTransitionTypeSlideUp)
166
b.MainStack.SetVisibleChild(b.GuildGrid)
167
b.MainStack.AddCSSClass("guild-foldericons-collapsed")
168
}
169
}
170
171
const colorCSSf = `
172
image {
173
color: rgb(%[1]d, %[2]d, %[3]d);
174
}
175
stack.guild-foldericons-collapsed {
176
background-color: rgba(%[1]d, %[2]d, %[3]d, 0.4);
177
}
178
`
179
180
func (b *FolderButton) colorWidgets() []gtk.Widgetter {
181
return []gtk.Widgetter{
182
b.Button,
183
b.FolderIcon,
184
b.MainStack,
185
}
186
}
187
188
// SetColor sets the color of the folder.
189
func (b *FolderButton) SetColor(color discord.Color) {
190
rr, gg, bb := color.RGB()
191
192
p := gtk.NewCSSProvider()
193
p.LoadFromData(fmt.Sprintf(colorCSSf, rr, gg, bb))
194
195
for _, w := range b.colorWidgets() {
196
s := gtk.BaseWidget(w).StyleContext()
197
if b.prov != nil {
198
s.RemoveProvider(b.prov)
199
}
200
s.AddProvider(p, gtk.STYLE_PROVIDER_PRIORITY_APPLICATION+10)
201
}
202
203
b.prov = p
204
}
205
206