diff --git a/CHANGELOG.md b/CHANGELOG.md index a03526840..60ea1b606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Support for further types: `QLine`, `QLineF`, `QImage`, `QPainter`, `QFont`, `QPen`, `QPolygon`, `QPolygonF` +- Support for further types: `QLine`, `QLineF`, `QImage`, `QPainter`, `QFont`, `QPen`, `QPolygon`, `QPolygonF`, `QRegion` - `internal_pointer_mut()` function on `QModelIndex` - `c_void` in CXX-Qt-lib for easy access to `void *` - `CxxQtThread` is now marked as `Sync` so that it can be used by reference diff --git a/crates/cxx-qt-lib-headers/include/gui/qregion.h b/crates/cxx-qt-lib-headers/include/gui/qregion.h new file mode 100644 index 000000000..32bb666c9 --- /dev/null +++ b/crates/cxx-qt-lib-headers/include/gui/qregion.h @@ -0,0 +1,22 @@ +// clang-format off +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Laurent Montel +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +#pragma once + +#include + +#include "rust/cxx.h" + +// Define namespace otherwise we hit a GCC bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace rust { + +template<> +struct IsRelocatable : ::std::true_type +{ +}; + +} // namespace rust diff --git a/crates/cxx-qt-lib-headers/src/lib.rs b/crates/cxx-qt-lib-headers/src/lib.rs index 9e25d96ff..bf1f5e230 100644 --- a/crates/cxx-qt-lib-headers/src/lib.rs +++ b/crates/cxx-qt-lib-headers/src/lib.rs @@ -86,6 +86,8 @@ pub fn build_opts() -> cxx_qt_build::CxxQtBuildersOpts { #[cfg(feature = "qt_gui")] (include_str!("../include/gui/qpainter.h"), "qpainter.h"), #[cfg(feature = "qt_gui")] + (include_str!("../include/gui/qregion.h"), "qregion.h"), + #[cfg(feature = "qt_gui")] (include_str!("../include/gui/qvector2d.h"), "qvector2d.h"), #[cfg(feature = "qt_gui")] (include_str!("../include/gui/qvector3d.h"), "qvector3d.h"), diff --git a/crates/cxx-qt-lib/build.rs b/crates/cxx-qt-lib/build.rs index de6bbb0c5..3d6176cdc 100644 --- a/crates/cxx-qt-lib/build.rs +++ b/crates/cxx-qt-lib/build.rs @@ -148,6 +148,7 @@ fn main() { "gui/qpen", "gui/qpolygon", "gui/qpolygonf", + "gui/qregion", "gui/qvector2d", "gui/qvector3d", "gui/qvector4d", @@ -208,6 +209,7 @@ fn main() { "gui/qpen", "gui/qpolygon", "gui/qpolygonf", + "gui/qregion", "gui/qvector2d", "gui/qvector3d", "gui/qvector4d", diff --git a/crates/cxx-qt-lib/src/gui/mod.rs b/crates/cxx-qt-lib/src/gui/mod.rs index bf5c18937..5d05db328 100644 --- a/crates/cxx-qt-lib/src/gui/mod.rs +++ b/crates/cxx-qt-lib/src/gui/mod.rs @@ -41,3 +41,6 @@ pub use qpainterpath::QPainterPath; mod qpainter; pub use qpainter::{QPainter, QPainterCompositionMode, QPainterRenderHint}; + +mod qregion; +pub use qregion::QRegion; diff --git a/crates/cxx-qt-lib/src/gui/qpainter.rs b/crates/cxx-qt-lib/src/gui/qpainter.rs index 3e69417a6..b28e51493 100644 --- a/crates/cxx-qt-lib/src/gui/qpainter.rs +++ b/crates/cxx-qt-lib/src/gui/qpainter.rs @@ -173,6 +173,8 @@ mod ffi { type QPen = crate::QPen; include!("cxx-qt-lib/qpolygon.h"); type QPolygon = crate::QPolygon; + include!("cxx-qt-lib/qregion.h"); + type QRegion = crate::QRegion; /// Returns the current background mode. #[rust_name = "background_mode"] @@ -191,6 +193,10 @@ mod ffi { #[rust_name = "clip_path"] fn clipPath(self: &QPainter) -> QPainterPath; + /// Returns the currently set clip region. Note that the clip region is given in logical coordinates. + #[rust_name = "clip_region"] + fn clipRegion(self: &QPainter) -> QRegion; + /// Returns the current composition mode. #[rust_name = "composition_mode"] fn compositionMode(self: &QPainter) -> QPainterCompositionMode; @@ -326,6 +332,12 @@ mod ffi { #[rust_name = "set_clip_rect"] fn setClipRect(self: Pin<&mut QPainter>, rectangle: &QRect, operation: ClipOperation); + /// Sets the clip region to the given region using the specified clip operation. The default + /// clip operation is to replace the current clip region. + /// Note that the clip region is given in logical coordinates. + #[rust_name = "set_clip_region"] + fn setClipRegion(self: Pin<&mut QPainter>, region: &QRegion, operation: ClipOperation); + /// Sets the composition mode to the given mode. #[rust_name = "set_composition_mode"] fn setCompositionMode(self: Pin<&mut QPainter>, mode: QPainterCompositionMode); diff --git a/crates/cxx-qt-lib/src/gui/qpainterpath.rs b/crates/cxx-qt-lib/src/gui/qpainterpath.rs index e9a6c621b..2e52f9b9d 100644 --- a/crates/cxx-qt-lib/src/gui/qpainterpath.rs +++ b/crates/cxx-qt-lib/src/gui/qpainterpath.rs @@ -29,6 +29,8 @@ mod ffi { type QString = crate::QString; include!("cxx-qt-lib/qpolygonf.h"); type QPolygonF = crate::QPolygonF; + include!("cxx-qt-lib/qregion.h"); + type QRegion = crate::QRegion; /// Creates an ellipse within the specified boundingRectangle and adds it to the painter /// path as a closed subpath. @@ -47,6 +49,9 @@ mod ffi { #[rust_name = "add_rect"] fn addRect(self: &mut QPainterPath, rectangle: &QRectF); + #[rust_name = "add_region"] + fn addRegion(self: &mut QPainterPath, region: &QRegion); + /// Adds the given rectangle rect with rounded corners to the path. #[rust_name = "add_rounded_rect"] fn addRoundedRect( diff --git a/crates/cxx-qt-lib/src/gui/qregion.cpp b/crates/cxx-qt-lib/src/gui/qregion.cpp new file mode 100644 index 000000000..fcdfcc82e --- /dev/null +++ b/crates/cxx-qt-lib/src/gui/qregion.cpp @@ -0,0 +1,23 @@ +// clang-format off +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Laurent Montel +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +#include "cxx-qt-lib/qregion.h" + +#include "../assertion_utils.h" + +// https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/painting/qregion.h?h=v5.15.6-lts-lgpl#n178 +// https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/painting/qregion.h?h=v6.2.4#n161 +assert_alignment_and_size(QRegion, + alignof(::std::size_t), + sizeof(::std::size_t)); + +static_assert(!::std::is_trivially_copy_assignable::value); +static_assert(!::std::is_trivially_copy_constructible::value); + +static_assert(!::std::is_trivially_destructible::value); + +static_assert(QTypeInfo::isRelocatable); diff --git a/crates/cxx-qt-lib/src/gui/qregion.rs b/crates/cxx-qt-lib/src/gui/qregion.rs new file mode 100644 index 000000000..baad2b256 --- /dev/null +++ b/crates/cxx-qt-lib/src/gui/qregion.rs @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Laurent Montel +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +use cxx::{type_id, ExternType}; +use std::mem::MaybeUninit; + +#[cxx::bridge] +mod ffi { + unsafe extern "C++" { + include!("cxx-qt-lib/qregion.h"); + type QRegion = super::QRegion; + + include!("cxx-qt-lib/qrect.h"); + type QRect = crate::QRect; + + include!("cxx-qt-lib/qpoint.h"); + type QPoint = crate::QPoint; + + /// Returns the bounding rectangle of this region. An empty region gives a rectangle that is QRect::isNul + #[rust_name = "bounding_rect"] + fn boundingRect(self: &QRegion) -> QRect; + + /// Returns true if the region overlaps the rectangle r; otherwise returns false. + fn contains(self: &QRegion, r: &QRect) -> bool; + + /// Returns a region which is the intersection of this region and r. + fn intersected(self: &QRegion, r: &QRegion) -> QRegion; + + /// Returns true if the region is empty; otherwise returns false. An empty region is a region that contains no points. + #[rust_name = "is_empty"] + fn isEmpty(self: &QRegion) -> bool; + + /// Returns true if the region is empty; otherwise returns false. An empty region is a region that contains no points. + /// This function is the same as isEmpty + #[rust_name = "is_null"] + fn isNull(self: &QRegion) -> bool; + + /// Returns the number of rectangles that this region is composed of. + #[rust_name = "rect_count"] + fn rectCount(self: &QRegion) -> i32; + + /// Returns a region which is r subtracted from this region. + fn subtracted(self: &QRegion, r: &QRegion) -> QRegion; + + /// Translates the region point.x() along the x axis and point.y() along the y axis, relative to the current position. + /// Positive values move the region to the right and down. + /// Translates to the given point. + fn translate(self: &mut QRegion, point: &QPoint); + + /// Returns a copy of the region that is translated p.x() along the x axis and p.y() along the y axis, + /// relative to the current position. Positive values move the rectangle to the right and down. + fn translated(self: &QRegion, p: &QPoint) -> QRegion; + + /// Returns a region which is the union of this region and r. + fn united(self: &QRegion, r: &QRegion) -> QRegion; + + /// Returns a region which is the exclusive or (XOR) of this region and r. + fn xored(self: &QRegion, r: &QRegion) -> QRegion; + } + + #[namespace = "rust::cxxqtlib1"] + unsafe extern "C++" { + include!("cxx-qt-lib/common.h"); + + #[doc(hidden)] + #[rust_name = "qregion_init_default"] + fn construct() -> QRegion; + + #[doc(hidden)] + #[rust_name = "qregion_drop"] + fn drop(r: &mut QRegion); + + #[doc(hidden)] + #[rust_name = "qregion_clone"] + fn construct(r: &QRegion) -> QRegion; + } +} + +#[repr(C)] +pub struct QRegion { + _cspec: MaybeUninit, +} + +impl Default for QRegion { + /// Constructs an empty region. + fn default() -> Self { + ffi::qregion_init_default() + } +} + +impl Drop for QRegion { + fn drop(&mut self) { + ffi::qregion_drop(self); + } +} + +impl Clone for QRegion { + fn clone(&self) -> Self { + ffi::qregion_clone(self) + } +} + +// Safety: +// +// Static checks on the C++ side to ensure the size is the same. +unsafe impl ExternType for QRegion { + type Id = type_id!("QRegion"); + type Kind = cxx::kind::Trivial; +} diff --git a/tests/qt_types_standalone/CMakeLists.txt b/tests/qt_types_standalone/CMakeLists.txt index bd2e1cd07..91e4de090 100644 --- a/tests/qt_types_standalone/CMakeLists.txt +++ b/tests/qt_types_standalone/CMakeLists.txt @@ -71,6 +71,7 @@ add_executable(${APP_NAME} cpp/qqmlengine.h cpp/qrect.h cpp/qrectf.h + cpp/qregion.h cpp/qset.h cpp/qsize.h cpp/qsizef.h diff --git a/tests/qt_types_standalone/cpp/main.cpp b/tests/qt_types_standalone/cpp/main.cpp index beae4764d..5e9920d78 100644 --- a/tests/qt_types_standalone/cpp/main.cpp +++ b/tests/qt_types_standalone/cpp/main.cpp @@ -30,6 +30,7 @@ #include "qqmlengine.h" #include "qrect.h" #include "qrectf.h" +#include "qregion.h" #include "qset.h" #include "qsize.h" #include "qsizef.h" @@ -92,6 +93,7 @@ main(int argc, char* argv[]) runTest(QScopedPointer(new QVector3DTest)); runTest(QScopedPointer(new QVector4DTest)); runTest(QScopedPointer(new QPolygonTest)); + runTest(QScopedPointer(new QRegionTest)); return status; } diff --git a/tests/qt_types_standalone/cpp/qregion.h b/tests/qt_types_standalone/cpp/qregion.h new file mode 100644 index 000000000..3d02acb37 --- /dev/null +++ b/tests/qt_types_standalone/cpp/qregion.h @@ -0,0 +1,31 @@ +// clang-format off +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Laurent Montel +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +#pragma once + +#include +#include + +#include "cxx-qt-gen/qregion.cxx.h" + +class QRegionTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void construct() + { + const auto p = construct_qregion(); + QVERIFY(p.isEmpty()); + } + + void clone() + { + const auto p = QRegion(2, 4, 5, 3); + const auto c = clone_qregion(p); + QCOMPARE(p, c); + } +}; diff --git a/tests/qt_types_standalone/rust/build.rs b/tests/qt_types_standalone/rust/build.rs index ae458ce59..970c2c1c0 100644 --- a/tests/qt_types_standalone/rust/build.rs +++ b/tests/qt_types_standalone/rust/build.rs @@ -30,6 +30,7 @@ fn main() { .file("src/qqmlengine.rs") .file("src/qrect.rs") .file("src/qrectf.rs") + .file("src/qregion.rs") .file("src/qset.rs") .file("src/qsize.rs") .file("src/qsizef.rs") diff --git a/tests/qt_types_standalone/rust/src/lib.rs b/tests/qt_types_standalone/rust/src/lib.rs index d81d4ccb3..916185cd8 100644 --- a/tests/qt_types_standalone/rust/src/lib.rs +++ b/tests/qt_types_standalone/rust/src/lib.rs @@ -27,6 +27,7 @@ mod qqmlapplicationengine; mod qqmlengine; mod qrect; mod qrectf; +mod qregion; mod qset; mod qsize; mod qsizef; diff --git a/tests/qt_types_standalone/rust/src/qregion.rs b/tests/qt_types_standalone/rust/src/qregion.rs new file mode 100644 index 000000000..513cc22c3 --- /dev/null +++ b/tests/qt_types_standalone/rust/src/qregion.rs @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Laurent Montel +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use cxx_qt_lib::QRegion; + +#[cxx::bridge] +mod qregion_cxx { + unsafe extern "C++" { + include!("cxx-qt-lib/qregion.h"); + + type QRegion = cxx_qt_lib::QRegion; + } + + extern "Rust" { + fn construct_qregion() -> QRegion; + fn clone_qregion(p: &QRegion) -> QRegion; + } +} + +fn construct_qregion() -> QRegion { + QRegion::default() +} + +fn clone_qregion(p: &QRegion) -> QRegion { + p.clone() +}