diff --git a/src/gui/print_window.cpp b/src/gui/print_window.cpp index dd26c6b0..4b892cf9 100644 --- a/src/gui/print_window.cpp +++ b/src/gui/print_window.cpp @@ -10,9 +10,12 @@ #include #include #include +#include +#include #include DECLARE_TYPEOF_COLLECTION(CardP); +DECLARE_POINTER_TYPE(PageLayout); // ----------------------------------------------------------------------------- : Buffering DC @@ -31,7 +34,7 @@ DECLARE_TYPEOF_COLLECTION(CardP); */ class TextBufferDC : public wxMemoryDC { public: - TextBufferDC(UInt width, UInt height); + TextBufferDC(int width, int height); virtual void DoDrawText(const String& str, int x, int y); virtual void DoDrawRotatedText(const String& str, int x, int y, double angle); @@ -47,9 +50,10 @@ class TextBufferDC : public wxMemoryDC { int x, y; String text; double angle; + double user_scale_x, user_scale_y; - TextDraw(wxFont font, Color color, int x, int y, String text, double angle = 0) - : font(font), color(color), x(x), y(y), text(text), angle(angle) + 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), user_scale_x(user_scale_x), user_scale_y(user_scale_y), x(x), y(y), text(text), angle(angle) {} }; public: @@ -59,7 +63,7 @@ class TextBufferDC : public wxMemoryDC { Bitmap buffer; }; -TextBufferDC::TextBufferDC(UInt width, UInt height) +TextBufferDC::TextBufferDC(int width, int height) : buffer(width, height, 32) { SelectObject(buffer); @@ -67,10 +71,14 @@ TextBufferDC::TextBufferDC(UInt width, UInt height) clearDC(*this,*wxWHITE_BRUSH); } void TextBufferDC::DoDrawText(const String& str, int x, int y) { - text.push_back( new_shared5(GetFont(), GetTextForeground(), x, y, str) ); + double usx,usy; + GetUserScale(&usx, &usy); + text.push_back( new_shared7(GetFont(), GetTextForeground(), usx, usy, x, y, str) ); } void TextBufferDC::DoDrawRotatedText(const String& str, int x, int y, double angle) { - text.push_back( new_shared6(GetFont(), GetTextForeground(), x, y, str, angle) ); + double usx,usy; + GetUserScale(&usx, &usy); + text.push_back( new_shared8(GetFont(), GetTextForeground(), usx, usy, x, y, str, angle) ); } DECLARE_TYPEOF_COLLECTION(TextBufferDC::TextDrawP); @@ -79,6 +87,9 @@ void TextBufferDC::drawToDevice(DC& dc, int x, int y) { SelectObject(wxNullBitmap); dc.DrawBitmap(buffer, x, y); 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.SetTextForeground(t->color); if (t->angle) { @@ -86,45 +97,139 @@ void TextBufferDC::drawToDevice(DC& dc, int x, int y) { } else { dc.DrawText(t->text, t->x + x, t->y + y); } + dc.SetUserScale(usx, usy); } } // ----------------------------------------------------------------------------- : Layout -/// Layout of a page of cards -class PageLayout { - public: - RealSize card_size; ///< Size of a card - RealSize card_space; ///< Spacing between cards - double margin_left, margin_right, margin_top, margin_bottom; ///< Page margins - int rows, cols; ///< Number of rows/columns of cards - bool landscape; ///< Are cards rotated to landscape orientation? -}; +PageLayout::PageLayout() + : margin_left(0), margin_right(0), margin_top(0), margin_bottom(0) + , rows(0), cols(0), card_landscape(false) +{} + +PageLayout::PageLayout(const StyleSheet& stylesheet, const RealSize& page_size) + : page_size(page_size) + , 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 /// A printout object specifying how to print a specified set of cards -class CardsPrintout : wxPrintout { +class CardsPrintout : public wxPrintout { public: CardsPrintout(const SetP& set, const vector& cards); - /// Determine card size, cards per row - void OnPreparePrinting(); /// 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 - bool HasPage(int page); + virtual bool HasPage(int page); + /// Determine the layout + virtual void OnPreparePrinting(); /// Print a page - bool OnPrintPage(int page); + virtual bool OnPrintPage(int page); private: - PageLayout layout; + PageLayoutP layout; + SetP set; + vector 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 - void drawCard(DC& dc, const CardP& card, size_t card_nr); - /// Draw a card at the specified coordinates - void drawCard(DC& dc, const CardP& card, double x, double y, int rotation = 0); + void drawCard(DC& dc, const CardP& card, int card_nr); }; +CardsPrintout::CardsPrintout(const SetP& set, const vector& 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(*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 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) { if (wnd.isSelected(c)) selected.push_back(c); } -/* // Show the print preview - wxPreviewFrame frame = new wxPreviewFrame( + // Show the print preview + wxPreviewFrame* frame = new wxPreviewFrame( new wxPrintPreview( new CardsPrintout(set, selected), new CardsPrintout(set, selected) @@ -146,7 +251,6 @@ void print_preview(Window* parent, const SetP& set) { frame->Initialize(); frame->Maximize(true); frame->Show(); -*/ } 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) { if (wnd.isSelected(c)) selected.push_back(c); } -/* // Print the cards + // Print the cards wxPrinter p; CardsPrintout pout(set, selected); p.Print(parent, &pout, true); -*/ } diff --git a/src/gui/print_window.hpp b/src/gui/print_window.hpp index ec61f44f..103cd4f7 100644 --- a/src/gui/print_window.hpp +++ b/src/gui/print_window.hpp @@ -10,8 +10,11 @@ // ----------------------------------------------------------------------------- : Includes #include +#include +#include DECLARE_POINTER_TYPE(Set); +class StyleSheet; // ----------------------------------------------------------------------------- : Printing @@ -21,5 +24,27 @@ void print_preview(Window* parent, const SetP& set); /// Print the given 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 #endif diff --git a/src/util/smart_ptr.hpp b/src/util/smart_ptr.hpp index 97f2c263..4bdc3a93 100644 --- a/src/util/smart_ptr.hpp +++ b/src/util/smart_ptr.hpp @@ -75,6 +75,16 @@ template 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(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 +inline shared_ptr 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(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 +inline shared_ptr 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(new T(a0, a1, a2, a3, a4, a5, a6, a7, a8)); +} // ----------------------------------------------------------------------------- : Intrusive pointers