fui_system 0.14.1

System controls (dialogs, tray etc.) for FUI UI Framework
#include "qwindow_ext.h"
#include <QMouseEvent>

QWindowExt::QWindowExt(QWindow *parent)
    : QOpenGLWindow(QOpenGLWindow::NoPartialUpdate, parent),
    m_funcEvent(0),
    m_funcInitializeGL(0),
    m_funcPaintGL(0)
{
}

void QWindowExt::setEventFunc(void* (*func)(void*, void*), void *data)
{
    m_funcEvent = func;
    m_dataEvent = data;
}

void QWindowExt::setInitializeGLFunc(void (*func)(void*), void *data)
{
    m_funcInitializeGL = func;
    m_dataInitializeGL = data;
}

void QWindowExt::setPaintGLFunc(void (*func)(void*), void *data)
{
    m_funcPaintGL = func;
    m_dataPaintGL = data;
}

bool QWindowExt::event(QEvent *event)
{
    if (m_funcEvent)
    {
        FFIEvent ffiEvent;
        if (convertEventToRust(event, ffiEvent)) {
            void *result = m_funcEvent(m_dataEvent, (void*)&ffiEvent);

            freeEvent(ffiEvent);

            if (result != 0) {
                return true;
            }
        }
    }

    return QOpenGLWindow::event(event);
}

void QWindowExt::initializeGL()
{
    if (m_funcInitializeGL)
    {
        m_funcInitializeGL(m_dataInitializeGL);
    }
}

void QWindowExt::paintGL()
{
    if (m_funcPaintGL)
    {
        m_funcPaintGL(m_dataPaintGL);
    }
}

bool QWindowExt::convertEventToRust(QEvent *event, FFIEvent &ffiEvent)
{
    switch (event->type())
    {
        case QEvent::Enter: {
            ffiEvent.tag = FFIEvent::Tag::MouseEnter;
            return true;
        }

        case QEvent::Leave: {
            ffiEvent.tag = FFIEvent::Tag::MouseLeave;
            return true;
        }

        case QEvent::MouseMove: {
            ffiEvent.tag = FFIEvent::Tag::MouseMove;
            ffiEvent.mouse_move.position.x = ((QMouseEvent*)event)->position().x();
            ffiEvent.mouse_move.position.y = ((QMouseEvent*)event)->position().y();
            return true;
        }

        case QEvent::MouseButtonPress:
        case QEvent::MouseButtonRelease: {
            ffiEvent.tag = FFIEvent::Tag::MouseButton;
            ffiEvent.mouse_button.state = event->type() == QEvent::MouseButtonPress ?
                                          FFIElementState::Pressed : FFIElementState::Released;
            ffiEvent.mouse_button.button = convertMouseButton(((QMouseEvent*)event)->button());
            return true;
        }

        case QEvent::Wheel: {
            ffiEvent.tag = FFIEvent::Tag::ScrollWheel;

            QPoint degrees = ((QWheelEvent*)event)->angleDelta();
            if (!degrees.isNull()) {
                ffiEvent.scroll_wheel.delta.tag = FFIScrollDelta::Tag::LineDelta;
                ffiEvent.scroll_wheel.delta.line_delta._0 = degrees.x() / 120.0;
                ffiEvent.scroll_wheel.delta.line_delta._1 = degrees.y() / 120.0;
                return true;
            }

            QPoint pixels = ((QWheelEvent*)event)->pixelDelta();
            if (!pixels.isNull()) {
                ffiEvent.scroll_wheel.delta.tag = FFIScrollDelta::Tag::PixelDelta;
                ffiEvent.scroll_wheel.delta.pixel_delta._0 = pixels.x();
                ffiEvent.scroll_wheel.delta.pixel_delta._1 = pixels.y();
                return true;
            }

            return false;
        }

        case QEvent::KeyPress:
        case QEvent::KeyRelease: {
            ffiEvent.tag = FFIEvent::Tag::KeyEvent;
            ffiEvent.key_event.state = event->type() == QEvent::KeyPress ?
                    FFIElementState::Pressed : FFIElementState::Released;
            ffiEvent.key_event.keycode = ((QKeyEvent*)event)->key();
            ffiEvent.key_event.is_repeat = ((QKeyEvent*)event)->isAutoRepeat();
            Qt::KeyboardModifiers modifiers = ((QKeyEvent*)event)->modifiers();
            ffiEvent.key_event.modifiers.shift = (modifiers & Qt::ShiftModifier);
            ffiEvent.key_event.modifiers.ctrl = (modifiers & Qt::ControlModifier);
            ffiEvent.key_event.modifiers.alt = (modifiers & Qt::AltModifier);
            ffiEvent.key_event.modifiers.win = (modifiers & Qt::MetaModifier);
            ffiEvent.key_event.modifiers.keypad = (modifiers & Qt::KeypadModifier);
            if (((QKeyEvent*)event)->text().isEmpty()) {
                ffiEvent.key_event.text = 0;
            } else {
                QByteArray textUtf8 = ((QKeyEvent *) event)->text().toUtf8();
                char *text = new char[textUtf8.size() + 1];
                strcpy(text, textUtf8.data());
                ffiEvent.key_event.text = text;
            }
            return true;
        }

        case QEvent::Resize: {
            ffiEvent.tag = FFIEvent::Tag::Resize;
            ffiEvent.resize.width = ((QResizeEvent*)event)->size().width();
            ffiEvent.resize.height = ((QResizeEvent*)event)->size().height();
            return true;
        }

        default: return false;
    }
}

void QWindowExt::freeEvent(FFIEvent &ffiEvent)
{
    if (ffiEvent.tag == FFIEvent::Tag::KeyEvent) {
        delete[] ffiEvent.key_event.text;
        ffiEvent.key_event.text = 0;
    }
}

FFIMouseButton QWindowExt::convertMouseButton(Qt::MouseButton button)
{
    FFIMouseButton result;

    switch (button) {
        case Qt::LeftButton: {
            result.tag = FFIMouseButton::Tag::Left;
            return result;
        }

        case Qt::RightButton: {
            result.tag = FFIMouseButton::Tag::Right;
            return result;
        }

        case Qt::MiddleButton: {
            result.tag = FFIMouseButton::Tag::Middle;
            return result;
        }

        default: {
            result.tag = FFIMouseButton::Tag::Other;

            uint8_t pos = 4;
            int mask = 8;
            while (!(((int)button) & mask) && pos < 31) {
                mask <<= 1;
                pos++;
            }

            result.other._0 = pos;
            return result;
        }
    }
}