/*************************************************************************** * Copyright (c) 2009 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # ifdef FC_OS_WIN32 # include # endif # ifdef FC_OS_MACOSX # include # else # include # endif # include # include # include # include # include # include # include # include # include # include #endif #include #include #include #include #include #include #include #include #include #include #include #if COIN_MAJOR_VERSION > 3 #include #else #include #endif #include #include "SoTextLabel.h" #include "SoFCInteractiveElement.h" #include "BitmapFactory.h" using namespace Gui; /*! \code s=""" #Inventor V2.1 ascii Annotation { Translation { translation 4 0 0 } FontStyle { size 20 style BOLD } BaseColor { rgb 0.0 0.0 0.0 } SoTextLabel { string ["Text label", "Second line"] backgroundColor 1.0 0.447059 0.337255} } """ App.ActiveDocument.addObject("App::InventorObject","iv").Buffer=s \endcode */ SO_NODE_SOURCE(SoTextLabel); void SoTextLabel::initClass() { SO_NODE_INIT_CLASS(SoTextLabel, SoText2, "Text2"); } SoTextLabel::SoTextLabel() { SO_NODE_CONSTRUCTOR(SoTextLabel); SO_NODE_ADD_FIELD(backgroundColor, (SbVec3f(1.0f,1.0f,1.0f))); SO_NODE_ADD_FIELD(background, (true)); SO_NODE_ADD_FIELD(frameSize, (10.0f)); } /** * Renders the label. */ void SoTextLabel::GLRender(SoGLRenderAction *action) { if (!this->shouldGLRender(action)) return; // only draw text without background if (!this->background.getValue()) { inherited::GLRender(action); return; } SoState * state = action->getState(); state->push(); SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); SbBox3f box; SbVec3f center; this->computeBBox(action, box, center); if (!SoCullElement::cullTest(state, box, true)) { SoMaterialBundle mb(action); mb.sendFirst(); const SbMatrix & mat = SoModelMatrixElement::get(state); //const SbViewVolume & vv = SoViewVolumeElement::get(state); const SbMatrix & projmatrix = (mat * SoViewingMatrixElement::get(state) * SoProjectionMatrixElement::get(state)); const SbViewportRegion & vp = SoViewportRegionElement::get(state); SbVec2s vpsize = vp.getViewportSizePixels(); // font stuff //float space = this->spacing.getValue(); //float fontsize = SoFontSizeElement::get(state); SbName fontname = SoFontNameElement::get(state); int lines = this->string.getNum(); // get left bottom corner of the label SbVec3f nilpoint(0.0f, 0.0f, 0.0f); projmatrix.multVecMatrix(nilpoint, nilpoint); nilpoint[0] = (nilpoint[0] + 1.0f) * 0.5f * vpsize[0]; nilpoint[1] = (nilpoint[1] + 1.0f) * 0.5f * vpsize[1]; #if 1 // Unfortunately, the size of the label is stored in the pimpl class of // SoText2 which cannot be accessed directly. However, there is a trick // to get the required information: set model, viewing and projection // matrix to the identity matrix and also view volume to some default // values. SoText2::computeBBox() then calls SoText2P::getQuad which // returns the sizes in form of the bounding box. These values can be // reverse-engineered to get width and height. state->push(); SoModelMatrixElement::set(state,this,SbMatrix::identity()); SoViewingMatrixElement::set(state,this,SbMatrix::identity()); SoProjectionMatrixElement::set(state,this,SbMatrix::identity()); SbViewVolume vv; vv.ortho(-1,1,-1,1,-1,1); SoViewVolumeElement::set(state,this,vv); SbBox3f box; SbVec3f center; this->computeBBox(action, box, center); state->pop(); float xmin,ymin,zmin,xmax,ymax,zmax; box.getBounds(xmin,ymin,zmin,xmax,ymax,zmax); SbVec3f v0(xmin,ymax,zmax); SbVec3f v1(xmax,ymax,zmax); SbVec3f v2(xmax,ymin,zmax); SbVec3f v3(xmin,ymin,zmax); vv.projectToScreen(v0,v0); vv.projectToScreen(v1,v1); vv.projectToScreen(v2,v2); vv.projectToScreen(v3,v3); float width,height; width = (v1[0]-v0[0])*vpsize[0]; height = (v1[1]-v3[1])*vpsize[1]; switch (this->justification.getValue()) { case SoText2::RIGHT: nilpoint[0] -= width; break; case SoText2::CENTER: nilpoint[0] -= 0.5f*width; break; default: break; } if (lines > 1) { nilpoint[1] -= (float(lines-1)/(float)lines*height); } #else // Unfortunately, the required size (in pixels) is stored in a non-accessible way // in the subclass SoText2. Thus, we try to get a satisfactory solution with Qt // methods. // The font name is of the form "family:style". If 'style' is given it can be // 'Bold', 'Italic' or 'Bold Italic'. QFont font; QString fn = QString::fromLatin1(fontname.getString()); int pos = fn.indexOf(QLatin1Char(':')); if (pos > -1) { if (fn.indexOf(QLatin1String("Bold"),pos,Qt::CaseInsensitive) > pos) font.setBold(true); if (fn.indexOf(QLatin1String("Italic"),pos,Qt::CaseInsensitive) > pos) font.setItalic(true); fn = fn.left(pos); } font.setFamily(fn); font.setPixelSize((int)fontsize); QFontMetrics fm(font); float width = 0.0f; float height = 0.75f*fontsize*lines + (lines-1)*space;//fm.height(); float hh=0; for (int i = 0; i < lines; i++) { SbString str = this->string[i]; float w = fm.width(QLatin1String(this->string[i].getString())); width = std::max(width, w); hh = fm.height(); } if (lines > 1) { nilpoint[1] -= ((lines-1)*fontsize*0.75f+space); } #endif SbVec3f toppoint = nilpoint; toppoint[0] += width; toppoint[1] += height; // Set new state. glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, vpsize[0], 0, vpsize[1], -1.0f, 1.0f); glPixelStorei(GL_UNPACK_ALIGNMENT,1); state->push(); // disable textures for all units SoGLTextureEnabledElement::set(state, this, false); #if COIN_MAJOR_VERSION > 3 SoMultiTextureEnabledElement::set(state, this, false); #else SoGLTexture3EnabledElement::set(state, this, false); #endif glPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT); glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); // color and frame size SbColor color = this->backgroundColor.getValue(); float fs = this->frameSize.getValue(); // draw background glColor3f(color[0], color[1], color[2]); glBegin(GL_QUADS); glVertex3f(nilpoint[0]-fs,nilpoint[1]-fs,0.0f); glVertex3f(toppoint[0]+fs,nilpoint[1]-fs,0.0f); glVertex3f(toppoint[0]+fs,toppoint[1]+fs,0.0f); glVertex3f(nilpoint[0]-fs,toppoint[1]+fs,0.0f); glEnd(); // pop old state glPopClientAttrib(); glPopAttrib(); state->pop(); glPixelStorei(GL_UNPACK_ALIGNMENT,4); // Pop old GL matrix state. glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } state->pop(); inherited::GLRender(action); } // ------------------------------------------------------ SO_NODE_SOURCE(SoStringLabel); void SoStringLabel::initClass() { SO_NODE_INIT_CLASS(SoStringLabel, SoNode, "Node"); } SoStringLabel::SoStringLabel() { SO_NODE_CONSTRUCTOR(SoStringLabel); SO_NODE_ADD_FIELD(string, ("")); SO_NODE_ADD_FIELD(textColor, (SbVec3f(1.0f,1.0f,1.0f))); SO_NODE_ADD_FIELD(name, ("Helvetica")); SO_NODE_ADD_FIELD(size, (12)); } /** * Renders the open edges only. */ void SoStringLabel::GLRender(SoGLRenderAction *action) { QtGLWidget* window; SoState * state = action->getState(); state->push(); SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); SoGLWidgetElement::get(state, window); if (!window) { state->pop(); return; } // Enter in 2D screen mode glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(-1,1,-1,1,-1,1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); QFont font; font.setStyleStrategy(QFont::NoAntialias); font.setFamily(QLatin1String(this->name.getValue())); font.setPixelSize(this->size.getValue()); glBlendFunc(GL_ONE,GL_SRC_ALPHA); /* Background Box */ //glColor4f(1,0.1f,0.1f,1); //int ln =4; //float ls = font.pixelSize()*1.5f; //float bh = -1 + 2.0*(ls*(ln+.25))/float(window->height()); //glBegin(GL_QUADS); //glVertex2f(-1.f,bh); glVertex2f(-1.f,-1.f); //glVertex2f( 1.f,-1.f); glVertex2f( 1.f,bh); //glEnd(); //float middleCol=window->width()*0.40; //float rightCol=window->width()*0.85; //float startPos = window->height()-(5+ls*(ln)); // text color SbColor color = this->textColor.getValue(); glColor4f(color[0], color[1], color[2],1); //window->renderText(20,20/*startPos+ 1*ls*/,QLatin1String(this->string[0].getString()),font); const SbMatrix & mat = SoModelMatrixElement::get(state); const SbMatrix & projmatrix = (mat * SoViewingMatrixElement::get(state) * SoProjectionMatrixElement::get(state)); SbVec3f nil(0.0f, 0.0f, 0.0f); projmatrix.multVecMatrix(nil, nil); QStringList list; for (int i=0; istring.getNum(); i++) list << QLatin1String(this->string[i].getString()); #if !defined(HAVE_QT5_OPENGL) window->renderText(nil[0],nil[1],nil[2],list.join(QLatin1String("\n")),font); #else //FIXME: HAVE_QT5_OPENGL #endif // Leave 2D screen mode glPopAttrib(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); state->pop(); } // ------------------------------------------------------ SO_NODE_SOURCE(SoFrameLabel); void SoFrameLabel::initClass() { SO_NODE_INIT_CLASS(SoFrameLabel, SoImage, "Image"); } SoFrameLabel::SoFrameLabel() { SO_NODE_CONSTRUCTOR(SoFrameLabel); SO_NODE_ADD_FIELD(string, ("")); SO_NODE_ADD_FIELD(textColor, (SbVec3f(1.0f,1.0f,1.0f))); SO_NODE_ADD_FIELD(backgroundColor, (SbVec3f(0.0f,0.333f,1.0f))); SO_NODE_ADD_FIELD(justification, (LEFT)); SO_NODE_ADD_FIELD(name, ("Helvetica")); SO_NODE_ADD_FIELD(size, (12)); SO_NODE_ADD_FIELD(frame, (true)); //SO_NODE_ADD_FIELD(image, (SbVec2s(0,0), 0, NULL)); } void SoFrameLabel::notify(SoNotList * list) { SoField *f = list->getLastField(); if (f == &this->string || f == &this->textColor || f == &this->backgroundColor || f == &this->justification || f == &this->name || f == &this->size || f == &this->frame) { drawImage(); } inherited::notify(list); } void SoFrameLabel::drawImage() { const SbString* s = string.getValues(0); int num = string.getNum(); if (num == 0) { this->image = SoSFImage(); return; } QFont font(QString::fromLatin1(name.getValue()), size.getValue()); QFontMetrics fm(font); int w = 0; int h = fm.height() * num; const SbColor& b = backgroundColor.getValue(); QColor brush; brush.setRgbF(b[0],b[1],b[2]); const SbColor& t = textColor.getValue(); QColor front; front.setRgbF(t[0],t[1],t[2]); QStringList lines; for (int i=0; i(w, fm.width(line)); lines << line; } QImage image(w+10,h+10,QImage::Format_ARGB32_Premultiplied); image.fill(0x00000000); QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing); SbBool drawFrame = frame.getValue(); if (drawFrame) { painter.setPen(QPen(QColor(0,0,127), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter.setBrush(QBrush(brush, Qt::SolidPattern)); QRectF rectangle(0.0, 0.0, w+10, h+10); painter.drawRoundedRect(rectangle, 5, 5); } painter.setPen(front); Qt::Alignment align = Qt::AlignVCenter; if (justification.getValue() == 0) align = Qt::AlignVCenter | Qt::AlignLeft; else if (justification.getValue() == 1) align = Qt::AlignVCenter | Qt::AlignRight; else align = Qt::AlignVCenter | Qt::AlignHCenter; QString text = lines.join(QLatin1String("\n")); painter.setFont(font); painter.drawText(5,5,w,h,align,text); painter.end(); SoSFImage sfimage; Gui::BitmapFactory().convert(image, sfimage); this->image = sfimage; } /** * Renders the open edges only. */ void SoFrameLabel::GLRender(SoGLRenderAction *action) { inherited::GLRender(action); #if 0 QtGLWidget* window; SoState * state = action->getState(); state->push(); SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); SoGLWidgetElement::get(state, window); if (!window) { state->pop(); return; } // Enter in 2D screen mode glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(-1,1,-1,1,-1,1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); QFont font; font.setStyleStrategy(QFont::NoAntialias); font.setFamily(QLatin1String(this->name.getValue())); font.setPixelSize(this->size.getValue()); glBlendFunc(GL_ONE,GL_SRC_ALPHA); /* Background Box */ //glColor4f(1,0.1f,0.1f,1); //int ln =4; //float ls = font.pixelSize()*1.5f; //float bh = -1 + 2.0*(ls*(ln+.25))/float(window->height()); //glBegin(GL_QUADS); //glVertex2f(-1.f,bh); glVertex2f(-1.f,-1.f); //glVertex2f( 1.f,-1.f); glVertex2f( 1.f,bh); //glEnd(); //float middleCol=window->width()*0.40; //float rightCol=window->width()*0.85; //float startPos = window->height()-(5+ls*(ln)); // text color SbColor color = this->textColor.getValue(); glColor4f(color[0], color[1], color[2],1); //window->renderText(20,20/*startPos+ 1*ls*/,QLatin1String(this->string[0].getString()),font); const SbMatrix & mat = SoModelMatrixElement::get(state); const SbMatrix & projmatrix = (mat * SoViewingMatrixElement::get(state) * SoProjectionMatrixElement::get(state)); SbVec3f nil(0.0f, 0.0f, 0.0f); projmatrix.multVecMatrix(nil, nil); QStringList list; for (int i=0; istring.getNum(); i++) list << QLatin1String(this->string[i].getString()); window->renderText(nil[0],nil[1],nil[2],list.join(QLatin1String("\n")),font); // Leave 2D screen mode glPopAttrib(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); state->pop(); #endif } // ------------------------------------------------------ SO_NODE_SOURCE(TranslateManip); void TranslateManip::initClass() { SO_NODE_INIT_CLASS(TranslateManip, SoTransformManip, "TransformManip"); } TranslateManip::TranslateManip() { SO_NODE_CONSTRUCTOR(TranslateManip); SoTranslate2Dragger *myDrag = new SoTranslate2Dragger; setDragger(myDrag); } TranslateManip::~TranslateManip() { }