Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port GUI to qt #526

Open
sezanzeb opened this issue Nov 1, 2022 · 12 comments
Open

Port GUI to qt #526

sezanzeb opened this issue Nov 1, 2022 · 12 comments

Comments

@sezanzeb
Copy link
Owner

sezanzeb commented Nov 1, 2022

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-gtk/
    • input-remapper-gtk/ (python code)
    • readme.md
    • setup.py
    • tests/
    • etc.
  • input-remapper-qt/
    • input-remapper-qt/ (python code)
    • readme.md
    • setup.py
    • tests/
    • etc.
  • input-remapper/
    • input-remapper/ (python code)
      • common classes for guis (message_broker, data_manager, controller, etc.)
      • service stuff
    • readme.md
    • setup.py
    • tests/
    • etc.
  • .reviewdog.yml
  • shell.nix
  • readme.md
  • etc.

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 sezanzeb changed the title Port Interface to QT Port GUI to qt Nov 1, 2022
@sezanzeb
Copy link
Owner Author

sezanzeb commented Nov 1, 2022

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

@sezanzeb sezanzeb pinned this issue Nov 1, 2022
@LunNova
Copy link
Contributor

LunNova commented Nov 1, 2022

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
Copy link
Owner Author

sezanzeb commented Nov 6, 2022

allright, thanks

@sezanzeb
Copy link
Owner Author

sezanzeb commented Feb 9, 2023

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
Copy link

Mte90 commented Mar 23, 2023

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:

  • usual QtDesigner with .ui files (xml), on KDE there is KUIviewer (just a viewer)
  • QML files (JSON) that can include JS to simplify

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
Copy link

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
Copy link

Mte90 commented Mar 23, 2023

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
Copy link

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
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
Copy link

Mte90 commented May 31, 2023

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
Copy link

It doesn't pull any KDE stuff.

@CarlSchwan
Copy link

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
Copy link
Owner Author

sezanzeb commented Nov 11, 2023

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:

  • there is no good place to add a search field to search through mappings
  • the displayed preset title should be editable in-place (possibly toggling from text to text-input by clicking on it), not via a separate input field below

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants