mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 13:06:59 -04:00
223 lines
8.3 KiB
C++
223 lines
8.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/print_window.hpp>
|
|
#include <gui/card_select_window.hpp>
|
|
#include <gui/util.hpp>
|
|
#include <data/set.hpp>
|
|
#include <data/card.hpp>
|
|
#include <data/stylesheet.hpp>
|
|
#include <render/card/viewer.hpp>
|
|
#include <wx/print.h>
|
|
|
|
DECLARE_POINTER_TYPE(PageLayout);
|
|
|
|
// ----------------------------------------------------------------------------- : Layout
|
|
|
|
PageLayout::PageLayout()
|
|
: margin_left(0), margin_right(0), margin_top(0), margin_bottom(0)
|
|
, rows(0), cols(0), card_landscape(false)
|
|
{}
|
|
|
|
void PageLayout::init(const StyleSheet& stylesheet, PageLayoutType type, const RealSize& page_size) {
|
|
this->page_size = page_size;
|
|
margin_left = margin_right = margin_top = 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 = int(floor(page_size.width / card_size.width));
|
|
rows = int(floor(page_size.height / card_size.height));
|
|
// spacing
|
|
double hspace = (page_size.width - (cols * card_size.width ));
|
|
double vspace = (page_size.height - (rows * card_size.height));
|
|
if (type == LAYOUT_NO_SPACE) {
|
|
// no space between cards
|
|
card_spacing.width = card_spacing.height = 0;
|
|
margin_left = margin_right = hspace / 2;
|
|
margin_top = vspace * 1./3; margin_bottom = vspace * 2./3; // most printers have more margin at the bottom
|
|
} else {
|
|
// distribute whitespace evenly
|
|
margin_left = margin_right = card_spacing.width = hspace / (cols + 1);
|
|
margin_top = margin_bottom = card_spacing.height = vspace / (rows + 1);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------- : Printout
|
|
|
|
/// A printout object specifying how to print a specified set of cards
|
|
class CardsPrintout : public wxPrintout {
|
|
public:
|
|
CardsPrintout(PrintJobP const& job);
|
|
/// Number of pages, and something else I don't understand...
|
|
void GetPageInfo(int* pageMin, int* pageMax, int* pageFrom, int* pageTo) override;
|
|
/// Again, 'number of pages', strange wx interface
|
|
bool HasPage(int page) override;
|
|
/// Determine the layout
|
|
void OnPreparePrinting() override;
|
|
/// Print a page
|
|
bool OnPrintPage(int page) override;
|
|
|
|
private:
|
|
PrintJobP job; ///< Cards to print
|
|
DataViewer viewer;
|
|
double scale_x, scale_y; // priter pixel per mm
|
|
|
|
int pageCount() {
|
|
return job->num_pages();
|
|
}
|
|
|
|
/// Draw a card, that is card_nr on this page, find the postion by asking the layout
|
|
void drawCard(DC& dc, const CardP& card, int card_nr);
|
|
};
|
|
|
|
CardsPrintout::CardsPrintout(PrintJobP const& job)
|
|
: job(job)
|
|
{
|
|
viewer.setSet(job->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() {
|
|
if (job->layout.empty()) {
|
|
int pw_mm, ph_mm;
|
|
GetPageSizeMM(&pw_mm, &ph_mm);
|
|
job->layout.init(*job->set->stylesheet, job->layout_type, 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) * job->layout.cards_per_page();
|
|
int end = min((int)job->cards.size(), start + job->layout.cards_per_page());
|
|
for (int i = start ; i < end ; ++i) {
|
|
drawCard(dc, job->cards.at(i), i - start);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CardsPrintout::drawCard(DC& dc, const CardP& card, int card_nr) {
|
|
// determine position
|
|
int col = card_nr % job->layout.cols;
|
|
int row = card_nr / job->layout.cols;
|
|
RealPoint pos( job->layout.margin_left + (job->layout.card_size.width + job->layout.card_spacing.width) * col
|
|
, job->layout.margin_top + (job->layout.card_size.height + job->layout.card_spacing.height) * row);
|
|
// determine rotation
|
|
const StyleSheet& stylesheet = job->set->stylesheetFor(card);
|
|
Radians rotation = 0;
|
|
if ((stylesheet.card_width > stylesheet.card_height) != job->layout.card_landscape) {
|
|
rotation = rad90;
|
|
}
|
|
/*
|
|
// 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 (is_rad90(rotation)) swap(card_size.width, card_size.height);
|
|
// adjust card size, to center card in the available space (from job->layout.card_size)?
|
|
// TODO: deal with different sized cards in general
|
|
*/
|
|
|
|
// create buffers
|
|
int w = int(stylesheet.card_width), h = int(stylesheet.card_height); // in pixels
|
|
if (is_rad90(rotation)) swap(w,h);
|
|
// Draw using text buffer
|
|
double zoom = IsPreview() ? 1 : 4;
|
|
wxBitmap buffer(w*zoom,h*zoom,32);
|
|
wxMemoryDC bufferDC;
|
|
bufferDC.SelectObject(buffer);
|
|
clearDC(bufferDC,*wxWHITE_BRUSH);
|
|
RotatedDC rdc(bufferDC, rotation, stylesheet.getCardRect(), zoom, QUALITY_AA, ROTATION_ATTACH_TOP_LEFT);
|
|
// render card to dc
|
|
viewer.setCard(card);
|
|
viewer.draw(rdc, *wxWHITE);
|
|
// render buffer to device
|
|
double px_per_mm = zoom * stylesheet.card_dpi / 25.4;
|
|
dc.SetUserScale(scale_x / px_per_mm, scale_y / px_per_mm);
|
|
dc.SetDeviceOrigin(int(scale_x * pos.x), int(scale_y * pos.y));
|
|
bufferDC.SelectObject(wxNullBitmap);
|
|
dc.DrawBitmap(buffer, 0, 0);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------- : PrintWindow
|
|
|
|
PrintJobP make_print_job(Window* parent, const SetP& set, const ExportCardSelectionChoices& choices) {
|
|
// Let the user choose cards
|
|
// controls
|
|
ExportWindowBase wnd(parent, _TITLE_("select cards"), set, choices);
|
|
wxCheckBox* space = new wxCheckBox(&wnd, wxID_ANY, L"Put space between cards");
|
|
space->SetValue(settings.print_layout);
|
|
// layout
|
|
wxSizer* s = new wxBoxSizer(wxVERTICAL);
|
|
wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
|
|
wxSizer* s3 = wnd.Create();
|
|
s2->Add(s3, 1, wxEXPAND | wxALL, 8);
|
|
wxSizer* s4 = new wxStaticBoxSizer(wxVERTICAL, &wnd, L"Settings");
|
|
s4->Add(space, 1, wxALL | wxALIGN_TOP, 8);
|
|
s2->Add(s4, 1, wxEXPAND | (wxALL & ~wxLEFT), 8);
|
|
s->Add(s2, 1, wxEXPAND);
|
|
s->Add(wnd.CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8);
|
|
s->SetSizeHints(&wnd);
|
|
wnd.SetSizer(s);
|
|
wnd.SetMinSize(wxSize(300,-1));
|
|
// show window
|
|
if (wnd.ShowModal() != wxID_OK) {
|
|
return PrintJobP(); // cancel
|
|
} else {
|
|
// make print job
|
|
PrintJobP job = make_intrusive<PrintJob>(set);
|
|
job->layout_type = settings.print_layout = space->GetValue() ? LAYOUT_EQUAL_SPACE : LAYOUT_NO_SPACE;
|
|
job->cards = wnd.getSelection();
|
|
return job;
|
|
}
|
|
}
|
|
|
|
void print_preview(Window* parent, const PrintJobP& job) {
|
|
if (!job) return;
|
|
// Show the print preview
|
|
wxPreviewFrame* frame = new wxPreviewFrame(
|
|
new wxPrintPreview(
|
|
new CardsPrintout(job),
|
|
new CardsPrintout(job)
|
|
), parent, _TITLE_("print preview"));
|
|
frame->Initialize();
|
|
frame->Maximize(true);
|
|
frame->Show();
|
|
}
|
|
|
|
void print_set(Window* parent, const PrintJobP& job) {
|
|
if (!job) return;
|
|
// Print the cards
|
|
wxPrinter p;
|
|
CardsPrintout pout(job);
|
|
p.Print(parent, &pout, true);
|
|
}
|
|
|
|
void print_preview(Window* parent, const SetP& set, const ExportCardSelectionChoices& choices) {
|
|
print_preview(parent, make_print_job(parent, set, choices));
|
|
}
|
|
void print_set(Window* parent, const SetP& set, const ExportCardSelectionChoices& choices) {
|
|
print_set(parent, make_print_job(parent, set, choices));
|
|
}
|