From 1d98ff79af9e7efbb971cf0847a35c6cfdfb2c95 Mon Sep 17 00:00:00 2001
From: Přemysl Eric Janouch 
Date: Fri, 13 Dec 2024 06:37:21 +0100
Subject: WIP: Add a Qt Quick frontend for xC
We have to decouple the UI from the relay code.
---
 xT/CMakeLists.txt |  25 ++++++++++---
 xT/xT.cpp         |   2 +-
 xT/xTq.cpp        |  40 +++++++++++++++++++++
 xT/xTq.h          |  15 ++++++++
 xT/xTq.qml        | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 181 insertions(+), 6 deletions(-)
 create mode 100644 xT/xTq.cpp
 create mode 100644 xT/xTq.h
 create mode 100644 xT/xTq.qml
(limited to 'xT')
diff --git a/xT/CMakeLists.txt b/xT/CMakeLists.txt
index 8f27be3..562c15a 100644
--- a/xT/CMakeLists.txt
+++ b/xT/CMakeLists.txt
@@ -12,8 +12,10 @@ project (xT VERSION "${project_version}"
 set (CMAKE_CXX_STANDARD 17)
 set (CMAKE_CXX_STANDARD_REQUIRED ON)
 
-find_package (Qt6 REQUIRED COMPONENTS Widgets Network Multimedia)
-qt_standard_project_setup ()
+find_package (Qt6 REQUIRED COMPONENTS Widgets Network Multimedia
+	Quick QuickControls2)
+# XXX: The version requirement is probably for Qt Quick only.
+qt_standard_project_setup (REQUIRES 6.5)
 
 add_compile_options ("$<$:/utf-8>")
 add_compile_options ("$<$:-Wall;-Wextra>")
@@ -77,7 +79,7 @@ else ()
 endif ()
 
 # Build the main executable and link it
-find_program (awk_EXECUTABLE awk ${find_program_REQUIRE})
+find_program (awk_EXECUTABLE awk REQUIRED)
 add_custom_command (OUTPUT xC-proto.cpp
 	COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${awk_EXECUTABLE}
 		-f ${root}/liberty/tools/lxdrgen.awk
@@ -103,11 +105,24 @@ set_target_properties (xT PROPERTIES WIN32_EXECUTABLE ON MACOSX_BUNDLE ON
 # https://stackoverflow.com/questions/79079161 and resolved in Qt Creator 16.
 set (QT_QML_GENERATE_QMLLS_INI ON)
 
+# TODO(p): Perhaps do it in one-or-the-other way,
+# as Qt Quick sucks on the desktop, and Qt Widgets is unusable on mobile.
+qt_add_executable (xTq
+	xTq.cpp ${project_config} ${project_sources} "${icon_icns}")
+set_property (SOURCE xTq.qml APPEND PROPERTY QT_QML_SOURCE_TYPENAME Main)
+qt_add_qml_module (xTq URI xTquick VERSION 1.0 QML_FILES xTq.qml)
+add_dependencies (xTq xC-proto)
+qt_add_resources (xTq "rsrc" PREFIX / FILES "${beep}" ${icon_rsrc_list})
+target_link_libraries (xTq PRIVATE
+	Qt6::Quick Qt6::QuickControls2 Qt6::Network Qt6::Multimedia)
+set_target_properties (xTq PROPERTIES WIN32_EXECUTABLE ON MACOSX_BUNDLE ON
+	MACOSX_BUNDLE_GUI_IDENTIFIER name.janouch.xTq)
+
 # The files to be installed
 include (GNUInstallDirs)
 
 if (ANDROID)
-	install (TARGETS xT DESTINATION .)
+	install (TARGETS xTq DESTINATION .)
 elseif (APPLE OR WIN32)
 	install (TARGETS xT
 		BUNDLE DESTINATION .
@@ -144,7 +159,7 @@ if (WIN32)
 		foreach (lib ${libs})
 			string (STRIP "${lib}" lib)
 			file (COPY "${cygroot}${lib}" DESTINATION "${bindir}")
-		endforeach()
+		endforeach ()
 	endif ()
 	]=])
 endif ()
diff --git a/xT/xT.cpp b/xT/xT.cpp
index f84c87c..72f5892 100644
--- a/xT/xT.cpp
+++ b/xT/xT.cpp
@@ -1,5 +1,5 @@
 /*
- * xT.cpp: Qt frontend for xC
+ * xT.cpp: Qt Widgets frontend for xC
  *
  * Copyright (c) 2024, Přemysl Eric Janouch 
  *
diff --git a/xT/xTq.cpp b/xT/xTq.cpp
new file mode 100644
index 0000000..a6d48bf
--- /dev/null
+++ b/xT/xTq.cpp
@@ -0,0 +1,40 @@
+/*
+ * xTq.cpp: Qt Quick frontend for xC
+ *
+ * Copyright (c) 2024, Přemysl Eric Janouch 
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "xC-proto.cpp"
+
+#include 
+
+#include 
+#include 
+
+#include "xTq.h"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+int
+main(int argc, char *argv[])
+{
+	QGuiApplication app(argc, argv);
+
+	QQmlApplicationEngine engine;
+	QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
+		&app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection);
+	engine.loadFromModule("xTquick", "Main");
+	return app.exec();
+}
diff --git a/xT/xTq.h b/xT/xTq.h
new file mode 100644
index 0000000..70a0374
--- /dev/null
+++ b/xT/xTq.h
@@ -0,0 +1,15 @@
+#ifndef XTQ_H
+#define XTQ_H
+
+#include 
+#include 
+
+class RelayConnection : public QObject {
+	Q_OBJECT
+	QML_ELEMENT
+
+public:
+	QTcpSocket *socket;                 ///< Buffered relay socket
+};
+
+#endif // XTQ_H
diff --git a/xT/xTq.qml b/xT/xTq.qml
new file mode 100644
index 0000000..50063c9
--- /dev/null
+++ b/xT/xTq.qml
@@ -0,0 +1,105 @@
+import QtQuick
+import QtQuick.Controls.Fusion
+//import QtQuick.Controls
+import QtQuick.Layouts
+
+ApplicationWindow {
+	id: window
+	width: 640
+	height: 480
+	visible: true
+	title: qsTr("xT")
+
+	property RelayConnection connection
+
+	ColumnLayout {
+		id: column
+		anchors.fill: parent
+		anchors.margins: 6
+
+		ScrollView {
+			id: bufferScroll
+			Layout.fillWidth: true
+			Layout.fillHeight: true
+			TextArea {
+				id: buffer
+				text: qsTr("Buffer text")
+			}
+		}
+
+		RowLayout {
+			id: row
+			Layout.fillWidth: true
+
+			Label {
+				Layout.fillWidth: true
+				id: prompt
+				text: qsTr("Prompt")
+			}
+
+			Label {
+				Layout.fillWidth: true
+				id: status
+				horizontalAlignment: Text.AlignRight
+				text: qsTr("Status")
+			}
+		}
+
+		TextArea {
+			id: input
+			Layout.fillWidth: true
+			text: qsTr("Input")
+		}
+	}
+
+	Component.onCompleted: {}
+
+	Dialog {
+		id: connect
+		title: "Connect to relay"
+		anchors.centerIn: parent
+		modal: true
+		visible: true
+
+		onRejected: Qt.quit()
+		onAccepted: {
+			// TODO(p): Store the host, store the port, initiate connection.
+		}
+
+		GridLayout {
+			anchors.fill: parent
+			anchors.margins: 6
+			columns: 2
+
+			// It is a bit silly that one has to do everything manually.
+			Keys.onReturnPressed: connect.accept()
+
+			Label { text: "Host:" }
+			TextField {
+				id: connectHost
+				Layout.fillWidth: true
+				// And if this doesn't work reliably, do it after open().
+				focus: true
+			}
+			Label { text: "Port:" }
+			TextField {
+				id: connectPort
+				Layout.fillWidth: true
+			}
+		}
+
+		footer: DialogButtonBox {
+			Button {
+				text: qsTr("Connect")
+				DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
+				Keys.onReturnPressed: connect.accept()
+				highlighted: true
+			}
+			Button {
+				text: qsTr("Close")
+				DialogButtonBox.buttonRole: DialogButtonBox.DestructiveRole
+				Keys.onReturnPressed: connect.reject()
+			}
+		}
+	}
+}
-- 
cgit v1.2.3-70-g09d2