@dusted/anqst 0.1.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/app.js +86 -103
- package/dist/src/build-stamp.js +5 -0
- package/dist/src/emit.js +530 -89
- package/dist/src/parser.js +159 -8
- package/dist/src/verify.js +6 -1
- package/package.json +3 -2
- package/spec/AnQst-Spec-DSL.d.ts +323 -213
package/dist/src/emit.js
CHANGED
|
@@ -626,6 +626,27 @@ function buildCppTypeContext(spec) {
|
|
|
626
626
|
}
|
|
627
627
|
return normalizer.buildContext();
|
|
628
628
|
}
|
|
629
|
+
function collectDragDropMimeConstants(spec) {
|
|
630
|
+
const seen = new Set();
|
|
631
|
+
const constants = [];
|
|
632
|
+
for (const service of spec.services) {
|
|
633
|
+
for (const member of service.members) {
|
|
634
|
+
if ((member.kind === "DropTarget" || member.kind === "HoverTarget") && member.payloadTypeText) {
|
|
635
|
+
const typeName = member.payloadTypeText.replace(/\s/g, "");
|
|
636
|
+
const key = `${service.name}-${typeName}`;
|
|
637
|
+
if (seen.has(key))
|
|
638
|
+
continue;
|
|
639
|
+
seen.add(key);
|
|
640
|
+
constants.push({
|
|
641
|
+
typeName,
|
|
642
|
+
serviceName: service.name,
|
|
643
|
+
mimeType: `application/anqst-dragdropevent_${service.name}-${typeName}`
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return constants;
|
|
649
|
+
}
|
|
629
650
|
function renderTypesHeader(spec, cppTypes) {
|
|
630
651
|
const decls = cppTypes.orderedDecls.map(renderCppDecl).join("\n\n");
|
|
631
652
|
const metatypes = cppTypes.structNames
|
|
@@ -634,6 +655,11 @@ function renderTypesHeader(spec, cppTypes) {
|
|
|
634
655
|
`Q_DECLARE_METATYPE(QList<${spec.widgetName}::${name}>)`
|
|
635
656
|
])
|
|
636
657
|
.join("\n");
|
|
658
|
+
const mimeConstants = collectDragDropMimeConstants(spec);
|
|
659
|
+
const mimeConstantLines = mimeConstants
|
|
660
|
+
.map((c) => `static constexpr const char* kDragDropMime_${c.typeName} = "${c.mimeType}";`)
|
|
661
|
+
.join("\n");
|
|
662
|
+
const mimeBlock = mimeConstantLines.length > 0 ? `\n${mimeConstantLines}\n` : "";
|
|
637
663
|
return `#pragma once
|
|
638
664
|
#include <QString>
|
|
639
665
|
#include <QStringList>
|
|
@@ -646,19 +672,30 @@ function renderTypesHeader(spec, cppTypes) {
|
|
|
646
672
|
namespace ${spec.widgetName} {
|
|
647
673
|
|
|
648
674
|
${decls}
|
|
649
|
-
|
|
675
|
+
${mimeBlock}
|
|
650
676
|
} // namespace ${spec.widgetName}
|
|
651
677
|
|
|
652
678
|
${metatypes}
|
|
653
679
|
`;
|
|
654
680
|
}
|
|
681
|
+
function renderWidgetUmbrellaHeader(spec) {
|
|
682
|
+
return `#pragma once
|
|
683
|
+
// Built by <AnQst_version>
|
|
684
|
+
#include "${spec.widgetName}Widget.h"
|
|
685
|
+
#include "${spec.widgetName}Types.h"
|
|
686
|
+
`;
|
|
687
|
+
}
|
|
655
688
|
function renderWidgetHeader(spec, cppTypes) {
|
|
689
|
+
const widgetClassName = `${spec.widgetName}Widget`;
|
|
656
690
|
const callbackAliases = [];
|
|
657
691
|
const publicMethods = [];
|
|
692
|
+
const slotMethods = [];
|
|
693
|
+
const handleMethods = [];
|
|
694
|
+
const callSetterMethods = [];
|
|
658
695
|
const signals = [];
|
|
659
696
|
const properties = [];
|
|
660
697
|
const fields = [];
|
|
661
|
-
const
|
|
698
|
+
const publicSlots = [];
|
|
662
699
|
const bindings = [];
|
|
663
700
|
for (const service of spec.services) {
|
|
664
701
|
for (const member of service.members) {
|
|
@@ -666,21 +703,20 @@ function renderWidgetHeader(spec, cppTypes) {
|
|
|
666
703
|
const memberPascal = pascalCase(member.name);
|
|
667
704
|
if (member.kind === "Call" && member.payloadTypeText) {
|
|
668
705
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
669
|
-
const args = member.parameters.map((p) =>
|
|
706
|
+
const args = member.parameters.map((p) => `const ${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])}& ${p.name}`).join(", ");
|
|
670
707
|
callbackAliases.push(`using ${memberPascal}Handler = std::function<${cppType}(${args})>;`);
|
|
671
|
-
|
|
708
|
+
handleMethods.push(` void ${member.name}(const ${memberPascal}Handler& handler) const;`);
|
|
709
|
+
callSetterMethods.push(`void set${memberPascal}CallHandler(const ${memberPascal}Handler& handler);`);
|
|
672
710
|
fields.push(`${memberPascal}Handler m_${member.name}Handler;`);
|
|
673
711
|
}
|
|
674
712
|
else if (member.kind === "Emitter") {
|
|
675
|
-
const args = member.parameters.map((p) =>
|
|
676
|
-
|
|
677
|
-
publicMethods.push(`void set${memberPascal}Handler(const ${memberPascal}Handler& handler);`);
|
|
678
|
-
fields.push(`${memberPascal}Handler m_${member.name}Handler;`);
|
|
713
|
+
const args = member.parameters.map((p) => `const ${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])}& ${p.name}`).join(", ");
|
|
714
|
+
signals.push(`void ${member.name}(${args});`);
|
|
679
715
|
}
|
|
680
716
|
else if (member.kind === "Slot") {
|
|
681
717
|
const ret = member.payloadTypeText ? cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]) : "void";
|
|
682
718
|
const args = member.parameters.map((p) => `${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])} ${p.name}`).join(", ");
|
|
683
|
-
|
|
719
|
+
slotMethods.push(`${ret} slot_${member.name}(${args});`);
|
|
684
720
|
}
|
|
685
721
|
else if ((member.kind === "Input" || member.kind === "Output") && member.payloadTypeText) {
|
|
686
722
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
@@ -696,13 +732,25 @@ function renderWidgetHeader(spec, cppTypes) {
|
|
|
696
732
|
fields.push(`${memberPascal}Handler m_${member.name}Handler;`);
|
|
697
733
|
}
|
|
698
734
|
else {
|
|
699
|
-
|
|
735
|
+
publicSlots.push(`void ${member.name}Slot(const ${cppType}& value);`);
|
|
700
736
|
}
|
|
701
737
|
}
|
|
738
|
+
else if (member.kind === "DropTarget" && member.payloadTypeText) {
|
|
739
|
+
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
740
|
+
signals.push(`void ${member.name}(const ${cppType}& payload, double x, double y);`);
|
|
741
|
+
}
|
|
742
|
+
else if (member.kind === "HoverTarget" && member.payloadTypeText) {
|
|
743
|
+
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
744
|
+
signals.push(`void ${member.name}(const ${cppType}& payload, double x, double y);`);
|
|
745
|
+
signals.push(`void ${member.name}Left();`);
|
|
746
|
+
}
|
|
702
747
|
}
|
|
703
748
|
}
|
|
704
749
|
return `#pragma once
|
|
750
|
+
#include <QDateTime>
|
|
705
751
|
#include <QHash>
|
|
752
|
+
#include <QMetaMethod>
|
|
753
|
+
#include <QQueue>
|
|
706
754
|
#include <QVariant>
|
|
707
755
|
#include <QVariantList>
|
|
708
756
|
#include <functional>
|
|
@@ -710,28 +758,54 @@ function renderWidgetHeader(spec, cppTypes) {
|
|
|
710
758
|
#include "${spec.widgetName}Types.h"
|
|
711
759
|
|
|
712
760
|
namespace ${spec.widgetName} {
|
|
761
|
+
} // namespace ${spec.widgetName}
|
|
762
|
+
|
|
763
|
+
using namespace ${spec.widgetName};
|
|
713
764
|
|
|
714
|
-
class ${
|
|
765
|
+
class ${widgetClassName} : public AnQstWebHostBase {
|
|
715
766
|
Q_OBJECT
|
|
716
767
|
${properties.map((p) => ` ${p}`).join("\n")}
|
|
717
768
|
|
|
718
769
|
public:
|
|
719
|
-
|
|
720
|
-
|
|
770
|
+
${callbackAliases.map((s) => ` ${s}`).join("\n")}
|
|
771
|
+
|
|
772
|
+
class handle {
|
|
773
|
+
public:
|
|
774
|
+
explicit handle(${widgetClassName}* owner) : m_owner(owner) {}
|
|
775
|
+
${handleMethods.join("\n")}
|
|
776
|
+
private:
|
|
777
|
+
${widgetClassName}* m_owner;
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
explicit ${widgetClassName}(QWidget* parent = nullptr);
|
|
781
|
+
~${widgetClassName}() override;
|
|
721
782
|
bool enableDebug();
|
|
722
783
|
static constexpr const char* kBootstrapEntryPoint = "index.html";
|
|
723
784
|
static constexpr const char* kBootstrapContentRoot = "qrc:/${spec.widgetName.toLowerCase()}";
|
|
724
785
|
static constexpr const char* kBootstrapBridgeObject = "${spec.widgetName}Bridge";
|
|
786
|
+
static constexpr int kMaxQueuedCallsPerEndpoint = 1024;
|
|
725
787
|
|
|
726
|
-
|
|
788
|
+
handle handle;
|
|
727
789
|
${publicMethods.map((s) => ` ${s}`).join("\n")}
|
|
728
|
-
|
|
790
|
+
|
|
791
|
+
public slots:
|
|
792
|
+
${slotMethods.map((s) => ` ${s}`).join("\n")}
|
|
793
|
+
${publicSlots.map((s) => ` ${s}`).join("\n")}
|
|
729
794
|
|
|
730
795
|
signals:
|
|
731
796
|
${signals.map((s) => ` ${s}`).join("\n")}
|
|
732
797
|
void diagnosticsForwarded(const QVariantMap& payload);
|
|
733
798
|
|
|
799
|
+
protected:
|
|
800
|
+
void connectNotify(const QMetaMethod& signal) override;
|
|
801
|
+
void disconnectNotify(const QMetaMethod& signal) override;
|
|
802
|
+
|
|
734
803
|
private:
|
|
804
|
+
struct PendingCallInvocation {
|
|
805
|
+
QString requestId;
|
|
806
|
+
QVariantList args;
|
|
807
|
+
QDateTime enqueuedAt;
|
|
808
|
+
};
|
|
735
809
|
struct BridgeBindingRow {
|
|
736
810
|
const char* service;
|
|
737
811
|
const char* member;
|
|
@@ -741,21 +815,37 @@ private:
|
|
|
741
815
|
static constexpr int kBridgeBindingsCount = ${bindings.length};
|
|
742
816
|
static QString makeBindingKey(const QString& service, const QString& member);
|
|
743
817
|
void installBridgeBindings();
|
|
818
|
+
bool hasEmitterListeners(const QString& service, const QString& member) const;
|
|
744
819
|
QVariant handleGeneratedCall(const QString& service, const QString& member, const QVariantList& args);
|
|
745
820
|
void handleGeneratedEmitter(const QString& service, const QString& member, const QVariantList& args);
|
|
746
821
|
void handleGeneratedInput(const QString& service, const QString& member, const QVariant& value);
|
|
747
|
-
|
|
822
|
+
QVariant waitForCallHandlerAndInvoke(
|
|
823
|
+
const QString& service,
|
|
824
|
+
const QString& member,
|
|
825
|
+
const QString& requestId,
|
|
826
|
+
int timeoutMs,
|
|
827
|
+
const std::function<QVariant()>& invokeNow);
|
|
828
|
+
void removeQueuedCallById(const QString& queueKey, const QString& requestId);
|
|
829
|
+
${callSetterMethods.map((s) => ` ${s}`).join("\n")}
|
|
830
|
+
|
|
831
|
+
qulonglong m_callRequestCounter{0};
|
|
832
|
+
QHash<QString, QQueue<PendingCallInvocation>> m_queuedCalls;
|
|
748
833
|
${fields.map((f) => ` ${f}`).join("\n")}
|
|
749
834
|
};
|
|
750
|
-
|
|
751
|
-
} // namespace ${spec.widgetName}
|
|
752
835
|
`;
|
|
753
836
|
}
|
|
754
837
|
function renderCppStub(spec, cppTypes) {
|
|
838
|
+
const widgetClassName = `${spec.widgetName}Widget`;
|
|
755
839
|
const lines = [];
|
|
756
|
-
lines.push(`#include "include/${spec.widgetName}.h"`);
|
|
840
|
+
lines.push(`#include "include/${spec.widgetName}Widget.h"`);
|
|
757
841
|
lines.push(`#include <QDebug>`);
|
|
842
|
+
lines.push(`#include <QElapsedTimer>`);
|
|
843
|
+
lines.push(`#include <QEventLoop>`);
|
|
758
844
|
lines.push(`#include <QMetaType>`);
|
|
845
|
+
lines.push(`#include <QTimer>`);
|
|
846
|
+
lines.push(`#include <stdexcept>`);
|
|
847
|
+
lines.push("");
|
|
848
|
+
lines.push(`using namespace ${spec.widgetName};`);
|
|
759
849
|
lines.push("");
|
|
760
850
|
lines.push(`extern int qInitResources_${spec.widgetName}();`);
|
|
761
851
|
lines.push("");
|
|
@@ -772,9 +862,23 @@ function renderCppStub(spec, cppTypes) {
|
|
|
772
862
|
lines.push("}");
|
|
773
863
|
lines.push("}");
|
|
774
864
|
lines.push("");
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
865
|
+
for (const service of spec.services) {
|
|
866
|
+
for (const member of service.members) {
|
|
867
|
+
if (member.kind !== "Call" || !member.payloadTypeText)
|
|
868
|
+
continue;
|
|
869
|
+
const pascal = pascalCase(member.name);
|
|
870
|
+
lines.push(`void ${widgetClassName}::handle::${member.name}(const ${pascal}Handler& handler) const {`);
|
|
871
|
+
lines.push(` if (m_owner == nullptr) return;`);
|
|
872
|
+
lines.push(` m_owner->set${pascal}CallHandler(handler);`);
|
|
873
|
+
lines.push(`}`);
|
|
874
|
+
lines.push("");
|
|
875
|
+
lines.push(`void ${widgetClassName}::set${pascal}CallHandler(const ${pascal}Handler& handler) {`);
|
|
876
|
+
lines.push(` m_${member.name}Handler = handler;`);
|
|
877
|
+
lines.push(`}`);
|
|
878
|
+
lines.push("");
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
lines.push(`const ${widgetClassName}::BridgeBindingRow ${widgetClassName}::kBridgeBindings[] = {`);
|
|
778
882
|
for (const service of spec.services) {
|
|
779
883
|
for (const member of service.members) {
|
|
780
884
|
lines.push(` {"${service.name}", "${member.name}", "${member.kind}"},`);
|
|
@@ -782,7 +886,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
782
886
|
}
|
|
783
887
|
lines.push(`};`);
|
|
784
888
|
lines.push("");
|
|
785
|
-
lines.push(`${
|
|
889
|
+
lines.push(`${widgetClassName}::${widgetClassName}(QWidget* parent) : AnQstWebHostBase(parent), handle(this) {`);
|
|
786
890
|
lines.push(` static const bool kResourcesInitialized = []() {`);
|
|
787
891
|
lines.push(` ::qInitResources_${spec.widgetName}();`);
|
|
788
892
|
lines.push(` return true;`);
|
|
@@ -790,7 +894,46 @@ function renderCppStub(spec, cppTypes) {
|
|
|
790
894
|
lines.push(` Q_UNUSED(kResourcesInitialized);`);
|
|
791
895
|
lines.push(` registerGeneratedMetaTypes();`);
|
|
792
896
|
lines.push(` installBridgeBindings();`);
|
|
793
|
-
|
|
897
|
+
for (const service of spec.services) {
|
|
898
|
+
for (const member of service.members) {
|
|
899
|
+
if (member.kind === "DropTarget" && member.payloadTypeText) {
|
|
900
|
+
const typeName = member.payloadTypeText.replace(/\s/g, "");
|
|
901
|
+
const mimeConst = `${spec.widgetName}::kDragDropMime_${typeName}`;
|
|
902
|
+
lines.push(` registerDropTarget(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"), QString::fromUtf8(${mimeConst}));`);
|
|
903
|
+
}
|
|
904
|
+
else if (member.kind === "HoverTarget" && member.payloadTypeText) {
|
|
905
|
+
const typeName = member.payloadTypeText.replace(/\s/g, "");
|
|
906
|
+
const mimeConst = `${spec.widgetName}::kDragDropMime_${typeName}`;
|
|
907
|
+
lines.push(` registerHoverTarget(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"), QString::fromUtf8(${mimeConst}), ${member.hoverThrottleMs});`);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
for (const service of spec.services) {
|
|
912
|
+
for (const member of service.members) {
|
|
913
|
+
if (member.kind === "DropTarget" && member.payloadTypeText) {
|
|
914
|
+
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
915
|
+
lines.push(` QObject::connect(this, &AnQstWebHostBase::anQstBridge_dropReceived, this, [this](const QString& service, const QString& member, const QVariant& payload, double x, double y) {`);
|
|
916
|
+
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
917
|
+
lines.push(` emit ${member.name}(payload.value<${cppType}>(), x, y);`);
|
|
918
|
+
lines.push(` }`);
|
|
919
|
+
lines.push(` });`);
|
|
920
|
+
}
|
|
921
|
+
else if (member.kind === "HoverTarget" && member.payloadTypeText) {
|
|
922
|
+
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
923
|
+
lines.push(` QObject::connect(this, &AnQstWebHostBase::anQstBridge_hoverUpdated, this, [this](const QString& service, const QString& member, const QVariant& payload, double x, double y) {`);
|
|
924
|
+
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
925
|
+
lines.push(` emit ${member.name}(payload.value<${cppType}>(), x, y);`);
|
|
926
|
+
lines.push(` }`);
|
|
927
|
+
lines.push(` });`);
|
|
928
|
+
lines.push(` QObject::connect(this, &AnQstWebHostBase::anQstBridge_hoverLeft, this, [this](const QString& service, const QString& member) {`);
|
|
929
|
+
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
930
|
+
lines.push(` emit ${member.name}Left();`);
|
|
931
|
+
lines.push(` }`);
|
|
932
|
+
lines.push(` });`);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
lines.push(` QObject::connect(this, &AnQstWebHostBase::onHostError, this, &${widgetClassName}::diagnosticsForwarded);`);
|
|
794
937
|
lines.push(` const bool rootOk = setContentRoot(QString::fromUtf8(kBootstrapContentRoot));`);
|
|
795
938
|
lines.push(` const bool bridgeOk = setBridgeObject(this, QString::fromUtf8(kBootstrapBridgeObject));`);
|
|
796
939
|
lines.push(` const bool loadOk = rootOk && bridgeOk && loadEntryPoint(QString::fromUtf8(kBootstrapEntryPoint));`);
|
|
@@ -799,17 +942,74 @@ function renderCppStub(spec, cppTypes) {
|
|
|
799
942
|
lines.push(` }`);
|
|
800
943
|
lines.push("}");
|
|
801
944
|
lines.push("");
|
|
802
|
-
lines.push(`${
|
|
945
|
+
lines.push(`${widgetClassName}::~${widgetClassName}() = default;`);
|
|
803
946
|
lines.push("");
|
|
804
|
-
lines.push(`bool ${
|
|
947
|
+
lines.push(`bool ${widgetClassName}::enableDebug() {`);
|
|
805
948
|
lines.push(` return AnQstWebHostBase::enableDebug();`);
|
|
806
949
|
lines.push("}");
|
|
807
950
|
lines.push("");
|
|
808
|
-
lines.push(`QString ${
|
|
951
|
+
lines.push(`QString ${widgetClassName}::makeBindingKey(const QString& service, const QString& member) {`);
|
|
809
952
|
lines.push(` return service + QStringLiteral("::") + member;`);
|
|
810
953
|
lines.push(`}`);
|
|
811
954
|
lines.push("");
|
|
812
|
-
lines.push(`void ${
|
|
955
|
+
lines.push(`void ${widgetClassName}::removeQueuedCallById(const QString& queueKey, const QString& requestId) {`);
|
|
956
|
+
lines.push(` if (!m_queuedCalls.contains(queueKey)) return;`);
|
|
957
|
+
lines.push(` auto& queue = m_queuedCalls[queueKey];`);
|
|
958
|
+
lines.push(` for (int i = 0; i < queue.size(); ++i) {`);
|
|
959
|
+
lines.push(` if (queue[i].requestId == requestId) {`);
|
|
960
|
+
lines.push(` queue.removeAt(i);`);
|
|
961
|
+
lines.push(` break;`);
|
|
962
|
+
lines.push(` }`);
|
|
963
|
+
lines.push(` }`);
|
|
964
|
+
lines.push(`}`);
|
|
965
|
+
lines.push("");
|
|
966
|
+
lines.push(`QVariant ${widgetClassName}::waitForCallHandlerAndInvoke(`);
|
|
967
|
+
lines.push(` const QString& service,`);
|
|
968
|
+
lines.push(` const QString& member,`);
|
|
969
|
+
lines.push(` const QString& requestId,`);
|
|
970
|
+
lines.push(` int timeoutMs,`);
|
|
971
|
+
lines.push(` const std::function<QVariant()>& invokeNow) {`);
|
|
972
|
+
lines.push(` const QString queueKey = makeBindingKey(service, member);`);
|
|
973
|
+
lines.push(` QElapsedTimer timer;`);
|
|
974
|
+
lines.push(` timer.start();`);
|
|
975
|
+
lines.push(` QEventLoop loop;`);
|
|
976
|
+
lines.push(` QTimer tick;`);
|
|
977
|
+
lines.push(` tick.setSingleShot(true);`);
|
|
978
|
+
lines.push(` QObject::connect(&tick, &QTimer::timeout, &loop, &QEventLoop::quit);`);
|
|
979
|
+
lines.push(` while (true) {`);
|
|
980
|
+
lines.push(` if (m_queuedCalls.contains(queueKey) && !m_queuedCalls[queueKey].isEmpty() && m_queuedCalls[queueKey].head().requestId == requestId) {`);
|
|
981
|
+
lines.push(` m_queuedCalls[queueKey].dequeue();`);
|
|
982
|
+
lines.push(` return invokeNow();`);
|
|
983
|
+
lines.push(` }`);
|
|
984
|
+
lines.push(` if (timeoutMs > 0 && timer.elapsed() >= timeoutMs) {`);
|
|
985
|
+
lines.push(` removeQueuedCallById(queueKey, requestId);`);
|
|
986
|
+
lines.push(` return QVariantMap{`);
|
|
987
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("BridgeTimeoutError")},`);
|
|
988
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("Call timed out while waiting for callback registration.")},`);
|
|
989
|
+
lines.push(` {QStringLiteral("service"), service},`);
|
|
990
|
+
lines.push(` {QStringLiteral("member"), member},`);
|
|
991
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
992
|
+
lines.push(` };`);
|
|
993
|
+
lines.push(` }`);
|
|
994
|
+
lines.push(` tick.start(10);`);
|
|
995
|
+
lines.push(` loop.exec();`);
|
|
996
|
+
lines.push(` }`);
|
|
997
|
+
lines.push(`}`);
|
|
998
|
+
lines.push("");
|
|
999
|
+
lines.push(`bool ${widgetClassName}::hasEmitterListeners(const QString& service, const QString& member) const {`);
|
|
1000
|
+
for (const service of spec.services) {
|
|
1001
|
+
for (const member of service.members) {
|
|
1002
|
+
if (member.kind !== "Emitter")
|
|
1003
|
+
continue;
|
|
1004
|
+
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
1005
|
+
lines.push(` return isSignalConnected(QMetaMethod::fromSignal(&${widgetClassName}::${member.name}));`);
|
|
1006
|
+
lines.push(` }`);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
lines.push(` return false;`);
|
|
1010
|
+
lines.push(`}`);
|
|
1011
|
+
lines.push("");
|
|
1012
|
+
lines.push(`void ${widgetClassName}::installBridgeBindings() {`);
|
|
813
1013
|
lines.push(` setCallHandler([this](const QString& service, const QString& member, const QVariantList& args) -> QVariant {`);
|
|
814
1014
|
lines.push(` return handleGeneratedCall(service, member, args);`);
|
|
815
1015
|
lines.push(` });`);
|
|
@@ -821,55 +1021,91 @@ function renderCppStub(spec, cppTypes) {
|
|
|
821
1021
|
lines.push(` });`);
|
|
822
1022
|
lines.push(`}`);
|
|
823
1023
|
lines.push("");
|
|
824
|
-
lines.push(`QVariant ${
|
|
1024
|
+
lines.push(`QVariant ${widgetClassName}::handleGeneratedCall(const QString& service, const QString& member, const QVariantList& args) {`);
|
|
825
1025
|
for (const service of spec.services) {
|
|
826
1026
|
for (const member of service.members) {
|
|
827
1027
|
if (member.kind !== "Call" || !member.payloadTypeText)
|
|
828
1028
|
continue;
|
|
1029
|
+
const timeoutMs = member.timeoutMs;
|
|
829
1030
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
830
|
-
const pascal = pascalCase(member.name);
|
|
831
1031
|
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
832
|
-
lines.push(` if (!m_${member.name}Handler) {`);
|
|
833
|
-
lines.push(` if (property("anqstDesignerContext").toBool()) {`);
|
|
834
|
-
lines.push(` return ${cppToVariantExpression(cppType, designerPlaceholderCppExpression(cppType, member.name))};`);
|
|
835
|
-
lines.push(` }`);
|
|
836
|
-
lines.push(` return QVariant();`);
|
|
837
|
-
lines.push(` }`);
|
|
838
1032
|
for (let i = 0; i < member.parameters.length; i++) {
|
|
839
1033
|
const p = member.parameters[i];
|
|
840
1034
|
const pType = cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name]);
|
|
841
1035
|
lines.push(` const ${pType} ${p.name} = ${variantToCppExpression(pType, `args.value(${i})`)};`);
|
|
842
1036
|
}
|
|
843
|
-
const
|
|
844
|
-
lines.push(` const
|
|
845
|
-
lines.push(`
|
|
1037
|
+
lines.push(` const QString requestId = QStringLiteral("call-%1").arg(++m_callRequestCounter);`);
|
|
1038
|
+
lines.push(` const QString queueKey = makeBindingKey(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"));`);
|
|
1039
|
+
lines.push(` auto invokeNow = [this, requestId${member.parameters.length > 0 ? `, ${member.parameters.map((p) => p.name).join(", ")}` : ""}]() -> QVariant {`);
|
|
1040
|
+
lines.push(` if (!m_${member.name}Handler) {`);
|
|
1041
|
+
lines.push(` return QVariantMap{`);
|
|
1042
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("HandlerNotRegisteredError")},`);
|
|
1043
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("No callback registered for Call endpoint.")},`);
|
|
1044
|
+
lines.push(` {QStringLiteral("service"), QStringLiteral("${service.name}")},`);
|
|
1045
|
+
lines.push(` {QStringLiteral("member"), QStringLiteral("${member.name}")},`);
|
|
1046
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
1047
|
+
lines.push(` };`);
|
|
1048
|
+
lines.push(` }`);
|
|
1049
|
+
lines.push(` try {`);
|
|
1050
|
+
const callArgs = member.parameters.map((p) => p.name).join(", ");
|
|
1051
|
+
lines.push(` const ${cppType} result = m_${member.name}Handler(${callArgs});`);
|
|
1052
|
+
lines.push(` return ${cppToVariantExpression(cppType, "result")};`);
|
|
1053
|
+
lines.push(` } catch (const std::exception& ex) {`);
|
|
1054
|
+
lines.push(` return QVariantMap{`);
|
|
1055
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("CallHandlerError")},`);
|
|
1056
|
+
lines.push(` {QStringLiteral("message"), QString::fromUtf8(ex.what())},`);
|
|
1057
|
+
lines.push(` {QStringLiteral("service"), QStringLiteral("${service.name}")},`);
|
|
1058
|
+
lines.push(` {QStringLiteral("member"), QStringLiteral("${member.name}")},`);
|
|
1059
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
1060
|
+
lines.push(` };`);
|
|
1061
|
+
lines.push(` } catch (...) {`);
|
|
1062
|
+
lines.push(` return QVariantMap{`);
|
|
1063
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("CallHandlerError")},`);
|
|
1064
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("Call handler threw unknown exception.")},`);
|
|
1065
|
+
lines.push(` {QStringLiteral("service"), QStringLiteral("${service.name}")},`);
|
|
1066
|
+
lines.push(` {QStringLiteral("member"), QStringLiteral("${member.name}")},`);
|
|
1067
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
1068
|
+
lines.push(` };`);
|
|
1069
|
+
lines.push(` }`);
|
|
1070
|
+
lines.push(` };`);
|
|
1071
|
+
lines.push(` if (m_${member.name}Handler) {`);
|
|
1072
|
+
lines.push(` return invokeNow();`);
|
|
1073
|
+
lines.push(` }`);
|
|
1074
|
+
lines.push(` auto& queue = m_queuedCalls[queueKey];`);
|
|
1075
|
+
lines.push(` if (queue.size() >= kMaxQueuedCallsPerEndpoint) {`);
|
|
1076
|
+
lines.push(` queue.dequeue();`);
|
|
1077
|
+
lines.push(` }`);
|
|
1078
|
+
lines.push(` queue.enqueue(PendingCallInvocation{requestId, args, QDateTime::currentDateTimeUtc()});`);
|
|
1079
|
+
lines.push(` return waitForCallHandlerAndInvoke(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"), requestId, ${timeoutMs}, invokeNow);`);
|
|
846
1080
|
lines.push(` }`);
|
|
847
1081
|
}
|
|
848
1082
|
}
|
|
849
1083
|
lines.push(` return QVariant();`);
|
|
850
1084
|
lines.push(`}`);
|
|
851
1085
|
lines.push("");
|
|
852
|
-
lines.push(`void ${
|
|
1086
|
+
lines.push(`void ${widgetClassName}::handleGeneratedEmitter(const QString& service, const QString& member, const QVariantList& args) {`);
|
|
1087
|
+
lines.push(` if (!hasEmitterListeners(service, member)) {`);
|
|
1088
|
+
lines.push(` return;`);
|
|
1089
|
+
lines.push(` }`);
|
|
853
1090
|
for (const service of spec.services) {
|
|
854
1091
|
for (const member of service.members) {
|
|
855
1092
|
if (member.kind !== "Emitter")
|
|
856
1093
|
continue;
|
|
857
1094
|
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
858
|
-
lines.push(` if (!m_${member.name}Handler) return;`);
|
|
859
1095
|
for (let i = 0; i < member.parameters.length; i++) {
|
|
860
1096
|
const p = member.parameters[i];
|
|
861
1097
|
const pType = cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name]);
|
|
862
1098
|
lines.push(` const ${pType} ${p.name} = ${variantToCppExpression(pType, `args.value(${i})`)};`);
|
|
863
1099
|
}
|
|
864
1100
|
const argNames = member.parameters.map((p) => p.name).join(", ");
|
|
865
|
-
lines.push(`
|
|
1101
|
+
lines.push(` emit ${member.name}(${argNames});`);
|
|
866
1102
|
lines.push(` return;`);
|
|
867
1103
|
lines.push(` }`);
|
|
868
1104
|
}
|
|
869
1105
|
}
|
|
870
1106
|
lines.push(`}`);
|
|
871
1107
|
lines.push("");
|
|
872
|
-
lines.push(`void ${
|
|
1108
|
+
lines.push(`void ${widgetClassName}::handleGeneratedInput(const QString& service, const QString& member, const QVariant& value) {`);
|
|
873
1109
|
for (const service of spec.services) {
|
|
874
1110
|
for (const member of service.members) {
|
|
875
1111
|
if (member.kind !== "Input" || !member.payloadTypeText)
|
|
@@ -888,20 +1124,8 @@ function renderCppStub(spec, cppTypes) {
|
|
|
888
1124
|
for (const service of spec.services) {
|
|
889
1125
|
for (const member of service.members) {
|
|
890
1126
|
const memberPascal = pascalCase(member.name);
|
|
891
|
-
if (
|
|
892
|
-
lines.push(`void ${
|
|
893
|
-
lines.push(` m_${member.name}Handler = handler;`);
|
|
894
|
-
lines.push("}");
|
|
895
|
-
lines.push("");
|
|
896
|
-
}
|
|
897
|
-
else if (member.kind === "Emitter") {
|
|
898
|
-
lines.push(`void ${spec.widgetName}::set${memberPascal}Handler(const ${memberPascal}Handler& handler) {`);
|
|
899
|
-
lines.push(` m_${member.name}Handler = handler;`);
|
|
900
|
-
lines.push("}");
|
|
901
|
-
lines.push("");
|
|
902
|
-
}
|
|
903
|
-
else if (member.kind === "Input" && member.payloadTypeText) {
|
|
904
|
-
lines.push(`void ${spec.widgetName}::set${memberPascal}Handler(const ${memberPascal}Handler& handler) {`);
|
|
1127
|
+
if (member.kind === "Input" && member.payloadTypeText) {
|
|
1128
|
+
lines.push(`void ${widgetClassName}::set${memberPascal}Handler(const ${memberPascal}Handler& handler) {`);
|
|
905
1129
|
lines.push(` m_${member.name}Handler = handler;`);
|
|
906
1130
|
lines.push("}");
|
|
907
1131
|
lines.push("");
|
|
@@ -909,8 +1133,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
909
1133
|
if (member.kind === "Slot") {
|
|
910
1134
|
const ret = member.payloadTypeText ? cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]) : "void";
|
|
911
1135
|
const args = member.parameters.map((p) => `${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])} ${p.name}`).join(", ");
|
|
912
|
-
|
|
913
|
-
lines.push(`${ret} ${spec.widgetName}::${member.name}(${argsWithMeta}) {`);
|
|
1136
|
+
lines.push(`${ret} ${widgetClassName}::slot_${member.name}(${args}) {`);
|
|
914
1137
|
lines.push(` QVariantList invokeArgs;`);
|
|
915
1138
|
for (const p of member.parameters) {
|
|
916
1139
|
const pType = mapTsTypeToCpp(p.typeText);
|
|
@@ -919,14 +1142,18 @@ function renderCppStub(spec, cppTypes) {
|
|
|
919
1142
|
lines.push(` QVariant result;`);
|
|
920
1143
|
lines.push(` QString invokeError;`);
|
|
921
1144
|
lines.push(` const bool success = invokeSlot(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"), invokeArgs, &result, &invokeError);`);
|
|
922
|
-
lines.push(` if (
|
|
923
|
-
lines.push(`
|
|
1145
|
+
lines.push(` if (!success) {`);
|
|
1146
|
+
lines.push(` if (invokeError == QStringLiteral("slot invocation timeout")) {`);
|
|
1147
|
+
lines.push(` const QString timeoutMsg = QStringLiteral("[Timeout] ${service.name}.${member.name}: The webapp inside the widget did not anwser within %1 ms.").arg(slotInvocationTimeoutMs());`);
|
|
1148
|
+
lines.push(` throw std::runtime_error(timeoutMsg.toStdString());`);
|
|
1149
|
+
lines.push(` }`);
|
|
1150
|
+
lines.push(` const QString requestFailed = QStringLiteral("[RequestFailed]: %1").arg(invokeError);`);
|
|
1151
|
+
lines.push(` throw std::runtime_error(requestFailed.toStdString());`);
|
|
1152
|
+
lines.push(` }`);
|
|
924
1153
|
if (ret === "void") {
|
|
925
|
-
lines.push(` if (!success) return;`);
|
|
926
1154
|
lines.push(` return;`);
|
|
927
1155
|
}
|
|
928
1156
|
else {
|
|
929
|
-
lines.push(` if (!success) return ${ret}{};`);
|
|
930
1157
|
lines.push(` return ${variantToCppExpression(ret, "result")};`);
|
|
931
1158
|
}
|
|
932
1159
|
lines.push("}");
|
|
@@ -935,11 +1162,11 @@ function renderCppStub(spec, cppTypes) {
|
|
|
935
1162
|
else if ((member.kind === "Input" || member.kind === "Output") && member.payloadTypeText) {
|
|
936
1163
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
937
1164
|
const cap = member.name.charAt(0).toUpperCase() + member.name.slice(1);
|
|
938
|
-
lines.push(`${cppType} ${
|
|
1165
|
+
lines.push(`${cppType} ${widgetClassName}::${member.name}() const {`);
|
|
939
1166
|
lines.push(` return m_${member.name};`);
|
|
940
1167
|
lines.push("}");
|
|
941
1168
|
lines.push("");
|
|
942
|
-
lines.push(`void ${
|
|
1169
|
+
lines.push(`void ${widgetClassName}::set${cap}(const ${cppType}& value) {`);
|
|
943
1170
|
lines.push(` if (m_${member.name} == value) return;`);
|
|
944
1171
|
lines.push(` m_${member.name} = value;`);
|
|
945
1172
|
if (member.kind === "Output") {
|
|
@@ -949,7 +1176,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
949
1176
|
lines.push("}");
|
|
950
1177
|
lines.push("");
|
|
951
1178
|
if (member.kind === "Output") {
|
|
952
|
-
lines.push(`void ${
|
|
1179
|
+
lines.push(`void ${widgetClassName}::${member.name}Slot(const ${cppType}& value) {`);
|
|
953
1180
|
lines.push(` set${cap}(value);`);
|
|
954
1181
|
lines.push(`}`);
|
|
955
1182
|
lines.push("");
|
|
@@ -957,7 +1184,16 @@ function renderCppStub(spec, cppTypes) {
|
|
|
957
1184
|
}
|
|
958
1185
|
}
|
|
959
1186
|
}
|
|
960
|
-
lines.push(`}
|
|
1187
|
+
lines.push(`void ${widgetClassName}::connectNotify(const QMetaMethod& signal) {`);
|
|
1188
|
+
lines.push(` AnQstWebHostBase::connectNotify(signal);`);
|
|
1189
|
+
lines.push(` Q_UNUSED(signal);`);
|
|
1190
|
+
lines.push(`}`);
|
|
1191
|
+
lines.push("");
|
|
1192
|
+
lines.push(`void ${widgetClassName}::disconnectNotify(const QMetaMethod& signal) {`);
|
|
1193
|
+
lines.push(` AnQstWebHostBase::disconnectNotify(signal);`);
|
|
1194
|
+
lines.push(` Q_UNUSED(signal);`);
|
|
1195
|
+
lines.push(`}`);
|
|
1196
|
+
lines.push("");
|
|
961
1197
|
return lines.join("\n");
|
|
962
1198
|
}
|
|
963
1199
|
function renderCMake(spec) {
|
|
@@ -977,6 +1213,7 @@ add_library(${spec.widgetName}Widget
|
|
|
977
1213
|
${spec.widgetName}.cpp
|
|
978
1214
|
${spec.widgetName}.qrc
|
|
979
1215
|
include/${spec.widgetName}.h
|
|
1216
|
+
include/${spec.widgetName}Widget.h
|
|
980
1217
|
include/${spec.widgetName}Types.h
|
|
981
1218
|
)
|
|
982
1219
|
target_include_directories(${spec.widgetName}Widget
|
|
@@ -1114,6 +1351,12 @@ function renderLocalTypeImports(spec) {
|
|
|
1114
1351
|
return "";
|
|
1115
1352
|
return `import type { ${localTypeNames.join(", ")} } from "./types";`;
|
|
1116
1353
|
}
|
|
1354
|
+
function slotHandlerReturnType(tsRet) {
|
|
1355
|
+
if (tsRet === "void") {
|
|
1356
|
+
return "void | Promise<void> | Error";
|
|
1357
|
+
}
|
|
1358
|
+
return `${tsRet} | Promise<${tsRet}> | Error`;
|
|
1359
|
+
}
|
|
1117
1360
|
function renderTsService(spec, serviceName) {
|
|
1118
1361
|
const members = spec.services.find((s) => s.name === serviceName)?.members ?? [];
|
|
1119
1362
|
const fieldLines = [];
|
|
@@ -1137,7 +1380,7 @@ function renderTsService(spec, serviceName) {
|
|
|
1137
1380
|
}
|
|
1138
1381
|
if (m.kind === "Slot") {
|
|
1139
1382
|
const ret = mapTypeTextToTs(m.payloadTypeText ?? "void");
|
|
1140
|
-
onSlotMembers.push(` ${m.name}: (handler: (${args}) => ${ret}): void => {`);
|
|
1383
|
+
onSlotMembers.push(` ${m.name}: (handler: (${args}) => ${slotHandlerReturnType(ret)}): void => {`);
|
|
1141
1384
|
onSlotMembers.push(` this._bridge.registerSlot("${serviceName}", "${m.name}", handler as (...args: unknown[]) => unknown);`);
|
|
1142
1385
|
onSlotMembers.push(" },");
|
|
1143
1386
|
continue;
|
|
@@ -1156,6 +1399,19 @@ function renderTsService(spec, serviceName) {
|
|
|
1156
1399
|
constructorBodyLines.push(` this._bridge.onOutput("${serviceName}", "${m.name}", (value) => this._${m.name}.set(value as ${tsType}));`);
|
|
1157
1400
|
}
|
|
1158
1401
|
}
|
|
1402
|
+
if (m.kind === "DropTarget" && m.payloadTypeText) {
|
|
1403
|
+
const tsType = mapTypeTextToTs(m.payloadTypeText);
|
|
1404
|
+
fieldLines.push(` private readonly _${m.name} = signal<{ payload: ${tsType}; x: number; y: number } | null>(null);`);
|
|
1405
|
+
methodLines.push(` ${m.name}(): { payload: ${tsType}; x: number; y: number } | null { return this._${m.name}(); }`);
|
|
1406
|
+
constructorBodyLines.push(` this._bridge.onDrop("${serviceName}", "${m.name}", (payload, x, y) => this._${m.name}.set({ payload: payload as ${tsType}, x, y }));`);
|
|
1407
|
+
}
|
|
1408
|
+
if (m.kind === "HoverTarget" && m.payloadTypeText) {
|
|
1409
|
+
const tsType = mapTypeTextToTs(m.payloadTypeText);
|
|
1410
|
+
fieldLines.push(` private readonly _${m.name} = signal<{ payload: ${tsType}; x: number; y: number } | null>(null);`);
|
|
1411
|
+
methodLines.push(` ${m.name}(): { payload: ${tsType}; x: number; y: number } | null { return this._${m.name}(); }`);
|
|
1412
|
+
constructorBodyLines.push(` this._bridge.onHover("${serviceName}", "${m.name}", (payload, x, y) => this._${m.name}.set({ payload: payload as ${tsType}, x, y }));`);
|
|
1413
|
+
constructorBodyLines.push(` this._bridge.onHoverLeft("${serviceName}", "${m.name}", () => this._${m.name}.set(null));`);
|
|
1414
|
+
}
|
|
1159
1415
|
}
|
|
1160
1416
|
const constructorLines = [
|
|
1161
1417
|
" constructor() {",
|
|
@@ -1197,7 +1453,7 @@ function renderTsServiceDts(spec, serviceName) {
|
|
|
1197
1453
|
}
|
|
1198
1454
|
if (m.kind === "Slot") {
|
|
1199
1455
|
const ret = mapTypeTextToTs(m.payloadTypeText ?? "void");
|
|
1200
|
-
onSlotMembers.push(` ${m.name}(handler: (${args}) => ${ret}): void;`);
|
|
1456
|
+
onSlotMembers.push(` ${m.name}(handler: (${args}) => ${slotHandlerReturnType(ret)}): void;`);
|
|
1201
1457
|
continue;
|
|
1202
1458
|
}
|
|
1203
1459
|
if ((m.kind === "Input" || m.kind === "Output") && m.payloadTypeText) {
|
|
@@ -1207,6 +1463,14 @@ function renderTsServiceDts(spec, serviceName) {
|
|
|
1207
1463
|
setMembers.push(` ${m.name}(value: ${tsType}): void;`);
|
|
1208
1464
|
}
|
|
1209
1465
|
}
|
|
1466
|
+
if (m.kind === "DropTarget" && m.payloadTypeText) {
|
|
1467
|
+
const tsType = mapTypeTextToTs(m.payloadTypeText);
|
|
1468
|
+
classMembers.push(` ${m.name}(): { payload: ${tsType}; x: number; y: number } | null;`);
|
|
1469
|
+
}
|
|
1470
|
+
if (m.kind === "HoverTarget" && m.payloadTypeText) {
|
|
1471
|
+
const tsType = mapTypeTextToTs(m.payloadTypeText);
|
|
1472
|
+
classMembers.push(` ${m.name}(): { payload: ${tsType}; x: number; y: number } | null;`);
|
|
1473
|
+
}
|
|
1210
1474
|
}
|
|
1211
1475
|
const setInterfaceDecl = setMembers.length > 0
|
|
1212
1476
|
? `export interface ${setInterfaceName} {\n${setMembers.join("\n")}\n}`
|
|
@@ -1237,6 +1501,9 @@ type SlotHandler = (...args: unknown[]) => unknown;
|
|
|
1237
1501
|
type OutputHandler = (value: unknown) => void;
|
|
1238
1502
|
type SlotInvocationListener = (requestId: string, service: string, member: string, args: unknown[]) => void;
|
|
1239
1503
|
type OutputListener = (service: string, member: string, value: unknown) => void;
|
|
1504
|
+
type DropListener = (service: string, member: string, payload: unknown, x: number, y: number) => void;
|
|
1505
|
+
type HoverListener = (service: string, member: string, payload: unknown, x: number, y: number) => void;
|
|
1506
|
+
type HoverLeftListener = (service: string, member: string) => void;
|
|
1240
1507
|
|
|
1241
1508
|
interface HostBridgeApi {
|
|
1242
1509
|
anQstBridge_call(service: string, member: string, args: unknown[], callback: (result: unknown) => void): void;
|
|
@@ -1248,6 +1515,9 @@ interface HostBridgeApi {
|
|
|
1248
1515
|
anQstBridge_slotInvocationRequested: {
|
|
1249
1516
|
connect: (cb: (requestId: string, service: string, member: string, args: unknown[]) => void) => void;
|
|
1250
1517
|
};
|
|
1518
|
+
anQstBridge_dropReceived: { connect: (cb: (service: string, member: string, payload: unknown, x: number, y: number) => void) => void };
|
|
1519
|
+
anQstBridge_hoverUpdated: { connect: (cb: (service: string, member: string, payload: unknown, x: number, y: number) => void) => void };
|
|
1520
|
+
anQstBridge_hoverLeft: { connect: (cb: (service: string, member: string) => void) => void };
|
|
1251
1521
|
}
|
|
1252
1522
|
|
|
1253
1523
|
interface QWebChannelCtor {
|
|
@@ -1265,6 +1535,27 @@ interface BridgeAdapter {
|
|
|
1265
1535
|
resolveSlot(requestId: string, ok: boolean, payload: unknown, error: string): void;
|
|
1266
1536
|
onOutput(handler: OutputListener): void;
|
|
1267
1537
|
onSlotInvocation(handler: SlotInvocationListener): void;
|
|
1538
|
+
onDrop(handler: DropListener): void;
|
|
1539
|
+
onHover(handler: HoverListener): void;
|
|
1540
|
+
onHoverLeft(handler: HoverLeftListener): void;
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
function isBridgeCallError(value: unknown): value is {
|
|
1544
|
+
code: unknown;
|
|
1545
|
+
message: unknown;
|
|
1546
|
+
service: unknown;
|
|
1547
|
+
member: unknown;
|
|
1548
|
+
requestId: unknown;
|
|
1549
|
+
} {
|
|
1550
|
+
if (value === null || typeof value !== "object") return false;
|
|
1551
|
+
const row = value as Record<string, unknown>;
|
|
1552
|
+
return (
|
|
1553
|
+
Object.prototype.hasOwnProperty.call(row, "code")
|
|
1554
|
+
&& Object.prototype.hasOwnProperty.call(row, "message")
|
|
1555
|
+
&& Object.prototype.hasOwnProperty.call(row, "service")
|
|
1556
|
+
&& Object.prototype.hasOwnProperty.call(row, "member")
|
|
1557
|
+
&& Object.prototype.hasOwnProperty.call(row, "requestId")
|
|
1558
|
+
);
|
|
1268
1559
|
}
|
|
1269
1560
|
|
|
1270
1561
|
class QtWebChannelAdapter implements BridgeAdapter {
|
|
@@ -1300,8 +1591,14 @@ class QtWebChannelAdapter implements BridgeAdapter {
|
|
|
1300
1591
|
}
|
|
1301
1592
|
|
|
1302
1593
|
async call<T>(service: string, member: string, args: unknown[]): Promise<T> {
|
|
1303
|
-
return new Promise<T>((resolve) => {
|
|
1304
|
-
this.host.anQstBridge_call(service, member, args, (result) =>
|
|
1594
|
+
return new Promise<T>((resolve, reject) => {
|
|
1595
|
+
this.host.anQstBridge_call(service, member, args, (result) => {
|
|
1596
|
+
if (isBridgeCallError(result)) {
|
|
1597
|
+
reject(result);
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
resolve(result as T);
|
|
1601
|
+
});
|
|
1305
1602
|
});
|
|
1306
1603
|
}
|
|
1307
1604
|
|
|
@@ -1328,12 +1625,33 @@ class QtWebChannelAdapter implements BridgeAdapter {
|
|
|
1328
1625
|
onSlotInvocation(handler: SlotInvocationListener): void {
|
|
1329
1626
|
this.host.anQstBridge_slotInvocationRequested.connect(handler);
|
|
1330
1627
|
}
|
|
1628
|
+
|
|
1629
|
+
onDrop(handler: DropListener): void {
|
|
1630
|
+
this.host.anQstBridge_dropReceived.connect(handler);
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
onHover(handler: HoverListener): void {
|
|
1634
|
+
this.host.anQstBridge_hoverUpdated.connect(handler);
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
onHoverLeft(handler: HoverLeftListener): void {
|
|
1638
|
+
this.host.anQstBridge_hoverLeft.connect(handler);
|
|
1639
|
+
}
|
|
1331
1640
|
}
|
|
1332
1641
|
|
|
1333
1642
|
class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
1334
|
-
private readonly pending = new Map<string,
|
|
1643
|
+
private readonly pending = new Map<string, {
|
|
1644
|
+
service: string;
|
|
1645
|
+
member: string;
|
|
1646
|
+
requestId: string;
|
|
1647
|
+
resolve: (result: unknown) => void;
|
|
1648
|
+
reject: (error: unknown) => void;
|
|
1649
|
+
}>();
|
|
1335
1650
|
private readonly outputListeners: OutputListener[] = [];
|
|
1336
1651
|
private readonly slotListeners: SlotInvocationListener[] = [];
|
|
1652
|
+
private readonly dropListeners: DropListener[] = [];
|
|
1653
|
+
private readonly hoverListeners: HoverListener[] = [];
|
|
1654
|
+
private readonly hoverLeftListeners: HoverLeftListener[] = [];
|
|
1337
1655
|
private requestCounter = 0;
|
|
1338
1656
|
|
|
1339
1657
|
private constructor(private readonly socket: WebSocket) {
|
|
@@ -1343,10 +1661,15 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1343
1661
|
const type = String(message["type"] ?? "");
|
|
1344
1662
|
if (type === "callResult") {
|
|
1345
1663
|
const requestId = String(message["requestId"] ?? "");
|
|
1346
|
-
const
|
|
1347
|
-
if (
|
|
1664
|
+
const pending = this.pending.get(requestId);
|
|
1665
|
+
if (pending) {
|
|
1348
1666
|
this.pending.delete(requestId);
|
|
1349
|
-
|
|
1667
|
+
const result = message["result"];
|
|
1668
|
+
if (isBridgeCallError(result)) {
|
|
1669
|
+
pending.reject(result);
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
pending.resolve(result);
|
|
1350
1673
|
}
|
|
1351
1674
|
return;
|
|
1352
1675
|
}
|
|
@@ -1368,6 +1691,34 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1368
1691
|
}
|
|
1369
1692
|
return;
|
|
1370
1693
|
}
|
|
1694
|
+
if (type === "dropReceived") {
|
|
1695
|
+
const service = String(message["service"] ?? "");
|
|
1696
|
+
const member = String(message["member"] ?? "");
|
|
1697
|
+
const x = Number(message["x"] ?? 0);
|
|
1698
|
+
const y = Number(message["y"] ?? 0);
|
|
1699
|
+
for (const listener of this.dropListeners) {
|
|
1700
|
+
listener(service, member, message["payload"], x, y);
|
|
1701
|
+
}
|
|
1702
|
+
return;
|
|
1703
|
+
}
|
|
1704
|
+
if (type === "hoverUpdated") {
|
|
1705
|
+
const service = String(message["service"] ?? "");
|
|
1706
|
+
const member = String(message["member"] ?? "");
|
|
1707
|
+
const x = Number(message["x"] ?? 0);
|
|
1708
|
+
const y = Number(message["y"] ?? 0);
|
|
1709
|
+
for (const listener of this.hoverListeners) {
|
|
1710
|
+
listener(service, member, message["payload"], x, y);
|
|
1711
|
+
}
|
|
1712
|
+
return;
|
|
1713
|
+
}
|
|
1714
|
+
if (type === "hoverLeft") {
|
|
1715
|
+
const service = String(message["service"] ?? "");
|
|
1716
|
+
const member = String(message["member"] ?? "");
|
|
1717
|
+
for (const listener of this.hoverLeftListeners) {
|
|
1718
|
+
listener(service, member);
|
|
1719
|
+
}
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1371
1722
|
if (type === "hostError") {
|
|
1372
1723
|
console.error("AnQst host error:", message["payload"]);
|
|
1373
1724
|
return;
|
|
@@ -1377,6 +1728,18 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1377
1728
|
this.socket.close();
|
|
1378
1729
|
}
|
|
1379
1730
|
});
|
|
1731
|
+
this.socket.addEventListener("close", () => {
|
|
1732
|
+
for (const pending of this.pending.values()) {
|
|
1733
|
+
pending.reject({
|
|
1734
|
+
code: "BridgeDisconnectedError",
|
|
1735
|
+
message: "Bridge disconnected before call completion.",
|
|
1736
|
+
service: pending.service,
|
|
1737
|
+
member: pending.member,
|
|
1738
|
+
requestId: pending.requestId
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
this.pending.clear();
|
|
1742
|
+
});
|
|
1380
1743
|
}
|
|
1381
1744
|
|
|
1382
1745
|
static async create(): Promise<WebSocketBridgeAdapter> {
|
|
@@ -1408,8 +1771,14 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1408
1771
|
async call<T>(service: string, member: string, args: unknown[]): Promise<T> {
|
|
1409
1772
|
const requestId = \`req-\${++this.requestCounter}\`;
|
|
1410
1773
|
const payload = { type: "call", requestId, service, member, args };
|
|
1411
|
-
return await new Promise<T>((resolve) => {
|
|
1412
|
-
this.pending.set(requestId,
|
|
1774
|
+
return await new Promise<T>((resolve, reject) => {
|
|
1775
|
+
this.pending.set(requestId, {
|
|
1776
|
+
service,
|
|
1777
|
+
member,
|
|
1778
|
+
requestId,
|
|
1779
|
+
resolve: (value) => resolve(value as T),
|
|
1780
|
+
reject
|
|
1781
|
+
});
|
|
1413
1782
|
this.socket.send(JSON.stringify(payload));
|
|
1414
1783
|
});
|
|
1415
1784
|
}
|
|
@@ -1437,6 +1806,18 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1437
1806
|
onSlotInvocation(handler: SlotInvocationListener): void {
|
|
1438
1807
|
this.slotListeners.push(handler);
|
|
1439
1808
|
}
|
|
1809
|
+
|
|
1810
|
+
onDrop(handler: DropListener): void {
|
|
1811
|
+
this.dropListeners.push(handler);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
onHover(handler: HoverListener): void {
|
|
1815
|
+
this.hoverListeners.push(handler);
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
onHoverLeft(handler: HoverLeftListener): void {
|
|
1819
|
+
this.hoverLeftListeners.push(handler);
|
|
1820
|
+
}
|
|
1440
1821
|
}
|
|
1441
1822
|
|
|
1442
1823
|
@Injectable({ providedIn: "root" })
|
|
@@ -1444,6 +1825,9 @@ class AnQstBridgeRuntime {
|
|
|
1444
1825
|
private adapter: BridgeAdapter | null = null;
|
|
1445
1826
|
private readonly slotHandlers = new Map<string, SlotHandler>();
|
|
1446
1827
|
private readonly outputHandlers = new Map<string, OutputHandler[]>();
|
|
1828
|
+
private readonly dropHandlers = new Map<string, ((payload: unknown, x: number, y: number) => void)[]>();
|
|
1829
|
+
private readonly hoverHandlers = new Map<string, ((payload: unknown, x: number, y: number) => void)[]>();
|
|
1830
|
+
private readonly hoverLeftHandlers = new Map<string, (() => void)[]>();
|
|
1447
1831
|
private readonly startup = this.init();
|
|
1448
1832
|
|
|
1449
1833
|
async ready(): Promise<void> {
|
|
@@ -1494,6 +1878,27 @@ class AnQstBridgeRuntime {
|
|
|
1494
1878
|
this.outputHandlers.set(key, existing);
|
|
1495
1879
|
}
|
|
1496
1880
|
|
|
1881
|
+
onDrop(service: string, member: string, handler: (payload: unknown, x: number, y: number) => void): void {
|
|
1882
|
+
const key = this.key(service, member);
|
|
1883
|
+
const existing = this.dropHandlers.get(key) ?? [];
|
|
1884
|
+
existing.push(handler);
|
|
1885
|
+
this.dropHandlers.set(key, existing);
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
onHover(service: string, member: string, handler: (payload: unknown, x: number, y: number) => void): void {
|
|
1889
|
+
const key = this.key(service, member);
|
|
1890
|
+
const existing = this.hoverHandlers.get(key) ?? [];
|
|
1891
|
+
existing.push(handler);
|
|
1892
|
+
this.hoverHandlers.set(key, existing);
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
onHoverLeft(service: string, member: string, handler: () => void): void {
|
|
1896
|
+
const key = this.key(service, member);
|
|
1897
|
+
const existing = this.hoverLeftHandlers.get(key) ?? [];
|
|
1898
|
+
existing.push(handler);
|
|
1899
|
+
this.hoverLeftHandlers.set(key, existing);
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1497
1902
|
private requireAdapterSync(): BridgeAdapter {
|
|
1498
1903
|
if (this.adapter === null) {
|
|
1499
1904
|
throw new Error("AnQst bridge is not ready.");
|
|
@@ -1520,7 +1925,7 @@ class AnQstBridgeRuntime {
|
|
|
1520
1925
|
outputHandler(value);
|
|
1521
1926
|
}
|
|
1522
1927
|
});
|
|
1523
|
-
this.adapter.onSlotInvocation((requestId, service, member, args) => {
|
|
1928
|
+
this.adapter.onSlotInvocation(async (requestId, service, member, args) => {
|
|
1524
1929
|
const key = this.key(service, member);
|
|
1525
1930
|
const handler = this.slotHandlers.get(key);
|
|
1526
1931
|
if (handler === undefined) {
|
|
@@ -1528,10 +1933,33 @@ class AnQstBridgeRuntime {
|
|
|
1528
1933
|
return;
|
|
1529
1934
|
}
|
|
1530
1935
|
try {
|
|
1531
|
-
const result = handler(...args);
|
|
1936
|
+
const result = await Promise.resolve(handler(...args));
|
|
1937
|
+
if (result instanceof Error) {
|
|
1938
|
+
this.adapter!.resolveSlot(requestId, false, undefined, result.message);
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1532
1941
|
this.adapter!.resolveSlot(requestId, true, result, "");
|
|
1533
1942
|
} catch (error) {
|
|
1534
|
-
|
|
1943
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1944
|
+
this.adapter!.resolveSlot(requestId, false, undefined, message);
|
|
1945
|
+
}
|
|
1946
|
+
});
|
|
1947
|
+
this.adapter.onDrop((service, member, payload, x, y) => {
|
|
1948
|
+
const key = this.key(service, member);
|
|
1949
|
+
for (const handler of this.dropHandlers.get(key) ?? []) {
|
|
1950
|
+
handler(payload, x, y);
|
|
1951
|
+
}
|
|
1952
|
+
});
|
|
1953
|
+
this.adapter.onHover((service, member, payload, x, y) => {
|
|
1954
|
+
const key = this.key(service, member);
|
|
1955
|
+
for (const handler of this.hoverHandlers.get(key) ?? []) {
|
|
1956
|
+
handler(payload, x, y);
|
|
1957
|
+
}
|
|
1958
|
+
});
|
|
1959
|
+
this.adapter.onHoverLeft((service, member) => {
|
|
1960
|
+
const key = this.key(service, member);
|
|
1961
|
+
for (const handler of this.hoverLeftHandlers.get(key) ?? []) {
|
|
1962
|
+
handler();
|
|
1535
1963
|
}
|
|
1536
1964
|
});
|
|
1537
1965
|
for (const key of this.slotHandlers.keys()) {
|
|
@@ -1764,7 +2192,7 @@ function renderNodeExpressWsIndex(spec) {
|
|
|
1764
2192
|
sendJson(session.socket, {
|
|
1765
2193
|
type: "callResult",
|
|
1766
2194
|
requestId,
|
|
1767
|
-
result: {
|
|
2195
|
+
result: { code: "HandlerNotRegisteredError", message: err.message, service, member, requestId }
|
|
1768
2196
|
});
|
|
1769
2197
|
throw err;
|
|
1770
2198
|
}
|
|
@@ -1786,7 +2214,7 @@ function renderNodeExpressWsIndex(spec) {
|
|
|
1786
2214
|
sendJson(session.socket, {
|
|
1787
2215
|
type: "callResult",
|
|
1788
2216
|
requestId,
|
|
1789
|
-
result: {
|
|
2217
|
+
result: { code: "CallHandlerError", message, service, member, requestId }
|
|
1790
2218
|
});
|
|
1791
2219
|
});
|
|
1792
2220
|
return;
|
|
@@ -2138,7 +2566,7 @@ export interface ${spec.widgetName}NodeBridge {
|
|
|
2138
2566
|
export function create${spec.widgetName}NodeExpressWsBridge(options: ${spec.widgetName}NodeBridgeOptions): ${spec.widgetName}NodeBridge {
|
|
2139
2567
|
const wsPath = options.wsPath ?? "/anqst-bridge";
|
|
2140
2568
|
const devConfigPath = options.devConfigPath ?? "/anqst-dev-config.json";
|
|
2141
|
-
const defaultSlotTimeoutMs = options.defaultSlotTimeoutMs ??
|
|
2569
|
+
const defaultSlotTimeoutMs = options.defaultSlotTimeoutMs ?? 1000;
|
|
2142
2570
|
const maxQueuedPerSlot = options.maxQueuedSlotInvocationsPerSlot ?? 1024;
|
|
2143
2571
|
const sessions = new Map<WebSocket, ${spec.widgetName}NodeSession>();
|
|
2144
2572
|
const diagnosticListeners = new Set<(diagnostic: AnQstDiagnostic) => void>();
|
|
@@ -2230,7 +2658,7 @@ ${callDispatch}
|
|
|
2230
2658
|
sendJson(session.socket, {
|
|
2231
2659
|
type: "callResult",
|
|
2232
2660
|
requestId,
|
|
2233
|
-
result: {
|
|
2661
|
+
result: { code: "HandlerNotRegisteredError", message: err.message, service, member, requestId }
|
|
2234
2662
|
});
|
|
2235
2663
|
throw err;
|
|
2236
2664
|
}
|
|
@@ -2363,7 +2791,8 @@ function generateOutputs(spec, options = { emitQWidget: true, emitAngularService
|
|
|
2363
2791
|
const cppTypes = buildCppTypeContext(spec);
|
|
2364
2792
|
outputs[`${cppDir}/CMakeLists.txt`] = renderCMake(spec);
|
|
2365
2793
|
outputs[`${cppDir}/${spec.widgetName}.qrc`] = renderEmbeddedQrc(spec.widgetName, []);
|
|
2366
|
-
outputs[`${cppDir}/include/${spec.widgetName}.h`] =
|
|
2794
|
+
outputs[`${cppDir}/include/${spec.widgetName}.h`] = renderWidgetUmbrellaHeader(spec);
|
|
2795
|
+
outputs[`${cppDir}/include/${spec.widgetName}Widget.h`] = renderWidgetHeader(spec, cppTypes);
|
|
2367
2796
|
outputs[`${cppDir}/include/${spec.widgetName}Types.h`] = renderTypesHeader(spec, cppTypes);
|
|
2368
2797
|
outputs[`${cppDir}/${spec.widgetName}.cpp`] = renderCppStub(spec, cppTypes);
|
|
2369
2798
|
}
|
|
@@ -2572,6 +3001,7 @@ set(CMAKE_AUTOUIC ON)
|
|
|
2572
3001
|
set(CMAKE_AUTORCC ON)
|
|
2573
3002
|
|
|
2574
3003
|
find_program(ANQST_NPM_EXECUTABLE npm REQUIRED)
|
|
3004
|
+
find_program(ANQST_NPX_EXECUTABLE npx REQUIRED)
|
|
2575
3005
|
|
|
2576
3006
|
add_custom_command(
|
|
2577
3007
|
OUTPUT
|
|
@@ -2579,10 +3009,11 @@ add_custom_command(
|
|
|
2579
3009
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2580
3010
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2581
3011
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
3012
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2582
3013
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2583
3014
|
"\${${generatedRootVar}}/webapp/index.html"
|
|
2584
3015
|
COMMAND "\${ANQST_NPM_EXECUTABLE}" install
|
|
2585
|
-
COMMAND "\${
|
|
3016
|
+
COMMAND "\${ANQST_NPX_EXECUTABLE}" anqst build
|
|
2586
3017
|
WORKING_DIRECTORY "\${${projectRootVar}}"
|
|
2587
3018
|
COMMENT "Generating AnQst widget library (${widgetTarget}) from Angular project"
|
|
2588
3019
|
VERBATIM
|
|
@@ -2594,6 +3025,7 @@ add_custom_target(${autogenTarget}
|
|
|
2594
3025
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2595
3026
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2596
3027
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
3028
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2597
3029
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2598
3030
|
"\${${generatedRootVar}}/webapp/index.html"
|
|
2599
3031
|
)
|
|
@@ -2602,6 +3034,7 @@ set_source_files_properties(
|
|
|
2602
3034
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2603
3035
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2604
3036
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
3037
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2605
3038
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2606
3039
|
PROPERTIES GENERATED TRUE
|
|
2607
3040
|
)
|
|
@@ -2610,6 +3043,7 @@ add_library(${widgetTarget}
|
|
|
2610
3043
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2611
3044
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2612
3045
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
3046
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2613
3047
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2614
3048
|
)
|
|
2615
3049
|
add_dependencies(${widgetTarget} ${autogenTarget})
|
|
@@ -2797,7 +3231,7 @@ function installDesignerPluginIconAssets(cwd, pluginDir) {
|
|
|
2797
3231
|
}
|
|
2798
3232
|
function renderQtDesignerPluginCpp(widgetName, widgetCategory, hasIcon) {
|
|
2799
3233
|
const pluginClass = `${widgetName}DesignerPlugin`;
|
|
2800
|
-
const widgetClass = `${widgetName}
|
|
3234
|
+
const widgetClass = `${widgetName}Widget`;
|
|
2801
3235
|
const groupName = escapeCppStringLiteral(widgetCategory);
|
|
2802
3236
|
const iconExpression = hasIcon
|
|
2803
3237
|
? 'QIcon(QStringLiteral(":/anqstdesignerplugin/plugin-icon.png"))'
|
|
@@ -2807,7 +3241,7 @@ function renderQtDesignerPluginCpp(widgetName, widgetCategory, hasIcon) {
|
|
|
2807
3241
|
#include <QObject>
|
|
2808
3242
|
#include <QString>
|
|
2809
3243
|
#include <QWidget>
|
|
2810
|
-
#include "
|
|
3244
|
+
#include "${widgetName}.h"
|
|
2811
3245
|
|
|
2812
3246
|
class ${pluginClass} final : public QObject, public QDesignerCustomWidgetInterface {
|
|
2813
3247
|
Q_OBJECT
|
|
@@ -2823,9 +3257,10 @@ public:
|
|
|
2823
3257
|
QString toolTip() const override { return QStringLiteral("${widgetName} generated by AnQst."); }
|
|
2824
3258
|
QString whatsThis() const override { return QStringLiteral("${widgetName} generated by AnQst."); }
|
|
2825
3259
|
bool isContainer() const override { return false; }
|
|
2826
|
-
QString includeFile() const override { return QStringLiteral("
|
|
3260
|
+
QString includeFile() const override { return QStringLiteral("${widgetName}.h"); }
|
|
2827
3261
|
QWidget* createWidget(QWidget* parent) override {
|
|
2828
3262
|
auto* widget = new ${widgetClass}(parent);
|
|
3263
|
+
widget->setMinimumHeight(128);
|
|
2829
3264
|
widget->setProperty("anqstDesignerContext", true);
|
|
2830
3265
|
return widget;
|
|
2831
3266
|
}
|
|
@@ -2836,6 +3271,12 @@ public:
|
|
|
2836
3271
|
return QStringLiteral(
|
|
2837
3272
|
"<ui language=\\"c++\\">\\n"
|
|
2838
3273
|
" <widget class=\\"${widgetClass}\\" name=\\"${widgetName.toLowerCase()}\\">\\n"
|
|
3274
|
+
" <property name=\\"minimumSize\\">\\n"
|
|
3275
|
+
" <size>\\n"
|
|
3276
|
+
" <width>256</width>\\n"
|
|
3277
|
+
" <height>128</height>\\n"
|
|
3278
|
+
" </size>\\n"
|
|
3279
|
+
" </property>\\n"
|
|
2839
3280
|
" </widget>\\n"
|
|
2840
3281
|
"</ui>\\n");
|
|
2841
3282
|
}
|