Skip to content

Commit 3575e7f

Browse files
committed
[DynamicScript] Add property change signals for repeatingState and repeatCount; Move evaluate() to public API; Add setRepeating(); Rename enum MainExprDefault to LastExprDefault; Add and update documentation.
1 parent 99283ce commit 3575e7f

File tree

5 files changed

+136
-35
lines changed

5 files changed

+136
-35
lines changed

src/DSE.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,26 @@ namespace DSE
108108

109109
//! The global default action repeat rate (interval), in milliseconds. The rate is the amount of time to wait between repeat activations a held action.
110110
//! The repeat rate takes effect _after_ the initial repeat delay. Minimum interval is 50ms. \n
111-
//! This property has a change notification event: `defaultActionRepeatRateChanged(int ms)`. A callback can be attached to this method by using the `connect()` syntax, eg:
111+
//! This property has a change notification event: `defaultActionRepeatRateChanged(int ms)`.
112+
//! A callback can be attached to, or detached from, this method by using the `connect()` and `disconnect()` syntax, eg:
112113
//! ```js
113-
//! DSE.defaultActionRepeatRateChanged.connect( (ms) => { console.log("Repeat Rate changed to " + ms); } );
114+
//! function onRateChanged(ms) { console.log("Repeat Rate changed to " + ms); }
115+
//! DSE.defaultActionRepeatRateChanged.connect(onRateChanged);
116+
//! // ... later, to disconnect:
117+
//! DSE.defaultActionRepeatRateChanged.disconnect(onRateChanged);
114118
//! ```
115119
//! \sa defaultActionRepeatDelay, DynamicScript.repeatRate
116120
//! \since v1.2
117121
Q_PROPERTY(int defaultActionRepeatRate READ defaultActionRepeatRate WRITE setDefaultActionRepeatRate NOTIFY defaultActionRepeatRateChanged)
118122
//! The global default action repeat delay, in milliseconds. The delay is the amount of time before a held action starts repeating, after the initial activation.
119123
//! After this initial delay, the action will be repeated at the current repeat rate. Minimum delay is 50ms.
120-
//! This property has a change notification event: `defaultActionRepeatDelayChanged(int ms)`. A callback can be attached to this method by using the `connect()` syntax, eg:
124+
//! This property has a change notification event: `defaultActionRepeatDelayChanged(int ms)`.
125+
//! A callback can be attached to, or detached from, this method by using the `connect()` and `disconnect()` syntax, eg:
121126
//! ```js
122-
//! DSE.defaultActionRepeatDelayChanged.connect( (ms) => { console.log("Repeat Delay changed to " + ms); } );
127+
//! function onDelayChanged(ms) { console.log("Repeat Delay changed to " + ms); }
128+
//! DSE.defaultActionRepeatDelayChanged.connect(onDelayChanged);
129+
//! // ... later, to disconnect:
130+
//! DSE.defaultActionRepeatDelayChanged.disconnect(onDelayChanged);
123131
//! ```
124132
//! \sa defaultActionRepeatRate, DynamicScript.repeatDelay
125133
//! \since v1.2
@@ -184,11 +192,11 @@ namespace DSE
184192
static DseNS::SavedDefaultType SavedDefaultType_NoSavedDefault() { return DseNS::NoSavedDefault; }
185193
static DseNS::SavedDefaultType SavedDefaultType_FixedValueDefault() { return DseNS::FixedValueDefault; }
186194
static DseNS::SavedDefaultType SavedDefaultType_CustomExprDefault() { return DseNS::CustomExprDefault; }
187-
static DseNS::SavedDefaultType SavedDefaultType_MainExprDefault() { return DseNS::MainExprDefault; }
195+
static DseNS::SavedDefaultType SavedDefaultType_LastExprDefault() { return DseNS::LastExprDefault; }
188196
Q_PROPERTY(DseNS::SavedDefaultType NoSavedDefault READ SavedDefaultType_NoSavedDefault CONSTANT)
189197
Q_PROPERTY(DseNS::SavedDefaultType FixedValueDefault READ SavedDefaultType_FixedValueDefault CONSTANT)
190198
Q_PROPERTY(DseNS::SavedDefaultType CustomExprDefault READ SavedDefaultType_CustomExprDefault CONSTANT)
191-
Q_PROPERTY(DseNS::SavedDefaultType MainExprDefault READ SavedDefaultType_MainExprDefault CONSTANT)
199+
Q_PROPERTY(DseNS::SavedDefaultType LastExprDefault READ SavedDefaultType_LastExprDefault CONSTANT)
192200

193201
static DseNS::ActivationBehavior ActivationBehavior_NoActivation() { return DseNS::NoActivation; }
194202
static DseNS::ActivationBehavior ActivationBehavior_OnPress() { return DseNS::OnPress; }

src/DSE_NS.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ enum SavedDefaultType : quint8 {
5858
NoSavedDefault, //!< The instance is not saved in persistent settings, default value type is not applicatble.
5959
FixedValueDefault, //!< Instance is created with a fixed default or empty value (specified in `DynamicScript.defaultValue`)
6060
CustomExprDefault, //!< Instance is created with default value coming from evaluating a custom expression (specified in `DynamicScript.defaultValue`)
61-
MainExprDefault, //!< Instance is created with default value coming from evaluating the last saved primary expression
61+
LastExprDefault, //!< Instance is created with default value coming from evaluating the last saved primary expression
6262
//! (exactly as last sent from the corresponding Touch Portal action/connector).
6363
};
6464
Q_ENUM_NS(SavedDefaultType)

src/DynamicScript.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -313,16 +313,10 @@ void DynamicScript::setPressed(bool isPressed)
313313
if (m_state.testFlags(State::PressedState) == isPressed)
314314
return;
315315

316-
if (this->isPressed()) {
317-
m_state.setFlag(State::RepeatingState, false);
318-
m_state.setFlag(State::HoldReleasedState, true);
319-
}
320-
else {
321-
m_repeatCount = 0;
322-
m_activeRepeatRate = -1;
323-
}
324-
325316
m_state.setFlag(State::PressedState, isPressed);
317+
if (!isPressed)
318+
setRepeating(false);
319+
326320
Q_EMIT pressedStateChanged(isPressed);
327321
}
328322

@@ -372,9 +366,10 @@ void DynamicScript::repeatEvaluate()
372366
if (m_maxRepeatCount < 0 || m_repeatCount < m_maxRepeatCount) {
373367
++m_repeatCount;
374368
evaluate();
369+
Q_EMIT repeatCountChanged(m_repeatCount);
375370
return;
376371
}
377-
m_state.setFlag(State::RepeatingState, false);
372+
setRepeating(false);
378373
}
379374
setupRepeatTimer(false);
380375
}
@@ -386,7 +381,7 @@ bool DynamicScript::scheduleRepeatIfNeeded()
386381
if (delay >= 50) {
387382
setupRepeatTimer();
388383
m_repeatTim->start(delay);
389-
m_state.setFlag(State::RepeatingState, true);
384+
setRepeating(true);
390385
return true;
391386
}
392387
}
@@ -467,7 +462,7 @@ QByteArray DynamicScript::getDefaultValue()
467462
return QByteArray();
468463

469464
QReadLocker lock(&m_mutex);
470-
const QString expr = m_defaultType == SavedDefaultType::CustomExprDefault ? m_defaultValue : m_defaultType == SavedDefaultType::MainExprDefault ? m_expr : QByteArray();
465+
const QString expr = m_defaultType == SavedDefaultType::CustomExprDefault ? m_defaultValue : m_defaultType == SavedDefaultType::LastExprDefault ? m_expr : QByteArray();
471466
QJSValue res;
472467
switch (m_inputType) {
473468
case ScriptInputType::ExpressionInput:

src/DynamicScript.h

Lines changed: 112 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class DynamicScript : public QObject
100100
//! to a settings file when DSE exits, and restored from settings the next time DSE starts. "Temporary" instances will be automatically deleted after a time span specified in \ref autoDeleteDelay.
101101
Q_PROPERTY(DseNS::PersistenceType persistence READ persistence WRITE setPersistence)
102102
//! When \ref persistence is of `DSE.PersistSave` type, this property value determines what happens when this instance is initially loaded from storage.
103-
//! `DSE.SavedDefaultType` enumeration value, one of: `DSE.FixedValueDefault`, `DSE.CustomExprDefault`, `DSE.MainExprDefault`
103+
//! `DSE.SavedDefaultType` enumeration value, one of: `DSE.FixedValueDefault`, `DSE.CustomExprDefault`, `DSE.LastExprDefault`
104104
//! \sa defaultValue, persistence
105105
Q_PROPERTY(DseNS::SavedDefaultType defaultType READ defaultType WRITE setDefaultType)
106106
//! The default value specified for saved instance, if any. Depending on the value of \ref defaultType, this could be an empty string, a fixed default string value, or an expression to be evaluated.
@@ -185,15 +185,15 @@ class DynamicScript : public QObject
185185
//! - `DSE.RepeatOnHold` - Ignores the initial button press and then starts repeating the evaluation after \ref effectiveRepeatDelay ms, until it is released.
186186
//! - `DSE.OnRelease` - Evaluates expression only when button is released. This is the default behavior when using an action in Touch Portal's "On Pressed" button setup (which actually triggers actions upon button release).
187187
Q_PROPERTY(DseNS::ActivationBehaviors activation READ activation WRITE setActivation)
188-
//! The default action repeat rate for this particular instance, in milliseconds. If `-1` (default) then the global default rate is used. \sa activeRepeatRate, DSE.defaultActionRepeatRate
188+
//! The default action repeat rate for this particular instance, in milliseconds. If `-1` (default) then the global default rate is used. \sa, activeRepeatRate, DSE.defaultActionRepeatRate, repeatRateChanged()
189189
Q_PROPERTY(int repeatRate READ repeatRate WRITE setRepeatRate NOTIFY repeatRateChanged)
190-
//! The default action repeat delay for this particular instance, in milliseconds. If `-1` (default) then the global default rate is used. \sa activeRepeatDelay, DSE.defaultActionRepeatDelay
190+
//! The default action repeat delay for this particular instance, in milliseconds. If `-1` (default) then the global default rate is used. \sa activeRepeatDelay, DSE.defaultActionRepeatDelay, repeatDelayChanged()
191191
Q_PROPERTY(int repeatDelay READ repeatDelay WRITE setRepeatDelay NOTIFY repeatDelayChanged)
192192
//! The action repeat rate for the _currently repeating_ script action, in milliseconds. Changes to this value are only relevant while an action is actively repeating (\ref isRepeating == `true`).
193-
//! If `-1` (default) then \ref repeatRate or the global default rate is used.
193+
//! If `-1` (default) then \ref repeatRate or the global default rate is used. \sa activeRepeatRateChanged()
194194
Q_PROPERTY(int activeRepeatRate READ activeRepeatRate WRITE setActiveRepeatRate NOTIFY activeRepeatRateChanged)
195195
//! The action repeat delay time for the _currently repeating_ script action, in milliseconds. Changes to this value are only relevant while an action is actively repeating (\ref isRepeating == `true`).
196-
//! If `-1` (default) then \ref repeatDelay or the global default delay is used.
196+
//! If `-1` (default) then \ref repeatDelay or the global default delay is used. \sa activeRepeatDelayChanged()
197197
Q_PROPERTY(int activeRepeatDelay READ activeRepeatDelay WRITE setActiveRepeatDelay NOTIFY activeRepeatDelayChanged)
198198
//! The currently effective action repeat rate which is either the global default rate, or this instance's \ref repeatRate if set, or \ref activeRepeatRate if it was set and \ref isRepeating is `true`.
199199
//! \n This property is read-only.
@@ -203,12 +203,19 @@ class DynamicScript : public QObject
203203
Q_PROPERTY(int effectiveRepeatDelay READ effectiveRepeatDelay CONSTANT)
204204
//! Get or set the maximum number of times this action will repeat when held. A value of `-1` (default) means to repeat an unlimited number of times. Setting the value to `0` effectively disables repeating.
205205
Q_PROPERTY(int maxRepeatCount READ maxRepeatCount WRITE setMaxRepeatCount)
206-
//! The number of times the current, or last, repeating action of this instance has repeated. The property is reset to zero when the action if first invoked.
206+
//! The number of times the current, or last, repeating action of this instance has repeated. The property is reset to zero when the \ref isRepeating property changes
207+
//! from `false` to `true` -- that is, every time the repetition is about to start, but before the initial \ref effectiveRepeatDelay time has passed. \sa repeatCountChanged(), isRepeating, isPressed
207208
//! \n This property is read-only.
208-
Q_PROPERTY(int repeatCount READ repeatCount CONSTANT)
209-
//! `true` if an Action using this instance is currently repeating, `false` otherwise.
209+
Q_PROPERTY(int repeatCount READ repeatCount NOTIFY repeatCountChanged)
210+
//! `true` if this script evaluation is currently repeating, `false` otherwise.
211+
//! The value changes to `true` every time the repetition is about to start, but before the initial \ref effectiveRepeatDelay time has passed.
212+
//! For example it is possible to cancel a repitition before it even starts by setting \ref isPressed to `false` whenever whenever this property changes. \sa repeatingStateChanged()
210213
//! \n This property is read-only.
211-
Q_PROPERTY(bool isRepeating READ isRepeating CONSTANT)
214+
Q_PROPERTY(bool isRepeating READ isRepeating NOTIFY repeatingStateChanged)
215+
//! This property value is `true` if a button using an Action which invokes this script is currently being held down, `false` otherwise.
216+
//! The value can be changed by setting the property or calling the `setPressedState()` method, which has further documentation on what this means.
217+
//! \sa pressedStateChanged()
218+
Q_PROPERTY(bool isPressed READ isPressed WRITE setPressedState NOTIFY pressedStateChanged)
212219
//! \}
213220

214221
enum State : quint16 {
@@ -393,29 +400,120 @@ class DynamicScript : public QObject
393400
inline void stateUpdate(const QByteArray &value) {
394401
if (createState()) {
395402
// FIXME: TP v3.1 doesn't fire state change events based on the default value; v3.2 might.
396-
createTpState(/*m_defaultType != DseNS::SavedDefaultType::MainExprDefault*/);
403+
createTpState(/*m_defaultType != DseNS::SavedDefaultType::LastExprDefault*/);
397404
Q_EMIT dataReady(tpStateId, value);
398405
//qCDebug(lcPlugin) << "DynamicScript instance" << name << "sending result:" << value;
399406
}
400407
}
401408

409+
/*!
410+
Callling this method causes the instance to evaluate its current \ref expression, basically as if it was invoked
411+
from a Touch Portal Action or Connector. This includes loading any script file or importing a module
412+
as per the current \ref inputType, \ref scriptFile, and \ref moduleAlias property settings.
413+
414+
__Note__ that we cannot retrieve data/values _from_ Touch Portal directly, it has to send them to us via an
415+
Action. So if the \ref expression originally gets some data value(s) provided by %TP itself (from a Value or State),
416+
the _last_ data it sent gets evaluated. There is no way to retrieve a more current value, and in fact the script
417+
instance itself isn't even aware that some Value or State was involved in the first place
418+
(it only gets the data from the Value/State, not the name or ID).
419+
*/
420+
void evaluate();
421+
422+
/*!
423+
This method provides direct control over the current "pressed state" of this script instance, which can be `true` or `false`.
424+
Normally an instance can be "pressed" and "released" when its corresponding Action is used in a Touch Portal button's
425+
"On Hold" setup tab. An action used there sends two events to the plugin, one for the "down" event, when the button
426+
is first pressed, and another for the "up" event.
427+
428+
Setting the pressed state to `false` while an action's button is being held and is repeating, for example,
429+
will cancel any further repeats, just as if the button had been released by the user.
430+
Setting the pressed state to `true` will not have any immediate effect until the next time the the action's expression
431+
is evaluated, either by using its corresponding action in Touch Portal, or by calling the `evaluate()` method.
432+
Once evaluation is performed, the behavior will depend on the current value of the \ref activation property (eg. the action
433+
could start repeating, wait for a delay, or be "armed" for a release/up event).
434+
\sa isPressed, pressedStateChanged()
435+
*/
402436
void setPressedState(bool isPressed);
403437

404438
Q_SIGNALS:
439+
/*!
440+
\name Events
441+
All these events correspond to changes in property values, provided as a way for a script to take some
442+
immediate action based on a new value for that property, vs, say, having to check the values periodically with a timer.
443+
444+
Callbacks can be attached to, or detached from, events by using the `connect()` and `disconnect()` syntax. For example:
445+
```js
446+
function onPressStateChange(isPressed) {
447+
console.log("The button has been " + (isPressed ? "pressed" : "released"));
448+
}
449+
450+
DSE.pressedStateChanged.connect(onPressStateChange);
451+
// ... later, to disconnect:
452+
DSE.pressedStateChanged.disconnect(onPressStateChange);
453+
```
454+
455+
\{
456+
*/
457+
458+
/*!
459+
This event is only emitted when an action is used in an "On Hold" button setup. When the button using this action
460+
is first pressed down, this event is emitted with the `isPressed` parameter set to `true`. When the button is later
461+
released, the event is emitted again with the parameter set to `false`.
462+
463+
The event is emitted regardless of the \ref activation property value, as long as the button is being used in the "On Hold" tab
464+
(when an action is used in the "On Pressed" tab setup, it is actually only activated when the button is _released_, so this event
465+
would have no relevance). \n
466+
This allows custom behavior for a button from within a script handler -- for example different actions could be performed
467+
on button press vs. release.
468+
\sa isPressed, setPressedState()
469+
*/
470+
void pressedStateChanged(bool isPressed);
471+
//! This event is emitted when an evaluation starts or stops repeating (as per the \ref activation property).
472+
//! The `isRepeating` parameter reflects the current (new) value of the \ref isRepeating property.
473+
void repeatingStateChanged(bool isRepeating);
474+
//! This event is emitted when the value of the \ref repeatCount property changes, meaning whenever the evaluation is repeated,
475+
//! or when a new "repetition" starts. See \ref repeatCount for more details.
476+
//! The `repeatCount` parameter value reflects the current (new) \ref repeatCount property value.
477+
void repeatCountChanged(int repeatCount);
478+
//! This event is emitted when the value of the \ref repeatRate property changes.
479+
//! The `ms` parameter value reflects the current (new) \ref repeatRate property value.
405480
void repeatRateChanged(int ms);
481+
//! This event is emitted when the value of the \ref repeatDelay property changes.
482+
//! The `ms` parameter value reflects the current (new) \ref repeatDelay property value.
406483
void repeatDelayChanged(int ms);
484+
//! This event is emitted when the value of the \ref activeRepeatRate property changes.
485+
//! The `ms` parameter value reflects the current (new) \ref activeRepeatRate property value.
407486
void activeRepeatRateChanged(int ms);
487+
//! This event is emitted when the value of the \ref activeRepeatDelay property changes.
488+
//! The `ms` parameter value reflects the current (new) \ref activeRepeatDelay property value.
408489
void activeRepeatDelayChanged(int ms);
409-
void pressedStateChanged(bool isHeld);
490+
491+
//! \}
410492

411493
private Q_SLOTS:
412-
// These are private to keep them hidden from scripting environment. `Plugin` is marked as friend to use these methods.
413-
void evaluate();
494+
// This is private to keep it hidden from scripting environment (for now?). `Plugin` is marked as friend to use these methods.
414495
void evaluateDefault();
415496

416497
// these really _are_ private
417-
void serializeStoredData();
498+
499+
inline void setRepeating(bool repeating)
500+
{
501+
if (m_state.testFlags(State::RepeatingState) == repeating)
502+
return;
503+
m_state.setFlag(State::RepeatingState, repeating);
504+
if (repeating) {
505+
m_activeRepeatRate = -1;
506+
m_repeatCount = 0;
507+
Q_EMIT repeatCountChanged(0);
508+
}
509+
else {
510+
m_state.setFlag(State::HoldReleasedState, true);
511+
}
512+
Q_EMIT repeatingStateChanged(repeating);
513+
}
514+
418515
void setPressed(bool isPressed);
516+
void serializeStoredData();
419517
void setupRepeatTimer(bool create = true);
420518
void repeatEvaluate();
421519
QByteArray getDefaultValue();

src/Plugin.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ static DseNS::SavedDefaultType stringToDefaultType(QStringView str)
8282
return str.isEmpty() || str[0] == 'N' ? SavedDefaultType::NoSavedDefault :
8383
str[0] == 'F' ? SavedDefaultType::FixedValueDefault :
8484
str[0] == 'C' ? SavedDefaultType::CustomExprDefault :
85-
SavedDefaultType::MainExprDefault;
85+
SavedDefaultType::LastExprDefault;
8686
}
8787

8888
static DseNS::PersistenceType stringToPersistenceType(QStringView str)
@@ -106,7 +106,7 @@ static DseNS::SavedDefaultType stringToSavedDefaultType(QStringView str)
106106
case 'C':
107107
return SavedDefaultType::CustomExprDefault;
108108
case 'L':
109-
return SavedDefaultType::MainExprDefault;
109+
return SavedDefaultType::LastExprDefault;
110110
default:
111111
return SavedDefaultType::FixedValueDefault;
112112
}

0 commit comments

Comments
 (0)