Skip to content

Commit

Permalink
Issue #602: Have Background images use CalChart::Draw (#603)
Browse files Browse the repository at this point in the history
Made the enumeration iterator range compatible.
  • Loading branch information
rmpowell77 authored Jan 20, 2025
1 parent 0cb4930 commit d8a9665
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 79 deletions.
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

0 comments on commit d8a9665

Please sign in to comment.