mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 05:36:59 -04:00
Implemented printing (finally)
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@272 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+133
-30
@@ -10,9 +10,12 @@
|
|||||||
#include <gui/card_select_window.hpp>
|
#include <gui/card_select_window.hpp>
|
||||||
#include <gui/util.hpp>
|
#include <gui/util.hpp>
|
||||||
#include <data/set.hpp>
|
#include <data/set.hpp>
|
||||||
|
#include <data/stylesheet.hpp>
|
||||||
|
#include <render/card/viewer.hpp>
|
||||||
#include <wx/print.h>
|
#include <wx/print.h>
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(CardP);
|
DECLARE_TYPEOF_COLLECTION(CardP);
|
||||||
|
DECLARE_POINTER_TYPE(PageLayout);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Buffering DC
|
// ----------------------------------------------------------------------------- : Buffering DC
|
||||||
|
|
||||||
@@ -31,7 +34,7 @@ DECLARE_TYPEOF_COLLECTION(CardP);
|
|||||||
*/
|
*/
|
||||||
class TextBufferDC : public wxMemoryDC {
|
class TextBufferDC : public wxMemoryDC {
|
||||||
public:
|
public:
|
||||||
TextBufferDC(UInt width, UInt height);
|
TextBufferDC(int width, int height);
|
||||||
|
|
||||||
virtual void DoDrawText(const String& str, int x, int y);
|
virtual void DoDrawText(const String& str, int x, int y);
|
||||||
virtual void DoDrawRotatedText(const String& str, int x, int y, double angle);
|
virtual void DoDrawRotatedText(const String& str, int x, int y, double angle);
|
||||||
@@ -47,9 +50,10 @@ class TextBufferDC : public wxMemoryDC {
|
|||||||
int x, y;
|
int x, y;
|
||||||
String text;
|
String text;
|
||||||
double angle;
|
double angle;
|
||||||
|
double user_scale_x, user_scale_y;
|
||||||
|
|
||||||
TextDraw(wxFont font, Color color, int x, int y, String text, double angle = 0)
|
TextDraw(wxFont font, Color color, double user_scale_x, double user_scale_y, int x, int y, String text, double angle = 0)
|
||||||
: font(font), color(color), x(x), y(y), text(text), angle(angle)
|
: font(font), color(color), user_scale_x(user_scale_x), user_scale_y(user_scale_y), x(x), y(y), text(text), angle(angle)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
@@ -59,7 +63,7 @@ class TextBufferDC : public wxMemoryDC {
|
|||||||
Bitmap buffer;
|
Bitmap buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
TextBufferDC::TextBufferDC(UInt width, UInt height)
|
TextBufferDC::TextBufferDC(int width, int height)
|
||||||
: buffer(width, height, 32)
|
: buffer(width, height, 32)
|
||||||
{
|
{
|
||||||
SelectObject(buffer);
|
SelectObject(buffer);
|
||||||
@@ -67,10 +71,14 @@ TextBufferDC::TextBufferDC(UInt width, UInt height)
|
|||||||
clearDC(*this,*wxWHITE_BRUSH);
|
clearDC(*this,*wxWHITE_BRUSH);
|
||||||
}
|
}
|
||||||
void TextBufferDC::DoDrawText(const String& str, int x, int y) {
|
void TextBufferDC::DoDrawText(const String& str, int x, int y) {
|
||||||
text.push_back( new_shared5<TextDraw>(GetFont(), GetTextForeground(), x, y, str) );
|
double usx,usy;
|
||||||
|
GetUserScale(&usx, &usy);
|
||||||
|
text.push_back( new_shared7<TextDraw>(GetFont(), GetTextForeground(), usx, usy, x, y, str) );
|
||||||
}
|
}
|
||||||
void TextBufferDC::DoDrawRotatedText(const String& str, int x, int y, double angle) {
|
void TextBufferDC::DoDrawRotatedText(const String& str, int x, int y, double angle) {
|
||||||
text.push_back( new_shared6<TextDraw>(GetFont(), GetTextForeground(), x, y, str, angle) );
|
double usx,usy;
|
||||||
|
GetUserScale(&usx, &usy);
|
||||||
|
text.push_back( new_shared8<TextDraw>(GetFont(), GetTextForeground(), usx, usy, x, y, str, angle) );
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(TextBufferDC::TextDrawP);
|
DECLARE_TYPEOF_COLLECTION(TextBufferDC::TextDrawP);
|
||||||
@@ -79,6 +87,9 @@ void TextBufferDC::drawToDevice(DC& dc, int x, int y) {
|
|||||||
SelectObject(wxNullBitmap);
|
SelectObject(wxNullBitmap);
|
||||||
dc.DrawBitmap(buffer, x, y);
|
dc.DrawBitmap(buffer, x, y);
|
||||||
FOR_EACH(t, text) {
|
FOR_EACH(t, text) {
|
||||||
|
double usx,usy;
|
||||||
|
dc.GetUserScale(&usx, &usy);
|
||||||
|
dc.SetUserScale(usx * t->user_scale_x, usx * t->user_scale_y);
|
||||||
dc.SetFont (t->font);
|
dc.SetFont (t->font);
|
||||||
dc.SetTextForeground(t->color);
|
dc.SetTextForeground(t->color);
|
||||||
if (t->angle) {
|
if (t->angle) {
|
||||||
@@ -86,45 +97,139 @@ void TextBufferDC::drawToDevice(DC& dc, int x, int y) {
|
|||||||
} else {
|
} else {
|
||||||
dc.DrawText(t->text, t->x + x, t->y + y);
|
dc.DrawText(t->text, t->x + x, t->y + y);
|
||||||
}
|
}
|
||||||
|
dc.SetUserScale(usx, usy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Layout
|
// ----------------------------------------------------------------------------- : Layout
|
||||||
|
|
||||||
/// Layout of a page of cards
|
PageLayout::PageLayout()
|
||||||
class PageLayout {
|
: margin_left(0), margin_right(0), margin_top(0), margin_bottom(0)
|
||||||
public:
|
, rows(0), cols(0), card_landscape(false)
|
||||||
RealSize card_size; ///< Size of a card
|
{}
|
||||||
RealSize card_space; ///< Spacing between cards
|
|
||||||
double margin_left, margin_right, margin_top, margin_bottom; ///< Page margins
|
PageLayout::PageLayout(const StyleSheet& stylesheet, const RealSize& page_size)
|
||||||
int rows, cols; ///< Number of rows/columns of cards
|
: page_size(page_size)
|
||||||
bool landscape; ///< Are cards rotated to landscape orientation?
|
, margin_left(0), margin_right(0), margin_top(0), margin_bottom(0)
|
||||||
};
|
{
|
||||||
|
card_size.width = stylesheet.card_width * 25.4 / stylesheet.card_dpi;
|
||||||
|
card_size.height = stylesheet.card_height * 25.4 / stylesheet.card_dpi;
|
||||||
|
card_landscape = card_size.width > card_size.height;
|
||||||
|
cols = floor(page_size.width / card_size.width);
|
||||||
|
rows = floor(page_size.height / card_size.height);
|
||||||
|
// distribute whitespace evenly
|
||||||
|
margin_left = margin_right = card_spacing.width = (page_size.width - (cols * card_size.width )) / (cols + 1);
|
||||||
|
margin_top = margin_bottom = card_spacing.height = (page_size.height - (rows * card_size.height)) / (rows + 1);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Printout
|
// ----------------------------------------------------------------------------- : Printout
|
||||||
|
|
||||||
/// A printout object specifying how to print a specified set of cards
|
/// A printout object specifying how to print a specified set of cards
|
||||||
class CardsPrintout : wxPrintout {
|
class CardsPrintout : public wxPrintout {
|
||||||
public:
|
public:
|
||||||
CardsPrintout(const SetP& set, const vector<CardP>& cards);
|
CardsPrintout(const SetP& set, const vector<CardP>& cards);
|
||||||
/// Determine card size, cards per row
|
|
||||||
void OnPreparePrinting();
|
|
||||||
/// Number of pages, and something else I don't understand...
|
/// Number of pages, and something else I don't understand...
|
||||||
void GetPageInfo(int* pageMin, int* pageMax, int* pageFrom, int* pageTo);
|
virtual void GetPageInfo(int* pageMin, int* pageMax, int* pageFrom, int* pageTo);
|
||||||
/// Again, 'number of pages', strange wx interface
|
/// Again, 'number of pages', strange wx interface
|
||||||
bool HasPage(int page);
|
virtual bool HasPage(int page);
|
||||||
|
/// Determine the layout
|
||||||
|
virtual void OnPreparePrinting();
|
||||||
/// Print a page
|
/// Print a page
|
||||||
bool OnPrintPage(int page);
|
virtual bool OnPrintPage(int page);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PageLayout layout;
|
PageLayoutP layout;
|
||||||
|
SetP set;
|
||||||
|
vector<CardP> cards; ///< Cards to print
|
||||||
|
DataViewer viewer;
|
||||||
|
double scale_x, scale_y; // priter pixel per mm
|
||||||
|
|
||||||
|
inline int pageCount() {
|
||||||
|
return ((int)cards.size() + layout->cardsPerPage() - 1) / layout->cardsPerPage();
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw a card, that is card_nr on this page, find the postion by asking the layout
|
/// Draw a card, that is card_nr on this page, find the postion by asking the layout
|
||||||
void drawCard(DC& dc, const CardP& card, size_t card_nr);
|
void drawCard(DC& dc, const CardP& card, int card_nr);
|
||||||
/// Draw a card at the specified coordinates
|
|
||||||
void drawCard(DC& dc, const CardP& card, double x, double y, int rotation = 0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CardsPrintout::CardsPrintout(const SetP& set, const vector<CardP>& cards)
|
||||||
|
: set(set), cards(cards)
|
||||||
|
{
|
||||||
|
viewer.setSet(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardsPrintout::GetPageInfo(int* page_min, int* page_max, int* page_from, int* page_to) {
|
||||||
|
*page_from = *page_min = 1;
|
||||||
|
*page_to = *page_max = pageCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CardsPrintout::HasPage(int page) {
|
||||||
|
return page <= pageCount(); // page number is 1 based
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardsPrintout::OnPreparePrinting() {
|
||||||
|
int pw_mm, ph_mm;
|
||||||
|
GetPageSizeMM(&pw_mm, &ph_mm);
|
||||||
|
if (!layout) {
|
||||||
|
layout = new_shared2<PageLayout>(*set->stylesheet, RealSize(pw_mm, ph_mm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CardsPrintout::OnPrintPage(int page) {
|
||||||
|
DC& dc = *GetDC();
|
||||||
|
// scale factors
|
||||||
|
int pw_mm, ph_mm;
|
||||||
|
GetPageSizeMM(&pw_mm, &ph_mm);
|
||||||
|
int pw_px, ph_px;
|
||||||
|
dc.GetSize(&pw_px, &ph_px);
|
||||||
|
scale_x = (double)pw_px / pw_mm;
|
||||||
|
scale_y = (double)ph_px / ph_mm;
|
||||||
|
// print the cards that belong on this page
|
||||||
|
int start = (page - 1) * layout->cardsPerPage();
|
||||||
|
int end = min((int)cards.size(), start + layout->cardsPerPage());
|
||||||
|
for (int i = start ; i < end ; ++i) {
|
||||||
|
drawCard(dc, cards[i], i - start);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardsPrintout::drawCard(DC& dc, const CardP& card, int card_nr) {
|
||||||
|
// determine position
|
||||||
|
int col = card_nr % layout->cols;
|
||||||
|
int row = card_nr / layout->cols;
|
||||||
|
RealPoint pos( layout->margin_left + (layout->card_size.width + layout->card_spacing.width) * col
|
||||||
|
, layout->margin_top + (layout->card_size.height + layout->card_spacing.height) * row);
|
||||||
|
// determine rotation
|
||||||
|
StyleSheet& stylesheet = *set->stylesheetFor(card);
|
||||||
|
int rotation = 0;
|
||||||
|
if ((stylesheet.card_width > stylesheet.card_height) != layout->card_landscape) {
|
||||||
|
rotation = 90 - rotation;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// size of this particular card (in mm)
|
||||||
|
RealSize card_size( stylesheet.card_width * 25.4 / stylesheet.card_dpi
|
||||||
|
, stylesheet.card_height * 25.4 / stylesheet.card_dpi);
|
||||||
|
if (rotation == 90) swap(card_size.width, card_size.height);
|
||||||
|
// adjust card size, to center card in the available space (from layout->card_size)?
|
||||||
|
// TODO
|
||||||
|
*/
|
||||||
|
|
||||||
|
// create buffers
|
||||||
|
int w = stylesheet.card_width, h = stylesheet.card_height; // in pixels
|
||||||
|
if (rotation == 90) swap(w,h);
|
||||||
|
TextBufferDC bufferDC(w,h);
|
||||||
|
RotatedDC rdc(bufferDC, rotation, RealRect(0,0,w,h), 1.0, QUALITY_SUB_PIXEL);
|
||||||
|
// render card to dc
|
||||||
|
viewer.setCard(card);
|
||||||
|
viewer.draw(rdc, *wxWHITE);
|
||||||
|
// render buffer to device
|
||||||
|
double px_per_mm = stylesheet.card_dpi / 25.4;
|
||||||
|
dc.SetUserScale(scale_x / px_per_mm, scale_y / px_per_mm);
|
||||||
|
dc.SetDeviceOrigin(scale_x * pos.x, scale_y * pos.y);
|
||||||
|
bufferDC.drawToDevice(dc, 0, 0); // adjust for scaling
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : PrintWindow
|
// ----------------------------------------------------------------------------- : PrintWindow
|
||||||
|
|
||||||
void print_preview(Window* parent, const SetP& set) {
|
void print_preview(Window* parent, const SetP& set) {
|
||||||
@@ -137,8 +242,8 @@ void print_preview(Window* parent, const SetP& set) {
|
|||||||
FOR_EACH(c, set->cards) {
|
FOR_EACH(c, set->cards) {
|
||||||
if (wnd.isSelected(c)) selected.push_back(c);
|
if (wnd.isSelected(c)) selected.push_back(c);
|
||||||
}
|
}
|
||||||
/* // Show the print preview
|
// Show the print preview
|
||||||
wxPreviewFrame frame = new wxPreviewFrame(
|
wxPreviewFrame* frame = new wxPreviewFrame(
|
||||||
new wxPrintPreview(
|
new wxPrintPreview(
|
||||||
new CardsPrintout(set, selected),
|
new CardsPrintout(set, selected),
|
||||||
new CardsPrintout(set, selected)
|
new CardsPrintout(set, selected)
|
||||||
@@ -146,7 +251,6 @@ void print_preview(Window* parent, const SetP& set) {
|
|||||||
frame->Initialize();
|
frame->Initialize();
|
||||||
frame->Maximize(true);
|
frame->Maximize(true);
|
||||||
frame->Show();
|
frame->Show();
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_set(Window* parent, const SetP& set) {
|
void print_set(Window* parent, const SetP& set) {
|
||||||
@@ -159,9 +263,8 @@ void print_set(Window* parent, const SetP& set) {
|
|||||||
FOR_EACH(c, set->cards) {
|
FOR_EACH(c, set->cards) {
|
||||||
if (wnd.isSelected(c)) selected.push_back(c);
|
if (wnd.isSelected(c)) selected.push_back(c);
|
||||||
}
|
}
|
||||||
/* // Print the cards
|
// Print the cards
|
||||||
wxPrinter p;
|
wxPrinter p;
|
||||||
CardsPrintout pout(set, selected);
|
CardsPrintout pout(set, selected);
|
||||||
p.Print(parent, &pout, true);
|
p.Print(parent, &pout, true);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,11 @@
|
|||||||
// ----------------------------------------------------------------------------- : Includes
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
#include <util/prec.hpp>
|
#include <util/prec.hpp>
|
||||||
|
#include <util/reflect.hpp>
|
||||||
|
#include <util/real_point.hpp>
|
||||||
|
|
||||||
DECLARE_POINTER_TYPE(Set);
|
DECLARE_POINTER_TYPE(Set);
|
||||||
|
class StyleSheet;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Printing
|
// ----------------------------------------------------------------------------- : Printing
|
||||||
|
|
||||||
@@ -21,5 +24,27 @@ void print_preview(Window* parent, const SetP& set);
|
|||||||
/// Print the given set
|
/// Print the given set
|
||||||
void print_set(Window* parent, const SetP& set);
|
void print_set(Window* parent, const SetP& set);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Layout
|
||||||
|
|
||||||
|
/// Layout of a page of cards
|
||||||
|
class PageLayout {
|
||||||
|
public:
|
||||||
|
PageLayout();
|
||||||
|
PageLayout(const StyleSheet& stylesheet, const RealSize& page_size);
|
||||||
|
|
||||||
|
RealSize page_size; ///< Size of a page (in millimetres)
|
||||||
|
RealSize card_size; ///< Size of a card (in millimetres)
|
||||||
|
RealSize card_spacing; ///< Spacing between cards (in millimetres)
|
||||||
|
double margin_left, margin_right, margin_top, margin_bottom; ///< Page margins (in millimetres)
|
||||||
|
int rows, cols; ///< Number of rows/columns of cards
|
||||||
|
bool card_landscape; ///< Are cards rotated to landscape orientation?
|
||||||
|
|
||||||
|
/// The number of cards per page
|
||||||
|
inline int cardsPerPage() const { return rows * cols; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
DECLARE_REFLECTION();
|
||||||
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -75,6 +75,16 @@ template <typename T, typename A0, typename A1, typename A2, typename A3, typena
|
|||||||
inline shared_ptr<T> new_shared7(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) {
|
inline shared_ptr<T> new_shared7(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) {
|
||||||
return shared_ptr<T>(new T(a0, a1, a2, a3, a4, a5, a6));
|
return shared_ptr<T>(new T(a0, a1, a2, a3, a4, a5, a6));
|
||||||
}
|
}
|
||||||
|
/// Allocate a new shared-pointed object, given eight arguments to pass to the ctor of T
|
||||||
|
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
|
||||||
|
inline shared_ptr<T> new_shared8(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) {
|
||||||
|
return shared_ptr<T>(new T(a0, a1, a2, a3, a4, a5, a6, a7));
|
||||||
|
}
|
||||||
|
/// Allocate a new shared-pointed object, given nine arguments to pass to the ctor of T
|
||||||
|
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
|
||||||
|
inline shared_ptr<T> new_shared9(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) {
|
||||||
|
return shared_ptr<T>(new T(a0, a1, a2, a3, a4, a5, a6, a7, a8));
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Intrusive pointers
|
// ----------------------------------------------------------------------------- : Intrusive pointers
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user