examples/mdoutliner: use go:embed, support multiple tabs

This commit is contained in:
mappu 2024-09-07 13:53:48 +12:00
parent b282701af9
commit 04692b78f8
2 changed files with 86 additions and 38 deletions

View File

@ -0,0 +1,8 @@
# Markdown Outliner
This is sample markdown content.
## Features
- You can use the outline on the left to jump to parts of the document
- Demonstrates use of the MIQT library

View File

@ -1,30 +1,62 @@
package main package main
import ( import (
"embed"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"strings" "strings"
"github.com/mappu/miqt/qt" "github.com/mappu/miqt/qt"
) )
const sampleContent = `# Markdown Outliner //go:embed README.md
var embedContent embed.FS
This is sample markdown content. const (
lineNumberRole = int(qt.ItemDataRole__UserRole + 1)
## Features )
- You can use the outline on the left to jump to parts of the document
- Demonstrates use of the MIQT library`
type AppWindow struct { type AppWindow struct {
w *qt.QMainWindow w *qt.QMainWindow
cw *qt.QWidget cw *qt.QWidget
tabs *qt.QTabWidget
tabData []AppTab
}
type AppTab struct {
tab *qt.QWidget
outline *qt.QListWidget outline *qt.QListWidget
textArea *qt.QTextEdit textArea *qt.QTextEdit
} }
func NewAppTab() *AppTab {
var ret AppTab
tab := qt.NewQWidget()
ret.tab = tab
layout := qt.NewQHBoxLayout2(tab)
panes := qt.NewQSplitter()
layout.AddWidget(panes.QWidget)
ret.outline = qt.NewQListWidget2(tab)
panes.AddWidget(ret.outline.QWidget)
ret.outline.OnCurrentItemChanged(ret.handleJumpToBookmark)
ret.textArea = qt.NewQTextEdit3(tab)
ret.textArea.OnTextChanged(ret.handleTextChanged)
panes.AddWidget(ret.textArea.QWidget)
panes.SetSizes([]int{250, 550})
return &ret
}
func NewAppWindow() *AppWindow { func NewAppWindow() *AppWindow {
ret := AppWindow{} ret := AppWindow{}
@ -36,6 +68,14 @@ func NewAppWindow() *AppWindow {
mnu := qt.NewQMenuBar() mnu := qt.NewQMenuBar()
fileMenu := mnu.AddMenuWithTitle("&File") fileMenu := mnu.AddMenuWithTitle("&File")
newtab := fileMenu.AddAction("New Tab")
newtab.SetShortcut(qt.NewQKeySequence2("Ctrl+N"))
newtab.SetIcon(qt.QIcon_FromTheme("document-new"))
newtab.OnTriggered1(func() {
ret.createTabWithContents("New Document", "")
})
open := fileMenu.AddAction("Open...") open := fileMenu.AddAction("Open...")
open.SetShortcut(qt.NewQKeySequence2("Ctrl+O")) open.SetShortcut(qt.NewQKeySequence2("Ctrl+O"))
open.SetIcon(qt.QIcon_FromTheme("document-open")) open.SetIcon(qt.QIcon_FromTheme("document-open"))
@ -59,29 +99,20 @@ func NewAppWindow() *AppWindow {
// Main widgets // Main widgets
ret.cw = qt.NewQWidget2(ret.w.QWidget) ret.tabs = qt.NewQTabWidget2(ret.w.QWidget)
ret.w.SetCentralWidget(ret.cw) ret.w.SetCentralWidget(ret.tabs.QWidget)
layout := qt.NewQHBoxLayout2(ret.cw)
panes := qt.NewQSplitter() // Add initial tab
layout.AddWidget(panes.QWidget)
ret.outline = qt.NewQListWidget2(ret.cw) sampleContent, err := embedContent.ReadFile("README.md")
panes.AddWidget(ret.outline.QWidget) if err != nil {
ret.outline.OnCurrentItemChanged(ret.handleJumpToBookmark) panic(err)
}
ret.textArea = qt.NewQTextEdit3(ret.cw) ret.createTabWithContents("README.md", string(sampleContent))
ret.textArea.OnTextChanged(ret.handleTextChanged)
ret.textArea.SetText(sampleContent)
panes.AddWidget(ret.textArea.QWidget)
panes.SetSizes([]int{250, 550})
return &ret return &ret
} }
const lineNumberRole = int(qt.ItemDataRole__UserRole + 1)
func (a *AppWindow) handleFileOpen() { func (a *AppWindow) handleFileOpen() {
fname := qt.QFileDialog_GetOpenFileName4(a.w.QWidget, "Open markdown file...", "", "Markdown files (*.md *.txt);;All Files (*)") fname := qt.QFileDialog_GetOpenFileName4(a.w.QWidget, "Open markdown file...", "", "Markdown files (*.md *.txt);;All Files (*)")
if fname == "" { if fname == "" {
@ -94,41 +125,50 @@ func (a *AppWindow) handleFileOpen() {
return return
} }
a.textArea.SetText(string(contents)) a.createTabWithContents(filepath.Base(fname), string(contents))
} }
func (a *AppWindow) handleTextChanged() { func (a *AppWindow) createTabWithContents(tabTitle, tabContent string) {
content := a.textArea.ToPlainText()
a.updateOutlineForContent(content) tab := NewAppTab()
tab.textArea.SetText(tabContent)
tabIdx := a.tabs.AddTab2(tab.tab, qt.QIcon_FromTheme("text-markdown"), tabTitle)
a.tabs.SetCurrentIndex(tabIdx)
} }
func (a *AppWindow) updateOutlineForContent(content string) { func (t *AppTab) handleTextChanged() {
a.outline.Clear() content := t.textArea.ToPlainText()
t.updateOutlineForContent(content)
}
func (t *AppTab) updateOutlineForContent(content string) {
t.outline.Clear()
lines := strings.Split(content, "\n") lines := strings.Split(content, "\n")
for lineNumber, line := range lines { for lineNumber, line := range lines {
if strings.HasPrefix(line, `#`) { if strings.HasPrefix(line, `#`) {
bookmark := qt.NewQListWidgetItem7(line, a.outline) bookmark := qt.NewQListWidgetItem7(line, t.outline)
bookmark.SetToolTip(fmt.Sprintf("Line %d", lineNumber+1)) bookmark.SetToolTip(fmt.Sprintf("Line %d", lineNumber+1))
bookmark.SetData(lineNumberRole, qt.NewQVariant5(lineNumber)) bookmark.SetData(lineNumberRole, qt.NewQVariant5(lineNumber))
} }
} }
} }
func (a *AppWindow) handleJumpToBookmark() { func (t *AppTab) handleJumpToBookmark() {
itm := a.outline.CurrentItem() itm := t.outline.CurrentItem()
if itm == nil { if itm == nil {
return return
} }
lineNumber := itm.Data(lineNumberRole).ToInt() lineNumber := itm.Data(lineNumberRole).ToInt()
targetBlock := a.textArea.Document().FindBlockByLineNumber(lineNumber) targetBlock := t.textArea.Document().FindBlockByLineNumber(lineNumber)
a.textArea.SetTextCursor(qt.NewQTextCursor4(targetBlock)) t.textArea.SetTextCursor(qt.NewQTextCursor4(targetBlock))
a.textArea.SetFocus() t.textArea.SetFocus()
} }
func main() { func main() {