float ofxFontStash2::drawFormattedColumn(const string& text, float x, float y, float targetWidth, bool debug){ if (targetWidth < 0) return 0; TS_START_NIF("parse text"); vector<StyledText> blocks = ofxFontStashParser::parseText(text, styleIDs); TS_STOP_NIF("parse text"); return drawAndLayout(blocks, x, y, targetWidth, debug); }
void ofApp::update(){ TS_START("simple measurement"); ofSleepMillis(1); TS_STOP("simple measurement"); TS_START("nested measurement1"); TS_START("nested measurement11"); TS_START("nested measurement111"); ofSleepMillis(1); TS_STOP("nested measurement111"); TS_STOP("nested measurement11"); TS_START("nested measurement12"); ofSleepMillis(1); TS_STOP("nested measurement12"); TS_STOP("nested measurement1"); if (ofGetFrameNum()%60 == 1){ TS_START_NIF("sample across frames"); } if (ofGetFrameNum()%60 == 3){ TS_STOP_NIF("sample across frames"); } if (ofGetFrameNum()%600 == 30 || ofGetFrameNum() == 1){ TS_START("some uncommon method") ofSleepMillis(ofRandom(3)); TS_STOP("some uncommon method"); } //test accumulation time sampling for(int i = 0; i < 3; i++){ TS_START_ACC("accum test"); ofSleepMillis(1); TS_STOP_ACC("accum test"); { TS_SCOPE_ACC("scope measurement acc"); ofSleepMillis(1); } } for(int i = myThreads.size() - 1; i >= 0 ; i--){ if (!myThreads[i]->isThreadRunning()){ delete myThreads[i]; myThreads.erase(myThreads.begin() + i); } } { TS_SCOPE("scope measurement"); ofSleepMillis(1); } }
const vector<StyledLine> ofxFontStash2::layoutLines(const vector<StyledText> &blocks, float targetWidth, bool debug ){ float x = 0; float y = 0; if (targetWidth < 0) return vector<StyledLine>(); float xx = x; float yy = y; TS_START_NIF("split words"); vector<SplitTextBlock> words = splitWords(blocks); TS_STOP_NIF("split words"); if (words.size() == 0) return vector<StyledLine>(); vector<StyledLine> lines; // here we create the first line. a few things to note: // - in general, like in a texteditor, the line exists first, then content is added to it. // - 'line' here refers to the visual representation. even a line with no newline (\n) can span multiple lines lines.push_back(StyledLine()); ofxFontStashStyle currentStyle; currentStyle.fontSize = -1; // this makes sure the first style is actually applied, even if it's the default style float lineWidth = 0; int wordsThisLine = 0; vector<float> lineHeigts; float currentLineH = 0; float bounds[4]; float dx; LineElement le; TS_START("walk words"); for(int i = 0; i < words.size(); i++){ StyledLine ¤tLine = lines.back(); //TS_START_ACC("word style"); if(words[i].styledText.style.valid && currentStyle != words[i].styledText.style ){ //cout << " new style!" << endl; currentStyle = words[i].styledText.style; if(applyStyle(currentStyle)){ fonsVertMetrics(fs, NULL, NULL, ¤tLineH); currentLineH/=pixelDensity; }else{ ofLogError() << "no style font defined!"; } } //TS_STOP_ACC("word style"); bool stayOnCurrentLine = true; if( words[i].type == SEPARATOR_INVISIBLE && words[i].styledText.text == "\n" ){ stayOnCurrentLine = false; dx = 0; // add a zero-width enter mark. this is used to keep track // of the vertical spacing of empty lines. le = LineElement(words[i], ofRectangle(xx,yy,0,currentLineH)); le.baseLineY = yy; le.x = xx; le.lineHeight = currentLineH; currentLine.elements.push_back(le); float lineH = calcLineHeight(currentLine); currentLine.lineH = lineH; currentLine.lineW = xx - x + dx; // no! //i--; //re-calc dimensions of this word on a new line! yy += lineH; lineWidth = 0; wordsThisLine = 0; xx = x; lines.push_back(StyledLine()); continue; } else{ //TS_START_ACC("fonsTextBounds"); // applyStyle() already upscaled the font size for the display resolution. // Here we do the same for x/y. // The result gets the inverse treatment. dx = fonsTextBounds( fs, xx*pixelDensity, yy*pixelDensity, words[i].styledText.text.c_str(), NULL, &bounds[0] )/pixelDensity; bounds[0]/=pixelDensity; bounds[1]/=pixelDensity; bounds[2]/=pixelDensity; bounds[3]/=pixelDensity; //TS_STOP_ACC("fonsTextBounds"); //hansi: using dx instead of bounds[2]-bounds[0] //dx is the right size for spacing out text. bounds give exact area of the char, which isn't so useful here. ofRectangle where = ofRectangle(bounds[0], bounds[1] , dx, bounds[3] - bounds[1]); le = LineElement(words[i], where); le.baseLineY = yy; le.x = xx; le.lineHeight = currentLineH; float nextWidth = lineWidth + dx; //if not wider than targetW // || //this is the 1st word in this line but even that doesnt fit stayOnCurrentLine = nextWidth < targetWidth || (wordsThisLine == 0 && (nextWidth >= targetWidth)); } if (stayOnCurrentLine){ //TS_START_ACC("stay on line"); currentLine.elements.push_back(le); lineWidth += dx; xx += dx; wordsThisLine++; //TS_STOP_ACC("stay on line"); } else if( words[i].type == SEPARATOR_INVISIBLE && words[i].styledText.text == " " ){ // ignore spaces when moving into the next line! continue; } else{ //too long, start a new line //TS_START_ACC("new line"); //calc height for this line - taking in account all words in the line float lineH = lineHeightMultiplier * calcLineHeight(currentLine); currentLine.lineH = lineH; currentLine.lineW = xx - x; i--; //re-calc dimensions of this word on a new line! yy += lineH; lineWidth = 0; wordsThisLine = 0; xx = x; lines.push_back(StyledLine()); //TS_STOP_ACC("new line"); } } //TS_START_ACC("last line"); // update dimensions of the last line StyledLine ¤tLine = lines.back(); if( currentLine.elements.size() == 0 ){ // but at least one spacing character, so we have a line height. le = LineElement(SplitTextBlock(SEPARATOR_INVISIBLE,"",currentStyle), ofRectangle(xx,yy,0,currentLineH)); le.baseLineY = yy; le.x = xx; le.lineHeight = currentLineH; currentLine.elements.push_back(le); } float lineH = calcLineHeight(currentLine); currentLine.lineH = lineH; currentLine.lineW = xx - x + dx; //TS_STOP_ACC("last line"); TS_STOP("walk words"); return lines; }