1
0
Fork 0
gnums/main.go

304 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"os"
"strconv"
"strings"
g "github.com/AllenDang/giu"
)
const (
MasterWidth int = 382
Version string = "0.1.1"
FullStack int = iota
TopThree
TopOfStack
Dsc
Asc
)
type Input struct {
buf strings.Builder
decimal bool
negative bool
}
func (i *Input) String() string {
return i.buf.String()
}
func (i *Input) Append(value rune) {
switch value {
case '.':
if i.decimal {
return
}
if i.buf.Len() == 0 {
i.buf.WriteRune('0')
}
i.decimal = true
i.buf.WriteRune(value)
case '-':
if i.buf.Len() > 0 {
return
}
i.negative = true
i.buf.WriteRune(value)
default:
i.buf.WriteRune(value)
}
inputDisplay = i.String()
SetComboOut()
}
func (i *Input) Store() {
if i.buf.Len() == 0 {
return
}
if i.buf.Len() == 1 && (i.negative || i.decimal) {
i.Reset()
return
}
num, err := strconv.ParseFloat(i.buf.String(), 64)
if err != nil {
panic("Bad input")
}
s.Push(num)
i.Reset()
inputDisplay = ""
}
func (i *Input) Reset() {
i.buf.Reset()
i.decimal = false
i.negative = false
}
func (i *Input) Delete() {
if i.buf.Len() == 0 {
return
}
val := i.buf.String()
popped := val[len(val)-1]
i.buf.Reset()
i.buf.WriteString(val[:len(val)-1])
if popped == '.' {
i.decimal = false
} else if popped == '-' {
i.negative = false
}
inputDisplay = i.String()
SetComboOut()
}
var (
wnd *g.MasterWindow
inputBuffer *Input = &Input{}
s *stack = &stack{-1, [100]float64{}}
stackStyle int = FullStack
inputDisplay string = inputBuffer.String()
outputDisplay string = s.String()
comboDisplay string = inputBuffer.String()
Display *g.InputTextWidget = g.InputText("", &inputDisplay)
Output *g.InputTextMultilineWidget = g.InputTextMultiline("", &outputDisplay)
ComboView *g.InputTextWidget = g.InputText("", &comboDisplay)
ShowStack bool = true
stackSort int = Dsc
stackLabel *g.LabelWidget = g.Label("Stack Output\n[d]{TOS ...}")
)
func callStackWord(f func()) {
inputBuffer.Store()
f()
outputDisplay = s.String()
SetComboOut()
}
func SetComboOut() {
if inputBuffer.buf.Len() > 0 {
comboDisplay = inputBuffer.String()
} else {
comboDisplay = strconv.FormatFloat(s.Peek(), 'f', -1, 64)
}
}
func SetStackLabelWithSort() {
sort := "TOS ..."
if stackSort == Asc {
sort = "... TOS"
}
stackLabel = g.Label(fmt.Sprintf("Stack Output\n[d]{%s}", sort))
}
func ToggleScreenSize() {
width := MasterWidth
if ShowStack {
width = MasterWidth + MasterWidth / 2
}
wnd.SetSize(width,400)
}
func loop() {
g.SingleWindowWithMenuBar("gnums - " + Version).Layout(
g.MenuBar().Layout(
g.Menu("File").Layout(
g.MenuItem("Exit").OnClick(Exit),
),
g.Menu("Edit").Layout(
g.MenuItem("Copy TOS"),
g.MenuItem("Copy Stack"),
g.MenuItem("Clear Stack"),
),
g.Menu("Settings").Layout(
g.Checkbox("Show Stack Window", &ShowStack).OnChange(ToggleScreenSize),
g.Menu("Output Style").Layout(
g.RadioButton("Full Stack", stackStyle == FullStack).OnChange(func(){stackStyle = FullStack; outputDisplay = s.String()}),
g.RadioButton("Top Three", stackStyle == TopThree).OnChange(func(){stackStyle = TopThree; outputDisplay = s.String()}),
g.RadioButton("Top Of Stack", stackStyle == TopOfStack).OnChange(func(){stackStyle = TopOfStack; outputDisplay = s.String()}),
),
g.Menu("Stack Sort").Layout(
g.RadioButton("TOS ...", stackSort == Dsc).OnChange(func(){stackSort = Dsc; SetStackLabelWithSort()}),
g.RadioButton("... TOS", stackSort == Asc).OnChange(func(){stackSort = Asc; SetStackLabelWithSort()}),
),
),
),
g.Row(
g.Label("gnums v" + Version),
),
g.Dummy(0, 8),
ComboView.Size(-1).Flags(1 << 14),
g.Dummy(0, 8),
g.Row(
g.Condition(ShowStack, g.Layout{
g.Row(
g.Child("Left").Layout(
stackLabel,
g.Tooltip("Stack display is\nnewest on top"),
Output.Size(-1, -1).Flags(1 << 14),
).Size(
float32(MasterWidth/2), -1,
),
g.Child("Section").Layout(
g.Row(
g.Button("Clear").Size(50,50).OnClick(func(){callStackWord(s.Clear)}),
g.Button("Delete").Size(50,50).OnClick(func(){inputBuffer.Delete()}),
g.Button("Round").Size(50,50).OnClick(func(){callStackWord(s.Round)}),
g.Button("^").Size(50,50).OnClick(func(){callStackWord(s.Pow)}),
g.Button("÷").Size(50,50).OnClick(func(){callStackWord(s.Div)}),
g.Button("Sqrt").Size(50,50).OnClick(func(){callStackWord(s.Sqt)}),
),
g.Row(
g.Button("Over").Size(50,50).OnClick(func(){callStackWord(s.Ovr)}),
g.Button("7").Size(50,50).OnClick(func(){inputBuffer.Append('7')}),
g.Button("8").Size(50,50).OnClick(func(){inputBuffer.Append('8')}),
g.Button("9").Size(50,50).OnClick(func(){inputBuffer.Append('9')}),
g.Button("×").Size(50,50).OnClick(func(){callStackWord(s.Mul)}),
g.Button("Floor").Size(50,50).OnClick(func(){callStackWord(s.Floor)}),
),
g.Row(
g.Button("Swap").Size(50,50).OnClick(func(){callStackWord(s.Swp)}),
g.Button("4").Size(50,50).OnClick(func(){inputBuffer.Append('4')}),
g.Button("5").Size(50,50).OnClick(func(){inputBuffer.Append('5')}),
g.Button("6").Size(50,50).OnClick(func(){inputBuffer.Append('6')}),
g.Button("-").Size(50,50).OnClick(func(){callStackWord(s.Sub)}),
g.Button("Ceil").Size(50,50).OnClick(func(){callStackWord(s.Ceil)}),
),
g.Row(
g.Button("Dup").Size(50,50).OnClick(func(){callStackWord(s.Dup)}),
g.Button("1").Size(50,50).OnClick(func(){inputBuffer.Append('1')}),
g.Button("2").Size(50,50).OnClick(func(){inputBuffer.Append('2')}),
g.Button("3").Size(50,50).OnClick(func(){inputBuffer.Append('3')}),
g.Button("+").Size(50,50).OnClick(func(){callStackWord(s.Add)}),
g.Button("+/-").Size(50,50).OnClick(func(){callStackWord(s.Inv)}),
),
g.Row(
g.Button("Drop").Size(50,50).OnClick(func(){callStackWord(s.Drp)}),
g.Button(".").Size(50,50).OnClick(func(){inputBuffer.Append('.')}),
g.Button("0").Size(50,50).OnClick(func(){inputBuffer.Append('0')}),
g.Button("Enter").Size(165,50).OnClick(func(){inputBuffer.Store(); outputDisplay = s.String()}),
),
),
),
}, g.Layout{
g.Child("Button Section").Layout(
g.Row(
g.Button("Clear").Size(50,50).OnClick(func(){callStackWord(s.Clear)}),
g.Button("Delete").Size(50,50).OnClick(func(){inputBuffer.Delete()}),
g.Button("Round").Size(50,50).OnClick(func(){callStackWord(s.Round)}),
g.Button("^").Size(50,50).OnClick(func(){callStackWord(s.Pow)}),
g.Button("÷").Size(50,50).OnClick(func(){callStackWord(s.Div)}),
g.Button("Sqrt").Size(50,50).OnClick(func(){callStackWord(s.Sqt)}),
),
g.Row(
g.Button("Over").Size(50,50).OnClick(func(){callStackWord(s.Ovr)}),
g.Button("7").Size(50,50).OnClick(func(){inputBuffer.Append('7')}),
g.Button("8").Size(50,50).OnClick(func(){inputBuffer.Append('8')}),
g.Button("9").Size(50,50).OnClick(func(){inputBuffer.Append('9')}),
g.Button("×").Size(50,50).OnClick(func(){callStackWord(s.Mul)}),
g.Button("Floor").Size(50,50).OnClick(func(){callStackWord(s.Floor)}),
),
g.Row(
g.Button("Swap").Size(50,50).OnClick(func(){callStackWord(s.Swp)}),
g.Button("4").Size(50,50).OnClick(func(){inputBuffer.Append('4')}),
g.Button("5").Size(50,50).OnClick(func(){inputBuffer.Append('5')}),
g.Button("6").Size(50,50).OnClick(func(){inputBuffer.Append('6')}),
g.Button("-").Size(50,50).OnClick(func(){callStackWord(s.Sub)}),
g.Button("Ceil").Size(50,50).OnClick(func(){callStackWord(s.Ceil)}),
),
g.Row(
g.Button("Dup").Size(50,50).OnClick(func(){callStackWord(s.Dup)}),
g.Button("1").Size(50,50).OnClick(func(){inputBuffer.Append('1')}),
g.Button("2").Size(50,50).OnClick(func(){inputBuffer.Append('2')}),
g.Button("3").Size(50,50).OnClick(func(){inputBuffer.Append('3')}),
g.Button("+").Size(50,50).OnClick(func(){callStackWord(s.Add)}),
g.Button("+/-").Size(50,50).OnClick(func(){callStackWord(s.Inv)}),
),
g.Row(
g.Button("Drop").Size(50,50).OnClick(func(){callStackWord(s.Drp)}),
g.Button(".").Size(50,50).OnClick(func(){inputBuffer.Append('.')}),
g.Button("0").Size(50,50).OnClick(func(){inputBuffer.Append('0')}),
g.Button("Enter").Size(165,50).OnClick(func(){inputBuffer.Store(); outputDisplay = s.String()}),
),
),
}),
),
)
}
func Exit() {
os.Exit(0)
}
func main() {
wnd = g.NewMasterWindow("gnums", MasterWidth+MasterWidth/2, 405, g.MasterWindowFlagsNotResizable).RegisterKeyboardShortcuts(
g.WindowShortcut{Key: g.KeyQ, Modifier: g.ModControl, Callback: Exit},
g.WindowShortcut{Key: g.Key0, Callback: func(){inputBuffer.Append('0')}},
g.WindowShortcut{Key: g.Key1, Callback: func(){inputBuffer.Append('1')}},
g.WindowShortcut{Key: g.Key2, Callback: func(){inputBuffer.Append('2')}},
g.WindowShortcut{Key: g.Key3, Callback: func(){inputBuffer.Append('3')}},
g.WindowShortcut{Key: g.Key4, Callback: func(){inputBuffer.Append('4')}},
g.WindowShortcut{Key: g.Key5, Callback: func(){inputBuffer.Append('5')}},
g.WindowShortcut{Key: g.Key6, Callback: func(){inputBuffer.Append('6')}},
g.WindowShortcut{Key: g.Key7, Callback: func(){inputBuffer.Append('7')}},
g.WindowShortcut{Key: g.Key8, Callback: func(){inputBuffer.Append('8')}},
g.WindowShortcut{Key: g.Key9, Callback: func(){inputBuffer.Append('9')}},
g.WindowShortcut{Key: g.KeyPeriod, Callback: func(){inputBuffer.Append('.')}},
g.WindowShortcut{Key: g.KeyMinus, Callback: func(){callStackWord(s.Sub)}},
g.WindowShortcut{Key: g.KeyEqual, Modifier: g.ModShift, Callback: func(){callStackWord(s.Add)}},
g.WindowShortcut{Key: g.Key8, Modifier: g.ModShift, Callback: func(){callStackWord(s.Mul)}},
g.WindowShortcut{Key: g.KeySlash, Callback: func(){callStackWord(s.Div)}},
g.WindowShortcut{Key: g.Key6, Modifier: g.ModShift, Callback: func(){callStackWord(s.Pow)}},
g.WindowShortcut{Key: g.KeyEnter, Callback: func(){inputBuffer.Store(); outputDisplay = s.String()}},
g.WindowShortcut{Key: g.KeySpace, Callback: func(){ShowStack = !ShowStack; ToggleScreenSize()}},
g.WindowShortcut{Key: g.KeyEscape, Callback: func(){callStackWord(s.Clear)}},
g.WindowShortcut{Key: g.Key1, Modifier: g.ModShift, Callback: func(){callStackWord(s.Inv)}},
g.WindowShortcut{Key: g.KeyBackspace, Callback: func(){inputBuffer.Delete()}},
)
wnd.Run(loop)
}