📄 rs_text.cpp
字号:
/****************************************************************************** $Id: rs_text.cpp 1952 2005-01-07 15:21:19Z andrew $**** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.**** This file is part of the qcadlib Library project.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** Licensees holding valid qcadlib Professional Edition licenses may use ** this file in accordance with the qcadlib Commercial License** Agreement provided with the Software.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.ribbonsoft.com for further details.**** Contact info@ribbonsoft.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "rs_text.h"#include "rs_fontlist.h"#include "rs_insert.h"/** * Constructor. */RS_Text::RS_Text(RS_EntityContainer* parent, const RS_TextData& d) : RS_EntityContainer(parent), data(d) { usedTextHeight = 0.0; usedTextWidth = 0.0; setText(data.text);}/** * Sets a new text. The entities representing the * text are updated. */void RS_Text::setText(const RS_String& t) { data.text = t; // handle some special flags embedded in the text: if (data.text.left(4)=="\\A0;") { data.text = data.text.mid(4); data.valign = RS2::VAlignBottom; } else if (data.text.left(4)=="\\A1;") { data.text = data.text.mid(4); data.valign = RS2::VAlignMiddle; } else if (data.text.left(4)=="\\A2;") { data.text = data.text.mid(4); data.valign = RS2::VAlignTop; } if (data.updateMode==RS2::Update) { update(); //calculateBorders(); }}/** * Gets the alignment as an int. * * @return 1: top left ... 9: bottom right */int RS_Text::getAlignment() { if (data.valign==RS2::VAlignTop) { if (data.halign==RS2::HAlignLeft) { return 1; } else if (data.halign==RS2::HAlignCenter) { return 2; } else if (data.halign==RS2::HAlignRight) { return 3; } } else if (data.valign==RS2::VAlignMiddle) { if (data.halign==RS2::HAlignLeft) { return 4; } else if (data.halign==RS2::HAlignCenter) { return 5; } else if (data.halign==RS2::HAlignRight) { return 6; } } else if (data.valign==RS2::VAlignBottom) { if (data.halign==RS2::HAlignLeft) { return 7; } else if (data.halign==RS2::HAlignCenter) { return 8; } else if (data.halign==RS2::HAlignRight) { return 9; } } return 1;}/** * Sets the alignment from an int. * * @param a 1: top left ... 9: bottom right */void RS_Text::setAlignment(int a) { switch (a%3) { default: case 1: data.halign = RS2::HAlignLeft; break; case 2: data.halign = RS2::HAlignCenter; break; case 0: data.halign = RS2::HAlignRight; break; } switch ((int)ceil(a/3.0)) { default: case 1: data.valign = RS2::VAlignTop; break; case 2: data.valign = RS2::VAlignMiddle; break; case 3: data.valign = RS2::VAlignBottom; break; }}/** * @return Number of lines in this text entity. */int RS_Text::getNumberOfLines() { int c=1; for (int i=0; i<(int)data.text.length(); ++i) { if (data.text.at(i).unicode()==0x0A) { c++; } } return c;}/** * 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); 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) { 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); break; case 'S': { RS_String up; RS_String 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_Text* upper = new RS_Text( oneLine, RS_TextData(letterPos + RS_Vector(0.0,9.0), 4.0, 100.0, RS2::VAlignTop, RS2::HAlignLeft, RS2::LeftToRight, RS2::Exact, 1.0, up, data.style, 0.0, RS2::Update)); upper->setLayer(NULL); upper->setPen(RS_Pen(RS2::FlagInvalid)); oneLine->addEntity(upper); RS_Text* lower = new RS_Text( oneLine, RS_TextData(letterPos+RS_Vector(0.0,4.0), 4.0, 100.0, RS2::VAlignTop, RS2::HAlignLeft, RS2::LeftToRight, RS2::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; } break; default: break; } } break; default: { // One Letter: 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(RS_String(data.text.at(i)), 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); oneLine->addEntity(letter); // next letter position: letterPos += letterWidth; letterPos += letterSpace; } } break; } } updateAddLine(oneLine, lineCounter); usedTextHeight -= data.height*data.lineSpacingFactor*1.6 - data.height; forcedCalculateBorders(); RS_DEBUG->print("RS_Text::update: OK");}/** * Used internally by update() to add a text line created with * default values and alignment to this text container. * * @param textLine The text line. * @param lineCounter Line number. */void RS_Text::updateAddLine(RS_EntityContainer* textLine, int lineCounter) { RS_DEBUG->print("RS_Text::updateAddLine: width: %f", textLine->getSize().x); //textLine->forcedCalculateBorders(); //RS_DEBUG->print("RS_Text::updateAddLine: width 2: %f", textLine->getSize().x); // Move to correct line position: textLine->move(RS_Vector(0.0, -9.0 * lineCounter * data.lineSpacingFactor * 1.6)); textLine->forcedCalculateBorders(); RS_Vector textSize = textLine->getSize(); RS_DEBUG->print("RS_Text::updateAddLine: width 2: %f", textSize.x); // Horizontal Align: switch (data.halign) { case RS2::HAlignCenter: RS_DEBUG->print("RS_Text::updateAddLine: move by: %f", -textSize.x/2.0); textLine->move(RS_Vector(-textSize.x/2.0, 0.0)); break; case RS2::HAlignRight: textLine->move(RS_Vector(-textSize.x, 0.0)); break; default: break; } // Vertical Align: double vSize = getNumberOfLines()*9.0*data.lineSpacingFactor*1.6 - (9.0*data.lineSpacingFactor*1.6 - 9.0); switch (data.valign) { case RS2::VAlignMiddle: textLine->move(RS_Vector(0.0, vSize/2.0)); break; case RS2::VAlignBottom: textLine->move(RS_Vector(0.0, vSize)); break; default: break; } // Scale: textLine->scale(RS_Vector(0.0,0.0), RS_Vector(data.height/9.0, data.height/9.0)); textLine->forcedCalculateBorders(); // Update actual text size (before rotating, after scaling!): if (textLine->getSize().x>usedTextWidth) { usedTextWidth = textLine->getSize().x; } usedTextHeight += data.height*data.lineSpacingFactor*1.6; // Rotate: textLine->rotate(RS_Vector(0.0,0.0), data.angle); // Move: textLine->move(data.insertionPoint); textLine->setPen(RS_Pen(RS2::FlagInvalid)); textLine->setLayer(NULL); textLine->forcedCalculateBorders(); addEntity(textLine);}RS_VectorSolutions RS_Text::getRefPoints() { RS_VectorSolutions ret(data.insertionPoint); return ret;} RS_Vector RS_Text::getNearestRef(const RS_Vector& coord, double* dist) { //return getRefPoints().getClosest(coord, dist); return RS_Entity::getNearestRef(coord, dist);}void RS_Text::move(RS_Vector offset) { data.insertionPoint.move(offset); update();}void RS_Text::rotate(RS_Vector center, double angle) { data.insertionPoint.rotate(center, angle); data.angle = RS_Math::correctAngle(data.angle+angle); update();}void RS_Text::scale(RS_Vector center, RS_Vector factor) { data.insertionPoint.scale(center, factor); data.width*=factor.x; data.height*=factor.x; update();}void RS_Text::mirror(RS_Vector axisPoint1, RS_Vector axisPoint2) { data.insertionPoint.mirror(axisPoint1, axisPoint2); //double ang = axisPoint1.angleTo(axisPoint2); bool readable = RS_Math::isAngleReadable(data.angle); RS_Vector vec; vec.setPolar(1.0, data.angle); vec.mirror(RS_Vector(0.0,0.0), axisPoint2-axisPoint1); data.angle = vec.angle(); bool corr; data.angle = RS_Math::makeAngleReadable(data.angle, readable, &corr); if (corr) { if (data.halign==RS2::HAlignLeft) { data.halign=RS2::HAlignRight; } else if (data.halign==RS2::HAlignRight) { data.halign=RS2::HAlignLeft; } } else { if (data.valign==RS2::VAlignTop) { data.valign=RS2::VAlignBottom; } else if (data.valign==RS2::VAlignBottom) { data.valign=RS2::VAlignTop; } } update();}bool RS_Text::hasEndpointsWithinWindow(RS_Vector /*v1*/, RS_Vector /*v2*/) { return false;}/** * Implementations must stretch the given range of the entity * by the given offset. */void RS_Text::stretch(RS_Vector firstCorner, RS_Vector secondCorner, RS_Vector offset) { if (getMin().isInWindow(firstCorner, secondCorner) && getMax().isInWindow(firstCorner, secondCorner)) { move(offset); }}/** * Dumps the point's data to stdout. */std::ostream& operator << (std::ostream& os, const RS_Text& p) { os << " Text: " << p.getData() << "\n"; return os;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -