diff --git a/src/data/card.cpp b/src/data/card.cpp index 03763e9f..f90a17ed 100644 --- a/src/data/card.cpp +++ b/src/data/card.cpp @@ -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& 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> Card::getLinkedCards(const Set& set) { +vector> Card::getLinkedCards(const vector& cards) { unordered_map links{ { linked_card_1, linked_relation_1 }, { linked_card_2, linked_relation_2 }, @@ -273,13 +273,31 @@ vector> Card::getLinkedCards(const Set& set) { { linked_card_4, linked_relation_4 } }; vector> 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> Card::getLinkedCards(const Set& set) { + return getLinkedCards(set.cards); +} + +CardP Card::getOtherFace(const vector& cards) { + unordered_set 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& Card::extraDataFor(const StyleSheet& stylesheet) { return extra_data.get(stylesheet.name(), stylesheet.extra_card_fields); diff --git a/src/data/card.hpp b/src/data/card.hpp index f5170b73..92fb9f83 100644 --- a/src/data/card.hpp +++ b/src/data/card.hpp @@ -35,7 +35,7 @@ public: Card(); /// Creates a card using the given game Card(const Game& game); - + /// The values on the fields of the card. /** The indices should correspond to the card_fields in the Game */ IndexMap data; @@ -60,26 +60,26 @@ 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 styling_data; /// Is the styling_data set? bool has_styling; - + /// Extra values for specitic stylesheets, indexed by stylesheet name DelayedIndexMaps extra_data; /// Styling information for a particular stylesheet IndexMap& extraDataFor(const StyleSheet& stylesheet); - + /// Keyword usage statistics vector> keyword_usage; - + /// Get the identification of this card, an identification is something like a name, title, etc. /** May return "" */ String identification() const; /// Does any field contains the given query string? bool contains(QuickFilterPart const& query) const; - + /// Link or unlink other cards to this card void link(const Set& set, const vector& linked_cards, const String& selected_relation, const String& linked_relation); void link(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation); @@ -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> getLinkedCards(const vector& cards); vector> getLinkedCards(const Set& set); + CardP getOtherFace(const vector& cards); + CardP getOtherFace(const Set& set); /// Find a value in the data by name and type template T& value(const String& name) { @@ -112,7 +115,7 @@ public: } throw InternalError(_("Expected a card field with name '")+name+_("'")); } - + DECLARE_REFLECTION(); }; diff --git a/src/data/format/image.cpp b/src/data/format/image.cpp index eb9960b2..d482720f 100644 --- a/src/data/format/image.cpp +++ b/src/data/format/image.cpp @@ -100,7 +100,7 @@ Bitmap export_bitmap(const SetP& set, const vector& cards, bool scale_to_ if (scale_to_lowest_dpi) { double dpi = max(set->stylesheetFor(card).card_dpi, 150.0); scale *= lowest_dpi / dpi; - } + } scales_out.push_back(scale); UnzoomedDataViewer viewer = UnzoomedDataViewer(scale, angle_radians); viewer.setSet(set); @@ -124,7 +124,7 @@ Bitmap export_bitmap(const SetP& set, const vector& cards, bool scale_to_ globalDC.SelectObject(global_bitmap); clearDC(globalDC, *wxWHITE_BRUSH); int offset = 0; - FOR_EACH(bitmap, bitmaps) { + FOR_EACH(bitmap, bitmaps) { offsets_out.push_back(offset); globalDC.SetDeviceOrigin(offset, 0); globalDC.DrawBitmap(bitmap, 0, 0); @@ -138,57 +138,58 @@ Bitmap export_bitmap(const SetP& set, const vector& cards, bool scale_to_ Image export_image(const SetP& set, const CardP& card, const double zoom, const Radians angle_radians) { Bitmap bitmap = export_bitmap(set, card, zoom, angle_radians); - Image img = bitmap.ConvertToImage(); - String data = _("["); - IndexMap& 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"] = ""; - for(IndexMap::iterator it = card_data.begin() ; it != card_data.end() ; ++it) { + Image img = bitmap.ConvertToImage(); + String data = _("["); + IndexMap& card_data = card->data; + boost::json::object& cardv = mse_to_json(card, set.get()); + boost::json::object& cardv_data = cardv["data"].as_object(); + StyleSheetP stylesheet = set->stylesheetForP(card); + if (!settings.stylesheetSettingsFor(*stylesheet).card_notes_export()) cardv["notes"] = ""; + for(IndexMap::iterator it = card_data.begin() ; it != card_data.end() ; ++it) { ImageValue* value = dynamic_cast(it->get()); - if (value && !value->filename.empty()) { - FieldP field = (*it)->fieldP; - StyleP style = set->stylesheetFor(card).card_style.at(field->index); - if (style) { + if (value && !value->filename.empty()) { + FieldP field = (*it)->fieldP; + StyleP style = stylesheet->card_style.at(field->index); + if (style) { style->update(set->getContext(card)); - std::string rect = style->getExternalRectString(zoom, 0).ToStdString(); - cardv_data[field->name.ToStdString()] = rect; - } - } - } + std::string rect = style->getExternalRectString(zoom, 0).ToStdString(); + cardv_data[field->name.ToStdString()] = rect; + } + } + } data += json_ugly_print(cardv) + _("]"); img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, data); return img; } Image export_image(const SetP& set, const vector& cards, bool scale_to_lowest_dpi, int padding, const double zoom, const Radians angle_radians) { - vector scales; - vector offsets; + vector scales; + vector offsets; Bitmap bitmap = export_bitmap(set, cards, scale_to_lowest_dpi, padding, zoom, angle_radians, scales, offsets); - Image img = bitmap.ConvertToImage(); + Image img = bitmap.ConvertToImage(); String data = _("["); - for (int i = 0; i < cards.size(); ++i) { - if (i > 0) data += _(","); + for (int i = 0; i < cards.size(); ++i) { + if (i > 0) data += _(","); CardP card = cards[i]; - IndexMap& 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"] = ""; - for(IndexMap::iterator it = card_data.begin() ; it != card_data.end() ; ++it) { + IndexMap& card_data = card->data; + boost::json::object& cardv = mse_to_json(card, set.get()); + boost::json::object& cardv_data = cardv["data"].as_object(); + StyleSheetP stylesheet = set->stylesheetForP(card); + if (!settings.stylesheetSettingsFor(*stylesheet).card_notes_export()) cardv["notes"] = ""; + for(IndexMap::iterator it = card_data.begin() ; it != card_data.end() ; ++it) { ImageValue* value = dynamic_cast(it->get()); - if (value && !value->filename.empty()) { - FieldP field = (*it)->fieldP; - StyleSheetP stylesheet = set->stylesheetForP(card); + if (value && !value->filename.empty()) { + FieldP field = (*it)->fieldP; StyleP style = stylesheet->card_style.at(field->index); - if (style) { + if (style) { style->update(set->getContext(card)); - std::string rect = style->getExternalRectString(scales[i], offsets[i]).ToStdString(); - cardv_data[field->name.ToStdString()] = rect; - } - } - } + std::string rect = style->getExternalRectString(scales[i], offsets[i]).ToStdString(); + cardv_data[field->name.ToStdString()] = rect; + } + } + } data += json_ugly_print(cardv); - } + } data += _("]"); img.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, data); return img; @@ -197,11 +198,11 @@ Image export_image(const SetP& set, const vector& 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& cards, - const String& path, const String& filename_template, FilenameConflicts conflicts) + const String& path, const String& filename_template, FilenameConflicts conflicts) { wxBusyCursor busy; // Script diff --git a/src/gui/card_link_window.cpp b/src/gui/card_link_window.cpp index cfe9320b..f17fb00b 100644 --- a/src/gui/card_link_window.cpp +++ b/src/gui/card_link_window.cpp @@ -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 () diff --git a/src/gui/print_window.cpp b/src/gui/print_window.cpp index 9eb01e2e..27d1fa2b 100644 --- a/src/gui/print_window.cpp +++ b/src/gui/print_window.cpp @@ -29,45 +29,81 @@ void PrintJob::init(const RealSize& page_size) { layout_cards(); align_cards(); center_cards(); -} -void PrintJob::measure_cards() { +} + +void PrintJob::measure_cards() { + unordered_set 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); + } + sorted_layouts = vector(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; } - std::sort(card_layouts.begin(), card_layouts.end()); -} + 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()); double row_top = 0.0, row_height = 0.0, row_width = 0.0; - unordered_set already_laidout_cards; + unordered_set 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 @@ -88,7 +124,8 @@ void PrintJob::layout_cards() { row_width = row_height = 0.0; continue_outer:; } -} +} + void PrintJob::align_cards() { // for each page for (int p = 0; p < page_layouts.size(); ++p) { @@ -138,7 +175,8 @@ void PrintJob::align_cards() { continue_outer:; } } -} +} + void PrintJob::center_cards() { for (int p = 0; p < page_layouts.size(); ++p) { vector& page_layout = page_layouts[p]; @@ -233,43 +271,47 @@ bool CardsPrintout::OnPrintPage(int page) { 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& page_layout = job->page_layouts[page - 1]; + const vector& 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))); + if (draw_left_line) { + 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 diff --git a/src/gui/print_window.hpp b/src/gui/print_window.hpp index 166528e0..d9a69468 100644 --- a/src/gui/print_window.hpp +++ b/src/gui/print_window.hpp @@ -44,27 +44,26 @@ 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 } CardP card; - RealSize size_mm; + RealSize size_mm; RealSize size_px; - RealSize px_per_mm; - Radians rot; + Radians rot; RealSize pos; + int other_face; }; void init(const RealSize& page_size); RealSize page_size; ///< Size of a page in millimetres vector card_layouts; ///< Locations of the cards on the pages + vector sorted_layouts; ///< Same as card_layouts, but sorted from widest to narrowest vector> page_layouts; ///< The CardLayout grouped by page vector 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