rewrite print logic once again

- move Front Face // Back Face card link to exe level
- print front faces and back faces together
- use printer dpi instead of stylesheet dpi
This commit is contained in:
GenevensiS
2025-11-30 10:37:59 +01:00
parent 22b3a3e8b2
commit 2d6c0d2aee
6 changed files with 206 additions and 142 deletions
+22 -4
View File
@@ -21,7 +21,7 @@
// ----------------------------------------------------------------------------- : Card
Card::Card()
// for files made before we saved these, set the time to 'yesterday', generate a uid
// for files made before we saved these, set the time to 'yesterday', generate a uid
: time_created (wxDateTime::Now().Subtract(wxDateSpan::Day()).ResetTime())
, time_modified(wxDateTime::Now().Subtract(wxDateSpan::Day()).ResetTime())
, uid(generate_uid())
@@ -80,7 +80,7 @@ void Card::link(const Set& set, const vector<CardP>& linked_cards, const String&
if (
this_linked_uid.empty() || // Not a reference
all_existing_uids.find(this_linked_uid) == all_existing_uids.end() // Reference to nonexistent card
) free_link_count++;
) free_link_count++;
}
if (free_link_count < linked_cards.size()) {
queue_message(MESSAGE_WARNING, _ERROR_("not enough free links"));
@@ -265,7 +265,7 @@ void Card::updateLink(String old_uid, String new_uid) {
}
}
vector<pair<CardP, String>> Card::getLinkedCards(const Set& set) {
vector<pair<CardP, String>> Card::getLinkedCards(const vector<CardP>& cards) {
unordered_map<String, String> links{
{ linked_card_1, linked_relation_1 },
{ linked_card_2, linked_relation_2 },
@@ -273,13 +273,31 @@ vector<pair<CardP, String>> Card::getLinkedCards(const Set& set) {
{ linked_card_4, linked_relation_4 }
};
vector<pair<CardP, String>> linked_cards;
FOR_EACH(other_card, set.cards) {
FOR_EACH(other_card, cards) {
if (links.find(other_card->uid) != links.end()) {
linked_cards.push_back(make_pair(other_card, links.at(other_card->uid)));
}
}
return linked_cards;
}
vector<pair<CardP, String>> Card::getLinkedCards(const Set& set) {
return getLinkedCards(set.cards);
}
CardP Card::getOtherFace(const vector<CardP>& cards) {
unordered_set<String> faces;
if (linked_relation_1 == _("Front Face") || linked_relation_1 == _("Back Face")) faces.emplace(linked_card_1);
if (linked_relation_2 == _("Front Face") || linked_relation_2 == _("Back Face")) faces.emplace(linked_card_2);
if (linked_relation_3 == _("Front Face") || linked_relation_3 == _("Back Face")) faces.emplace(linked_card_3);
if (linked_relation_4 == _("Front Face") || linked_relation_4 == _("Back Face")) faces.emplace(linked_card_4);
FOR_EACH(other_card, cards) {
if (faces.find(other_card->uid) != faces.end()) return other_card;
}
return nullptr;
}
CardP Card::getOtherFace(const Set& set) {
return getOtherFace(set.cards);
}
IndexMap<FieldP, ValueP>& Card::extraDataFor(const StyleSheet& stylesheet) {
return extra_data.get(stylesheet.name(), stylesheet.extra_card_fields);
+5 -2
View File
@@ -60,8 +60,8 @@ public:
StyleSheetP stylesheet;
/// Alternative options to use for this card, for this card's stylesheet
/** Optional; if not set use the styling data from the set.
* If stylesheet is set then contains data for the this->stylesheet, otherwise for set->stylesheet
*/
* If stylesheet is set then contains data for the this->stylesheet, otherwise for set->stylesheet
*/
IndexMap<FieldP,ValueP> styling_data;
/// Is the styling_data set?
bool has_styling;
@@ -89,7 +89,10 @@ public:
void copyLink(const Set& set, String old_uid, String new_uid);
void updateLink(String old_uid, String new_uid);
vector<pair<CardP, String>> getLinkedCards(const vector<CardP>& cards);
vector<pair<CardP, String>> getLinkedCards(const Set& set);
CardP getOtherFace(const vector<CardP>& cards);
CardP getOtherFace(const Set& set);
/// Find a value in the data by name and type
template <typename T> T& value(const String& name) {
+7 -6
View File
@@ -143,12 +143,13 @@ Image export_image(const SetP& set, const CardP& card, const double zoom, const
IndexMap<FieldP, ValueP>& card_data = card->data;
boost::json::object& cardv = mse_to_json(card, set.get());
boost::json::object& cardv_data = cardv["data"].as_object();
if (!settings.stylesheetSettingsFor(set->stylesheetFor(card)).card_notes_export()) cardv["notes"] = "";
StyleSheetP stylesheet = set->stylesheetForP(card);
if (!settings.stylesheetSettingsFor(*stylesheet).card_notes_export()) cardv["notes"] = "";
for(IndexMap<FieldP, ValueP>::iterator it = card_data.begin() ; it != card_data.end() ; ++it) {
ImageValue* value = dynamic_cast<ImageValue*>(it->get());
if (value && !value->filename.empty()) {
FieldP field = (*it)->fieldP;
StyleP style = set->stylesheetFor(card).card_style.at(field->index);
StyleP style = stylesheet->card_style.at(field->index);
if (style) {
style->update(set->getContext(card));
std::string rect = style->getExternalRectString(zoom, 0).ToStdString();
@@ -173,12 +174,12 @@ Image export_image(const SetP& set, const vector<CardP>& cards, bool scale_to_lo
IndexMap<FieldP, ValueP>& card_data = card->data;
boost::json::object& cardv = mse_to_json(card, set.get());
boost::json::object& cardv_data = cardv["data"].as_object();
if (!settings.stylesheetSettingsFor(set->stylesheetFor(card)).card_notes_export()) cardv["notes"] = "";
StyleSheetP stylesheet = set->stylesheetForP(card);
if (!settings.stylesheetSettingsFor(*stylesheet).card_notes_export()) cardv["notes"] = "";
for(IndexMap<FieldP, ValueP>::iterator it = card_data.begin() ; it != card_data.end() ; ++it) {
ImageValue* value = dynamic_cast<ImageValue*>(it->get());
if (value && !value->filename.empty()) {
FieldP field = (*it)->fieldP;
StyleSheetP stylesheet = set->stylesheetForP(card);
StyleP style = stylesheet->card_style.at(field->index);
if (style) {
style->update(set->getContext(card));
@@ -197,11 +198,11 @@ Image export_image(const SetP& set, const vector<CardP>& cards, bool scale_to_lo
void export_image(const SetP& set, const CardP& card, const String& filename) {
Image img = export_image(set, card);
img.SaveFile(filename); // can't use Bitmap::saveFile, it wants to know the file type
// but image.saveFile determines it automagicly
// but image.saveFile determines it automagicly
}
void export_image(const SetP& set, const vector<CardP>& cards,
const String& path, const String& filename_template, FilenameConflicts conflicts)
const String& path, const String& filename_template, FilenameConflicts conflicts)
{
wxBusyCursor busy;
// Script
+16 -15
View File
@@ -25,6 +25,7 @@ CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& sel
linked_relation = new wxTextCtrl(this, wxID_ANY, _(""));
relation_type = new wxChoice(this, ID_CARD_LINK_TYPE, wxDefaultPosition, wxDefaultSize, 0, nullptr);
relation_type->Clear();
relation_type->Append("Front Face // Back Face");
FOR_EACH(link, set->game->card_links) {
relation_type->Append(link);
}
@@ -38,18 +39,18 @@ CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& sel
// init sizers
if (sizer) {
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(new wxStaticText(this, -1, _LABEL_("linked cards relation")), 0, wxALL, 8);
s->Add(relation_type, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(new wxStaticText(this, -1, _(" ") + _LABEL_("selected card")), 0, wxALL, 4);
s->Add(selected_relation, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(new wxStaticText(this, -1, _(" ") + _LABEL_("linked cards")), 0, wxALL, 4);
s->Add(linked_relation, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("select linked cards")), 0, wxALL & ~wxBOTTOM, 8);
s->Add(list, 1, wxEXPAND | wxALL, 8);
wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
s2->Add(sel_none, 0, wxEXPAND | wxRIGHT, 8);
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(new wxStaticText(this, -1, _LABEL_("linked cards relation")), 0, wxALL, 8);
s->Add(relation_type, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(new wxStaticText(this, -1, _(" ") + _LABEL_("selected card")), 0, wxALL, 4);
s->Add(selected_relation, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(new wxStaticText(this, -1, _(" ") + _LABEL_("linked cards")), 0, wxALL, 4);
s->Add(linked_relation, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("select linked cards")), 0, wxALL & ~wxBOTTOM, 8);
s->Add(list, 1, wxEXPAND | wxALL, 8);
wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
s2->Add(sel_none, 0, wxEXPAND | wxRIGHT, 8);
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s);
SetSize(600,500);
@@ -105,7 +106,7 @@ void CardLinkWindow::onOk(wxCommandEvent&) {
}
BEGIN_EVENT_TABLE(CardLinkWindow, wxDialog)
EVT_BUTTON (ID_SELECT_NONE, CardLinkWindow::onSelectNone)
EVT_BUTTON (wxID_OK, CardLinkWindow::onOk)
EVT_CHOICE (ID_CARD_LINK_TYPE, CardLinkWindow::onRelationTypeChange)
EVT_BUTTON (ID_SELECT_NONE, CardLinkWindow::onSelectNone)
EVT_BUTTON (wxID_OK, CardLinkWindow::onOk)
EVT_CHOICE (ID_CARD_LINK_TYPE, CardLinkWindow::onRelationTypeChange)
END_EVENT_TABLE ()
+102 -61
View File
@@ -30,44 +30,80 @@ void PrintJob::init(const RealSize& page_size) {
align_cards();
center_cards();
}
void PrintJob::measure_cards() {
unordered_set<CardP> already_measured_cards;
FOR_EACH(card, cards) {
const StyleSheet& stylesheet = set->stylesheetFor(card);
RealSize size_px(stylesheet.card_width, stylesheet.card_height);
RealSize size_mm(stylesheet.card_width * 25.4 / stylesheet.card_dpi, stylesheet.card_height * 25.4 / stylesheet.card_dpi);
Radians rotation = 0.0;
bool rotated = abs(size_mm.width - default_size_mm.height) < abs(size_mm.height - default_size_mm.height); // try to align best to default card height
if (rotated) {
swap(size_mm.width, size_mm.height);
swap(size_px.width, size_px.height);
rotation = rad90;
if (already_measured_cards.find(card) != already_measured_cards.end()) continue;
already_measured_cards.emplace(card);
card_layouts.push_back(measure_card(card));
CardP other_face = card->getOtherFace(cards);
if (other_face && already_measured_cards.find(other_face) == already_measured_cards.end()) {
already_measured_cards.emplace(other_face);
card_layouts.push_back(measure_card(other_face));
int index = card_layouts.size()-1;
card_layouts[index].other_face = index-1;
card_layouts[index-1].other_face = index;
}
if (abs(size_mm.width - default_size_mm.width) < threshold_size.width) size_mm.width = default_size_mm.width; // snap to default_size_mm if we are close
if (abs(size_mm.height - default_size_mm.height) < threshold_size.height) size_mm.height = default_size_mm.height;
CardLayout layout(card, size_mm, size_px, rotation);
card_layouts.push_back(layout);
}
std::sort(card_layouts.begin(), card_layouts.end());
sorted_layouts = vector<CardLayout>(card_layouts);
std::sort(sorted_layouts.begin(), sorted_layouts.end());
}
PrintJob::CardLayout PrintJob::measure_card(const CardP& card) {
const StyleSheet& stylesheet = set->stylesheetFor(card);
RealSize size_mm(stylesheet.card_width * 25.4 / stylesheet.card_dpi, stylesheet.card_height * 25.4 / stylesheet.card_dpi);
RealSize size_px(stylesheet.card_width, stylesheet.card_height);
Radians rotation = 0.0;
bool rotated = abs(size_mm.width - default_size_mm.height) < abs(size_mm.height - default_size_mm.height); // try to align best to default card height
if (rotated) {
swap(size_mm.width, size_mm.height);
swap(size_px.width, size_px.height);
rotation = rad90;
}
if (abs(size_mm.width - default_size_mm.width) < threshold_size.width) size_mm.width = default_size_mm.width; // snap to default_size_mm if we are close
if (abs(size_mm.height - default_size_mm.height) < threshold_size.height) size_mm.height = default_size_mm.height;
return CardLayout(card, size_mm, size_px, rotation);
}
void PrintJob::layout_cards() {
page_layouts.push_back(vector<CardLayout>());
double row_top = 0.0, row_height = 0.0, row_width = 0.0;
unordered_set<int> already_laidout_cards;
unordered_set<CardP> already_laidout_cards;
while (true) {
// try to find a card that will fit on the current row
for (int i = 0; i < card_layouts.size(); ++i) {
if (already_laidout_cards.find(i) != already_laidout_cards.end()) continue;
if (card_layouts[i].size_mm.width + row_width >= page_size.width) continue;
if (card_layouts[i].size_mm.height + row_top >= page_size.height) continue;
// the card fits
card_layouts[i].pos.width = row_width;
card_layouts[i].pos.height = row_top;
page_layouts[page_layouts.size()-1].push_back(card_layouts[i]);
already_laidout_cards.insert(i);
if (already_laidout_cards.size() == card_layouts.size()) return;
// move to next spot on the row
row_width += card_layouts[i].size_mm.width + settings.print_spacing;
row_height = max(row_height, card_layouts[i].size_mm.height + settings.print_spacing);
FOR_EACH(layout, sorted_layouts) {
if (already_laidout_cards.find(layout.card) != already_laidout_cards.end()) continue;
if (layout.other_face >= 0) {
CardLayout& other_layout = card_layouts[layout.other_face];
if ( layout.size_mm.width + other_layout.size_mm.width + settings.print_spacing + row_width >= page_size.width) continue;
if (max(layout.size_mm.height, other_layout.size_mm.height) + row_top >= page_size.height) continue;
// the card and its other face fit
layout.pos.width = row_width;
layout.pos.height = row_top;
page_layouts[page_layouts.size()-1].push_back(layout);
already_laidout_cards.emplace(layout.card);
other_layout.pos.width = row_width + layout.size_mm.width + settings.print_spacing;
other_layout.pos.height = row_top;
page_layouts[page_layouts.size()-1].push_back(other_layout);
already_laidout_cards.emplace(other_layout.card);
if (already_laidout_cards.size() >= card_layouts.size()) return;
// move to next spot on the row
row_width += layout.size_mm.width + other_layout.size_mm.width + 2 * settings.print_spacing;
row_height = max(max(row_height, layout.size_mm.height + settings.print_spacing), other_layout.size_mm.height + settings.print_spacing);
}
else {
if (layout.size_mm.width + row_width >= page_size.width) continue;
if (layout.size_mm.height + row_top >= page_size.height) continue;
// the card fits
layout.pos.width = row_width;
layout.pos.height = row_top;
page_layouts[page_layouts.size()-1].push_back(layout);
already_laidout_cards.emplace(layout.card);
if (already_laidout_cards.size() >= card_layouts.size()) return;
// move to next spot on the row
row_width += layout.size_mm.width + settings.print_spacing;
row_height = max(row_height, layout.size_mm.height + settings.print_spacing);
}
goto continue_outer;
}
// no card fits
@@ -89,6 +125,7 @@ void PrintJob::layout_cards() {
continue_outer:;
}
}
void PrintJob::align_cards() {
// for each page
for (int p = 0; p < page_layouts.size(); ++p) {
@@ -139,6 +176,7 @@ void PrintJob::align_cards() {
}
}
}
void PrintJob::center_cards() {
for (int p = 0; p < page_layouts.size(); ++p) {
vector<CardLayout>& page_layout = page_layouts[p];
@@ -234,42 +272,46 @@ void CardsPrintout::drawCards(DC& dc, PrintJobP& job, int page) {
FOR_EACH(card_layout, job->page_layouts[page - 1]) {
drawCard(dc, card_layout);
}
dc.SetUserScale(printer_px_per_mm.width, printer_px_per_mm.height);
dc.SetDeviceOrigin(0, 0);
//dc.SetUserScale(printer_px_per_mm.width, printer_px_per_mm.height);
}
void CardsPrintout::drawCard(DC& dc, PrintJob::CardLayout& card_layout) {
// draw card to its own buffer
wxBitmap buffer(card_layout.size_px.width, card_layout.size_px.height, 32);
// upscale to printer dpi
double card_px_per_mm_width = card_layout.size_px.width / card_layout.size_mm.width;
double scale = printer_px_per_mm.width / card_px_per_mm_width;
// render card to its own dc
wxBitmap buffer(card_layout.size_px.width * scale, card_layout.size_px.height * scale, 32);
wxMemoryDC bufferDC;
bufferDC.SelectObject(buffer);
clearDC(bufferDC,*wxWHITE_BRUSH);
RotatedDC rdc(bufferDC, card_layout.rot, RealRect(0, 0, card_layout.size_px.width, card_layout.size_px.height), 1.0, QUALITY_AA, ROTATION_ATTACH_TOP_LEFT);
RotatedDC rdc(bufferDC, card_layout.rot, RealRect(0, 0, card_layout.size_px.width, card_layout.size_px.height), scale, QUALITY_AA, ROTATION_ATTACH_TOP_LEFT);
viewer.setCard(card_layout.card);
viewer.draw(rdc, *wxWHITE);
bufferDC.SelectObject(wxNullBitmap);
// draw card buffer to page dc
dc.SetUserScale(printer_px_per_mm.width / card_layout.px_per_mm.width, printer_px_per_mm.height / card_layout.px_per_mm.height);
dc.DrawBitmap(buffer, int(card_layout.pos.width * card_layout.px_per_mm.width), int(card_layout.pos.height * card_layout.px_per_mm.height));
// render card dc to page dc
dc.SetDeviceOrigin(int(printer_px_per_mm.width * card_layout.pos.width), int(printer_px_per_mm.height * card_layout.pos.height));
dc.DrawBitmap(buffer, 0, 0);
}
void CardsPrintout::drawCutterLines(DC& dc, PrintJobP& job, int page) {
const vector<PrintJob::CardLayout>& page_layout = job->page_layouts[page - 1];
const vector<PrintJob::CardLayout>& page_layouts = job->page_layouts[page - 1];
const RealSize& page_margin = job->page_margins[page - 1];
int page_width, page_height;
GetPageSizeMM(&page_width, &page_height);
double vertical_line_size = min(10.0, page_margin.height - 3.0);
if (vertical_line_size > 0.0) {
for (int i = 0; i < page_layout.size(); ++i) {
double left_line = page_layout[i].pos.width;
double right_line = left_line + page_layout[i].size_mm.width;
for (int i = 0; i < page_layouts.size(); ++i) {
double left_line = page_layouts[i].pos.width;
double right_line = left_line + page_layouts[i].size_mm.width;
bool draw_left_line = true;
bool draw_right_line = true;
if (settings.print_cutter_lines == CUTTER_NO_INTERSECTION) {
// check if another card is in the way of this cutter line
for (int j = 0; j < page_layout.size(); ++j) {
for (int j = 0; j < page_layouts.size(); ++j) {
if (i == j) continue;
double other_left_line = page_layout[j].pos.width;
double other_right_line = other_left_line + page_layout[j].size_mm.width;
double other_left_line = page_layouts[j].pos.width;
double other_right_line = other_left_line + page_layouts[j].size_mm.width;
if (draw_left_line && left_line - other_left_line > job->threshold_bottom && other_right_line - left_line > job->threshold_bottom) {
draw_left_line = false;
if (!draw_right_line) break;
@@ -280,15 +322,15 @@ void CardsPrintout::drawCutterLines(DC& dc, PrintJobP& job, int page) {
}
}
}
const RealSize& px_per_mm = page_layout[i].px_per_mm;
dc.SetUserScale(printer_px_per_mm.width / px_per_mm.width, printer_px_per_mm.height / px_per_mm.height);
if (draw_left_line) {
dc.DrawLine(wxPoint(px_per_mm.width * left_line, 0.0), wxPoint(px_per_mm.width * left_line, px_per_mm.height * vertical_line_size));
dc.DrawLine(wxPoint(px_per_mm.width * left_line, px_per_mm.height * page_height), wxPoint(px_per_mm.width * left_line, px_per_mm.height * (page_height - vertical_line_size)));
int left = printer_px_per_mm.width * left_line;
dc.DrawLine(wxPoint(left, 0.0), wxPoint(left, printer_px_per_mm.height * vertical_line_size));
dc.DrawLine(wxPoint(left, printer_px_per_mm.height * page_height), wxPoint(left, printer_px_per_mm.height * (page_height - vertical_line_size)));
}
if (draw_right_line) {
dc.DrawLine(wxPoint(px_per_mm.width * right_line, 0.0), wxPoint(px_per_mm.width * right_line, px_per_mm.height * vertical_line_size));
dc.DrawLine(wxPoint(px_per_mm.width * right_line, px_per_mm.height * page_height), wxPoint(px_per_mm.width * right_line, px_per_mm.height * (page_height - vertical_line_size)));
int right = printer_px_per_mm.width * right_line;
dc.DrawLine(wxPoint(right, 0.0), wxPoint(right, printer_px_per_mm.height * vertical_line_size));
dc.DrawLine(wxPoint(right, printer_px_per_mm.height * page_height), wxPoint(right, printer_px_per_mm.height * (page_height - vertical_line_size)));
}
}
} else {
@@ -297,17 +339,17 @@ void CardsPrintout::drawCutterLines(DC& dc, PrintJobP& job, int page) {
double horizontal_line_size = min(10.0, page_margin.width - 3.0);
if (horizontal_line_size > 0.0) {
for (int i = 0; i < page_layout.size(); ++i) {
double top_line = page_layout[i].pos.height;
double bottom_line = top_line + page_layout[i].size_mm.height;
for (int i = 0; i < page_layouts.size(); ++i) {
double top_line = page_layouts[i].pos.height;
double bottom_line = top_line + page_layouts[i].size_mm.height;
bool draw_top_line = true;
bool draw_bottom_line = true;
if (settings.print_cutter_lines == CUTTER_NO_INTERSECTION) {
// check if another card is in the way of this cutter line
for (int j = 0; j < page_layout.size(); ++j) {
for (int j = 0; j < page_layouts.size(); ++j) {
if (i == j) continue;
double other_top_line = page_layout[j].pos.height;
double other_bottom_line = other_top_line + page_layout[j].size_mm.height;
double other_top_line = page_layouts[j].pos.height;
double other_bottom_line = other_top_line + page_layouts[j].size_mm.height;
if (draw_top_line && top_line - other_top_line > job->threshold_bottom && other_bottom_line - top_line > job->threshold_bottom) {
draw_top_line = false;
if (!draw_bottom_line) break;
@@ -318,21 +360,20 @@ void CardsPrintout::drawCutterLines(DC& dc, PrintJobP& job, int page) {
}
}
}
const RealSize& px_per_mm = page_layout[i].px_per_mm;
dc.SetUserScale(printer_px_per_mm.width / px_per_mm.width, printer_px_per_mm.height / px_per_mm.height);
if (draw_top_line) {
dc.DrawLine(wxPoint(0.0, px_per_mm.height * top_line), wxPoint(px_per_mm.width * horizontal_line_size, px_per_mm.height * top_line));
dc.DrawLine(wxPoint(px_per_mm.width * page_width, px_per_mm.height * top_line), wxPoint(px_per_mm.width * (page_width - horizontal_line_size), px_per_mm.height * top_line));
int top = printer_px_per_mm.height * top_line;
dc.DrawLine(wxPoint(0.0, top), wxPoint(printer_px_per_mm.width * horizontal_line_size, top));
dc.DrawLine(wxPoint(printer_px_per_mm.width * page_width, top), wxPoint(printer_px_per_mm.width * (page_width - horizontal_line_size), top));
}
if (draw_bottom_line) {
dc.DrawLine(wxPoint(0.0, px_per_mm.height * bottom_line), wxPoint(px_per_mm.width * horizontal_line_size, px_per_mm.height * bottom_line));
dc.DrawLine(wxPoint(px_per_mm.width * page_width, px_per_mm.height * bottom_line), wxPoint(px_per_mm.width * (page_width - horizontal_line_size), px_per_mm.height * bottom_line));
int bottom = printer_px_per_mm.height * bottom_line;
dc.DrawLine(wxPoint(0.0, bottom), wxPoint(printer_px_per_mm.width * horizontal_line_size, bottom));
dc.DrawLine(wxPoint(printer_px_per_mm.width * page_width, bottom), wxPoint(printer_px_per_mm.width * (page_width - horizontal_line_size), bottom));
}
}
} else {
queue_message(MESSAGE_WARNING, _ERROR_("h margin too small for cutter"));
}
dc.SetUserScale(printer_px_per_mm.width, printer_px_per_mm.height);
}
// ----------------------------------------------------------------------------- : PrintWindow
+5 -5
View File
@@ -44,10 +44,8 @@ public:
RealSize threshold_size;
struct CardLayout {
CardLayout(const CardP& card, const RealSize& size_mm, const RealSize& size_px, Radians rot)
: card(card), size_mm(size_mm), size_px(size_px), rot(rot) {
px_per_mm = RealSize(size_px.width / size_mm.width, size_px.height / size_mm.height);
}
CardLayout(const CardP& card, const RealSize& size_mm, const RealSize& size_px, const Radians& rotation)
: card(card), size_mm(size_mm), size_px(size_px), rot(rotation), other_face(-1) {}
bool operator<(const CardLayout& that) const {
return size_mm.width > that.size_mm.width; // put the widest cards first
@@ -56,15 +54,16 @@ public:
CardP card;
RealSize size_mm;
RealSize size_px;
RealSize px_per_mm;
Radians rot;
RealSize pos;
int other_face;
};
void init(const RealSize& page_size);
RealSize page_size; ///< Size of a page in millimetres
vector<CardLayout> card_layouts; ///< Locations of the cards on the pages
vector<CardLayout> sorted_layouts; ///< Same as card_layouts, but sorted from widest to narrowest
vector<vector<CardLayout>> page_layouts; ///< The CardLayout grouped by page
vector<RealSize> page_margins; ///< The empty space on the sides of the pages
@@ -74,6 +73,7 @@ public:
private:
// calculate the width and height of each card in millimeters
void measure_cards();
CardLayout measure_card(const CardP& card);
// calculate where the cards go on the pages
void layout_cards();
// if two cards are almost aligned, align them