int findBreak(int A[], int n, int p, int q) { int len = q - p + 1; if(len == 1 || A[p] < A[q]) return p; if(len == 2) return q; int m = (p + q) / 2; if(A[m] > A[p]) return findBreak(A, n, m, q); return findBreak(A, n, p, m); }
int search(int A[], int n, int target) { if(n == 0) return -1; if(n == 1) return A[0] == target ? 0 : -1; int breakpos = findBreak(A, n); breakpos = (breakpos == 0 ? n-1 : breakpos - 1); if(breakpos >= n - 1) { return searchInSortedArray(A, n, 0, n - 1, target); } else if(target > A[breakpos] || target < A[breakpos + 1]) { return -1; } else if(target >= A[0]) { return searchInSortedArray(A, n, 0, breakpos, target); } else { return searchInSortedArray(A, n, breakpos + 1, n - 1, target); } }
bool RectDrawing::drawField(QPainter *p, int f, DrawParams *dp) { if (!dp) { dp = drawParams(); } if (!_fm) { _fm = new QFontMetrics(dp->font()); _fontHeight = _fm->height(); } QRect r = _rect; int h = _fontHeight; bool rotate = dp->rotated(); int width = (rotate ? r.height() : r.width()) - 4; int height = (rotate ? r.width() : r.height()); int lines = height / h; // stop if there is no space available if (lines < 1) { return false; } // calculate free space in first line (<unused>) int pos = dp->position(f); if (pos == DrawParams::Default) { switch (f % 4) { case 0: pos = DrawParams::TopLeft; break; case 1: pos = DrawParams::TopRight; break; case 2: pos = DrawParams::BottomRight; break; case 3: pos = DrawParams::BottomLeft; break; } } int unused = 0; bool isBottom = false; bool isCenter = false; bool isRight = false; int *used = 0; switch (pos) { case DrawParams::TopLeft: used = &_usedTopLeft; if (_usedTopLeft == 0) { if (_usedTopCenter) { unused = (width - _usedTopCenter) / 2; } else { unused = width - _usedTopRight; } } break; case DrawParams::TopCenter: isCenter = true; used = &_usedTopCenter; if (_usedTopCenter == 0) { if (_usedTopLeft > _usedTopRight) { unused = width - 2 * _usedTopLeft; } else { unused = width - 2 * _usedTopRight; } } break; case DrawParams::TopRight: isRight = true; used = &_usedTopRight; if (_usedTopRight == 0) { if (_usedTopCenter) { unused = (width - _usedTopCenter) / 2; } else { unused = width - _usedTopLeft; } } break; case DrawParams::BottomLeft: isBottom = true; used = &_usedBottomLeft; if (_usedBottomLeft == 0) { if (_usedBottomCenter) { unused = (width - _usedBottomCenter) / 2; } else { unused = width - _usedBottomRight; } } break; case DrawParams::BottomCenter: isCenter = true; isBottom = true; used = &_usedBottomCenter; if (_usedBottomCenter == 0) { if (_usedBottomLeft > _usedBottomRight) { unused = width - 2 * _usedBottomLeft; } else { unused = width - 2 * _usedBottomRight; } } break; case DrawParams::BottomRight: isRight = true; isBottom = true; used = &_usedBottomRight; if (_usedBottomRight == 0) { if (_usedBottomCenter) { unused = (width - _usedBottomCenter) / 2; } else { unused = width - _usedBottomLeft; } } break; } if (isBottom) { if ((_usedTopLeft > 0) || (_usedTopCenter > 0) || (_usedTopRight > 0)) { lines--; } } else if (!isBottom) { if ((_usedBottomLeft > 0) || (_usedBottomCenter > 0) || (_usedBottomRight > 0)) { lines--; } } if (lines < 1) { return false; } int y = isBottom ? height - h : 0; if (unused < 0) { unused = 0; } if (unused == 0) { // no space available in last line at this position y = isBottom ? (y - h) : (y + h); lines--; if (lines < 1) { return false; } // new line: reset used space if (isBottom) { _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0; } else { _usedTopLeft = _usedTopCenter = _usedTopRight = 0; } unused = width; } // stop as soon as possible when there is no space for "..." static int dotW = 0; if (!dotW) { dotW = _fm->width("..."); } if (width < dotW) { return false; } // get text and pixmap now, only if we need to, because it is possible // that they are calculated on demand (and this can take some time) QString name = dp->text(f); if (name.isEmpty()) { return 0; } QPixmap pix = dp->pixmap(f); // check if pixmap can be drawn int pixW = pix.width(); int pixH = pix.height(); int pixY = 0; bool pixDrawn = true; if (pixW > 0) { pixW += 2; // X distance from pix if ((width < pixW + dotW) || (height < pixH)) { // do not draw pixW = 0; } else { pixDrawn = false; } } // width of text and pixmap to be drawn int w = pixW + _fm->width(name); // if we have limited space at 1st line: // use it only if whole name does fit in last line... if ((unused < width) && (w > unused)) { y = isBottom ? (y - h) : (y + h); lines--; if (lines < 1) { return false; } // new line: reset used space if (isBottom) { _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0; } else { _usedTopLeft = _usedTopCenter = _usedTopRight = 0; } } p->save(); p->setPen((qGray(dp->backColor().rgb()) > 100) ? Qt::black : Qt::white); p->setFont(dp->font()); if (rotate) { //p->translate(r.x()+2, r.y()+r.height()); p->translate(r.x(), r.y() + r.height() - 2); p->rotate(270); } else { p->translate(r.x() + 2, r.y()); } // adjust available lines according to maxLines int max = dp->maxLines(f); if ((max > 0) && (lines > max)) { lines = max; } /* loop over name parts to break up string depending on available width. * every char category change is supposed a possible break, * with the exception Uppercase=>Lowercase. * It is good enough for numbers, Symbols... * * If the text is to be written at the bottom, we start with the * end of the string (so everything is reverted) */ QString remaining; int origLines = lines; while (lines > 0) { // more than one line: search for line break if (w > width && lines > 1) { int breakPos; if (!isBottom) { w = pixW + findBreak(breakPos, name, _fm, width - pixW); remaining = name.mid(breakPos); // remove space on break point if (name[breakPos - 1].category() == QChar::Separator_Space) { name = name.left(breakPos - 1); } else { name = name.left(breakPos); } } else { // bottom w = pixW + findBreakBackwards(breakPos, name, _fm, width - pixW); remaining = name.left(breakPos); // remove space on break point if (name[breakPos].category() == QChar::Separator_Space) { name = name.mid(breakPos + 1); } else { name = name.mid(breakPos); } } } else { remaining.clear(); } /* truncate and add ... if needed */ if (w > width) { name = _fm->elidedText(name, Qt::ElideRight, width - pixW); w = _fm->width(name) + pixW; } int x = 0; if (isCenter) { x = (width - w) / 2; } else if (isRight) { x = width - w; } if (!pixDrawn) { pixY = y + (h - pixH) / 2; // default: center vertically if (pixH > h) { pixY = isBottom ? y - (pixH - h) : y; } p->drawPixmap(x, pixY, pix); // for distance to next text pixY = isBottom ? (pixY - h - 2) : (pixY + pixH + 2); pixDrawn = true; } p->drawText(x + pixW, y, width - pixW, h, Qt::AlignLeft, name); y = isBottom ? (y - h) : (y + h); lines--; if (remaining.isEmpty()) { break; } name = remaining; w = pixW + _fm->width(name); } // make sure the pix stays visible if (pixDrawn && (pixY > 0)) { if (isBottom && (pixY < y)) { y = pixY; } if (!isBottom && (pixY > y)) { y = pixY; } } if (origLines > lines) { // if only 1 line written, do not reset _used* vars if (lines - origLines > 1) { if (isBottom) { _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0; } else { _usedTopLeft = _usedTopCenter = _usedTopRight = 0; } } // take back one line y = isBottom ? (y + h) : (y - h); if (used) { *used = w; } } // update free space if (!isBottom) { if (rotate) { _rect.setRect(r.x() + y, r.y(), r.width() - y, r.height()); } else { _rect.setRect(r.x(), r.y() + y, r.width(), r.height() - y); } } else { if (rotate) { _rect.setRect(r.x(), r.y(), y + h, r.height()); } else { _rect.setRect(r.x(), r.y(), r.width(), y + h); } } p->restore(); return true; }
int findBreak(int A[], int n) { return findBreak(A, n, 0, n - 1); }