/** * @RDE_HEADER@ * GraphicalObjectText * $Id$ * $HeadURL$ * $Author$ */ // Own #include "graphical_object_text.h" #include // operator<< // ESRI #include #include #include // Qt #include #include #include namespace SituationMap { GraphicalObjectText::GraphicalObjectText(const Esri::ArcGISRuntime::GeoView *geoView , Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer , const QString &debugInfo , const UniqueMapId &uniqueMapId) : BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId) , m_textSymbol(nullptr) , m_logger(getLogger("GraphicalObjectText")) { TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"; TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"; } GraphicalObjectText::~GraphicalObjectText() { TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'" << " text='" << m_text << "'"; delete m_textSymbol; m_textSymbol = nullptr; TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'" << " text='" << m_text << "'"; } QString GraphicalObjectText::toString() const { QString str; // str.append( BaseClass::toString() ); if (!m_debugInfo.isEmpty()) str.append(QStringLiteral("debugInfo=%1").arg(m_debugInfo)); if (m_graphicsLayer) str.append(QStringLiteral(" layer='%1'").arg(m_graphicsLayer->objectName())); if (m_graphic) str.append(QStringLiteral(" zIndex='%1'").arg(m_graphic->zIndex())); std::ostringstream stream; stream << this->origin(); str.append(QLatin1String(stream.str().c_str())); if (!m_text.value().isEmpty()) str.append(QStringLiteral("text=%1").arg(m_text.value())); return str; } QString GraphicalObjectText::text() const { return m_text.value(); } void GraphicalObjectText::setText(const QString &text) { m_text = text; } TextStyle GraphicalObjectText::textStyle() const { return m_textStyle.value(); } TextStyle &GraphicalObjectText::rTextStyle() { return m_textStyle.refValue(); } void GraphicalObjectText::setTextStyle(const TextStyle &textStyle) { m_textStyle = textStyle; } float GraphicalObjectText::xOffset() const { return m_offset.value().x(); } void GraphicalObjectText::setXOffset(float xOffset) { QPointF temp = m_offset.value(); temp.rx() = xOffset; m_offset = temp; } float GraphicalObjectText::yOffset() const { return m_offset.value().y(); } void GraphicalObjectText::setYOffset(float yOffset) { QPointF temp = m_offset.value(); temp.ry() = yOffset; m_offset = temp; } bool GraphicalObjectText::create() { TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'" << " text='" << m_text << "'" << " origin =" << this->origin() // .x() << " , " << this->origin().y() << " visibility=" << m_visibility; bool success = true; // some checks: if (!m_graphicsLayer) { ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " no graphicsLayer"; return false; } BaseClass::create(); if (!m_textSymbol) m_textSymbol = new Esri::ArcGISRuntime::TextSymbol(); TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'" << " text='" << m_text << "'" << " success=" << success << " drawOrder = " << m_graphic->zIndex(); return success; } bool GraphicalObjectText::updateViewImpl() { TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'" << " text='" << m_text << "'" << " origin =" << this->origin() // .x() << " , " << this->origin().y() << " visibility=" << m_visibility << " m_textStyle=" << m_textStyle << " offset=" << m_offset; // some checks: if (!this->isSinglePoint()) { ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " incorrect number of positions" << " (" << this->positions().count() << ")"; return false; } bool success = true; if (m_visibility.value()) { success = create(); // create only if visible if (!success) { ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " create failed"; return false; } if (! BaseClass::updateViewImpl()) { ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " updateViewImpl failed"; } // FATAL_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" // << " text='" << m_text << "'" // << " changed1=" << m_text.changed() // << " changed2="<< m_textStyle.changed(); bool assignTextSymbol = false; // || m_visibility.changed()) -> szenario: create invisible object and make it visible if (m_text.changed() || m_visibility.changed()) { m_textSymbol->setText(m_text.value()); assignTextSymbol = true; } // TextStyle to TextSymbol@ESRI : if (m_textStyle.changed() || m_scale.changed() || m_visibility.changed() // -> szenario: create invisible object and make it visible ) { const TextStyle &textStyle = m_textStyle.value(); m_textSymbol->setColor(textStyle.textColor()); // High values can lead to coredump with 'SymbolDrawHelper::create_line_image FAILED, SkBitmap is NULL or empty' -> limit m_textSymbol->setSize(std::min(500.0f, textStyle.size() * m_scale.value())); m_textSymbol->setAngle(textStyle.angle()); m_textSymbol->setFontFamily(textStyle.fontFamily()); m_textSymbol->setFontWeight(textStyle.bold() ? Esri::ArcGISRuntime::FontWeight::Bold : Esri::ArcGISRuntime::FontWeight::Normal); m_textSymbol->setFontStyle(textStyle.italic() ? Esri::ArcGISRuntime::FontStyle::Italic : Esri::ArcGISRuntime::FontStyle::Normal); Esri::ArcGISRuntime::FontDecoration fd = Esri::ArcGISRuntime::FontDecoration::None; if (textStyle.underline()) fd = Esri::ArcGISRuntime::FontDecoration::Underline; if (textStyle.strikeThrough()) fd = Esri::ArcGISRuntime::FontDecoration::LineThrough; m_textSymbol->setFontDecoration(fd); float outlineWidth = 0; if (textStyle.textOutlineWidth() > 0) outlineWidth = textStyle.textOutlineWidth() * m_scale.value(); if (m_textSymbol->size() <= 15) // small size -> outline reduces readability :-( outlineWidth = 0.0; m_textSymbol->setHaloWidth(outlineWidth); if (textStyle.textOutlineColor().isValid()) m_textSymbol->setHaloColor(textStyle.textOutlineColor()); // qWarning() << " haloWidth = " << m_textSymbol->haloWidth(); // m_textSymbol->setHaloColor(Qt::white); // m_textSymbol->setHaloWidth(outlineWidth); // qWarning() << " fontSize " << textStyle.size() * m_scale.value() // <<" (textStyle.size() " << textStyle.size() // << " m_scale.value() " << m_scale.value() << ")"; // qWarning() << " outlineWidth " << outlineWidth // <<" (textStyle.textOutlineWidth() " << textStyle.textOutlineWidth() // << " m_scale.value() " << m_scale.value() << ")"; // if (textStyle.backgroundColor().isValid()) m_textSymbol->setBackgroundColor(textStyle.backgroundColor()); // m_textSymbol->setAntiAliased(textStyle.antiAliased()); m_textSymbol->setHorizontalAlignment(convert(textStyle.horizontalAlignment())); m_textSymbol->setVerticalAlignment(convert(textStyle.verticalAlignment())); assignTextSymbol = true; // : TextStyle to TextSymbol@ESRI } // || m_visibility.changed()) -> szenario: create invisible object and make it visible if (m_offset.changed() || m_visibility.changed()) { m_textSymbol->setOffsetX(m_offset.value().x()); m_textSymbol->setOffsetY(m_offset.value().y()); assignTextSymbol = true; } if (assignTextSymbol) m_graphic->setSymbol(m_textSymbol); // check ChangedFlags: // Object is created and text is invisble due to scale (meterPerPixel) // map is zoomed in -> text should arise, but on m_visibility is changed: if (m_visibility.changed() || m_positions.changed()) { const Point3D &origin = this->origin(); m_graphic->setGeometry(Esri::ArcGISRuntime::Point(origin.x(), origin.y(), origin.z(), spatialReference())); success = addUpdateGraphic(); } // m_visibility.changed() || m_positions.changed() } else // if visible { BaseClass::updateViewImpl(); success = addUpdateGraphic(); } if (m_logger.isTraceEnabled()) { int drawOrder = -1; if (m_graphic) drawOrder = m_graphic->zIndex(); TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'" << " text='" << m_text << "'" << " success=" << success << " drawOrder = " << drawOrder; } TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'" // << " fontFamily='" << m_textSymbol->fontFamily() << "'" ; return success; } Esri::ArcGISRuntime::HorizontalAlignment GraphicalObjectText::convert(const HorizontalAlignment horizontalAlignment) { Esri::ArcGISRuntime::HorizontalAlignment esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Left; switch (horizontalAlignment) { case HorizontalAlignment::Left: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Left; break; case HorizontalAlignment::Center: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Center; break; case HorizontalAlignment::Right: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Right; break; case HorizontalAlignment::Justify: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Justify; break; } // switch return esriAlignmenmt; } Esri::ArcGISRuntime::VerticalAlignment GraphicalObjectText::convert(const VerticalAlignment verticalAlignment) { Esri::ArcGISRuntime::VerticalAlignment esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Bottom; switch (verticalAlignment) { case VerticalAlignment::Bottom: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Bottom; break; case VerticalAlignment::Middle: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Middle; break; case VerticalAlignment::Top: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Top; break; case VerticalAlignment::BaseLine: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Baseline; break; } // switch return esriAlignmenmt; } } // namespace SituationMap