mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-18 13:04:25 -04:00
feat: embed license in executable and add menu item to show it
This commit is contained in:
parent
6f1db6b392
commit
fb0fa4af92
@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
|
- Help menu, with a menu item to show the license ([#196][i196])
|
||||||
- Show CPU load percentage in the song panel ([#192][i192])
|
- Show CPU load percentage in the song panel ([#192][i192])
|
||||||
- Theme can be user configured, in theme.yml. This theme.yml should be placed in
|
- Theme can be user configured, in theme.yml. This theme.yml should be placed in
|
||||||
the usual sointu config directory (i.e.
|
the usual sointu config directory (i.e.
|
||||||
@ -337,3 +338,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
[i176]: https://github.com/vsariola/sointu/issues/176
|
[i176]: https://github.com/vsariola/sointu/issues/176
|
||||||
[i186]: https://github.com/vsariola/sointu/issues/186
|
[i186]: https://github.com/vsariola/sointu/issues/186
|
||||||
[i192]: https://github.com/vsariola/sointu/issues/192
|
[i192]: https://github.com/vsariola/sointu/issues/192
|
||||||
|
[i196]: https://github.com/vsariola/sointu/issues/196
|
||||||
|
3
LICENSE
3
LICENSE
@ -1,7 +1,8 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018 Dominik Ries
|
Copyright (c) 2018 Dominik Ries
|
||||||
(c) 2020 Veikko Sariola
|
(c) 2020-2025 Veikko Sariola, moitias, qm210, LeStahl,
|
||||||
|
petersalomonsen, anticore
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
4
song.go
4
song.go
@ -1,6 +1,7 @@
|
|||||||
package sointu
|
package sointu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_ "embed"
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -92,6 +93,9 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:embed LICENSE
|
||||||
|
var License string
|
||||||
|
|
||||||
func (s *Score) SongPos(songRow int) SongPos {
|
func (s *Score) SongPos(songRow int) SongPos {
|
||||||
if s.RowsPerPattern == 0 {
|
if s.RowsPerPattern == 0 {
|
||||||
return SongPos{OrderRow: 0, PatternRow: 0}
|
return SongPos{OrderRow: 0, PatternRow: 0}
|
||||||
|
@ -92,6 +92,7 @@ type (
|
|||||||
Item MIDIDevice
|
Item MIDIDevice
|
||||||
*Model
|
*Model
|
||||||
}
|
}
|
||||||
|
ShowLicense Model
|
||||||
)
|
)
|
||||||
|
|
||||||
// Action methods
|
// Action methods
|
||||||
@ -123,6 +124,9 @@ func (a Action) Do() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a Action) Enabled() bool {
|
func (a Action) Enabled() bool {
|
||||||
|
if a.doer == nil {
|
||||||
|
return false // no doer, not allowed
|
||||||
|
}
|
||||||
if a.enabler == nil {
|
if a.enabler == nil {
|
||||||
return true // no enabler, always allowed
|
return true // no enabler, always allowed
|
||||||
}
|
}
|
||||||
@ -588,6 +592,9 @@ func (m *ExportFloat) Do() { m.dialog = ExportFloatExplorer }
|
|||||||
func (m *Model) ExportInt16() Action { return MakeEnabledAction((*ExportInt16)(m)) }
|
func (m *Model) ExportInt16() Action { return MakeEnabledAction((*ExportInt16)(m)) }
|
||||||
func (m *ExportInt16) Do() { m.dialog = ExportInt16Explorer }
|
func (m *ExportInt16) Do() { m.dialog = ExportInt16Explorer }
|
||||||
|
|
||||||
|
func (m *Model) ShowLicense() Action { return MakeEnabledAction((*ShowLicense)(m)) }
|
||||||
|
func (m *ShowLicense) Do() { m.dialog = License }
|
||||||
|
|
||||||
func (m *Model) SelectMidiInput(item MIDIDevice) Action {
|
func (m *Model) SelectMidiInput(item MIDIDevice) Action {
|
||||||
return MakeEnabledAction(SelectMidiInput{Item: item, Model: m})
|
return MakeEnabledAction(SelectMidiInput{Item: item, Model: m})
|
||||||
}
|
}
|
||||||
|
@ -92,13 +92,15 @@ func (d *Dialog) handleKeys(gtx C) {
|
|||||||
for d.BtnCancel.Clicked(gtx) {
|
for d.BtnCancel.Clicked(gtx) {
|
||||||
d.cancel.Do()
|
d.cancel.Do()
|
||||||
}
|
}
|
||||||
if d.alt.Enabled() {
|
if d.alt.Enabled() && d.cancel.Enabled() {
|
||||||
d.handleKeysForButton(gtx, &d.BtnAlt, &d.BtnCancel, &d.BtnOk)
|
d.handleKeysForButton(gtx, &d.BtnAlt, &d.BtnCancel, &d.BtnOk)
|
||||||
d.handleKeysForButton(gtx, &d.BtnCancel, &d.BtnOk, &d.BtnAlt)
|
d.handleKeysForButton(gtx, &d.BtnCancel, &d.BtnOk, &d.BtnAlt)
|
||||||
d.handleKeysForButton(gtx, &d.BtnOk, &d.BtnAlt, &d.BtnCancel)
|
d.handleKeysForButton(gtx, &d.BtnOk, &d.BtnAlt, &d.BtnCancel)
|
||||||
} else {
|
} else if d.ok.Enabled() {
|
||||||
d.handleKeysForButton(gtx, &d.BtnOk, &d.BtnCancel, &d.BtnCancel)
|
d.handleKeysForButton(gtx, &d.BtnOk, &d.BtnCancel, &d.BtnCancel)
|
||||||
d.handleKeysForButton(gtx, &d.BtnCancel, &d.BtnOk, &d.BtnOk)
|
d.handleKeysForButton(gtx, &d.BtnCancel, &d.BtnOk, &d.BtnOk)
|
||||||
|
} else {
|
||||||
|
d.handleKeysForButton(gtx, &d.BtnCancel, &d.BtnCancel, &d.BtnCancel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,18 +119,17 @@ func (d *DialogStyle) Layout(gtx C) D {
|
|||||||
layout.Rigid(Label(d.Theme, &d.Theme.Dialog.Text, d.Text).Layout),
|
layout.Rigid(Label(d.Theme, &d.Theme.Dialog.Text, d.Text).Layout),
|
||||||
layout.Rigid(func(gtx C) D {
|
layout.Rigid(func(gtx C) D {
|
||||||
return layout.E.Layout(gtx, func(gtx C) D {
|
return layout.E.Layout(gtx, func(gtx C) D {
|
||||||
gtx.Constraints.Min.X = gtx.Dp(unit.Dp(120))
|
fl := layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween}
|
||||||
if d.dialog.alt.Enabled() {
|
ok := layout.Rigid(d.OkStyle.Layout)
|
||||||
return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween}.Layout(gtx,
|
alt := layout.Rigid(d.AltStyle.Layout)
|
||||||
layout.Rigid(d.OkStyle.Layout),
|
cancel := layout.Rigid(d.CancelStyle.Layout)
|
||||||
layout.Rigid(d.AltStyle.Layout),
|
if d.dialog.alt.Enabled() && d.dialog.cancel.Enabled() {
|
||||||
layout.Rigid(d.CancelStyle.Layout),
|
return fl.Layout(gtx, ok, alt, cancel)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween}.Layout(gtx,
|
if d.dialog.ok.Enabled() {
|
||||||
layout.Rigid(d.OkStyle.Layout),
|
return fl.Layout(gtx, ok, cancel)
|
||||||
layout.Rigid(d.CancelStyle.Layout),
|
}
|
||||||
)
|
return fl.Layout(gtx, cancel)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -185,6 +185,8 @@ func (t *Tracker) KeyEvent(e key.Event, gtx C) {
|
|||||||
t.SplitTrack().Do()
|
t.SplitTrack().Do()
|
||||||
case "SplitInstrument":
|
case "SplitInstrument":
|
||||||
t.SplitInstrument().Do()
|
t.SplitInstrument().Do()
|
||||||
|
case "ShowLicense":
|
||||||
|
t.ShowLicense().Do()
|
||||||
// Booleans
|
// Booleans
|
||||||
case "PanicToggle":
|
case "PanicToggle":
|
||||||
t.Panic().Toggle()
|
t.Panic().Toggle()
|
||||||
|
@ -32,7 +32,6 @@ func (l LabelWidget) Layout(gtx C) D {
|
|||||||
textColor := textColorMacro.Stop()
|
textColor := textColorMacro.Stop()
|
||||||
t := widget.Label{
|
t := widget.Label{
|
||||||
Alignment: l.Alignment,
|
Alignment: l.Alignment,
|
||||||
MaxLines: 1,
|
|
||||||
}
|
}
|
||||||
if l.ShadowColor.A > 0 {
|
if l.ShadowColor.A > 0 {
|
||||||
shadowColorMacro := op.Record(gtx.Ops)
|
shadowColorMacro := op.Record(gtx.Ops)
|
||||||
|
@ -307,6 +307,7 @@ type MenuBar struct {
|
|||||||
fileMenuItems []MenuItem
|
fileMenuItems []MenuItem
|
||||||
editMenuItems []MenuItem
|
editMenuItems []MenuItem
|
||||||
midiMenuItems []MenuItem
|
midiMenuItems []MenuItem
|
||||||
|
helpMenuItems []MenuItem
|
||||||
|
|
||||||
panicHint string
|
panicHint string
|
||||||
PanicBtn *Clickable
|
PanicBtn *Clickable
|
||||||
@ -314,8 +315,8 @@ type MenuBar struct {
|
|||||||
|
|
||||||
func NewMenuBar(model *tracker.Model) *MenuBar {
|
func NewMenuBar(model *tracker.Model) *MenuBar {
|
||||||
ret := &MenuBar{
|
ret := &MenuBar{
|
||||||
Clickables: make([]Clickable, 3),
|
Clickables: make([]Clickable, 4),
|
||||||
Menus: make([]Menu, 3),
|
Menus: make([]Menu, 4),
|
||||||
PanicBtn: new(Clickable),
|
PanicBtn: new(Clickable),
|
||||||
panicHint: makeHint("Panic", " (%s)", "PanicToggle"),
|
panicHint: makeHint("Panic", " (%s)", "PanicToggle"),
|
||||||
}
|
}
|
||||||
@ -341,6 +342,9 @@ func NewMenuBar(model *tracker.Model) *MenuBar {
|
|||||||
Doer: model.SelectMidiInput(input),
|
Doer: model.SelectMidiInput(input),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ret.helpMenuItems = []MenuItem{
|
||||||
|
{IconBytes: icons.ActionCopyright, Text: "License", ShortcutText: keyActionMap["ShowLicense"], Doer: model.ShowLicense()},
|
||||||
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,11 +360,12 @@ func (t *MenuBar) Layout(gtx C, tr *Tracker) D {
|
|||||||
fileFC := layout.Rigid(tr.layoutMenu(gtx, "File", &t.Clickables[0], &t.Menus[0], unit.Dp(200), t.fileMenuItems...))
|
fileFC := layout.Rigid(tr.layoutMenu(gtx, "File", &t.Clickables[0], &t.Menus[0], unit.Dp(200), t.fileMenuItems...))
|
||||||
editFC := layout.Rigid(tr.layoutMenu(gtx, "Edit", &t.Clickables[1], &t.Menus[1], unit.Dp(200), t.editMenuItems...))
|
editFC := layout.Rigid(tr.layoutMenu(gtx, "Edit", &t.Clickables[1], &t.Menus[1], unit.Dp(200), t.editMenuItems...))
|
||||||
midiFC := layout.Rigid(tr.layoutMenu(gtx, "MIDI", &t.Clickables[2], &t.Menus[2], unit.Dp(200), t.midiMenuItems...))
|
midiFC := layout.Rigid(tr.layoutMenu(gtx, "MIDI", &t.Clickables[2], &t.Menus[2], unit.Dp(200), t.midiMenuItems...))
|
||||||
|
helpFC := layout.Rigid(tr.layoutMenu(gtx, "?", &t.Clickables[3], &t.Menus[3], unit.Dp(200), t.helpMenuItems...))
|
||||||
panicFC := layout.Flexed(1, func(gtx C) D { return layout.E.Layout(gtx, panicBtn.Layout) })
|
panicFC := layout.Flexed(1, func(gtx C) D { return layout.E.Layout(gtx, panicBtn.Layout) })
|
||||||
if len(t.midiMenuItems) > 0 {
|
if len(t.midiMenuItems) > 0 {
|
||||||
return flex.Layout(gtx, fileFC, editFC, midiFC, panicFC)
|
return flex.Layout(gtx, fileFC, editFC, midiFC, helpFC, panicFC)
|
||||||
}
|
}
|
||||||
return flex.Layout(gtx, fileFC, editFC, panicFC)
|
return flex.Layout(gtx, fileFC, editFC, helpFC, panicFC)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlayBar struct {
|
type PlayBar struct {
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"gioui.org/op/paint"
|
"gioui.org/op/paint"
|
||||||
"gioui.org/text"
|
"gioui.org/text"
|
||||||
"gioui.org/x/explorer"
|
"gioui.org/x/explorer"
|
||||||
|
"github.com/vsariola/sointu"
|
||||||
"github.com/vsariola/sointu/tracker"
|
"github.com/vsariola/sointu/tracker"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,6 +40,7 @@ type (
|
|||||||
|
|
||||||
SaveChangesDialog *Dialog
|
SaveChangesDialog *Dialog
|
||||||
WaveTypeDialog *Dialog
|
WaveTypeDialog *Dialog
|
||||||
|
LicenseDialog *Dialog
|
||||||
|
|
||||||
ModalDialog layout.Widget
|
ModalDialog layout.Widget
|
||||||
InstrumentEditor *InstrumentEditor
|
InstrumentEditor *InstrumentEditor
|
||||||
@ -79,6 +81,7 @@ func NewTracker(model *tracker.Model) *Tracker {
|
|||||||
|
|
||||||
SaveChangesDialog: NewDialog(model.SaveSong(), model.DiscardSong(), model.Cancel()),
|
SaveChangesDialog: NewDialog(model.SaveSong(), model.DiscardSong(), model.Cancel()),
|
||||||
WaveTypeDialog: NewDialog(model.ExportInt16(), model.ExportFloat(), model.Cancel()),
|
WaveTypeDialog: NewDialog(model.ExportInt16(), model.ExportFloat(), model.Cancel()),
|
||||||
|
LicenseDialog: NewDialog(tracker.MakeAction(nil), tracker.MakeAction(nil), model.Cancel()),
|
||||||
InstrumentEditor: NewInstrumentEditor(model),
|
InstrumentEditor: NewInstrumentEditor(model),
|
||||||
OrderEditor: NewOrderEditor(model),
|
OrderEditor: NewOrderEditor(model),
|
||||||
TrackEditor: NewNoteEditor(model),
|
TrackEditor: NewNoteEditor(model),
|
||||||
@ -291,6 +294,10 @@ func (t *Tracker) showDialog(gtx C) {
|
|||||||
t.explorerCreateFile(func(wc io.WriteCloser) {
|
t.explorerCreateFile(func(wc io.WriteCloser) {
|
||||||
t.WriteWav(wc, t.Dialog() == tracker.ExportInt16Explorer)
|
t.WriteWav(wc, t.Dialog() == tracker.ExportInt16Explorer)
|
||||||
}, filename)
|
}, filename)
|
||||||
|
case tracker.License:
|
||||||
|
dstyle := ConfirmDialog(gtx, t.Theme, t.LicenseDialog, "License", sointu.License)
|
||||||
|
dstyle.CancelStyle.Text = "Close"
|
||||||
|
dstyle.Layout(gtx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +155,7 @@ const (
|
|||||||
ExportInt16Explorer
|
ExportInt16Explorer
|
||||||
QuitChanges
|
QuitChanges
|
||||||
QuitSaveExplorer
|
QuitSaveExplorer
|
||||||
|
License
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxUndo = 64
|
const maxUndo = 64
|
||||||
|
Reference in New Issue
Block a user