diff --git a/CHANGELOG.md b/CHANGELOG.md index a03526840..cd8ca7e83 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`, `QBrush` - `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/qbrush.h b/crates/cxx-qt-lib-headers/include/gui/qbrush.h new file mode 100644 index 000000000..951dabab4 --- /dev/null +++ b/crates/cxx-qt-lib-headers/include/gui/qbrush.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..8f471f195 100644 --- a/crates/cxx-qt-lib-headers/src/lib.rs +++ b/crates/cxx-qt-lib-headers/src/lib.rs @@ -42,6 +42,7 @@ pub fn build_opts() -> cxx_qt_build::CxxQtBuildersOpts { "qmodelindex.h", ), #[cfg(feature = "qt_gui")] + (include_str!("../include/gui/qbrush.h"), "qbrush.h"), (include_str!("../include/gui/qpen.h"), "qpen.h"), ( include_str!("../include/core/qpersistentmodelindex.h"), diff --git a/crates/cxx-qt-lib/build.rs b/crates/cxx-qt-lib/build.rs index de6bbb0c5..c437ae8fe 100644 --- a/crates/cxx-qt-lib/build.rs +++ b/crates/cxx-qt-lib/build.rs @@ -139,6 +139,7 @@ fn main() { "core/qlist/qlist_qcolor", "core/qvariant/qvariant_qcolor", "core/qvector/qvector_qcolor", + "gui/qbrush", "gui/qcolor", "gui/qfont", "gui/qguiapplication", @@ -199,6 +200,7 @@ fn main() { if feature_qt_gui_enabled { cpp_files.extend([ + "gui/qbrush", "gui/qcolor", "gui/qfont", "gui/qguiapplication", diff --git a/crates/cxx-qt-lib/src/core/mod.rs b/crates/cxx-qt-lib/src/core/mod.rs index 7f8d82a7e..1614f00cb 100644 --- a/crates/cxx-qt-lib/src/core/mod.rs +++ b/crates/cxx-qt-lib/src/core/mod.rs @@ -70,9 +70,9 @@ pub use qstringlist::QStringList; mod qt; pub use qt::{ - AspectRatioMode, BGMode, CaseSensitivity, ClipOperation, ConnectionType, DateFormat, FillRule, - LayoutDirection, PenCapStyle, PenJoinStyle, PenStyle, SizeMode, SplitBehaviorFlags, TimeSpec, - TransformationMode, + AspectRatioMode, BGMode, BrushStyle, CaseSensitivity, ClipOperation, ConnectionType, + DateFormat, FillRule, LayoutDirection, PenCapStyle, PenJoinStyle, PenStyle, SizeMode, + SplitBehaviorFlags, TimeSpec, TransformationMode, }; mod qtime; diff --git a/crates/cxx-qt-lib/src/core/qt.rs b/crates/cxx-qt-lib/src/core/qt.rs index 3f8398b8e..98b43bfe0 100644 --- a/crates/cxx-qt-lib/src/core/qt.rs +++ b/crates/cxx-qt-lib/src/core/qt.rs @@ -134,6 +134,50 @@ mod ffi { IntersectClip, } + /// This enum type defines the brush styles supported by Qt, i.e. + /// the fill pattern of shapes drawn using QPainter. + #[repr(i32)] + enum BrushStyle { + /// No brush pattern. + NoBrush, + /// Uniform color. + SolidPattern, + /// Extremely dense brush pattern. + Dense1Pattern, + /// Very dense brush pattern. + Dense2Pattern, + /// Somewhat dense brush pattern. + Dense3Pattern, + /// Half dense brush pattern. + Dense4Pattern, + /// Somewhat sparse brush pattern. + Dense5Pattern, + /// Very sparse brush pattern. + Dense6Pattern, + /// Extremely sparse brush pattern. + Dense7Pattern, + /// Horizontal lines. + HorPattern, + /// Vertical lines. + VerPattern, + /// Crossing horizontal and vertical lines. + CrossPattern, + /// Backward diagonal lines. + BDiagPattern, + /// Forward diagonal lines. + FDiagPattern, + /// Crossing diagonal lines. + DiagCrossPattern, + /// Linear gradient (set using a dedicated QBrush constructor). + LinearGradientPattern, + /// Conical gradient (set using a dedicated QBrush constructor). + RadialGradientPattern, + /// Radial gradient (set using a dedicated QBrush constructor). + ConicalGradientPattern, + /// Custom pattern (see QBrush::setTexture()). + TexturePattern = 24, + } + /// This enum is used by QPainter::drawRoundedRect() and QPainterPath::addRoundedRect() /// functions to specify the radii of rectangle corners with respect to the dimensions /// of the bounding rectangles specified. @@ -160,13 +204,14 @@ mod ffi { type LayoutDirection; type BGMode; type ClipOperation; + type BrushStyle; type SizeMode; } } pub use ffi::{ - AspectRatioMode, BGMode, CaseSensitivity, ClipOperation, DateFormat, FillRule, LayoutDirection, - PenCapStyle, PenJoinStyle, PenStyle, SizeMode, SplitBehaviorFlags, TimeSpec, + AspectRatioMode, BGMode, BrushStyle, CaseSensitivity, ClipOperation, DateFormat, FillRule, + LayoutDirection, PenCapStyle, PenJoinStyle, PenStyle, SizeMode, SplitBehaviorFlags, TimeSpec, TransformationMode, }; diff --git a/crates/cxx-qt-lib/src/gui/mod.rs b/crates/cxx-qt-lib/src/gui/mod.rs index bf5c18937..6e5d03101 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 qbrush; +pub use qbrush::QBrush; diff --git a/crates/cxx-qt-lib/src/gui/qbrush.cpp b/crates/cxx-qt-lib/src/gui/qbrush.cpp new file mode 100644 index 000000000..6f9716ad7 --- /dev/null +++ b/crates/cxx-qt-lib/src/gui/qbrush.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/qbrush.h" + +#include "../assertion_utils.h" + +// https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/painting/qbrush.h?h=v5.15.6-lts-lgpl#n130 +// https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/painting/qbrush.h?h=v6.2.4#n123 +assert_alignment_and_size(QBrush, + 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/qbrush.rs b/crates/cxx-qt-lib/src/gui/qbrush.rs new file mode 100644 index 000000000..1ed2b7c79 --- /dev/null +++ b/crates/cxx-qt-lib/src/gui/qbrush.rs @@ -0,0 +1,130 @@ +// 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 { + #[namespace = "Qt"] + unsafe extern "C++" { + include!("cxx-qt-lib/qt.h"); + type BrushStyle = crate::BrushStyle; + } + + unsafe extern "C++" { + include!("cxx-qt-lib/qbrush.h"); + type QBrush = super::QBrush; + include!("cxx-qt-lib/qcolor.h"); + type QColor = crate::QColor; + include!("cxx-qt-lib/qimage.h"); + type QImage = crate::QImage; + + /// Returns true if the brush is fully opaque otherwise false + #[rust_name = "is_opaque"] + fn isOpaque(self: &QBrush) -> bool; + + /// Returns the brush color. + fn color(self: &QBrush) -> &QColor; + + /// Sets the brush style to style. + #[rust_name = "set_style"] + fn setStyle(self: &mut QBrush, style: BrushStyle); + + /// Sets the brush color to the given color. + #[rust_name = "set_color"] + fn setColor(self: &mut QBrush, color: &QColor); + + /// Sets the brush image to image. The style is set to Qt::TexturePattern. + #[rust_name = "set_texture_image"] + fn setTextureImage(self: &mut QBrush, image: &QImage); + + /// Returns the brush style. + fn style(self: &QBrush) -> BrushStyle; + + /// Returns the custom brush pattern, or a null image if no custom brush pattern has been set. + #[rust_name = "texture_image"] + fn textureImage(self: &QBrush) -> QImage; + } + + #[namespace = "rust::cxxqtlib1"] + unsafe extern "C++" { + include!("cxx-qt-lib/common.h"); + + #[doc(hidden)] + #[rust_name = "qbrush_init_default"] + fn construct() -> QBrush; + + #[doc(hidden)] + #[rust_name = "qcolor_init_from_qimage"] + fn construct(image: &QImage) -> QBrush; + + #[doc(hidden)] + #[rust_name = "qcolor_init_from_brush_style"] + fn construct(brushstyle: &BrushStyle) -> QBrush; + + #[rust_name = "qbrush_drop"] + fn drop(brush: &mut QBrush); + + #[doc(hidden)] + #[rust_name = "qbrush_clone"] + fn construct(brush: &QBrush) -> QBrush; + + #[doc(hidden)] + #[rust_name = "qbrush_eq"] + fn operatorEq(a: &QBrush, b: &QBrush) -> bool; + } +} + +#[repr(C)] +pub struct QBrush { + _cspec: MaybeUninit, +} + +impl Default for QBrush { + /// Constructs a default black brush with the style Qt::NoBrush (i.e. this brush will not fill shapes). + fn default() -> Self { + ffi::qbrush_init_default() + } +} + +impl Drop for QBrush { + fn drop(&mut self) { + ffi::qbrush_drop(self); + } +} + +impl Clone for QBrush { + fn clone(&self) -> Self { + ffi::qbrush_clone(self) + } +} + +impl PartialEq for QBrush { + fn eq(&self, other: &Self) -> bool { + ffi::qbrush_eq(self, other) + } +} + +impl Eq for QBrush {} + +impl From<&ffi::QImage> for QBrush { + fn from(image: &ffi::QImage) -> Self { + ffi::qcolor_init_from_qimage(image) + } +} + +impl From<&ffi::BrushStyle> for QBrush { + fn from(brushstyle: &ffi::BrushStyle) -> Self { + ffi::qcolor_init_from_brush_style(brushstyle) + } +} + +// Safety: +// +// Static checks on the C++ side to ensure the size is the same. +unsafe impl ExternType for QBrush { + type Id = type_id!("QBrush"); + type Kind = cxx::kind::Trivial; +} diff --git a/crates/cxx-qt-lib/src/gui/qpainter.rs b/crates/cxx-qt-lib/src/gui/qpainter.rs index 3e69417a6..7e6d7ab8f 100644 --- a/crates/cxx-qt-lib/src/gui/qpainter.rs +++ b/crates/cxx-qt-lib/src/gui/qpainter.rs @@ -173,11 +173,19 @@ mod ffi { type QPen = crate::QPen; include!("cxx-qt-lib/qpolygon.h"); type QPolygon = crate::QPolygon; + include!("cxx-qt-lib/qbrush.h"); + type QBrush = crate::QBrush; + + /// Returns the current background brush. + fn background(self: &QPainter) -> &QBrush; /// Returns the current background mode. #[rust_name = "background_mode"] fn backgroundMode(self: &QPainter) -> BGMode; + /// Returns the painter's current brush. + fn brush(self: &QPainter) -> &QBrush; + /// Returns the currently set brush origin. #[rust_name = "brush_origin"] fn brushOrigin(self: &QPainter) -> QPoint; @@ -279,6 +287,10 @@ mod ffi { #[rust_name = "erase_rect"] fn eraseRect(self: Pin<&mut QPainter>, rectangle: &QRectF); + /// Fills the given path using the given brush. The outline is not drawn. + #[rust_name = "fill_path"] + fn fillPath(self: Pin<&mut QPainter>, path: &QPainterPath, brush: &QBrush); + /// Fills the given rectangle with the color specified. #[rust_name = "fill_rect"] fn fillRect(self: Pin<&mut QPainter>, rectangle: &QRectF, color: &QColor); @@ -308,10 +320,18 @@ mod ffi { /// A save() must be followed by a corresponding restore(); the end() function unwinds the stack. fn save(self: Pin<&mut QPainter>); + /// Sets the background brush of the painter to the given brush. + #[rust_name = "set_background"] + fn setBackground(self: Pin<&mut QPainter>, brush: &QBrush); + /// Sets the background mode of the painter to the given mode #[rust_name = "set_background_mode"] fn setBackgroundMode(self: Pin<&mut QPainter>, mode: BGMode); + /// Sets the painter's brush to the given brush. + #[rust_name = "set_brush"] + fn setBrush(self: Pin<&mut QPainter>, brush: &QBrush); + /// Enables clipping if enable is true, or disables clipping if enable is false. #[rust_name = "set_clipping"] fn setClipping(self: Pin<&mut QPainter>, enable: bool); diff --git a/crates/cxx-qt-lib/src/gui/qpen.rs b/crates/cxx-qt-lib/src/gui/qpen.rs index 131707d8e..9e40688b4 100644 --- a/crates/cxx-qt-lib/src/gui/qpen.rs +++ b/crates/cxx-qt-lib/src/gui/qpen.rs @@ -21,9 +21,14 @@ mod ffi { type QPen = super::QPen; include!("cxx-qt-lib/qcolor.h"); type QColor = crate::QColor; + include!("cxx-qt-lib/qbrush.h"); + type QBrush = crate::QBrush; include!("cxx-qt-lib/qstring.h"); type QString = crate::QString; + /// Returns the brush used to fill strokes generated with this pen. + fn brush(self: &QPen) -> QBrush; + /// Returns the pen's cap style. #[rust_name = "cap_style"] fn capStyle(self: &QPen) -> PenCapStyle; @@ -52,6 +57,10 @@ mod ffi { #[rust_name = "miter_limit"] fn miterLimit(self: &QPen) -> f64; + /// Sets the brush used to fill strokes generated with this pen to the given brush. + #[rust_name = "set_brush"] + fn setBrush(self: &mut QPen, brush: &QBrush); + /// Sets the pen's cap style to the given style. The default value is Qt::SquareCap. #[rust_name = "set_cap_style"] fn setCapStyle(self: &mut QPen, style: PenCapStyle); diff --git a/tests/qt_types_standalone/CMakeLists.txt b/tests/qt_types_standalone/CMakeLists.txt index bd2e1cd07..dfe99e8e0 100644 --- a/tests/qt_types_standalone/CMakeLists.txt +++ b/tests/qt_types_standalone/CMakeLists.txt @@ -49,6 +49,7 @@ target_link_libraries(${CRATE} INTERFACE add_executable(${APP_NAME} cpp/main.cpp cpp/qbytearray.h + cpp/qbrush.h cpp/qcolor.h cpp/qcoreapplication.h cpp/qdate.h diff --git a/tests/qt_types_standalone/cpp/main.cpp b/tests/qt_types_standalone/cpp/main.cpp index beae4764d..960dca508 100644 --- a/tests/qt_types_standalone/cpp/main.cpp +++ b/tests/qt_types_standalone/cpp/main.cpp @@ -7,6 +7,7 @@ #include #include +#include "qbrush.h" #include "qbytearray.h" #include "qcolor.h" #include "qcoreapplication.h" @@ -57,6 +58,7 @@ main(int argc, char* argv[]) }; runTest(QScopedPointer(new QByteArrayTest)); + runTest(QScopedPointer(new QBrushTest)); runTest(QScopedPointer(new QColorTest)); runTest(QScopedPointer(new QCoreApplicationTest)); runTest(QScopedPointer(new QDateTest)); diff --git a/tests/qt_types_standalone/cpp/qbrush.h b/tests/qt_types_standalone/cpp/qbrush.h new file mode 100644 index 000000000..3a7109843 --- /dev/null +++ b/tests/qt_types_standalone/cpp/qbrush.h @@ -0,0 +1,31 @@ +// clang-format off +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// clang-format on +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 +#pragma once + +#include +#include + +#include "cxx-qt-gen/qbrush.cxx.h" + +class QBrushTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void construct() + { + const auto p = construct_qbrush(); + QCOMPARE(p.color(), QColor(Qt::red)); + } + + void clone() + { + const auto p = construct_qbrush(); + const auto c = clone_qbrush(p); + QCOMPARE(c.color(), QColor(Qt::red)); + } +}; diff --git a/tests/qt_types_standalone/rust/build.rs b/tests/qt_types_standalone/rust/build.rs index ae458ce59..c50e39a8f 100644 --- a/tests/qt_types_standalone/rust/build.rs +++ b/tests/qt_types_standalone/rust/build.rs @@ -7,6 +7,7 @@ use cxx_qt_build::CxxQtBuilder; fn main() { CxxQtBuilder::new() + .file("src/qbrush.rs") .file("src/qbytearray.rs") .file("src/qcolor.rs") .file("src/qcoreapplication.rs") diff --git a/tests/qt_types_standalone/rust/src/lib.rs b/tests/qt_types_standalone/rust/src/lib.rs index d81d4ccb3..e15cd38b6 100644 --- a/tests/qt_types_standalone/rust/src/lib.rs +++ b/tests/qt_types_standalone/rust/src/lib.rs @@ -1,9 +1,11 @@ // SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company // SPDX-FileContributor: Andrew Hayzen // SPDX-FileContributor: Gerhard de Clercq +// SPDX-FileContributor: Laurent Montel // // SPDX-License-Identifier: MIT OR Apache-2.0 +mod qbrush; mod qbytearray; mod qcolor; mod qcoreapplication; diff --git a/tests/qt_types_standalone/rust/src/qbrush.rs b/tests/qt_types_standalone/rust/src/qbrush.rs new file mode 100644 index 000000000..36b88fc44 --- /dev/null +++ b/tests/qt_types_standalone/rust/src/qbrush.rs @@ -0,0 +1,30 @@ +// 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::QBrush; +use cxx_qt_lib::QColor; + +#[cxx::bridge] +mod qpoint_cxx { + unsafe extern "C++" { + include!("cxx-qt-lib/qbrush.h"); + type QBrush = cxx_qt_lib::QBrush; + } + + extern "Rust" { + fn construct_qbrush() -> QBrush; + fn clone_qbrush(p: &QBrush) -> QBrush; + } +} + +fn construct_qbrush() -> QBrush { + let mut brush = QBrush::default(); + brush.set_color(&QColor::from_rgb(255, 0, 0)); + brush +} + +fn clone_qbrush(p: &QBrush) -> QBrush { + p.clone() +}