mirror of
https://github.com/bloeys/gopad.git
synced 2025-12-29 15:08:21 +00:00
Multiple files
This commit is contained in:
14
imgui.ini
14
imgui.ini
@ -1,5 +1,5 @@
|
|||||||
[Window][Debug##Default]
|
[Window][Debug##Default]
|
||||||
Pos=496,94
|
Pos=306,2
|
||||||
Size=400,400
|
Size=400,400
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
@ -10,6 +10,16 @@ Collapsed=0
|
|||||||
|
|
||||||
[Window][sidebar]
|
[Window][sidebar]
|
||||||
Pos=0,0
|
Pos=0,0
|
||||||
Size=32,32
|
Size=128,720
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][editor]
|
||||||
|
Pos=128,0
|
||||||
|
Size=1152,38
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][editorText]
|
||||||
|
Pos=128,38
|
||||||
|
Size=1152,682
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
|
|||||||
163
main.go
163
main.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
"github.com/bloeys/nmage/engine"
|
"github.com/bloeys/nmage/engine"
|
||||||
"github.com/bloeys/nmage/input"
|
"github.com/bloeys/nmage/input"
|
||||||
@ -14,6 +15,12 @@ import (
|
|||||||
|
|
||||||
//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
|
||||||
|
|
||||||
|
type Editor struct {
|
||||||
|
fileName string
|
||||||
|
filePath string
|
||||||
|
fileContents string
|
||||||
|
}
|
||||||
|
|
||||||
type Gopad struct {
|
type Gopad struct {
|
||||||
Win *engine.Window
|
Win *engine.Window
|
||||||
mainFont imgui.Font
|
mainFont imgui.Font
|
||||||
@ -25,7 +32,9 @@ type Gopad struct {
|
|||||||
CurrDir string
|
CurrDir string
|
||||||
CurrDirContents []fs.DirEntry
|
CurrDirContents []fs.DirEntry
|
||||||
|
|
||||||
buffer []rune
|
editors []Editor
|
||||||
|
activeEditor int
|
||||||
|
lastActiveEditor int
|
||||||
}
|
}
|
||||||
|
|
||||||
var ()
|
var ()
|
||||||
@ -50,8 +59,10 @@ func main() {
|
|||||||
g := Gopad{
|
g := Gopad{
|
||||||
Win: window,
|
Win: window,
|
||||||
ImGUIInfo: nmageimgui.NewImGUI(),
|
ImGUIInfo: nmageimgui.NewImGUI(),
|
||||||
buffer: make([]rune, 0, 10000),
|
|
||||||
CurrDir: dir,
|
CurrDir: dir,
|
||||||
|
editors: []Editor{
|
||||||
|
{fileName: "**scratch**"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.Run(&g)
|
engine.Run(&g)
|
||||||
@ -83,7 +94,7 @@ func (g *Gopad) handleWindowEvents(event sdl.Event) {
|
|||||||
|
|
||||||
case *sdl.TextEditingEvent:
|
case *sdl.TextEditingEvent:
|
||||||
case *sdl.TextInputEvent:
|
case *sdl.TextInputEvent:
|
||||||
g.buffer = append(g.buffer, []rune(e.GetText())...)
|
// g.buffer = append(g.buffer, []rune(e.GetText())...)
|
||||||
|
|
||||||
case *sdl.WindowEvent:
|
case *sdl.WindowEvent:
|
||||||
if e.Event == sdl.WINDOWEVENT_SIZE_CHANGED {
|
if e.Event == sdl.WINDOWEVENT_SIZE_CHANGED {
|
||||||
@ -110,60 +121,103 @@ func (g *Gopad) Update() {
|
|||||||
sdl.StopTextInput()
|
sdl.StopTextInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.KeyClicked(sdl.K_BACKSPACE) && len(g.buffer) > 0 {
|
// if input.KeyClicked(sdl.K_BACKSPACE) && len(g.buffer) > 0 {
|
||||||
g.buffer = g.buffer[:len(g.buffer)-1]
|
// g.buffer = g.buffer[:len(g.buffer)-1]
|
||||||
}
|
// }
|
||||||
|
|
||||||
if input.KeyClicked(sdl.K_RETURN) || input.KeyClicked(sdl.K_RETURN2) {
|
// if input.KeyClicked(sdl.K_RETURN) || input.KeyClicked(sdl.K_RETURN2) {
|
||||||
g.buffer = append(g.buffer, rune('\n'))
|
// g.buffer = append(g.buffer, rune('\n'))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gopad) Render() {
|
func (g *Gopad) Render() {
|
||||||
|
|
||||||
open := true
|
|
||||||
w, h := g.Win.SDLWin.GetSize()
|
|
||||||
|
|
||||||
//Global imgui settings
|
//Global imgui settings
|
||||||
imgui.PushStyleColor(imgui.StyleColorText, imgui.Vec4{X: 1, Y: 1, Z: 1, W: 1})
|
imgui.PushStyleColor(imgui.StyleColorText, imgui.Vec4{X: 1, Y: 1, Z: 1, W: 1})
|
||||||
imgui.PushFont(g.mainFont)
|
imgui.PushFont(g.mainFont)
|
||||||
|
|
||||||
//Sidebar
|
g.drawSidebar()
|
||||||
imgui.SetNextWindowPos(imgui.Vec2{X: 0, Y: 0})
|
g.drawEditors()
|
||||||
imgui.SetNextWindowSize(imgui.Vec2{X: g.sidebarSize, Y: float32(h)})
|
|
||||||
imgui.BeginV("sidebar", &open, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
|
||||||
|
|
||||||
g.refreshSidebar()
|
|
||||||
|
|
||||||
imgui.End()
|
|
||||||
|
|
||||||
//Text area
|
|
||||||
imgui.SetNextWindowPos(imgui.Vec2{X: g.sidebarSize, Y: 0})
|
|
||||||
imgui.SetNextWindowSize(imgui.Vec2{X: float32(w) - g.sidebarSize, Y: float32(h)})
|
|
||||||
imgui.BeginV("editor", &open, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
|
||||||
imgui.Text(string(g.buffer) + "|")
|
|
||||||
imgui.End()
|
|
||||||
|
|
||||||
imgui.PopFont()
|
imgui.PopFont()
|
||||||
imgui.PopStyleColor()
|
imgui.PopStyleColor()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gopad) refreshSidebar() {
|
func (g *Gopad) drawSidebar() {
|
||||||
|
|
||||||
|
_, h := g.Win.SDLWin.GetSize()
|
||||||
|
imgui.SetNextWindowPos(imgui.Vec2{X: 0, Y: 0})
|
||||||
|
imgui.SetNextWindowSize(imgui.Vec2{X: g.sidebarSize, Y: float32(h)})
|
||||||
|
imgui.BeginV("sidebar", nil, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
||||||
|
|
||||||
|
imgui.PushStyleColor(imgui.StyleColorButton, 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]
|
||||||
if c.IsDir() {
|
if c.IsDir() {
|
||||||
drawDir(c, g.CurrDir+"/"+c.Name()+"/")
|
g.drawDir(c, g.CurrDir+"/"+c.Name()+"/")
|
||||||
} else {
|
} else {
|
||||||
imgui.Button(c.Name())
|
g.drawFile(c, g.CurrDir+"/"+c.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui.PopStyleColor()
|
||||||
|
imgui.End()
|
||||||
}
|
}
|
||||||
|
|
||||||
func drawDir(dir fs.DirEntry, path string) {
|
func (g *Gopad) drawEditors() {
|
||||||
|
|
||||||
isEnabled := imgui.TreeNode(dir.Name())
|
//Draw editor area window
|
||||||
|
w, h := g.Win.SDLWin.GetSize()
|
||||||
|
imgui.SetNextWindowPos(imgui.Vec2{X: g.sidebarSize, Y: 0})
|
||||||
|
imgui.SetNextWindowSize(imgui.Vec2{X: float32(w) - g.sidebarSize})
|
||||||
|
imgui.BeginV("editor", nil, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
||||||
|
|
||||||
|
//Draw tabs
|
||||||
|
isEditorsEnabled := imgui.BeginTabBarV("editorTabs", 0)
|
||||||
|
for i := 0; i < len(g.editors); i++ {
|
||||||
|
|
||||||
|
e := &g.editors[i]
|
||||||
|
|
||||||
|
shouldForceSwitch := g.activeEditor == i && g.activeEditor != g.lastActiveEditor
|
||||||
|
flags := imgui.TabItemFlagsNone
|
||||||
|
if shouldForceSwitch {
|
||||||
|
flags = imgui.TabItemFlagsSetSelected
|
||||||
|
}
|
||||||
|
|
||||||
|
if !imgui.BeginTabItemV(e.fileName, nil, flags) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//If these two aren't equal it means we programmatically changed the active editor (instead of a mouse click),
|
||||||
|
//and so we shouldn't change based on what imgui is telling us
|
||||||
|
if g.activeEditor == g.lastActiveEditor {
|
||||||
|
g.activeEditor = i
|
||||||
|
g.lastActiveEditor = i
|
||||||
|
}
|
||||||
|
imgui.EndTabItem()
|
||||||
|
}
|
||||||
|
g.lastActiveEditor = g.activeEditor
|
||||||
|
|
||||||
|
if isEditorsEnabled {
|
||||||
|
imgui.EndTabBar()
|
||||||
|
}
|
||||||
|
|
||||||
|
tabsHeight := imgui.WindowHeight()
|
||||||
|
imgui.End()
|
||||||
|
|
||||||
|
//Draw text area
|
||||||
|
imgui.SetNextWindowPos(imgui.Vec2{X: g.sidebarSize, Y: tabsHeight})
|
||||||
|
imgui.SetNextWindowSize(imgui.Vec2{X: float32(w) - g.sidebarSize, Y: float32(h) - tabsHeight})
|
||||||
|
imgui.BeginV("editorText", nil, imgui.WindowFlagsNoCollapse|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoMove)
|
||||||
|
imgui.Text(g.editors[g.activeEditor].fileContents)
|
||||||
|
imgui.End()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Gopad) drawDir(dir fs.DirEntry, path string) {
|
||||||
|
|
||||||
|
isEnabled := imgui.TreeNodeV(dir.Name(), imgui.TreeNodeFlagsSpanAvailWidth)
|
||||||
if !isEnabled {
|
if !isEnabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -171,15 +225,56 @@ func drawDir(dir fs.DirEntry, path string) {
|
|||||||
contents := getDirContents(path)
|
contents := getDirContents(path)
|
||||||
for _, c := range contents {
|
for _, c := range contents {
|
||||||
if c.IsDir() {
|
if c.IsDir() {
|
||||||
drawDir(c, path+c.Name()+"/")
|
g.drawDir(c, path+c.Name()+"/")
|
||||||
} else {
|
} else {
|
||||||
imgui.Button(c.Name())
|
g.drawFile(c, path+c.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imgui.TreePop()
|
imgui.TreePop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Gopad) drawFile(f fs.DirEntry, path string) {
|
||||||
|
|
||||||
|
if imgui.Button(f.Name()) {
|
||||||
|
g.handleFileClick(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Gopad) handleFileClick(fPath string) {
|
||||||
|
|
||||||
|
//Check if we already have the file open
|
||||||
|
editorIndex := -1
|
||||||
|
for i := 0; i < len(g.editors); i++ {
|
||||||
|
|
||||||
|
e := &g.editors[i]
|
||||||
|
if e.filePath == fPath {
|
||||||
|
editorIndex = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If already found switch to it
|
||||||
|
if editorIndex >= 0 {
|
||||||
|
g.activeEditor = editorIndex
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Read new file and switch to it
|
||||||
|
println("Reading:", fPath)
|
||||||
|
b, err := os.ReadFile(fPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.editors = append(g.editors, Editor{
|
||||||
|
fileName: path.Base(fPath),
|
||||||
|
filePath: fPath,
|
||||||
|
fileContents: string(b),
|
||||||
|
})
|
||||||
|
g.activeEditor = len(g.editors) - 1
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Gopad) FrameEnd() {
|
func (g *Gopad) FrameEnd() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user