Files
aego/editor/panels/favorites/panel.go
sanspie 2fcbaa6c12 Stage 11g1: the editor in Russian (D348)
engine/i18n with catalogs, plural forms and module catalogs; tools/i18n extract and check; the editor UI, menus, panels and notices in Russian with the author's terms; overflow test and tooltip wrapping; the English log.
2026-10-25 15:31:22 +03:00

119 lines
2.9 KiB
Go

package favorites
import (
"aego/asset"
"aego/core/mathx"
"aego/editor/core/context"
favs "aego/editor/core/favorites"
"aego/editor/core/services"
"aego/engine/i18n"
"aego/ui/core"
"aego/ui/widgets"
)
const ID = "favorites"
type Deps struct {
Store *favs.Store
Env favs.Env
Notices services.Notices
}
type Panel struct {
d Deps
scroll float32
}
func New(d Deps) *Panel {
return &Panel{d: d}
}
func (p *Panel) ID() string {
return ID
}
func (p *Panel) Title() string {
return i18n.Tr("editor.favorites.title", "Favorites")
}
func (p *Panel) Icon() string {
return "panel.favorites"
}
func (p *Panel) icon(it favs.Item, fallback string) string {
if it.Kind != favs.Asset || p.d.Env.Pipeline == nil {
return fallback
}
e, ok := p.d.Env.Pipeline.Entry(it.Asset)
if !ok {
return fallback
}
switch e.Kind {
case asset.ArtScene:
return "file.scene"
case asset.ArtPrefab:
return "file.prefab"
case asset.ArtScript:
return "file.script"
case asset.ArtData:
return "file.data"
case asset.ArtTable:
return "file.table"
case asset.ArtMesh:
return "file.mesh"
}
return "file.texture"
}
func (p *Panel) Draw(f *services.Frame, r mathx.Rect) {
ui := f.UI
th := &ui.Theme
if p.d.Store == nil {
return
}
items := p.d.Store.Items()
if len(items) == 0 {
widgets.LabelWrapped(ui, i18n.Tr("editor.favorites.nothing_here_yet_add_assets", "Nothing here yet. Add assets from their menu, nodes from the Hierarchy menu and actions with Ctrl+D in the command palette."), true)
return
}
top := ui.Cursor().Y
list := mathx.Rect{X: r.X, Y: top, W: r.W, H: max(0, r.Y+r.H-top)}
var remove, open = -1, -1
widgets.VirtualList(ui, ui.ID("list"), list, len(items), th.RowHeight+2, &p.scroll, func(i int, row mathx.Rect) {
it := items[i]
label, detail, icon, ok := favs.Describe(p.d.Env, it)
icon = p.icon(it, icon)
id := core.IDSeq(ui.ID("row"), i)
xr := mathx.Rect{X: row.X + row.W - row.H, Y: row.Y, W: row.H, H: row.H}
body := mathx.Rect{X: row.X, Y: row.Y, W: row.W - row.H - 2, H: row.H}
if ui.Clicked(id, body) {
open = i
}
if ui.Hot() == id {
ui.Rect(row, th.WidgetHot)
}
col, dim := th.Text, th.TextDim
if !ok {
col, dim = th.TextDisabled, th.TextDisabled
}
widgets.IconAt(ui, mathx.Rect{X: row.X + 4, Y: row.Y + (row.H-16)/2, W: 16, H: 16}, icon, dim)
ui.PushClip(body)
ui.Text(label, mathx.Vec2{X: row.X + 26, Y: ui.TextY(row)}, col)
ui.Text(detail, mathx.Vec2{X: row.X + 38 + ui.TextSize(label).X, Y: ui.TextY(row)}, dim)
ui.PopClip()
if widgets.IconButtonRect(ui, core.IDSeq(id, 1), xr, "ui.close") {
remove = i
}
})
if open >= 0 {
if err := favs.Open(p.d.Env, items[open]); err != nil && p.d.Notices != nil {
p.d.Notices.Notify(context.LevelInfo, err.Error())
}
}
if remove >= 0 {
if err := p.d.Store.Remove(items[remove]); err != nil && p.d.Notices != nil {
p.d.Notices.Notify(context.LevelError, err.Error())
}
}
}