Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ lib@WXPDFDOC_LIBNAME@_la_SOURCES = \
src/pdfimage.cpp \
src/pdfkernel.cpp \
src/pdflayer.cpp \
src/pdflistctrl.cpp \
src/pdfobjects.cpp \
src/pdfocg.cpp \
src/pdfparser.cpp \
Expand Down
17 changes: 17 additions & 0 deletions include/wx/pdfdc.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@
#ifndef _PDF_DC_H_
#define _PDF_DC_H_

#include <wx/defs.h>
#include <wx/cmndata.h>
#include <wx/dc.h>

#include <stack>

#if wxUSE_LISTCTRL
class wxListCtrl;
#endif

#include "wx/pdfdocument.h"
#include "wx/pdffont.h"

Expand Down Expand Up @@ -136,6 +141,18 @@ class WXDLLIMPEXP_PDFDOC wxPdfDC : public wxDC
*/
wxPdfMapModeStyle GetMapModeStyle() const;

#if wxUSE_LISTCTRL
/// Draws a list control's content at the given position
/**
* \param list Pointer to the list control
* \param x Abscissa of the top left corner
* \param y Ordinate of the top left corner
* \param options Export options
*/
void DrawList(wxListCtrl* list, wxCoord x, wxCoord y,
const wxPdfListCtrlOptions& options = wxPdfListCtrlOptions());
#endif

private:
wxDECLARE_DYNAMIC_CLASS(wxPdfDC);
};
Expand Down
17 changes: 17 additions & 0 deletions include/wx/pdfdocument.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
#ifndef _PDF_DOCUMENT_H_
#define _PDF_DOCUMENT_H_

#if wxUSE_LISTCTRL
class wxListCtrl;
#endif

// wxWidgets headers
#include <wx/dynarray.h>
#include <wx/graphics.h>
Expand All @@ -33,6 +37,10 @@
#include "wx/pdfproperties.h"
#include "wx/pdfdoc_version.h"

#if wxUSE_LISTCTRL
#include "wx/pdflistctrl.h"
#endif

#define wxPDF_PRODUCER wxS(PDFDOC_VERSION_STRING)

#define wxPDF_EPSILON 1e-6
Expand Down Expand Up @@ -2970,6 +2978,15 @@ class WXDLLIMPEXP_PDFDOC wxPdfDocument
*/
virtual void WriteXml(const wxString& str);

#if wxUSE_LISTCTRL
/// Adds a list control's content to the document
/**
* \param list Pointer to the list control
* \param options Export options
*/
virtual void AddList(wxListCtrl* list, const wxPdfListCtrlOptions& options = wxPdfListCtrlOptions());
#endif

/// Adds a check box field at the current position
/**
* Adds a check box to the list of form fields at the current position
Expand Down
248 changes: 248 additions & 0 deletions include/wx/pdflistctrl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
///////////////////////////////////////////////////////////////////////////////
// Name: pdflistctrl.h
// Purpose:
// Author: Blake Madden
// Created: 2026-06-10
// Copyright: (c) Blake Madden
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////

/// \file pdflistctrl.h Interface of the wxPdfListCtrlOptions class

#ifndef _PDF_LISTCTRL_H_
#define _PDF_LISTCTRL_H_

// wxWidgets headers
#include <wx/defs.h>
#include <wx/font.h>

// wxPdfDocument headers
#include "wx/pdfdocdef.h"
#include "wx/pdfcolour.h"
#include "wx/pdffont.h"

class wxListCtrl;

/// Table rendering style for wxListCtrl export.
enum wxPdfListCtrlStyle
{
wxPDF_LISTCTRL_STYLE_GRID, ///< Full grid with borders and optional cell fills (default)
wxPDF_LISTCTRL_STYLE_SIMPLE ///< Horizontal rules only — no vertical lines or cell fills (LaTeX \e booktabs style)
};

/// Options that control how a wxListCtrl is rendered into a PDF document.
/**
* Pass an instance to wxPdfDocument::AddList() or wxPdfDC::DrawList() to
* configure colours, fonts, borders, and layout behaviour.
*
* \par Example
* \code
* // Standard grid export
* wxPdfDocument doc;
* doc.AddPage();
*
* wxPdfListCtrlOptions options;
* options.SetHeaderBackgroundColour(wxPdfColour(220, 220, 255));
* options.SetAlternateRowBackgroundColour(wxPdfColour(245, 245, 245));
* doc.AddList(myListCtrl, options);
* doc.SaveAsFile("grid.pdf");
*
* // LaTeX booktabs-style export stretched to page width
* wxPdfDocument doc2;
* doc2.AddPage();
*
* wxPdfListCtrlOptions simple;
* simple.SetStyle(wxPDF_LISTCTRL_STYLE_SIMPLE);
* simple.SetFitToPage(true);
* doc2.AddList(myListCtrl, simple);
* doc2.SaveAsFile("simple.pdf");
* \endcode
*
* \see wxPdfDocument::AddList(), wxPdfDC::DrawList()
*/
class WXDLLIMPEXP_PDFDOC wxPdfListCtrlOptions
{
public:
/// Default constructor
wxPdfListCtrlOptions();

/// Set the font for the column headers
/**
* \param font The font to use for headers
*/
void SetHeaderFont(const wxFont& font) { m_headerFont = font; }

/// Get the font for the column headers
/**
* \return The header font
*/
wxFont GetHeaderFont() const { return m_headerFont; }

/// Set the font for the list items
/**
* \param font The font to use for items
*/
void SetBodyFont(const wxFont& font) { m_bodyFont = font; }

/// Get the font for the list items
/**
* \return The body font
*/
wxFont GetBodyFont() const { return m_bodyFont; }

/// Set the PDF font for the column headers (takes precedence over SetHeaderFont())
/**
* \param font The wxPdfFont to use for headers
*/
void SetHeaderPdfFont(const wxPdfFont& font) { m_headerPdfFont = font; }

/// Get the PDF font for the column headers
/**
* \return The header PDF font
*/
wxPdfFont GetHeaderPdfFont() const { return m_headerPdfFont; }

/// Set the PDF font for the list items (takes precedence over SetBodyFont())
/**
* \param font The wxPdfFont to use for items
*/
void SetBodyPdfFont(const wxPdfFont& font) { m_bodyPdfFont = font; }

/// Get the PDF font for the list items
/**
* \return The body PDF font
*/
wxPdfFont GetBodyPdfFont() const { return m_bodyPdfFont; }

/// Set the background colour for the column headers
/**
* \param colour The background colour
*/
void SetHeaderBackgroundColour(const wxPdfColour& colour) { m_headerBackgroundColour = colour; }

/// Get the background colour for the column headers
/**
* \return The header background colour
*/
wxPdfColour GetHeaderBackgroundColour() const { return m_headerBackgroundColour; }

/// Set the text colour for the column headers
/**
* \param colour The text colour
*/
void SetHeaderTextColour(const wxPdfColour& colour) { m_headerTextColour = colour; }

/// Get the text colour for the column headers
/**
* \return The header text colour
*/
wxPdfColour GetHeaderTextColour() const { return m_headerTextColour; }

/// Set the background colour for alternate rows
/**
* \param colour The background colour for even rows
*/
void SetAlternateRowBackgroundColour(const wxPdfColour& colour) { m_alternateRowBackgroundColour = colour; }

/// Get the background colour for alternate rows
/**
* \return The alternate row background colour
*/
wxPdfColour GetAlternateRowBackgroundColour() const { return m_alternateRowBackgroundColour; }

/// Set the colour for borders
/**
* \param colour The border colour
*/
void SetBorderColour(const wxPdfColour& colour) { m_borderColour = colour; }

/// Get the colour for borders
/**
* \return The border colour
*/
wxPdfColour GetBorderColour() const { return m_borderColour; }

/// Set whether to draw horizontal borders between rows
/**
* \param draw true to draw row borders
*/
void SetDrawRowBorders(bool draw) { m_drawRowBorders = draw; }

/// Check whether to draw horizontal borders between rows
/**
* \return true if row borders should be drawn
*/
bool GetDrawRowBorders() const { return m_drawRowBorders; }

/// Set whether to draw vertical borders between columns
/**
* \param draw true to draw column borders
*/
void SetDrawColumnBorders(bool draw) { m_drawColumnBorders = draw; }

/// Check whether to draw vertical borders between columns
/**
* \return true if column borders should be drawn
*/
bool GetDrawColumnBorders() const { return m_drawColumnBorders; }

/// Set whether to show "Continued on next page" and "(continued)" labels
/**
* \param show true to show the labels
*/
void SetShowContinued(bool show) { m_showContinued = show; }

/// Check whether to show "Continued on next page" and "(continued)" labels
/**
* \return true if labels should be shown
*/
bool GetShowContinued() const { return m_showContinued; }

/// Set whether to stretch the table to the full printable page width.
/**
* When enabled, all columns are scaled proportionally so that the table
* fills the available width between the left and right margins, analogous
* to LaTeX's \c tabularx or \c tabular* with \c \\linewidth. Multi-column
* layout is disabled when this option is active.
* \param fit true to stretch to full page width
*/
void SetFitToPage(bool fit) { m_fitToPage = fit; }

/// Check whether the table is stretched to the full printable page width.
/**
* \return true if full-page-width mode is active
*/
bool GetFitToPage() const { return m_fitToPage; }

/// Set the table rendering style.
/**
* \c wxPDF_LISTCTRL_STYLE_GRID (default) draws full cell borders and honours fill colours.
* \c wxPDF_LISTCTRL_STYLE_SIMPLE renders only a top rule, a rule below the header, and a
* bottom rule with no vertical lines or cell fills, analogous to the LaTeX \c booktabs package.
* \param style The rendering style
*/
void SetStyle(wxPdfListCtrlStyle style) { m_style = style; }

/// Get the table rendering style.
/**
* \return The current rendering style
*/
wxPdfListCtrlStyle GetStyle() const { return m_style; }

private:
wxFont m_headerFont;
wxFont m_bodyFont;
wxPdfFont m_headerPdfFont;
wxPdfFont m_bodyPdfFont;
wxPdfColour m_headerBackgroundColour;
wxPdfColour m_headerTextColour;
wxPdfColour m_alternateRowBackgroundColour;
wxPdfColour m_borderColour;
bool m_drawRowBorders;
bool m_drawColumnBorders;
bool m_showContinued;
bool m_fitToPage;
wxPdfListCtrlStyle m_style;
};

#endif
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ on the FPDF web site are incorporated into wxPdfDocument.
- **Document Protection**: Support for document encryption (including AES-256) and permission management.
- **Templates & Layers**: Import pages from existing PDF documents as templates and organize content with layers (Optional Content Groups).
- **Markup & Tables**: Use a simple XML markup language for styled text and complex tables with multi-page support.
- **wxListCtrl Export**: Export any `wxListCtrl` directly to PDF via `wxPdfDocument::AddList()` or `wxPdfDC::DrawList()`. Supports column headers repeated across pages, alternating row colours, per-item text/background colours, full-page-width layout, and a LaTeX *booktabs*-style rendering with horizontal rules only.
- **Integration**: Includes `wxPdfDC` and `wxPdfGraphicsContext`, providing seamless integration with the wxWidgets `wxDC` and `wxGraphicsContext` APIs and the printing framework.
- **Standards**: Support for PDF/A-1B conformance.

Expand Down
21 changes: 21 additions & 0 deletions samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,24 @@ set_target_properties(pdfgc PROPERTIES
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${WXPDFDOC_ROOT}/samples/pdfgc"
VS_DEBUGGER_WORKING_DIRECTORY "${WXPDFDOC_ROOT}/samples/pdfgc"
)

# ---------------------------------------------------------------------------
# listctrl sample executable (wxListCtrl export demo)
# ---------------------------------------------------------------------------
file(GLOB LISTCTRL_SRCS CONFIGURE_DEPENDS ${WXPDFDOC_ROOT}/samples/listctrl/*.cpp)

add_executable(listctrl WIN32 ${LISTCTRL_SRCS})
if(WIN32)
target_sources(listctrl PRIVATE ${WXPDFDOC_ROOT}/samples/listctrl/listctrlsample.rc)
endif()
target_include_directories(listctrl PRIVATE ${WXPDFDOC_ROOT}/samples/listctrl)
target_link_libraries(listctrl PRIVATE wxpdfdoc)

set_target_properties(listctrl PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${WXPDFDOC_ROOT}/samples/listctrl"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${WXPDFDOC_ROOT}/samples/listctrl"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${WXPDFDOC_ROOT}/samples/listctrl"
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${WXPDFDOC_ROOT}/samples/listctrl"
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${WXPDFDOC_ROOT}/samples/listctrl"
VS_DEBUGGER_WORKING_DIRECTORY "${WXPDFDOC_ROOT}/samples/listctrl"
)
Loading
Loading