sezanzeb / input-remapper

🎮 ⌨ An easy to use tool to change the behaviour of your input devices.
GNU General Public License v3.0
3.69k stars 153 forks source link

Port GUI to qt #526

Open sezanzeb opened 1 year ago

sezanzeb commented 1 year ago

Looking for a qt contributor

This is about the GUI on beta: https://github.com/sezanzeb/input-remapper/tree/beta

I switched to KDE and I'm interested in seeing how this would work with qt, and am not interested in GTK right now.

As long as the GTK GUI works I'd keep in the repo. If GTK3 ever reaches EOL in a way that prevents it to work at all, input-remapper-gtk will reach EOL as well unless someone upgrades it to GTK4. I would like to avoid using libadwaita, because that prevents theming in KDE.

Requirements

I'd like the qt port to be similar to the existing GUI, unless the change is justified by https://develop.kde.org/hig/, how other KDE applications generally look, or by an improved user experience.

Doing this step-by-step over multiple pull requests is fine, starting with an MVP.

Maybe use https://develop.kde.org/frameworks/kirigami/

Difficulties

I think the ReaderClient uses glib to call something every few ms, this would require some clever trick to make it work with both qt and gtk event loops. Other modules might be affected as well.

The Autocompletion uses lots of GTK code. I don't know how autocompletions would work in qt, in GTK I had to write it myself because the one from the GtkSourceView component is not looking good enough.

There is a huge load of tests for the GTK GUI, which test GUI components by interacting with GTK things. Porting them directly might be unrealistic. I guess writing new tests based on coverage results is a better idea.

Repo and Architecture

Input-remapper should be refactored to a monorepo containing multiple packages

input-remapper contains the service and all common python classes, but no gtk/glib/etc. dependencies at all.

Ubuntu has already split the package into multiple: https://packages.ubuntu.com/kinetic/input-remapper-gtk, this might make it easier for them to maintain it in their repo.

Here is some info about input-remappers architecture: https://github.com/sezanzeb/input-remapper/blob/beta/readme/development.md#architecture

sezanzeb commented 1 year ago

@LunNova is changing the repo into a monorepo containing multiple python packages difficult for CI?

LunNova commented 1 year ago

I think as long as you can still pip install them all separately in the ci script and have the tests work it should be fine? I haven't set that up before for python.

sezanzeb commented 1 year ago

allright, thanks

sezanzeb commented 1 year ago

Should input-remappers gui be changed to not use headerbars and instead use the regular headers?

I couldn't care less about gnome nowadays. It will make it look a bit better in KDE, because the window-border setting is respected. And gnome users are probably used to having a wild mix between headerbar apps and regular apps anyway

As far as I am concerned, gnomes headerbars and libadwaita are for gnome exclusive semi mobile apps. Not for desktop environment agnostic linux desktop apps.

Mte90 commented 1 year ago

Just some inputs as I worked on various app with Python/qt, I did also a boilerplate https://github.com/Mte90/PyQT-Boilerplate As today there are 2 ways to do GUI:

Right now on kde they are slowly migrating everything to QML because it is more easy to complex advanced UI (as they need). Kirigami right now (on QML) is just used on C++/Rust/Whatever but not on python (there aren't guides), I was able to just find this https://invent.kde.org/nicolasfella/kstraba that is a tiny application.

On python with ui files there are 2 solutions, load the ui file directly or generate with a command the py version so you can have also the autocomplete and should be more faster. I usually do the second way. Anyway both the solution let to you to use CSS. Also for documentation about python you find very few things but the cool part is that is just Qt so you can see the code on a C++ or other languages and the official documentation on how to use it/what you need to do. The only difference is that you don't have the QString object as pyqt/pyside switch to the native python feature as both support unicode with python3.

For some python/qt (I suggest as today to use pyside) you can look on this my old projects (some of them still works):

I have an old talk by me about pyqt http://mte90.tech/Talk-PyQT/ with the recording https://www.youtube.com/watch?v=bbkFkf2WBgk

So my suggestion to start is recreate the same UI with QtDesigner or atleast part of that and start recreating the various features. Last time I worked with Gtk it was like 10 years ago to me so I don't know if it is easy or not migrate the actual codebase.

About the testing stuff instead I have 0 experience.

herzenschein commented 1 year ago

There is a more complete tutorial about Kirigami + PySide: https://dimitris.cc/kde/2022/02/26/pyside-blog-post.html

It's well done, so it's being upstreamed as an official tutorial with minimal changes (mostly updates and ensuring it works).

I've heard one of the problems with this approach is that PySide comes with its own Qt, which Kirigami cannot be installed into, so you'd need to install PySide from the package manager instead of pip. But from what I understand, this is only for the build phase. After it's packaged it should work I think.

Taking a look at the app's screenshot it does seem like it could be easily replicated with QML.

Mte90 commented 1 year ago

Thanks for that article I missed in my kde feeds :-)

I think that can be investigated what is the best approach if pure qt or use kirigami/qt.

herzenschein commented 1 year ago

I made a very low effort, buggy example in half an hour with my limited knowledge of QML and Kirigami based on https://github.com/sezanzeb/input-remapper/blob/main/readme/screenshot.png:

QML File contents ```qml import QtQuick 2.15 import QtQuick.Controls 2.15 as Controls import QtQuick.Layouts 1.15 import org.kde.kirigami 2.12 as Kirigami Kirigami.ApplicationWindow { width: 700 height: 500 pageStack.initialPage: editorPage contextDrawer: Kirigami.ContextDrawer {} Component { id: devicesPage Kirigami.Page { title: "Devices" } } Component { id: presetsPage Kirigami.Page { title: "Presets" } } Component { id: editorPage Kirigami.Page { title: "Editor" actions { main: Kirigami.Action { text: "Create a new preset" onTriggered: newPreset.open() } } RowLayout { anchors.fill: parent ColumnLayout { Layout.alignment: Qt.AlignTop Layout.fillWidth: true Layout.fillHeight: true Controls.Label { text: "Input" } RowLayout { id: lay Layout.fillWidth: true Controls.Button { text: "Add" icon.name: "list-add" } Controls.Button { text: "Record" icon.name: "media-record" } Controls.Button { text: "Advaced" icon.name: "document-edit" } Controls.Button { text: "Delete" icon.name: "edit-delete" } } ListView { Layout.fillWidth: true height: 200 model: 10 delegate: Controls.Button { text: modelData width: lay.width } } } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignTop Controls.Label { text: "Output" Layout.alignment: Text.AlignHCenter } Kirigami.FormLayout { ColumnLayout { Kirigami.FormData.label: "Type" Controls.RadioButton { text: "Key or Macro" } Controls.RadioButton { text: "Analog Axis" } } Controls.ComboBox { Kirigami.FormData.label: "Target" model: ["Keyboard", "Something else"] } } } } } } Kirigami.OverlaySheet { id: newPreset header: Kirigami.Heading { text: "Your device: New preset" } ColumnLayout { RowLayout { Controls.Button { text: "Apply" icon.name: "media-playback-start" } Controls.Button { text: "Stop" icon.name: "media-playback-stop" } Controls.Button { text: "Copy" icon.name: "edit-copy" } Controls.Button { text: "Delete" icon.name: "edit-delete" } } ColumnLayout { Layout.fillWidth: parent RowLayout { Controls.Label { text: "Rename" } Controls.TextField { Layout.fillWidth: parent } Controls.Button { icon.name: "document-save" } } RowLayout { Controls.Label { text: "Autoload" } Controls.Switch { } } } } } } ```

You can run it with QT_QUICK_CONTROLS_STYLE=org.kde.desktop qmlscene main.qml.

After clicking the button

It's awfully done and I didn't bother to center the title label or style the listview, but it's less than 100 actual code lines (146 with the curly brackets). It should give a general idea of how QML looks like and why Kirigami can be handy in some places (like Pages, the pageStack for global access the pages, or FormLayout). I immediately thought the Devices, Presets and Editor could each be a separate page, or maybe a dynamic TabBox.

Ways to improve this awful example of mine could be using GroupBox or a separator, using Kirigami.PlatformTheme for theme integration, using separate QML files, creating your own small components, fixing layout issues. A better showcase of those is QtQuick Controls Gallery and Kirigami Gallery, and an example of a well designed Kirigami application would be Neochat, though all of those use C++ together with QML.

Having said that, the boxy, traditional UI style used here could look very good with Python + QtWidgets as well. Especially since QtWidgets gets some extra default styling compared to QtQuick.

Mte90 commented 1 year ago

Reading now, kirigami is cool but this means that on GTK environment requires to download all the kde stuff to not just the QT. This it should be something that the project need to decide what are the next steps.

I don't know if it is possible to use kirigami if available otherwise switch to pure qt.

herzenschein commented 1 year ago

It doesn't pull any KDE stuff.

CarlSchwan commented 1 year ago

So Kirigami doesn't pull other KDE stuff aside of Extra Cmake Module (ECM), but ECM is a built-time dependency, so not something your user will have to download.

Aside from Kirigami, I recommend looking into Ki18n, which is also a tier 1 kde framework since you are using in your existing app gettext and ki18n is a Qt wrapper around gettext. So you won't have to port all your translation to the Qt translation format.

I guess 2 KDE dependencies should be okay :)

Qt uses glib event loops on Linux, so using a bit of glib stuff in a Qt app should also not be an issue.

sezanzeb commented 10 months ago

I just realized I never commented on this. Thanks for the work and thought you put into this earlier this year. I sometimes wonder if qt is better to work with, using GTK was not a fun experience.

There are a few issues with the current gui, many of which are probably documented in the issues https://github.com/sezanzeb/input-remapper/issues?q=is%3Aissue+is%3Aopen+label%3A%22feature+request%22 so a qt-gui from scratch would be a good opportunity to propose a better user interface design.

Apart from those, I think for the following two points there is no existing feature-request: