- Keterangan tombol saat hover: baris hint di footer window dan di dalam dialog (bukan popup: overlay Fyne menelan klik pertama, tombol jadi perlu 2x klik) - Dialog proses sekarang pakai progress bar berjalan (bukan spinner diam) - Tombol edit per shortcut: ganti binary/URL, ikon (file/online), nama, kategori, dan lokasi; berkas .desktop + salinan Desktop ditulis ulang, berkas lama dibuang, jenis aplikasi dideteksi ulang, binary lama dihapus kalau nama berubah - Export/Import daftar shortcut ke berkas SQLite .lazy (driver murni Go modernc), skema + meta format versi, impor tidak menimpa shortcut yang sudah ada - Tes: detect kind, edit (rename/ganti binary/ikon/target), db roundtrip, merge impor, tooltip (hint muncul/hilang + klik tetap sampai ke tombol), semua paket hijau - README: bagian backup + hint tombol
108 lines
2.6 KiB
Go
108 lines
2.6 KiB
Go
package ui
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/dialog"
|
|
"fyne.io/fyne/v2/driver/desktop"
|
|
"fyne.io/fyne/v2/widget"
|
|
)
|
|
|
|
// Keterangan tombol muncul di satu baris hint (bawah window atau dalam dialog),
|
|
// bukan sebagai popup: popup Fyne selalu jadi overlay, dan selama overlay ada
|
|
// semua klik ke konten di bawahnya tidak diteruskan (tombol jadi perlu 2x klik).
|
|
var (
|
|
hintMu sync.Mutex
|
|
hintTarget *canvas.Text
|
|
)
|
|
|
|
// pushHintTarget mengarahkan keterangan hover ke label tertentu (dipakai dialog).
|
|
// Fungsi yang dikembalikan mengembalikan target sebelumnya.
|
|
func pushHintTarget(label *canvas.Text) func() {
|
|
hintMu.Lock()
|
|
previous := hintTarget
|
|
hintTarget = label
|
|
hintMu.Unlock()
|
|
|
|
return func() {
|
|
hintMu.Lock()
|
|
hintTarget = previous
|
|
hintMu.Unlock()
|
|
}
|
|
}
|
|
|
|
func showHint(text string) {
|
|
hintMu.Lock()
|
|
target := hintTarget
|
|
hintMu.Unlock()
|
|
|
|
if target == nil || text == "" {
|
|
return
|
|
}
|
|
target.Text = text
|
|
target.Refresh()
|
|
}
|
|
|
|
// clearHint menghapus hint hanya kalau isinya memang milik tombol ini.
|
|
func clearHint(text string) {
|
|
hintMu.Lock()
|
|
target := hintTarget
|
|
hintMu.Unlock()
|
|
|
|
if target == nil || target.Text != text {
|
|
return
|
|
}
|
|
target.Text = ""
|
|
target.Refresh()
|
|
}
|
|
|
|
// tipButton adalah tombol yang menampilkan fungsinya saat disorot mouse.
|
|
type tipButton struct {
|
|
widget.Button
|
|
tip string
|
|
}
|
|
|
|
// newButton membuat tombol (dengan ikon kalau diberikan) plus keterangan hover.
|
|
func newButton(text string, icon fyne.Resource, tip string, importance widget.Importance, tapped func()) *tipButton {
|
|
button := &tipButton{tip: tip}
|
|
button.Text = text
|
|
button.Icon = icon
|
|
button.Importance = importance
|
|
button.OnTapped = tapped
|
|
button.ExtendBaseWidget(button)
|
|
return button
|
|
}
|
|
|
|
// newIconButton adalah tombol ikon saja (tanpa teks), gaya datar.
|
|
func newIconButton(icon fyne.Resource, tip string, tapped func()) *tipButton {
|
|
return newButton("", icon, tip, widget.LowImportance, tapped)
|
|
}
|
|
|
|
func (b *tipButton) MouseIn(event *desktop.MouseEvent) {
|
|
b.Button.MouseIn(event)
|
|
showHint(b.tip)
|
|
}
|
|
|
|
func (b *tipButton) MouseOut() {
|
|
b.Button.MouseOut()
|
|
clearHint(b.tip)
|
|
}
|
|
|
|
// showLoading menampilkan dialog proses dengan progress bar yang berjalan,
|
|
// dan mengembalikan fungsi untuk menutupnya.
|
|
func (ui *app) showLoading(title, message string) func() {
|
|
bar := widget.NewProgressBarInfinite()
|
|
|
|
var d *dialog.CustomDialog
|
|
d = dialog.NewCustomWithoutButtons(title, container.NewBorder(
|
|
container.NewVBox(logoBox(newLogo(), 22), muted(message)),
|
|
nil, nil, nil,
|
|
bar,
|
|
), ui.win)
|
|
showDialog(d, ui.win, 420, 170)
|
|
return d.Hide
|
|
}
|