QSizeF ItemItem::calcMinimumGeometry() const { double width = 0.0; double height = 0.0; if (m_customIcon) { QSizeF sz = stereotypeIconMinimumSize(m_customIcon->stereotypeIcon(), CUSTOM_ICON_MINIMUM_AUTO_WIDTH, CUSTOM_ICON_MINIMUM_AUTO_HEIGHT); if (shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignTop && shapeIcon().textAlignment() != qmt::StereotypeIcon::TextalignCenter) return sz; width = sz.width(); } height += BODY_VERT_BORDER; if (CustomIconItem *stereotypeIconItem = this->stereotypeIconItem()) { width = std::max(width, stereotypeIconItem->boundingRect().width()); height += stereotypeIconItem->boundingRect().height(); } if (StereotypesItem *stereotypesItem = this->stereotypesItem()) { width = std::max(width, stereotypesItem->boundingRect().width()); height += stereotypesItem->boundingRect().height(); } if (nameItem()) { width = std::max(width, nameItem()->boundingRect().width()); height += nameItem()->boundingRect().height(); } if (m_contextLabel) height += m_contextLabel->height(); height += BODY_VERT_BORDER; width = BODY_HORIZ_BORDER + width + BODY_HORIZ_BORDER; return GeometryUtilities::ensureMinimumRasterSize(QSizeF(width, height), 2 * RASTER_WIDTH, 2 * RASTER_HEIGHT); }
void SymbolBucket::addFeatures(uintptr_t tileUID, SpriteAtlas& spriteAtlas, GlyphAtlas& glyphAtlas, GlyphStore& glyphStore) { float horizontalAlign = 0.5; float verticalAlign = 0.5; switch (layout.text.anchor) { case TextAnchorType::Top: case TextAnchorType::Bottom: case TextAnchorType::Center: break; case TextAnchorType::Right: case TextAnchorType::TopRight: case TextAnchorType::BottomRight: horizontalAlign = 1; break; case TextAnchorType::Left: case TextAnchorType::TopLeft: case TextAnchorType::BottomLeft: horizontalAlign = 0; break; } switch (layout.text.anchor) { case TextAnchorType::Left: case TextAnchorType::Right: case TextAnchorType::Center: break; case TextAnchorType::Bottom: case TextAnchorType::BottomLeft: case TextAnchorType::BottomRight: verticalAlign = 1; break; case TextAnchorType::Top: case TextAnchorType::TopLeft: case TextAnchorType::TopRight: verticalAlign = 0; break; } const float justify = layout.text.justify == TextJustifyType::Right ? 1 : layout.text.justify == TextJustifyType::Left ? 0 : 0.5; auto fontStack = glyphStore.getFontStack(layout.text.font); for (const auto& feature : features) { if (feature.geometry.empty()) continue; Shaping shapedText; PositionedIcon shapedIcon; GlyphPositions face; // if feature has text, shape the text if (feature.label.length()) { shapedText = fontStack->getShaping( /* string */ feature.label, /* maxWidth: ems */ layout.placement != PlacementType::Line ? layout.text.maxWidth * 24 : 0, /* lineHeight: ems */ layout.text.lineHeight * 24, /* horizontalAlign */ horizontalAlign, /* verticalAlign */ verticalAlign, /* justify */ justify, /* spacing: ems */ layout.text.letterSpacing * 24, /* translate */ vec2<float>(layout.text.offset.value[0], layout.text.offset.value[1])); // Add the glyphs we need for this label to the glyph atlas. if (shapedText) { glyphAtlas.addGlyphs(tileUID, feature.label, layout.text.font, **fontStack, face); } } // if feature has icon, get sprite atlas position if (feature.sprite.length()) { auto image = spriteAtlas.getImage(feature.sprite, false); if (image) { shapedIcon = shapeIcon(*image, layout); assert((*image).spriteImage); if ((*image).spriteImage->sdf) { sdfIcons = true; } if ((*image).relativePixelRatio != 1.0f) { iconsNeedLinear = true; } } } // if either shapedText or icon position is present, add the feature if (shapedText || shapedIcon) { addFeature(feature.geometry, shapedText, shapedIcon, face); } } features.clear(); }
void ItemItem::updateGeometry() { prepareGeometryChange(); // calc width and height double width = 0.0; double height = 0.0; QSizeF geometry = calcMinimumGeometry(); width = geometry.width(); height = geometry.height(); if (object()->isAutoSized()) { // nothing } else { QRectF rect = object()->rect(); if (rect.width() > width) width = rect.width(); if (rect.height() > height) height = rect.height(); } // update sizes and positions double left = -width / 2.0; double right = width / 2.0; double top = -height / 2.0; double y = top; setPos(object()->pos()); QRectF rect(left, top, width, height); // the object is updated without calling DiagramController intentionally. // attribute rect is not a real attribute stored on DObject but // a backup for the graphics item used for manual resized and persistency. object()->setRect(rect); if (m_customIcon) { m_customIcon->setPos(left, top); m_customIcon->setActualSize(QSizeF(width, height)); } if (m_shape) m_shape->setRect(rect); if (m_customIcon) { switch (shapeIcon().textAlignment()) { case qmt::StereotypeIcon::TextalignBelow: y += height + BODY_VERT_BORDER; break; case qmt::StereotypeIcon::TextalignCenter: { double h = 0.0; if (CustomIconItem *stereotypeIconItem = this->stereotypeIconItem()) h += stereotypeIconItem->boundingRect().height(); if (StereotypesItem *stereotypesItem = this->stereotypesItem()) h += stereotypesItem->boundingRect().height(); if (nameItem()) h += nameItem()->boundingRect().height(); if (m_contextLabel) h += m_contextLabel->height(); y = top + (height - h) / 2.0; break; } case qmt::StereotypeIcon::TextalignNone: // nothing to do break; case qmt::StereotypeIcon::TextalignTop: y += BODY_VERT_BORDER; break; } } else { y += BODY_VERT_BORDER; } if (CustomIconItem *stereotypeIconItem = this->stereotypeIconItem()) { stereotypeIconItem->setPos(right - stereotypeIconItem->boundingRect().width() - BODY_HORIZ_BORDER, y); y += stereotypeIconItem->boundingRect().height(); } if (StereotypesItem *stereotypesItem = this->stereotypesItem()) { stereotypesItem->setPos(-stereotypesItem->boundingRect().width() / 2.0, y); y += stereotypesItem->boundingRect().height(); } if (nameItem()) { nameItem()->setPos(-nameItem()->boundingRect().width() / 2.0, y); y += nameItem()->boundingRect().height(); } if (m_contextLabel) { if (m_customIcon) { m_contextLabel->resetMaxWidth(); } else { double maxContextWidth = width - 2 * BODY_HORIZ_BORDER; m_contextLabel->setMaxWidth(maxContextWidth); } m_contextLabel->setPos(-m_contextLabel->boundingRect().width() / 2.0, y); } updateSelectionMarkerGeometry(rect); updateRelationStarterGeometry(rect); updateAlignmentButtonsGeometry(rect); updateDepth(); }