/// ------------------------------------------------------------------------------------ /// <summary> /// Scrolls the selection into view, positioning it as requested /// </summary> /// <param name="sel">The selection, or <c>null</c> to use the current selection</param> /// <param name="scrollOption">The VwScrollSelOpts specification.</param> /// ------------------------------------------------------------------------------------ bool IVwRootSite.ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts scrollOption) { // Do nothing for printing return false; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Scrolls the selection into view, positioning it as requested /// </summary> /// <param name="sel">The selection, or <c>null</c> to use the current selection</param> /// <param name="scrollOption">The VwScrollSelOpts specification.</param> /// ------------------------------------------------------------------------------------ bool IVwRootSite.ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts scrollOption) { // Do nothing for printing return(false); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Scroll the given or current selection into view. /// </summary> /// <param name="sel"></param> /// <param name="ssoFlag"></param> /// ------------------------------------------------------------------------------------ public bool ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts ssoFlag) { CheckDisposed(); IVwSelection vwsel = sel; if (vwsel == null) { if (FocusedRootBox != null) vwsel = FocusedRootBox.Selection; } if (vwsel == null) return false; // nothing to do, no selection IVwGraphics vg = PrinterGraphics; try { // Loop until we have figured a scroll offset and confirmed the pages that // are visible there are laid out ready to draw. for (; ; ) { // We pass this as source AND destination rectangle to get the selection // location relative to the whole document in printer coordinates. // Rect rcSrc = new Rect(0, 0, (int)DpiXPrinter, (int)DpiYPrinter); bool fEndBeforeAnchor; Rectangle rcSelPrinter; int clientWidthPrinter = ConvertScreenDistanceToPrinterX(ClientRectangle.Width, DpiXScreen); rcSelPrinter = GetSelectionRectangle(vwsel, vg, out fEndBeforeAnchor); // At this point, rcIdeal is a rectangle that we want on the screen, in // printer coordinates relative to the top of the document. IVwLayoutStream stream = (IVwLayoutStream)(vwsel.RootBox); int iDivTop; // index of division containing top of ideal rectangle int dysPageTopScreen; // top of page to top of rectangle in screen coords. bool layedOutPage; Page pageTop = PageFromPrinterY(rcSelPrinter.Left, rcSelPrinter.Top, false, stream, out dysPageTopScreen, out iDivTop, out layedOutPage); if (layedOutPage) continue; int iDivBottom; // index of division containing bottom of ideal rectangle int dysPageBottomScreen; // top of page to bottom of rectangle in screen coords. Page pageBottom = PageFromPrinterY(rcSelPrinter.Right, rcSelPrinter.Bottom, true, stream, out dysPageBottomScreen, out iDivBottom, out layedOutPage); if (layedOutPage) continue; // Enhance: this happens when moving within a secondary stream when the page that // will eventually contain the footnote (or whatever) has not been laid out. // This generic code has no idea which page will eventually contain the anchor for // this object. // Options: // 1. Leave it like this...fail to make the selection visible. (Maybe dialog?) // 2. Create real pages sequentially through the document until PageFromPrinterY // succeeds. (This might take a while!). // 3. Make use of a virtual function, the default version of which fails, // which can be asked, given a selection in a secondary stream, for a selection at // the corresponding anchor. (This might be useful for other purposes...could be a // method of the configurer.) Then we lay out the page that contains the anchor, // after which we should be able to retry PageFromPrinterY successfully. if (pageTop == null || pageBottom == null) return false; // If those aren't properly laid-out pages, make them so and try again. // We repeat all the logic, because making them real may have expanded lazy // boxes and invalidated all the positions we worked out. // The process must terminate, because eventually (in a worst case) all pages are // laid out, all lazy boxes expanded. In practice it should terminate much sooner. if (EnsureRealBoxAt(pageTop) || EnsureRealBoxAt(pageBottom)) continue; Page oldPageBeingLaidOut = m_pageBeingLaidOut; try { m_pageBeingLaidOut = pageTop; if (pageTop.LayOutIfNeeded()) continue; m_pageBeingLaidOut = pageBottom; if (pageBottom.LayOutIfNeeded()) continue; } finally { // We need to restore the page that was being laid out if we got here // during a layout in another place like PrepareToDrawPages() m_pageBeingLaidOut = oldPageBeingLaidOut; } int indexOfTopPage = IndexOfPage(pageTop); int indexOfBottomPage = indexOfTopPage; if (pageTop != pageBottom) indexOfBottomPage = IndexOfPage(pageBottom); int ysTopOfTopPageScreen = indexOfTopPage * PageHeightPlusGapInScreenPixels; int ysTopOfBottomPageScreen = indexOfBottomPage * PageHeightPlusGapInScreenPixels; int ysTopOfIdealScreen = dysPageTopScreen + ysTopOfTopPageScreen; int ysBottomOfIdealScreen = dysPageBottomScreen + ysTopOfBottomPageScreen; int scrollPosScreen = -AutoScrollPosition.Y; int clientHeightScreen = ClientRectangle.Height; // The amount we need to scroll by. This gets subtracted from the distance // we are scrolled (autoscrollposition.Y = -autoscrollposition.Y - // dysScrollPos), so a positive value causes the document to move up in the // window (thumb moves down). int dysScrollPosScreen = 0; // distance we need to scroll (positive = down) // The screen height of the rectangle we want to be visible. int dysIdealHeightScreen = ysBottomOfIdealScreen - ysTopOfIdealScreen; // The amount of space to spare...what we have to play with as we // decide where on the screen to try to place the rectangle we want to see. int dysSlackScreen = clientHeightScreen - dysIdealHeightScreen; // Reduce the height of the rectangle we want to make visible,if necessary, so // it fits on the client window. Reduce it at the 'anchor' not the 'end'. if (dysSlackScreen < 0) { if (!fEndBeforeAnchor) { ysTopOfIdealScreen -= dysSlackScreen; } else ysBottomOfIdealScreen += dysSlackScreen; dysIdealHeightScreen = clientHeightScreen; dysSlackScreen = 0; } if (rcSelPrinter.Width > clientWidthPrinter) { int delta = rcSelPrinter.Width - clientWidthPrinter; rcSelPrinter.Width = rcSelPrinter.Width - delta; } if (scrollPosScreen + clientHeightScreen < ysBottomOfIdealScreen) { // need to move doc up in window: dysScrollPos is negative dysScrollPosScreen = scrollPosScreen + clientHeightScreen - ysBottomOfIdealScreen; } else if (scrollPosScreen > ysTopOfIdealScreen) { // need to move doc down in window: dysScrollPos is positive. dysScrollPosScreen = scrollPosScreen - ysTopOfIdealScreen; } if (dysScrollPosScreen == 0) { // No need to move!! Unless...maybe we moved a long way, and redrawing // is going to expand a lazy box above our selection on the screen, and // it will grow so much we can't see the selection after all... // This ensures that everything in the client rectangle is real boxes. PrepareToDrawPages(0, clientHeightScreen); if (!vwsel.IsValid) { // At least one case where it might not be is typing in a footnote using smushing. // If the height of the footnote paragraph changes it gets regenerated. A new substitute // selection is created, but the old actual selection object isn't valid. // Of course, it's POSSIBLE that the selection we're trying to scroll isn't the // focussed root box's one, but that's the best guess I can see to make. It's right // for the only case so far where this has happened. vwsel = FocusedRootBox.Selection; } Rect rcPrimary2 = GetSelectionRectangle(vwsel, vg, out fEndBeforeAnchor); if (rcPrimary2.top != rcSelPrinter.Top) continue; // PrepareToDrawPages expanded something, try again. return true; } if (dysScrollPosScreen > 0) { // doc moving down. dysScrollPos as currently computed will put the rectangle // we want to see at the very top of the screen. That is good both for // case default (it's the smallest movement that works) and for a request // to put it at the top. Since it's at the top, no previous page can be // visible above it, so we will just use this value. // It we wanted to, say, center it, we would add half of dysSlack, then // make sure no previous page is showing by taking the min of that and // the distance to move the top of page to top of screen. } else { // doc moving up. (-dysScrollPos) is the distance to align the // bottom of the ideal rectangle with the bottom of the screen. // That is our default. If aligning to the top, we want to move more. if (ssoFlag == VwScrollSelOpts.kssoNearTop) { // To align the tops instead, make dysScrollPos more negative // by the difference between the rectangle heights. dysScrollPosScreen -= dysSlackScreen; } // Now we need to check that no previous page is visible. We avoid showing // a previous page partly because it tends to put a lot of white space // on the screen that may not be helpful to the user, but mainly because // it is possible that the previous page has not been laid out, and // laying it out will expand lazy boxes and mess up our prediction of // where the ideal rectangle will appear. We could all PrepareToDraw to // check whether this happens and then 'continue' to try again if // necessary, but we suspect it would make things jerky. int ysTopOfTopPageScrn = ysTopOfTopPageScreen + AutoScrollPosition.Y; if (ysTopOfTopPageScrn + dysScrollPosScreen > 0) { // Need to scroll more so that no previous page shows. // Scroll to put top of page exactly at top of screen. dysScrollPosScreen = -ysTopOfTopPageScrn; } } // OK, moving by dysScrollPos should make the selection visible // without expanding anything lazy above it. Do it and end the loop! AutoScrollPosition = new Point(-AutoScrollPosition.X, -AutoScrollPosition.Y - dysScrollPosScreen); return true; } } finally { ReleaseGraphics(vg); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// This is the actual workhorse for all the above methods that allows a selection to /// be created. /// </summary> /// <param name="iBook">The 0-based index of the Scripture book in which to put the /// insertion point</param> /// <param name="iSection">The 0-based index of the Scripture section in which to put the /// insertion point</param> /// <param name="tag">Indicates whether selection should be made in the section /// Heading or Content or in the book title</param> /// <param name="iPara">The 0-based index of the paragraph in which to put the insertion /// point</param> /// <param name="startCharacter">The 0-based index of the character at which the /// selection begins (or before which the insertion point is to be placed if /// startCharacter == endCharacter)</param> /// <param name="endCharacter">The character location to end the selection</param> /// <param name="fInstall"></param> /// <param name="fMakeVisible"></param> /// <param name="fAssocPrev">If an insertion point, does it have the properties of the /// previous character?</param> /// <param name="scrollOption">Where to scroll the selection</param> /// <returns>The selection helper</returns> /// ------------------------------------------------------------------------------------ public SelectionHelper SelectRangeOfChars(int iBook, int iSection, int tag, int iPara, int startCharacter, int endCharacter, bool fInstall, bool fMakeVisible, bool fAssocPrev, VwScrollSelOpts scrollOption) { Debug.Assert(ContentType != StVc.ContentTypes.kctSegmentBT, "isegment arg required for segment BT SelectRangeOfChars"); return SelectRangeOfChars(iBook, iSection, tag, iPara, 0, startCharacter, endCharacter, fInstall, fMakeVisible, fAssocPrev, scrollOption); }
/// ------------------------------------------------------------------------------------ /// <summary> /// This is the actual workhorse for all the above methods that allows a selection to /// be created. /// </summary> /// <param name="iBook">The 0-based index of the Scripture book in which to put the /// selection</param> /// <param name="iSection">The 0-based index of the Scripture section in which to put the /// selection</param> /// <param name="tag">Indicates whether selection should be made in the section /// Heading or Content or in the book title</param> /// <param name="isegment">If ContentType == segmentBT, the index of the segment /// in which to place the selection; otherwise ignored.</param> /// <param name="iPara">The 0-based index of the paragraph in which to put the insertion /// point</param> /// <param name="startCharacter">The 0-based index of the character at which the /// selection begins (or before which the insertion point is to be placed if /// startCharacter == endCharacter)</param> /// <param name="endCharacter">The character location to end the selection</param> /// <param name="fInstall"></param> /// <param name="fMakeVisible"></param> /// <param name="fAssocPrev">If an insertion point, does it have the properties of the /// previous character?</param> /// <param name="scrollOption">Where to scroll the selection</param> /// <returns>The selection helper</returns> /// ------------------------------------------------------------------------------------ public SelectionHelper SelectRangeOfChars(int iBook, int iSection, int tag, int iPara, int isegment, int startCharacter, int endCharacter, bool fInstall, bool fMakeVisible, bool fAssocPrev, VwScrollSelOpts scrollOption) { CheckDisposed(); if (Callbacks == null || Callbacks.EditedRootBox == null) return null; // can't make a selection Debug.Assert(tag == (int)ScrSection.ScrSectionTags.kflidHeading || tag == (int)ScrSection.ScrSectionTags.kflidContent || tag == (int)ScrBook.ScrBookTags.kflidTitle); SelectionHelper selHelper = new SelectionHelper(); selHelper.NumberOfLevels = ((ITeView)Control).LocationTracker.GetLevelCount(tag); int levelForPara = LocationTrackerImpl.GetLevelIndexForTag((int)StText.StTextTags.kflidParagraphs, m_contentType); selHelper.LevelInfo[levelForPara].ihvo = iPara; selHelper.LevelInfo[levelForPara + 1].tag = tag; ((ITeView)Control).LocationTracker.SetBookAndSection(selHelper, SelectionHelper.SelLimitType.Anchor, iBook, tag == (int)ScrBook.ScrBookTags.kflidTitle ? -1 : iSection); if (ContentType == StVc.ContentTypes.kctSimpleBT) { int levelForBT = LocationTrackerImpl.GetLevelIndexForTag((int)StTxtPara.StTxtParaTags.kflidTranslations, m_contentType); selHelper.LevelInfo[levelForBT].tag = -1; selHelper.LevelInfo[levelForBT].ihvo = 0; selHelper.LevelInfo[levelForPara].tag = (int)StText.StTextTags.kflidParagraphs; selHelper.SetTextPropId(SelectionHelper.SelLimitType.Anchor, (int)CmTranslation.CmTranslationTags.kflidTranslation); selHelper.SetTextPropId(SelectionHelper.SelLimitType.End, (int)CmTranslation.CmTranslationTags.kflidTranslation); } else if (ContentType == StVc.ContentTypes.kctSegmentBT) { // In all segment BT views, under the paragraph there is a segment, and under that // an object which is the free translation itself. selHelper.LevelInfo[2].tag = (int) StText.StTextTags.kflidParagraphs; // JohnT: why don't we need this for non-BT?? selHelper.LevelInfo[1].ihvo = isegment; selHelper.LevelInfo[1].tag = StTxtPara.SegmentsFlid(Cache); selHelper.LevelInfo[0].ihvo = 0; // not a sequence. selHelper.LevelInfo[0].tag = StTxtPara.SegmentFreeTranslationFlid(Cache); selHelper.SetTextPropId(SelectionHelper.SelLimitType.Anchor, (int)CmAnnotation.CmAnnotationTags.kflidComment); selHelper.SetTextPropId(SelectionHelper.SelLimitType.End, (int)CmAnnotation.CmAnnotationTags.kflidComment); } // else selHelper.LevelInfo[0].tag is set automatically by SelectionHelper class selHelper.AssocPrev = fAssocPrev; selHelper.SetLevelInfo(SelectionHelper.SelLimitType.End, selHelper.LevelInfo); // Prepare to move the IP to the specified character in the paragraph. selHelper.IchAnchor = startCharacter; selHelper.IchEnd = endCharacter; // Now that all the preparation to set the IP is done, set it. IVwSelection vwsel = selHelper.SetSelection(Callbacks.EditedRootBox.Site, fInstall, fMakeVisible, scrollOption); // If the selection fails, then try selecting the user prompt. if (vwsel == null) { selHelper.SetTextPropId(SelectionHelper.SelLimitType.Anchor, SimpleRootSite.kTagUserPrompt); selHelper.SetTextPropId(SelectionHelper.SelLimitType.End, SimpleRootSite.kTagUserPrompt); vwsel = selHelper.SetSelection(Callbacks.EditedRootBox.Site, fInstall, fMakeVisible, scrollOption); } if (vwsel == null) { Debug.WriteLine("SetSelection failed in TeEditinHelper.SelectRangeOfChars()"); } return selHelper; }
/// <summary> /// Override to prevent scrolling in DropDownList mode. /// </summary> /// <param name="sel"></param> /// <param name="scrollOption"></param> /// <returns></returns> public override bool ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts scrollOption) { if (m_comboBox != null && m_comboBox.DropDownStyle == ComboBoxStyle.DropDownList) { // no meaningful selections are possible, no reason ever to scroll it. // That's true as long as we always left-align. // If we use right-alignment with a huge width to prevent wrapping, no scrolling means the text is invisible, // somewhere way off to the right. We'd then need something like this, but better, because this doesn't // work when the combo is resized, as when you change the size of a column and the filter bar combo resizes. // See also what I did in OnSizeChanged. if (Rtl) { // But, if it is RTL, we need to scroll, typically only once, to make it as visible as possible. // Right alignment otherwise puts the string way off to the right. var initialSel = m_rootb.MakeSimpleSel(true, false, false, false); base.ScrollSelectionIntoView(initialSel, VwScrollSelOpts.kssoDefault); } return false; } return base.ScrollSelectionIntoView(sel, scrollOption); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Set the insertion point in this draftview to the specified location. /// </summary> /// <param name="tag">Indicates whether selection should be made in the title, section /// Heading or section Content</param> /// <param name="book">The 0-based index of the Scripture book in which to put the /// insertion point</param> /// <param name="section">The 0-based index of the Scripture section in which to put the /// insertion point</param> /// <param name="para">The 0-based index of the paragraph in which to put the insertion /// point</param> /// <param name="character">The 0-based index of the character before which the /// insertion point is to be placed</param> /// <param name="fAssocPrev">True if the properties of the text entered at the new /// insertion point should be associated with the properties of the text before the new /// insertion point. False if text entered at the new insertion point should be /// associated with the text following the new insertion point.</param> /// <param name="scrollOption">Where to scroll the selection</param> /// <returns>The selection helper object used to make move the IP.</returns> /// ------------------------------------------------------------------------------------ public SelectionHelper SetInsertionPoint(int tag, int book, int section, int para, int character, bool fAssocPrev, VwScrollSelOpts scrollOption) { CheckDisposed(); return SelectRangeOfChars(book, section, tag, para, character, character, true, true, fAssocPrev, scrollOption); }
/// ----------------------------------------------------------------------------------- /// <summary> /// Sets the selection by calling <c>IVwRootBox.MakeRangeSelection</c>. /// </summary> /// <param name="rootSite">The root site</param> /// <param name="fInstall">Makes the selection the current selection</param> /// <param name="fMakeVisible">Determines whether or not to make the selection visible. /// </param> /// <param name="scrollOption">Where to scroll the selection</param> /// <returns>The selection, null if it could not return a valid one.</returns> /// ----------------------------------------------------------------------------------- public virtual IVwSelection SetSelection(IVwRootSite rootSite, bool fInstall, bool fMakeVisible, VwScrollSelOpts scrollOption) { if (rootSite == null || rootSite.RootBox == null) return null; m_rootSite = rootSite; try { IVwSelection sel = MakeRangeSelection(rootSite.RootBox, fInstall); if (sel == null) return null; if (fInstall && !sel.IsValid) { // We rarely expect to have an invalid selection after we install a new selection, // but it's possible for selection side-effects to have invalidated it // (e.g. highlighting a row in a browse view cf. LT-5033.) sel = MakeRangeSelection(rootSite, fInstall); } if (sel.IsValid) m_vwSel = sel; else m_vwSel = null; if (fMakeVisible && m_vwSel != null) rootSite.ScrollSelectionIntoView(m_vwSel, scrollOption); return m_vwSel; } catch (COMException) { return null; } catch(Exception) { Debug.Assert(false, "Exceptional condition encountered while making selection."); // ReSharper disable HeuristicUnreachableCode return null; //Um, asserts don't happen in release you overzealous Heuristic. // ReSharper restore HeuristicUnreachableCode } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Scrolls the selection into view, positioning it as requested /// </summary> /// <param name="sel">The selection, or <c>null</c> to use the current selection</param> /// <param name="scrollOption">The VwScrollSelOpts specification.</param> /// ------------------------------------------------------------------------------------ public override void ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts scrollOption) { m_fScrollSelectionIntoViewWasCalled = true; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Scrolls the selection into view, positioning it as requested /// </summary> /// <param name="sel">The selection, or <c>null</c> to use the current selection</param> /// <param name="scrollOption">The VwScrollSelOpts specification.</param> /// <returns>True if the selection was moved into view, false if this function did /// nothing</returns> /// ------------------------------------------------------------------------------------ public virtual bool ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts scrollOption) { CheckDisposed(); switch (scrollOption) { case VwScrollSelOpts.kssoDefault: return MakeSelectionVisible(sel, true); case VwScrollSelOpts.kssoNearTop: return ScrollSelectionToLocation(sel, LineHeight); case VwScrollSelOpts.kssoTop: return ScrollSelectionToLocation(sel, 1); case VwScrollSelOpts.kssoBoth: return MakeSelectionVisible(sel, true, true, true); default: throw new ArgumentException("Unsupported VwScrollSelOpts"); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Scrolls the selection into view, positioning it as requested /// </summary> /// <param name="sel">The selection, or <c>null</c> to use the current selection</param> /// <param name="scrollOption">The VwScrollSelOpts specification.</param> /// ------------------------------------------------------------------------------------ void IVwRootSite.ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts scrollOption) { // Do nothing for printing }
// We absolutely don't ever want the Sandbox to scroll. public override bool ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts scrollOption) { CheckDisposed(); return false; }
/// ----------------------------------------------------------------------------------- /// <summary> /// Sets the selection by calling <c>IVwRootBox.MakeRangeSelection</c>. /// </summary> /// <param name="rootSite">The root site</param> /// <param name="fInstall">Makes the selection the current selection</param> /// <param name="fMakeVisible">Determines whether or not to make the selection visible. /// </param> /// <param name="scrollOption">Where to scroll the selection</param> /// <returns>The selection, null if it could not return a valid one.</returns> /// ----------------------------------------------------------------------------------- public virtual IVwSelection SetSelection(IVwRootSite rootSite, bool fInstall, bool fMakeVisible, VwScrollSelOpts scrollOption) { if (rootSite == null || rootSite.RootBox == null) return null; try { IVwSelection sel = MakeRangeSelection(rootSite.RootBox, fInstall); if (fInstall && !sel.IsValid) { // We rarely expect to have an invalid selection after we install a new selection, // but it's possible for selection side-effects to have invalidated it // (e.g. highlighting a row in a browse view cf. LT-5033.) sel = MakeRangeSelection(rootSite, fInstall); } if (sel.IsValid) m_vwSel = sel; else m_vwSel = null; if (fMakeVisible && m_vwSel != null) rootSite.ScrollSelectionIntoView(m_vwSel, scrollOption); return m_vwSel; } catch { return null; } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Scrolls the selection into view, positioning it as requested /// </summary> /// <param name="sel">The selection, or <c>null</c> to use the current selection</param> /// <param name="scrollOption">The VwScrollSelOpts specification.</param> /// ------------------------------------------------------------------------------------ public override bool ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts scrollOption) { m_fScrollSelectionIntoViewWasCalled = true; return true; }
// We absolutely don't ever want the Sandbox to scroll. public override void ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts scrollOption) { CheckDisposed(); }