Replace `~...~` overbar syntax with `~{...}`

Fixes https://gitlab.com/kicad/code/kicad/issues/8134

Fixes https://gitlab.com/kicad/code/kicad/issues/4227
This commit is contained in:
Mikolaj Wielgus 2021-06-05 15:52:58 +02:00 committed by Jeff Young
parent 7fdbe2f387
commit 3d520ebe1e
6 changed files with 163 additions and 193 deletions

View File

@ -248,7 +248,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
// because only this line can change the bounding box
for( unsigned ii = 1; ii < text.size(); ii++ )
{
if( text[ii-1] == '~' && text[ii] != '~' )
if( text[ii-1] == '~' && text[ii] == '{' )
{
hasOverBar = true;
break;

View File

@ -1303,52 +1303,54 @@ void OPENGL_GAL::BitmapText( const wxString& aText, const VECTOR2D& aPosition,
break;
}
int i = 0;
int overbarDepth = -1;
int braceNesting = 0;
for( UTF8::uni_iter chIt = text.ubegin(), end = text.uend(); chIt < end; ++chIt )
{
unsigned int c = *chIt;
wxASSERT_MSG( c != '\n' && c != '\r', wxT( "No support for multiline bitmap text yet" ) );
wxASSERT_MSG( *chIt != '\n' && *chIt != '\r',
wxT( "No support for multiline bitmap text yet" ) );
bool wasOverbar = overbar;
bool wasOverbar = overbarDepth == -1;
if( c == '~' )
if( *chIt == '~' && overbarDepth == -1 )
{
if( ++chIt == end )
break;
UTF8::uni_iter lookahead = chIt;
c = *chIt;
if( c == '~' )
if( ++lookahead != end && *lookahead == '{' )
{
// double ~ is really a ~ so go ahead and process the second one
// so what's a triple ~? It could be a real ~ followed by an overbar, or
// it could be an overbar followed by a real ~. The old algorithm did the
// former so we will too....
}
else
{
overbar = !overbar;
chIt = lookahead;
overbarDepth = braceNesting;
braceNesting++;
continue;
}
}
else if( c == ' ' || c == '}' || c == ')' )
else if( *chIt == '{' )
{
overbar = false;
braceNesting++;
}
else if( *chIt == '}' )
{
if( braceNesting > 0 )
braceNesting--;
if( braceNesting == overbarDepth )
{
overbarDepth = -1;
continue;
}
}
if( wasOverbar && !overbar )
if( wasOverbar && overbarDepth == -1 )
{
drawBitmapOverbar( overbarLength, overbarHeight );
overbarLength = 0;
}
if( overbar )
overbarLength += drawBitmapChar( c );
overbarLength += drawBitmapChar( *chIt );
else
drawBitmapChar( c );
++i;
drawBitmapChar( *chIt );
}
// Handle the case when overbar is active till the end of the drawn text
@ -2064,33 +2066,38 @@ std::pair<VECTOR2D, float> OPENGL_GAL::computeBitmapTextSize( const UTF8& aText
VECTOR2D textSize( 0, 0 );
float commonOffset = std::numeric_limits<float>::max();
bool in_overbar = false;
float char_height = font_information.max_y - defaultGlyph->miny;
float charHeight = font_information.max_y - defaultGlyph->miny;
int overbarDepth = -1;
int braceNesting = 0;
for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
{
if( *chIt == '~' )
if( *chIt == '~' && overbarDepth == -1 )
{
if( ++chIt == end )
break;
UTF8::uni_iter lookahead = chIt;
if( *chIt == '~' )
if( ++lookahead != end && *lookahead == '{' )
{
// double ~ is really a ~ so go ahead and process the second one
// so what's a triple ~? It could be a real ~ followed by an overbar, or
// it could be an overbar followed by a real ~. The old algorithm did the
// former so we will too....
}
else
{
// single ~ toggles overbar
in_overbar = !in_overbar;
chIt = lookahead;
overbarDepth = braceNesting;
braceNesting++;
continue;
}
}
else if( in_overbar && ( *chIt == ' ' || *chIt == '}' || *chIt == ')' ) )
else if( *chIt == '{' )
{
in_overbar = false;
braceNesting++;
}
else if( *chIt == '}' )
{
if( braceNesting > 0 )
braceNesting--;
if( braceNesting == overbarDepth )
{
overbarDepth = -1;
continue;
}
}
const FONT_GLYPH_TYPE* glyph = LookupGlyph( *chIt );
@ -2105,15 +2112,15 @@ std::pair<VECTOR2D, float> OPENGL_GAL::computeBitmapTextSize( const UTF8& aText
{
textSize.x += glyph->advance;
if( in_overbar )
if( overbarDepth != -1 )
{
const float H = lineGlyph->maxy - lineGlyph->miny;
textSize.y = std::max<float>( textSize.y, char_height + 1.5 * H );
textSize.y = std::max<float>( textSize.y, charHeight + 1.5 * H );
}
}
}
textSize.y = std::max<float>( textSize.y, char_height );
textSize.y = std::max<float>( textSize.y, charHeight );
commonOffset = std::min<float>( font_information.max_y - defaultGlyph->maxy, commonOffset );
textSize.y -= commonOffset;

View File

@ -329,9 +329,10 @@ void STROKE_FONT::drawSingleLineText( const UTF8& aText )
// The overbar is indented inward at the beginning of an italicized section, but
// must not be indented on subsequent letters to ensure that the bar segments
// overlap.
bool last_had_overbar = false;
bool in_overbar = false;
bool in_super_or_subscript = false;
bool lastHadOverbar = false;
int overbarDepth = -1;
int superSubDepth = -1;
int braceNesting = 0;
VECTOR2D glyphSize = baseGlyphSize;
// Allocate only once (for performance)
@ -354,67 +355,72 @@ void STROKE_FONT::drawSingleLineText( const UTF8& aText )
glyphSize = baseGlyphSize;
yOffset = 0;
// Tab ends an overbar
in_overbar = false;
}
else if( *chIt == '~' )
else if( *chIt == '^' && superSubDepth == -1 )
{
if( ++chIt == end )
break;
if( *chIt == '~' )
{
// double ~ is really a ~ so go ahead and process the second one
// so what's a triple ~? It could be a real ~ followed by an overbar, or
// it could be an overbar followed by a real ~. The old algorithm did the
// former so we will too....
}
else
{
in_overbar = !in_overbar;
}
}
else if( *chIt == '^' )
{
auto lookahead = chIt;
UTF8::uni_iter lookahead = chIt;
if( ++lookahead != end && *lookahead == '{' )
{
// process superscript
chIt = lookahead;
in_super_or_subscript = true;
superSubDepth = braceNesting;
braceNesting++;
glyphSize = baseGlyphSize * 0.8;
yOffset = -baseGlyphSize.y * 0.3;
continue;
}
}
else if( *chIt == '_' )
else if( *chIt == '_' && superSubDepth == -1 )
{
auto lookahead = chIt;
UTF8::uni_iter lookahead = chIt;
if( ++lookahead != end && *lookahead == '{' )
{
// process subscript
chIt = lookahead;
in_super_or_subscript = true;
superSubDepth = braceNesting;
braceNesting++;
glyphSize = baseGlyphSize * 0.8;
yOffset = baseGlyphSize.y * 0.1;
continue;
}
}
else if( *chIt == '}' && in_super_or_subscript )
else if( *chIt == '~' && overbarDepth == -1 )
{
in_super_or_subscript = false;
glyphSize = baseGlyphSize;
yOffset = 0;
continue;
UTF8::uni_iter lookahead = chIt;
if( ++lookahead != end && *lookahead == '{' )
{
chIt = lookahead;
overbarDepth = braceNesting;
braceNesting++;
continue;
}
}
// Overbar syntax is less precise so we have to have some special cases
else if( in_overbar && ( *chIt == ' ' || *chIt == '}' || *chIt == ')' ) )
else if( *chIt == '{' )
{
in_overbar = false;
braceNesting++;
}
else if( *chIt == '}' )
{
if( braceNesting > 0 )
braceNesting--;
if( braceNesting == superSubDepth )
{
superSubDepth = -1;
glyphSize = baseGlyphSize;
yOffset = 0;
continue;
}
if( braceNesting == overbarDepth )
{
overbarDepth = -1;
continue;
}
}
// Index into bounding boxes table
@ -429,19 +435,19 @@ void STROKE_FONT::drawSingleLineText( const UTF8& aText )
const GLYPH* glyph = m_glyphs->at( dd );
const BOX2D& bbox = m_glyphBoundingBoxes->at( dd );
if( in_overbar )
if( overbarDepth != -1 )
{
double overbar_start_x = xOffset;
double overbar_start_y = - computeOverbarVerticalPosition();
double overbar_end_x = xOffset + glyphSize.x * bbox.GetEnd().x;
double overbar_end_y = overbar_start_y;
if( !last_had_overbar )
if( !lastHadOverbar )
{
if( m_gal->IsFontItalic() )
overbar_start_x += overbar_italic_comp;
last_had_overbar = true;
lastHadOverbar = true;
}
VECTOR2D startOverbar( overbar_start_x, overbar_start_y );
@ -451,7 +457,7 @@ void STROKE_FONT::drawSingleLineText( const UTF8& aText )
}
else
{
last_had_overbar = false;
lastHadOverbar = false;
}
if( m_gal->IsFontUnderlined() )
@ -534,12 +540,13 @@ VECTOR2D STROKE_FONT::ComputeStringBoundaryLimits( const UTF8& aText, const VECT
double maxX = 0.0, curX = 0.0;
double curScale = 1.0;
bool in_overbar = false;
bool in_super_or_subscript = false;
int overbarDepth = -1;
int superSubDepth = -1;
int braceNesting = 0;
for( UTF8::uni_iter it = aText.ubegin(), end = aText.uend(); it < end; ++it )
for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
{
if( *it == '\n' )
if( *chIt == '\n' )
{
curX = 0.0;
maxX = std::max( maxX, curX );
@ -549,67 +556,52 @@ VECTOR2D STROKE_FONT::ComputeStringBoundaryLimits( const UTF8& aText, const VECT
// Handle tabs as locked to the nearest 4th column (counting in spaces)
// The choice of spaces is somewhat arbitrary but sufficient for aligning text
if( *it == '\t' )
if( *chIt == '\t' )
{
double spaces = m_glyphBoundingBoxes->at( 0 ).GetEnd().x;
double addlSpace = 3.0 * spaces - std::fmod( curX, 4.0 * spaces );
// Add the remaining space (between 0 and 3 spaces)
curX += addlSpace;
// Tab ends an overbar
in_overbar = false;
}
else if( *it == '~' )
else if( (*chIt == '^' || *chIt == '_') && superSubDepth == -1 )
{
if( ++it == end )
break;
if( *it == '~' )
{
// double ~ is really a ~ so go ahead and process the second one
// so what's a triple ~? It could be a real ~ followed by an overbar, or
// it could be an overbar followed by a real ~. The old algorithm did the
// former so we will too....
}
else
{
// single ~ toggles overbar
in_overbar = !in_overbar;
}
}
else if( *it == '^' || *it == '_' )
{
auto lookahead = it;
auto lookahead = chIt;
if( ++lookahead != end && *lookahead == '{' )
{
// process superscript
it = lookahead;
in_super_or_subscript = true;
chIt = lookahead;
superSubDepth = braceNesting;
curScale = 0.8;
continue;
}
}
else if( *it == '}' && in_super_or_subscript )
else if( *chIt == '{' )
{
in_super_or_subscript = false;
curScale = 1.0;
continue;
braceNesting++;
}
// Overbar syntax is less precise so we have to have some special cases
else if( in_overbar && ( *it == ' ' || *it == '}' || *it == ')' ) )
else if( *chIt == '}' )
{
in_overbar = false;
if( braceNesting > 0 )
braceNesting--;
if( braceNesting == superSubDepth )
{
superSubDepth = -1;
curScale = 1.0;
continue;
}
}
// Index in the bounding boxes table
int dd = (signed) *it - ' ';
int dd = (signed) *chIt - ' ';
if( dd >= (int) m_glyphBoundingBoxes->size() || dd < 0 )
{
int substitute = *it == '\t' ? ' ' : '?';
int substitute = *chIt == '\t' ? ' ' : '?';
dd = substitute - ' ';
}

View File

@ -965,11 +965,12 @@ void DXF_PLOTTER::Text( const wxPoint& aPos,
in no more details...
*/
bool overlining = false;
int braceNesting = 0;
int overbarDepth = -1;
fputs( " 1\n", m_outputFile );
for( unsigned i = 0; i < aText.length(); i++ )
for( unsigned int i = 0; i < aText.length(); i++ )
{
/* Here I do a bad thing: writing the output one byte at a time!
but today I'm lazy and I have no idea on how to coerce a Unicode
@ -986,31 +987,30 @@ void DXF_PLOTTER::Text( const wxPoint& aPos,
}
else
{
if( ch == '~' )
if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
{
if( ++i == aText.length() )
break;
fputs( "%%o", m_outputFile );
overbarDepth = braceNesting;
ch = aText[i];
if( ch == '~' )
{
// double ~ is really a ~ so go ahead and process the second one
// so what's a triple ~? It could be a real ~ followed by an overbar,
// or it could be an overbar followed by a real ~. The old algorithm
// did the former so we will too....
}
else
{
// Handle the overline toggle
fputs( overlining ? "%%o" : "%%O", m_outputFile );
overlining = !overlining;
}
// Skip the '{'
i++;
continue;
}
else if( ch == ' ' || ch == '}' || ch == ')' )
else if( aText[i] == '{' )
{
overlining = false;
braceNesting++;
}
else if( aText[i] == '}' )
{
if( braceNesting > 0 )
braceNesting--;
if( braceNesting == overbarDepth )
{
fputs( "%%O", m_outputFile );
overbarDepth = -1;
continue;
}
}
putc( ch, m_outputFile );

View File

@ -272,9 +272,9 @@ const wxString& NET_SETTINGS::GetNetclassName( const wxString& aNetName ) const
}
static bool isSuperSub( wxChar c )
static bool isSuperSubOverbar( wxChar c )
{
return c == '_' || c == '^';
return c == '_' || c == '^' || c == '~';
}
@ -304,7 +304,7 @@ bool NET_SETTINGS::ParseBusVector( const wxString& aBus, wxString* aName,
{
if( aBus[i] == '{' )
{
if( i > 0 && isSuperSub( aBus[i-1] ) )
if( i > 0 && isSuperSubOverbar( aBus[i-1] ) )
braceNesting++;
else
return false;
@ -376,10 +376,6 @@ bool NET_SETTINGS::ParseBusVector( const wxString& aBus, wxString* aName,
braceNesting--;
suffix += aBus[i];
}
else if( aBus[i] == '~' )
{
suffix += aBus[i];
}
else
{
return false;
@ -431,7 +427,7 @@ bool NET_SETTINGS::ParseBusGroup( const wxString& aGroup, wxString* aName,
{
if( aGroup[i] == '{' )
{
if( i > 0 && isSuperSub( aGroup[i-1] ) )
if( i > 0 && isSuperSubOverbar( aGroup[i-1] ) )
braceNesting++;
else
break;
@ -464,7 +460,7 @@ bool NET_SETTINGS::ParseBusGroup( const wxString& aGroup, wxString* aName,
{
if( aGroup[i] == '{' )
{
if( i > 0 && isSuperSub( aGroup[i-1] ) )
if( i > 0 && isSuperSubOverbar( aGroup[i-1] ) )
braceNesting++;
else
return false;

View File

@ -497,9 +497,9 @@ const std::vector< std::shared_ptr< SCH_CONNECTION > > SCH_CONNECTION::AllMember
}
static bool isSuperSub( wxChar c )
static bool isSuperSubOverbar( wxChar c )
{
return c == '_' || c == '^';
return c == '_' || c == '^' || c == '~';
};
@ -509,30 +509,17 @@ wxString SCH_CONNECTION::PrintBusForUI( const wxString& aGroup )
size_t i = 0;
wxString ret;
int braceNesting = 0;
int tildeNesting = 0;
// Parse prefix
//
for( ; i < groupLen; ++i )
{
if( isSuperSub( aGroup[i] ) && i + 1 < groupLen && aGroup[i+1] == '{' )
if( isSuperSubOverbar( aGroup[i] ) && i + 1 < groupLen && aGroup[i+1] == '{' )
{
braceNesting++;
i++;
continue;
}
else if( aGroup[i] == '~' )
{
if( tildeNesting )
{
tildeNesting = 0;
continue;
}
else
{
tildeNesting++;
}
}
else if( aGroup[i] == '}' )
{
braceNesting--;
@ -551,24 +538,12 @@ wxString SCH_CONNECTION::PrintBusForUI( const wxString& aGroup )
for( ; i < groupLen; ++i )
{
if( isSuperSub( aGroup[i] ) && i + 1 < groupLen && aGroup[i+1] == '{' )
if( isSuperSubOverbar( aGroup[i] ) && i + 1 < groupLen && aGroup[i+1] == '{' )
{
braceNesting++;
i++;
continue;
}
else if( aGroup[i] == '~' )
{
if( tildeNesting )
{
tildeNesting = 0;
continue;
}
else
{
tildeNesting++;
}
}
else if( aGroup[i] == '}' )
{
braceNesting--;