ADDED: Go to page hyperlinks in schematic editor (virtual page numbers)

The problem is that "real" page numbers can be duplicated, so we work around it
by using virtual page numbers instead which are guaranteed unique.

Example "goto:3" will go to page 3. If customised page numbers are used such as
a, b, c, then to go to page b, we should specify goto:2 (i.e. the virtual page
number).
This commit is contained in:
Roberto Fernandez Bautista 2022-07-03 16:19:55 +01:00 committed by Jeff Young
parent 5d90f3f54f
commit 9b007ca4bf
7 changed files with 95 additions and 26 deletions

View File

@ -983,7 +983,33 @@ bool EDA_TEXT::ValidateHyperlink( const wxString& aURL )
{
wxURL url;
return aURL.IsEmpty() || url.SetURL( aURL ) == wxURL_NOERR;
return aURL.IsEmpty() || url.SetURL( aURL ) == wxURL_NOERR || IsGotoPageHyperlink( aURL );
}
bool EDA_TEXT::IsGotoPageHyperlink( const wxString& aURL, int* aDestination )
{
wxString dest;
if( !aURL.StartsWith( "goto:", &dest ) )
return false;
long num;
bool retval = dest.ToLong( &num );
if( !retval || num < 0 )
return false;
if( aDestination )
*aDestination = static_cast<int>( num );
return true;
}
wxString EDA_TEXT::GotoPageHyperlinkString( const int& aDestination )
{
return wxString::Format( "goto:%d", aDestination );
}

View File

@ -34,6 +34,7 @@
#include <wx/zstream.h>
#include <advanced_config.h>
#include <eda_text.h> // for IsGotoPageHyperlink
#include <ignore.h>
#include <macros.h>
#include <trigo.h>
@ -741,8 +742,8 @@ void PDF_PLOTTER::ClosePage()
closePdfObject();
}*/
// Write out all "goto" hyperlinks for the page as link annotations (compatible with pdf 1.0)
for( const std::pair<BOX2I, wxString>& linkPair : m_urlHyperlinksInPage )
// Allocate all hyperlink objects for the page and calculate their position in user space coordinates
for( const std::pair<BOX2I, wxString>& linkPair : m_hyperlinksInPage )
{
const BOX2I& box = linkPair.first;
const wxString& url = linkPair.second;
@ -754,12 +755,11 @@ void PDF_PLOTTER::ClosePage()
userSpaceBox.SetOrigin( bottomLeft );
userSpaceBox.SetEnd( topRight );
hyperlinkHandles.push_back( startPdfObject() );
hyperlinkHandles.push_back( allocPdfObject() );
m_urlHyperlinksHandles.insert( { hyperlinkHandles.back(), { userSpaceBox, url } } );
m_hyperlinkHandles.insert( { hyperlinkHandles.back(), { userSpaceBox, url } } );
}
//
// TODO use allocPdfObject() !!
int hyperLinkArrayHandle = -1;
// If we have added any annotation links, create an array containing all the objects
@ -807,8 +807,8 @@ void PDF_PLOTTER::ClosePage()
// Mark the page stream as idle
m_pageStreamHandle = 0;
//
m_urlHyperlinksInPage.clear();
// Clean up
m_hyperlinksInPage.clear();
}
@ -819,8 +819,8 @@ bool PDF_PLOTTER::StartPlot()
// First things first: the customary null object
m_xrefTable.clear();
m_xrefTable.push_back( 0 );
m_urlHyperlinksInPage.clear();
m_urlHyperlinksHandles.clear();
m_hyperlinksInPage.clear();
m_hyperlinkHandles.clear();
/* The header (that's easy!). The second line is binary junk required
to make the file binary from the beginning (the important thing is
@ -895,7 +895,7 @@ bool PDF_PLOTTER::EndPlot()
fputs( ">>\n", m_outputFile );
closePdfObject();
for( const std::pair<int,std::pair<BOX2D, wxString>>& handlePair : m_urlHyperlinksHandles )
for( const std::pair<int,std::pair<BOX2D, wxString>>& handlePair : m_hyperlinkHandles )
{
const int& linkhandle = handlePair.first;
const std::pair<BOX2D, wxString>& linkpair = handlePair.second;
@ -907,10 +907,37 @@ bool PDF_PLOTTER::EndPlot()
fprintf( m_outputFile,
"<< /Type /Annot\n"
" /Subtype /Link\n"
" /Rect[%g %g %g %g] /Border[16 16 1]\n"
" /Dest [%d 0 R] >>\n" // /D [3 0 R /FitR 4 399 199 533]
" /Rect[%g %g %g %g] /Border[16 16 1]\n",
box.GetLeft(), box.GetBottom(), box.GetRight(), box.GetTop() );
int pageIdx = -1;
if( EDA_TEXT::IsGotoPageHyperlink( url, &pageIdx ) )
{
if( pageIdx <= m_pageHandles.size() && pageIdx > 0 )
{
fprintf( m_outputFile,
" /Dest [%d 0 R] >>\n"
">>\n",
box.GetLeft(), box.GetBottom(), box.GetRight(), box.GetTop(), m_pageHandles[0] );
m_pageHandles[pageIdx - 1] );
//todo: do we want to support specifying zoom factor/ position? e.g. /FitR
}
else
{
// destination page is not being plotted, assign the NOP action to the link
fprintf( m_outputFile,
" /A << /Type /Action /S /NOP >>\n"
">>\n" );
}
}
else
{
fprintf( m_outputFile,
" /A << /Type /Action /S /URI /URI %s >>\n"
">>\n",
encodeStringForPlotter( url ).c_str() );
}
closePdfObject();
}
@ -1056,8 +1083,8 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
}
void PDF_PLOTTER::HyperlinkBoxURL( const BOX2I& aBox, const wxString& aDestinationURL )
void PDF_PLOTTER::HyperlinkBox( const BOX2I& aBox, const wxString& aDestinationURL )
{
m_urlHyperlinksInPage.push_back( std::make_pair( aBox, aDestinationURL ) );
m_hyperlinksInPage.push_back( std::make_pair( aBox, aDestinationURL ) );
}

View File

@ -485,7 +485,7 @@ void SCH_TEXT::Plot( PLOTTER* aPlotter, bool aBackground ) const
}
if( HasHyperlink() )
aPlotter->HyperlinkBoxURL( GetBoundingBox(), GetHyperlink() );
aPlotter->HyperlinkBox( GetBoundingBox(), GetHyperlink() );
}

View File

@ -385,7 +385,7 @@ void SCH_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground ) const
}
if( HasHyperlink() )
aPlotter->HyperlinkBoxURL( GetBoundingBox(), GetHyperlink() );
aPlotter->HyperlinkBox( GetBoundingBox(), GetHyperlink() );
}

View File

@ -335,6 +335,22 @@ public:
*/
static bool ValidateHyperlink( const wxString& aURL );
/**
* Check if aURL is a valid "goto" hyperlink.
*
* @param aURL String to validate
* @param aDestinationIdx optional. pointer to populate with the page index destination
* @return true if aURL is a valid hyperlink
*/
static bool IsGotoPageHyperlink( const wxString& aURL, int* aDestination = nullptr );
/**
* Generate a hyperlink string that goes to the page number specified
* @param aDestination Virtual page number to go to. Note that the root sheet is 1.
* @return A hyperlink String that goes to the page number specified
*/
static wxString GotoPageHyperlinkString( const int& aDestination );
protected:
/**
* A hyperlink to a URL or file in the system. If empty, this text object is not a hyperlink

View File

@ -440,9 +440,9 @@ public:
* Create a clickable hyperlink with a rectangular click area
*
* @aBox is the rectangular click target
* @aDestinationURL is the target
* @aDestinationURL is the target URL
*/
virtual void HyperlinkBoxURL( const BOX2I& aBox, const wxString& aDestinationURL )
virtual void HyperlinkBox( const BOX2I& aBox, const wxString& aDestinationURL )
{
// NOP for most plotters.
}

View File

@ -352,7 +352,7 @@ public:
KIFONT::FONT* aFont = nullptr,
void* aData = nullptr ) override;
virtual void HyperlinkBoxURL( const BOX2I& aBox, const wxString& aDestinationURL ) override;
virtual void HyperlinkBox( const BOX2I& aBox, const wxString& aDestinationURL ) override;
/**
* PDF images are handles as inline, not XObject streams...
@ -417,11 +417,11 @@ protected:
FILE* m_workFile; ///< Temporary file to construct the stream before zipping
std::vector<long> m_xrefTable; ///< The PDF xref offset table
///< List of loaded URLs in current page
std::vector<std::pair<BOX2I, wxString>> m_urlHyperlinksInPage;
///< List of loaded hyperlinks in current page
std::vector<std::pair<BOX2I, wxString>> m_hyperlinksInPage;
///< Handles for all the hyperlink objects that will be deferred
std::map<int, std::pair<BOX2D, wxString>> m_urlHyperlinksHandles;
std::map<int, std::pair<BOX2D, wxString>> m_hyperlinkHandles;
};