akiyosi.goneovim/editor/palette.go

445 lines
11 KiB
Go
Raw Normal View History

2017-11-09 02:11:05 +00:00
package editor
2017-06-28 08:28:24 +01:00
import (
"fmt"
2018-09-02 15:55:24 +09:00
"math"
2020-02-24 18:15:38 +09:00
"runtime"
2017-06-28 08:28:24 +01:00
2020-07-30 22:50:02 +09:00
"github.com/akiyosi/goneovim/fuzzy"
2020-09-26 12:04:36 +09:00
"github.com/akiyosi/goneovim/util"
2017-06-28 08:28:24 +01:00
"github.com/therecipe/qt/core"
"github.com/therecipe/qt/gui"
"github.com/therecipe/qt/svg"
"github.com/therecipe/qt/widgets"
)
// Palette is the popup for fuzzy finder, cmdline etc
type Palette struct {
2018-10-31 12:12:57 +09:00
// mu sync.Mutex
// procCount int
2018-01-05 08:07:29 +00:00
ws *Workspace
2017-11-09 01:41:26 +00:00
hidden bool
2017-06-28 11:06:47 +01:00
widget *widgets.QWidget
2019-08-31 01:47:08 +09:00
padding int
2017-06-28 11:06:47 +01:00
patternText string
2019-09-09 23:11:32 +09:00
isHTMLText bool
2017-06-28 11:06:47 +01:00
resultItems []*PaletteResultItem
resultWidget *widgets.QWidget
resultMainWidget *widgets.QWidget
itemHeight int
width int
cursorX int
resultType string
itemTypes []string
max int
showTotal int
pattern *widgets.QLabel
patternPadding int
patternWidget *widgets.QWidget
scrollBar *widgets.QWidget
scrollBarPos int
scrollCol *widgets.QWidget
2017-06-28 08:28:24 +01:00
}
// PaletteResultItem is the result item
type PaletteResultItem struct {
2018-01-05 08:07:29 +00:00
p *Palette
2017-06-28 08:28:24 +01:00
hidden bool
icon *svg.QSvgWidget
iconType string
iconHidden bool
base *widgets.QLabel
baseText string
widget *widgets.QWidget
selected bool
}
func initPalette() *Palette {
width := 600
2019-09-08 21:40:15 +09:00
padding := 8
2017-06-28 08:28:24 +01:00
mainLayout := widgets.NewQVBoxLayout()
mainLayout.SetContentsMargins(0, 0, 0, 0)
mainLayout.SetSpacing(0)
2017-11-09 01:41:26 +00:00
mainLayout.SetSizeConstraint(widgets.QLayout__SetMinAndMaxSize)
2017-06-28 08:28:24 +01:00
widget := widgets.NewQWidget(nil, 0)
widget.SetLayout(mainLayout)
widget.SetContentsMargins(1, 1, 1, 1)
2017-11-09 01:41:26 +00:00
// widget.SetFixedWidth(width)
2017-06-28 08:28:24 +01:00
widget.SetObjectName("palette")
2019-09-08 21:40:15 +09:00
2019-10-18 00:08:56 +09:00
widget.SetGraphicsEffect(util.DropShadow(0, 15, 130, 120))
2017-06-28 08:28:24 +01:00
resultMainLayout := widgets.NewQHBoxLayout()
resultMainLayout.SetContentsMargins(0, 0, 0, 0)
resultMainLayout.SetSpacing(0)
2017-11-09 01:41:26 +00:00
resultMainLayout.SetSizeConstraint(widgets.QLayout__SetMinAndMaxSize)
2017-06-28 08:28:24 +01:00
resultLayout := widgets.NewQVBoxLayout()
resultLayout.SetContentsMargins(0, 0, 0, 0)
resultLayout.SetSpacing(0)
2017-11-09 01:41:26 +00:00
resultLayout.SetSizeConstraint(widgets.QLayout__SetMinAndMaxSize)
2017-06-28 08:28:24 +01:00
resultWidget := widgets.NewQWidget(nil, 0)
resultWidget.SetLayout(resultLayout)
2019-10-26 03:00:14 +09:00
resultWidget.SetStyleSheet("background-color: rgba(0, 0, 0, 0); white-space: pre-wrap;")
2017-06-28 08:28:24 +01:00
resultWidget.SetContentsMargins(0, 0, 0, 0)
scrollCol := widgets.NewQWidget(nil, 0)
scrollCol.SetContentsMargins(0, 0, 0, 0)
scrollCol.SetFixedWidth(5)
scrollBar := widgets.NewQWidget(scrollCol, 0)
scrollBar.SetFixedWidth(5)
resultMainWidget := widgets.NewQWidget(nil, 0)
2019-03-21 18:38:53 +09:00
resultMainWidget.SetStyleSheet(" * { background-color: rgba(0, 0, 0, 0); }")
2017-06-28 08:28:24 +01:00
resultMainWidget.SetContentsMargins(0, 0, 0, 0)
resultMainLayout.AddWidget(resultWidget, 0, 0)
resultMainLayout.AddWidget(scrollCol, 0, 0)
resultMainWidget.SetLayout(resultMainLayout)
pattern := widgets.NewQLabel(nil, 0)
pattern.SetContentsMargins(padding, padding, padding, padding)
2017-11-09 01:41:26 +00:00
pattern.SetFixedWidth(width - padding*2)
pattern.SetSizePolicy2(widgets.QSizePolicy__Preferred, widgets.QSizePolicy__Maximum)
2017-06-28 08:28:24 +01:00
patternLayout := widgets.NewQVBoxLayout()
patternLayout.AddWidget(pattern, 0, 0)
patternLayout.SetContentsMargins(0, 0, 0, 0)
patternLayout.SetSpacing(0)
2017-11-09 01:41:26 +00:00
patternLayout.SetSizeConstraint(widgets.QLayout__SetMinAndMaxSize)
2017-06-28 08:28:24 +01:00
patternWidget := widgets.NewQWidget(nil, 0)
patternWidget.SetLayout(patternLayout)
patternWidget.SetContentsMargins(padding, padding, padding, padding)
mainLayout.AddWidget(patternWidget, 0, 0)
mainLayout.AddWidget(resultMainWidget, 0, 0)
2018-01-05 08:07:29 +00:00
palette := &Palette{
width: width,
widget: widget,
2019-08-31 01:47:08 +09:00
padding: padding,
2018-01-05 08:07:29 +00:00
resultWidget: resultWidget,
resultMainWidget: resultMainWidget,
pattern: pattern,
patternPadding: padding,
patternWidget: patternWidget,
scrollCol: scrollCol,
scrollBar: scrollBar,
}
2017-06-28 08:28:24 +01:00
resultItems := []*PaletteResultItem{}
2019-03-13 17:35:59 +09:00
max := editor.config.Palette.MaxNumberOfResultItems
2017-06-28 08:28:24 +01:00
for i := 0; i < max; i++ {
itemWidget := widgets.NewQWidget(nil, 0)
itemWidget.SetContentsMargins(0, 0, 0, 0)
2019-03-05 23:09:22 +09:00
itemLayout := util.NewVFlowLayout(padding, padding*2, 0, 0, 9999)
2017-11-09 01:41:26 +00:00
itemLayout.SetSizeConstraint(widgets.QLayout__SetMinAndMaxSize)
2017-06-28 08:28:24 +01:00
itemWidget.SetLayout(itemLayout)
2019-10-26 03:00:14 +09:00
// itemWidget.SetStyleSheet("background-color: rgba(0, 0, 0, 0);")
2017-06-28 08:28:24 +01:00
resultLayout.AddWidget(itemWidget, 0, 0)
icon := svg.NewQSvgWidget(nil)
2018-11-08 18:10:12 +09:00
icon.SetFixedWidth(editor.iconSize - 1)
icon.SetFixedHeight(editor.iconSize - 1)
2017-06-28 08:28:24 +01:00
icon.SetContentsMargins(0, 0, 0, 0)
2019-10-26 03:00:14 +09:00
// icon.SetStyleSheet("background-color: rgba(0, 0, 0, 0);")
2017-06-28 08:28:24 +01:00
base := widgets.NewQLabel(nil, 0)
base.SetText("base")
base.SetContentsMargins(0, padding, 0, padding)
2019-10-26 03:00:14 +09:00
// base.SetStyleSheet("background-color: rgba(0, 0, 0, 0); white-space: pre-wrap;")
base.SetSizePolicy2(widgets.QSizePolicy__Preferred, widgets.QSizePolicy__Maximum)
2017-06-28 08:28:24 +01:00
itemLayout.AddWidget(icon)
itemLayout.AddWidget(base)
resultItem := &PaletteResultItem{
2018-01-05 08:07:29 +00:00
p: palette,
2017-06-28 08:28:24 +01:00
widget: itemWidget,
icon: icon,
base: base,
}
resultItems = append(resultItems, resultItem)
}
2018-01-05 08:07:29 +00:00
palette.max = max
palette.resultItems = resultItems
2017-06-28 08:28:24 +01:00
return palette
}
2018-12-27 21:03:21 +09:00
func (p *Palette) setColor() {
fg := editor.colors.widgetFg.String()
2019-02-17 18:00:09 +09:00
bg := editor.colors.widgetBg
2019-03-21 14:24:54 +09:00
inactiveFg := editor.colors.inactiveFg
2019-02-17 18:00:09 +09:00
transparent := transparent() * transparent()
2019-11-23 03:46:36 +09:00
if editor.config.Palette.Transparent < 1.0 {
transparent = editor.config.Palette.Transparent * editor.config.Palette.Transparent
}
2019-02-17 18:00:09 +09:00
p.widget.SetStyleSheet(fmt.Sprintf(" .QWidget { background-color: rgba(%d, %d, %d, %f); } * { color: %s; } ", bg.R, bg.G, bg.B, transparent, fg))
2019-03-21 14:24:54 +09:00
p.scrollBar.SetStyleSheet(fmt.Sprintf("background-color: rgba(%d, %d, %d, %f);", inactiveFg.R, inactiveFg.G, inactiveFg.B, transparent))
2019-08-10 06:23:48 +09:00
for _, item := range p.resultItems {
item.widget.SetStyleSheet(fmt.Sprintf(" .QWidget { background-color: rgba(0, 0, 0, 0.0); } * { color: %s; } ", fg))
}
2019-03-21 18:38:53 +09:00
if transparent < 1.0 {
p.patternWidget.SetStyleSheet("background-color: rgba(0, 0, 0, 0);")
p.pattern.SetStyleSheet("background-color: rgba(0, 0, 0, 0);")
} else {
p.pattern.SetStyleSheet(fmt.Sprintf("background-color: %s;", bg.String()))
}
2018-12-27 21:03:21 +09:00
}
2017-06-28 08:28:24 +01:00
func (p *Palette) resize() {
2020-08-11 00:42:38 +09:00
eWidth := editor.window.Width() - 10
width := int(math.Trunc(float64(eWidth) * 0.7))
2019-09-08 21:40:15 +09:00
cursorBoundary := p.padding*4 + p.textLength() + p.patternPadding
2019-11-21 16:29:43 +09:00
if cursorBoundary > width {
width = cursorBoundary
2018-01-11 06:11:34 +00:00
}
2020-08-11 00:42:38 +09:00
if width > eWidth {
width = eWidth
2018-10-31 12:12:57 +09:00
p.pattern.SetAlignment(core.Qt__AlignRight | core.Qt__AlignCenter)
2020-08-11 00:42:38 +09:00
} else if width <= eWidth {
2018-10-31 12:12:57 +09:00
if p.pattern.Alignment() != core.Qt__AlignLeft {
p.pattern.SetAlignment(core.Qt__AlignLeft)
2018-09-02 15:55:24 +09:00
}
2018-10-31 12:12:57 +09:00
}
2017-06-28 08:28:24 +01:00
2019-11-21 16:29:43 +09:00
if p.width == width {
return
}
p.width = width
2019-09-08 21:40:15 +09:00
p.pattern.SetFixedWidth(p.width - p.padding*2)
2018-10-31 12:12:57 +09:00
p.widget.SetMaximumWidth(p.width)
p.widget.SetMinimumWidth(p.width)
2018-09-02 15:55:24 +09:00
2020-08-11 00:42:38 +09:00
x := eWidth - p.width
2018-10-31 12:12:57 +09:00
if x < 0 {
x = 0
}
2018-12-05 12:25:22 +09:00
p.widget.Move2(x/2, 10)
2018-09-02 15:55:24 +09:00
2020-07-30 22:50:02 +09:00
p.showTotal = 0
for i := p.showTotal; i < len(p.resultItems); i++ {
p.resultItems[i].hide()
}
}
func (p *Palette) resizeResultItems() {
if p.showTotal != 0 {
return
}
2018-10-31 12:12:57 +09:00
itemHeight := p.resultItems[0].widget.SizeHint().Height()
p.itemHeight = itemHeight
2019-03-13 17:35:59 +09:00
p.showTotal = int(float64(p.ws.height)/float64(itemHeight)*editor.config.Palette.AreaRatio) - 1
2020-07-30 22:50:02 +09:00
if p.ws.uiAttached {
fuzzy.UpdateMax(p.ws.nvim, p.showTotal)
2018-10-31 12:12:57 +09:00
}
2017-06-28 08:28:24 +01:00
}
func (p *Palette) show() {
2017-11-09 01:41:26 +00:00
if !p.hidden {
return
}
2020-07-30 22:50:02 +09:00
p.resizeResultItems()
2017-11-09 01:41:26 +00:00
p.hidden = false
2018-09-02 15:55:24 +09:00
p.widget.Raise()
p.widget.SetWindowOpacity(1.0)
2017-06-28 08:28:24 +01:00
p.widget.Show()
}
func (p *Palette) hide() {
2017-11-09 01:41:26 +00:00
if p.hidden {
return
}
p.hidden = true
2017-06-28 08:28:24 +01:00
p.widget.Hide()
}
2017-06-28 11:06:47 +01:00
func (p *Palette) setPattern(text string) {
p.patternText = text
p.pattern.SetText(text)
}
2017-06-28 08:28:24 +01:00
func (p *Palette) cursorMove(x int) {
2019-09-08 21:40:15 +09:00
X := p.textLength()
2019-11-21 16:29:43 +09:00
var stickOutLen int
2019-09-29 00:17:37 +09:00
boundary := p.pattern.Width() - (p.padding * 2)
2019-09-08 21:40:15 +09:00
if X >= boundary {
2019-11-21 16:29:43 +09:00
stickOutLen = X - boundary
}
pos := p.cursorPos(x) - stickOutLen
if pos < 0 {
pos = 0
2019-09-08 21:40:15 +09:00
}
2019-11-21 16:29:43 +09:00
p.cursorX = pos
2019-09-08 21:40:15 +09:00
p.ws.cursor.x = p.cursorX + p.patternPadding
p.ws.cursor.y = p.patternPadding + p.ws.cursor.shift
p.ws.cursor.widget.Move2(p.ws.cursor.x, p.ws.cursor.y+p.ws.cursor.shift+1)
2019-09-08 21:40:15 +09:00
p.ws.cursor.widget.SetParent(p.pattern)
2020-02-24 18:15:38 +09:00
p.redrawAllContentInWindows()
}
func (p *Palette) redrawAllContentInWindows() {
if runtime.GOOS != "windows" {
return
}
if p.ws.markdown.webview.IsVisible() {
2020-02-24 18:15:38 +09:00
return
}
p.hide()
p.resultWidget.Hide()
p.resultMainWidget.Hide()
p.show()
p.resultWidget.Show()
p.resultMainWidget.Show()
2019-09-08 21:40:15 +09:00
}
2019-09-15 23:09:46 +09:00
func (p *Palette) updateFont() {
font := gui.NewQFont2(editor.extFontFamily, editor.extFontSize, 1, false)
p.widget.SetFont(font)
p.pattern.SetFont(font)
}
2019-09-08 21:40:15 +09:00
func (p *Palette) textLength() int {
2019-09-15 23:09:46 +09:00
font := gui.NewQFontMetricsF(gui.NewQFont2(editor.extFontFamily, editor.extFontSize, 1, false))
2019-09-09 23:11:32 +09:00
l := 0
if p.isHTMLText {
t := gui.NewQTextDocument(nil)
t.SetHtml(p.patternText)
l = int(
font.HorizontalAdvance(
t.ToPlainText(),
-1,
),
)
} else {
l = int(
font.HorizontalAdvance(
p.patternText,
-1,
),
)
}
return l
2017-06-28 08:28:24 +01:00
}
2019-09-16 18:53:27 +09:00
func (p *Palette) cursorPos(x int) int {
font := gui.NewQFontMetricsF(gui.NewQFont2(editor.extFontFamily, editor.extFontSize, 1, false))
l := 0
if p.isHTMLText {
t := gui.NewQTextDocument(nil)
2019-09-16 19:28:02 +09:00
t.SetHtml(p.patternText)
2019-09-16 18:53:27 +09:00
l = int(
font.HorizontalAdvance(
2019-09-16 19:28:02 +09:00
t.ToPlainText()[:x],
2019-09-16 18:53:27 +09:00
-1,
),
)
} else {
l = int(
font.HorizontalAdvance(
p.patternText[:x],
-1,
),
)
}
return l
}
2017-06-28 08:28:24 +01:00
func (p *Palette) showSelected(selected int) {
if p.resultType == "file_line" {
n := 0
for i := 0; i <= selected; i++ {
for n++; n < len(p.itemTypes) && p.itemTypes[n] == "file"; n++ {
}
}
selected = n
}
for i, resultItem := range p.resultItems {
resultItem.setSelected(selected == i)
}
}
func (f *PaletteResultItem) update() {
2019-02-17 18:00:09 +09:00
c := editor.colors.selectedBg
// transparent := editor.config.Editor.Transparent
transparent := transparent()
2017-06-28 08:28:24 +01:00
if f.selected {
2019-02-17 18:00:09 +09:00
f.widget.SetStyleSheet(fmt.Sprintf(".QWidget {background-color: rgba(%d, %d, %d, %f);}", c.R, c.G, c.B, transparent))
2017-06-28 08:28:24 +01:00
} else {
f.widget.SetStyleSheet("")
}
2019-10-26 03:00:14 +09:00
// f.p.widget.Hide()
// f.p.widget.Show()
2019-02-17 18:00:09 +09:00
2017-06-28 08:28:24 +01:00
}
func (f *PaletteResultItem) setSelected(selected bool) {
if f.selected == selected {
return
}
f.selected = selected
f.update()
}
func (f *PaletteResultItem) show() {
2017-11-09 01:41:26 +00:00
// if f.hidden {
f.hidden = false
f.widget.Show()
// }
2017-06-28 08:28:24 +01:00
}
func (f *PaletteResultItem) hide() {
if !f.hidden {
f.hidden = true
f.widget.Hide()
}
}
func (f *PaletteResultItem) setItem(text string, itemType string, match []int) {
iconType := ""
path := false
if itemType == "dir" {
iconType = "folder"
path = true
} else if itemType == "file" {
iconType = getFileType(text)
path = true
} else if itemType == "file_line" {
iconType = "empty"
}
if iconType != "" {
if iconType != f.iconType {
f.iconType = iconType
f.updateIcon()
}
f.showIcon()
} else {
f.hideIcon()
}
formattedText := formatText(text, match, path)
if formattedText != f.baseText {
f.baseText = formattedText
f.base.SetText(f.baseText)
}
}
func (f *PaletteResultItem) updateIcon() {
2018-10-13 23:14:34 +09:00
svgContent := editor.getSvg(f.iconType, nil)
2017-06-28 08:28:24 +01:00
f.icon.Load2(core.NewQByteArray2(svgContent, len(svgContent)))
}
func (f *PaletteResultItem) showIcon() {
if f.iconHidden {
f.iconHidden = false
f.icon.Show()
}
}
func (f *PaletteResultItem) hideIcon() {
if !f.iconHidden {
f.iconHidden = true
f.icon.Hide()
}
}