Files
MagicSetEditor2/src/gui/control/card_viewer.cpp
T
Twan van Laarhoven bad9981ad9 Cleaned up copyright block.
Removed the year so we don't get tempted to change this ever again.
2020-04-26 01:11:14 +02:00

160 lines
5.3 KiB
C++

//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <gui/control/card_viewer.hpp>
#include <data/stylesheet.hpp>
#include <data/settings.hpp>
#include <render/value/viewer.hpp>
#include <wx/dcbuffer.h>
// ----------------------------------------------------------------------------- : Events
DEFINE_EVENT_TYPE(EVENT_SIZE_CHANGE);
// ----------------------------------------------------------------------------- : CardViewer
CardViewer::CardViewer(Window* parent, int id, long style)
: wxControl(parent, id, wxDefaultPosition, wxDefaultSize, style)
, up_to_date(false)
{}
wxSize CardViewer::DoGetBestSize() const {
wxSize ws = GetSize(), cs = GetClientSize();
if (set) {
if (!stylesheet) stylesheet = set->stylesheet;
StyleSheetSettings& ss = settings.stylesheetSettingsFor(*stylesheet);
wxSize size(int(stylesheet->card_width * ss.card_zoom()), int(stylesheet->card_height * ss.card_zoom()));
if (is_sideways(deg_to_rad(ss.card_angle()))) swap(size.x, size.y);
return size + ws - cs;
}
return cs;
}
void CardViewer::redraw(const ValueViewer& v) {
// Don't refresh if we OR ANOTHER CardViewer is drawing
// drawing another viewer causes styles to be updated for its active card, which may be different,
// causing the two viewers to continously refresh.
if (drawing_card()) return;
up_to_date = false;
RefreshRect(getRotation().trRectToBB(v.boundingBox()), false);
}
void CardViewer::onChange() {
redraw();
}
void CardViewer::redraw() {
if (drawing_card()) return;
up_to_date = false;
Refresh(false);
}
void CardViewer::onChangeSize() {
InvalidateBestSize();
wxSize ws = GetSize(), cs = GetClientSize();
wxSize desired_cs = (wxSize)getRotation().getExternalSize() + ws - cs;
if (desired_cs != cs) {
wxCommandEvent ev(EVENT_SIZE_CHANGE, GetId());
ProcessEvent(ev);
}
}
#ifdef _DEBUG
DECLARE_DYNAMIC_ARG(bool, inOnPaint);
IMPLEMENT_DYNAMIC_ARG(bool, inOnPaint, false);
#endif
void CardViewer::onPaint(wxPaintEvent&) {
#ifdef _DEBUG
// we don't want recursion
if (inOnPaint()) {
wxTrap();
}
WITH_DYNAMIC_ARG(inOnPaint, true);
#endif
wxSize cs = GetClientSize();
if (cs.GetWidth() == 0 || cs.GetHeight() == 0) {
return; // empty bitmaps are not allowed because some idiots think that 0 is not a number
}
if (!buffer.Ok() || buffer.GetWidth() != cs.GetWidth() || buffer.GetHeight() != cs.GetHeight()) {
buffer = Bitmap(cs.GetWidth(), cs.GetHeight());
up_to_date = false;
}
wxBufferedPaintDC dc(this, buffer);
// scrolling
// int dx = GetScrollPos(wxHORIZONTAL), dy = GetScrollPos(wxVERTICAL);
// dc.SetDeviceOrigin(-dx, -dy);
wxRegion clip = GetUpdateRegion();
// clip.Offset(dx, dy);
dc.SetDeviceClippingRegion(clip);
// draw
if (!up_to_date) {
up_to_date = true;
try {
draw(dc);
} CATCH_ALL_ERRORS(false); // don't show message boxes in onPaint!
}
}
void CardViewer::drawViewer(RotatedDC& dc, ValueViewer& v) {
if (shouldDraw(v)) v.draw(dc);
}
bool CardViewer::shouldDraw(const ValueViewer& v) const {
// int dx = GetScrollPos(wxHORIZONTAL), dy = GetScrollPos(wxVERTICAL);
// wxRegion clip = GetUpdateRegion();
// clip.Offset(dx, dy);
return GetUpdateRegion().Contains(getRotation().trRectToBB(v.boundingBox().toRect()).toRect()) != wxOutRegion;
}
// helper class for overdrawDC()
class CardViewer::OverdrawDC_aux : private wxClientDC {
protected:
wxBufferedDC bufferedDC;
OverdrawDC_aux(CardViewer* window)
: wxClientDC(window)
{
bufferedDC.Init((wxClientDC*)this, window->buffer);
}
};
class CardViewer::OverdrawDC : private OverdrawDC_aux, public RotatedDC {
public:
OverdrawDC(CardViewer* window)
: OverdrawDC_aux(window)
, RotatedDC(bufferedDC, window->getRotation(), QUALITY_LOW)
{}
};
shared_ptr<RotatedDC> CardViewer::overdrawDC() {
#ifdef _DEBUG
// don't call from onPaint
if (inOnPaint()) {
wxTrap();
}
#endif
return shared_ptr<RotatedDC>(new OverdrawDC(this));
}
Rotation CardViewer::getRotation() const {
// Same as DataViewer::getRotation, only taking into account scrolling
if (!stylesheet) stylesheet = set->stylesheet;
StyleSheetSettings& ss = settings.stylesheetSettingsFor(*stylesheet);
int dx = CanScroll(wxHORIZONTAL) ? GetScrollPos(wxHORIZONTAL) : 0;
int dy = CanScroll(wxVERTICAL) ? GetScrollPos(wxVERTICAL) : 0;
return Rotation(deg_to_rad(ss.card_angle()), stylesheet->getCardRect().move(-dx,-dy,0,0), ss.card_zoom(), 1.0, ROTATION_ATTACH_TOP_LEFT);
}
// ----------------------------------------------------------------------------- : Event table
BEGIN_EVENT_TABLE(CardViewer, wxControl)
EVT_PAINT (CardViewer::onPaint)
EVT_ERASE_BACKGROUND(CardViewer::onEraseBackground)
END_EVENT_TABLE ()