VECTOR2D STROKE_FONT::computeTextSize( const UTF8& aText ) const { VECTOR2D result = VECTOR2D( 0.0, m_glyphSize.y ); for( UTF8::uni_iter it = aText.ubegin(), end = aText.uend(); it < end; ++it ) { wxASSERT_MSG( *it != '\n', wxT( "This function is intended to work with single line strings" ) ); // If it is double tilda, then it is displayed as a single tilda // If it is single tilda, then it is toggling overbar, so we need to skip it if( *it == '~' ) { if( ++it >= end ) break; } // Index in the bounding boxes table int dd = *it - ' '; if( dd >= (int) m_glyphBoundingBoxes.size() || dd < 0 ) dd = '?' - ' '; result.x += m_glyphSize.x * m_glyphBoundingBoxes[dd].GetEnd().x; } return result; }
void STROKE_FONT::Draw( const UTF8& aText, const VECTOR2D& aPosition, double aRotationAngle ) { // Context needs to be saved before any transformations m_gal->Save(); m_gal->Translate( aPosition ); m_gal->Rotate( -aRotationAngle ); // Single line height int lineHeight = getInterline(); // The overall height of all lines of text double textBlockHeight = lineHeight * ( linesCount( aText ) - 1 ); switch( m_verticalJustify ) { case GR_TEXT_VJUSTIFY_CENTER: m_gal->Translate( VECTOR2D( 0, -textBlockHeight / 2.0 ) ); break; case GR_TEXT_VJUSTIFY_BOTTOM: m_gal->Translate( VECTOR2D( 0, -textBlockHeight ) ); break; case GR_TEXT_VJUSTIFY_TOP: break; default: break; } m_gal->SetIsStroke( true ); m_gal->SetIsFill( false ); if( m_bold ) m_gal->SetLineWidth( m_gal->GetLineWidth() * BOLD_FACTOR ); // Split multiline strings into separate ones and draw them line by line size_t begin = 0; size_t newlinePos = aText.find( '\n' ); while( newlinePos != aText.npos ) { size_t length = newlinePos - begin; drawSingleLineText( aText.substr( begin, length ) ); m_gal->Translate( VECTOR2D( 0.0, lineHeight ) ); begin = newlinePos + 1; newlinePos = aText.find( '\n', begin ); } // Draw the last (or the only one) line if( !aText.empty() ) drawSingleLineText( aText.substr( begin ) ); m_gal->Restore(); }
int main() { std::string str = "input"; UTF8 u0 = L"wide string"; UTF8 u1 = "initial"; wxString wx = wxT( "input2" ); printf( "u0:'%s'\n", u0.c_str() ); printf( "u1:'%s'\n", u1.c_str() ); u1 = str; wxString wx2 = u1; // force a std::string into a UTF8, then into a wxString, then copy construct: wxString wx3 = (UTF8&) u1; UTF8 u2 = wx2; u2 += 'X'; printf( "u2:'%s'\n", u2.c_str() ); // key accomplishments here: // 1) passing a UTF8 to a function which normally takes a wxString. // 2) return a wxString back into a UTF8. UTF8 result = wxFunctionTaking_wxString( u2 ); printf( "result:'%s'\n", result.c_str() ); // test the unicode iterator: for( UTF8::uni_iter it = u2.ubegin(); it < u2.uend(); ) { // test post-increment: printf( " _%02x_", *it++ ); } printf( "\n" ); UTF8::uni_iter it = u2.ubegin(); UTF8::uni_iter it2 = it++; printf( "post_inc:'%c' should be 'i'\n", *it2 ); it2 = ++it; printf( "pre_inc:'%c' should be 'p'\n", *it2 ); printf( "u[1]:'%c' should be 'n'\n", u2[1] ); return 0; }
FPID::FPID( const wxString& aId ) throw( PARSE_ERROR ) { UTF8 id = aId; int offset = Parse( id ); if( offset != -1 ) { THROW_PARSE_ERROR( _( "Illegal character found in FPID string" ), aId, id.c_str(), 0, offset ); } }
int FPID::Parse( const UTF8& aId ) { clear(); size_t cnt = aId.length() + 1; char tmp[cnt]; // C string for speed std::strcpy( tmp, aId.c_str() ); const char* rev = EndsWithRev( tmp, tmp+aId.length(), '/' ); size_t revNdx; size_t partNdx; int offset; //=====<revision>========================================= if( rev ) { revNdx = rev - aId.c_str(); // no need to check revision, EndsWithRev did that. revision = aId.substr( revNdx ); --revNdx; // back up to omit the '/' which precedes the rev } else { revNdx = aId.size(); } //=====<nickname>========================================== if( ( partNdx = aId.find( ':' ) ) != aId.npos ) { offset = SetLibNickname( aId.substr( 0, partNdx ) ); if( offset > -1 ) { return offset; } ++partNdx; // skip ':' } else { partNdx = 0; } //=====<footprint name>==================================== if( partNdx >= revNdx ) return partNdx; SetFootprintName( aId.substr( partNdx, revNdx ) ); return -1; }
int FPID::SetFootprintName( const UTF8& aFootprintName ) { int separation = int( aFootprintName.find_first_of( "/" ) ); if( separation != -1 ) { footprint = aFootprintName.substr( 0, separation-1 ); return separation; } else { footprint = aFootprintName; } return -1; }
int LIB_ID::SetLibItemName( const UTF8& aLibItemName, bool aTestForRev ) { int separation = int( aLibItemName.find_first_of( "/" ) ); if( aTestForRev && separation != -1 ) { item_name = aLibItemName.substr( 0, separation-1 ); return separation; } else { item_name = aLibItemName; } return -1; }
int FPID::SetFootprintName( const UTF8& aFootprintName ) { int separation = int( aFootprintName.find_first_of( "/" ) ); if( separation != -1 ) { nickname = aFootprintName.substr( separation+1 ); return separation + (int) nickname.size() + 1; } else { footprint = aFootprintName; } return -1; }
static void generateJSONString(Error& error, const HOutputStream& out, const UTF8& s) { UTF16Buffer sb(2 + s.length() + 1); sb << '"'; if (error) return; for (const Chr8* p = s.ptr(); (*p) != '\0'; p++) { Chr8 c = *p; switch (c) { case '\"' : sb << '\\' << '\"'; break; case '\\' : sb << '\\' << '\\'; break; case '/' : sb << '\\' << '/'; break; case '\b' : sb << '\\' << 'b'; break; case '\f' : sb << '\\' << 'f'; break; case '\n' : sb << '\\' << 'n'; break; case '\r' : sb << '\\' << 'r'; break; case '\t' : sb << '\\' << 't'; break; default: if (c >= 0x20) { sb << c; } else { sb << UTF8("\\u00") << UTF8::format("%.2X",UInt32(c)); } break; } } sb << '"'; out->twrite(error, UTF8(sb)); };
int FPID::Parse( const UTF8& aId ) { clear(); const char* buffer = aId.c_str(); const char* rev = EndsWithRev( buffer, buffer+aId.length(), '/' ); size_t revNdx; size_t partNdx; int offset; //=====<revision>========================================= // in a FPID like discret:R3/rev4 if( rev ) { revNdx = rev - buffer; // no need to check revision, EndsWithRev did that. revision = aId.substr( revNdx ); --revNdx; // back up to omit the '/' which precedes the rev } else { revNdx = aId.size(); } //=====<nickname>========================================== if( ( partNdx = aId.find( ':' ) ) != aId.npos ) { offset = SetLibNickname( aId.substr( 0, partNdx ) ); if( offset > -1 ) { return offset; } ++partNdx; // skip ':' } else { partNdx = 0; } //=====<footprint name>==================================== if( partNdx >= revNdx ) return partNdx; // Error: no footprint name. // Be sure the footprint name is valid. // Some chars can be found in board file (in old board files // or converted files from an other EDA tool std::string fpname = aId.substr( partNdx, revNdx-partNdx ); ReplaceIllegalFileNameChars( &fpname, '_' ); SetFootprintName( UTF8( fpname ) ); return -1; }
int main( int argc, char** argv ) { UTF8 bozo = "ü"; callee( bozo ); wxString s = bozo; wxString b = bozo; if( s.IsEmpty() ) { printf( "string is empty\n" ); } if( s != bozo.wx_str() ) { printf( "string miscompare\n" ); } return 0; }
UTF8 LIB_TABLE::FormatOptions( const PROPERTIES* aProperties ) { UTF8 ret; if( aProperties ) { for( PROPERTIES::const_iterator it = aProperties->begin(); it != aProperties->end(); ++it ) { const std::string& name = it->first; const UTF8& value = it->second; if( ret.size() ) ret += OPT_SEP; ret += name; // the separation between name and value is '=' if( value.size() ) { ret += '='; for( std::string::const_iterator si = value.begin(); si != value.end(); ++si ) { // escape any separator in the value. if( *si == OPT_SEP ) ret += '\\'; ret += *si; } } } } return ret; }
UTF8 FPID::Format( const UTF8& aLogicalLib, const UTF8& aFootprintName, const UTF8& aRevision ) throw( PARSE_ERROR ) { UTF8 ret; int offset; if( aLogicalLib.size() ) { offset = okLogical( aLogicalLib ); if( offset != -1 ) { THROW_PARSE_ERROR( _( "Illegal character found in logical library name" ), wxString::FromUTF8( aLogicalLib.c_str() ), aLogicalLib.c_str(), 0, offset ); } ret += aLogicalLib; ret += ':'; } if( aRevision.size() ) { offset = okRevision( aRevision ); if( offset != -1 ) { THROW_PARSE_ERROR( _( "Illegal character found in revision" ), wxString::FromUTF8( aRevision.c_str() ), aRevision.c_str(), 0, offset ); } ret += '/'; ret += aRevision; } return ret; }
void STROKE_FONT::drawSingleLineText( const UTF8& aText ) { // By default the overbar is turned off bool overbar = false; double xOffset; VECTOR2D glyphSize( m_gal->GetGlyphSize() ); double overbar_italic_comp = computeOverbarVerticalPosition() * ITALIC_TILT; if( m_gal->IsTextMirrored() ) overbar_italic_comp = -overbar_italic_comp; // Compute the text size VECTOR2D textSize = computeTextLineSize( aText ); double half_thickness = m_gal->GetLineWidth()/2; // Context needs to be saved before any transformations m_gal->Save(); // First adjust: the text X position is corrected by half_thickness // because when the text with thickness is draw, its full size is textSize, // but the position of lines is half_thickness to textSize - half_thickness // so we must translate the coordinates by half_thickness on the X axis // to place the text inside the 0 to textSize X area. m_gal->Translate( VECTOR2D( half_thickness, 0 ) ); // Adjust the text position to the given horizontal justification switch( m_gal->GetHorizontalJustify() ) { case GR_TEXT_HJUSTIFY_CENTER: m_gal->Translate( VECTOR2D( -textSize.x / 2.0, 0 ) ); break; case GR_TEXT_HJUSTIFY_RIGHT: if( !m_gal->IsTextMirrored() ) m_gal->Translate( VECTOR2D( -textSize.x, 0 ) ); break; case GR_TEXT_HJUSTIFY_LEFT: if( m_gal->IsTextMirrored() ) m_gal->Translate( VECTOR2D( -textSize.x, 0 ) ); break; default: break; } if( m_gal->IsTextMirrored() ) { // In case of mirrored text invert the X scale of points and their X direction // (m_glyphSize.x) and start drawing from the position where text normally should end // (textSize.x) xOffset = textSize.x - m_gal->GetLineWidth(); glyphSize.x = -glyphSize.x; } else { xOffset = 0.0; } // 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; for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt ) { // Toggle overbar if( *chIt == '~' ) { if( ++chIt >= end ) break; if( *chIt != '~' ) // It was a single tilda, it toggles overbar overbar = !overbar; // If it is a double tilda, just process the second one } int dd = *chIt - ' '; if( dd >= (int) m_glyphBoundingBoxes.size() || dd < 0 ) dd = '?' - ' '; GLYPH& glyph = m_glyphs[dd]; BOX2D& bbox = m_glyphBoundingBoxes[dd]; if( overbar ) { 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 ) { overbar_start_x += overbar_italic_comp; last_had_overbar = true; } VECTOR2D startOverbar( overbar_start_x, overbar_start_y ); VECTOR2D endOverbar( overbar_end_x, overbar_end_y ); m_gal->DrawLine( startOverbar, endOverbar ); } else { last_had_overbar = false; } for( GLYPH::iterator pointListIt = glyph.begin(); pointListIt != glyph.end(); ++pointListIt ) { std::deque<VECTOR2D> pointListScaled; for( std::deque<VECTOR2D>::iterator pointIt = pointListIt->begin(); pointIt != pointListIt->end(); ++pointIt ) { VECTOR2D pointPos( pointIt->x * glyphSize.x + xOffset, pointIt->y * glyphSize.y ); if( m_gal->IsFontItalic() ) { // FIXME should be done other way - referring to the lowest Y value of point // because now italic fonts are translated a bit if( m_gal->IsTextMirrored() ) pointPos.x += pointPos.y * STROKE_FONT::ITALIC_TILT; else pointPos.x -= pointPos.y * STROKE_FONT::ITALIC_TILT; } pointListScaled.push_back( pointPos ); } m_gal->DrawPolyline( pointListScaled ); } xOffset += glyphSize.x * bbox.GetEnd().x; } m_gal->Restore(); }
void STROKE_FONT::drawSingleLineText( const UTF8& aText ) { // By default the overbar is turned off m_overbar = false; double xOffset; VECTOR2D glyphSize( m_glyphSize ); // Compute the text size VECTOR2D textSize = computeTextSize( aText ); m_gal->Save(); // Adjust the text position to the given alignment switch( m_horizontalJustify ) { case GR_TEXT_HJUSTIFY_CENTER: m_gal->Translate( VECTOR2D( -textSize.x / 2.0, 0 ) ); break; case GR_TEXT_HJUSTIFY_RIGHT: if( !m_mirrored ) m_gal->Translate( VECTOR2D( -textSize.x, 0 ) ); break; case GR_TEXT_HJUSTIFY_LEFT: if( m_mirrored ) m_gal->Translate( VECTOR2D( -textSize.x, 0 ) ); break; default: break; } if( m_mirrored ) { // In case of mirrored text invert the X scale of points and their X direction // (m_glyphSize.x) and start drawing from the position where text normally should end // (textSize.x) xOffset = textSize.x; glyphSize.x = -m_glyphSize.x; } else { xOffset = 0.0; } for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt ) { // Toggle overbar if( *chIt == '~' ) { if( ++chIt >= end ) break; if( *chIt != '~' ) // It was a single tilda, it toggles overbar m_overbar = !m_overbar; // If it is a double tilda, just process the second one } int dd = *chIt - ' '; if( dd >= (int) m_glyphBoundingBoxes.size() || dd < 0 ) dd = '?' - ' '; GLYPH& glyph = m_glyphs[dd]; BOX2D& bbox = m_glyphBoundingBoxes[dd]; if( m_overbar ) { VECTOR2D startOverbar( xOffset, -getInterline() * OVERBAR_HEIGHT ); VECTOR2D endOverbar( xOffset + glyphSize.x * bbox.GetEnd().x, -getInterline() * OVERBAR_HEIGHT ); m_gal->DrawLine( startOverbar, endOverbar ); } for( GLYPH::iterator pointListIt = glyph.begin(); pointListIt != glyph.end(); ++pointListIt ) { std::deque<VECTOR2D> pointListScaled; for( std::deque<VECTOR2D>::iterator pointIt = pointListIt->begin(); pointIt != pointListIt->end(); ++pointIt ) { VECTOR2D pointPos( pointIt->x * glyphSize.x + xOffset, pointIt->y * glyphSize.y ); if( m_italic ) { // FIXME should be done other way - referring to the lowest Y value of point // because now italic fonts are translated a bit if( m_mirrored ) pointPos.x += pointPos.y * 0.1; else pointPos.x -= pointPos.y * 0.1; } pointListScaled.push_back( pointPos ); } m_gal->DrawPolyline( pointListScaled ); } xOffset += glyphSize.x * bbox.GetEnd().x; } m_gal->Restore(); }
int wmain(int argc, Chr16** argv) { Lock::setupGlobalLock(); Error error; LogStdout log; class Fatal {}; try { loginfo("Tomazos Resource Compiler 1.0 (c) Andrew Tomazos 2009"); if (argc != 3) { error.what(L"Usage: ResourceCompiler <ResourceDir> <Out.cpp>"); throw Fatal(); } UTF16 sSourceDirPath = argv[1]; UTF16 sOutPath = argv[2]; Path sourceDir(error, sSourceDirPath); if (error) throw Fatal(); UTF16 sFullSourceDirPath = UTF16(sourceDir); if (!sFullSourceDirPath.endsWith(L"\\")) sFullSourceDirPath = sFullSourceDirPath + L"\\"; UTF16List fps; sourceDir.walk(ResourceCompilerWalker(fps)); loginfo("Found %d files", fps.size()); TreeMap<UTF16, Blob> data; { UTF16List::Iterator it(fps); UTF16 sFullFilePath; while (it(sFullFilePath)) { if (!sFullFilePath.startsWith(sFullSourceDirPath)) { Check(); throw Fatal(); } UTF16 sRelFilePath = sFullFilePath.suffix(sFullFilePath.length() - sFullSourceDirPath.length()); Path file(error, sFullFilePath); if (error) throw Fatal(); HInputStream fis; file.readFile(error, fis); if (error) throw Fatal(); Blob sFileContent = fis->slurp(error); if (error) throw Fatal(); loginfo("Found %s (%d bytes)", sRelFilePath.ptr(), sFileContent.length()); data.add(sRelFilePath, sFileContent); } } Path outPath(error, sOutPath); if (error) throw Fatal(); HOutputStream hOut; outPath.overwriteFile(error, hOut); if (error) throw Fatal(); #define ResLine(x) { hOut->twrite(error, UTF8(x)); if (error) throw Fatal(); hOut->twrite(error, UTF8("\r\n")); if (error) throw Fatal(); } #define ResLineF(...) { ResLine(UTF8::format(__VA_ARGS__)); } ResLine("#include \"Runtime.h\""); ResLine(""); ResLine("void ResourceManager::setup()"); ResLine("{"); { TreeMap<UTF16, Blob>::Iterator it(data); UTF16 sPath; Blob bData; int iCount = 0; int iNumResources = data.size(); while (it(sPath, bData)) { iCount++; UTF8 sId = UTF8::format("s_res_data_%d", iCount); ResLineF(" static UInt8 %s[] = { ", sId.ptr()); for (int i = 0; i < bData.length(); i++) { if (i % 16 == 0) { hOut->twrite(error, UTF8(" ")); if (error) throw Fatal(); } hOut->twrite(error, UTF8::format("0x%.2X", UInt32(bData.idx<UInt8>(i)))); if (error) throw Fatal(); if (i != bData.length() - 1) { hOut->twrite(error, UTF8(", ")); if (error) throw Fatal(); } if (i % 16 == 15 || i == bData.length() - 1) ResLine(""); } ResLineF(" };"); ResLine(""); ResLineF(" ResourceManager::instance()->set(%s, %s, %d);", stringToCStringLiteral(sPath).ptr(), sId.ptr(), bData.length()); if (iCount != iNumResources) ResLine(""); } } ResLine("}"); #undef ResLine return 0; } catch (Fatal&) { if (error) logerr("%s", UTF16(error).ptr()); return 1; } }
void STROKE_FONT::Draw( const UTF8& aText, const VECTOR2D& aPosition, double aRotationAngle ) { if( aText.empty() ) return; // Context needs to be saved before any transformations m_gal->Save(); m_gal->Translate( aPosition ); m_gal->Rotate( -aRotationAngle ); // Single line height int lineHeight = getInterline( ); int lineCount = linesCount( aText ); const VECTOR2D& glyphSize = m_gal->GetGlyphSize(); // align the 1st line of text switch( m_gal->GetVerticalJustify() ) { case GR_TEXT_VJUSTIFY_TOP: m_gal->Translate( VECTOR2D( 0, glyphSize.y ) ); break; case GR_TEXT_VJUSTIFY_CENTER: m_gal->Translate( VECTOR2D( 0, glyphSize.y / 2.0 ) ); break; case GR_TEXT_VJUSTIFY_BOTTOM: break; default: break; } if( lineCount > 1 ) { switch( m_gal->GetVerticalJustify() ) { case GR_TEXT_VJUSTIFY_TOP: break; case GR_TEXT_VJUSTIFY_CENTER: m_gal->Translate( VECTOR2D(0, -( lineCount - 1 ) * lineHeight / 2) ); break; case GR_TEXT_VJUSTIFY_BOTTOM: m_gal->Translate( VECTOR2D(0, -( lineCount - 1 ) * lineHeight ) ); break; } } m_gal->SetIsStroke( true ); //m_gal->SetIsFill( false ); if( m_gal->IsFontBold() ) m_gal->SetLineWidth( m_gal->GetLineWidth() * BOLD_FACTOR ); // Split multiline strings into separate ones and draw them line by line size_t begin = 0; size_t newlinePos = aText.find( '\n' ); while( newlinePos != aText.npos ) { size_t length = newlinePos - begin; drawSingleLineText( aText.substr( begin, length ) ); m_gal->Translate( VECTOR2D( 0.0, lineHeight ) ); begin = newlinePos + 1; newlinePos = aText.find( '\n', begin ); } // Draw the last (or the only one) line if( !aText.empty() ) drawSingleLineText( aText.substr( begin ) ); m_gal->Restore(); }
void callee( const wxString& aString ) { UTF8 arg = aString; printf( "%s: '%s'\n", __func__, arg.c_str() ); }
VECTOR2D STROKE_FONT::ComputeStringBoundaryLimits( const UTF8& aText, VECTOR2D aGlyphSize, double aGlyphThickness, double* aTopLimit, double* aBottomLimit ) const { VECTOR2D string_bbox; double ymax = 0.0; double ymin = 0.0; for( UTF8::uni_iter it = aText.ubegin(), end = aText.uend(); it < end; ++it ) { wxASSERT_MSG( *it != '\n', wxT( "This function is intended to work with single line strings" ) ); // If it is double tilda, then it is displayed as a single tilda // If it is single tilda, then it is toggling overbar, so we need to skip it if( *it == '~' ) { if( ++it >= end ) break; } // Index in the bounding boxes table int dd = *it - ' '; if( dd >= (int) m_glyphBoundingBoxes.size() || dd < 0 ) dd = '?' - ' '; const BOX2D& box = m_glyphBoundingBoxes[dd]; string_bbox.x += box.GetEnd().x; // Calculate Y min and Y max if( aTopLimit ) { ymax = std::max( ymax, box.GetY() ); ymax = std::max( ymax, box.GetEnd().y ); } if( aBottomLimit ) { ymin = std::min( ymin, box.GetY() ); ymin = std::min( ymin, box.GetEnd().y ); } } string_bbox.x *= aGlyphSize.x; string_bbox.x += aGlyphThickness; string_bbox.y = aGlyphSize.y + aGlyphThickness; // For italic correction, take in account italic tilt if( m_gal->IsFontItalic() ) string_bbox.x += string_bbox.y * STROKE_FONT::ITALIC_TILT; if( aTopLimit ) *aTopLimit = ymax * aGlyphSize.y; if( aBottomLimit ) *aBottomLimit = ymin * aGlyphSize.y; return string_bbox; }