/** * Testing function. */ void LC_SimpleTests::slotTestUnicode() { RS_DEBUG->print("%s\n: begin\n", __func__); auto appWin= QC_ApplicationWindow::getAppWindow(); appWin->slotFileOpen("./fonts/unicode.cxf", RS2::FormatCXF); RS_Document* d =appWin->getDocument(); if (d) { RS_Graphic* graphic = (RS_Graphic*)d; if (graphic==NULL) { return; } RS_Insert* ins; int col; int row; QChar uCode; // e.g. 65 (or 'A') QString strCode; // unicde as string e.g. '[0041] A' graphic->setAutoUpdateBorders(false); for (col=0x0000; col<=0xFFF0; col+=0x10) { printf("col: %X\n", col); for (row=0x0; row<=0xF; row++) { //printf(" row: %X\n", row); uCode = QChar(col+row); //printf(" code: %X\n", uCode.unicode()); strCode.setNum(uCode.unicode(), 16); while (strCode.length()<4) { strCode="0"+strCode; } strCode = "[" + strCode + "] " + uCode; if (graphic->findBlock(strCode)) { RS_InsertData d(strCode, RS_Vector(col/0x10*20.0,row*20.0), RS_Vector(1.0,1.0), 0.0, 1, 1, RS_Vector(0.0, 0.0), NULL, RS2::NoUpdate); ins = new RS_Insert(graphic, d); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(255, 255, 255), RS2::Width01, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); } } } graphic->setAutoUpdateBorders(true); graphic->calculateBorders(); } RS_DEBUG->print("%s\n: end\n", __func__); }
/** * Updates the Inserts (letters) of this text. Called when the * text or it's data, position, alignment, .. changes. * This method also updates the usedTextWidth / usedTextHeight property. */ void RS_Text::update() { RS_DEBUG->print("RS_Text::update"); clear(); if (isUndone()) { return; } usedTextWidth = 0.0; usedTextHeight = 0.0; RS_Font* font = RS_FONTLIST->requestFont(data.style); if (font==NULL) { return; } RS_Vector letterPos = RS_Vector(0.0, -9.0); RS_Vector letterSpace = RS_Vector(font->getLetterSpacing(), 0.0); RS_Vector space = RS_Vector(font->getWordSpacing(), 0.0); // First every text line is created with // alignement: top left // angle: 0 // height: 9.0 // Rotation, scaling and centering is done later // For every letter: for (int i=0; i<(int)data.text.length(); ++i) { // Space: if (data.text.at(i).unicode() == 0x20) { letterPos+=space; } else { // One Letter: QString letterText = QString(data.text.at(i)); if (font->findLetter(letterText) == NULL) { RS_DEBUG->print("RS_Text::update: missing font for letter( %s ), replaced it with QChar(0xfffd)",qPrintable(letterText)); letterText = QChar(0xfffd); } RS_DEBUG->print("RS_Text::update: insert a " "letter at pos: %f/%f", letterPos.x, letterPos.y); RS_InsertData d(letterText, letterPos, RS_Vector(1.0, 1.0), 0.0, 1,1, RS_Vector(0.0,0.0), font->getLetterList(), RS2::NoUpdate); RS_Insert* letter = new RS_Insert(this, d); RS_Vector letterWidth; letter->setPen(RS_Pen(RS2::FlagInvalid)); letter->setLayer(NULL); letter->update(); letter->forcedCalculateBorders(); letterWidth = RS_Vector(letter->getMax().x-letterPos.x, 0.0); if (letterWidth.x < 0) letterWidth.x = -letterSpace.x; // oneLine->addEntity(letter); addEntity(letter); // next letter position: letterPos += letterWidth; letterPos += letterSpace; } } if( ! RS_EntityContainer::autoUpdateBorders) { //only update borders when needed forcedCalculateBorders(); } RS_Vector textSize = getSize(); RS_DEBUG->print("RS_Text::updateAddLine: width 2: %f", textSize.x); // Vertical Align: double vSize = 9.0; //HAAligned, HAFit, HAMiddle require VABaseline if (data.halign == RS_TextData::HAAligned || data.halign == RS_TextData::HAFit || data.halign == RS_TextData::HAMiddle) { data.valign = RS_TextData::VABaseline; } RS_Vector offset(0.0, 0.0); switch (data.valign) { case RS_TextData::VAMiddle: offset.move(RS_Vector(0.0, vSize/2.0)); break; case RS_TextData::VABottom: offset.move(RS_Vector(0.0, vSize+3)); break; case RS_TextData::VABaseline: offset.move(RS_Vector(0.0, vSize)); break; default: break; } // Horizontal Align: switch (data.halign) { case RS_TextData::HAMiddle:{ offset.move(RS_Vector(-textSize.x/2.0, -(vSize + textSize.y/2.0 + getMin().y) )); break;} case RS_TextData::HACenter: RS_DEBUG->print("RS_Text::updateAddLine: move by: %f", -textSize.x/2.0); offset.move(RS_Vector(-textSize.x/2.0, 0.0)); break; case RS_TextData::HARight: offset.move(RS_Vector(-textSize.x, 0.0)); break; default: break; } if (data.halign!=RS_TextData::HAAligned && data.halign!=RS_TextData::HAFit){ data.secondPoint = RS_Vector(offset.x, offset.y - vSize); } RS_EntityContainer::move(offset); // Scale: if (data.halign==RS_TextData::HAAligned){ double dist = data.insertionPoint.distanceTo(data.secondPoint)/textSize.x; data.height = vSize*dist; RS_EntityContainer::scale(RS_Vector(0.0,0.0), RS_Vector(dist, dist)); } else if (data.halign==RS_TextData::HAFit){ double dist = data.insertionPoint.distanceTo(data.secondPoint)/textSize.x; RS_EntityContainer::scale(RS_Vector(0.0,0.0), RS_Vector(dist, data.height/9.0)); } else { RS_EntityContainer::scale(RS_Vector(0.0,0.0), RS_Vector(data.height*data.widthRel/9.0, data.height/9.0)); data.secondPoint.scale(RS_Vector(0.0,0.0), RS_Vector(data.height*data.widthRel/9.0, data.height/9.0)); } forcedCalculateBorders(); // Update actual text size (before rotating, after scaling!): usedTextWidth = getSize().x; usedTextHeight = data.height; // Rotate: if (data.halign==RS_TextData::HAAligned || data.halign==RS_TextData::HAFit){ double angle = data.insertionPoint.angleTo(data.secondPoint); data.angle = angle; } else { data.secondPoint.rotate(RS_Vector(0.0,0.0), data.angle); data.secondPoint.move(data.insertionPoint); } RS_EntityContainer::rotate(RS_Vector(0.0,0.0), data.angle); // Move to insertion point: RS_EntityContainer::move(data.insertionPoint); forcedCalculateBorders(); RS_DEBUG->print("RS_Text::update: OK"); }
/** * Testing function. */ void LC_SimpleTests::slotTestInsertBlock() { RS_DEBUG->print("%s\n: begin\n", __func__); auto appWin=QC_ApplicationWindow::getAppWindow(); RS_Document* d = appWin->getDocument(); if (d && d->rtti()==RS2::EntityGraphic) { RS_Graphic* graphic = (RS_Graphic*)d; if (graphic==NULL) { return; } graphic->addLayer(new RS_Layer("default")); RS_Block* block = new RS_Block(graphic, RS_BlockData("debugblock", RS_Vector(0.0,0.0), true)); RS_Line* line; RS_Arc* arc; RS_Circle* circle; // Add one red line: line = new RS_Line{block, {0.,0.}, {50.,0.}}; line->setLayerToActive(); line->setPen(RS_Pen(RS_Color(255, 0, 0), RS2::Width01, RS2::SolidLine)); block->addEntity(line); // Add one line with attributes from block: line = new RS_Line{block, {50.,0.}, {50.,50.}}; line->setPen(RS_Pen(RS_Color(RS2::FlagByBlock), RS2::WidthByBlock, RS2::LineByBlock)); block->addEntity(line); // Add one arc with attributes from block: RS_ArcData d({50.,0.}, 50.0, M_PI_2, M_PI, false); arc = new RS_Arc(block, d); arc->setPen(RS_Pen(RS_Color(RS2::FlagByBlock), RS2::WidthByBlock, RS2::LineByBlock)); block->addEntity(arc); // Add one blue circle: RS_CircleData circleData(RS_Vector(20.0,15.0), 12.5); circle = new RS_Circle(block, circleData); circle->setLayerToActive(); circle->setPen(RS_Pen(RS_Color(0, 0, 255), RS2::Width01, RS2::SolidLine)); block->addEntity(circle); graphic->addBlock(block); RS_Insert* ins; RS_InsertData insData("debugblock", RS_Vector(0.0,0.0), RS_Vector(1.0,1.0), 0.0, 1, 1, RS_Vector(0.0, 0.0), NULL, RS2::NoUpdate); // insert one magenta instance of the block (original): ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(255, 0, 255), RS2::Width02, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); // insert one green instance of the block (rotate): insData = RS_InsertData("debugblock", RS_Vector(-50.0,20.0), RS_Vector(1.0,1.0), M_PI/6., 1, 1, RS_Vector(0.0, 0.0), NULL, RS2::NoUpdate); ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(0, 255, 0), RS2::Width02, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); // insert one cyan instance of the block (move): insData = RS_InsertData("debugblock", RS_Vector(10.0,20.0), RS_Vector(1.0,1.0), 0.0, 1, 1, RS_Vector(0.0, 0.0), NULL, RS2::NoUpdate); ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(0, 255, 255), RS2::Width02, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); // insert one blue instance of the block: for (double a=0.0; a<360.0; a+=45.0) { insData = RS_InsertData("debugblock", RS_Vector(60.0,0.0), RS_Vector(2.0/5,2.0/5), RS_Math::deg2rad(a), 1, 1, RS_Vector(0.0, 0.0), NULL, RS2::NoUpdate); ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(0, 0, 255), RS2::Width05, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); } // insert an array of yellow instances of the block: insData = RS_InsertData("debugblock", RS_Vector(-100.0,-100.0), RS_Vector(0.2,0.2), M_PI/6.0, 6, 4, RS_Vector(100.0, 100.0), NULL, RS2::NoUpdate); ins = new RS_Insert(graphic, insData); ins->setLayerToActive(); ins->setPen(RS_Pen(RS_Color(255, 255, 0), RS2::Width01, RS2::SolidLine)); ins->update(); graphic->addEntity(ins); RS_GraphicView* v = appWin->getGraphicView(); if (v) { v->redraw(); } } RS_DEBUG->print("%s\n: end\n", __func__); }
/** * Updates the Inserts (letters) of this text. Called when the * text or it's data, position, alignment, .. changes. * This method also updates the usedTextWidth / usedTextHeight property. */ void RS_MText::update() { RS_DEBUG->print("RS_Text::update"); clear(); if (isUndone()) { return; } usedTextWidth = 0.0; usedTextHeight = 0.0; RS_Font* font = RS_FONTLIST->requestFont(data.style); if (font==NULL) { return; } RS_Vector letterPos = RS_Vector(0.0, -9.0); RS_Vector letterSpace = RS_Vector(font->getLetterSpacing(), 0.0); RS_Vector space = RS_Vector(font->getWordSpacing(), 0.0); int lineCounter = 0; // Every single text line gets stored in this entity container // so we can move the whole line around easely: RS_EntityContainer* oneLine = new RS_EntityContainer(this); // First every text line is created with // alignement: top left // angle: 0 // height: 9.0 // Rotation, scaling and centering is done later // For every letter: for (int i=0; i<(int)data.text.length(); ++i) { bool handled = false; switch (data.text.at(i).unicode()) { case 0x0A: // line feed: updateAddLine(oneLine, lineCounter++); oneLine = new RS_EntityContainer(this); letterPos = RS_Vector(0.0, -9.0); break; case 0x20: // Space: letterPos+=space; break; case 0x5C: { // code (e.g. \S, \P, ..) i++; int ch = data.text.at(i).unicode(); switch (ch) { case 'P': updateAddLine(oneLine, lineCounter++); oneLine = new RS_EntityContainer(this); letterPos = RS_Vector(0.0, -9.0); handled = true; break; case 'f': case 'F': //font change // \f{symbol} changes font to symbol // \f{} sets font to standard { i++; if(data.text.at(i).unicode()!='{') { i--; continue; } int j=data.text.indexOf('}',i); if(j>i){ // QString fontName; if(j==i+1) fontName="standard"; else fontName=data.text.mid(i+1,j-i-1); RS_Font* fontNew = RS_FONTLIST->requestFont( fontName ); if(fontNew != NULL) { font=fontNew; } if(font==NULL) font = RS_FONTLIST->requestFont("standard"); i=j; } } continue; case 'S': { QString up; QString dw; //letterPos += letterSpace; // get upper string: i++; while (data.text.at(i).unicode()!='^' && //data.text.at(i).unicode()!='/' && data.text.at(i).unicode()!='\\' && //data.text.at(i).unicode()!='#' && i<(int)data.text.length()) { up += data.text.at(i); i++; } i++; if (data.text.at(i-1).unicode()=='^' && data.text.at(i).unicode()==' ') { i++; } // get lower string: while (data.text.at(i).unicode()!=';' && i<(int)data.text.length()) { dw += data.text.at(i); i++; } // add texts: RS_MText* upper = new RS_MText( oneLine, RS_MTextData(letterPos + RS_Vector(0.0,9.0), 4.0, 100.0, RS_MTextData::VATop, RS_MTextData::HALeft, RS_MTextData::LeftToRight, RS_MTextData::Exact, 1.0, up, data.style, 0.0, RS2::Update)); upper->setLayer(NULL); upper->setPen(RS_Pen(RS2::FlagInvalid)); oneLine->addEntity(upper); RS_MText* lower = new RS_MText( oneLine, RS_MTextData(letterPos+RS_Vector(0.0,4.0), 4.0, 100.0, RS_MTextData::VATop, RS_MTextData::HALeft, RS_MTextData::LeftToRight, RS_MTextData::Exact, 1.0, dw, data.style, 0.0, RS2::Update)); lower->setLayer(NULL); lower->setPen(RS_Pen(RS2::FlagInvalid)); oneLine->addEntity(lower); // move cursor: upper->calculateBorders(); lower->calculateBorders(); double w1 = upper->getSize().x; double w2 = lower->getSize().x; if (w1>w2) { letterPos += RS_Vector(w1, 0.0); } else { letterPos += RS_Vector(w2, 0.0); } letterPos += letterSpace; } handled = true; break; default: i--; break; } } //if char is not handled continue in default: statement if (handled) break; default: { // One Letter: QString letterText = QString(data.text.at(i)); if (font->findLetter(letterText) == NULL) { RS_DEBUG->print("RS_Text::update: missing font for letter( %s ), replaced it with QChar(0xfffd)",qPrintable(letterText)); letterText = QChar(0xfffd); } // if (font->findLetter(QString(data.text.at(i))) != NULL) { RS_DEBUG->print("RS_Text::update: insert a " "letter at pos: %f/%f", letterPos.x, letterPos.y); RS_InsertData d(letterText, letterPos, RS_Vector(1.0, 1.0), 0.0, 1,1, RS_Vector(0.0,0.0), font->getLetterList(), RS2::NoUpdate); RS_Insert* letter = new RS_Insert(this, d); RS_Vector letterWidth; letter->setPen(RS_Pen(RS2::FlagInvalid)); letter->setLayer(NULL); letter->update(); letter->forcedCalculateBorders(); // until 2.0.4.5: //letterWidth = RS_Vector(letter->getSize().x, 0.0); // from 2.0.4.6: letterWidth = RS_Vector(letter->getMax().x-letterPos.x, 0.0); if (letterWidth.x < 0) letterWidth.x = -letterSpace.x; oneLine->addEntity(letter); // next letter position: letterPos += letterWidth; letterPos += letterSpace; // } } break; } } double tt = updateAddLine(oneLine, lineCounter); if (data.valign == RS_MTextData::VABottom) { RS_Vector ot = RS_Vector(0.0,-tt).rotate(data.angle); RS_EntityContainer::move(ot); } usedTextHeight -= data.height*data.lineSpacingFactor*5.0/3.0 - data.height; forcedCalculateBorders(); RS_DEBUG->print("RS_Text::update: OK"); }