diff --git a/gotolinedialog.go b/gotolinedialog.go new file mode 100755 index 0000000..70558a4 --- /dev/null +++ b/gotolinedialog.go @@ -0,0 +1,132 @@ +package main + +import ( + "strconv" + "strings" + + "github.com/gdamore/tcell/v2" + "github.com/fivemoreminix/qedit/ui" +) + +type GotoLineDialog struct { + LineChosenCallback func(int) + + x, y int + width, height int + focused bool + screen *tcell.Screen + theme *ui.Theme + + tabOrder []ui.Component + tabOrderIdx int + + inputField *ui.InputField + acceptButton *ui.Button + cancelButton *ui.Button +} + +func NewGotoLineDialog(s *tcell.Screen, theme *ui.Theme, lineChosenCallback func(int), cancelCallback func()) *GotoLineDialog { + dialog := &GotoLineDialog{ + LineChosenCallback: lineChosenCallback, + screen: s, + theme: theme, + } + + dialog.inputField = ui.NewInputField(s, nil, theme.GetOrDefault("Window")) + dialog.acceptButton = ui.NewButton("Go", theme, dialog.onConfirm) // TODO: callback + dialog.cancelButton = ui.NewButton("Cancel", theme, cancelCallback) + dialog.tabOrder = []ui.Component{dialog.inputField, dialog.cancelButton, dialog.acceptButton} + + return dialog +} + +func (d *GotoLineDialog) onConfirm() { + if d.LineChosenCallback != nil { + if len(d.inputField.Buffer) > 0 { + num, err := strconv.Atoi(strings.TrimSpace(string(d.inputField.Buffer))) + if err == nil { + d.LineChosenCallback(num) + } + } + } +} + +func (d *GotoLineDialog) Draw(s tcell.Screen) { + ui.DrawWindow(s, d.x, d.y, d.width, d.height, "Go to line", d.theme) + + btnWidth, _ := d.acceptButton.GetSize() + d.acceptButton.SetPos(d.x+d.width-btnWidth-1, d.y+4) // Place "Ok" button on right, bottom + + d.inputField.Draw(s) + d.acceptButton.Draw(s) + d.cancelButton.Draw(s) +} + +func (d *GotoLineDialog) SetFocused(v bool) { + d.focused = v + d.tabOrder[d.tabOrderIdx].SetFocused(v) +} + +func (d *GotoLineDialog) SetTheme(theme *ui.Theme) { + d.theme = theme + d.inputField.SetStyle(theme.GetOrDefault("Window")) + d.acceptButton.SetTheme(theme) + d.cancelButton.SetTheme(theme) +} + +func (d *GotoLineDialog) GetPos() (int, int) { + return d.x, d.y +} + +func (d *GotoLineDialog) SetPos(x, y int) { + d.x, d.y = x, y + d.inputField.SetPos(d.x+1, d.y+2) // Center input field + d.cancelButton.SetPos(d.x+1, d.y+4) // Place "Cancel" button on left, bottom +} + +func (d *GotoLineDialog) GetMinSize() (int, int) { + return 20, 6 +} + +func (d *GotoLineDialog) GetSize() (int, int) { + return d.width, d.height +} + +func (d *GotoLineDialog) SetSize(width, height int) { + minX, minY := d.GetMinSize() + d.width, d.height = ui.Max(width, minX), ui.Max(height, minY) + + d.inputField.SetSize(d.width-2, 1) + d.cancelButton.SetSize(d.cancelButton.GetMinSize()) + d.acceptButton.SetSize(d.acceptButton.GetMinSize()) +} + +func (d *GotoLineDialog) HandleEvent(event tcell.Event) bool { + switch ev := event.(type) { + case *tcell.EventKey: + switch ev.Key() { + case tcell.KeyTab: + d.tabOrder[d.tabOrderIdx].SetFocused(false) + + d.tabOrderIdx++ + if d.tabOrderIdx >= len(d.tabOrder) { + d.tabOrderIdx = 0 + } + + d.tabOrder[d.tabOrderIdx].SetFocused(true) + + return true + case tcell.KeyEsc: + if d.cancelButton.Callback != nil { + d.cancelButton.Callback() + } + return true + case tcell.KeyEnter: + if d.tabOrder[d.tabOrderIdx] == d.inputField { + d.onConfirm() + return true + } + } + } + return d.tabOrder[d.tabOrderIdx].HandleEvent(event) +} diff --git a/main.go b/main.go index 5e4e321..1bf5e78 100644 --- a/main.go +++ b/main.go @@ -347,8 +347,19 @@ func main() { }}, &ui.ItemSeparator{}, &ui.ItemEntry{Name: "Go to line...", Shortcut: "Ctrl+G", Callback: func() { te := getActiveTextEdit() if te != nil { - line := 50 - te.SetLineCol(line-1, 0) + callback := func(line int) { + te := getActiveTextEdit() + te.SetLineCol(line-1, 0) + // Hide dialog + dialog = nil + changeFocus(tabContainer) + } + dialog = NewGotoLineDialog(screen, &theme, callback, func() { + // Dialog canceled + dialog = nil + changeFocus(tabContainer) + }) + changeFocus(dialog) } }}})