diff --git a/editor.go b/editor.go index f6262ea..d349551 100755 --- a/editor.go +++ b/editor.go @@ -39,6 +39,9 @@ type Editor struct { LinesHead *LinesNode LineCount int + LineHeight float32 + CharWidth float32 + StartPos float32 } @@ -51,6 +54,23 @@ func (e *Editor) SetStartPos(mouseDeltaNorm int32) { e.StartPos = clampF32(e.StartPos+float32(-mouseDeltaNorm)*settings.ScrollSpeed, 0, float32(e.LineCount)) } +func (e *Editor) RefreshFontSettings() { + e.LineHeight = imgui.TextLineHeightWithSpacing() + + //NOTE: Because of 'https://github.com/ocornut/imgui/issues/792', CalcTextSize returns slightly incorrect width + //values for sentences than to be expected with singleCharWidth*sentenceCharCount. For example, with 3 chars at width 10 + //we expect width of 30 (for a fixed-width font), but instead we might get 29. + // This is fixed in the newer releases, but imgui-go hasn't updated yet. + // + //That's why instead of getting width of one char, we get the average width from the width of a sentence, which helps us position + //cursors properly for now + e.CharWidth = imgui.CalcTextSize("abcdefghijklmnopqrstuvwxyz", false, 1000).X / 26 +} + +func (e *Editor) RoundToNearestChar(x float32) float32 { + return float32(math.Round(float64(x/e.CharWidth))) * e.CharWidth +} + func (e *Editor) Render(drawStartPos, winSize *imgui.Vec2) { //Draw window @@ -67,52 +87,42 @@ func (e *Editor) Render(drawStartPos, winSize *imgui.Vec2) { paddedDrawStartPos := *drawStartPos //Draw lines - lineHeight := imgui.TextLineHeightWithSpacing() - charWidth := imgui.CalcTextSize("a", false, 1000).X - linesToDraw := int(winSize.Y / lineHeight) + linesToDraw := int(winSize.Y / e.LineHeight) // println("Lines to draw:", linesToDraw) dl := imgui.WindowDrawList() startLine := clampInt(int(e.StartPos), 0, e.LineCount) - println("Start Pos: ", e.StartPos, "; Start line:", startLine) for i := startLine; i < startLine+linesToDraw; i++ { dl.AddText(*drawStartPos, imgui.PackedColorFromVec4(imgui.Vec4{X: 1, Y: 1, Z: 1, W: 1}), string(e.GetLine(0+i).chars)) - drawStartPos.Y += lineHeight + drawStartPos.Y += e.LineHeight } - //Draw cursor - cx := clampInt(e.MouseX-int(paddedDrawStartPos.X), 0, int(winSize.X)) - cy := clampInt(e.MouseY-int(paddedDrawStartPos.Y), 0, int(winSize.Y)) + //Calculate position of cursor in window and grid coords. + //Window coords are as reported by SDL, but we correct for padding and snap to the nearest + //char window pos. + // + //Since gopad only supports fixed-width fonts, we treat the text area as a grid with each + //cell having identical width and one char. + clickedColWindowY := clampInt(e.MouseY-int(paddedDrawStartPos.Y), 0, math.MaxInt) + clickedColGridY := clampInt(clickedColWindowY/int(e.LineHeight), 0, e.LineCount) - clickedLine := clampInt(cy/int(lineHeight), 0, e.LineCount) - clickedCol := cx / int(charWidth) - // fmt.Printf("line,col: %v,%v\n", clickedLine, clickedCol) + clickedColWindowX := clampInt(int(e.RoundToNearestChar(float32(e.MouseX))), 0, math.MaxInt) + clickedColGridX := clickedColWindowX / int(e.CharWidth) - eee := e.GetLine(clickedLine) - tabCount, tabChars := getTabs(eee, clickedCol) + clickedLine := e.GetLine(startLine + clickedColGridY) + tabCount, _ := getTabs(clickedLine, clickedColGridX) - maxCol := len(eee.chars) - 1 - if tabCount > 0 { - maxCol += clampInt(tabCount*settings.TabSize, 0, math.MaxInt) - } - finalCol := clampInt(clickedCol+tabChars, 0, maxCol) - // if len(eee.chars) > 0 && finalCol > 0 { - // x := finalCol - tabCount*settings.TabSize - // println("!!!!", len(string(eee.chars)), "; C:", string(eee.chars[x])) - // } - - lineX := paddedDrawStartPos.X + float32(finalCol)*charWidth + textWidth := float32(len(clickedLine.chars)-tabCount+tabCount*settings.TabSize) * e.CharWidth + lineX := clampF32(float32(clickedColWindowX), 0, paddedDrawStartPos.X+textWidth) lineStart := imgui.Vec2{ X: lineX, - Y: paddedDrawStartPos.Y + float32(clickedLine)*lineHeight - lineHeight*0.25, + Y: paddedDrawStartPos.Y + float32(clickedColGridY)*e.LineHeight - e.LineHeight*0.25, } lineEnd := imgui.Vec2{ X: lineX, - Y: paddedDrawStartPos.Y + float32(clickedLine)*lineHeight + lineHeight*0.75, + Y: paddedDrawStartPos.Y + float32(clickedColGridY)*e.LineHeight + e.LineHeight*0.75, } - - thickness := 0.2 * charWidth - dl.AddLineV(lineStart, lineEnd, imgui.PackedColorFromVec4(imgui.Vec4{Z: 0.7, W: 1}), thickness) + dl.AddLineV(lineStart, lineEnd, imgui.PackedColorFromVec4(imgui.Vec4{Z: 0.7, W: 1}), settings.CursorWidthFactor*e.CharWidth) } func getTabs(l *Line, col int) (tabCount, charsToOffsetBy int) { @@ -247,6 +257,7 @@ func NewScratchEditor() *Editor { FileName: "**scratch**", LinesHead: NewLineNode(), } + return e } diff --git a/go.mod b/go.mod index a2c39cc..cb56ae9 100755 --- a/go.mod +++ b/go.mod @@ -3,12 +3,13 @@ module github.com/bloeys/gopad go 1.17 require ( - github.com/bloeys/nmage v0.0.8 + github.com/bloeys/nmage v0.0.10 github.com/inkyblackness/imgui-go/v4 v4.3.0 github.com/veandco/go-sdl2 v0.4.14 ) require ( + github.com/bloeys/assimp-go v0.4.2 // indirect github.com/bloeys/gglm v0.3.1 // indirect github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect ) diff --git a/go.sum b/go.sum index 0812842..86eb488 100755 --- a/go.sum +++ b/go.sum @@ -1,8 +1,13 @@ +github.com/bloeys/assimp-go v0.4.2 h1:ArVK74BCFcTO/rCGj2NgZG9xtbjnJdEn5npIeJx1Z04= github.com/bloeys/assimp-go v0.4.2/go.mod h1:my3yRxT7CfOztmvi+0svmwbaqw0KFrxaHxncoyaEIP0= github.com/bloeys/gglm v0.3.1 h1:Sy9upW7SBsBfDXrSmEhid3aQ+7J7itej+upwcxOnPMQ= github.com/bloeys/gglm v0.3.1/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk= github.com/bloeys/nmage v0.0.8 h1:HCoEaTBWTucnXrjQ+8OCUTzG/3rjpV1eliXWUW44+FY= github.com/bloeys/nmage v0.0.8/go.mod h1:4h2tKtMvk9ab8r/+rem4QonPXEBTho6VWvpCMm0M6iM= +github.com/bloeys/nmage v0.0.9 h1:dP0g8e7VeygbX5AcYLTIPheLJr+CZmG2uOICQfcDTDA= +github.com/bloeys/nmage v0.0.9/go.mod h1:4h2tKtMvk9ab8r/+rem4QonPXEBTho6VWvpCMm0M6iM= +github.com/bloeys/nmage v0.0.10 h1:6Ryl3qjEbXxeIL+9BnBxOrGaW9mKObyY/JbRYkR8ogQ= +github.com/bloeys/nmage v0.0.10/go.mod h1:4h2tKtMvk9ab8r/+rem4QonPXEBTho6VWvpCMm0M6iM= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-gl/gl v0.0.0-20211025173605-bda47ffaa784/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw= diff --git a/main.go b/main.go index 704a97f..ed60151 100755 --- a/main.go +++ b/main.go @@ -6,9 +6,11 @@ import ( "os" "path/filepath" + "github.com/bloeys/gopad/settings" "github.com/bloeys/nmage/engine" "github.com/bloeys/nmage/input" "github.com/bloeys/nmage/logging" + "github.com/bloeys/nmage/renderer/rend3dgl" nmageimgui "github.com/bloeys/nmage/ui/imgui" "github.com/inkyblackness/imgui-go/v4" "github.com/veandco/go-sdl2/sdl" @@ -56,7 +58,7 @@ func main() { panic(err) } - window, err := engine.CreateOpenGLWindowCentered("nMage", 1280, 720, engine.WindowFlags_RESIZABLE|engine.WindowFlags_ALLOW_HIGHDPI) + window, err := engine.CreateOpenGLWindowCentered("nMage", 1280, 720, engine.WindowFlags_RESIZABLE|engine.WindowFlags_ALLOW_HIGHDPI, rend3dgl.NewRend3DGL()) if err != nil { logging.ErrLog.Fatalln("Failed to create window. Err: ", err) } @@ -86,13 +88,12 @@ func (g *Gopad) Init() { g.Win.EventCallbacks = append(g.Win.EventCallbacks, g.handleWindowEvents) //Setup font - var fontSize float32 = 16 fConfig := imgui.NewFontConfig() defer fConfig.Delete() fConfig.SetOversampleH(2) fConfig.SetOversampleV(2) - g.mainFont = g.ImGUIInfo.AddFontTTF("./res/fonts/courier-prime.regular.ttf", fontSize, &fConfig, nil) + g.mainFont = g.ImGUIInfo.AddFontTTF("./res/fonts/courier-prime.regular.ttf", settings.FontSize, &fConfig, nil) //Sidebar g.CurrDirContents = getDirContents(g.CurrDir) @@ -121,6 +122,15 @@ func (g *Gopad) Init() { g.activeEditor = len(g.editors) - 1 } +func (g *Gopad) Start() { + imgui.PushFont(g.mainFont) + for i := 0; i < len(g.editors); i++ { + e := &g.editors[i] + e.RefreshFontSettings() + } + imgui.PopFont() +} + func (g *Gopad) handleWindowEvents(event sdl.Event) { switch e := event.(type) { @@ -361,7 +371,8 @@ func (g *Gopad) getActiveEditor() *Editor { func (g *Gopad) getEditor(index int) *Editor { if len(g.editors) == 0 { - e := Editor{FileName: "**scratch**"} + e := *NewScratchEditor() + e.RefreshFontSettings() g.editors = append(g.editors, e) g.activeEditor = 0 return &e @@ -420,7 +431,9 @@ func (g *Gopad) handleFileClick(fPath string) { } //Read new file and switch to it - g.editors = append(g.editors, *NewEditor(fPath)) + e := *NewEditor(fPath) + e.RefreshFontSettings() + g.editors = append(g.editors, e) g.activeEditor = len(g.editors) - 1 } diff --git a/settings/settings.go b/settings/settings.go index 690ec92..d91bbbe 100755 --- a/settings/settings.go +++ b/settings/settings.go @@ -3,8 +3,10 @@ package settings import "github.com/inkyblackness/imgui-go/v4" var ( + FontSize float32 = 16 TextSelectionColor imgui.Vec4 = imgui.Vec4{X: 84 / 255.0, Y: 153 / 255.0, Z: 199 / 255.0, W: 0.4} EditorBgColor imgui.Vec4 = imgui.Vec4{X: 0.1, Y: 0.1, Z: 0.1, W: 1} TabSize int = 4 ScrollSpeed float32 = 4 + CursorWidthFactor float32 = 0.15 )