//protected void MapGraphicsView::doTileLayout() { //Calculate the center point and polygon of the viewport in QGraphicsScene coordinates const QPointF centerPointQGS = _childView->mapToScene(_childView->width()/2.0, _childView->height()/2.0); QPolygon viewportPolygonQGV; viewportPolygonQGV << QPoint(0,0) << QPoint(0,_childView->height()) << QPoint(_childView->width(),_childView->height()) << QPoint(_childView->width(),0); const QPolygonF viewportPolygonQGS = _childView->mapToScene(viewportPolygonQGV); const QRectF boundingRect = viewportPolygonQGS.boundingRect(); //We exaggerate the bounding rect for some purposes! QRectF exaggeratedBoundingRect = boundingRect; exaggeratedBoundingRect.setSize(boundingRect.size()*2.0); exaggeratedBoundingRect.moveCenter(boundingRect.center()); //We'll mark tiles that aren't being displayed as free so we can use them QQueue<MapTileGraphicsObject *> freeTiles; QSet<QPointF> placesWhereTilesAre; foreach(MapTileGraphicsObject * tileObject, _tileObjects) { if (!tileObject->isVisible() || !exaggeratedBoundingRect.contains(tileObject->pos())) { freeTiles.enqueue(tileObject); tileObject->setVisible(false); } else placesWhereTilesAre.insert(tileObject->pos()); } const quint16 tileSize = _tileSource->tileSize(); const quint32 tilesPerRow = sqrt((long double)_tileSource->tilesOnZoomLevel(this->zoomLevel())); const quint32 tilesPerCol = tilesPerRow; const qint32 perSide = qMax(boundingRect.width()/tileSize, boundingRect.height()/tileSize) + 3; const qint32 xc = qMax((qint32)0, (qint32)(centerPointQGS.x() / tileSize) - perSide/2); const qint32 yc = qMax((qint32)0, (qint32)(centerPointQGS.y() / tileSize) - perSide/2); const qint32 xMax = qMin((qint32)tilesPerRow, xc + perSide); const qint32 yMax = qMin(yc + perSide, (qint32)tilesPerCol); for (qint32 x = xc; x < xMax; x++) { for (qint32 y = yc; y < yMax; y++) { const QPointF scenePos(x*tileSize + tileSize/2, y*tileSize + tileSize/2); bool tileIsThere = false; if (placesWhereTilesAre.contains(scenePos)) tileIsThere = true; if (tileIsThere) continue; //Just in case we're running low on free tiles, add one if (freeTiles.isEmpty()) { MapTileGraphicsObject * tileObject = new MapTileGraphicsObject(tileSize); tileObject->setTileSource(_tileSource); _tileObjects.insert(tileObject); _childScene->addItem(tileObject); freeTiles.enqueue(tileObject); } //Get the first free tile and make it do its thing MapTileGraphicsObject * tileObject = freeTiles.dequeue(); if (tileObject->pos() != scenePos) tileObject->setPos(scenePos); if (tileObject->isVisible() != true) tileObject->setVisible(true); tileObject->setTile(x,y,this->zoomLevel()); } } //If we've got a lot of free tiles left over, delete some of them while (freeTiles.size() > 2) { MapTileGraphicsObject * tileObject = freeTiles.dequeue(); _tileObjects.remove(tileObject); _childScene->removeItem(tileObject); delete tileObject; } }
void ChessBoard::renderBoard( QPainter &p, const QRectF &rc, bool flip, const std::vector<cheng4::Square> *excludeSquares ) { qreal maxh = std::max( rc.width(), rc.height() )/14; maxh = 18; qreal bordersz = maxh; if ( !border ) bordersz = 0; qreal sw = (rc.width() - 2*bordersz) / 8; qreal sh = (rc.height() - 2*bordersz) / 8; sh = sw = std::min(sw, sh); QColor wb[2] = { QColor(255, 255, 255, 255), QColor(0, 0, 0, 255) }; QColor bord = borderColor; QBrush lightb(lightColor); QBrush darkb(darkColor); p.setPen(Qt::transparent); // render border... p.setBrush( QBrush(bord) ); p.drawRect(QRectF(rc.left(), rc.top(), 8*sw + 2*bordersz+1, 8*sh + 2*bordersz+1)); QPen bpen( QColor(0, 0, 0, 128) ); bpen.setWidth(1); p.setPen( bpen ); p.setBrush( Qt::transparent ); QRectF brect; brect.setTopLeft( QPoint(bordersz-1, bordersz-1) ); brect.setSize( QSizeF(8*sw+2, 8*sh+2) ); p.drawRect( brect ); brect.setTopLeft( QPoint(0, 0) ); brect.setSize( QSizeF(8*sw+2*bordersz, 8*sh+2*bordersz) ); p.drawRect( brect ); p.setPen( Qt::transparent ); for (cheng4::Square s = 0; s < 64; s++) { cheng4::File f = cheng4::SquarePack::file(s); cheng4::Rank r = cheng4::SquarePack::rank(s); QRectF sub(rc.left() + sw*f + bordersz, rc.top() + sh*r + bordersz, sw, sh); cheng4::Square sq = flip ? cheng4::SquarePack::flipH(cheng4::SquarePack::flipV(s)) : s; p.setBrush( ((f+r) & 1) ? darkb : lightb ); p.drawRect( sub ); if ( excludeSquares && std::find(excludeSquares->begin(), excludeSquares->end(), sq) != excludeSquares->end() ) continue; cheng4::Piece pc = board.piece(sq); cheng4::Piece pt = cheng4::PiecePack::type(pc); if ( pt == cheng4::ptNone ) continue; cheng4::Color c = cheng4::PiecePack::color(pc); if ( !pieceSet || !pieceSet->pieces[c][pt-1] ) continue; pieceSet->pieces[c][pt-1]->renderer()->render(&p, sub); } // FIXME: better!!! for (cheng4::Square s = 0; s < 64; s++) { cheng4::File f = cheng4::SquarePack::file(s); cheng4::Rank r = cheng4::SquarePack::rank(s); QRectF sub(rc.left() + sw*f + bordersz, rc.top() + sh*r + bordersz, sw, sh); cheng4::Square sq = flip ? cheng4::SquarePack::flipH(cheng4::SquarePack::flipV(s)) : s; // now highlight!!! if ( highlight == cheng4::mcNone || highlight == cheng4::mcNull ) continue; cheng4::Square from, to; from = cheng4::MovePack::from(highlight); to = cheng4::MovePack::to(highlight); if ( sq != from && sq != to ) continue; QPen hpen( highlightColor ); hpen.setWidth(2); p.setPen( hpen ); p.setBrush( Qt::transparent ); p.drawRect( sub ); p.setPen( Qt::transparent ); } if ( !border ) return; // draw board letters p.setPen( letterColor ); QTextOption opt; opt.setAlignment(Qt::AlignCenter); QFont font; font.setBold(0); font.setPixelSize(12); p.setFont(font); for (uint i=0; i<8; i++) { // rows: QPointF pt( 0, bordersz + sh*i ); QRectF rct; rct.setTopLeft( pt ); rct.setSize( QSizeF( bordersz, sh ) ); QString text; int irow = 7-(int)i; if ( flip ) irow = 8-1-irow; text.sprintf("%d", irow+1); p.drawText(rct, text, opt); pt.setX( bordersz+sw*8 ); rct.setTopLeft( pt ); rct.setSize( QSizeF( bordersz, sh ) ); p.drawText(rct, text, opt); // cols: int icol = (int)i; if ( flip ) icol = 8-1-i; text.sprintf("%c", 'a' + icol); pt.setX( bordersz + sw*i ); pt.setY( 0 ); rct.setTopLeft(pt); rct.setSize( QSizeF( sw, bordersz ) ); p.drawText(rct, text, opt); pt.setY( bordersz+sh*8 ); rct.setTopLeft( pt ); rct.setSize( QSizeF( sw, bordersz ) ); p.drawText(rct, text, opt); } // draw stm QRectF upr; upr.setTopLeft( QPointF( bordersz + sw*8 + bordersz/8, bordersz/8 ) ); upr.setSize( QSizeF( bordersz - 2*bordersz/8, bordersz - 2*bordersz/8 ) ); bool upper = board.turn() == (flip ? cheng4::ctWhite : cheng4::ctBlack); p.setPen( wb[ cheng4::flip(board.turn()) ] ); p.setBrush( wb[ board.turn() ] ); if ( upper ) p.drawRect( upr ); QRectF lwr; lwr.setTopLeft( QPointF( bordersz + sw*8 + bordersz/8, bordersz + sh*8 + bordersz/8 ) ); lwr.setSize( QSizeF( bordersz - 2*bordersz/8, bordersz - 2*bordersz/8 ) ); if ( !upper ) p.drawRect( lwr ); }
void paintEvent(QPaintEvent *event) { Q_UNUSED (event) // XXX Maybe we should cache this and recompute separately for // transform changes, shape movement and viewport changes? // Draw a white background. QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::white); painter.setBrush(Qt::white); QRectF drawingRect = QRectF(0, 0, width(), height()); painter.drawRect(drawingRect); if (m_canvasview == NULL) { return; } // Compute the diagram bounds. Canvas *canvas = m_canvasview->canvas(); QRectF diagramBounds = diagramBoundingRect(canvas->items()); double buffer = 50; diagramBounds.adjust(-buffer, -buffer, buffer, buffer); // Compute the scale to with the drawing into the overview rect. qreal xscale = drawingRect.width() / diagramBounds.width(); qreal yscale = drawingRect.height() / diagramBounds.height(); // Choose the smallest of the two scale values. qreal scale = std::min(xscale, yscale); // Scale uniformly, and transform to center in the overview. QTransform scaleTransform = QTransform::fromScale(scale, scale); QRectF targetRect = scaleTransform.mapRect(diagramBounds); QPointF diff = drawingRect.center() - targetRect.center(); m_transform = QTransform(); m_transform.translate(diff.x(), diff.y()); m_transform.scale(scale, scale); // Draw edges in overview for each connector on the canvas. painter.setPen(QColor(0, 0, 0, 100)); QList<CanvasItem *> items = canvas->items(); for (int i = 0; i < items.count(); ++i) { Connector *connector = dynamic_cast<Connector *> (items.at(i)); if (connector) { QPair<ShapeObj *, ShapeObj *> endShapes = connector->getAttachedShapes(); if (!endShapes.first || !endShapes.second) { continue; } QLineF line(endShapes.first->centrePos(), endShapes.second->centrePos()); painter.drawLine(m_transform.map(line)); } } // Draw Rectangles in overview for each shape on the canvas. painter.setPen(Qt::black); painter.setBrush(Qt::darkGray); QRectF shapeRect; for (int i = 0; i < items.count(); ++i) { ShapeObj *shape = dynamic_cast<ShapeObj *> (items.at(i)); if (shape) { shapeRect.setSize(shape->size()); shapeRect.moveCenter(shape->centrePos()); painter.drawRect(m_transform.mapRect(shapeRect)); } } // Show where the visible viewport is (by making everything // outside this have a light grey overlay). QColor grey(0, 0, 0, 60); painter.setPen(QPen(Qt::transparent)); painter.setBrush(QBrush(grey)); QRectF viewRect = m_transform.mapRect(m_canvasview->viewportRect()); QPolygon polygon = QPolygon(drawingRect.toRect()).subtracted( QPolygon(viewRect.toRect())); painter.drawPolygon(polygon); }
void QQuickTextNodeEngine::processCurrentLine() { // No glyphs, do nothing if (m_currentLineTree.isEmpty()) return; // 1. Go through current line and get correct decoration position for each node based on // neighbouring decorations. Add decoration to global list // 2. Create clip nodes for all selected text. Try to merge as many as possible within // the line. // 3. Add QRects to a list of selection rects. // 4. Add all nodes to a global processed list QVarLengthArray<int> sortedIndexes; // Indexes in tree sorted by x position BinaryTreeNode::inOrder(m_currentLineTree, &sortedIndexes); Q_ASSERT(sortedIndexes.size() == m_currentLineTree.size()); SelectionState currentSelectionState = Unselected; QRectF currentRect; QQuickTextNode::Decorations currentDecorations = QQuickTextNode::NoDecoration; qreal underlineOffset = 0.0; qreal underlineThickness = 0.0; qreal overlineOffset = 0.0; qreal overlineThickness = 0.0; qreal strikeOutOffset = 0.0; qreal strikeOutThickness = 0.0; QRectF decorationRect = currentRect; QColor lastColor; QColor lastBackgroundColor; QVarLengthArray<TextDecoration> pendingUnderlines; QVarLengthArray<TextDecoration> pendingOverlines; QVarLengthArray<TextDecoration> pendingStrikeOuts; if (!sortedIndexes.isEmpty()) { QQuickDefaultClipNode *currentClipNode = m_hasSelection ? new QQuickDefaultClipNode(QRectF()) : 0; bool currentClipNodeUsed = false; for (int i=0; i<=sortedIndexes.size(); ++i) { BinaryTreeNode *node = 0; if (i < sortedIndexes.size()) { int sortedIndex = sortedIndexes.at(i); Q_ASSERT(sortedIndex < m_currentLineTree.size()); node = m_currentLineTree.data() + sortedIndex; } if (i == 0) currentSelectionState = node->selectionState; // Update decorations if (currentDecorations != QQuickTextNode::NoDecoration) { decorationRect.setY(m_position.y() + m_currentLine.y()); decorationRect.setHeight(m_currentLine.height()); if (node != 0) decorationRect.setRight(node->boundingRect.left()); TextDecoration textDecoration(currentSelectionState, decorationRect, lastColor); if (currentDecorations & QQuickTextNode::Underline) pendingUnderlines.append(textDecoration); if (currentDecorations & QQuickTextNode::Overline) pendingOverlines.append(textDecoration); if (currentDecorations & QQuickTextNode::StrikeOut) pendingStrikeOuts.append(textDecoration); if (currentDecorations & QQuickTextNode::Background) m_backgrounds.append(qMakePair(decorationRect, lastBackgroundColor)); } // If we've reached an unselected node from a selected node, we add the // selection rect to the graph, and we add decoration every time the // selection state changes, because that means the text color changes if (node == 0 || node->selectionState != currentSelectionState) { if (node != 0) currentRect.setRight(node->boundingRect.left()); currentRect.setY(m_position.y() + m_currentLine.y()); currentRect.setHeight(m_currentLine.height()); // Draw selection all the way up to the left edge of the unselected item if (currentSelectionState == Selected) m_selectionRects.append(currentRect); if (currentClipNode != 0) { if (!currentClipNodeUsed) { delete currentClipNode; } else { currentClipNode->setIsRectangular(true); currentClipNode->setRect(currentRect); currentClipNode->update(); } } if (node != 0 && m_hasSelection) currentClipNode = new QQuickDefaultClipNode(QRectF()); else currentClipNode = 0; currentClipNodeUsed = false; if (node != 0) { currentSelectionState = node->selectionState; currentRect = node->boundingRect; // Make sure currentRect is valid, otherwise the unite won't work if (currentRect.isNull()) currentRect.setSize(QSizeF(1, 1)); } } else { if (currentRect.isNull()) currentRect = node->boundingRect; else currentRect = currentRect.united(node->boundingRect); } if (node != 0) { node->clipNode = currentClipNode; currentClipNodeUsed = true; decorationRect = node->boundingRect; // If previous item(s) had underline and current does not, then we add the // pending lines to the lists and likewise for overlines and strikeouts if (!pendingUnderlines.isEmpty() && !(node->decorations & QQuickTextNode::Underline)) { addTextDecorations(pendingUnderlines, underlineOffset, underlineThickness); pendingUnderlines.clear(); underlineOffset = 0.0; underlineThickness = 0.0; } // ### Add pending when overlineOffset/thickness changes to minimize number of // nodes if (!pendingOverlines.isEmpty()) { addTextDecorations(pendingOverlines, overlineOffset, overlineThickness); pendingOverlines.clear(); overlineOffset = 0.0; overlineThickness = 0.0; } // ### Add pending when overlineOffset/thickness changes to minimize number of // nodes if (!pendingStrikeOuts.isEmpty()) { addTextDecorations(pendingStrikeOuts, strikeOutOffset, strikeOutThickness); pendingStrikeOuts.clear(); strikeOutOffset = 0.0; strikeOutThickness = 0.0; } // Merge current values with previous. Prefer greatest thickness QRawFont rawFont = node->glyphRun.rawFont(); if (node->decorations & QQuickTextNode::Underline) { if (rawFont.lineThickness() > underlineThickness) { underlineThickness = rawFont.lineThickness(); underlineOffset = rawFont.underlinePosition(); } } if (node->decorations & QQuickTextNode::Overline) { overlineOffset = -rawFont.ascent(); overlineThickness = rawFont.lineThickness(); } if (node->decorations & QQuickTextNode::StrikeOut) { strikeOutThickness = rawFont.lineThickness(); strikeOutOffset = rawFont.ascent() / -3.0; } currentDecorations = node->decorations; lastColor = node->color; lastBackgroundColor = node->backgroundColor; m_processedNodes.append(*node); } } if (!pendingUnderlines.isEmpty()) addTextDecorations(pendingUnderlines, underlineOffset, underlineThickness); if (!pendingOverlines.isEmpty()) addTextDecorations(pendingOverlines, overlineOffset, overlineThickness); if (!pendingStrikeOuts.isEmpty()) addTextDecorations(pendingStrikeOuts, strikeOutOffset, strikeOutThickness); } m_currentLineTree.clear(); m_currentLine = QTextLine(); m_hasSelection = false; }