Пример #1
0
void ezQtPropertyContainerWidget::OnElementButtonClicked()
{
  ezQtElementGroupButton* pButton = qobject_cast<ezQtElementGroupButton*>(sender());
  const ezAbstractProperty* pProp = pButton->GetGroupWidget()->GetProperty();
  ezHybridArray<ezPropertySelection, 8> items = pButton->GetGroupWidget()->GetSelection();

  switch (pButton->GetAction())
  {
    case ezQtElementGroupButton::ElementAction::MoveElementUp:
    {
      MoveItems(items, -1);
    }
    break;
    case ezQtElementGroupButton::ElementAction::MoveElementDown:
    {
      MoveItems(items, 2);
    }
    break;
    case ezQtElementGroupButton::ElementAction::DeleteElement:
    {
      DeleteItems(items);
    }
    break;
  }
}
Пример #2
0
bool
DragSortableListView::HandleDropMessage(const BMessage* message,
	int32 dropIndex)
{
	DragSortableListView *list = NULL;
	if (message->FindPointer("list", (void **)&list) != B_OK || list != this)
		return false;

	BList items;
	int32 index;
	for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK; i++) {
		BListItem* item = ItemAt(index);
		if (item != NULL)
			items.AddItem((void*)item);
	}

	if (items.CountItems() == 0)
		return false;

	if ((modifiers() & B_SHIFT_KEY) != 0)
		CopyItems(items, dropIndex);
	else
		MoveItems(items, dropIndex);

	return true;
}
Пример #3
0
	void Vector<T>::Delete(int ieMin, int ieLim, T * prge)
{
	AssertObj(this);
	Assert((uint)ieMin <= (uint)ieLim && (uint)ieLim <= (uint)m_ieLim);
	AssertArrayN(prge, ieLim - ieMin);
	if ((uint)ieLim > (uint)m_ieLim)
		throw std::invalid_argument("ieLim");
	if ((uint)ieMin > (uint)ieLim)
		throw std::invalid_argument("ieMin");

	if (ieMin == ieLim)
		return;

	if (prge)
	{
		// More efficient to destroy the existing objects at the destination, then do a raw
		// binary copy across than to invoke assignment operators.
		::DestroyRange(prge, ieLim - ieMin);
		CopyItems(m_prge + ieMin, prge, ieLim - ieMin);
	}
	else
		::DestroyRange(m_prge + ieMin, ieLim - ieMin);

	if (ieLim < m_ieLim)
		MoveItems(m_prge + ieLim, m_prge + ieMin, m_ieLim - ieLim);
	m_ieLim -= ieLim - ieMin;

	AssertObj(this);
}
Пример #4
0
	void Vector<T>::InsertMulti(int ieIns, int ceIns, const T * prgeIns)
{
	AssertObj(this);
	Assert((uint)ieIns <= (uint)m_ieLim);
	Assert(ceIns >= 0);
	if ((uint)ieIns > (uint)m_ieLim)
		throw std::invalid_argument("ieIns");
	if (ceIns < 0)
		throw std::invalid_argument("ceIns");

	// Checks for overflow.
	Assert(ceIns + m_ieLim >= ceIns);

	if (!ceIns)
		return;

	// Make sure we have enough memory allocated.
	EnsureSpace(ceIns);

	MoveItems(m_prge, m_prge + ceIns, m_ieLim - ieIns);
	m_ieLim += ceIns;

	T * pe = m_prge + ieIns;
	T * peLim = pe + ceIns;

	for ( ; pe < peLim; ++pe, ++prgeIns)
	{
		// Call constructor on previously allocated memory.
		new((void *)pe) T(*prgeIns);
	}

	AssertObj(this);
}
Пример #5
0
void CBaseRecordVector::Delete(int index, int num)
{
  TestIndexAndCorrectNum(index, num);
  if (num > 0)
  {
    MoveItems(index, index + num);
    _size -= num;
  }
}
Пример #6
0
void
AudioListView::MessageReceived(BMessage* message)
{
	switch (message->what) {
		case kDraggedItem:
		{
			BPoint dropPoint = message->DropPoint();
			int32 dropIndex = IndexOf(ConvertFromScreen(dropPoint));
			int32 count = CountItems();
			if (dropIndex < 0 || dropIndex > count)
				dropIndex = count;

			BList indices;
			GetSelectedItems(indices);
			MoveItems(indices, dropIndex);

			RenumberTracks();
			break;
		}
		case kDeleteItem:
		{
			if (!IsEmpty()) {
				RemoveSelected();

				if (!IsEmpty())
					RenumberTracks();
			}
			// fake to update button state and calculate SizeBar
			Looper()->PostMessage(B_REFS_RECEIVED);
			break;
		}
		case kPopupClosed:
		{
			fShowingPopUpMenu = false;
			break;
		}
		default:
		{
			BListView::MessageReceived(message);
			break;
		}
	}
}
Пример #7
0
void ezQtPropertyContainerWidget::dropEvent(QDropEvent* event)
{
  if (updateDropIndex(event))
  {
    ezQtGroupBoxBase* pGroup = qobject_cast<ezQtGroupBoxBase*>(event->source());
    Element* pDragElement =
        std::find_if(begin(m_Elements), end(m_Elements), [pGroup](const Element& elem) -> bool { return elem.m_pSubGroup == pGroup; });
    if (pDragElement)
    {
      const ezAbstractProperty* pProp = pDragElement->m_pWidget->GetProperty();
      ezHybridArray<ezPropertySelection, 8> items = pDragElement->m_pWidget->GetSelection();
      if (m_iDropSource != m_iDropTarget && (m_iDropSource + 1) != m_iDropTarget)
      {
        MoveItems(items, m_iDropTarget - m_iDropSource);
      }
    }
  }
  m_iDropSource = -1;
  m_iDropTarget = -1;
  update();
}
Пример #8
0
void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
{
	if (mouseDown) {
		vec2 pos = GetMouseEventPos(event);

		if (!mouseMoved && !mouseOverItems &&
		    stretchHandle == ItemHandle::None) {
			ProcessClick(startPos);
			mouseOverItems = SelectedAtPos(startPos);
		}

		pos.x = std::round(pos.x);
		pos.y = std::round(pos.y);

		if (stretchHandle != ItemHandle::None)
			StretchItem(pos);
		else if (mouseOverItems)
			MoveItems(pos);

		mouseMoved = true;
	}
}
Пример #9
0
/*****************************************************************************
 * DragSortableListView::MessageReceived
 *****************************************************************************/
void
DragSortableListView::MessageReceived(BMessage* message)
{
    switch ( message->what )
    {
        case B_MODIFIERS_CHANGED:
            ModifiersChanged();
            break;
        case B_SIMPLE_DATA:
        {
            DragSortableListView *list = NULL;
            if ( message->FindPointer( "list", (void **)&list ) == B_OK
                 && list == this )
            {
                int32 count = CountItems();
                if ( fDropIndex < 0 || fDropIndex > count )
                    fDropIndex = count;
                BList items;
                int32 index;
                for ( int32 i = 0; message->FindInt32( "index", i, &index ) == B_OK; i++ )
                    if ( BListItem* item = ItemAt(index) )
                        items.AddItem( (void*)item );
                if ( items.CountItems() > 0 )
                {
                    if ( modifiers() & B_SHIFT_KEY )
                        CopyItems( items, fDropIndex );
                    else
                        MoveItems( items, fDropIndex );
                }
                fDropIndex = -1;
            }
            break;
        }
        default:
            BListView::MessageReceived( message );
            break;
    }
}
Пример #10
0
// MessageReceived
void
DragSortableListView::MessageReceived(BMessage* message)
{
	if (message->what == fDragCommand) {
		DragSortableListView *list = NULL;
		if (message->FindPointer("list", (void **)&list) == B_OK
			 && list == this) {
			int32 count = CountItems();
			if (fDropIndex < 0 || fDropIndex > count)
				fDropIndex = count;
			BList items;
			int32 index;
			for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK; i++)
				if (BListItem* item = ItemAt(index))
					items.AddItem((void*)item);
			if (items.CountItems() > 0) {
				if (modifiers() & B_SHIFT_KEY)
					CopyItems(items, fDropIndex);
				else
					MoveItems(items, fDropIndex);
			}
			fDropIndex = -1;
		}
	} else {
		switch (message->what) {
			case MSG_TICK: {
				float scrollV = 0.0;
				BRect rect(Bounds());
				BPoint point;
				uint32 buttons;
				GetMouse(&point, &buttons, false);
				if (rect.Contains(point)) {
					// calculate the vertical scrolling offset
					float hotDist = rect.Height() * SCROLL_AREA;
					if (point.y > rect.bottom - hotDist)
						scrollV = hotDist - (rect.bottom - point.y);
					else if (point.y < rect.top + hotDist)
						scrollV = (point.y - rect.top) - hotDist;
				}
				// scroll
				if (scrollV != 0.0 && fScrollView) {
					if (BScrollBar* scrollBar = fScrollView->ScrollBar(B_VERTICAL)) {
						float value = scrollBar->Value();
						scrollBar->SetValue(scrollBar->Value() + scrollV);
						if (scrollBar->Value() != value) {
							// update mouse position
							uint32 buttons;
							BPoint point;
							GetMouse(&point, &buttons, false);
							uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
							MouseMoved(point, transit, &fDragMessageCopy);
						}
					}
				}
				break;
			}
//			case B_MODIFIERS_CHANGED:
//				ModifiersChanged();
//				break;
			case B_MOUSE_WHEEL_CHANGED: {
				BListView::MessageReceived(message);
				BPoint point;
				uint32 buttons;
				GetMouse(&point, &buttons, false);
				uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
				MouseMoved(point, transit, &fDragMessageCopy);
				break;
			}
			default:
				BListView::MessageReceived(message);
				break;
		}
	}
}
Пример #11
0
void CBaseRecordVector::InsertOneItem(int index)
{
  ReserveOnePosition();
  MoveItems(index + 1, index);
  _size++;
}
Пример #12
0
/*----------------------------------------------------------------------------------------------
	Make a segment by finding a suitable break point in the specified range of text.
	Note that it is appropriate for line layout to use this routine even if putting
	text on a single line, because an old writing system may take advantage of line layout
	to handle direction changes and style changes and generate multiple segments
	even on one line. For such layouts, pass a large dxMaxWidth, but still expect
	possibly multiple segments.
	Arguments:
		pgjus				NULL if no justification will ever be needed for the resulting segment
		ichMinNew			index of the first char in the text that is of interest
		ichLimText			index of the last char in the text that is of interest (+ 1)
		ichLimBacktrack		index of last char that may be included in the segment.
							Generally the same as ichLimText unless backtracking.
		fNeedFinalBreak
		fStartLine			seg is logically first on line?
		dxMaxWidth			whatever coords pvg is using
		lbPref				try for longest seg of this weight
		lbMax				max if no preferred break possible
		twsh				how we are handling trailing white-space
		fParaRtoL			overall paragraph direction
		ppsegRet			segment produced, or null if nothing fits
		pdichLimSeg			offset to last char of segment, first of next if any
		pdxWidth			of new segment, if any
		pest				what caused the segment to end?
		cbPrev				(not used)
		pbPrevSegDat		(not used)
		cbNextMax			(not used)
		pbNextSegDat		(not used)
		pcbNextSegDat		(*pcbNextSegDat always set to zero)
		pdichContext		(*pdichContext always set to zero)

	TODO 1441 (SharonC): handle fParaRtoL; specifically, if the paragraph direction is
	right-to-left, trailing white-space characters should be reversed.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP RomRenderEngine::FindBreakPoint(
	IVwGraphics * pvg, IVwTextSource * pts, IVwJustifier * pvjus,
	int ichMinNew, int ichLimText, int ichLimBacktrack,
	ComBool fNeedFinalBreak, ComBool fStartLine,
	int dxMaxWidth, LgLineBreak lbPref, LgLineBreak lbMax,
	LgTrailingWsHandling twsh, ComBool fParaRtoL,
	ILgSegment ** ppsegRet, int * pdichLimSeg, int * pdxWidth, LgEndSegmentType * pest,
	ILgSegment * psegPrev)
{
	BEGIN_COM_METHOD
	ChkComArgPtr(pvg);
	ChkComArgPtr(pts);
	ChkComOutPtr(ppsegRet);
	ChkComOutPtr(pdichLimSeg);
	ChkComArgPtr(pdxWidth);
	ChkComArgPtr(pest);
	ChkComArgPtrN(psegPrev);
#define INIT_BUF_SIZE 1000
	OLECHAR rgchBuf[INIT_BUF_SIZE]; // Unlikely segments are longer than this...
	memset(rgchBuf, 0, sizeof(rgchBuf));
	Vector<OLECHAR> vch; // Use as buffer if 1000 is not enough
	OLECHAR * prgch = rgchBuf; // Use on-stack variable if big enough
	int cchBuf = INIT_BUF_SIZE; // chars available in prgch; INIT_BUF_SIZE or vch.Size().

	int ichForceBreak;
	byte rglbsBuf[INIT_BUF_SIZE]; // line break status
	Vector<byte> vlbs;
	byte * prglbsForString = rglbsBuf; // switch to resized vector if needed.

	RomRenderSegmentPtr qrrs;
	LgCharRenderProps chrp;
	int ichMinRun, ichLimRun;
	CheckHr(pts->GetCharProps(ichMinNew, &chrp, &ichMinRun, &ichLimRun));
	// Ws and old writing system for the segment; don't use chars with different ones.
	int ws = chrp.ws;
	int nDirDepth = chrp.nDirDepth;
	if (fParaRtoL)
		nDirDepth += 2;
	//Assert((nDirDepth % 2) == 0); // left-to-right

	// Get a char props engine
	AssertPtr(m_qwsf);
	ILgCharacterPropertyEnginePtr qcpe;
	CheckHr(m_qwsf->get_CharPropEngine(ws, &qcpe));

// The maximum number of characters we will fetch and measure, beyond what we
// know we need. This should be less than the length of rgchBuf.
#define MAX_MEASURE 100
	EndAvailType eat;
	int ichLimSegCur; // Current proposal for where seg might end
	// We aren't allowed to include characters at or beyond ichLimBacktrack in the
	// segment. But it's worth getting one more, if more are available, so we can
	// check whether an line break at the very end is allowed.
	// Note that this time we're getting at most MAX_MEASURE chars, so we don't
	// have to check for buffer overflow.
	GetAvailChars(pts, ws, ichMinNew, ichLimBacktrack, MAX_MEASURE, twsh, qcpe,
		prgch, &ichLimSegCur, &eat);

	// Measure all the characters we got, or all we are allowed to use, whichever
	// is less.
	int cchMeasure = ichLimSegCur - ichMinNew;
	// Make a segment to use in measuring things; if all goes well use it for the
	// final result.
	qrrs.Attach(NewObj RomRenderSegment(pts, this, cchMeasure,
		klbNoBreak, klbNoBreak, true));
	qrrs->SetDirectionInfo(nDirDepth, (twsh == ktwshOnlyWs));

	// If a forced empty segment, stop here
	if (ichLimBacktrack <= ichMinNew)
	{
		*pest = kestNoMore;
		*pdxWidth = 0;
		*ppsegRet = qrrs.Detach();
		*pdichLimSeg = 0;
		return S_OK;
	}

	int dxWidthMeasure = 0; // width of part of run initially measured.

	CheckHr(qrrs->get_Width(ichMinNew, pvg, &dxWidthMeasure));

	int cchLineEst; // Calculate the estimated number of characters to fill line.
	int cchMaxText = ichLimBacktrack - ichMinNew;
#ifdef ICU_LINEBREAKING
	int ichTempBreak;
	LgLineBreak lbWeight;
	LgGeneralCharCategory cc;
#endif /*ICU_LINEBREAKING*/

	// Now, if it is a short text or already contains all candidate characters,
	// we have the actual width; otherwise, we have
	// a measurement of MAX_MEASURE characters that we can use in guessing how many we
	// need. If we have less than we need, increase the limit until we have more.
	// Note that we need the <= here because, if we have exactly filled the width, we
	// will consider putting a break after the MAX_MEASURE'th character. We need to
	// fetch at least one more character in order to have valid line-break info
	// about the last one that might be put on the line.
	while (eat == keatMax && ichLimSegCur < ichLimBacktrack && dxWidthMeasure <= dxMaxWidth)
	{
		// Compute the number we estimate will fill the line (min the number we have).
		// Don't let this estimate be zero unless we actually have no characters available.
		if (!dxWidthMeasure)
			cchLineEst = min(max(1, dxMaxWidth * cchMeasure), cchMaxText);
		else
			// Use MulDiv to avoid overflow, likely when dxMaxWidth is INT_MAX
			cchLineEst = min(max(1, MulDiv(dxMaxWidth, cchMeasure, dxWidthMeasure)), cchMaxText);
		// Make sure the buffer contains MAX_MEASURE more than that. First make sure
		// there is room for them.
		// We have already loaded out to ichLimSegCur, so use that as a start position.
		// Already in the buffer are pts[ichMinNew...ichLimSegCur] starting at prgch.
		// We need room for cchLineEst + MAX_MEASURE, but add a few more to buffer size
		// so we are always safe adding one or two for end of line testing.
		if (cchLineEst + MAX_MEASURE + 5 >= cchBuf)
		{
			// Allocate memory for the characters in the vector, or resize it.
			// Allocate extra in case we keep adding later.
			cchBuf = cchLineEst + MAX_MEASURE + 500;
			vch.Resize(cchBuf);
			if (prgch == rgchBuf)
				MoveItems(rgchBuf, vch.Begin(), ichLimSegCur - ichMinNew);
			prgch = vch.Begin();
			vlbs.Clear();  // no need to copy, nothing in it yet.
			vlbs.Resize(cchBuf);
			prglbsForString = vlbs.Begin();
		}
		GetAvailChars(pts, ws, ichLimSegCur, ichLimBacktrack,
			ichMinNew + cchLineEst + MAX_MEASURE - ichLimSegCur, twsh, qcpe,
			prgch + ichLimSegCur - ichMinNew, &ichLimSegCur, &eat);
		cchMeasure = ichLimSegCur - ichMinNew;
		qrrs->SetLim(cchMeasure);
		qrrs->SetDirectionInfo(nDirDepth, (twsh == ktwshOnlyWs));
		CheckHr(qrrs->get_Width(ichMinNew, pvg, &dxWidthMeasure));
	}

#ifdef ICU_LINEBREAKING
	//updating the BreakIterator text for calculating line breaks later
	CheckHr(qcpe->put_LineBreakText(prgch, ichLimSegCur-ichMinNew));
#endif /*ICU_LINEBREAKING*/

	// Update this with the results of the latest measurement.
	if (!dxWidthMeasure)
		cchLineEst = min(max(1, dxMaxWidth * cchMeasure), cchMaxText);
	else
		// Use MulDiv to avoid overflow, likely when dxMaxWidth is INT_MAX
		cchLineEst = min(max(1, MulDiv(dxMaxWidth, cchMeasure, dxWidthMeasure)), cchMaxText);
	// Now we have measured either all the characters we are allowed, or enough to
	// fill the line.

	if (dxWidthMeasure <= dxMaxWidth)
	{
		// we will most likely answer the segment we just found
		*pdxWidth = dxWidthMeasure;
		*pdichLimSeg = min(ichLimSegCur - ichMinNew, ichLimBacktrack - ichMinNew);
		if (ichLimSegCur == ichLimText)
		{
			// the whole text we were asked to use fit
			*pest = kestNoMore;
			*ppsegRet = qrrs.Detach();
			return S_OK;
		}
		if (ichLimSegCur == ichLimBacktrack)
		{
			// Everything allowed fits, but, since this is not the real end of the text,
			// we have to consider whether this is a valid line break. We will need one
			// more character in the buffer. We made sure above there is room for it.
			CheckHr(pts->Fetch(ichLimSegCur, ichLimSegCur + 1, prgch + ichLimSegCur - ichMinNew));
			// We want to get line break info for the character at ichLimSegCur - 1, relative to
			// the string as a whole. Offset relative to buffer is less by ichMinNew.
			int ichBuf = ichLimSegCur - ichMinNew - 1;
#ifndef ICU_LINEBREAKING
			CheckHr(qcpe->GetLineBreakInfo(prgch, ichLimSegCur - ichMinNew + 1,
				ichBuf, ichBuf + 1, prglbsForString, &ichForceBreak));
#else
			//updating the BreakIterator text for calculating line breaks
			CheckHr(qcpe->put_LineBreakText(prgch, ichLimSegCur-ichMinNew+1));
			CheckHr(qcpe->LineBreakAfter(ichBuf, &ichTempBreak, &lbWeight));
// Previous code was wrong twice:
// 1. did not offset by ichMinNew
// 2. did not allow GetLineBreakInfo to use info about characters earlier in run.
// Also it got one more result than we need.
//			CheckHr(qcpe->GetLineBreakInfo(prgch + ichLimSegCur - 1, 2, 0, 2, prglbsForString,
//				&ichForceBreak));
			CheckHr(qcpe->get_GeneralCategory(prgch[ichBuf], &cc));
			if ((ichTempBreak == ichBuf+1) && (cc == kccZs))
#endif /*ICU_LINEBREAKING*/
#ifndef ICU_LINEBREAKING
			if (prglbsForString[0] & kflbsBrk)
#endif /*ICU_LINEBREAKING*/
			{
				// Backtrack posn is also a line break
				*pest = kestOkayBreak;
				*ppsegRet = qrrs.Detach();
				return S_OK;
			}
			else if (!fNeedFinalBreak)
			{
				// Backtrack position is not a break, but we may return it anyway
				// This probably never happens but include it for consistency.
				*pest = kestBadBreak;
				*ppsegRet = qrrs.Detach();
				return S_OK;
			}
			// If we get here we must search for an earlier break.
			goto LFindEarlierBreak;
		}
		if (eat == keatBreak || eat == keatOnlyWs)
		{
			*pest = (eat == keatOnlyWs) ? kestOkayBreak : kestHardBreak;
			// a segment up to a hard return or similar fit
			// Return the segment we got (which may be an empty segment)
			*ppsegRet = qrrs.Detach();
			return S_OK;
		}
		// Only one reason remains for us to have stopped while not filling the width
		Assert(eat == keatNewWs);
		// See whether the WS break is also a line break.
		// We want to get line break info for the character at ichLimSegCur - 1, relative to
		// the string as a whole. Offset relative to buffer is less by ichMinNew.
		int ichBuf = ichLimSegCur - ichMinNew - 1;
#ifndef ICU_LINEBREAKING
		CheckHr(qcpe->GetLineBreakInfo(prgch, ichLimSegCur - ichMinNew,
			ichBuf, ichBuf + 1, prglbsForString, &ichForceBreak));
#else
		CheckHr(qcpe->LineBreakAfter(ichBuf, &ichTempBreak, &lbWeight));

		CheckHr(qcpe->get_GeneralCategory(prgch[ichBuf], &cc));
		if ((ichTempBreak == ichBuf+1) && (cc == kccZs))
#endif /*ICU_LINEBREAKING*/
#ifndef ICU_LINEBREAKING
		if (prglbsForString[0] & kflbsBrk)
#endif /*ICU_LINEBREAKING*/
		{
			// WS break is also a line break
			*pest = kestOkayBreak;
			*ppsegRet = qrrs.Detach();
			return S_OK;
		}
		else
		{
			if (!fNeedFinalBreak)
			{
				// Though not a line break, return it and see if we can fit some
				// of next WS on to make things OK.
				*pest = kestWsBreak;
				*ppsegRet = qrrs.Detach();
				return S_OK;
			}
			// otherwise, fall through to find a valid line break earlier.
		}
	}

LFindEarlierBreak:
	// ENHANCE JohnT: arguably we ought to look further back to be absolutely sure
	// of line break props. It makes a difference only if old writing system changes
	// in middle of a run of spaces or combining marks, and even then, the extra spaces
	// will fit so we shouldn't make a spurious break, and the run of CMs should only
	// get broken if the column is too narrow for a whole word. I think we can live
	// wit this.
	// Note: we can ignore ichForceBreak here because we made sure in GetAvailChars
	// that there aren't any break characters before ichLimSegCur.
	CheckHr(qcpe->GetLineBreakInfo(prgch, ichLimSegCur - ichMinNew, 0,
		ichLimSegCur - ichMinNew, prglbsForString, &ichForceBreak));

	// If we got here, we will have to make a line break within the run, somewhere
	// before ichLimSegCur, since stopping there either makes it too wide, or violates
	// fNeedFinalBreak.
	*pest = kestMoreLines;

	// broken segment will certainly end line
	CheckHr(qrrs->put_EndLine(ichMinNew, pvg, true));

	// Get info about line break possibilities

	// Figure the best kind of line break we can do at all,
	// starting at lbPref
	LgLineBreak lbTry;
	lbTry = lbPref;	// sep from decl because of goto
	int ichBreak;	// index in prglbsForString of character after which break is allowed at
					// given level
	int ichDim;		// index in prglbsForString of last character before ichBreak which is
					// not a space,
	ichBreak = -1;	// don't init in decl because of goto
	int dxBreakWidth;
	// loop over possible levels of badness of break, from lbPref to lbMax.
	for (;;)
	{
		if (!(lbTry == klbHyphenBreak && lbTry != lbPref))
		{
			// Look for a break at this level. The condition above means
			// don't try hyphen break if we already tried word break.
			// This engine can't (yet) find a hyphen break that is not
			// a word break.
#ifndef ICU_LINEBREAKING
			FindLineBreak(prglbsForString, 0, ichLimSegCur - ichMinNew, lbTry, false,
				ichBreak, ichDim);
#else
			FindLineBreak(prgch, qcpe, 0, ichLimSegCur - ichMinNew, lbTry, false,
				ichBreak, ichDim);
#endif /*ICU_LINEBREAKING*/
			if (ichBreak >= 0)
			{
				if (ichDim < 0)
					break;		// all characters up to break are spaces
				qrrs->SetLim(ichDim + 1);
				qrrs->SetDirectionInfo(nDirDepth, (twsh == ktwshOnlyWs));
				CheckHr(qrrs->get_Width(ichMinNew, pvg, &dxBreakWidth));
				if (dxBreakWidth > dxMaxWidth && lbTry < klbClipBreak)
				{
					// can't do this kind of break
					ichBreak = -1;
				}
			}
			if (ichBreak >= 0)
				break;		// found a useable break at this level
		}
		lbTry = (LgLineBreak) (lbTry + 1);	// otherwise try next level.
		if (lbTry > lbMax)
		{
			// can't get any valid break. Give up.
			*ppsegRet = NULL;
			*pdxWidth = 0;
			return S_OK;  // this is a perfectly valid result.
		}
		Assert(lbTry <= klbClipBreak); // that level should always succeed
	}
	// OK, we are going to put something on the line. The break type will be lbTry.
	// See if we can find any later breaks of the same type that fit.

	int ichNewBreak;		// in prglbsForString
	int ichNewDim = -1;		// in prglbsForString
	int dxNewBreakWidth;

	// 1. look backward for first break prior to cchLineEst
	// 2. while break doesn't fit, look backward for next prior break
	// 3. once a break fits, quit and use it.
	// 4. while break fits, remember it and look forward for next following break
	// 5. once a break doesn't fit, quit and use the previous break.

	bool fLookAhead = true;
	if (cchLineEst > ichBreak)
#ifndef ICU_LINEBREAKING
		FindLineBreak(prglbsForString, ichBreak + 1, cchLineEst, lbTry, true, ichNewBreak,
			ichNewDim);
#else
		FindLineBreak(prgch, qcpe, ichBreak + 1, cchLineEst, lbTry, true, ichNewBreak,
			ichNewDim);
#endif /*ICU_LINEBREAKING*/
	else