mirror of
https://github.com/bloeys/gopad.git
synced 2025-12-29 15:08:21 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 50b5a5819a | |||
| e4fc3feda9 | |||
| 1f62c3ae60 | |||
| 5b15017fc6 | |||
| 967c9815a0 | |||
| cf20686a43 |
133
editor.go
133
editor.go
@ -5,19 +5,22 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
imgui "github.com/AllenDang/cimgui-go"
|
||||||
"github.com/bloeys/gopad/settings"
|
"github.com/bloeys/gopad/settings"
|
||||||
"github.com/bloeys/nmage/input"
|
|
||||||
"github.com/inkyblackness/imgui-go/v4"
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// hello there my friend
|
|
||||||
const (
|
const (
|
||||||
linesPerNode = 100
|
linesPerNode = 100
|
||||||
textPadding = 10
|
textPadding = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
type Line struct {
|
type Line struct {
|
||||||
|
// @TODO: This will explode on long lines.
|
||||||
|
// We can use the same strategy of line nodes here, where a line is something like
|
||||||
|
// type Line struct {
|
||||||
|
// Line [RunesPerLine]rune
|
||||||
|
// Next *Line
|
||||||
|
// }
|
||||||
chars []rune
|
chars []rune
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +87,7 @@ func (e *Editor) RefreshFontSettings() {
|
|||||||
//
|
//
|
||||||
//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
|
//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
|
//cursors properly for now
|
||||||
e.CharWidth = imgui.CalcTextSize("abcdefghijklmnopqrstuvwxyz", false, 1000).X / 26
|
e.CharWidth = imgui.CalcTextSizeV("abcdefghijklmnopqrstuvwxyz", false, 1000).X / 26
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Editor) RoundToGridX(x float32) float32 {
|
func (e *Editor) RoundToGridX(x float32) float32 {
|
||||||
@ -102,59 +105,76 @@ func (e *Editor) UpdateAndDraw(drawStartPos, winSize *imgui.Vec2, newRunes []run
|
|||||||
imgui.SetNextWindowSize(*winSize)
|
imgui.SetNextWindowSize(*winSize)
|
||||||
imgui.BeginV("editorText", nil, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
imgui.BeginV("editorText", nil, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
||||||
|
|
||||||
imgui.PushStyleColor(imgui.StyleColorFrameBg, settings.EditorBgColor)
|
imgui.PushStyleColorVec4(imgui.ColFrameBg, settings.EditorBgColor)
|
||||||
imgui.PushStyleColor(imgui.StyleColorTextSelectedBg, settings.TextSelectionColor)
|
imgui.PushStyleColorVec4(imgui.ColTextSelectedBg, settings.TextSelectionColor)
|
||||||
|
|
||||||
//Add padding to text
|
imgui.SetNextItemWidth(winSize.X)
|
||||||
drawStartPos.X += textPadding
|
|
||||||
drawStartPos.Y += textPadding
|
|
||||||
paddedDrawStartPos := *drawStartPos
|
|
||||||
|
|
||||||
//Make edits
|
// We want different lables so multiple editors don't mess eaach other, but we don't want the label to show
|
||||||
posInfo := e.getPositions(&paddedDrawStartPos)
|
// so we prefix the whole thing with ##
|
||||||
e.Insert(&posInfo, newRunes)
|
if imgui.InputTextMultiline("##"+e.FilePath, &e.FileContents, imgui.Vec2{X: winSize.X - winSize.X*0.02, Y: winSize.Y - winSize.Y*0.02}, imgui.InputTextFlagsNone|imgui.InputTextFlagsAllowTabInput, nil) {
|
||||||
|
e.IsModified = true
|
||||||
if input.KeyClicked(sdl.K_LEFT) {
|
|
||||||
e.MoveMouseXByChars(-1, &posInfo)
|
|
||||||
} else if input.KeyClicked(sdl.K_RIGHT) {
|
|
||||||
e.MoveMouseXByChars(1, &posInfo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.KeyClicked(sdl.K_UP) {
|
// @NOTE: Commented out until rewrite that doesn't use imgui as an editor is complete
|
||||||
e.MoveMouseYByLines(-1, &posInfo)
|
// //Draw window
|
||||||
} else if input.KeyClicked(sdl.K_DOWN) {
|
// imgui.SetNextWindowPos(*drawStartPos)
|
||||||
e.MoveMouseYByLines(1, &posInfo)
|
// imgui.SetNextWindowSize(*winSize)
|
||||||
}
|
// imgui.BeginV("editorText", nil, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
||||||
|
|
||||||
if input.KeyClicked(sdl.K_BACKSPACE) {
|
// imgui.PushStyleColor(imgui.StyleColorFrameBg, settings.EditorBgColor)
|
||||||
e.Delete(&posInfo, 1)
|
// imgui.PushStyleColor(imgui.StyleColorTextSelectedBg, settings.TextSelectionColor)
|
||||||
}
|
|
||||||
|
|
||||||
//Draw text
|
// //Add padding to text
|
||||||
dl := imgui.WindowDrawList()
|
// drawStartPos.X += textPadding
|
||||||
linesToDraw := int(winSize.Y / e.LineHeight)
|
// drawStartPos.Y += textPadding
|
||||||
startLine := clampInt(int(e.StartPos), 0, e.LineCount)
|
// paddedDrawStartPos := *drawStartPos
|
||||||
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 += e.LineHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
tabCount, charsToOffsetBy := getTabs(posInfo.Line, posInfo.GridXEditor)
|
// //Make edits
|
||||||
textWidth := float32(len(posInfo.Line.chars)-tabCount+tabCount*settings.TabSize) * e.CharWidth
|
// posInfo := e.getPositions(&paddedDrawStartPos)
|
||||||
lineX := clampF32(float32(posInfo.GridXGlobal)+float32(charsToOffsetBy)*e.CharWidth, 0, paddedDrawStartPos.X+textWidth)
|
// e.Insert(&posInfo, newRunes)
|
||||||
|
|
||||||
lineStart := imgui.Vec2{
|
// if input.KeyClickedCaptured(sdl.K_LEFT) {
|
||||||
X: lineX,
|
// e.MoveMouseXByChars(-1, &posInfo)
|
||||||
Y: paddedDrawStartPos.Y + float32(posInfo.GridYEditor)*e.LineHeight - e.LineHeight*0.25,
|
// } else if input.KeyClickedCaptured(sdl.K_RIGHT) {
|
||||||
}
|
// e.MoveMouseXByChars(1, &posInfo)
|
||||||
lineEnd := imgui.Vec2{
|
// }
|
||||||
X: lineX,
|
|
||||||
Y: paddedDrawStartPos.Y + float32(posInfo.GridYEditor)*e.LineHeight + e.LineHeight*0.75,
|
|
||||||
}
|
|
||||||
dl.AddLineV(lineStart, lineEnd, imgui.PackedColorFromVec4(settings.CursorColor), settings.CursorWidthFactor*e.CharWidth)
|
|
||||||
|
|
||||||
// charAtCursor := getCharFromCursor(clickedLine, clickedColGridXEditor)
|
// if input.KeyClickedCaptured(sdl.K_UP) {
|
||||||
// println("Chars:", "'"+charAtCursor+"'", ";", clickedColGridXEditor)
|
// e.MoveMouseYByLines(-1, &posInfo)
|
||||||
|
// } else if input.KeyClickedCaptured(sdl.K_DOWN) {
|
||||||
|
// e.MoveMouseYByLines(1, &posInfo)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if input.KeyClickedCaptured(sdl.K_BACKSPACE) {
|
||||||
|
// e.Delete(&posInfo, 1)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //Draw text
|
||||||
|
// dl := imgui.WindowDrawList()
|
||||||
|
// linesToDraw := int(winSize.Y / e.LineHeight)
|
||||||
|
// startLine := clampInt(int(e.StartPos), 0, e.LineCount)
|
||||||
|
// 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 += e.LineHeight
|
||||||
|
// }
|
||||||
|
|
||||||
|
// tabCount, charsToOffsetBy := getTabs(posInfo.Line, posInfo.GridXEditor)
|
||||||
|
// textWidth := float32(len(posInfo.Line.chars)-tabCount+tabCount*settings.TabSize) * e.CharWidth
|
||||||
|
// lineX := clampF32(float32(posInfo.GridXGlobal)+float32(charsToOffsetBy)*e.CharWidth, 0, paddedDrawStartPos.X+textWidth)
|
||||||
|
|
||||||
|
// lineStart := imgui.Vec2{
|
||||||
|
// X: lineX,
|
||||||
|
// Y: paddedDrawStartPos.Y + float32(posInfo.GridYEditor)*e.LineHeight - e.LineHeight*0.25,
|
||||||
|
// }
|
||||||
|
// lineEnd := imgui.Vec2{
|
||||||
|
// X: lineX,
|
||||||
|
// Y: paddedDrawStartPos.Y + float32(posInfo.GridYEditor)*e.LineHeight + e.LineHeight*0.75,
|
||||||
|
// }
|
||||||
|
// dl.AddLineV(lineStart, lineEnd, imgui.PackedColorFromVec4(settings.CursorColor), settings.CursorWidthFactor*e.CharWidth)
|
||||||
|
|
||||||
|
// // charAtCursor := getCharFromCursor(clickedLine, clickedColGridXEditor)
|
||||||
|
// // println("Chars:", "'"+charAtCursor+"'", ";", clickedColGridXEditor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Editor) Insert(posInfo *MousePosInfo, rs []rune) {
|
func (e *Editor) Insert(posInfo *MousePosInfo, rs []rune) {
|
||||||
@ -400,12 +420,17 @@ func (e *Editor) GetLineCharCount(lineNum int) int {
|
|||||||
func ParseLines(fileContents string) (*LinesNode, int) {
|
func ParseLines(fileContents string) (*LinesNode, int) {
|
||||||
|
|
||||||
head := NewLineNode()
|
head := NewLineNode()
|
||||||
|
if len(fileContents) == 0 {
|
||||||
|
return head, 0
|
||||||
|
}
|
||||||
|
|
||||||
lineCount := 0
|
lineCount := 0
|
||||||
start := 0
|
start := 0
|
||||||
end := 0
|
end := 0
|
||||||
currLine := 0
|
currLine := 0
|
||||||
currNode := head
|
currNode := head
|
||||||
|
|
||||||
|
// @PERF: Would be a lot faster to use something like bytes index
|
||||||
for i := 0; i < len(fileContents); i++ {
|
for i := 0; i < len(fileContents); i++ {
|
||||||
|
|
||||||
if fileContents[i] != '\n' {
|
if fileContents[i] != '\n' {
|
||||||
@ -474,9 +499,9 @@ func roundF32(x float32) float32 {
|
|||||||
return float32(math.Round(float64(x)))
|
return float32(math.Round(float64(x)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewScratchEditor() *Editor {
|
func NewScratchEditor() Editor {
|
||||||
|
|
||||||
e := &Editor{
|
e := Editor{
|
||||||
FileName: "**scratch**",
|
FileName: "**scratch**",
|
||||||
LinesHead: NewLineNode(),
|
LinesHead: NewLineNode(),
|
||||||
}
|
}
|
||||||
@ -484,18 +509,20 @@ func NewScratchEditor() *Editor {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEditor(fPath string) *Editor {
|
func NewEditor(fPath string) Editor {
|
||||||
|
|
||||||
b, err := os.ReadFile(fPath)
|
b, err := os.ReadFile(fPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e := &Editor{
|
e := Editor{
|
||||||
FileName: filepath.Base(fPath),
|
FileName: filepath.Base(fPath),
|
||||||
FilePath: fPath,
|
FilePath: fPath,
|
||||||
FileContents: string(b),
|
FileContents: string(b),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.RefreshFontSettings()
|
||||||
e.LinesHead, e.LineCount = ParseLines(e.FileContents)
|
e.LinesHead, e.LineCount = ParseLines(e.FileContents)
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|||||||
71
file_dialogs_windows.go
Executable file
71
file_dialogs_windows.go
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
comdlg32 = syscall.NewLazyDLL("Comdlg32.dll")
|
||||||
|
procGetOpenFileName = comdlg32.NewProc("GetOpenFileNameW")
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Err_No_File_Chosen = fmt.Errorf("no file was chosen")
|
||||||
|
)
|
||||||
|
|
||||||
|
func OpenFileDialog(title string) (filepath string, err error) {
|
||||||
|
|
||||||
|
type OPENFILENAMEW struct {
|
||||||
|
LStructSize uint32
|
||||||
|
HwndOwner syscall.Handle
|
||||||
|
HInstance syscall.Handle
|
||||||
|
Filter *uint16
|
||||||
|
CustomFilter *uint16
|
||||||
|
MaxCustFilter uint32
|
||||||
|
FilterIndex uint32
|
||||||
|
File *uint16
|
||||||
|
MaxFile uint32
|
||||||
|
FileTitle *uint16
|
||||||
|
MaxFileTitle uint32
|
||||||
|
InitialDir *uint16
|
||||||
|
Title *uint16
|
||||||
|
Flags uint32
|
||||||
|
FileOffset uint16
|
||||||
|
FileExtension uint16
|
||||||
|
DefExt *uint16
|
||||||
|
CustData uintptr
|
||||||
|
FnHook syscall.Handle
|
||||||
|
TemplateName *uint16
|
||||||
|
PvReserved uintptr
|
||||||
|
DwReserved uint32
|
||||||
|
FlagsEx uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
titleByteArr := utf16.Encode([]rune(title + "\x00"))
|
||||||
|
filterByteArr := utf16.Encode([]rune("All Files (*.*)\x00*.*\x00Text Files (*.txt)\x00*.txt\x00\x00"))
|
||||||
|
|
||||||
|
filenameByteArr := make([]uint16, syscall.MAX_LONG_PATH)
|
||||||
|
|
||||||
|
ofn := &OPENFILENAMEW{
|
||||||
|
HwndOwner: 0,
|
||||||
|
HInstance: 0,
|
||||||
|
LStructSize: uint32(unsafe.Sizeof(OPENFILENAMEW{})),
|
||||||
|
Title: &titleByteArr[0],
|
||||||
|
Filter: &filterByteArr[0],
|
||||||
|
File: &filenameByteArr[0],
|
||||||
|
MaxFile: syscall.MAX_LONG_PATH,
|
||||||
|
// OFN_FILEMUSTEXIST
|
||||||
|
Flags: 0x00001000,
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, _, _ := procGetOpenFileName.Call(uintptr(unsafe.Pointer(ofn)))
|
||||||
|
if ret == 0 {
|
||||||
|
return "", Err_No_File_Chosen
|
||||||
|
}
|
||||||
|
|
||||||
|
filepath = syscall.UTF16ToString(filenameByteArr)
|
||||||
|
return filepath, nil
|
||||||
|
}
|
||||||
8
go.mod
8
go.mod
@ -1,11 +1,11 @@
|
|||||||
module github.com/bloeys/gopad
|
module github.com/bloeys/gopad
|
||||||
|
|
||||||
go 1.18
|
go 1.22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bloeys/nmage v0.16.2
|
github.com/AllenDang/cimgui-go v0.0.0-20230720025235-f2ff398a66b2
|
||||||
github.com/inkyblackness/imgui-go/v4 v4.6.0
|
github.com/bloeys/nmage v0.23.2
|
||||||
github.com/veandco/go-sdl2 v0.4.25
|
github.com/veandco/go-sdl2 v0.4.35
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
19
go.sum
19
go.sum
@ -1,19 +1,12 @@
|
|||||||
|
github.com/AllenDang/cimgui-go v0.0.0-20230720025235-f2ff398a66b2 h1:3HA/5qD8Rimxz/y1sLyVaM7ws1dzjXzMt4hOBiwHggo=
|
||||||
|
github.com/AllenDang/cimgui-go v0.0.0-20230720025235-f2ff398a66b2/go.mod h1:iNfbIyOBN8k3XScMxULbrwYbPsXEAUD0Jb6UwrspQb8=
|
||||||
github.com/bloeys/assimp-go v0.4.4 h1:Yn5e/RpE0Oes0YMBy8O7KkwAO4R/RpgrZPJCt08dVIU=
|
github.com/bloeys/assimp-go v0.4.4 h1:Yn5e/RpE0Oes0YMBy8O7KkwAO4R/RpgrZPJCt08dVIU=
|
||||||
github.com/bloeys/assimp-go v0.4.4/go.mod h1:my3yRxT7CfOztmvi+0svmwbaqw0KFrxaHxncoyaEIP0=
|
github.com/bloeys/assimp-go v0.4.4/go.mod h1:my3yRxT7CfOztmvi+0svmwbaqw0KFrxaHxncoyaEIP0=
|
||||||
github.com/bloeys/gglm v0.43.0 h1:ZpOghR3PHfpkigTDh+FqxLsF0gN8CD6s/bWoei6LyxI=
|
github.com/bloeys/gglm v0.43.0 h1:ZpOghR3PHfpkigTDh+FqxLsF0gN8CD6s/bWoei6LyxI=
|
||||||
github.com/bloeys/gglm v0.43.0/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk=
|
github.com/bloeys/gglm v0.43.0/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk=
|
||||||
github.com/bloeys/nmage v0.16.2 h1:fuCaMrGW5ev4sRS0E70bv3Y++C84RMItFTBSq4/+Tfc=
|
github.com/bloeys/nmage v0.23.2 h1:b0OxcTFwKOOXChvgB5DTSnX0jyYd7lHOi/8I0tZXEm0=
|
||||||
github.com/bloeys/nmage v0.16.2/go.mod h1:Z9pqkadzLYP+HUnV11lsomfxIzcpzLX3Yp5YCqiICUM=
|
github.com/bloeys/nmage v0.23.2/go.mod h1:0hQAs1tCB/EOVwoac0zl+vsANkqGP9EOKc8cM/+3Now=
|
||||||
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-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
|
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
|
||||||
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
||||||
github.com/inkyblackness/imgui-go/v4 v4.6.0 h1:ShcnXEYl80+xREGBY9OpGWePA6FfJChY9Varsm+3jjE=
|
github.com/veandco/go-sdl2 v0.4.35 h1:NohzsfageDWGtCd9nf7Pc3sokMK/MOK+UA2QMJARWzQ=
|
||||||
github.com/inkyblackness/imgui-go/v4 v4.6.0/go.mod h1:g8SAGtOYUP7rYaOB2AsVKCEHmPMDmJKgt4z6d+flhb0=
|
github.com/veandco/go-sdl2 v0.4.35/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/veandco/go-sdl2 v0.4.25 h1:J5ac3KKOccp/0xGJA1PaNYKPUcZm19IxhDGs8lJofPI=
|
|
||||||
github.com/veandco/go-sdl2 v0.4.25/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
|
||||||
|
|||||||
94
main.go
94
main.go
@ -6,17 +6,19 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
imgui "github.com/AllenDang/cimgui-go"
|
||||||
"github.com/bloeys/gopad/settings"
|
"github.com/bloeys/gopad/settings"
|
||||||
"github.com/bloeys/nmage/engine"
|
"github.com/bloeys/nmage/engine"
|
||||||
"github.com/bloeys/nmage/input"
|
"github.com/bloeys/nmage/input"
|
||||||
"github.com/bloeys/nmage/logging"
|
"github.com/bloeys/nmage/logging"
|
||||||
"github.com/bloeys/nmage/renderer/rend3dgl"
|
"github.com/bloeys/nmage/renderer/rend3dgl"
|
||||||
nmageimgui "github.com/bloeys/nmage/ui/imgui"
|
nmageimgui "github.com/bloeys/nmage/ui/imgui"
|
||||||
"github.com/inkyblackness/imgui-go/v4"
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
)
|
)
|
||||||
|
|
||||||
//TODO: Cache os.ReadDir so we don't have to use lots of disk
|
// @TODO:
|
||||||
|
// - Cache os.ReadDir so we don't have to use lots of disk
|
||||||
|
// - Seems undo is broken
|
||||||
|
|
||||||
type Gopad struct {
|
type Gopad struct {
|
||||||
Win *engine.Window
|
Win *engine.Window
|
||||||
@ -69,10 +71,14 @@ func main() {
|
|||||||
|
|
||||||
g := Gopad{
|
g := Gopad{
|
||||||
Win: window,
|
Win: window,
|
||||||
ImGUIInfo: nmageimgui.NewImGUI(),
|
ImGUIInfo: nmageimgui.NewImGui(""),
|
||||||
CurrDir: dir,
|
CurrDir: dir,
|
||||||
editors: []Editor{*NewScratchEditor()},
|
editors: []Editor{NewScratchEditor()},
|
||||||
editorToClose: -1,
|
editorToClose: -1,
|
||||||
|
|
||||||
|
// This is to force a focus on the scratch editr on startup
|
||||||
|
lastActiveEditor: -1,
|
||||||
|
|
||||||
sidebarWidthFactor: 0.15,
|
sidebarWidthFactor: 0.15,
|
||||||
newRunes: []rune{},
|
newRunes: []rune{},
|
||||||
}
|
}
|
||||||
@ -81,7 +87,7 @@ func main() {
|
|||||||
// so we do it here
|
// so we do it here
|
||||||
g.LoadFonts()
|
g.LoadFonts()
|
||||||
|
|
||||||
// engine.SetVSync(true)
|
engine.SetVSync(true)
|
||||||
engine.Run(&g, g.Win, g.ImGUIInfo)
|
engine.Run(&g, g.Win, g.ImGUIInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +99,7 @@ func (g *Gopad) LoadFonts() {
|
|||||||
|
|
||||||
g.mainFont = g.ImGUIInfo.AddFontTTF("./res/fonts/courier-prime.regular.ttf", settings.FontSize, &fConfig, nil)
|
g.mainFont = g.ImGUIInfo.AddFontTTF("./res/fonts/courier-prime.regular.ttf", settings.FontSize, &fConfig, nil)
|
||||||
|
|
||||||
fConfig.Delete()
|
fConfig.Destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gopad) Init() {
|
func (g *Gopad) Init() {
|
||||||
@ -111,18 +117,10 @@ func (g *Gopad) Init() {
|
|||||||
|
|
||||||
//Read os.Args
|
//Read os.Args
|
||||||
for i := 1; i < len(os.Args); i++ {
|
for i := 1; i < len(os.Args); i++ {
|
||||||
b, err := os.ReadFile(os.Args[i])
|
|
||||||
if err != nil {
|
|
||||||
errMsg := "Error opening file. Error: " + err.Error()
|
|
||||||
println(errMsg)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
g.editors = append(g.editors, Editor{
|
e := NewEditor(os.Args[i])
|
||||||
FileName: filepath.Base(os.Args[i]),
|
g.editors = append(g.editors, e)
|
||||||
FilePath: os.Args[i],
|
g.activeEditor = len(g.editors) - 1
|
||||||
FileContents: string(b),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g.activeEditor = len(g.editors) - 1
|
g.activeEditor = len(g.editors) - 1
|
||||||
@ -171,27 +169,33 @@ func (g *Gopad) Update() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close editors if needed
|
|
||||||
if g.editorToClose > -1 {
|
|
||||||
g.closeEditor(g.editorToClose)
|
|
||||||
g.editorToClose = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
if g.haveErr {
|
if g.haveErr {
|
||||||
g.showErrorPopup()
|
g.showErrorPopup()
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.MouseClicked(sdl.BUTTON_LEFT) {
|
if input.KeyDownCaptured(sdl.K_LCTRL) && input.KeyClickedCaptured(sdl.K_o) {
|
||||||
|
|
||||||
|
filepath, err := OpenFileDialog("Open")
|
||||||
|
if err != nil && err != Err_No_File_Chosen {
|
||||||
|
g.triggerError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
g.loadFileFromPath(filepath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.MouseClickedCaptued(sdl.BUTTON_LEFT) {
|
||||||
x, y := input.GetMousePos()
|
x, y := input.GetMousePos()
|
||||||
g.getActiveEditor().SetCursorPos(int(x), int(y))
|
g.getActiveEditor().SetCursorPos(int(x), int(y))
|
||||||
}
|
}
|
||||||
|
|
||||||
if yMove := input.GetMouseWheelYNorm(); yMove != 0 {
|
if yMove := input.GetMouseWheelYNormCaptured(); yMove != 0 {
|
||||||
g.getActiveEditor().SetStartPos(yMove)
|
g.getActiveEditor().SetStartPos(yMove)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Close editor if needed
|
//Close editor if needed
|
||||||
if input.KeyDown(sdl.K_LCTRL) && input.KeyClicked(sdl.K_w) {
|
if input.KeyDownCaptured(sdl.K_LCTRL) && input.KeyClickedCaptured(sdl.K_w) {
|
||||||
g.closeEditor(g.activeEditor)
|
g.closeEditor(g.activeEditor)
|
||||||
g.editorToClose = -1
|
g.editorToClose = -1
|
||||||
}
|
}
|
||||||
@ -199,15 +203,11 @@ func (g *Gopad) Update() {
|
|||||||
e := g.getActiveEditor()
|
e := g.getActiveEditor()
|
||||||
|
|
||||||
//Save if needed
|
//Save if needed
|
||||||
if !e.IsModified {
|
if e.IsModified {
|
||||||
return
|
if input.KeyDownCaptured(sdl.K_LCTRL) && input.KeyClickedCaptured(sdl.K_s) {
|
||||||
}
|
|
||||||
|
|
||||||
if !input.KeyDown(sdl.K_LCTRL) || !input.KeyClicked(sdl.K_s) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
g.saveEditor(e)
|
g.saveEditor(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gopad) saveEditor(e *Editor) {
|
func (g *Gopad) saveEditor(e *Editor) {
|
||||||
@ -227,7 +227,7 @@ func (g *Gopad) saveEditor(e *Editor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gopad) triggerError(errMsg string) {
|
func (g *Gopad) triggerError(errMsg string) {
|
||||||
imgui.OpenPopup("err")
|
imgui.OpenPopupStr("err")
|
||||||
g.haveErr = true
|
g.haveErr = true
|
||||||
g.errMsg = errMsg
|
g.errMsg = errMsg
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ func (g *Gopad) drawMenubar() {
|
|||||||
|
|
||||||
if imgui.BeginMenu("File") {
|
if imgui.BeginMenu("File") {
|
||||||
|
|
||||||
if imgui.MenuItem("Save") {
|
if imgui.MenuItemBool("Save") {
|
||||||
g.saveEditor(g.getActiveEditor())
|
g.saveEditor(g.getActiveEditor())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ func (g *Gopad) drawSidebar() {
|
|||||||
imgui.SetNextWindowSize(imgui.Vec2{X: g.sidebarWidthPx, Y: g.winHeight - g.mainMenuBarHeight})
|
imgui.SetNextWindowSize(imgui.Vec2{X: g.sidebarWidthPx, Y: g.winHeight - g.mainMenuBarHeight})
|
||||||
imgui.BeginV("sidebar", nil, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
imgui.BeginV("sidebar", nil, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
||||||
|
|
||||||
imgui.PushStyleColor(imgui.StyleColorButton, imgui.Vec4{W: 0})
|
imgui.PushStyleColorVec4(imgui.ColButton, imgui.Vec4{W: 0})
|
||||||
for i := 0; i < len(g.CurrDirContents); i++ {
|
for i := 0; i < len(g.CurrDirContents); i++ {
|
||||||
|
|
||||||
c := g.CurrDirContents[i]
|
c := g.CurrDirContents[i]
|
||||||
@ -320,7 +320,7 @@ func (g *Gopad) drawEditors() {
|
|||||||
|
|
||||||
e := &g.editors[i]
|
e := &g.editors[i]
|
||||||
|
|
||||||
flags := imgui.TabItemFlagsNone
|
var flags imgui.TabItemFlags = imgui.TabItemFlagsNone
|
||||||
if shouldForceSwitch && g.activeEditor == i {
|
if shouldForceSwitch && g.activeEditor == i {
|
||||||
flags = imgui.TabItemFlagsSetSelected
|
flags = imgui.TabItemFlagsSetSelected
|
||||||
}
|
}
|
||||||
@ -380,7 +380,7 @@ func (g *Gopad) getActiveEditor() *Editor {
|
|||||||
func (g *Gopad) getEditor(index int) *Editor {
|
func (g *Gopad) getEditor(index int) *Editor {
|
||||||
|
|
||||||
if len(g.editors) == 0 {
|
if len(g.editors) == 0 {
|
||||||
e := *NewScratchEditor()
|
e := NewScratchEditor()
|
||||||
e.RefreshFontSettings()
|
e.RefreshFontSettings()
|
||||||
g.editors = append(g.editors, e)
|
g.editors = append(g.editors, e)
|
||||||
g.activeEditor = 0
|
g.activeEditor = 0
|
||||||
@ -396,7 +396,7 @@ func (g *Gopad) getEditor(index int) *Editor {
|
|||||||
|
|
||||||
func (g *Gopad) drawDir(dir fs.DirEntry, path string) {
|
func (g *Gopad) drawDir(dir fs.DirEntry, path string) {
|
||||||
|
|
||||||
isEnabled := imgui.TreeNodeV(dir.Name(), imgui.TreeNodeFlagsSpanAvailWidth)
|
isEnabled := imgui.TreeNodeExStrV(dir.Name(), imgui.TreeNodeFlagsSpanAvailWidth)
|
||||||
if !isEnabled {
|
if !isEnabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -416,11 +416,11 @@ func (g *Gopad) drawDir(dir fs.DirEntry, path string) {
|
|||||||
func (g *Gopad) drawFile(f fs.DirEntry, path string) {
|
func (g *Gopad) drawFile(f fs.DirEntry, path string) {
|
||||||
|
|
||||||
if imgui.Button(f.Name()) {
|
if imgui.Button(f.Name()) {
|
||||||
g.handleFileClick(path)
|
g.loadFileFromPath(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gopad) handleFileClick(fPath string) {
|
func (g *Gopad) loadFileFromPath(fPath string) {
|
||||||
|
|
||||||
//Check if we already have the file open
|
//Check if we already have the file open
|
||||||
editorIndex := -1
|
editorIndex := -1
|
||||||
@ -440,14 +440,22 @@ func (g *Gopad) handleFileClick(fPath string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Read new file and switch to it
|
//Read new file and switch to it
|
||||||
e := *NewEditor(fPath)
|
e := NewEditor(fPath)
|
||||||
e.RefreshFontSettings()
|
e.RefreshFontSettings()
|
||||||
|
|
||||||
g.editors = append(g.editors, e)
|
g.editors = append(g.editors, e)
|
||||||
g.activeEditor = len(g.editors) - 1
|
g.activeEditor = len(g.editors) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gopad) FrameEnd() {
|
func (g *Gopad) FrameEnd() {
|
||||||
|
|
||||||
g.newRunes = []rune{}
|
g.newRunes = []rune{}
|
||||||
|
|
||||||
|
// Close editors if needed
|
||||||
|
if g.editorToClose > -1 {
|
||||||
|
g.closeEditor(g.editorToClose)
|
||||||
|
g.editorToClose = -1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gopad) DeInit() {
|
func (g *Gopad) DeInit() {
|
||||||
|
|||||||
@ -1,57 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/inkyblackness/imgui-go/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
func selectFolder(startDir string, winWidth float32, winHeight float32) (path string, done bool) {
|
|
||||||
|
|
||||||
if strings.TrimSpace(startDir) == "" {
|
|
||||||
var err error
|
|
||||||
startDir, err = os.UserHomeDir()
|
|
||||||
if err != nil {
|
|
||||||
panic(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
imgui.OpenPopup("selectFolder")
|
|
||||||
|
|
||||||
imgui.SetNextWindowPos(imgui.Vec2{X: float32(winWidth) * 0.5, Y: float32(winHeight) * 0.5})
|
|
||||||
shouldEnd := imgui.BeginPopupModalV("selectFolder", nil, imgui.WindowFlagsNoCollapse)
|
|
||||||
|
|
||||||
drawDir(startDir, true)
|
|
||||||
|
|
||||||
if shouldEnd {
|
|
||||||
imgui.EndPopup()
|
|
||||||
} else {
|
|
||||||
done = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return path, done
|
|
||||||
}
|
|
||||||
|
|
||||||
func drawDir(fPath string, foldersOnly bool) {
|
|
||||||
|
|
||||||
// contents, err := os.ReadDir(fPath)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for _, c := range contents {
|
|
||||||
|
|
||||||
// if !c.IsDir() {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// isEnabled := imgui.TreeNodeV( dir.Name(), imgui.TreeNodeFlagsSpanAvailWidth)
|
|
||||||
// if !isEnabled {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// imgui.bu
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package settings
|
package settings
|
||||||
|
|
||||||
import "github.com/inkyblackness/imgui-go/v4"
|
import imgui "github.com/AllenDang/cimgui-go"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
FontSize float32 = 16
|
FontSize float32 = 16
|
||||||
|
|||||||
Reference in New Issue
Block a user