Skip to content

Commit

Permalink
Updated README
Browse files Browse the repository at this point in the history
  • Loading branch information
JonTheBurger committed Sep 13, 2020
1 parent c69a716 commit 160b969
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 25 deletions.
10 changes: 1 addition & 9 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
* text=auto

#sources
*.c text diff=cpp
*.cc text diff=cpp
Expand All @@ -10,36 +9,29 @@
*.h text diff=cpp
*.h++ text diff=cpp
*.hh text diff=cpp

# Compiled Object files
*.slo binary filter=lfs diff=lfs merge=lfs -binary
*.lo binary filter=lfs diff=lfs merge=lfs -binary
*.o binary filter=lfs diff=lfs merge=lfs -binary
*.obj binary filter=lfs diff=lfs merge=lfs -binary

# Precompiled Headers
*.gch binary filter=lfs diff=lfs merge=lfs -binary
*.pch binary filter=lfs diff=lfs merge=lfs -binary

# Compiled Dynamic libraries
*.so binary filter=lfs diff=lfs merge=lfs -binary
*.dylib binary filter=lfs diff=lfs merge=lfs -binary
*.dll binary filter=lfs diff=lfs merge=lfs -binary

# Compiled Static libraries
*.lai binary filter=lfs diff=lfs merge=lfs -binary
*.la binary filter=lfs diff=lfs merge=lfs -binary
*.a binary filter=lfs diff=lfs merge=lfs -binary
*.lib binary filter=lfs diff=lfs merge=lfs -binary

# Executables
*.exe binary filter=lfs diff=lfs merge=lfs -binary
*.out binary filter=lfs diff=lfs merge=lfs -binary
*.app binary filter=lfs diff=lfs merge=lfs -binary

# Resources
*.png binary
*.png filter=lfs diff=lfs merge=lfs -text
*.ico binary
*.jpeg binary
*.jpg binary

1 change: 0 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,3 @@ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# lvgl_sim_qt

![Demo](demo.png?raw=true "Demo")

Provides a small example of how to embed an [lvgl](https://lvgl.io/) application in both a Qt Widgets and Qt Quick C++
application. In Widgets, mouse events are supported, a basic keyboard is supported but must be manually hooked into a
group, and treating the mousewheel as en encoder is left as an exercise to the reader. Demos that require `lv_drivers`
are not currently supported. 32, 16, 8, and 1-bit color are supported, though most examples do not work well with 1-bit
color.

# Building
This software requires:
- C++ >= 14
- CMake >= 3.10
- Qt >= 5.9

```bash
git clone https://github.com/JonTheBurger/lvgl_sim_qt.git --recursive
cd lvgl_sim_qt
cmake -Bbuild -S.
```

Executables will be placed in `build/lvgl_qt_quick` and `build/lvgl_qt_widgets`.

# Modifying
Edits lvgl_sim_qt has made to `lv_conf.h` and `lv_ex_conf.h` can be found by searching for `/** lvgl_sim_qt */`, which
precedes all edits. To change which demo is being run, replace the `lv_example` function call found after
`/// lvgl_sim_qt_example` in the `main.cpp` files. To change the tick period, modify `LvglRenderer::Tick_Period_Ms`. The
default value is `50`. Double buffering can be disabled.

This project is setup to use `lvgl v7.4.0`. When upgrading, be sure to bump both the `lvgl` and `lv_examples` submodules
to matching versions.

# Implementation Notes
- If attempting to port code, note that `LvglGraphicsView` is added in Qt Designer using [promote widget](https://doc.qt.io/qt-5/designer-using-custom-widgets.html).
- Some amount of care has been taken to make this repository Qt6 compatible and lvgl update friendly, but no stable
releases exist at time of writing, so these remain untested
- Qt5 does not support 8-bit 332 color, so a quick and dirty 8-bit color palette is generated in this case
- Both applications render to a `QImage`, so this common functionality is extracted into `lvgl_qt/LvglRenderer`
- Forward declarations of classes are used when possible to speed up preprocess time
- All render callbacks are piped through the Qt event loop, so no additional multithreading considerations should be
necessary for this example
- `mouseMoveEvent` only registers movement on a mouse click by default, so a simpler position query is used instead
- Blindly setting Qt Quick properties from C++ is not a great idea in a production application. In fact, don't use this
as an example of QML best practices.
- Decrease `Tick_Period_Ms` to improve responsiveness

# Future Work
- Mouse support in the Qt Quick example
- _Maybe_ hack around `lv_drivers` to get Qt based keyboard globally registered
3 changes: 3 additions & 0 deletions external/demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions lvgl_qt/LvglRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ static void loadColorTable(QImage& image)
{
lv_color8_t truncated{};
truncated.full = i;
// Shift bitfields by remaining bits in a uint8_t to give their representation maximum impact
Color_Table.push_back(qRgb(truncated.ch.red << 5, truncated.ch.green << 5, truncated.ch.blue << 6));
}
Color_Table[255] = ~0;
Expand Down
6 changes: 3 additions & 3 deletions lvgl_qt/LvglRenderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ class LvglRenderer {
static constexpr size_t Max_Width = LV_HOR_RES_MAX;

private:
alignas(uint32_t) lv_color_t display_frame1_[Max_Width * Max_Height];
alignas(uint32_t) lv_color_t display_frame2_[Max_Width * Max_Height];
alignas(uint32_t) lv_color_t current_frame_[Max_Height][Max_Width];
lv_color_t display_frame1_[Max_Width * Max_Height];
lv_color_t display_frame2_[Max_Width * Max_Height];
lv_color_t current_frame_[Max_Height][Max_Width];
lv_disp_buf_t display_buffer_;
lv_disp_drv_t display_driver_;
QImage image_;
Expand Down
20 changes: 11 additions & 9 deletions lvgl_qt_quick/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <memory>

// 3rd Party
#include <QDebug>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
Expand All @@ -27,18 +28,19 @@ int main(int argc, char* argv[])

const QUrl url(QStringLiteral("qrc:/main.qml"));
engine.load(url);
if (engine.rootObjects().isEmpty())
auto* window = qobject_cast<QQuickWindow*>(engine.rootObjects().value(0, nullptr));
if (window == nullptr)
{
return EXIT_FAILURE;
EXIT_FAILURE;
}
window->setProperty("width", LvglRenderer::Max_Width);
window->setProperty("height", LvglRenderer::Max_Height);

auto* win = qobject_cast<QQuickWindow*>(engine.rootObjects().value(0));
if (win != nullptr)
{
win->setProperty("width", LvglRenderer::Max_Width);
win->setProperty("height", LvglRenderer::Max_Height);
win->setProperty("tick_period_ms", LvglRenderer::Tick_Period_Ms);
}
auto* timer = window->findChild<QObject*>("timer");
timer->setProperty("interval", LvglRenderer::Tick_Period_Ms);

auto* mouseArea = window->findChild<QObject*>("mouseArea");
mouseArea->property("mouseX");

return app.exec();
}
10 changes: 8 additions & 2 deletions lvgl_qt_quick/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ Window {
id: window
visible: true
title: qsTr("lvgl_qt_quick")
property int tick_period_ms: 0
property int swap: 0

// `image.source` has been binded to `swap`, so updating `swap` re-runs `requestPixmap`.
Expand All @@ -15,10 +14,17 @@ Window {
anchors.fill: parent
source: "image://LvglImageProvider/buf" + swap
cache: false

MouseArea {
id: mouseArea
objectName: "mouseArea"
anchors.fill: parent
}
}

Timer {
interval: tick_period_ms
id: timer
objectName: "timer"
running: true
repeat: true
onTriggered: swap = (swap ? 0 : 1)
Expand Down
2 changes: 1 addition & 1 deletion lvgl_qt_widgets/LvglGraphicsView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ static uint32_t toAscii(Qt::Key key)
case Qt::Key_Home:
ascii = LV_KEY_HOME;
case Qt::Key_End:
ascii = (LV_KEY_END);
ascii = (LV_KEY_END); // lack of parens breaks clang-format for some reason...
default:
ascii = key;
break;
Expand Down

0 comments on commit 160b969

Please sign in to comment.