Skip to content

Commit

Permalink
Merge pull request #54 from ja-he/refactor-editor-ui-creation
Browse files Browse the repository at this point in the history
refactor(tui): Implement Event-Editor via generic editor

probably some unfinished work in here
  • Loading branch information
ja-he authored Jul 1, 2024
2 parents 3c6624a + 3453995 commit 5be0d02
Show file tree
Hide file tree
Showing 12 changed files with 509 additions and 747 deletions.
196 changes: 89 additions & 107 deletions internal/control/cli/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,20 @@ func NewController(
"<right>": "move-cursor-rune-right",
"0": "move-cursor-to-beginning",
"$": "move-cursor-to-end",
"w": "move-cursor-to-next-word-beginning",
"b": "move-cursor-to-prev-word-beginning",
"e": "move-cursor-to-next-word-end",
"<ESC>": "quit",
"D": "delete-to-end",
"d$": "delete-to-end",
"d0": "backspace-to-beginning",
"C": "delete-to-end-and-insert",
"c$": "delete-to-end-and-insert",
"c0": "backspace-to-beginning-and-insert",
"x": "delete-rune",
"s": "delete-rune-and-insert",
"i": "swap-mode-insert",
"a": "swap-mode-insert-append",
},
Insert: map[input.Keyspec]input.Actionspec{
"<left>": "move-cursor-rune-left",
Expand Down Expand Up @@ -207,14 +213,7 @@ func NewController(
screenWidth, screenHeight := screenSize()
return 0, 0, screenWidth, screenHeight
}
centeredFloat := func(floatWidth, floatHeight int) func() (x, y, w, h int) {
return func() (x, y, w, h int) {
screenWidth, screenHeight := screenSize()
return (screenWidth / 2) - (floatWidth / 2), (screenHeight / 2) - (floatHeight / 2), floatWidth, floatHeight
}
}
helpDimensions := screenDimensions
editorDimensions := centeredFloat(editorWidth, editorHeight)
tasksDimensions := func() (x, y, w, h int) {
screenWidth, screenHeight := screenSize()
return screenWidth - rightFlexWidth, 0, tasksWidth, screenHeight - statusHeight
Expand All @@ -227,6 +226,12 @@ func NewController(
screenWidth, screenHeight := screenSize()
return 0, screenHeight - statusHeight, screenWidth, statusHeight
}
editorDimensions := func() (x, y, w, h int) {
screenWidth, screenHeight := screenSize()
taskEditorBoxWidth := int(math.Min(float64(editorWidth), float64(screenWidth)))
taskEditorBoxHeight := int(math.Min(float64(editorHeight), float64(screenHeight)))
return (screenWidth / 2) - (taskEditorBoxWidth / 2), (screenHeight / 2) - (taskEditorBoxHeight / 2), taskEditorBoxWidth, taskEditorBoxHeight
}
dayViewMainPaneDimensions := screenDimensions
dayViewScrollablePaneDimensions := func() (x, y, w, h int) {
parentX, parentY, parentW, parentH := dayViewMainPaneDimensions()
Expand Down Expand Up @@ -460,7 +465,7 @@ func NewController(
log.Warn().Msg("apparently, task editor was still active when a new one was activated, unexpected / error")
}
var err error
taskEditor, err := editors.ConstructEditor("root", task, nil, func() (bool, bool) { return true, true })
taskEditor, err := editors.ConstructEditor("root", task, nil, nil)
if err != nil {
log.Error().Err(err).Interface("task", task).Msg("was not able to construct editor for task")
return
Expand All @@ -472,24 +477,21 @@ func NewController(
controller.data.TaskEditor = nil
return
}
taskEditorPane, err := controller.data.TaskEditor.GetPane(
ui.NewConstrainedRenderer(renderer, func() (x, y, w, h int) {
screenWidth, screenHeight := screenSize()
taskEditorBoxWidth := int(math.Min(80, float64(screenWidth)))
taskEditorBoxHeight := int(math.Min(20, float64(screenHeight)))
return (screenWidth / 2) - (taskEditorBoxWidth / 2), (screenHeight / 2) - (taskEditorBoxHeight / 2), taskEditorBoxWidth, taskEditorBoxHeight
}),

taskEditorRenderer := ui.NewConstrainedRenderer(renderer, editorDimensions)

taskEditorPane, err := panes.NewCompositeEditorPane(
taskEditorRenderer,
cursorWrangler,
func() bool { return true },
inputConfig,
stylesheet,
cursorWrangler,
controller.data.TaskEditor,
)
if err != nil {
log.Error().Err(err).Msgf("could not construct task editor pane")
controller.data.TaskEditor = nil
return
log.Fatal().Err(err).Msg("could not construct task editor pane (this is likely a serious programming error / omission)")
}
log.Info().Str("info", taskEditorPane.(*panes.CompositeEditorPane).GetDebugInfo()).Msg("here is the debug info for the task editor pane")

controller.rootPane.PushSubpane(taskEditorPane)
taskEditorDone := make(chan struct{})
controller.data.TaskEditor.AddQuitCallback(func() {
Expand Down Expand Up @@ -716,7 +718,6 @@ func NewController(
}
}
var startMovePushing func()
var pushEditorAsRootSubpane func()
// TODO: directly?
eventsPaneDayInputExtension := map[input.Keyspec]action.Action{
"j": action.NewSimple(func() string { return "switch to next event" }, func() {
Expand All @@ -741,10 +742,50 @@ func NewController(
}),
"<cr>": action.NewSimple(func() string { return "open the event editor" }, func() {
event := controller.data.GetCurrentDay().Current
if event != nil {
controller.data.EventEditor.Activate(event)
if event == nil {
log.Warn().Msgf("ignoring event editing request since no current event selected")
return
}
pushEditorAsRootSubpane()

if controller.data.EventEditor != nil {
log.Warn().Msgf("was about to construct new event editor but still have old one")
return
}
newEventEditor, err := editors.ConstructEditor("event", event, nil, nil)
if err != nil {
log.Warn().Err(err).Msgf("unable to construct event editor")
return
}
var ok bool
controller.data.EventEditor, ok = newEventEditor.(*editors.Composite)
if !ok {
log.Error().Msgf("something went _really_ wrong and the editor constructed for the event is _not_ a composite editor but a %T", newEventEditor)
controller.data.EventEditor = nil
return
}

eventEditorRenderer := ui.NewConstrainedRenderer(renderer, editorDimensions)
eventEditorPane, err := panes.NewCompositeEditorPane(
eventEditorRenderer,
cursorWrangler,
func() bool { return true },
inputConfig,
stylesheet,
controller.data.EventEditor,
)
if err != nil {
log.Fatal().Err(err).Msg("could not construct event editor pane (this is likely a serious programming error / omission)")
}

controller.rootPane.PushSubpane(eventEditorPane)
eventEditorDone := make(chan struct{})
controller.data.EventEditor.AddQuitCallback(func() {
close(eventEditorDone) // TODO: this can CERTAINLY happen twice; prevent
})
go func() {
<-eventEditorDone
controller.controllerEvents <- ControllerEventEventEditorExit
}()
}),
"o": action.NewSimple(func() string { return "add event after selected" }, func() {
current := controller.data.GetCurrentDay().Current
Expand Down Expand Up @@ -1302,61 +1343,6 @@ func NewController(
stderrLogger.Fatal().Err(err).Msg("failed to construct input tree for summary pane")
}

var editorStartInsertMode func()
var editorLeaveInsertMode func()
editorInsertMode, err := processors.NewTextInputProcessor( // TODO rename
map[input.Keyspec]action.Action{
"<ESC>": action.NewSimple(func() string { return "exit insert mode" }, func() { editorLeaveInsertMode() }),
"<c-a>": action.NewSimple(func() string { return "move cursor to beginning" }, controller.data.EventEditor.MoveCursorToBeginning),
"<del>": action.NewSimple(func() string { return "delete character" }, controller.data.EventEditor.DeleteRune),
"<c-d>": action.NewSimple(func() string { return "delete character" }, controller.data.EventEditor.DeleteRune),
"<c-bs>": action.NewSimple(func() string { return "backspace" }, controller.data.EventEditor.BackspaceRune),
"<bs>": action.NewSimple(func() string { return "backspace" }, controller.data.EventEditor.BackspaceRune),
"<c-e>": action.NewSimple(func() string { return "move cursor to end" }, controller.data.EventEditor.MoveCursorToEnd),
"<c-u>": action.NewSimple(func() string { return "backspace to beginning" }, controller.data.EventEditor.BackspaceToBeginning),
"<left>": action.NewSimple(func() string { return "move cursor left" }, controller.data.EventEditor.MoveCursorLeft),
"<right>": action.NewSimple(func() string { return "move cursor right" }, controller.data.EventEditor.MoveCursorRight),
},
controller.data.EventEditor.AddRune,
)
if err != nil {
log.Fatal().Err(err).Msgf("could not construct editor insert mode processor")
}
editorNormalModeTree, err := input.ConstructInputTree(
map[input.Keyspec]action.Action{
"<esc>": action.NewSimple(func() string { return "abord edit, discard changes" }, controller.abortEdit),
"<cr>": action.NewSimple(func() string { return "finish edit, commit changes" }, controller.endEdit),
"i": action.NewSimple(func() string { return "enter insert mode" }, func() { editorStartInsertMode() }),
"a": action.NewSimple(func() string { return "enter insert mode (after character)" }, func() {
controller.data.EventEditor.MoveCursorRightA()
editorStartInsertMode()
}),
"A": action.NewSimple(func() string { return "enter insert mode (at end)" }, func() {
controller.data.EventEditor.MoveCursorPastEnd()
editorStartInsertMode()
}),
"0": action.NewSimple(func() string { return "move cursor to beginning" }, controller.data.EventEditor.MoveCursorToBeginning),
"$": action.NewSimple(func() string { return "move cursor to end" }, controller.data.EventEditor.MoveCursorToEnd),
"h": action.NewSimple(func() string { return "move cursor left" }, controller.data.EventEditor.MoveCursorLeft),
"l": action.NewSimple(func() string { return "move cursor right" }, controller.data.EventEditor.MoveCursorRight),
"w": action.NewSimple(func() string { return "move cursor to next word beginning" }, controller.data.EventEditor.MoveCursorNextWordBeginning),
"b": action.NewSimple(func() string { return "move cursor to previous word beginning" }, controller.data.EventEditor.MoveCursorPrevWordBeginning),
"e": action.NewSimple(func() string { return "move cursor to next word end" }, controller.data.EventEditor.MoveCursorNextWordEnd),
"x": action.NewSimple(func() string { return "delete character" }, controller.data.EventEditor.DeleteRune),
"C": action.NewSimple(func() string { return "delete to end" }, func() {
controller.data.EventEditor.DeleteToEnd()
editorStartInsertMode()
}),
"dd": action.NewSimple(func() string { return "clear text content" }, func() { controller.data.EventEditor.Clear() }),
"cc": action.NewSimple(func() string { return "clear text content, enter insert" }, func() {
controller.data.EventEditor.Clear()
editorStartInsertMode()
}),
},
)
if err != nil {
stderrLogger.Fatal().Err(err).Msg("failed to construct input tree for editor pane's normal mode")
}
helpPaneInputTree, err := input.ConstructInputTree(
map[input.Keyspec]action.Action{
"?": action.NewSimple(func() string { return "close help" }, func() {
Expand All @@ -1374,26 +1360,6 @@ func NewController(
func() bool { return controller.data.ShowHelp },
processors.NewModalInputProcessor(helpPaneInputTree),
)
editorPane := panes.NewEventEditorPane(
ui.NewConstrainedRenderer(renderer, editorDimensions),
cursorWrangler,
editorDimensions,
stylesheet,
func() bool { return controller.data.EventEditor.Active },
func() string { return controller.data.EventEditor.TmpEventInfo.Name },
controller.data.EventEditor.GetMode,
func() int { return controller.data.EventEditor.CursorPos },
processors.NewModalInputProcessor(editorNormalModeTree),
)
pushEditorAsRootSubpane = func() { controller.rootPane.PushSubpane(editorPane) }
editorStartInsertMode = func() {
editorPane.ApplyModalOverlay(editorInsertMode)
controller.data.EventEditor.SetMode(input.TextEditModeInsert)
}
editorLeaveInsertMode = func() {
editorPane.PopModalOverlay()
controller.data.EventEditor.SetMode(input.TextEditModeNormal)
}

rootPane := panes.NewRootPane(
renderer,
Expand Down Expand Up @@ -1489,7 +1455,6 @@ func NewController(
helpPane.Content = rootPane.GetHelp()
}

controller.data.EventEditor.SetMode(input.TextEditModeNormal)
controller.data.EventEditMode = edit.EventEditModeNormal

coordinatesProvided := (envData.Latitude != "" && envData.Longitude != "")
Expand Down Expand Up @@ -1589,20 +1554,23 @@ func (t *Controller) ScrollBottom() {
func (t *Controller) abortEdit() {
t.data.MouseEditState = edit.MouseEditStateNone
t.data.MouseEditedEvent = nil
t.data.EventEditor.Active = false
if t.data.EventEditor != nil {
t.data.EventEditor.Quit()
t.data.EventEditor = nil
}
t.rootPane.PopSubpane()
}

func (t *Controller) endEdit() {
t.data.MouseEditState = edit.MouseEditStateNone
t.data.MouseEditedEvent = nil
if t.data.EventEditor.Active {
t.data.EventEditor.Active = false
tmp := t.data.EventEditor.TmpEventInfo
t.data.EventEditor.Original.Name = tmp.Name
if t.data.EventEditor != nil {
t.data.EventEditor.Write()
t.data.EventEditor.Quit()
t.data.EventEditor = nil
}
t.data.GetCurrentDay().UpdateEventOrder()
t.rootPane.PopSubpane()
t.rootPane.PopSubpane() // TODO: this will need to be re-done conceptually
}

func (t *Controller) startMouseMove(eventsInfo *ui.EventsPanePositionInfo) {
Expand Down Expand Up @@ -1788,7 +1756,7 @@ func (t *Controller) handleMouseNoneEditEvent(e *tcell.EventMouse) {
case ui.EventBoxInterior:
t.startMouseMove(eventsInfo)
case ui.EventBoxTopEdge:
t.data.EventEditor.Activate(eventsInfo.Event)
log.Info().Msgf("would construct editor here, once the programmer has figured out how to do so correctly")
}

case tcell.WheelUp:
Expand Down Expand Up @@ -1876,6 +1844,7 @@ const (
ControllerEventExit ControllerEvent = iota
ControllerEventRender
ControllerEventTaskEditorExit
ControllerEventEventEditorExit
)

// Empties all render events from the channel.
Expand Down Expand Up @@ -1941,8 +1910,21 @@ func (t *Controller) Run() {
go func() { t.controllerEvents <- ControllerEventRender }()
}

case ControllerEventEventEditorExit:
if t.data.EventEditor == nil {
log.Warn().Msgf("got event editor exit event, but no event editor active; likely logic error")
} else {
t.data.EventEditor = nil
t.rootPane.PopSubpane()
log.Debug().Msgf("removed (presumed) event-editor subpane from root")
go func() { t.controllerEvents <- ControllerEventRender }()
}

case ControllerEventExit:
return

default:
log.Error().Interface("event", controllerEvent).Msgf("unhandled controller event")
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/control/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ type ControlData struct {
CurrentDate model.Date
Weather weather.Handler

EventEditor editors.EventEditor
EventEditor *editors.Composite
TaskEditor *editors.Composite

ShowLog bool
Expand Down
Loading

0 comments on commit 5be0d02

Please sign in to comment.