diff --git a/Import/GacUI.Windows.cpp b/Import/GacUI.Windows.cpp index fd0fb0df..a1d1a494 100644 --- a/Import/GacUI.Windows.cpp +++ b/Import/GacUI.Windows.cpp @@ -8773,10 +8773,10 @@ WindowsGDIParagraph void PrepareUniscribeData() { - if(paragraph->BuildUniscribeData(renderTarget->GetDC())) + if (paragraph->BuildUniscribeData(renderTarget->GetDC())) { - vint width=paragraph->lastAvailableWidth==-1?65536:paragraph->lastAvailableWidth; - paragraph->Layout(width, paragraph->paragraphAlignment); + vint width = paragraph->lastAvailableWidth == -1 ? 65536 : paragraph->lastAvailableWidth; + paragraph->Layout(paragraph->lastWrapLine, width, paragraph->paragraphAlignment); } } @@ -8829,18 +8829,13 @@ WindowsGDIParagraph bool GetWrapLine()override { - return paragraph->wrapLine; + return paragraph->lastWrapLine; } void SetWrapLine(bool value)override { - CHECK_ERROR(value, L"vl::presentation::elements_windows_gdi::WindowsGDIParagraph::SetWrapLine(bool)#Non-wrapline not implemented."); - if (paragraph->wrapLine != value) - { - paragraph->wrapLine = value; - paragraph->BuildUniscribeData(renderTarget->GetDC()); - paragraph->Layout(paragraph->lastAvailableWidth, paragraph->paragraphAlignment); - } + paragraph->BuildUniscribeData(renderTarget->GetDC()); + paragraph->Layout(value, paragraph->lastAvailableWidth, paragraph->paragraphAlignment); } vint GetMaxWidth()override @@ -8851,7 +8846,7 @@ WindowsGDIParagraph void SetMaxWidth(vint value)override { paragraph->BuildUniscribeData(renderTarget->GetDC()); - paragraph->Layout(value, paragraph->paragraphAlignment); + paragraph->Layout(paragraph->lastWrapLine, value, paragraph->paragraphAlignment); } Alignment GetParagraphAlignment()override @@ -8862,7 +8857,7 @@ WindowsGDIParagraph void SetParagraphAlignment(Alignment value)override { paragraph->BuildUniscribeData(renderTarget->GetDC()); - paragraph->Layout(paragraph->lastAvailableWidth, value); + paragraph->Layout(paragraph->lastWrapLine, paragraph->lastAvailableWidth, value); } bool SetFont(vint start, vint length, const WString& value)override @@ -8976,7 +8971,7 @@ WindowsGDIParagraph { PrepareUniscribeData(); return Size( - (paragraph->wrapLine ? 0 : paragraph->bounds.Width()), + (paragraph->lastWrapLine ? 0 : paragraph->bounds.Width()), paragraph->bounds.Height()); } @@ -9000,6 +8995,31 @@ WindowsGDIParagraph return true; } + bool IsCaretBoundsFromTextRun(vint caret, bool caretFrontSide) + { + if (!paragraph->IsValidCaret(caret)) return false; + + vint frontLine = 0; + vint backLine = 0; + paragraph->GetLineIndexFromTextPos(caret, frontLine, backLine); + if (frontLine == -1 || backLine == -1) return false; + + vint lineIndex = caretFrontSide ? frontLine : backLine; + lineIndex = lineIndex < 0 ? 0 : lineIndex > paragraph->lines.Count() - 1 ? paragraph->lines.Count() - 1 : lineIndex; + Ptr line = paragraph->lines[caretFrontSide ? frontLine : backLine]; + + vint frontRun = -1; + vint backRun = -1; + paragraph->GetRunIndexFromTextPos(caret, lineIndex, frontRun, backRun); + if (frontRun == -1 || backRun == -1) return false; + + vint runIndex = caretFrontSide ? frontRun : backRun; + runIndex = runIndex < 0 ? 0 : runIndex > line->scriptRuns.Count() - 1 ? line->scriptRuns.Count() - 1 : runIndex; + Ptr run = line->scriptRuns[runIndex]; + + return run.Cast(); + } + void Render(Rect bounds)override { PrepareUniscribeData(); @@ -9010,17 +9030,17 @@ WindowsGDIParagraph paragraph->Render(this, false); paragraphDC = 0; - if(caret!=-1) + if (caret != -1) { - Rect caretBounds=GetCaretBounds(caret, caretFrontSide); - vint x=caretBounds.x1+bounds.x1; - vint y1=caretBounds.y1+bounds.y1; - vint y2=y1+(vint)(caretBounds.Height()*1.5); + Rect caretBounds = GetCaretBounds(caret, caretFrontSide); + vint x = caretBounds.x1 + bounds.x1; + vint y1 = caretBounds.y1 + bounds.y1; + vint y2 = y1 + (vint)(caretBounds.Height() * (IsCaretBoundsFromTextRun(caret, caretFrontSide) ? 1.5 : 1)); - WinDC* dc=renderTarget->GetDC(); + WinDC* dc = renderTarget->GetDC(); dc->SetPen(caretPen); - dc->MoveTo(x-1, y1); - dc->LineTo(x-1, y2); + dc->MoveTo(x - 1, y1); + dc->LineTo(x - 1, y2); dc->MoveTo(x, y1); dc->LineTo(x, y2); } @@ -10838,7 +10858,7 @@ UniscribeTextRun return SumHeight(); } - void UniscribeTextRun::SearchForLineBreak(vint tempStart, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances) + void UniscribeTextRun::SearchForLineBreak(vint tempStart, bool wrapLine, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances) { vint width=0; charLength=0; @@ -10847,7 +10867,7 @@ UniscribeTextRun { if(i==length || scriptItem->charLogattrs[i+(startFromLine-scriptItem->startFromLine)].fSoftBreak==TRUE) { - if(width<=maxWidth || (firstRun && charLength==0)) + if(!wrapLine || width<=maxWidth || (firstRun && charLength==0)) { charLength=i-tempStart; charAdvances=width; @@ -11030,9 +11050,9 @@ UniscribeEmbeddedObjectRun return 0; } - void UniscribeEmbeddedObjectRun::SearchForLineBreak(vint tempStart, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances) + void UniscribeEmbeddedObjectRun::SearchForLineBreak(vint tempStart, bool wrapLine, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances) { - if (firstRun || properties.size.x <= maxWidth) + if (firstRun || !wrapLine || properties.size.x <= maxWidth) { charLength = length - tempStart; charAdvances = properties.size.x; @@ -11299,17 +11319,17 @@ UniscribeLine return false; } - void UniscribeLine::Layout(vint availableWidth, Alignment alignment, vint top, vint& totalHeight) + void UniscribeLine::Layout(bool wrapLine, vint availableWidth, Alignment alignment, vint top, vint& totalHeight) { - vint cx=0; - vint cy=top; + vint cx = 0; + vint cy = top; virtualLines.Clear(); - if(scriptRuns.Count()==0) + if (scriptRuns.Count() == 0) { // if this line doesn't contains any run, skip and render a blank line - vint height=(vint)(documentFragments[0]->fontStyle.size*1.5); - bounds=Rect(Point(cx, cy), Size(0, height)); - cy+=height; + vint height = (vint)(documentFragments[0]->fontStyle.size * 1.5); + bounds = Rect(Point(cx, cy), Size(0, height)); + cy += height; } else { @@ -11319,122 +11339,132 @@ UniscribeLine } // render this line into lines with auto line wrapping - vint startRun=0; - vint startRunOffset=0; - vint lastRun=0; - vint lastRunOffset=0; - vint currentWidth=0; + vint startRun = 0; + vint startRunOffset = 0; + vint lastRun = 0; + vint lastRunOffset = 0; + vint currentWidth = 0; - while(startRunSearchForLineBreak(lastRunOffset, availableWidth-currentWidth, firstRun, charLength, charAdvances); - firstRun=false; + vint charLength = 0; + vint charAdvances = 0; + UniscribeRun* run = scriptRuns[i].Obj(); + run->SearchForLineBreak(lastRunOffset, wrapLine, availableWidth - currentWidth, firstRun, charLength, charAdvances); + firstRun = false; - if(charLength==run->length-lastRunOffset) + if (charLength == run->length - lastRunOffset) { - lastRun=i+1; - lastRunOffset=0; - currentWidth+=charAdvances; + lastCompletedRunOffset = lastRunOffset; + lastRun = i + 1; + lastRunOffset = 0; + currentWidth += charAdvances; } else { - lastRun=i; - lastRunOffset=lastRunOffset+charLength; + if (lastRunOffset == 0 && charLength == 0) + { + lastRun--; + lastRunOffset = lastCompletedRunOffset; + } + else + { + lastRun = i; + lastRunOffset = lastRunOffset + charLength; + } break; } } // if the range is empty, than this should be the end of line, ignore it - if(startRunSumHeight(); - if(maxHeightSumHeight(); + if (maxHeight < size) maxHeight = size; } { - vint size=scriptRuns[i]->SumTextHeight(); - if(maxTextHeightSumTextHeight(); + if (maxTextHeight < size) maxTextHeight = size; } } // determine the rendering order for all runs inside this range - Array levels(availableLastRun-startRun+1); + Array levels(availableLastRun - startRun + 1); Array runVisualToLogical(levels.Count()); Array runLogicalToVisual(levels.Count()); - for(vint i=startRun;i<=availableLastRun;i++) + for (vint i = startRun; i <= availableLastRun; i++) { - levels[i-startRun]=scriptRuns[i]->scriptItem->scriptItem.a.s.uBidiLevel; + levels[i - startRun] = scriptRuns[i]->scriptItem->scriptItem.a.s.uBidiLevel; } ScriptLayout((int)levels.Count(), &levels[0], &runVisualToLogical[0], &runLogicalToVisual[0]); // render all runs inside this range - vint startRunFragmentCount=-1; - for(vint i=startRun;i<=availableLastRun;i++) + vint startRunFragmentCount = -1; + for (vint i = startRun; i <= availableLastRun; i++) { - vint runIndex=runVisualToLogical[i-startRun]+startRun; - UniscribeRun* run=scriptRuns[runIndex].Obj(); - vint start=runIndex==startRun?startRunOffset:0; - vint end=runIndex==lastRun?lastRunOffset:run->length; - vint length=end-start; + vint runIndex = runVisualToLogical[i - startRun] + startRun; + UniscribeRun* run = scriptRuns[runIndex].Obj(); + vint start = runIndex == startRun ? startRunOffset : 0; + vint end = runIndex == lastRun ? lastRunOffset : run->length; + vint length = end - start; - if(runIndex==startRun) + if (runIndex == startRun) { - startRunFragmentCount=run->fragmentBounds.Count(); + startRunFragmentCount = run->fragmentBounds.Count(); } UniscribeRun::RunFragmentBounds fragmentBounds; - fragmentBounds.startFromRun=start; - fragmentBounds.length=length; - fragmentBounds.bounds=Rect( - Point(cx, cy+maxHeight-run->SumHeight()), + fragmentBounds.startFromRun = start; + fragmentBounds.length = length; + fragmentBounds.bounds = Rect( + Point(cx, cy + maxHeight - run->SumHeight()), Size(run->SumWidth(start, length), run->SumHeight()) - ); + ); run->fragmentBounds.Add(fragmentBounds); - cx+=run->SumWidth(start, length); + cx += run->SumWidth(start, length); } // adjust alignment - vint cxOffset=0; - switch(alignment) + vint cxOffset = 0; + switch (alignment) { case Alignment::Center: - cxOffset=(availableWidth-cx)/2; + cxOffset = (availableWidth - cx) / 2; break; case Alignment::Right: - cxOffset=availableWidth-cx; + cxOffset = availableWidth - cx; break; } // shift all bounds using alignment - if(cxOffset!=0) + if (cxOffset != 0) { - for(vint i=startRun;i<=availableLastRun;i++) + for (vint i = startRun; i <= availableLastRun; i++) { - UniscribeRun* run=scriptRuns[i].Obj(); - for(vint j=(i==startRun?startRunFragmentCount:0);jfragmentBounds.Count();j++) + UniscribeRun* run = scriptRuns[i].Obj(); + for (vint j = (i == startRun ? startRunFragmentCount : 0); j < run->fragmentBounds.Count(); j++) { - UniscribeRun::RunFragmentBounds& fragmentBounds=run->fragmentBounds[j]; - fragmentBounds.bounds.x1+=cxOffset; - fragmentBounds.bounds.x2+=cxOffset; + UniscribeRun::RunFragmentBounds& fragmentBounds = run->fragmentBounds[j]; + fragmentBounds.bounds.x1 += cxOffset; + fragmentBounds.bounds.x2 += cxOffset; } } } @@ -11442,71 +11472,71 @@ UniscribeLine // create a virtual line { auto virtualLine = Ptr(new UniscribeVirtualLine); - virtualLine->firstRunIndex=startRun; - virtualLine->firstRunBoundsIndex=startRunFragmentCount; - virtualLine->lastRunIndex=availableLastRun; - virtualLine->lastRunBoundsIndex=scriptRuns[availableLastRun]->fragmentBounds.Count()-1; + virtualLine->firstRunIndex = startRun; + virtualLine->firstRunBoundsIndex = startRunFragmentCount; + virtualLine->lastRunIndex = availableLastRun; + virtualLine->lastRunBoundsIndex = scriptRuns[availableLastRun]->fragmentBounds.Count() - 1; - UniscribeRun* firstRun=scriptRuns[virtualLine->firstRunIndex].Obj(); - UniscribeRun* lastRun=scriptRuns[virtualLine->lastRunIndex].Obj(); - UniscribeRun::RunFragmentBounds& firstBounds=firstRun->fragmentBounds[virtualLine->firstRunBoundsIndex]; - UniscribeRun::RunFragmentBounds& lastBounds=lastRun->fragmentBounds[virtualLine->lastRunBoundsIndex]; - - virtualLine->startFromLine=firstRun->startFromLine+firstBounds.startFromRun; - virtualLine->length=lastRun->startFromLine+lastBounds.startFromRun+lastBounds.length-virtualLine->startFromLine; - virtualLine->runText=lineText.Buffer()+virtualLine->startFromLine; + UniscribeRun* firstRun = scriptRuns[virtualLine->firstRunIndex].Obj(); + UniscribeRun* lastRun = scriptRuns[virtualLine->lastRunIndex].Obj(); + UniscribeRun::RunFragmentBounds& firstBounds = firstRun->fragmentBounds[virtualLine->firstRunBoundsIndex]; + UniscribeRun::RunFragmentBounds& lastBounds = lastRun->fragmentBounds[virtualLine->lastRunBoundsIndex]; - bool updateBounds=false; - for(vint i=startRun;i<=availableLastRun;i++) + virtualLine->startFromLine = firstRun->startFromLine + firstBounds.startFromRun; + virtualLine->length = lastRun->startFromLine + lastBounds.startFromRun + lastBounds.length - virtualLine->startFromLine; + virtualLine->runText = lineText.Buffer() + virtualLine->startFromLine; + + bool updateBounds = false; + for (vint i = startRun; i <= availableLastRun; i++) { - UniscribeRun* run=scriptRuns[i].Obj(); - for(vint j=(i==startRun?startRunFragmentCount:0);jfragmentBounds.Count();j++) + UniscribeRun* run = scriptRuns[i].Obj(); + for (vint j = (i == startRun ? startRunFragmentCount : 0); j < run->fragmentBounds.Count(); j++) { - UniscribeRun::RunFragmentBounds& fragmentBounds=run->fragmentBounds[j]; - if(updateBounds) + UniscribeRun::RunFragmentBounds& fragmentBounds = run->fragmentBounds[j]; + if (updateBounds) { - if(virtualLine->bounds.x1>fragmentBounds.bounds.x1) virtualLine->bounds.x1=fragmentBounds.bounds.x1; - if(virtualLine->bounds.x2bounds.x2=fragmentBounds.bounds.x2; - if(virtualLine->bounds.y1>fragmentBounds.bounds.y1) virtualLine->bounds.y1=fragmentBounds.bounds.y1; - if(virtualLine->bounds.y2bounds.y2=fragmentBounds.bounds.y2; + if (virtualLine->bounds.x1 > fragmentBounds.bounds.x1) virtualLine->bounds.x1 = fragmentBounds.bounds.x1; + if (virtualLine->bounds.x2 < fragmentBounds.bounds.x2) virtualLine->bounds.x2 = fragmentBounds.bounds.x2; + if (virtualLine->bounds.y1 > fragmentBounds.bounds.y1) virtualLine->bounds.y1 = fragmentBounds.bounds.y1; + if (virtualLine->bounds.y2 < fragmentBounds.bounds.y2) virtualLine->bounds.y2 = fragmentBounds.bounds.y2; } else { - virtualLine->bounds=fragmentBounds.bounds; - updateBounds=true; + virtualLine->bounds = fragmentBounds.bounds; + updateBounds = true; } } } virtualLines.Add(virtualLine); } - cx=0; - cy+=(vint)(maxHeight + maxTextHeight*0.5); + cx = 0; + cy += (vint)(maxHeight + maxTextHeight * 0.5); } - startRun=lastRun; - startRunOffset=lastRunOffset; + startRun = lastRun; + startRunOffset = lastRunOffset; } // calculate line bounds - vint minX=0; - vint minY=top; - vint maxX=0; - vint maxY=top; + vint minX = 0; + vint minY = top; + vint maxX = 0; + vint maxY = top; for (auto run : scriptRuns) { for (auto fragmentBounds : run->fragmentBounds) { - Rect bounds=fragmentBounds.bounds; - if(minX>bounds.Left()) minX=bounds.Left(); - if(minY>bounds.Top()) minX=bounds.Top(); - if(maxX bounds.Left()) minX = bounds.Left(); + if (minY > bounds.Top()) minX = bounds.Top(); + if (maxX < bounds.Right()) maxX = bounds.Right(); + if (maxY < bounds.Bottom()) maxY = bounds.Bottom(); } } - bounds=Rect(minX, minY, maxX, maxY); + bounds = Rect(minX, minY, maxX, maxY); } - totalHeight=cy; + totalHeight = cy; } void UniscribeLine::Render(UniscribeRun::IRendererCallback* callback, vint offsetX, vint offsetY, bool renderBackground) @@ -11525,7 +11555,7 @@ UniscribeParagraph ***********************************************************************/ UniscribeParagraph::UniscribeParagraph() - :wrapLine(true) + :lastWrapLine(true) ,lastAvailableWidth(-1) ,paragraphAlignment(Alignment::Left) ,built(false) @@ -11638,48 +11668,54 @@ UniscribeParagraph (Initialization) return true; } - void UniscribeParagraph::Layout(vint availableWidth, Alignment alignment) + void UniscribeParagraph::Layout(bool wrapLine, vint availableWidth, Alignment alignment) { - if(lastAvailableWidth==availableWidth && paragraphAlignment==alignment) + if (lastWrapLine == wrapLine && lastAvailableWidth == availableWidth && paragraphAlignment == alignment) { return; } - lastAvailableWidth=availableWidth; - paragraphAlignment=alignment; + lastWrapLine = wrapLine; + lastAvailableWidth = availableWidth; + paragraphAlignment = alignment; - vint cy=0; + if (lastAvailableWidth == -1) + { + return; + } + + vint cy = 0; for (auto line : lines) { - line->Layout(availableWidth, alignment, cy, cy); + line->Layout(wrapLine, availableWidth, alignment, cy, cy); } // calculate paragraph bounds - vint minX=0; - vint minY=0; - vint maxX=0; - vint maxY=0; + vint minX = 0; + vint minY = 0; + vint maxX = 0; + vint maxY = 0; for (auto line : lines) { - Rect bounds=line->bounds; - if(minX>bounds.Left()) minX=bounds.Left(); - if(minY>bounds.Top()) minX=bounds.Top(); - if(maxXbounds; + if (minX > bounds.Left()) minX = bounds.Left(); + if (minY > bounds.Top()) minX = bounds.Top(); + if (maxX < bounds.Right()) maxX = bounds.Right(); + if (maxY < bounds.Bottom()) maxY = bounds.Bottom(); } - vint offsetY=0; + vint offsetY = 0; for (auto line : lines) { for (auto fragment : line->documentFragments) { - vint size=fragment->fontStyle.size/3; - if(size>offsetY) + vint size = fragment->fontStyle.size / 3; + if (size > offsetY) { - offsetY=size; + offsetY = size; } } } - bounds=Rect(minX, minY, maxX, maxY+offsetY); + bounds = Rect(minX, minY, maxX, maxY + offsetY); } void UniscribeParagraph::Render(UniscribeRun::IRendererCallback* callback, bool renderBackground) @@ -12122,118 +12158,174 @@ UniscribeParagraph (Caret Helper) } } + void UniscribeParagraph::GetRunIndexFromTextPos(vint textPos, vint lineIndex, vint& frontRun, vint& backRun) + { + frontRun = -1; + backRun = -1; + if (!IsValidTextPos(textPos)) return; + if (lineIndex < 0 || lineIndex >= lines.Count()) return; + + Ptr line = lines[lineIndex]; + vint start = 0; + vint end = line->scriptRuns.Count() - 1; + while (start <= end) + { + vint middle = (start + end) / 2; + Ptr run = line->scriptRuns[middle]; + vint lineStart = line->startFromParagraph + run->startFromLine; + vint lineEnd = line->startFromParagraph + run->startFromLine + run->length; + if (textPos < lineStart) + { + end = middle - 1; + } + else if (textPos > lineEnd) + { + start = middle + 1; + } + else if (textPos == lineStart) + { + frontRun = middle == 0 ? 0 : middle - 1; + backRun = middle; + return; + } + else if (textPos == lineEnd) + { + frontRun = middle; + backRun = middle == line->scriptItems.Count() - 1 ? middle : middle + 1; + return; + } + else + { + frontRun = middle; + backRun = middle; + return; + } + } + } + Rect UniscribeParagraph::GetCaretBoundsWithLine(vint caret, vint lineIndex, vint virtualLineIndex, bool frontSide) { - Ptr line=lines[lineIndex]; - if(line->startFromParagraph<=caret && caret<=line->startFromParagraph+line->lineText.Length()) + Ptr line = lines[lineIndex]; + if (line->startFromParagraph <= caret && caret <= line->startFromParagraph + line->lineText.Length()) { - if(line->lineText==L"") return line->bounds; - Ptr virtualLine=line->virtualLines[virtualLineIndex]; + if (line->lineText == L"") return line->bounds; + Ptr virtualLine = line->virtualLines[virtualLineIndex]; - for(vint i=virtualLine->firstRunIndex;i<=virtualLine->lastRunIndex;i++) + for (vint i = virtualLine->firstRunIndex; i <= virtualLine->lastRunIndex; i++) { - Ptr run=line->scriptRuns[i]; - if(Ptr textRun=run.Cast()) + Ptr run = line->scriptRuns[i]; + vint firstBounds = i == virtualLine->firstRunIndex ? virtualLine->firstRunBoundsIndex : 0; + vint lastBounds = i == virtualLine->lastRunIndex ? virtualLine->lastRunBoundsIndex : run->fragmentBounds.Count() - 1; + + for (vint j = firstBounds; j <= lastBounds; j++) { - vint firstBounds=i==virtualLine->firstRunIndex?virtualLine->firstRunBoundsIndex:0; - vint lastBounds=i==virtualLine->lastRunIndex?virtualLine->lastRunBoundsIndex:run->fragmentBounds.Count()-1; - - for(vint j=firstBounds;j<=lastBounds;j++) + UniscribeRun::RunFragmentBounds& bounds = run->fragmentBounds[j]; + vint boundsStart = line->startFromParagraph + run->startFromLine + bounds.startFromRun; + if (boundsStart == caret) { - UniscribeRun::RunFragmentBounds& bounds=run->fragmentBounds[j]; - vint boundsStart=line->startFromParagraph+run->startFromLine+bounds.startFromRun; - if(boundsStart==caret) + if (!frontSide || i == virtualLine->firstRunIndex && j == virtualLine->firstRunBoundsIndex) { - if(!frontSide || i==virtualLine->firstRunIndex && j==virtualLine->firstRunBoundsIndex) + if (run->scriptItem->scriptItem.a.fRTL) { - if(run->scriptItem->scriptItem.a.fRTL) - { - return Rect(bounds.bounds.x2, bounds.bounds.y1, bounds.bounds.x2, bounds.bounds.y2); - } - else - { - return Rect(bounds.bounds.x1, bounds.bounds.y1, bounds.bounds.x1, bounds.bounds.y2); - } + return Rect(bounds.bounds.x2, bounds.bounds.y1, bounds.bounds.x2, bounds.bounds.y2); + } + else + { + return Rect(bounds.bounds.x1, bounds.bounds.y1, bounds.bounds.x1, bounds.bounds.y2); } } - else if(caret==boundsStart+bounds.length) + } + else if (caret == boundsStart + bounds.length) + { + if (frontSide || i == virtualLine->lastRunIndex && j == virtualLine->lastRunBoundsIndex) { - if(frontSide || i==virtualLine->lastRunIndex && j==virtualLine->lastRunBoundsIndex) + if (run->scriptItem->scriptItem.a.fRTL) { - if(run->scriptItem->scriptItem.a.fRTL) - { - return Rect(bounds.bounds.x1, bounds.bounds.y1, bounds.bounds.x1, bounds.bounds.y2); - } - else - { - return Rect(bounds.bounds.x2, bounds.bounds.y1, bounds.bounds.x2, bounds.bounds.y2); - } + return Rect(bounds.bounds.x1, bounds.bounds.y1, bounds.bounds.x1, bounds.bounds.y2); + } + else + { + return Rect(bounds.bounds.x2, bounds.bounds.y1, bounds.bounds.x2, bounds.bounds.y2); } } - else if(boundsStart textRun = run.Cast()) { - vint accumulatedWidth=0; - vint lastRunChar=bounds.startFromRun; - for(vint i=0;i<=bounds.length;i++) + vint accumulatedWidth = 0; + vint lastRunChar = bounds.startFromRun; + for (vint i = 0; i <= bounds.length; i++) { - vint charIndex=bounds.startFromRun+i; - vint newLastRunChar=lastRunChar; - if(i>0) + vint charIndex = bounds.startFromRun + i; + vint newLastRunChar = lastRunChar; + if (i > 0) { - if(i==bounds.length) + if (i == bounds.length) { - newLastRunChar=charIndex; + newLastRunChar = charIndex; } else { - WORD cluster1=textRun->wholeGlyph.charCluster[charIndex-1]; - WORD cluster2=textRun->wholeGlyph.charCluster[charIndex]; - if(cluster1!=cluster2) + WORD cluster1 = textRun->wholeGlyph.charCluster[charIndex - 1]; + WORD cluster2 = textRun->wholeGlyph.charCluster[charIndex]; + if (cluster1 != cluster2) { - newLastRunChar=charIndex; + newLastRunChar = charIndex; } } } - if(newLastRunChar!=lastRunChar) + if (newLastRunChar != lastRunChar) { - WORD glyph1=0; - WORD glyph2=0; - if(run->scriptItem->scriptItem.a.fRTL) + WORD glyph1 = 0; + WORD glyph2 = 0; + if (run->scriptItem->scriptItem.a.fRTL) { - glyph2=textRun->wholeGlyph.charCluster[lastRunChar]+1; - glyph1=newLastRunChar==run->length?0:textRun->wholeGlyph.charCluster[newLastRunChar]+1; + glyph2 = textRun->wholeGlyph.charCluster[lastRunChar] + 1; + glyph1 = newLastRunChar == run->length ? 0 : textRun->wholeGlyph.charCluster[newLastRunChar] + 1; } else { - glyph1=textRun->wholeGlyph.charCluster[lastRunChar]; - glyph2=newLastRunChar==run->length?(WORD)textRun->wholeGlyph.glyphs.Count():textRun->wholeGlyph.charCluster[newLastRunChar]; + glyph1 = textRun->wholeGlyph.charCluster[lastRunChar]; + glyph2 = newLastRunChar == run->length ? (WORD)textRun->wholeGlyph.glyphs.Count() : textRun->wholeGlyph.charCluster[newLastRunChar]; } - vint glyphWidth=0; - for(WORD g=glyph1;gwholeGlyph.glyphAdvances[g]; + glyphWidth += textRun->wholeGlyph.glyphAdvances[g]; } - accumulatedWidth+=glyphWidth; - lastRunChar=newLastRunChar; + accumulatedWidth += glyphWidth; + lastRunChar = newLastRunChar; - if(line->startFromParagraph+run->startFromLine+lastRunChar==caret) + if (line->startFromParagraph + run->startFromLine + lastRunChar == caret) { - vint x=0; - if(run->scriptItem->scriptItem.a.fRTL) + vint x = 0; + if (run->scriptItem->scriptItem.a.fRTL) { - x=bounds.bounds.x2-accumulatedWidth; + x = bounds.bounds.x2 - accumulatedWidth; } else { - x=bounds.bounds.x1+accumulatedWidth; + x = bounds.bounds.x1 + accumulatedWidth; } return Rect(x, bounds.bounds.y1, x, bounds.bounds.y2); } } } } + else + { + if (frontSide == !run->scriptItem->scriptItem.a.fRTL) + { + return Rect(bounds.bounds.x1, bounds.bounds.y1, bounds.bounds.x1, bounds.bounds.y2); + } + else + { + return Rect(bounds.bounds.x2, bounds.bounds.y1, bounds.bounds.x2, bounds.bounds.y2); + } + } } } } @@ -12612,51 +12704,68 @@ UniscribeParagraph (Caret) vint UniscribeParagraph::GetNearestCaretFromTextPos(vint textPos, bool frontSide) { - if(!IsValidTextPos(textPos)) return -1; - vint frontLine=0; - vint backLine=0; + if (!IsValidTextPos(textPos)) return -1; + vint frontLine = 0; + vint backLine = 0; GetLineIndexFromTextPos(textPos, frontLine, backLine); - if(frontLine==-1 || backLine==-1) return -1; - if(frontLine!=backLine) + if (frontLine == -1 || backLine == -1) return -1; + if (frontLine != backLine) { - return frontSide?textPos-1:textPos+1; + return frontSide ? textPos - 1 : textPos + 1; } - Ptr line=lines[frontLine]; - if(textPos==line->startFromParagraph || textPos==line->startFromParagraph+line->lineText.Length()) + Ptr line = lines[frontLine]; + if (textPos == line->startFromParagraph || textPos == line->startFromParagraph + line->lineText.Length()) { return textPos; } - vint frontItem=-1; - vint backItem=-1; - GetItemIndexFromTextPos(textPos, frontLine, frontItem, backItem); - if(frontItem==-1 || backItem==-1) return -1; - if(frontItem!=backItem) return textPos; - - Ptr item=line->scriptItems[frontItem]; - vint lineTextPos=textPos-line->startFromParagraph; - if(lineTextPos==item->startFromLine) return textPos; - if(lineTextPos==item->startFromLine+item->length) return textPos; - - vint itemTextPos=lineTextPos-item->startFromLine; - if(item->charLogattrs[itemTextPos].fCharStop) return textPos; - - if(frontSide) + vint frontRun = -1; + vint backRun = -1; + GetRunIndexFromTextPos(textPos, frontLine, frontRun, backRun); + if (frontRun == -1 || backRun == -1) return -1; + if (frontRun != backRun) { - for(vint i=itemTextPos-1;i>=0;i--) + return textPos; + } + + Ptr run = line->scriptRuns[frontRun]; + if (auto objectRun = run.Cast()) + { + return frontSide + ? line->startFromParagraph + run->startFromLine + : line->startFromParagraph + run->startFromLine + run->length + ; + } + vint lineTextPos = textPos - line->startFromParagraph; + if (lineTextPos == run->startFromLine) return textPos; + if (lineTextPos == run->startFromLine + run->length) return textPos; + + auto item = run->scriptItem; + vint itemTextPos = lineTextPos - item->startFromLine; + if (item->charLogattrs[itemTextPos].fCharStop) return textPos; + + if (frontSide) + { + for (vint i = itemTextPos - 1; i >= 0; i--) { - if(item->charLogattrs[i].fCharStop) return i+line->startFromParagraph+item->startFromLine; + if (item->charLogattrs[i].fCharStop) + { + return i + line->startFromParagraph + item->startFromLine; + } } - return line->startFromParagraph+item->startFromLine; + return line->startFromParagraph + item->startFromLine; } else { - for(vint i=itemTextPos+1;ilength;i++) + for (vint i = itemTextPos + 1; i < item->length; i++) { - if(item->charLogattrs[i].fCharStop) return i+line->startFromParagraph+item->startFromLine; + if (item->charLogattrs[i].fCharStop) + { + return i + line->startFromParagraph + item->startFromLine; + } } - return line->startFromParagraph+item->startFromLine+item->length; + return line->startFromParagraph + item->startFromLine + item->length; } } diff --git a/Import/GacUI.Windows.h b/Import/GacUI.Windows.h index 6370e1bb..cbd4af98 100644 --- a/Import/GacUI.Windows.h +++ b/Import/GacUI.Windows.h @@ -1261,7 +1261,7 @@ UniscribeRun virtual vint SumWidth(vint charStart, vint charLength)=0; virtual vint SumHeight()=0; virtual vint SumTextHeight()=0; - virtual void SearchForLineBreak(vint tempStart, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances)=0; + virtual void SearchForLineBreak(vint tempStart, bool wrapLine, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances)=0; virtual void Render(IRendererCallback* callback, vint fragmentBoundsIndex, vint offsetX, vint offsetY, bool renderBackground)=0; }; @@ -1289,7 +1289,7 @@ UniscribeTextRun vint SumWidth(vint charStart, vint charLength)override; vint SumHeight()override; vint SumTextHeight()override; - void SearchForLineBreak(vint tempStart, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances)override; + void SearchForLineBreak(vint tempStart, bool wrapLine, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances)override; void Render(IRendererCallback* callback, vint fragmentBoundsIndex, vint offsetX, vint offsetY, bool renderBackground)override; }; @@ -1310,7 +1310,7 @@ UniscribeElementRun vint SumWidth(vint charStart, vint charLength)override; vint SumHeight()override; vint SumTextHeight()override; - void SearchForLineBreak(vint tempStart, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances)override; + void SearchForLineBreak(vint tempStart, bool wrapLine, vint maxWidth, bool firstRun, vint& charLength, vint& charAdvances)override; void Render(IRendererCallback* callback, vint fragmentBoundsIndex, vint offsetX, vint offsetY, bool renderBackground)override; }; @@ -1357,7 +1357,7 @@ UniscribeLine void ClearUniscribeData(); bool BuildUniscribeData(WinDC* dc); - void Layout(vint availableWidth, Alignment alignment, vint top, vint& totalHeight); + void Layout(bool wrapLine, vint availableWidth, Alignment alignment, vint top, vint& totalHeight); void Render(UniscribeRun::IRendererCallback* callback, vint offsetX, vint offsetY, bool renderBackground); }; @@ -1376,7 +1376,7 @@ UniscribeParagraph //***************************** Uniscribe Data List> lines; //***************************** Layout Data - bool wrapLine; + bool lastWrapLine; vint lastAvailableWidth; Rect bounds; @@ -1385,7 +1385,7 @@ UniscribeParagraph void ClearUniscribeData(); bool BuildUniscribeData(WinDC* dc); - void Layout(vint availableWidth, Alignment alignment); + void Layout(bool wrapLine, vint availableWidth, Alignment alignment); void Render(UniscribeRun::IRendererCallback* callback, bool renderBackground); void SearchFragment(vint start, vint length, vint& fs, vint& ss, vint& fe, vint& se); @@ -1403,6 +1403,7 @@ UniscribeParagraph void GetLineIndexFromTextPos(vint textPos, vint& frontLine, vint& backLine); void GetVirtualLineIndexFromTextPos(vint textPos, vint lineIndex, vint& frontLine, vint& backLine); void GetItemIndexFromTextPos(vint textPos, vint lineIndex, vint& frontItem, vint& backItem); + void GetRunIndexFromTextPos(vint textPos, vint lineIndex, vint& frontRun, vint& backRun); Rect GetCaretBoundsWithLine(vint caret, vint lineIndex, vint virtualLineIndex, bool frontSide); vint GetCaretFromXWithTextRunBounds(vint x, vint lineIndex, vint runIndex, vint runBoundsIndex); vint GetCaretFromXWithLine(vint x, vint lineIndex, vint virtualLineIndex); diff --git a/Import/GacUI.cpp b/Import/GacUI.cpp index d2b90a5c..ce045a82 100644 --- a/Import/GacUI.cpp +++ b/Import/GacUI.cpp @@ -18697,15 +18697,6 @@ GuiDocumentCommonInterface SetActiveHyperlink(nullptr); } - Point GuiDocumentCommonInterface::GetDocumentViewPosition() - { - return Point(0, 0); - } - - void GuiDocumentCommonInterface::EnsureRectVisible(Rect bounds) - { - } - //================ callback void GuiDocumentCommonInterface::OnStartRender() @@ -18743,11 +18734,120 @@ GuiDocumentCommonInterface //================ basic + void GuiDocumentCommonInterface::UserInput_FixForPlainText(Ptr model, vint beginParagraph, vint endParagraph) + { + if (beginParagraph > endParagraph) return; + + RunRangeMap runRanges; + document_editor::GetRunRange(model->paragraphs[endParagraph].Obj(), runRanges); + + TextPos begin(beginParagraph, 0); + TextPos end(endParagraph, runRanges[model->paragraphs[endParagraph].Obj()].end); + model->ConvertToPlainText(begin, end); + + for (vint i = beginParagraph; i <= endParagraph; i++) + { + model->paragraphs[i]->alignment.Reset(); + } + } + + void GuiDocumentCommonInterface::UserInput_FixForSingleline(collections::List& paragraphTexts) + { + auto line = stream::GenerateToStream([&](stream::StreamWriter& writer) + { + for(auto [paragraph, index] : indexed(paragraphTexts)) + { + if (index > 0 && config.spaceForFlattenedLineBreak) + { + writer.WriteChar(L' '); + } + writer.WriteString(paragraph); + } + }); + paragraphTexts.Clear(); + paragraphTexts.Add(line); + } + + void GuiDocumentCommonInterface::UserInput_FixForSingleline(Ptr model) + { + auto firstParagraph = model->paragraphs[0]; + for (auto paragraph : From(model->paragraphs).Skip(1)) + { + if (config.spaceForFlattenedLineBreak) + { + auto textRun = Ptr(new DocumentTextRun); + textRun->text = WString::Unmanaged(L" "); + firstParagraph->runs.Add(textRun); + } + CopyFrom(firstParagraph->runs, paragraph->runs, true); + } + model->paragraphs.Clear(); + model->paragraphs.Add(firstParagraph); + } + + void GuiDocumentCommonInterface::UserInput_FixForNonParagraph(WString& text) + { + text = stream::GenerateToStream([&](stream::StreamWriter& writer) + { + for (vint j = 0; j < text.Length(); j++) + { + if (text[j] == L'\n') + { + if (config.spaceForFlattenedLineBreak) + { + writer.WriteChar(L' '); + } + } + else if (text[j] != L'\r') + { + writer.WriteChar(text[j]); + } + } + }); + } + + void GuiDocumentCommonInterface::UserInput_FixForNonParagraph(Ptr paragraph) + { + List> containers; + containers.Add(paragraph); + + for (vint i = 0; i < containers.Count(); i++) + { + auto container = containers[i]; + for (auto run : container->runs) + { + if (auto subContainer = run.Cast()) + { + containers.Add(subContainer); + } + else if (auto textRun = run.Cast()) + { + UserInput_FixForNonParagraph(textRun->text); + } + } + } + } + WString GuiDocumentCommonInterface::UserInput_ConvertDocumentToText(Ptr model) { return model->GetTextForReading(WString::Unmanaged(config.doubleLineBreaksBetweenParagraph ? L"\r\n\r\n" : L"\r\n")); } + void GuiDocumentCommonInterface::UserInput_FormatText(collections::List& paragraphTexts) + { + if (config.paragraphMode != GuiDocumentParagraphMode::Paragraph) + { + for (vint i = 0; i < paragraphTexts.Count(); i++) + { + UserInput_FixForNonParagraph(paragraphTexts[i]); + } + } + if (config.paragraphMode == GuiDocumentParagraphMode::Singleline) + { + UserInput_FixForSingleline(paragraphTexts); + } + } + void GuiDocumentCommonInterface::UserInput_FormatText(const WString& text, collections::List& paragraphTexts) { stream::StringReader reader(text); @@ -18800,22 +18900,9 @@ GuiDocumentCommonInterface { paragraphTexts.Add(paragraph); } - if (config.paragraphMode == GuiDocumentParagraphMode::Singleline) { - auto line = stream::GenerateToStream([&](stream::StreamWriter& writer) - { - for(auto [paragraph, index] : indexed(paragraphTexts)) - { - if (index > 0 && config.spaceForFlattenedLineBreak) - { - writer.WriteChar(L' '); - } - writer.WriteString(paragraph); - } - }); - paragraphTexts.Clear(); - paragraphTexts.Add(line); + UserInput_FixForSingleline(paragraphTexts); } } @@ -18824,21 +18911,7 @@ GuiDocumentCommonInterface if (!model) return; if (config.pasteAsPlainText) { - if (model->paragraphs.Count() > 0) - { - RunRangeMap runRanges; - vint lastParagraphIndex = model->paragraphs.Count() - 1; - document_editor::GetRunRange(model->paragraphs[lastParagraphIndex].Obj(), runRanges); - - TextPos begin(0, 0); - TextPos end(lastParagraphIndex, runRanges[model->paragraphs[lastParagraphIndex].Obj()].end); - model->ConvertToPlainText(begin, end); - - for (auto paragraph : model->paragraphs) - { - paragraph->alignment.Reset(); - } - } + UserInput_FixForPlainText(model, 0, model->paragraphs.Count() - 1); if (baselineDocument) { @@ -18857,60 +18930,14 @@ GuiDocumentCommonInterface if (config.paragraphMode != GuiDocumentParagraphMode::Paragraph) { - List> containers; for (auto paragraph : model->paragraphs) { - containers.Add(paragraph); - } - - for (vint i = 0; i < containers.Count(); i++) - { - auto container = containers[i]; - for (auto run : container->runs) - { - if (auto subContainer = run.Cast()) - { - containers.Add(subContainer); - } - else if (auto textRun = run.Cast()) - { - textRun->text = stream::GenerateToStream([&](stream::StreamWriter& writer) - { - for (vint j = 0; j < textRun->text.Length(); j++) - { - if (textRun->text[j] == L'\n') - { - if (config.spaceForFlattenedLineBreak) - { - writer.WriteChar(L' '); - } - } - else if (textRun->text[j] != L'\r') - { - writer.WriteChar(textRun->text[j]); - } - } - }); - } - } + UserInput_FixForNonParagraph(paragraph); } } - if (config.paragraphMode == GuiDocumentParagraphMode::Singleline) { - auto firstParagraph = model->paragraphs[0]; - for(auto paragraph:From(model->paragraphs).Skip(1)) - { - if (config.spaceForFlattenedLineBreak) - { - auto textRun = Ptr(new DocumentTextRun); - textRun->text = WString::Unmanaged(L" "); - firstParagraph->runs.Add(textRun); - } - CopyFrom(firstParagraph->runs, paragraph->runs, true); - } - model->paragraphs.Clear(); - model->paragraphs.Add(firstParagraph); + UserInput_FixForSingleline(model); } } @@ -19027,11 +19054,44 @@ GuiDocumentCommonInterface void GuiDocumentCommonInterface::NotifyParagraphUpdated(vint index, vint oldCount, vint newCount, bool updatedText) { - documentElement->NotifyParagraphUpdated(index, oldCount, newCount, updatedText); +#define ERROR_MESSAGE_PREFIX L"vl::presentation::controls::GuiDocumentCommonInterface::NotifyParagraphUpdated(vint, vint, vint, bool)#" + auto model = documentElement->GetDocument(); + if (config.paragraphMode == GuiDocumentParagraphMode::Singleline) + { + CHECK_ERROR(model->paragraphs.Count() <= 1, ERROR_MESSAGE_PREFIX L"In Singleline mode, there should be no more than 1 paragraphs in the document."); + } + + if (0 <= index && index + newCount <= model->paragraphs.Count()) + { + if (config.pasteAsPlainText && updatedText) + { + UserInput_FixForPlainText(model, index, index + newCount - 1); + if (baselineDocument) + { + CopyFrom(model->styles, baselineDocument->styles); + } + else + { + model->styles.Clear(); + } + } + + if (config.paragraphMode != GuiDocumentParagraphMode::Paragraph) + { + for (vint i = index; i < index + newCount; i++) + { + UserInput_FixForNonParagraph(model->paragraphs[i]); + } + } + + documentElement->NotifyParagraphUpdated(index, oldCount, newCount, updatedText); + } +#undef ERROR_MESSAGE_PREFIX } void GuiDocumentCommonInterface::EditRun(TextPos begin, TextPos end, Ptr model, bool copy) { + UserInput_FormatDocument(model); EditTextInternal(begin, end, [=, this](TextPos begin, TextPos end, vint& paragraphCount, vint& lastParagraphLength) { documentElement->EditRun(begin, end, model, copy); @@ -19044,14 +19104,26 @@ GuiDocumentCommonInterface { EditTextInternal(begin, end, [=, this, &text](TextPos begin, TextPos end, vint& paragraphCount, vint& lastParagraphLength) { - documentElement->EditText(begin, end, frontSide, text); - paragraphCount=text.Count(); - lastParagraphLength=paragraphCount==0?0:text[paragraphCount-1].Length(); + Array updatedText; + bool useUpdatedText = config.paragraphMode != GuiDocumentParagraphMode::Paragraph; + if (useUpdatedText) + { + List paragraphTexts; + CopyFrom(paragraphTexts, text); + UserInput_FormatText(paragraphTexts); + CopyFrom(updatedText, paragraphTexts); + } + + const Array& textToUse = useUpdatedText ? updatedText : text; + documentElement->EditText(begin, end, frontSide, textToUse); + paragraphCount = textToUse.Count(); + lastParagraphLength = paragraphCount == 0 ? 0 : textToUse[paragraphCount - 1].Length(); }); } void GuiDocumentCommonInterface::EditStyle(TextPos begin, TextPos end, Ptr style) { + if (config.pasteAsPlainText) return; EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end) { documentElement->EditStyle(begin, end, style); @@ -19060,6 +19132,7 @@ GuiDocumentCommonInterface void GuiDocumentCommonInterface::EditImage(TextPos begin, TextPos end, Ptr image) { + if (config.pasteAsPlainText) return; EditTextInternal(begin, end, [=, this](TextPos begin, TextPos end, vint& paragraphCount, vint& lastParagraphLength) { documentElement->EditImage(begin, end, image); @@ -19070,6 +19143,7 @@ GuiDocumentCommonInterface void GuiDocumentCommonInterface::EditHyperlink(vint paragraphIndex, vint begin, vint end, const WString& reference, const WString& normalStyleName, const WString& activeStyleName) { + if (config.pasteAsPlainText) return; EditStyleInternal(TextPos(paragraphIndex, begin), TextPos(paragraphIndex, end), [=, this](TextPos begin, TextPos end) { documentElement->EditHyperlink(begin.row, begin.column, end.column, reference, normalStyleName, activeStyleName); @@ -19078,6 +19152,7 @@ GuiDocumentCommonInterface void GuiDocumentCommonInterface::RemoveHyperlink(vint paragraphIndex, vint begin, vint end) { + if (config.pasteAsPlainText) return; EditStyleInternal(TextPos(paragraphIndex, begin), TextPos(paragraphIndex, end), [=, this](TextPos begin, TextPos end) { documentElement->RemoveHyperlink(begin.row, begin.column, end.column); @@ -19086,6 +19161,7 @@ GuiDocumentCommonInterface void GuiDocumentCommonInterface::EditStyleName(TextPos begin, TextPos end, const WString& styleName) { + if (config.pasteAsPlainText) return; EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end) { documentElement->EditStyleName(begin, end, styleName); @@ -19094,6 +19170,7 @@ GuiDocumentCommonInterface void GuiDocumentCommonInterface::RemoveStyleName(TextPos begin, TextPos end) { + if (config.pasteAsPlainText) return; EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end) { documentElement->RemoveStyleName(begin, end); @@ -19102,6 +19179,7 @@ GuiDocumentCommonInterface void GuiDocumentCommonInterface::RenameStyle(const WString& oldStyleName, const WString& newStyleName) { + if (config.pasteAsPlainText) return; documentElement->RenameStyle(oldStyleName, newStyleName); // submit redo-undo @@ -19113,12 +19191,21 @@ GuiDocumentCommonInterface void GuiDocumentCommonInterface::ClearStyle(TextPos begin, TextPos end) { + if (config.pasteAsPlainText) return; EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end) { documentElement->ClearStyle(begin, end); }); } + void GuiDocumentCommonInterface::ConvertToPlainText(TextPos begin, TextPos end) + { + EditStyleInternal(begin, end, [=, this](TextPos begin, TextPos end) + { + documentElement->ConvertToPlainText(begin, end); + }); + } + Ptr GuiDocumentCommonInterface::SummarizeStyle(TextPos begin, TextPos end) { if (begin>end) @@ -19472,7 +19559,8 @@ GuiDocumentViewer Point GuiDocumentViewer::GetDocumentViewPosition() { - return GetViewBounds().LeftTop(); + // the document does not move in containerComposition + return { 0,0 }; } void GuiDocumentViewer::EnsureRectVisible(Rect bounds) @@ -33854,6 +33942,25 @@ GuiDocumentElement } } + void GuiDocumentElement::ConvertToPlainText(TextPos begin, TextPos end) + { + if (auto elementRenderer = renderer.Cast()) + { + if (begin > end) + { + TextPos temp = begin; + begin = end; + end = temp; + } + + if (document->ConvertToPlainText(begin, end)) + { + elementRenderer->NotifyParagraphUpdated(begin.row, end.row - begin.row + 1, end.row - begin.row + 1, false); + } + InvokeOnCompositionStateChanged(); + } + } + Ptr GuiDocumentElement::SummarizeStyle(TextPos begin, TextPos end) { if (auto elementRenderer = renderer.Cast()) diff --git a/Import/GacUI.h b/Import/GacUI.h index d88536d7..a33c77d5 100644 --- a/Import/GacUI.h +++ b/Import/GacUI.h @@ -13113,6 +13113,10 @@ Rich Content Document (element) /// The begin position of the range. /// The end position of the range. void ClearStyle(TextPos begin, TextPos end); + /// Clear all styles and remove non-text contents in a specified range. + /// The begin position of the range. + /// The end position of the range. + void ConvertToPlainText(TextPos begin, TextPos end); /// Summarize the text style in a specified range. /// The text style summary. /// The begin position of the range. @@ -16851,8 +16855,8 @@ GuiDocumentCommonInterface void OnMouseUp(compositions::GuiGraphicsComposition* sender, compositions::GuiMouseEventArgs& arguments); void OnMouseLeave(compositions::GuiGraphicsComposition* sender, compositions::GuiEventArgs& arguments); - virtual Point GetDocumentViewPosition(); - virtual void EnsureRectVisible(Rect bounds); + virtual Point GetDocumentViewPosition() = 0; + virtual void EnsureRectVisible(Rect bounds) = 0; //================ callback @@ -16862,7 +16866,14 @@ GuiDocumentCommonInterface protected: + void UserInput_FixForPlainText(Ptr model, vint beginParagraph, vint endParagraph); + void UserInput_FixForSingleline(collections::List& paragraphTexts); + void UserInput_FixForSingleline(Ptr model); + void UserInput_FixForNonParagraph(WString& text); + void UserInput_FixForNonParagraph(Ptr paragraph); + WString UserInput_ConvertDocumentToText(Ptr model); + void UserInput_FormatText(collections::List& paragraphTexts); void UserInput_FormatText(const WString& text, collections::List& paragraphTexts); void UserInput_FormatDocument(Ptr model); @@ -16993,6 +17004,10 @@ GuiDocumentCommonInterface /// The begin position of the range. /// The end position of the range. void ClearStyle(TextPos begin, TextPos end); + /// Clear all styles and remove non-text contents in a specified range. + /// The begin position of the range. + /// The end position of the range. + void ConvertToPlainText(TextPos begin, TextPos end); /// Summarize the text style in a specified range. /// The text style summary. /// The begin position of the range. diff --git a/Import/GacUIReflection.cpp b/Import/GacUIReflection.cpp index 172d0866..50d05a85 100644 --- a/Import/GacUIReflection.cpp +++ b/Import/GacUIReflection.cpp @@ -2988,6 +2988,7 @@ Type Declaration (Class) CLASS_MEMBER_METHOD(RemoveStyleName, {L"begin" _ L"end" _ L"image"}) CLASS_MEMBER_METHOD(RenameStyle, {L"oldStyleName" _ L"newStyleName"}) CLASS_MEMBER_METHOD(ClearStyle, {L"begin" _ L"end"}) + CLASS_MEMBER_METHOD(ConvertToPlainText, { L"begin" _ L"end" }) CLASS_MEMBER_METHOD(SummarizeStyle, {L"begin" _ L"end"}) CLASS_MEMBER_METHOD(SummarizeStyleName, { L"begin" _ L"end" }) CLASS_MEMBER_METHOD(SetParagraphAlignments, { L"begin" _ L"end" _ L"alignments" }) @@ -3471,6 +3472,7 @@ Type Declaration (Class) CLASS_MEMBER_METHOD(RemoveStyleName, {L"begin" _ L"end" _ L"image"}) CLASS_MEMBER_METHOD(RenameStyle, {L"oldStyleName" _ L"newStyleName"}) CLASS_MEMBER_METHOD(ClearStyle, {L"begin" _ L"end"}) + CLASS_MEMBER_METHOD(ConvertToPlainText, { L"begin" _ L"end" }) CLASS_MEMBER_METHOD(SummarizeStyle, {L"begin" _ L"end"}) CLASS_MEMBER_METHOD(SummarizeStyleName, { L"begin" _ L"end" }) CLASS_MEMBER_METHOD(SetParagraphAlignment, {L"begin" _ L"end" _ L"alignments"}) diff --git a/Import/Vlpp.cpp b/Import/Vlpp.cpp index fe9f8106..e81f44ed 100644 --- a/Import/Vlpp.cpp +++ b/Import/Vlpp.cpp @@ -1621,6 +1621,7 @@ UnitTest case FailureMode::Copilot: PrintMessage(L"Failures cause immediate exit.", MessageKind::Info); break; + default:; } auto current = testHead; diff --git a/Tools/Reflection32.bin b/Tools/Reflection32.bin index 5a1202e3..ebe1ff88 100644 Binary files a/Tools/Reflection32.bin and b/Tools/Reflection32.bin differ diff --git a/Tools/Reflection64.bin b/Tools/Reflection64.bin index 4f994a1b..8de4725d 100644 Binary files a/Tools/Reflection64.bin and b/Tools/Reflection64.bin differ diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 index c4dddb0a..c85fa530 100644 Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 differ diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 index fe2fc985..93f15f8e 100644 Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 differ