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

Issue #602: Have Background images use CalChart::Draw #603

Merged
merged 1 commit into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions LATEST_RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ Bugs addressed in this release:
Other changes:

* [#590](../../issues/590) Move things related to drawing a sheet to sheet so it can generate Draw commands
* [#602](../../issues/602) Have Background images use CalChart::Draw

124 changes: 70 additions & 54 deletions src/BackgroundImages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@

#include "BackgroundImages.h"
#include "CalChartDrawPrimativesHelper.h"
#include "CalChartDrawing.h"
#include "CalChartImage.h"
#include "CalChartRanges.h"
#include "CalChartTypes.h"
#include "CalChartUtils.h"
#include <algorithm>

class BackgroundImage {
Expand Down Expand Up @@ -57,12 +60,11 @@ class BackgroundImage {
kRight,
kLowerLeft,
kLower,
kLowerRight,
kLast
kLowerRight
};
using BackgroundAdjustTypeIterator = CalChart::Iterator<BackgroundAdjustType, BackgroundAdjustType::kUpperLeft, BackgroundAdjustType::kLowerRight>;
BackgroundAdjustType mBackgroundAdjustType;
[[nodiscard]] auto WhereIsMouseClick(const wxMouseEvent& event, const wxDC& dc) const -> BackgroundAdjustType;
std::optional<BackgroundAdjustType> mBackgroundAdjustType = std::nullopt;
[[nodiscard]] auto WhereIsMouseClick(const wxMouseEvent& event, const wxDC& dc) const -> std::optional<BackgroundAdjustType>;

static auto toOffsetX(BackgroundAdjustType where)
{
Expand Down Expand Up @@ -113,11 +115,10 @@ BackgroundImage::BackgroundImage(CalChart::ImageInfo const& image)
, mScaledSize{ image.scaledWidth, image.scaledHeight }
, mRawImage{ wxCalChart::towxImage(image.data) }
, mBitmap{ mRawImage.Scale(mScaledSize.x, mScaledSize.y, wxIMAGE_QUALITY_HIGH) }
, mBackgroundAdjustType(BackgroundAdjustType::kLast) // always adjust when we get created
{
}

BackgroundImage::BackgroundAdjustType BackgroundImage::WhereIsMouseClick(const wxMouseEvent& event, const wxDC& dc) const
auto BackgroundImage::WhereIsMouseClick(const wxMouseEvent& event, const wxDC& dc) const -> std::optional<BackgroundAdjustType>
{
auto point = event.GetPosition();
auto x = dc.DeviceToLogicalX(point.x);
Expand All @@ -143,12 +144,12 @@ BackgroundImage::BackgroundAdjustType BackgroundImage::WhereIsMouseClick(const w
return where;
}
}
return BackgroundAdjustType::kLast;
return std::nullopt;
}

bool BackgroundImage::MouseClickIsHit(const wxMouseEvent& event, const wxDC& dc) const
auto BackgroundImage::MouseClickIsHit(const wxMouseEvent& event, const wxDC& dc) const -> bool
{
return WhereIsMouseClick(event, dc) != BackgroundAdjustType::kLast;
return WhereIsMouseClick(event, dc).has_value();
}

void BackgroundImage::OnMouseLeftDown(wxMouseEvent const& event, wxDC const& dc)
Expand All @@ -158,11 +159,11 @@ void BackgroundImage::OnMouseLeftDown(wxMouseEvent const& event, wxDC const& dc)
auto y = dc.DeviceToLogicalY(point.y);

auto where = WhereIsMouseClick(event, dc);
if (where == BackgroundAdjustType::kLast) {
if (!where.has_value()) {
return;
}
mBackgroundAdjustType = where;
mScaleAndMove = { wxPoint{ x, y }, wxRect{ wxCalChart::toPoint(mPosition), wxCalChart::toSize(mScaledSize) }, mBackgroundAdjustType };
mScaleAndMove = { wxPoint{ x, y }, wxRect{ wxCalChart::toPoint(mPosition), wxCalChart::toSize(mScaledSize) }, *mBackgroundAdjustType };
}

std::array<int, 4> BackgroundImage::OnMouseLeftUp(const wxMouseEvent&, const wxDC&)
Expand All @@ -174,7 +175,7 @@ std::array<int, 4> BackgroundImage::OnMouseLeftUp(const wxMouseEvent&, const wxD
auto [x, y] = wxCalChart::toPoint(mPosition);
std::array<int, 4> data{ { x, y, width, height } };
mScaleAndMove.reset();
mBackgroundAdjustType = BackgroundAdjustType::kLast;
mBackgroundAdjustType = std::nullopt;
return data;
}
return { { 0, 0, 0, 0 } };
Expand All @@ -196,37 +197,48 @@ void BackgroundImage::OnMouseMove(const wxMouseEvent& event, const wxDC& dc)

void BackgroundImage::OnPaint(wxDC& dc, bool drawPicAdjustDots, bool selected) const
{
auto pos = wxCalChart::toPoint(mPosition);
dc.DrawBitmap(mBitmap, pos.x, pos.y, true);
auto drawCmds = std::vector<CalChart::Draw::DrawCommand>{
CalChart::Draw::Image{ mPosition, std::make_shared<wxCalChart::BitmapHolder>(mBitmap) },
};

if (drawPicAdjustDots) {
// draw guide dots
auto bitmapSize = wxCalChart::toSize(mScaledSize);
auto middle = wxCalChart::toPoint(mPosition) + bitmapSize / 2;
dc.SetBrush(*wxBLUE_BRUSH);
dc.SetPen(*wxBLUE_PEN);
for (auto where : BackgroundAdjustTypeIterator()) {
dc.SetBrush(*wxBLUE_BRUSH);
if (where == BackgroundAdjustType::kMove) {
continue;
}
auto offsetX = toOffsetX(where);
auto offsetY = toOffsetY(where);
if (mBackgroundAdjustType == where) {
dc.SetBrush(*wxRED_BRUSH);
}
dc.DrawCircle(
middle.x + (offsetX * (bitmapSize.x / 2 + dc.DeviceToLogicalXRel(kCircleSize / 3))),
middle.y + (offsetY * (bitmapSize.y / 2 + dc.DeviceToLogicalYRel(kCircleSize / 3))),
dc.DeviceToLogicalXRel(kCircleSize));
if (selected && mBackgroundAdjustType != where) {
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawCircle(
middle.x + (offsetX * (bitmapSize.x / 2 + dc.DeviceToLogicalXRel(kCircleSize / 3))),
middle.y + (offsetY * (bitmapSize.y / 2 + dc.DeviceToLogicalYRel(kCircleSize / 3))),
dc.DeviceToLogicalXRel(kCircleSize * 0.75));
}
auto brush = selected ? wxCalChart::toBrush(*wxWHITE_BRUSH) : wxCalChart::toBrush(*wxBLUE_BRUSH);
auto middle1 = mPosition + mScaledSize / 2;
CalChart::append(drawCmds,
CalChart::Draw::withBrush(
brush,
CalChart::Draw::withPen(
wxCalChart::toPen(*wxBLUE_PEN).withWidth(4),
CalChart::Ranges::ToVector<CalChart::Draw::DrawCommand>(
BackgroundAdjustTypeIterator()
| std::views::filter([](auto where) {
return where != BackgroundAdjustType::kMove;
})
| std::views::transform([this, middle1](auto where) {
auto offsetX = toOffsetX(where);
auto offsetY = toOffsetY(where);
return CalChart::Draw::Circle{
middle1.x + offsetX * (mScaledSize.x / 2),
middle1.y + offsetY * (mScaledSize.y / 2),
kCircleSize
};
})))));
if (mBackgroundAdjustType.has_value() && *mBackgroundAdjustType != BackgroundAdjustType::kMove) {
auto offsetX = toOffsetX(*mBackgroundAdjustType);
auto offsetY = toOffsetY(*mBackgroundAdjustType);
CalChart::append(drawCmds,
CalChart::Draw::withBrush(
wxCalChart::toBrush(*wxRED_BRUSH),
CalChart::Draw::withPen(
wxCalChart::toPen(*wxBLUE_PEN).withWidth(4),
CalChart::Draw::Circle{
middle1.x + offsetX * (mScaledSize.x / 2),
middle1.y + offsetY * (mScaledSize.y / 2),
kCircleSize })));
}
}
wxCalChart::Draw::DrawCommandList(dc,
drawCmds);
}

BackgroundImage::CalculateScaleAndMove::CalculateScaleAndMove(wxPoint startClick, wxRect rect, BackgroundAdjustType adjustType)
Expand Down Expand Up @@ -324,16 +336,16 @@ BackgroundImages::~BackgroundImages() = default;
void BackgroundImages::SetBackgroundImages(std::vector<CalChart::ImageInfo> const& images)
{
mBackgroundImages.clear();
mWhichBackgroundIndex = -1;
mWhichBackgroundIndex = std::nullopt;
for (auto&& image : images) {
mBackgroundImages.emplace_back(image);
}
}

void BackgroundImages::OnPaint(wxDC& dc) const
{
for (auto i = 0; i < static_cast<int>(mBackgroundImages.size()); ++i) {
mBackgroundImages[i].OnPaint(dc, mAdjustBackgroundMode, mWhichBackgroundIndex == i);
for (auto&& [i, backgroundImages] : CalChart::Ranges::enumerate_view(mBackgroundImages)) {
backgroundImages.OnPaint(dc, mAdjustBackgroundMode, mWhichBackgroundIndex.has_value() ? *mWhichBackgroundIndex == i : false);
}
}

Expand All @@ -342,14 +354,18 @@ void BackgroundImages::OnMouseLeftDown(wxMouseEvent const& event, wxDC const& dc
if (!mAdjustBackgroundMode) {
return;
}
mWhichBackgroundIndex = -1;
for (auto i = 0; i < static_cast<int>(mBackgroundImages.size()); ++i) {
if (mBackgroundImages[i].MouseClickIsHit(event, dc)) {
mWhichBackgroundIndex = i;
}
mWhichBackgroundIndex = std::nullopt;
if (auto iter = std::find_if(
mBackgroundImages.begin(),
mBackgroundImages.end(),
[&event, &dc](auto&& backgroundImage) {
return backgroundImage.MouseClickIsHit(event, dc);
});
iter != mBackgroundImages.end()) {
mWhichBackgroundIndex = std::distance(mBackgroundImages.begin(), iter);
}
if (mWhichBackgroundIndex != -1) {
mBackgroundImages[mWhichBackgroundIndex].OnMouseLeftDown(event, dc);
if (mWhichBackgroundIndex.has_value()) {
mBackgroundImages[*mWhichBackgroundIndex].OnMouseLeftDown(event, dc);
}
}

Expand All @@ -358,8 +374,8 @@ std::optional<std::tuple<int, std::array<int, 4>>> BackgroundImages::OnMouseLeft
if (!mAdjustBackgroundMode) {
return {};
}
if (mWhichBackgroundIndex >= 0 && mWhichBackgroundIndex < static_cast<int>(mBackgroundImages.size())) {
return { { mWhichBackgroundIndex, mBackgroundImages[mWhichBackgroundIndex].OnMouseLeftUp(event, dc) } };
if (mWhichBackgroundIndex.has_value()) {
return { { *mWhichBackgroundIndex, mBackgroundImages[*mWhichBackgroundIndex].OnMouseLeftUp(event, dc) } };
}
return {};
}
Expand All @@ -369,7 +385,7 @@ void BackgroundImages::OnMouseMove(wxMouseEvent const& event, wxDC const& dc)
if (!mAdjustBackgroundMode) {
return;
}
if (mWhichBackgroundIndex >= 0 && mWhichBackgroundIndex < static_cast<int>(mBackgroundImages.size())) {
mBackgroundImages[mWhichBackgroundIndex].OnMouseMove(event, dc);
if (mWhichBackgroundIndex.has_value()) {
mBackgroundImages[*mWhichBackgroundIndex].OnMouseMove(event, dc);
}
}
8 changes: 4 additions & 4 deletions src/BackgroundImages.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,19 @@ class BackgroundImages {

void SetBackgroundImages(std::vector<CalChart::ImageInfo> const& images);

auto GetAdjustBackgroundMode() const { return mAdjustBackgroundMode; }
[[nodiscard]] auto GetAdjustBackgroundMode() const { return mAdjustBackgroundMode; }
void SetAdjustBackgroundMode(bool adjustBackgroundMode) { mAdjustBackgroundMode = adjustBackgroundMode; }

std::optional<std::size_t> GetCurrentIndex() const { return mWhichBackgroundIndex == -1 ? std::optional<std::size_t>{} : mWhichBackgroundIndex; }
[[nodiscard]] auto GetCurrentIndex() const { return mWhichBackgroundIndex; }

void OnMouseLeftDown(wxMouseEvent const& event, wxDC const& dc);
std::optional<std::tuple<int, std::array<int, 4>>> OnMouseLeftUp(wxMouseEvent const& event, wxDC const& dc);
[[nodiscard]] auto OnMouseLeftUp(wxMouseEvent const& event, wxDC const& dc) -> std::optional<std::tuple<int, std::array<int, 4>>>;
void OnMouseMove(wxMouseEvent const& event, wxDC const& dc);

void OnPaint(wxDC& dc) const;

private:
std::vector<BackgroundImage> mBackgroundImages;
bool mAdjustBackgroundMode{};
int mWhichBackgroundIndex = -1;
std::optional<std::size_t> mWhichBackgroundIndex = std::nullopt;
};
8 changes: 6 additions & 2 deletions src/CalChartDrawPrimativesHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,12 @@ inline auto towxImage(CalChart::ImageData const& image) -> wxImage
}

struct BitmapHolder : CalChart::Draw::OpaqueImageData {
BitmapHolder(wxImage const& image)
: bitmap(image)
explicit BitmapHolder(wxImage const& image)
: bitmap{ image }
{
}
explicit BitmapHolder(wxBitmap const& bitmap)
: bitmap{ bitmap }
{
}
~BitmapHolder() override = default;
Expand Down
74 changes: 55 additions & 19 deletions src/core/CalChartUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,31 +55,67 @@ constexpr auto toUType(E enumerator)
// from https://stackoverflow.com/questions/261963/how-can-i-iterate-over-an-enum
template <typename C, C beginVal, C endVal>
class Iterator {
using val_t = typename std::underlying_type<C>::type;
val_t val;

public:
explicit Iterator(const C& f)
: val(static_cast<val_t>(f))
Iterator() = default;

// Iterator type
class iterator {
using val_t = typename std::underlying_type<C>::type;

public:
using difference_type = std::ptrdiff_t;
using value_type = C;
iterator() = default;
explicit iterator(val_t value)
: val_{ value }
{
}

// Increment operators
auto operator++() -> iterator&
{
++val_;
return *this;
}

auto operator++(int) -> iterator
{
iterator tmp(*this);
++(*this);
return tmp;
}

// Dereference operator
auto operator*() const -> C
{
return static_cast<C>(val_);
}

// Equality comparison operator
auto operator==(const iterator& other) const
{
return val_ == other.val_;
}

auto operator!=(const iterator& other) const
{
return !(*this == other);
}

private:
val_t val_{};
};

auto begin() const -> iterator
{
return iterator(toUType(beginVal));
}
Iterator()
: val(static_cast<val_t>(beginVal))
{
}
auto operator++() -> Iterator
{
++val;
return *this;
}
auto operator*() const { return static_cast<C>(val); }
auto begin() const -> Iterator { return *this; } // default ctor is good
auto end() const -> Iterator

auto end() const -> iterator
{
static const Iterator endIter = ++Iterator(endVal); // cache it
return endIter;
return iterator(toUType(endVal) + 1);
}
auto operator!=(const Iterator& i) const { return val != i.val; }
};

template <class... Ts>
Expand Down