Implement customizable actions
This commit is contained in:
parent
fd81e24976
commit
f5510a7944
11 changed files with 282 additions and 38 deletions
62
lisp/local-projects/sextant/models/actions.lisp
Normal file
62
lisp/local-projects/sextant/models/actions.lisp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
(uiop:define-package :sextant/models/actions
|
||||
(:use :cl :eql :qml :options
|
||||
:sextant/models/org-model))
|
||||
(in-package :sextant/models/actions)
|
||||
|
||||
(defmacro defaction (action-name types &body body)
|
||||
(declare (ignore types))
|
||||
`(prog1
|
||||
(defun ,action-name (ui-item node coords)
|
||||
(declare (ignorable ui-item node coords))
|
||||
,@body
|
||||
nil)
|
||||
(push-action (symbol-name ',action-name) ',types)))
|
||||
|
||||
(defaction raw-edit (org-line org-headline)
|
||||
(qjs |setFocus| ui-item)
|
||||
(qjs |setCursorPositionAt| ui-item (car coords) (cdr coords))
|
||||
(qjs |editRawText| ui-item))
|
||||
|
||||
(defaction nothing (org-line org-headline)
|
||||
)
|
||||
|
||||
|
||||
|
||||
(defmacro defaction-type (type)
|
||||
`(progn
|
||||
,(let ((symbol (intern (concatenate 'string (symbol-name type) "-CLICKED")))
|
||||
(funsym (intern (concatenate 'string "CLICK-ON-" (symbol-name type))
|
||||
:sextant/options/options)))
|
||||
`(prog1
|
||||
(defun ,symbol (index x y)
|
||||
(let ((funsym ,funsym))
|
||||
(when funsym
|
||||
(let ((fun (intern funsym #.*package*)))
|
||||
(when (fboundp fun)
|
||||
(funcall fun *caller* (goto-index index) (cons x y)))))))
|
||||
(export ',symbol)))
|
||||
,(let ((symbol (intern (concatenate 'string (symbol-name type) "-DOUBLE-CLICKED")))
|
||||
(funsym (intern (concatenate 'string "DOUBLE-CLICK-ON-" (symbol-name type))
|
||||
:sextant/options/options)))
|
||||
`(prog1
|
||||
(defun ,symbol (index x y)
|
||||
(let ((funsym ,funsym))
|
||||
(when funsym
|
||||
(let ((fun (intern funsym #.*package*)))
|
||||
(when (fboundp fun)
|
||||
(funcall fun *caller* (goto-index index) (cons x y)))))))
|
||||
(export ',symbol)))
|
||||
,(let ((symbol (intern (concatenate 'string (symbol-name type) "-PRESS-AND-HOLD")))
|
||||
(funsym (intern (concatenate 'string "PRESS-AND-HOLD-ON-" (symbol-name type))
|
||||
:sextant/options/options)))
|
||||
`(prog1
|
||||
(defun ,symbol (index x y)
|
||||
(let ((funsym ,funsym))
|
||||
(when funsym
|
||||
(let ((fun (intern funsym #.*package*)))
|
||||
(when (fboundp fun)
|
||||
(funcall fun *caller* (goto-index index) (cons x y)))))))
|
||||
(export ',symbol)))))
|
||||
|
||||
(defaction-type org-line)
|
||||
(defaction-type org-headline)
|
||||
|
|
@ -4,4 +4,5 @@
|
|||
:sextant/models/utils
|
||||
:sextant/models/files-model
|
||||
:sextant/models/commands
|
||||
:sextant/models/actions
|
||||
:sextant/models/org-model))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
(uiop:define-package :sextant/options/options
|
||||
(:use :cl :sextant/options/config))
|
||||
(:use :cl :sextant/options/config)
|
||||
(:export #:push-action))
|
||||
(in-package :sextant/options/options)
|
||||
|
||||
(set-config-package :sextant/options/options)
|
||||
|
|
@ -20,4 +21,33 @@
|
|||
(defconfig undo-history-size 100)
|
||||
(defconfig recent-files-size 10)
|
||||
|
||||
(eval-when (:compile-toplevel :load-toplevel)
|
||||
(defun push-action (action-name types)
|
||||
(dolist (type types)
|
||||
(pushnew action-name (get (intern (concatenate 'string (symbol-name type) "-ACTIONS")
|
||||
#.*package*)
|
||||
'actions)))))
|
||||
|
||||
(defmacro defaction-config (choices-list-symbol &rest config-name/value)
|
||||
`(progn
|
||||
,(let ((list-getter (intern (concatenate 'string "GET-" (symbol-name choices-list-symbol)))))
|
||||
`(prog1
|
||||
(defun ,list-getter (index)
|
||||
(nth index (get ',choices-list-symbol 'actions)))
|
||||
(export ',list-getter)))
|
||||
,@(loop for action on config-name/value by #'cddr
|
||||
collect `(defconfig ,(first action) ,(second action)
|
||||
:set ((index)
|
||||
(setf ,(first action) (nth index (get ',choices-list-symbol 'actions))))))))
|
||||
|
||||
(defaction-config org-line-actions
|
||||
click-on-org-line "RAW-EDIT"
|
||||
double-click-on-org-line "NOTHING"
|
||||
press-and-hold-on-org-line "NOTHING")
|
||||
|
||||
(defaction-config org-headline-actions
|
||||
click-on-org-headline "RAW-EDIT"
|
||||
double-click-on-org-headline "NOTHING"
|
||||
press-and-hold-on-org-headline "NOTHING")
|
||||
|
||||
(defconfig slynk-at-startup-p nil)
|
||||
|
|
|
|||
43
qml/components/ActionComboBox.qml
Normal file
43
qml/components/ActionComboBox.qml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import EQL5 1.0
|
||||
|
||||
ComboBox {
|
||||
id: actionComboBox
|
||||
width: parent.width
|
||||
|
||||
property string list
|
||||
property string getter
|
||||
property string setter
|
||||
|
||||
menu: ContextMenu {
|
||||
Repeater {
|
||||
model: ListModel {
|
||||
|
||||
function populate () {
|
||||
var current = Lisp.call(getter)
|
||||
var i = 0
|
||||
var item = Lisp.call(list, i)
|
||||
while (item) {
|
||||
append({inputText: item})
|
||||
|
||||
if (item == current)
|
||||
actionComboBox.currentIndex = i
|
||||
|
||||
item = Lisp.call(list, ++i)
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: populate()
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: inputText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onCurrentItemChanged: {
|
||||
Lisp.call(setter, currentIndex)
|
||||
}
|
||||
}
|
||||
|
|
@ -38,4 +38,5 @@ Item {
|
|||
|
||||
function forceCommit (update) { loader.item.forceCommit(update) }
|
||||
function setCursorPositionAtEnd (fix) { loader.item.setCursorPositionAtEnd(fix) }
|
||||
function editRawText () { loader.item.editRawText() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ TextArea {
|
|||
property bool textModified: false
|
||||
property int fixedCursorPosition: -1
|
||||
|
||||
signal loseFocus
|
||||
|
||||
text: index > 0 ? sentinelChar + rawtext : (index == 0 ? rawtext : "")
|
||||
|
||||
anchors {
|
||||
|
|
@ -24,10 +26,7 @@ TextArea {
|
|||
labelVisible: false
|
||||
inputMethodHints: Qt.ImhNoAutoUppercase
|
||||
|
||||
onCursorPositionChanged: {
|
||||
if (index > 0 && cursorPosition == 0)
|
||||
cursorPosition = 1
|
||||
}
|
||||
onCursorPositionChanged: { refreshCursorPosition() }
|
||||
|
||||
onSelectionStartChanged: {
|
||||
if (index > 0 && selectionStart == 0)
|
||||
|
|
@ -36,23 +35,23 @@ TextArea {
|
|||
|
||||
onTextChanged: {
|
||||
if (visible) {
|
||||
if (fixedCursorPosition != -1) {
|
||||
cursorPosition = fixedCursorPosition
|
||||
fixedCursorPosition = -1
|
||||
}
|
||||
refreshCursorPosition()
|
||||
if (index >= 0) {
|
||||
if (index > 0 && text[0] != sentinelChar) {
|
||||
var textEmpty = text.length != 0
|
||||
var textEmpty = text.length == 0
|
||||
forceCommit(false)
|
||||
document.focusedIndex = index - 1
|
||||
document.focusedItem.setCursorPositionAtEnd(textEmpty)
|
||||
var focusedItem = document.focusedItem
|
||||
focusedItem.setCursorPositionAtEnd(!textEmpty)
|
||||
Lisp.call("models:join-node", index - 1, true)
|
||||
focusedItem.editRawText()
|
||||
} else {
|
||||
var split = text.indexOf("\n")
|
||||
if (split != -1) {
|
||||
forceCommit(false)
|
||||
Lisp.call("models:split-node", index, text.substring(index > 0 ? 1 : 0, split), text.substring(split + 1), true)
|
||||
document.focusedIndex = index + 1
|
||||
document.focusedItem.editRawText()
|
||||
} else {
|
||||
lastText = getText()
|
||||
textModified = lastText != rawtext
|
||||
|
|
@ -71,6 +70,7 @@ TextArea {
|
|||
document.focusedIndex = -1
|
||||
|
||||
forceCommit(true)
|
||||
loseFocus()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,11 +84,20 @@ TextArea {
|
|||
function initFocus() {
|
||||
if (visible) {
|
||||
forceActiveFocus()
|
||||
if (index > 0 && cursorPosition == 0)
|
||||
cursorPosition = 1
|
||||
refreshCursorPosition()
|
||||
}
|
||||
}
|
||||
|
||||
function refreshCursorPosition () {
|
||||
if (fixedCursorPosition != -1) {
|
||||
cursorPosition = fixedCursorPosition
|
||||
fixedCursorPosition = -1
|
||||
}
|
||||
|
||||
if (index > 0 && cursorPosition == 0)
|
||||
cursorPosition = 1
|
||||
}
|
||||
|
||||
function forceCommit (update) {
|
||||
if (textModified) {
|
||||
textModified = false
|
||||
|
|
@ -102,6 +111,7 @@ TextArea {
|
|||
|
||||
function setCursorPositionAtEnd (fix) {
|
||||
if (fix) {
|
||||
console.log("fixed " + text.length)
|
||||
fixedCursorPosition = text.length
|
||||
} else {
|
||||
cursorPosition = text.length
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import EQL5 1.0
|
||||
|
||||
OrgText {
|
||||
id: orgHeadline
|
||||
|
||||
contentHeight: titleLabel.contentHeight
|
||||
editing: orgItem.focused
|
||||
|
||||
Label {
|
||||
id: bullet
|
||||
|
|
@ -20,7 +20,7 @@ OrgText {
|
|||
family: Theme.fontFamilyHeading
|
||||
}
|
||||
|
||||
visible: !orgItem.focused
|
||||
visible: !editing
|
||||
text: "*"
|
||||
}
|
||||
|
||||
|
|
@ -39,8 +39,20 @@ OrgText {
|
|||
family: Theme.fontFamilyHeading
|
||||
}
|
||||
|
||||
visible: !orgItem.focused
|
||||
visible: !editing
|
||||
text: title
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
Lisp.call(this, "models:org-headline-clicked", index, mouse.x, mouse.y)
|
||||
}
|
||||
|
||||
onDoubleClicked: {
|
||||
Lisp.call(this, "models:org-headline-double-clicked", index, mouse.x, mouse.y)
|
||||
}
|
||||
|
||||
onPressAndHold: {
|
||||
Lisp.call(this, "models:org-headline-press-and-hold", index, mouse.x, mouse.y)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import EQL5 1.0
|
||||
|
||||
OrgText {
|
||||
id: orgLine
|
||||
|
||||
contentHeight: label.contentHeight
|
||||
editing: orgItem.focused
|
||||
|
||||
Label {
|
||||
id: label
|
||||
|
|
@ -16,8 +16,21 @@ OrgText {
|
|||
rightMargin: Theme.paddingSmall
|
||||
}
|
||||
|
||||
visible: !orgItem.focused
|
||||
visible: !editing
|
||||
text: rawtext
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
Lisp.call(this, "models:org-line-clicked", index, mouse.x, mouse.y)
|
||||
}
|
||||
|
||||
onDoubleClicked: {
|
||||
Lisp.call(this, "models:org-line-double-clicked", index, mouse.x, mouse.y)
|
||||
}
|
||||
|
||||
onPressAndHold: {
|
||||
Lisp.call(this, "models:org-line-press-and-hold", index, mouse.x, mouse.y)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,14 @@ MouseArea {
|
|||
OrgEdit {
|
||||
id: edit
|
||||
visible: editing
|
||||
|
||||
onLoseFocus: {
|
||||
editing = false
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
edit.setCursorPositionAt(mouse.x, mouse.y)
|
||||
document.focusedIndex = index
|
||||
}
|
||||
function setFocus() { document.focusedIndex = index }
|
||||
function editRawText() { editing = true }
|
||||
|
||||
function forceCommit (update) { edit.forceCommit(update) }
|
||||
function setCursorPositionAt (x, y) { edit.setCursorPositionAt(x, y) }
|
||||
|
|
|
|||
|
|
@ -48,23 +48,91 @@ Page {
|
|||
onValueChanged: Lisp.call("options:set-recent-files-size", value)
|
||||
}
|
||||
|
||||
SectionHeader {
|
||||
text: qsTr("Development")
|
||||
}
|
||||
ExpandingSectionGroup {
|
||||
currentIndex: -1
|
||||
|
||||
TextSwitch {
|
||||
text: qsTr("Enable Slynk at startup")
|
||||
checked: Lisp.call("options:get-slynk-at-startup-p")
|
||||
onCheckedChanged: Lisp.call("options:set-slynk-at-startup-p", checked)
|
||||
}
|
||||
ExpandingSection {
|
||||
id: actions
|
||||
title: qsTr("Actions")
|
||||
|
||||
Button {
|
||||
text: qsTr("Start")
|
||||
visible: false
|
||||
enabled: !Lisp.call("sextant:slynkp")
|
||||
onClicked: {
|
||||
Lisp.call("sextant:start-slynk")
|
||||
enabled = !Lisp.call("sextant:slynkp")
|
||||
content.sourceComponent: Column {
|
||||
width: actions.width
|
||||
|
||||
SectionHeader {
|
||||
text: qsTr("Line")
|
||||
}
|
||||
|
||||
ActionComboBox {
|
||||
label: qsTr("On clicked")
|
||||
list: "options:get-org-line-actions"
|
||||
getter: "options:get-click-on-org-line"
|
||||
setter: "options:set-click-on-org-line"
|
||||
}
|
||||
|
||||
ActionComboBox {
|
||||
label: qsTr("On double-clicked")
|
||||
list: "options:get-org-line-actions"
|
||||
getter: "options:get-double-click-on-org-line"
|
||||
setter: "options:set-double-click-on-org-line"
|
||||
}
|
||||
|
||||
ActionComboBox {
|
||||
label: qsTr("On press and hold")
|
||||
list: "options:get-org-line-actions"
|
||||
getter: "options:get-press-and-hold-on-org-line"
|
||||
setter: "options:set-press-and-hold-on-org-line"
|
||||
}
|
||||
|
||||
SectionHeader {
|
||||
text: qsTr("Headline")
|
||||
}
|
||||
|
||||
ActionComboBox {
|
||||
label: qsTr("On clicked")
|
||||
list: "options:get-org-headline-actions"
|
||||
getter: "options:get-click-on-org-headline"
|
||||
setter: "options:set-click-on-org-headline"
|
||||
}
|
||||
|
||||
ActionComboBox {
|
||||
label: qsTr("On double-clicked")
|
||||
list: "options:get-org-headline-actions"
|
||||
getter: "options:get-double-click-on-org-headline"
|
||||
setter: "options:set-double-click-on-org-headline"
|
||||
}
|
||||
|
||||
ActionComboBox {
|
||||
label: qsTr("On press and hold")
|
||||
list: "options:get-org-headline-actions"
|
||||
getter: "options:get-press-and-hold-on-org-headline"
|
||||
setter: "options:set-press-and-hold-on-org-headline"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExpandingSection {
|
||||
id: development
|
||||
title: qsTr("Development")
|
||||
|
||||
content.sourceComponent: Column {
|
||||
width: section.width
|
||||
|
||||
TextSwitch {
|
||||
text: qsTr("Enable Slynk at startup")
|
||||
checked: Lisp.call("options:get-slynk-at-startup-p")
|
||||
onCheckedChanged: Lisp.call("options:set-slynk-at-startup-p", checked)
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Start")
|
||||
visible: false
|
||||
enabled: !Lisp.call("sextant:slynkp")
|
||||
onClicked: {
|
||||
Lisp.call("sextant:start-slynk")
|
||||
enabled = !Lisp.call("sextant:slynkp")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ LISP_FILES = make.lisp \
|
|||
lisp/local-projects/sextant/models/utils.lisp \
|
||||
lisp/local-projects/sextant/models/org-model.lisp \
|
||||
lisp/local-projects/sextant/models/files-model.lisp \
|
||||
lisp/local-projects/sextant/models/all.lisp \
|
||||
lisp/local-projects/sextant/models/commands.lisp \
|
||||
lisp/local-projects/sextant/models/actions.lisp \
|
||||
lisp/local-projects/sextant/models/all.lisp \
|
||||
lisp/local-projects/sextant/sextant.lisp \
|
||||
lisp/local-projects/sextant/sextant.asd \
|
||||
lisp/local-projects/sextant/org/parser.lisp \
|
||||
|
|
@ -57,6 +58,7 @@ SOURCES += src/harbour-sextant.cc
|
|||
DISTFILES += qml/harbour-sextant.qml \
|
||||
qml/cover/CoverPage.qml \
|
||||
qml/components/ListTextField.qml \
|
||||
qml/components/ActionComboBox.qml \
|
||||
qml/components/OrgDelegate.qml \
|
||||
qml/components/OrgLine.qml \
|
||||
qml/components/OrgText.qml \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue