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

Add QBrush support #862

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions crates/cxx-qt-lib-headers/include/gui/qbrush.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// clang-format off
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Laurent Montel <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <QtGui/QBrush>

#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<QBrush> : ::std::true_type
{
};

} // namespace rust
1 change: 1 addition & 0 deletions crates/cxx-qt-lib-headers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
2 changes: 2 additions & 0 deletions crates/cxx-qt-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ fn main() {
"core/qlist/qlist_qcolor",
"core/qvariant/qvariant_qcolor",
"core/qvector/qvector_qcolor",
"gui/qbrush",
"gui/qcolor",
"gui/qfont",
"gui/qguiapplication",
Expand Down Expand Up @@ -218,6 +219,7 @@ fn main() {

if feature_qt_gui_enabled {
cpp_files.extend([
"gui/qbrush",
"gui/qcolor",
"gui/qfont",
"gui/qguiapplication",
Expand Down
6 changes: 3 additions & 3 deletions crates/cxx-qt-lib/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
49 changes: 47 additions & 2 deletions crates/cxx-qt-lib/src/core/qt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Montel marked this conversation as resolved.
Show resolved Hide resolved
/// 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.
Expand All @@ -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,
};

Expand Down
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib/src/gui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ pub use qpainterpath::QPainterPath;

mod qpainter;
pub use qpainter::QPainter;

mod qbrush;
pub use qbrush::QBrush;
23 changes: 23 additions & 0 deletions crates/cxx-qt-lib/src/gui/qbrush.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// clang-format off
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Laurent Montel <[email protected]>
//
// 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<QBrush>::value);
static_assert(!::std::is_trivially_copy_constructible<QBrush>::value);

static_assert(!::std::is_trivially_destructible<QBrush>::value);

static_assert(QTypeInfo<QBrush>::isRelocatable);
130 changes: 130 additions & 0 deletions crates/cxx-qt-lib/src/gui/qbrush.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Laurent Montel <[email protected]>
//
// 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 {
Montel marked this conversation as resolved.
Show resolved Hide resolved
_cspec: MaybeUninit<usize>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valgrind isn't happy about something, maybe something is still incorrect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep :) I try to make it working on local here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea where is the problem...
we have "'using DataPtr = std::unique_ptr<QBrushData, QBrushDataPointerDeleter>;"

which is a _cspec: MaybeUninit,

but valgrind found a memory leak...

}

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;
}
20 changes: 20 additions & 0 deletions crates/cxx-qt-lib/src/gui/qpainter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,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;
Expand Down Expand Up @@ -142,6 +150,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);
Expand Down Expand Up @@ -171,10 +183,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);
Expand Down
9 changes: 9 additions & 0 deletions crates/cxx-qt-lib/src/gui/qpen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ 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;

/// 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"]
Expand Down Expand Up @@ -49,6 +54,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);
Expand Down
1 change: 1 addition & 0 deletions tests/qt_types_standalone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/qt_types_standalone/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <QtCore/QScopedPointer>
#include <QtTest/QTest>

#include "qbrush.h"
#include "qbytearray.h"
#include "qcolor.h"
#include "qcoreapplication.h"
Expand Down Expand Up @@ -56,6 +57,7 @@ main(int argc, char* argv[])
};

runTest(QScopedPointer<QObject>(new QByteArrayTest));
runTest(QScopedPointer<QObject>(new QBrushTest));
runTest(QScopedPointer<QObject>(new QColorTest));
runTest(QScopedPointer<QObject>(new QCoreApplicationTest));
runTest(QScopedPointer<QObject>(new QDateTest));
Expand Down
Loading
Loading