From 37e3f157c7d76f13de807fa66e36df209e1005fb Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 10 Jul 2011 15:17:53 -0500 Subject: Added TQt4 HEAD --- .../tqtinterface/qt4/src/kernel/tqtextlayout.cpp | 818 +++++++++++++++++++++ 1 file changed, 818 insertions(+) create mode 100644 experimental/tqtinterface/qt4/src/kernel/tqtextlayout.cpp (limited to 'experimental/tqtinterface/qt4/src/kernel/tqtextlayout.cpp') diff --git a/experimental/tqtinterface/qt4/src/kernel/tqtextlayout.cpp b/experimental/tqtinterface/qt4/src/kernel/tqtextlayout.cpp new file mode 100644 index 000000000..1a007a8eb --- /dev/null +++ b/experimental/tqtinterface/qt4/src/kernel/tqtextlayout.cpp @@ -0,0 +1,818 @@ +/**************************************************************************** +** +** ??? +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include +// Nasty, nasty horrid HACK to get access to QTextLine's private members +// This is TERRIBLE and I wish there was a way around it +// This is a good example of the new, broken & irritating Qt4 API, +// and the corresponding loss in functionality versus Qt3. +// See also tqrect.cpp +#define private protected +#include +#undef private + +#include "tqtextlayout_p.h" +#include "tqtextengine_p.h" + +#include +#include +#include + +#ifdef USE_QT4 +#include "private/qt4_qtextengine_p.h" +#endif // USE_QT4 + +#ifdef USE_QT4 + +TQTextItem::TQTextItem(int line, QTextEngine *e) : QTextLine(line, e) {} + +// TQt internal functions +// Do not modify unless you know what you are doing! +QTextEngine* TQTextItem::tqt_textEngine() const { + return eng; +} + +TQString TQTextItem::tqt_textString() const { + return eng->layoutData->string; +} + +void TQTextItem::tqt_tqdrawTextItem( TQPainter* p, int x, int y, const TQTextItem &ti, int textFlags ) const { + // [FIXME] This needs serious help--it ignores the selected font, font size, etc. + #warning TQTextItem::tqt_tqdrawTextItem( TQPainter* p, int x, int y, const TQTextItem &ti, int textFlags ) unimplemented + printf("[WARNING] TQTextItem::tqt_tqdrawTextItem( TQPainter* p, int x, int y, const TQTextItem &ti, int textFlags ) partially implemented\n\r"); + + // Cheat! + TQString textToPaint = ti.tqt_textString(); + p->save(); + p->setFont(eng->font()); + p->drawText( x, y, textToPaint, textToPaint.length()); +// p->drawText( x, y, TQString("BAD WOLF"), 8); + p->restore(); +} + +// End TQt internal functions + +// // [FIXME] +TQTextItem TQTextLayout::nextItem() { + tqtl_currentItem++; + + if ( tqtl_currentItem >= numItems() ) + return TQTextItem(); + +// d->tqshape( tqtl_currentItem ); + return TQTextItem( tqtl_currentItem, d ); +} + +TQTextItem TQTextLayout::currentItem() { + if ( tqtl_currentItem >= numItems() ) + return TQTextItem(); + +// d->tqshape( tqtl_currentItem ); + return TQTextItem( tqtl_currentItem, d ); +} + +bool TQTextItem::isRightToLeft() const +{ +// if (textDirection() == Qt::RightToLeft) { +// return true; +// } +// else { +// return false; +// } + printf("[WARNING] bool TQTextItem::isRightToLeft() const unimplemented\n\r"); + return false; +} + +bool TQTextItem::isObject() const +{ + printf("[WARNING] bool TQTextItem::isObject() const unimplemented\n\r"); + return false; +} + +bool TQTextItem::isSpace() const +{ + printf("[WARNING] bool TQTextItem::isSpace() const unimplemented\n\r"); + return false; +} + +bool TQTextItem::isTab() const +{ + printf("[WARNING] bool TQTextItem::isTab() const unimplemented\n\r"); + return false; +} + +int TQTextLayout::availableWidth() const +{ + return tqtl_lineWidth - tqtl_widthUsed; +} + +int TQTextItem::from() const +{ +// return engine->items[item].position; + return textStart(); + +// printf("[WARNING] int TQTextItem::from() const unimplemented\n\r"); +// return 0; +} + +int TQTextItem::length() const +{ +// return engine->length(item); + return textLength(); + +// printf("[WARNING] int TQTextItem::length() const unimplemented\n\r"); +// return 0; +} + +void TQTextLayout::beginLine( int width ) { + tqtl_widthUsed = 0; + tqtl_lineWidth = width; + QTextLine line = createLine(); + tqtl_currentItem = numItems() - 1; + line.setLineWidth(width); +} + +bool TQTextLayout::atEnd() const +{ + return tqtl_currentItem >= numItems(); +} + +int TQTextLayout::widthUsed() { + return tqtl_widthUsed; +} + +TQTextLayout::Result TQTextLayout::addCurrentItem() { + if (currentItem().isValid()) { + tqtl_widthUsed = currentItem().naturalTextWidth(); + } + else { + tqtl_widthUsed = 0; + } + tqtl_currentItem++; + printf("[WARNING] TextLayout::Result TQTextLayout::addCurrentItem() partially implemented -- some of its functionality has been moved to beginLine()\n\r"); + return Ok; +// return (tqtl_widthUsed <= tqtl_lineWidth || (tqtl_currentItem < d->items.size() && d->items[tqtl_currentItem].isSpace)) ? Ok : LineFull; +} + +TQTextLayout::Result TQTextLayout::endLine( int x, int y, int tqalignment, int *ascent, int *descent, int *lineLeft, int *lineRight ) +{ +// [FIXME] This crashes... +// QTextLine line = itemAt(tqtl_currentItem); +// line.setPosition(QPointF(x,y)); +// TQ_UNUSED(tqalignment); +// TQ_UNUSED(ascent); +// TQ_UNUSED(descent); +// TQ_UNUSED(lineLeft); +// TQ_UNUSED(lineRight); + + TQ_UNUSED(x); + TQ_UNUSED(y); + TQ_UNUSED(tqalignment); + TQ_UNUSED(ascent); + TQ_UNUSED(descent); + TQ_UNUSED(lineLeft); + TQ_UNUSED(lineRight); + // tqtl_currentItem must be dealt with here as well + printf("[WARNING] TQTextLayout::Result TQTextLayout::endLine( int x, int y, int tqalignment, int *ascent, int *descent, int *lineLeft, int *lineRight ) unimplemented\n\r"); + return Ok; +} + +void TQTextLayout::setDirection(TQChar::Direction dir) { + printf("[WARNING] void TQTextLayout::setDirection(TQChar::Direction dir) unimplemented\n\r"); +} + +#else // USE_QT4 + +TQRect TQTextItem::rect() const +{ + TQScriptItem& si = engine->items[item]; + return TQRect( si.x, si.y, si.width, si.ascent+si.descent ); +} + +int TQTextItem::x() const +{ + return engine->items[item].x; +} + +int TQTextItem::y() const +{ + return engine->items[item].y; +} + +int TQTextItem::width() const +{ + return engine->items[item].width; +} + +int TQTextItem::ascent() const +{ + return engine->items[item].ascent; +} + +int TQTextItem::descent() const +{ + return engine->items[item].descent; +} + +void TQTextItem::setWidth( int w ) +{ + engine->items[item].width = w; +} + +void TQTextItem::setAscent( int a ) +{ + engine->items[item].ascent = a; +} + +void TQTextItem::setDescent( int d ) +{ + engine->items[item].descent = d; +} + +int TQTextItem::from() const +{ + return engine->items[item].position; +} + +int TQTextItem::length() const +{ + return engine->length(item); +} + + +int TQTextItem::cursorToX( int *cPos, Edge edge ) const +{ + int pos = *cPos; + TQScriptItem *si = &engine->items[item]; + + engine->tqshape( item ); + advance_t *advances = engine->advances( si ); + GlyphAttributes *glyphAttributes = engine->glyphAttributes( si ); + unsigned short *logClusters = engine->logClusters( si ); + + int l = engine->length( item ); + if ( pos > l ) + pos = l; + if ( pos < 0 ) + pos = 0; + + int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos]; + if ( edge == Trailing ) { + // trailing edge is leading edge of next cluster + while ( glyph_pos < si->num_glyphs && !glyphAttributes[glyph_pos].clusterStart ) + glyph_pos++; + } + + int x = 0; + bool reverse = engine->items[item].analysis.bidiLevel % 2; + + if ( reverse ) { + for ( int i = si->num_glyphs-1; i >= glyph_pos; i-- ) + x += advances[i]; + } else { + for ( int i = 0; i < glyph_pos; i++ ) + x += advances[i]; + } +// qDebug("cursorToX: pos=%d, gpos=%d x=%d", pos, glyph_pos, x ); + *cPos = pos; + return x; +} + +int TQTextItem::xToCursor( int x, CursorPosition cpos ) const +{ + TQScriptItem *si = &engine->items[item]; + engine->tqshape( item ); + advance_t *advances = engine->advances( si ); + unsigned short *logClusters = engine->logClusters( si ); + + int l = engine->length( item ); + bool reverse = si->analysis.bidiLevel % 2; + if ( x < 0 ) + return reverse ? l : 0; + + + if ( reverse ) { + int width = 0; + for ( int i = 0; i < si->num_glyphs; i++ ) { + width += advances[i]; + } + x = -x + width; + } + int cp_before = 0; + int cp_after = 0; + int x_before = 0; + int x_after = 0; + + int lastCluster = 0; + for ( int i = 1; i <= l; i++ ) { + int newCluster = i < l ? logClusters[i] : si->num_glyphs; + if ( newCluster != lastCluster ) { + // calculate cluster width + cp_before = cp_after; + x_before = x_after; + cp_after = i; + for ( int j = lastCluster; j < newCluster; j++ ) + x_after += advances[j]; + // qDebug("cluster boundary: lastCluster=%d, newCluster=%d, x_before=%d, x_after=%d", + // lastCluster, newCluster, x_before, x_after ); + if ( x_after > x ) + break; + lastCluster = newCluster; + } + } + + bool before = ( cpos == OnCharacters || (x - x_before) < (x_after - x) ); + +// qDebug("got cursor position for %d: %d/%d, x_ba=%d/%d using %d", +// x, cp_before,cp_after, x_before, x_after, before ? cp_before : cp_after ); + + return before ? cp_before : cp_after; + +} + + +bool TQTextItem::isRightToLeft() const +{ + return (engine->items[item].analysis.bidiLevel % 2); +} + +bool TQTextItem::isObject() const +{ + return engine->items[item].isObject; +} + +bool TQTextItem::isSpace() const +{ + return engine->items[item].isSpace; +} + +bool TQTextItem::isTab() const +{ + return engine->items[item].isTab; +} + +TQTextLayout::TQTextLayout() + :d(0) {} + +TQTextLayout::TQTextLayout( const TQString& string, TQPainter *p ) +{ + TQFontPrivate *f = p ? ( p->pfont ? p->pfont->d : p->cfont.d ) : TQApplication::font().d; + d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::tqfromLatin1("") : string), f ); +} + +TQTextLayout::TQTextLayout( const TQString& string, const TQFont& fnt ) +{ + d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::tqfromLatin1("") : string), fnt.d ); +} + +TQTextLayout::~TQTextLayout() +{ + delete d; +} + +void TQTextLayout::setText( const TQString& string, const TQFont& fnt ) +{ + delete d; + d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::tqfromLatin1("") : string), fnt.d ); +} + +/* add an additional item boundary eg. for style change */ +void TQTextLayout::setBoundary( int strPos ) +{ + if ( strPos <= 0 || strPos >= (int)d->string.length() ) + return; + + int itemToSplit = 0; + while ( itemToSplit < d->items.size() && d->items[itemToSplit].position <= strPos ) + itemToSplit++; + itemToSplit--; + if ( d->items[itemToSplit].position == strPos ) { + // already a split at the requested position + return; + } + d->splitItem( itemToSplit, strPos - d->items[itemToSplit].position ); +} + + +int TQTextLayout::numItems() const +{ + return d->items.size(); +} + +TQTextItem TQTextLayout::itemAt( int i ) const +{ + return TQTextItem( i, d ); +} + + +TQTextItem TQTextLayout::tqfindItem( int strPos ) const +{ + if ( strPos == 0 && d->items.size() ) + return TQTextItem( 0, d ); + // ## TODO use bsearch + for ( int i = d->items.size()-1; i >= 0; --i ) { + if ( d->items[i].position < strPos ) + return TQTextItem( i, d ); + } + return TQTextItem(); +} + + +void TQTextLayout::beginLayout( TQTextLayout::LayoutMode m ) +{ + d->items.clear(); + TQTextEngine::Mode mode = TQTextEngine::Full; + if (m == NoBidi) + mode = TQTextEngine::NoBidi; + else if (m == SingleLine) + mode = TQTextEngine::SingleLine; + d->itemize( mode ); + d->currentItem = 0; + d->firstItemInLine = -1; +} + +void TQTextLayout::beginLine( int width ) +{ + d->lineWidth = width; + d->widthUsed = 0; + d->firstItemInLine = -1; +} + +bool TQTextLayout::atEnd() const +{ + return d->currentItem >= d->items.size(); +} + +TQTextItem TQTextLayout::nextItem() +{ + d->currentItem++; + + if ( d->currentItem >= d->items.size() ) + return TQTextItem(); + + d->tqshape( d->currentItem ); + return TQTextItem( d->currentItem, d ); +} + +TQTextItem TQTextLayout::currentItem() +{ + if ( d->currentItem >= d->items.size() ) + return TQTextItem(); + + d->tqshape( d->currentItem ); + return TQTextItem( d->currentItem, d ); +} + +/* ## maybe also currentItem() */ +void TQTextLayout::setLineWidth( int newWidth ) +{ + d->lineWidth = newWidth; +} + +int TQTextLayout::lineWidth() const +{ + return d->lineWidth; +} + +int TQTextLayout::widthUsed() const +{ + return d->widthUsed; +} + +int TQTextLayout::availableWidth() const +{ + return d->lineWidth - d->widthUsed; +} + + +/* returns true if completely added */ +TQTextLayout::Result TQTextLayout::addCurrentItem() +{ + if ( d->firstItemInLine == -1 ) + d->firstItemInLine = d->currentItem; + TQScriptItem ¤t = d->items[d->currentItem]; + d->tqshape( d->currentItem ); + d->widthUsed += current.width; +// qDebug("trying to add item %d with width %d, remaining %d", d->currentItem, current.width, d->lineWidth-d->widthUsed ); + + d->currentItem++; + + return (d->widthUsed <= d->lineWidth + || (d->currentItem < d->items.size() && d->items[d->currentItem].isSpace)) ? Ok : LineFull; +} + +TQTextLayout::Result TQTextLayout::endLine( int x, int y, int tqalignment, + int *ascent, int *descent, int *lineLeft, int *lineRight ) +{ + int available = d->lineWidth; + int numRuns = 0; + int numSpaceItems = 0; + TQ_UINT8 _levels[128]; + int _visual[128]; + TQ_UINT8 *levels = _levels; + int *visual = _visual; + int i; + TQTextLayout::Result result = LineEmpty; + +// qDebug("endLine x=%d, y=%d, first=%d, current=%d lw=%d wu=%d", x, y, d->firstItemInLine, d->currentItem, d->lineWidth, d->widthUsed ); + int width_nobreak_found = d->widthUsed; + if ( d->firstItemInLine == -1 ) + goto end; + + if ( !(tqalignment & (TQt::SingleLine|TQt::IncludeTrailingSpaces)) + && d->currentItem > d->firstItemInLine && d->items[d->currentItem-1].isSpace ) { + int i = d->currentItem-1; + while ( i > d->firstItemInLine && d->items[i].isSpace ) { + numSpaceItems++; + d->widthUsed -= d->items[i--].width; + } + } + + if ( (tqalignment & (TQt::WordBreak|TQt::BreakAnywhere)) && + d->widthUsed > d->lineWidth ) { + // tqfind linebreak + + // even though we removed trailing spaces the line was too wide. We'll have to break at an earlier + // position. To not confuse the layouting below, reset the number of space items + numSpaceItems = 0; + + + bool breakany = tqalignment & TQt::BreakAnywhere; + + const TQCharAttributes *attrs = d->attributes(); + int w = 0; + int itemWidth = 0; + int breakItem = d->firstItemInLine; + int breakPosition = -1; +#if 0 + // we iterate backwards or forward depending on what we guess is closer + if ( d->widthUsed - d->lineWidth < d->lineWidth ) { + // backwards search should be faster + + } else +#endif + { + int tmpWidth = 0; + int swidth = 0; + // forward search is probably faster + for ( int i = d->firstItemInLine; i < d->currentItem; i++ ) { + const TQScriptItem *si = &d->items[i]; + int length = d->length( i ); + const TQCharAttributes *itemAttrs = attrs + si->position; + + advance_t *advances = d->advances( si ); + unsigned short *logClusters = d->logClusters( si ); + + int lastGlyph = 0; + int tmpItemWidth = 0; + +// qDebug("looking for break in item %d, isSpace=%d", i, si->isSpace ); + if(si->isSpace && !(tqalignment & (TQt::SingleLine|TQt::IncludeTrailingSpaces))) { + swidth += si->width; + } else { + tmpWidth += swidth; + swidth = 0; + for ( int pos = 0; pos < length; pos++ ) { +// qDebug("advance=%d, w=%d, tmpWidth=%d, softbreak=%d, whitespace=%d", +// *advances, w, tmpWidth, itemAttrs->softBreak, itemAttrs->whiteSpace ); + int glyph = logClusters[pos]; + if ( lastGlyph != glyph ) { + while ( lastGlyph < glyph ) + tmpItemWidth += advances[lastGlyph++]; + if ( breakPosition != -1 && w + tmpWidth + tmpItemWidth > d->lineWidth ) { +// qDebug("found break at w=%d, tmpWidth=%d, tmpItemWidth=%d", w, tmpWidth, tmpItemWidth); + d->widthUsed = w; + goto found; + } + } + if ( (itemAttrs->softBreak || + ( breakany && itemAttrs->charStop ) ) && + (i != d->firstItemInLine || pos != 0) ) { + if ( breakItem != i ) + itemWidth = 0; + if (itemAttrs->softBreak) + breakany = FALSE; + breakItem = i; + breakPosition = pos; +// qDebug("found possible break at item %d, position %d (absolute=%d), w=%d, tmpWidth=%d, tmpItemWidth=%d", breakItem, breakPosition, d->items[breakItem].position+breakPosition, w, tmpWidth, tmpItemWidth); + w += tmpWidth + tmpItemWidth; + itemWidth += tmpItemWidth; + tmpWidth = 0; + tmpItemWidth = 0; + } + itemAttrs++; + } + while ( lastGlyph < si->num_glyphs ) + tmpItemWidth += advances[lastGlyph++]; + tmpWidth += tmpItemWidth; + if ( w + tmpWidth > d->lineWidth ) { + d->widthUsed = w; + goto found; + } + } + } + } + + found: + // no valid break point found + if ( breakPosition == -1 ) { + d->widthUsed = width_nobreak_found; + goto nobreak; + } + +// qDebug("linebreak at item %d, position %d, wu=%d", breakItem, breakPosition, d->widthUsed ); + // split the line + if ( breakPosition > 0 ) { +// int length = d->length( breakItem ); + +// qDebug("splitting item, itemWidth=%d", itemWidth); + // not a full item, need to break + d->splitItem( breakItem, breakPosition ); + d->currentItem = breakItem+1; + } else { + d->currentItem = breakItem; + } + } + + result = Ok; + + nobreak: + // position the objects in the line + available -= d->widthUsed; + + numRuns = d->currentItem - d->firstItemInLine - numSpaceItems; + if ( numRuns > 127 ) { + levels = new TQ_UINT8[numRuns]; + visual = new int[numRuns]; + } + +// qDebug("reordering %d runs, numSpaceItems=%d", numRuns, numSpaceItems ); + for ( i = 0; i < numRuns; i++ ) { + levels[i] = d->items[i+d->firstItemInLine].analysis.bidiLevel; +// qDebug(" level = %d", d->items[i+d->firstItemInLine].analysis.bidiLevel ); + } + d->bidiReorder( numRuns, levels, visual ); + + end: + // ### FIXME + if ( tqalignment & TQt::AlignJustify ) { + // #### justify items + tqalignment = TQt::AlignAuto; + } + if ( (tqalignment & TQt::AlignHorizontal_Mask) == TQt::AlignAuto ) + tqalignment = TQt::AlignLeft; + if ( tqalignment & TQt::AlignRight ) + x += available; + else if ( tqalignment & TQt::AlignHCenter ) + x += available/2; + + + int asc = ascent ? *ascent : 0; + int desc = descent ? *descent : 0; + + for ( i = 0; i < numRuns; i++ ) { + TQScriptItem &si = d->items[d->firstItemInLine+visual[i]]; + asc = TQMAX( asc, si.ascent ); + desc = TQMAX( desc, si.descent ); + } + + int left = x; + for ( i = 0; i < numRuns; i++ ) { + TQScriptItem &si = d->items[d->firstItemInLine+visual[i]]; +// qDebug("positioning item %d with width %d (from=%d/length=%d) at %d", d->firstItemInLine+visual[i], si.width, si.position, +// d->length(d->firstItemInLine+visual[i]), x ); + si.x = x; + si.y = y + asc; + x += si.width; + } + int right = x; + + if ( numSpaceItems ) { + if ( d->items[d->firstItemInLine+numRuns].analysis.bidiLevel % 2 ) { + x = left; + for ( i = 0; i < numSpaceItems; i++ ) { + TQScriptItem &si = d->items[d->firstItemInLine + numRuns + i]; + x -= si.width; + si.x = x; + si.y = y + asc; + } + } else { + for ( i = 0; i < numSpaceItems; i++ ) { + TQScriptItem &si = d->items[d->firstItemInLine + numRuns + i]; + si.x = x; + si.y = y + asc; + x += si.width; + } + } + } + + if ( lineLeft ) + *lineLeft = left; + if ( lineRight ) + *lineRight = right; + if ( ascent ) + *ascent = asc; + if ( descent ) + *descent = desc; + + if (levels != _levels) + delete []levels; + if (visual != _visual) + delete []visual; + + return result; +} + +void TQTextLayout::endLayout() +{ + // nothing to do currently +} + + +int TQTextLayout::nextCursorPosition( int oldPos, CursorMode mode ) const +{ +// qDebug("looking for next cursor pos for %d", oldPos ); + const TQCharAttributes *attributes = d->attributes(); + int len = d->string.length(); + if ( oldPos >= len ) + return oldPos; + oldPos++; + if ( mode == SkipCharacters ) { + while ( oldPos < len && !attributes[oldPos].charStop ) + oldPos++; + } else { + while ( oldPos < len && !attributes[oldPos].wordStop && !attributes[oldPos-1].whiteSpace ) + oldPos++; + } +// qDebug(" -> %d", oldPos ); + return oldPos; +} + +int TQTextLayout::previousCursorPosition( int oldPos, CursorMode mode ) const +{ +// qDebug("looking for previous cursor pos for %d", oldPos ); + const TQCharAttributes *attributes = d->attributes(); + if ( oldPos <= 0 ) + return 0; + oldPos--; + if ( mode == SkipCharacters ) { + while ( oldPos && !attributes[oldPos].charStop ) + oldPos--; + } else { + while ( oldPos && !attributes[oldPos].wordStop && !attributes[oldPos-1].whiteSpace ) + oldPos--; + } +// qDebug(" -> %d", oldPos ); + return oldPos; +} + + +bool TQTextLayout::validCursorPosition( int pos ) const +{ + const TQCharAttributes *attributes = d->attributes(); + if ( pos < 0 || pos > (int)d->string.length() ) + return FALSE; + return attributes[pos].charStop; +} + +void TQTextLayout::setDirection(TQChar::Direction dir) +{ + d->direction = dir; +} + +#endif // USE_QT4 \ No newline at end of file -- cgit v1.2.1