Beispiel #1
0
		public void Select()
		{
			var styles = new AssembledStyles();
			var root = new RootBoxFdo(styles);
			var mock1 = new MockData1(23, 23);
			mock1.SimpleThree = "new old contents";
			var engine = new FakeRenderEngine() { Ws = 23, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(23, engine);
			root.Builder.Show(Display.Of(() => mock1.SimpleThree, 23));
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;

			int x = FakeRenderEngine.SimulatedWidth("new ") + 2;
			var location = new Point(x, 8);
			EventArgs e = new EventArgs();
			MouseEventArgs m = new MouseEventArgs(MouseButtons.Left, 1, location.X, location.Y, 0);

			root.OnMouseDown(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnDoubleClick(e);
			Assert.That(!root.Selection.IsInsertionPoint, "Should be ranged selection");
			Assert.That((root.Selection as RangeSelection).SelectedText(), Is.EqualTo("old "));

			mock1.SimpleThree = "new old:contents";
			x = FakeRenderEngine.SimulatedWidth("new o") + 2;
			location = new Point(x, 8);
			m = new MouseEventArgs(MouseButtons.Left, 1, location.X, location.Y, 0);
			root.OnMouseDown(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnMouseClick(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnDoubleClick(e);
			Assert.That(!root.Selection.IsInsertionPoint, "Should be ranged selection");
			Assert.That((root.Selection as RangeSelection).SelectedText(), Is.EqualTo("old"));

			mock1.SimpleThree = "new(old contents";
			x = FakeRenderEngine.SimulatedWidth("new ol") + 2;
			location = new Point(x, 8);
			m = new MouseEventArgs(MouseButtons.Left, 1, location.X, location.Y, 0);
			root.OnMouseDown(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnMouseClick(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnDoubleClick(e);
			Assert.That(!root.Selection.IsInsertionPoint, "Should be ranged selection");
			Assert.That((root.Selection as RangeSelection).SelectedText(), Is.EqualTo("old "));

			mock1.SimpleThree = "newo1dcontents";
			x = FakeRenderEngine.SimulatedWidth("new o1d") + 2;
			location = new Point(x, 8);
			m = new MouseEventArgs(MouseButtons.Left, 1, location.X, location.Y, 0);
			root.OnMouseDown(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnMouseClick(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnDoubleClick(e);
			Assert.That(!root.Selection.IsInsertionPoint, "Should be ranged selection");
			Assert.That((root.Selection as RangeSelection).SelectedText(), Is.EqualTo("newo1dcontents"));
		}
Beispiel #2
0
		public void DragStartsOnMoveInSelection()
		{
			string contents = "This is the day.";
			var engine = new FakeRenderEngine() {Ws = 34, SegmentHeight = 13};
			var factory = new FakeRendererFactory();
			factory.SetRenderer(34, engine);
			var styles = new AssembledStyles().WithWs(34);
			var clientRuns = new List<IClientRun>();
			var run = new StringClientRun(contents, styles);
			clientRuns.Add(run);
			var source = new TextSource(clientRuns, null);
			var para = new ParaBox(styles, source);
			var extraBox = new BlockBox(styles, Color.Red, 50, 72000); // tall, narrow spacer at top
			var root = new RootBoxFdo(styles);
			root.AddBox(extraBox);
			root.AddBox(para);
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue/2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			Assert.That(root.Height, Is.EqualTo(96 + 13));
			Assert.That(root.Width, Is.EqualTo(FakeRenderEngine.SimulatedWidth(contents)));

			var ip1 = run.SelectAt(para, 5, false);
			var ip2 = run.SelectAt(para, 7, true);
			var range = new RangeSelection(ip1, ip2);
			range.Install();
			PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
			var sbox = para.FirstBox as StringBox;
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;
			int indent = FakeRenderEngine.SimulatedWidth("This ");
			root.OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, indent + 5, 100, 0), Keys.None, m_gm.VwGraphics, ptrans);
			root.OnMouseMove(new MouseEventArgs(MouseButtons.Left, 1, indent + 5, 100, 0), Keys.None, m_gm.VwGraphics, ptrans);
			Assert.That(GetStringDropData(site), Is.EqualTo("is"));
			Assert.That(site.LastDoDragDropArgs.AllowedEffects, Is.EqualTo(DragDropEffects.Copy),
				"editing not possible in this paragraph, we can only copy");
			Assert.That(root.Selection, Is.EqualTo(range), "selection should not be changed by drag drop");
			site.LastDoDragDropArgs = null;
			root.OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, 3, 100, 0), Keys.None, m_gm.VwGraphics, ptrans);
			Assert.That(site.LastDoDragDropArgs, Is.Null, "click outside selection should not initiate drag");

			// Tack on an extra check that a read-only view does not handle drop.
			var dataObj = new DataObject(DataFormats.StringFormat, "new ");
			var dragArgs = new DragEventArgs(dataObj, (int)DragDropKeyStates.ControlKey, 10, 8,
				DragDropEffects.Copy | DragDropEffects.Move,
				DragDropEffects.None);
			root.OnDragEnter(dragArgs, new Point(14, 8), m_gm.VwGraphics, ptrans);
			Assert.That(dragArgs.Effect, Is.EqualTo(DragDropEffects.None));
			Assert.That(root.DragState, Is.EqualTo(WindowDragState.DraggingHere));
		}
Beispiel #3
0
		public void BasicDrop()
		{
			var styles = new AssembledStyles();
			var root = new RootBoxFdo(styles);
			var mock1 = new MockData1(23, 23);
			mock1.SimpleThree = "old contents";
			var engine = new FakeRenderEngine() { Ws = 23, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(23, engine);
			root.Builder.Show(Display.Of(() => mock1.SimpleThree, 23));
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;

			var dataObj = new DataObject(DataFormats.StringFormat, "new ");
			int x = FakeRenderEngine.SimulatedWidth("old ") + 2;
			var location = new Point(x, 8);

			// A drag to where we can drop, allowing both copy and move, no keys held
			var dragArgs = new DragEventArgs(dataObj, (int) DragDropKeyStates.None, 200,300,
				DragDropEffects.Copy | DragDropEffects.Move,
				DragDropEffects.None);
			root.OnDragEnter(dragArgs, location, m_gm.VwGraphics, ptrans);
			Assert.That(dragArgs.Effect, Is.EqualTo(DragDropEffects.Move));
			Assert.That(root.DragState, Is.EqualTo(WindowDragState.DraggingHere));
			root.OnDragLeave();
			Assert.That(root.DragState, Is.EqualTo(WindowDragState.None));

			// Though other factors would favor move, only copy is allowed here.
			dragArgs = new DragEventArgs(dataObj, (int)DragDropKeyStates.None, 200,300,
				DragDropEffects.Copy,
				DragDropEffects.None);
			root.OnDragEnter(dragArgs, location, m_gm.VwGraphics, ptrans);
			Assert.That(dragArgs.Effect, Is.EqualTo(DragDropEffects.Copy));

			// Though otherwise we could copy, there is no text data in the data object.
			dragArgs = new DragEventArgs(new DataObject(), (int)DragDropKeyStates.None, 200,300,
				DragDropEffects.Copy | DragDropEffects.Move,
				DragDropEffects.None);
			root.OnDragEnter(dragArgs, location, m_gm.VwGraphics, ptrans);
			Assert.That(dragArgs.Effect, Is.EqualTo(DragDropEffects.None));

			dragArgs = new DragEventArgs(dataObj, (int)DragDropKeyStates.ControlKey, 200,300,
				DragDropEffects.Copy | DragDropEffects.Move,
				DragDropEffects.None);
			root.OnDragEnter(dragArgs, location, m_gm.VwGraphics, ptrans);
			Assert.That(dragArgs.Effect, Is.EqualTo(DragDropEffects.Copy));

			root.OnDragDrop(dragArgs, location, m_gm.VwGraphics, ptrans);
			Assert.That(mock1.SimpleThree, Is.EqualTo("old new contents"));
		}
Beispiel #4
0
		public void DragCopyRtf()
		{
			var stylesheet = new MockStylesheet();
			var styleFirst = stylesheet.AddStyle("first", false);
			var styleSecond = stylesheet.AddStyle("second", false);
			var propsTrue = new MockStyleProp<bool>() {Value = true, ValueIsSet = true};
			var charInfo = new MockCharStyleInfo();
			styleFirst.DefaultCharacterStyleInfo = charInfo;
			charInfo.Bold = propsTrue;
			// Todo: make styleSecond have pretty much everything else.
			var charInfo2 = new MockCharStyleInfo();
			styleSecond.DefaultCharacterStyleInfo = charInfo2;
			charInfo2.FontColor = MakeColorProp(Color.Red);
			charInfo2.BackColor = MakeColorProp(Color.Yellow);
			charInfo2.UnderlineColor = MakeColorProp(Color.Green);
			charInfo2.Italic = propsTrue;
			charInfo2.FontName = new MockStyleProp<string>() {Value = "Arial", ValueIsSet = true};

			var styles = new AssembledStyles(stylesheet);
			var root = new RootBoxFdo(styles);
			var mock1 = new MockData1(23, 23);
			mock1.SimpleThree = "This is";
			var mock2 = new MockData1(23, 23);
			mock2.SimpleThree = " the day";
			var mock3 = new MockData1(23, 23);
			mock3.SimpleThree = " that the";
			var engine = new FakeRenderEngine() { Ws = 23, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			var wsf = new MockWsf();
			engine.WritingSystemFactory = wsf;
			var wsEngine = wsf.MakeMockEngine(23, "en", engine);
			factory.SetRenderer(23, engine);
			root.Builder.Show(
				Paragraph.Containing(
					Display.Of(() => mock1.SimpleThree, 23).Style("first"),
					Display.Of(() => mock2.SimpleThree, 23).Style("second"),
					Display.Of(() => mock3.SimpleThree, 23).Style("first")
					));
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;

			SelectionBuilder.In(root).Offset("This ".Length).To.Offset("This is the day that".Length).Install();
			int indent = FakeRenderEngine.SimulatedWidth("This ");
			root.OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, indent + 5, 4, 0), Keys.None, m_gm.VwGraphics, ptrans);
			root.OnMouseMove(new MouseEventArgs(MouseButtons.Left, 1, indent + 5, 4, 0), Keys.None, m_gm.VwGraphics, ptrans);
			Assert.That(GetStringDropData(site), Is.EqualTo("is the day that"));
			// The order of the font and colors in the color table is arbitrary. This happens to be what the code does now. For some reason
			// Color.Green has green only 128.
			// The order of items in the definition of a style is arbitrary.
			// We're not doing anything yet for background color. \highlightN can specify background color for a character run,
			// but it can't be part of a style definition.
			Assert.That(GetRtfDropData(site), Is.EqualTo(
				RangeSelection.RtfPrefix
				+ @"{\fonttbl{\f0 MockFont;}{\f1 Arial;}}"
				+ @"{\colortbl ;\red0\green0\blue0;\red255\green255\blue255;\red255\green0\blue0;\red255\green255\blue0;\red0\green128\blue0;}"
				+ @"{\stylesheet{\*\cs1\b\additive first;\*\cs2\i\f1\cf3\ulc5\additive second;}}"
				+ RangeSelection.RtfDataPrefix
				+ @"{\*\cs1\b is}{\*\cs2\i\f1\cf3\ulc5\highlight4  the day}{\*\cs1\b  that\par}"
				+ @"}"));

			// Todo: handle styles that depend on WS
			// Todo: handle more than two runs
			// Todo: handle runs where actual formatting differs from style-specified formatting
			// Todo: handle multiple paragraphs
			// Todo: handle paragraph styles
		}
Beispiel #5
0
		public void BasicDragMove()
		{
			var styles = new AssembledStyles();
			var root = new RootBoxFdo(styles);
			var mock1 = new MockData1(23, 23);
			mock1.SimpleThree = "This is the day";
			var engine = new FakeRenderEngine() { Ws = 23, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(23, engine);
			root.Builder.Show(Display.Of(() => mock1.SimpleThree, 23));
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;

			SelectionBuilder.In(root).Offset("This ".Length).To.Offset("This is ".Length).Install();

			var dataObj = new DataObject(DataFormats.StringFormat, "is ");
			int x = FakeRenderEngine.SimulatedWidth("This is the ") + 2;
			var location = new Point(x, 8);

			// A drag to where we can drop, allowing both copy and move, no keys held
			var dragArgs = new DragEventArgs(dataObj, (int)DragDropKeyStates.None, 200, 300,
				DragDropEffects.Copy | DragDropEffects.Move,
				DragDropEffects.None);
			root.OnDragEnter(dragArgs, location, m_gm.VwGraphics, ptrans);
			Assert.That(dragArgs.Effect, Is.EqualTo(DragDropEffects.Move));
			Assert.That(root.DragState, Is.EqualTo(WindowDragState.DraggingHere));

			var qcdArgs = new QueryContinueDragEventArgs((int) DragDropKeyStates.None, false, DragAction.Drop);
			root.OnQueryContinueDrag(qcdArgs);
			Assert.That(root.DragState, Is.EqualTo(WindowDragState.InternalMove));
			root.OnDragLeave();
			Assert.That(root.DragState, Is.EqualTo(WindowDragState.InternalMove), "DragLeave should not clear InternalMove");

			root.OnDragDrop(dragArgs, location, m_gm.VwGraphics, ptrans);
			Assert.That(mock1.SimpleThree, Is.EqualTo("This the is day"));
			Assert.That(root.DragState, Is.EqualTo(WindowDragState.None));

			// Now let's drag the 'is' out to another window.
			SelectionBuilder.In(root).Offset("This the ".Length).To.Offset("This the is ".Length).Install();
			qcdArgs = new QueryContinueDragEventArgs((int)DragDropKeyStates.None, false, DragAction.Drop);
			root.OnQueryContinueDrag(qcdArgs);
			Assert.That(root.DragState, Is.EqualTo(WindowDragState.None),
				"We should only set InternalMove if this window is the destination");
			Assert.That(mock1.SimpleThree, Is.EqualTo("This the day"));

			// Check that we can't drag inside our own selection.
			SelectionBuilder.In(root).Offset("This ".Length).To.Offset("This the".Length).Install();
			x = FakeRenderEngine.SimulatedWidth("This t") + 2;
			location = new Point(x, 8);
			dragArgs = new DragEventArgs(dataObj, (int)DragDropKeyStates.None, 200, 300,
							DragDropEffects.Copy | DragDropEffects.Move,
							DragDropEffects.None);
			root.DragState = WindowDragState.InternalMove;
			root.OnDragDrop(dragArgs, location, m_gm.VwGraphics, ptrans);
			Assert.That(dragArgs.Effect, Is.EqualTo(DragDropEffects.None));
			Assert.That(mock1.SimpleThree, Is.EqualTo("This the day"));
		}
Beispiel #6
0
		private static IRendererFactory SetupFakeRenderer(int ws)
		{
			var fakeRenderer = new FakeRenderEngine();
			var fakeRendererFactory = new FakeRendererFactory();
			fakeRendererFactory.SetRenderer(ws, fakeRenderer);
			return fakeRendererFactory;
		}
Beispiel #7
0
		public void BidiLayout()
		{
			string content1 = "This is the ";
			string contentRtl = "day ";
			string content3 = "that ";

			// Two writing systems
			int wsLtr = 5;
			int wsRtl = 6;

			// Two corresponding renderers
			var factory = new FakeRendererFactory();
			var engineLtr = new FakeRenderEngine() { Ws = wsLtr, SegmentHeight = 13 };
			factory.SetRenderer(wsLtr, engineLtr);
			var engineRtl = new FakeRenderEngine() {Ws = wsRtl, SegmentHeight = 13 };
			engineRtl.RightToLeft = true;
			factory.SetRenderer(wsRtl, engineRtl);

			// Two corresponding styles (and a vanilla one)
			var styles = new AssembledStyles();
			var stylesLtr = new AssembledStyles().WithWs(wsLtr);
			var stylesRtl = new AssembledStyles().WithWs(wsRtl);

			var clientRuns = new List<IClientRun>();
			var run1 = new StringClientRun(content1, stylesLtr);
			clientRuns.Add(run1);
			var runRtl = new StringClientRun(contentRtl, stylesRtl);
			clientRuns.Add(runRtl);
			var run3 = new StringClientRun(content3, stylesLtr);
			clientRuns.Add(run3);

			var root = new RootBoxFdo(styles);

			var source = new TextSource(clientRuns, null);
			var para = new ParaBox(styles, source);
			root.AddBox(para);

			var stylesParaRtl = styles.WithRightToLeft(true);
			var sourceRtl = new TextSource(clientRuns, null);
			var paraRtl = new ParaBox(stylesParaRtl, sourceRtl);
			root.AddBox(paraRtl);

			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);

			// "day " being upstream should make two distinct boxes.
			// We should get something like
			// "This is the yad that ", where the space between "yad" and "that" is the one that
			// follows the 'y' in "day".
			var box1 = para.FirstBox as StringBox;
			var box2 = box1.Next as StringBox;
			var box3 = box2.Next as StringBox;
			var box4 = box3.Next as StringBox;
			Assert.That(box4, Is.Not.Null);
			Assert.That(box1.Segment.get_Lim(box1.IchMin) == content1.Length);
			Assert.That(box2.Segment.get_Lim(box2.IchMin) == contentRtl.Length - 1);
			Assert.That(box3.Segment.get_Lim(box3.IchMin) == 1);
			Assert.That(box4.Segment.get_Lim(box4.IchMin) == content3.Length);
			Assert.That(box1.Left, Is.LessThan(box2.Left));
			Assert.That(box2.Left, Is.LessThan(box3.Left));
			Assert.That(box3.Left, Is.LessThan(box4.Left));

			// In the second paragraph, the two LRT runs are upstream. We should get boxes
			// "This is the", " ", "day ", "that" and " " (but the final space will have zero width at end of line)
			// The effect should be something like
			// that yad This is the", where the space between "yad" and "This" is the one following "the",
			// and the one between "that" and "yad" is the one following "day", and the space following "that"
			// is invisible at the end of the line to the left of 'that'.
			var boxR1 = paraRtl.FirstBox as StringBox;
			var boxR2 = boxR1.Next as StringBox;
			var boxR3 = boxR2.Next as StringBox;
			var boxR4 = boxR3.Next as StringBox;
			var boxR5 = boxR4.Next as StringBox;
			Assert.That(boxR5, Is.Not.Null);
			Assert.That(boxR1.Segment.get_Lim(boxR1.IchMin) == content1.Length - 1);
			Assert.That(boxR2.Segment.get_Lim(boxR2.IchMin) == 1);
			Assert.That(boxR3.Segment.get_Lim(boxR3.IchMin) == contentRtl.Length);
			Assert.That(boxR4.Segment.get_Lim(boxR4.IchMin) == content3.Length - 1);
			Assert.That(boxR5.Segment.get_Lim(boxR5.IchMin) == 1);
		}
Beispiel #8
0
		public void MlsDelete()
		{
			var styles = new AssembledStyles();
			var root = new RootBoxFdo(styles.WithWs(23));
			var mock1 = new MockData1(23, 23);
			mock1.MlSimpleOne = new MultiAccessor(23, 23);
			mock1.MlSimpleOne.set_String(23, TsStrFactoryClass.Create().MakeString("This is it", 23));
			var engine = new FakeRenderEngine() { Ws = 23, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(23, engine);
			root.Builder.Show(Display.Of(() => mock1.MlSimpleOne, 23));
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;

			SelectionBuilder.In(root).Offset("This ".Length).To.Offset("This is ".Length).Install();
			var sel = root.Selection as RangeSelection;
			// This is currently the main test for SelectionBuilder.In(RootBox) and SelectionBuilder.To in TsStrings
			// This verifies that it makes roughly the right range selection.
			Assert.That(sel.Anchor.LogicalParaPosition, Is.EqualTo("This ".Length));
			Assert.That(sel.DragEnd.LogicalParaPosition, Is.EqualTo("This is ".Length));

			Assert.That(sel.CanDelete(), Is.True);
			root.OnDelete();
			ITsString i = mock1.MlSimpleOne.get_String(23);
			Assert.That(mock1.MlSimpleOne.get_String(23).Text, Is.EqualTo("This it"));
			var ip = root.Selection as InsertionPoint;
			Assert.That(ip.LogicalParaPosition, Is.EqualTo("This ".Length));
			// Enhance JohnT: if there is any reason to prefer associatePrevious to be true or false,
			// clamp that and make it so.
			// A fairly rudimentary check on invalidate, since we elsewhere check general string-edit ops.
			Assert.That(site.RectsInvalidatedInRoot, Is.Not.Empty);
		}
Beispiel #9
0
		public void Backtracking()
		{
			var styles = new AssembledStyles();
			var layoutInfo = MakeLayoutInfo();

			var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(34, engine);
			var engine2 = new FakeRenderEngine() { Ws = 35, SegmentHeight = 13 };
			factory.SetRenderer(35, engine2);

			// This first test doesn't strictly require backtracking; it is an example of a similar
			// case where all the second client run fits, nothing of the following one fits, but
			// there is a satisfactory break at the end of the last thing that fit.
			var root = new RootBoxFdo(styles);
			root.Builder.Show(Paragraph.Containing(Display.Of("this is ", 34),
				Display.Of("some mixed ", 35), Display.Of("text", 34)));
			int maxWidth = FakeRenderEngine.SimulatedWidth("this is some mixed t");
			var layoutArgs = MakeLayoutInfo(maxWidth, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			var para = (ParaBox)root.FirstBox;
			var secondChild = (StringBox) para.FirstBox.Next;
			Assert.That(secondChild.Text, Is.EqualTo("some mixed "));

			// True backtracking: the second client run fits entirely, but nothing of the following text.
			// We must go back and find the break in the middle of that second run.
			root = new RootBoxFdo(styles);
			root.Builder.Show(Paragraph.Containing(Display.Of("this is ", 34),
				Display.Of("some mixed", 35), Display.Of("text", 34)));
			maxWidth = FakeRenderEngine.SimulatedWidth("this is some mixedte");
			layoutArgs = MakeLayoutInfo(maxWidth, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			para = (ParaBox)root.FirstBox;
			secondChild = (StringBox)para.FirstBox.Next;
			Assert.That(secondChild.Text, Is.EqualTo("some "));

			// Now a harder problem: the second client run fits entirely, but nothing of the following text,
			// and there is no break point in the second client run at all.
			// We must go back and find the break in the first client run.
			root = new RootBoxFdo(styles);
			root.Builder.Show(Paragraph.Containing(Display.Of("this is", 34),
				Display.Of("some", 35), Display.Of("text", 34)));
			maxWidth = FakeRenderEngine.SimulatedWidth("this issomete");
			layoutArgs = MakeLayoutInfo(maxWidth, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			para = (ParaBox)root.FirstBox;
			var firstChild = (StringBox)para.FirstBox;
			Assert.That(firstChild.Text, Is.EqualTo("this "));
			secondChild = (StringBox)para.FirstBox.Next;
			Assert.That(secondChild.Text, Is.EqualTo("is"));
			var thirdChild = (StringBox)secondChild.Next;
			Assert.That(thirdChild.Text, Is.EqualTo("some"));
			var fourthChild = (StringBox)thirdChild.Next;
			Assert.That(fourthChild.Text, Is.EqualTo("text"));
			Assert.That(secondChild.Top > firstChild.Top);
			Assert.That(fourthChild.Top, Is.EqualTo(secondChild.Top));

			// This time the third client run fits entirely, but nothing of the following text,
			// and there is no break point in the second client run at all; but right
			// before that third client run there is a non-text box.
			// We must break following the non-text box.
			root = new RootBoxFdo(styles);
			root.Builder.Show(Paragraph.Containing(Display.Of("this is", 34), Display.Block(Color.Red, 6000, 2000),
				Display.Of("some", 35), Display.Of("text", 34)));
			maxWidth = FakeRenderEngine.SimulatedWidth("this issomete") + layoutArgs.MpToPixelsX(6000);
			layoutArgs = MakeLayoutInfo(maxWidth, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			para = (ParaBox)root.FirstBox;
			firstChild = (StringBox)para.FirstBox;
			Assert.That(firstChild.Text, Is.EqualTo("this is"));
			Assert.That(firstChild.Next, Is.InstanceOf(typeof(BlockBox)));
			thirdChild = (StringBox)firstChild.Next.Next;
			Assert.That(thirdChild.Text, Is.EqualTo("some"));
			fourthChild = (StringBox)thirdChild.Next;
			Assert.That(fourthChild.Text, Is.EqualTo("text"));
			Assert.That(firstChild.Next.Top, Is.EqualTo(firstChild.Top), "The blockbox should be left on the first line");
			Assert.That(thirdChild.Top, Is.GreaterThan(firstChild.Top), "The 'some' run should be on the second line");
			Assert.That(fourthChild.Top, Is.EqualTo(thirdChild.Top), "all the rest of the text should fit on one more line");

			// This time the thing that does not fit IS the block at the end.
			// It should move to the next line, without taking any text with it.
			root = new RootBoxFdo(styles);
			root.Builder.Show(Paragraph.Containing(Display.Of("this is ", 34),
				Display.Of("some text", 35), Display.Block(Color.Red, 6000, 2000)));
			maxWidth = FakeRenderEngine.SimulatedWidth("this is some text") + layoutArgs.MpToPixelsX(2000);
			layoutArgs = MakeLayoutInfo(maxWidth, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			para = (ParaBox)root.FirstBox;
			firstChild = (StringBox)para.FirstBox;
			Assert.That(firstChild.Text, Is.EqualTo("this is "));
			secondChild = (StringBox)para.FirstBox.Next;
			Assert.That(secondChild.Text, Is.EqualTo("some text"));
			Assert.That(secondChild.Next, Is.InstanceOf(typeof(BlockBox)));
			Assert.That(secondChild.Top, Is.EqualTo(firstChild.Top), "The two string boxes should fit on the first line");
			Assert.That(secondChild.Next.Top, Is.GreaterThan(secondChild.Top), "The block should be on the second line");

			// Todo JohnT: should also test that a break can occur after a non-string box.
			// And many other cases (see Backtrack method).
		}
Beispiel #10
0
		public void RtlPara()
		{
			var styles = new AssembledStyles();
			var layoutInfo = MakeLayoutInfo();
			var root = new RootBoxFdo(styles);

			var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			engine.RightToLeft = true;
			factory.SetRenderer(34, engine);
			var engine2 = new FakeRenderEngine() { Ws = 35, SegmentHeight = 13 };
			engine2.RightToLeft = true;
			factory.SetRenderer(35, engine);

			root.Builder.Show(Paragraph.Containing(Display.Of("this is ", 34),
				Display.Of("mixed ", 35), Display.Of("text", 34)).RightToLeft(true));
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			var para = (ParaBox) root.FirstBox;
			int left1 = para.FirstBox.Left;
			int left2 = para.FirstBox.Next.Left;
			int left3 = para.FirstBox.Next.Next.Left;
			Assert.That(left3, Is.LessThan(left2));
			Assert.That(left2, Is.LessThan(left1));
		}
		public void ArrowKeys()
		{
			var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(34, engine);
			var styles = new AssembledStyles().WithWs(34);
			var root = new RootBoxFdo(styles);
			var para1 = AddPara("This i~^s the~ day", styles, root);
			var para2 = AddPara("", styles, root);
			var para3 = AddPara(new string[] {"that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE + " the Lord", "has made"},
				styles, root);
			var para4 = AddPara(new string[] { "we will", "", "rejoice" }, styles, root);

			int widthThisIsThe = FakeRenderEngine.SimulatedWidth("This is the");
			var layoutArgs = MakeLayoutInfo(widthThisIsThe + 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			Assert.That(root.Height, Is.EqualTo(13 * 8), "A two-line and a one-line and a three-line and a two-line paragraph");
			PaintTransform ptrans = new PaintTransform(2, 4, 96, 100, 0, 10, 120, 128);
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;

			// Simple left movement.
			var ipThisIsTheDay = para1.SelectAtEnd();
			var ipThisIsTheDa = ipThisIsTheDay.MoveByKey(new KeyEventArgs(Keys.Left));
			VerifyIp(ipThisIsTheDa, para1, "This i~^s the~ da", false, "left from end");
			var ipThisIsTheD = ipThisIsTheDa.MoveByKey(new KeyEventArgs(Keys.Left));
			VerifyIp(ipThisIsTheD, para1, "This i~^s the~ d", false, "left from no special plae");

			// Left from one run into an adjacent non-empty run
			var ipThatTheLord2 = ((TextClientRun) para3.Source.ClientRuns[1]).SelectAt(para3, 0, false);
			var ipThatTheLor = ipThatTheLord2.MoveByKey(new KeyEventArgs(Keys.Left));
			VerifyIp(ipThatTheLor, para3, "that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE + " the Lor", false, "left from start run2");

			// Left from one run into an adjacent empty run. Is this right or should we skip over it into
			// another run so we actually move a character?
			var ipStartOfRejoice = ((TextClientRun)para4.Source.ClientRuns[2]).SelectAt(para4, 0, false);
			var ipEmptyPara4 = ipStartOfRejoice.MoveByKey(new KeyEventArgs(Keys.Left));
			VerifyIp(ipEmptyPara4, para4, "we will", false, "left from start run into empty");

			// Out of the empty run into the previous one.
			var ipWeWil = ipEmptyPara4.MoveByKey(new KeyEventArgs(Keys.Left));
			VerifyIp(ipWeWil, para4, "we wil", false, "left from empty run");

			// back from one para into another.
			var ipPara2 = para2.SelectAtStart();
			var ipEndPara1 = ipPara2.MoveByKey(new KeyEventArgs(Keys.Left));
			VerifyIp(ipEndPara1, para1, "This i~^s the~ day", true, "left from one para to another");

			// back at the very start.
			var ipStart = para1.SelectAtStart();
			Assert.That(ipStart.MoveByKey(new KeyEventArgs(Keys.Left)), Is.Null);

			// back after a surrogate pair should not stop in the middle.
			var ipThatSurrogate = ((TextClientRun)para3.Source.ClientRuns[0]).SelectAt(para3,
				("that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE).Length, false);
			var ipThat = ipThatSurrogate.MoveByKey(new KeyEventArgs(Keys.Left));
			VerifyIp(ipThat, para3, "that", false, "left over surrogate pair");

			// Back to a place between diacritic and base should not stop.
			var ipThisI_Diacritics = ((TextClientRun)para1.Source.ClientRuns[0]).SelectAt(para1,
				"This i~^".Length, false);
			var ipThisSpace = ipThisI_Diacritics.MoveByKey(new KeyEventArgs(Keys.Left));
			VerifyIp(ipThisSpace, para1, "This ", false, "left over diacritics");

			// We can use many of the same ones to check right movement.
			var ipThisIsTheDa_r = ipThisIsTheD.MoveByKey(new KeyEventArgs(Keys.Right));
			VerifyIp(ipThisIsTheDa_r, para1, "This i~^s the~ da", true, "simple right");

			// Move right into an empty paragraph.
			// Review JohnT: should this IP in an empty para associate forward or back?
			var ipStartP2 = ipThisIsTheDay.MoveByKey(new KeyEventArgs(Keys.Right));
			VerifyIp(ipStartP2, para2, "", false, "right into empty para");
			// Should definitely associate with the character following, not the nonexistent preceding one.
			var ipStartP3 = ipStartP2.MoveByKey(new KeyEventArgs(Keys.Right));
			VerifyIp(ipStartP3, para3, "", false, "right to start of non-empty para");

			var ipP3_t = ipStartP3.MoveByKey(new KeyEventArgs(Keys.Right));
			VerifyIp(ipP3_t, para3, "t", true, "simple right");

			var ipThatSurrogate2 = ipThat.MoveByKey(new KeyEventArgs(Keys.Right));
			VerifyIp(ipThatSurrogate2, para3, "that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE, true, "right over surrogate pair");

			var ipThatTheLord_left = ((TextClientRun)para3.Source.ClientRuns[0]).SelectAt(para3,
				("that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE + " the Lord").Length, true);
			var ipThatTheLord_space = ipThatTheLord_left.MoveByKey(new KeyEventArgs(Keys.Right));
			VerifyIp(ipThatTheLord_space, para3, "that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE + " the Lord ", true, "right from end run1");

			var ipEnd = para4.SelectAtEnd();
			Assert.That(ipEnd.MoveByKey(new KeyEventArgs(Keys.Right)), Is.Null);

			// Also can't make range by moving right from end.
			Assert.That(ipEnd.MoveByKey(new KeyEventArgs(Keys.Right | Keys.Shift)), Is.Null);

			var rangeThatSurrogate2 = ipThat.MoveByKey(new KeyEventArgs(Keys.Right | Keys.Shift));
			VerifyRange(rangeThatSurrogate2, para3, "that", para3, "that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE, "shift-right over surrogate pair");

			var rangeThatTha = ipThat.MoveByKey(new KeyEventArgs(Keys.Left | Keys.Shift));
			VerifyRange(rangeThatTha, para3, "that", para3, "tha", "shift-left end before anchor");

			// left from a range puts us at the start of the range
			var ipThat2 = rangeThatSurrogate2.MoveByKey(new KeyEventArgs(Keys.Left));
			VerifyIp(ipThat2, para3, "that", false, "left from range to IP");
			// right from a range puts us at the end of the range
			var ipThatSurrrogate2 = rangeThatSurrogate2.MoveByKey(new KeyEventArgs(Keys.Right));
			VerifyIp(ipThatSurrrogate2, para3, "that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE, true, "right from range");

			// shift-left from a 1-char range collapses it to an IP
			var ipThat3 = rangeThatSurrogate2.MoveByKey(new KeyEventArgs(Keys.Left | Keys.Shift));
			VerifyIp(ipThat3, para3, "that", false, "left over surrogate pair");

			// shift-right from a range makes one with the same anchor but an extended end
			var rangeThatSurrogateSpace = rangeThatSurrogate2.MoveByKey(new KeyEventArgs(Keys.Right | Keys.Shift));
			VerifyRange(rangeThatSurrogateSpace, para3, "that", para3, "that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE + " ", "shift-right from range");

			// shift-right from a range that can't grow returns null.
			var ipWeWillRejoic = (InsertionPoint) ipEnd.MoveByKey(new KeyEventArgs(Keys.Left));
			var range1AtEnd = new RangeSelection(ipWeWillRejoic, ipEnd);
			Assert.That(range1AtEnd.MoveByKey(new KeyEventArgs(Keys.Right | Keys.Shift)), Is.Null);

			// Home key.
			var ipStartP2_2 = ipThat.MoveByKey(new KeyEventArgs(Keys.Home));
			VerifyIp(ipStartP2_2, para3, "", false, "home in Para 3");

			var ipStart_2 = ipThat.MoveByKey(new KeyEventArgs(Keys.Home | Keys.Control));
			VerifyIp(ipStart_2, para1, "", false, "ctrl-home in Para 3");

			// End key.
			var ipEndP2 = ipThat.MoveByKey(new KeyEventArgs(Keys.End));
			VerifyIp(ipEndP2, para3, "that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE + " the Lord" + "has made",
				true, "end in Para 3");

			var ipEnd_2 = ipThat.MoveByKey(new KeyEventArgs(Keys.End | Keys.Control));
			VerifyIp(ipEnd_2, para4, "we will" + "rejoice", true, "ctrl-end in Para 3");

			// Down key
			var ipThisIsThe_R = ipStart.MoveByKey(new KeyEventArgs(Keys.Down));
			VerifyIp(ipThisIsThe_R, para1, "This i~^s the~ ", false, "down from start line 1");

			var ipTh = para1.SelectAt(2, true);
			var ipThisIsTheDa2 = ipTh.MoveByKey(new KeyEventArgs(Keys.Down));
			VerifyIp(ipThisIsTheDa2, para1, "This i~^s the~ da", false, "down from 2 chars into line 1");

			var ipThisIdTh = para1.SelectAt("This i~^s th".Length, false);
			var ipThisIsTheDay2 = ipThisIdTh.MoveByKey(new KeyEventArgs(Keys.Down));
			VerifyIp(ipThisIsTheDay2, para1, "This i~^s the~ day", true, "down from near end line 1");

			// Empty para: arbitrary which way it associates.
			var ipPara2Down = ipThisIsTheDay2.MoveByKey(new KeyEventArgs(Keys.Down));
			VerifyIp(ipPara2Down, para2, "", true, "down twice from near end line 1");

			// Going on down, we should remember the starting X position and end up about that
			// far into the next full-length line. The 'i' characters in the first line make it
			// a bit iffy; might be closer to the start of the 'e' at the end of 'the'.
			// The other complication is that our fake render engine is not smart about surrogate pairs,
			// and treats the musical semibrevis as two ordinary characters.
			// Omitting the diacritics in the first paragraph, our selection starts 10 characters in.
			// The result string here is 9 characters, since with no narrow letters on this para,
			// we end up closer to the left of the 'e'.
			var ipThatTheSpaceDown = ipPara2Down.MoveByKey(new KeyEventArgs(Keys.Down));
			VerifyIp(ipThatTheSpaceDown, para3, "that" + MUSICAL_SYMBOL_SEMIBREVIS_WHITE + " th", false,
				"down 3x from near end line 1");

			Assert.That(ipEnd.MoveByKey(new KeyEventArgs(Keys.Down)), Is.Null);

			var ipPara2Up = ipThatTheSpaceDown.MoveByKey(new KeyEventArgs(Keys.Up));
			VerifyIp(ipPara2Up, para2, "", true, "back up aligned with near end line 1");

			var ipThisIsTheDayUp = ipPara2Up.MoveByKey(new KeyEventArgs(Keys.Up));
			VerifyIp(ipThisIsTheDayUp, para1, "This i~^s the~ day", true, "up from para2 aligned near end line 1");
			// It's going to be looking for a position right at the boundary...either assocPrev would be
			// reasonable.
			var ipThisIdTh2Up = ipThisIsTheDayUp.MoveByKey(new KeyEventArgs(Keys.Up));
			VerifyIp(ipThisIdTh2Up, para1, "This i~^s th", false, "up from end para 1 aligned near end line 1");

			//var ipPara2_2 = ipThisIsTheDay.MoveByKey(new KeyEventArgs(Keys.Down));
			//VerifyIp(ipPara2_2, para2, "", true, "down from end para 1");

			// Todo:
			// HandleSpecialKey is called from OnKeyDown and should handle at least these:
				//case Keys.PageUp:
				//case Keys.PageDown:
				//case Keys.End:
				//case Keys.Home:
				//case Keys.Left: // done
				//case Keys.Up:
				//case Keys.Right: // done
				//case Keys.Down:
				//case Keys.F7: // the only two function keys currently known to the Views code,
				//case Keys.F8: // used for left and right arrow by string character amounts.
			// Test Left: (done)
			// - char to char in same line
			//	- skipping diacritics
			//	- skipping surrogate pairs
			// - to another line in same paragraph
			// - to previous (empty?) paragraph
			// - at very start (nothing happens)
			// - range collapses to start
			// - anything special to test if there are multiple runs? e.g., at boundary
			// - skip over embedded pictures
			// - eventually drop into embedded boxes that contain text?
			// Similarly right (done)
			// Down:
			// - same para, there is text below
			// - same para, no text immediately below on same line (goes to end of previous line)
			//  - eventually: what should happen if logical and physical end of next line don't coincide?
			// - down again to a longer line: should stay aligned with start position (what resets this??)
			// etc for others.
		}
		private void BodyofUserPromptTest(MockData1 data1, Flow promptField, Func<string> reader)
		{
			var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(34, engine);
			factory.SetRenderer(35, engine);
			factory.SetRenderer(0, engine); // for literals
			var styles = new AssembledStyles().WithWs(34);

			var root = new RootBoxFdo(styles);
			root.Builder.Show(
				Paragraph.Containing(
					Display.Of("lead in ", 34),
					promptField,
					Display.Of("trailing", 34)
					)
				);
			var para = (ParaBox)root.FirstBox;
			Assert.That(para.Source.RenderText, Is.EqualTo("lead in type here trailing"));

			int width = FakeRenderEngine.SimulatedWidth("lead in type her"); // should make it take 2 lines and split prompt.
			var layoutArgs = MakeLayoutInfo(width, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			MockSite site = new MockSite();
			PaintTransform ptrans = new PaintTransform(2, 4, 96, 96, 0, 10, 96, 96);
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;

			// Click on "type here" produces an IP in the empty string.
			int leadWidth = FakeRenderEngine.SimulatedWidth("lead in ");
			var mouseArgs = new MouseEventArgs(MouseButtons.Left, 1, 2 + leadWidth + 3, 0, 0);
			root.OnMouseDown(mouseArgs, Keys.None, m_gm.VwGraphics, ptrans);
			var ip = root.Selection as InsertionPoint;
			Assert.That(ip, Is.Not.Null);
			Assert.That(ip.LogicalParaPosition, Is.EqualTo("lead in ".Length));
			Assert.That(ip.StringPosition, Is.EqualTo(0));

			// IP is drawn as range covering "type here"
			ip.Draw(m_gm.VwGraphics, ptrans);
			var first = (StringBox)para.FirstBox;
			VerifyRangeSegmentDrawing(para, first, (FakeSegment)first.Segment, "lead in ".Length, "lead in type here ".Length,
				-4, 4 - 10, 4 - 10 + 13);
			var second = (StringBox)first.Next;
			VerifyRangeSegmentDrawing(para, second, (FakeSegment)second.Segment, "lead in ".Length, "lead in type here ".Length,
				-4 - 13, 4 - 10 + 13, 4 - 10 + 13 * 2);
			// Check that we get a sensible answer for the selection's containing rectangle.
			((FakeSegment) first.Segment).LeftPositionOfRangeResult = 17;
			((FakeSegment)first.Segment).RightPositionOfRangeResult = 29;
			((FakeSegment)second.Segment).LeftPositionOfRangeResult = 5;
			((FakeSegment)second.Segment).RightPositionOfRangeResult = 13;
			var rect = ip.GetSelectionLocation(m_gm.VwGraphics, ptrans);
			Assert.That(rect.Top, Is.EqualTo(4 - 10));
			Assert.That(rect.Bottom, Is.EqualTo(4 - 10 + 13*2));
			Assert.That(rect.Left, Is.EqualTo(5));
			Assert.That(rect.Right, Is.EqualTo(29));
			VerifyRangeSegmentQuery(para, first, (FakeSegment)first.Segment, "lead in ".Length, "lead in type here ".Length,
				-4, 4 - 10, 4 - 10 + 13);
			VerifyRangeSegmentQuery(para, second, (FakeSegment)second.Segment, "lead in ".Length, "lead in type here ".Length,
				-4 - 13, 4 - 10 + 13, 4 - 10 + 13 * 2);
			Assert.That(second.IchMin, Is.EqualTo("lead in type ".Length));
			// When the IP is drawn like this, it doesn't flash!
			site.RectsInvalidatedInRoot.Clear();
			site.RectsInvalidated.Clear();
			root.FlashInsertionPoint(); // Call twice just in case somehow only some invalidates worked.
			root.FlashInsertionPoint();
			Assert.That(site.RectsInvalidated, Is.Empty);
			Assert.That(site.RectsInvalidatedInRoot, Is.Empty);
			// Typing something else makes "type here" go away and produces a normal IP after it.
			ip.InsertText("x");
			Assert.That(reader(), Is.EqualTo("x"));
			Assert.That(para.Source.RenderText, Is.EqualTo("lead in xtrailing"));
			ip = root.Selection as InsertionPoint;
			Assert.That(ip, Is.Not.Null);
			Assert.That(ip.ShouldFlash, Is.True);
			Assert.That(ip.LogicalParaPosition, Is.EqualTo("lead in x".Length));
			// Deleting back to empty string makes "type here" reappear.
			ip.Backspace();
			Assert.That(reader(), Is.EqualTo(""));
			Assert.That(para.Source.RenderText, Is.EqualTo("lead in type here trailing"));
			ip = root.Selection as InsertionPoint;
			Assert.That(ip, Is.Not.Null);
			Assert.That(ip.ShouldFlash, Is.False);
			Assert.That(ip.LogicalParaPosition, Is.EqualTo("lead in ".Length));
			Assert.That(ip.LastRenderParaPosition, Is.EqualTo("lead in type here ".Length));
			second = (StringBox)para.FirstBox.Next;
			Assert.That(second.IchMin, Is.EqualTo("lead in type ".Length));
			// Click after "type here" produces an IP at the right place in the following string.
			// We've arranged for the prompt to be split, so this is after the word 'here' on the second line.
			int hereTWidth = FakeRenderEngine.SimulatedWidth("here t");
			mouseArgs = new MouseEventArgs(MouseButtons.Left, 1, 2 + hereTWidth - 1, 4 - 10 + 13 + 2, 0);
			root.OnMouseDown(mouseArgs, Keys.None, m_gm.VwGraphics, ptrans);
			ip = root.Selection as InsertionPoint;
			Assert.That(ip, Is.Not.Null);
			Assert.That(ip.LogicalParaPosition, Is.EqualTo("lead in t".Length));
			Assert.That(ip.AssociatePrevious, Is.True);
			Assert.That(ip.StringPosition, Is.EqualTo(1));
			Assert.That(ip.RenderParaPosition, Is.EqualTo("lead in type here t".Length));
			// Also try a click in the second-line part of the prompt.
			int herWidth = FakeRenderEngine.SimulatedWidth("her");
			mouseArgs = new MouseEventArgs(MouseButtons.Left, 1, 2 + herWidth - 1, 4 - 10 + 13 + 2, 0);
			root.OnMouseDown(mouseArgs, Keys.None, m_gm.VwGraphics, ptrans);
			ip = root.Selection as InsertionPoint;
			Assert.That(ip, Is.Not.Null);
			Assert.That(ip.LogicalParaPosition, Is.EqualTo("lead in ".Length));
			Assert.That(ip.StringPosition, Is.EqualTo(0));
			Assert.That(ip.RenderParaPosition, Is.EqualTo("lead in ".Length));
			Assert.That(ip.LastRenderParaPosition, Is.EqualTo("lead in type here ".Length));
		}
		public void InsertCharInEmptyLine()
		{
			string contents = "";
			var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(34, engine);
			var styles = new AssembledStyles().WithWs(34);
			var clientRuns = new List<IClientRun>();
			var run = new StringClientRun(contents, styles);
			clientRuns.Add(run);
			var data1 = new MockData1(34, 35);
			data1.SimpleThree = contents;
			var source = new TextSource(clientRuns, null);
			var para = new ParaBox(styles, source);
			var hookup = new StringHookup(this, () => data1.SimpleThree, hook => data1.SimpleThreeChanged += hook.StringPropChanged,
				hook => data1.SimpleThreeChanged -= hook.StringPropChanged, para);
			hookup.Writer = newVal => data1.SimpleThree = newVal;
			run.Hookup = hookup;
			var root = new RootBox(styles);
			var block = new BlockBox(styles, Color.Red, 20000, 10000);
			root.AddBox(block);
			root.AddBox(para);
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			Assert.That(root.Height, Is.EqualTo(13 + block.Height));
			Assert.That(para.Width, Is.EqualTo(FakeRenderEngine.SimulatedWidth(contents)));
			Assert.That(root.Width, Is.EqualTo(block.Width));
			int simulatedWidth = FakeRenderEngine.SimulatedWidth("x");
			Assert.That(root.Width, Is.GreaterThan(para.Width + simulatedWidth));
			PaintTransform ptrans = new PaintTransform(2, 4, 96, 100, 0, 10, 120, 128);
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;
			var oldRootWidth = root.Width;

			var ip = root.SelectAtEnd();
			ip.InsertText("x");
			Assert.That(root.Height, Is.EqualTo(13 + block.Height));
			Assert.That(root.Width, Is.EqualTo(oldRootWidth));
			Assert.That(para.Width, Is.EqualTo(simulatedWidth));
			var expectedInvalidate = new Rectangle(-RootBox.InvalidateMargin,
							- RootBox.InvalidateMargin + block.Height,
							simulatedWidth + RootBox.InvalidateMargin * 2,
							13 + 2 * RootBox.InvalidateMargin);
			Assert.That(site.RectsInvalidatedInRoot, Has.Member(expectedInvalidate));
		}
		public void InsertGrowsPara()
		{
			string contents = "This is the day.";
			var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(34, engine);
			var styles = new AssembledStyles().WithWs(34);
			var clientRuns = new List<IClientRun>();
			var run = new StringClientRun(contents, styles);
			clientRuns.Add(run);
			var data1 = new MockData1(34, 35);
			data1.SimpleThree = contents;
			var source = new TextSource(clientRuns, null);
			var para = new ParaBox(styles, source);
			var hookup = new StringHookup(this, () => data1.SimpleThree, hook => data1.SimpleThreeChanged += hook.StringPropChanged,
				hook => data1.SimpleThreeChanged -= hook.StringPropChanged, para);
			hookup.Writer = newVal => data1.SimpleThree = newVal;
			run.Hookup = hookup;
			var extraBox = new BlockBox(styles, Color.Red, 50, 72000);
			var root = new RootBoxFdo(styles);
			root.SizeChanged += root_SizeChanged;
			root.AddBox(para);
			root.AddBox(extraBox);
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			Assert.IsTrue(m_sizeChangedCalled);
			Assert.That(root.Height, Is.EqualTo(13 + 96));
			Assert.That(root.Width, Is.EqualTo(FakeRenderEngine.SimulatedWidth(contents)));

			int widthThisIsThe = FakeRenderEngine.SimulatedWidth("This is the");
			layoutArgs = MakeLayoutInfo(widthThisIsThe + 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			Assert.That(root.Height, Is.EqualTo(26 + 96), "two line para is twice the height");
			Assert.That(root.Width, Is.EqualTo(widthThisIsThe + 2), "two-line para occupies full available width");
			Assert.That(extraBox.Top, Is.EqualTo(26));

			PaintTransform ptrans = new PaintTransform(2, 4, 96, 100, 0, 10, 120, 128);
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;
			m_sizeChangedCalled = false;
			var ip = para.SelectAtEnd();

			ip.InsertText(" We will be");
			Assert.That(para.Height, Is.EqualTo(39), "inserted text makes para a line higher");
			Assert.That(root.Height, Is.EqualTo(39 + 96), "root grows when para does");
			Assert.That(root.Width, Is.EqualTo(widthThisIsThe + 2), "three-line para occupies full available width");
			Assert.That(extraBox.Top, Is.EqualTo(39));
			Assert.IsTrue(m_sizeChangedCalled);
		}
Beispiel #15
0
		public void ComplexRangeDrawing()
		{
			var string1 = "This is the day that the Lord has made.";
			var string2 = "We will rejoice and be glad in it.";
			var string3 = "Love the Lord your God with all your heart.";

			var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(34, engine);
			var runStyle = new AssembledStyles().WithWs(34);

			var lineHeightMp = 20000;
			var style = new AssembledStyles().WithLineHeight(lineHeightMp);
			var root = new RootBox(style);
			var para1 = MakePara(style, runStyle, string1);
			root.AddBox(para1);
			var div = new DivBox(style);
			root.AddBox(div);
			var para2 = MakePara(style, runStyle, string2);
			div.AddBox(para2);
			var para3 = MakePara(style, runStyle, string3);
			div.AddBox(para3);

			// This width makes each paragraph take three lines.
			var layoutArgs = new LayoutInfo(2, 2, 96, 96, FakeRenderEngine.SimulatedWidth("This is the day "), m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);

			var ip1 = para1.SelectAt(1, false);
			var ip2 = para1.SelectAt(3, true);
			var range1 = new RangeSelection(ip1, ip2);
			Assert.That(range1.EndBeforeAnchor, Is.False);
			Assert.That(range1.Start, Is.EqualTo(ip1));
			Assert.That(range1.End, Is.EqualTo(ip2));

			PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
			var sbox1_1 = para1.FirstBox as StringBox;
			range1.Draw(m_gm.VwGraphics, ptrans);
			int topOffset = -2; // top of RcSrc for top of root box.
			int topYd = 2; // destination coord corresponding to top of root box.
			int leftXd = 2; // destination coord corresponding to left of root box.
			int bottomOfFirstLine = topYd + engine.SegmentHeight;
			int lineHeight = ptrans.MpToPixelsY(lineHeightMp);
			int bottomOfFirstHilite = bottomOfFirstLine + (lineHeight - engine.SegmentHeight)/2;
			VerifyRangeSegmentDrawing(para1, sbox1_1, range1, topOffset, topYd, bottomOfFirstHilite);
			var sbox1_2 = sbox1_1.Next as StringBox;
			int bottomOfSecondHilite = bottomOfFirstHilite + lineHeight;
			VerifyRangeSegmentDrawing(para1, sbox1_2, range1, topOffset - lineHeight, bottomOfFirstHilite, bottomOfSecondHilite);
			var sbox1_3 = sbox1_2.Next as StringBox;
			int bottomOfThirddHilite = bottomOfSecondHilite + lineHeight - para1.Ascent;
			VerifyRangeSegmentDrawing(para1, sbox1_3, range1, topOffset - lineHeight * 2, bottomOfSecondHilite, bottomOfThirddHilite);

			// A two-line selection has much the same results.
			var ip3 = para1.SelectAt(sbox1_2.IchMin + 2, true);
			var range2 = new RangeSelection(ip1, ip3);
			range2.Draw(m_gm.VwGraphics, ptrans);
			VerifyRangeSegmentDrawing(para1, sbox1_1, range2, topOffset, topYd, bottomOfFirstHilite);
			VerifyRangeSegmentDrawing(para1, sbox1_2, range2, topOffset - lineHeight, bottomOfFirstHilite, bottomOfSecondHilite);
			VerifyRangeSegmentDrawing(para1, sbox1_3, range2, topOffset - lineHeight * 2, bottomOfSecondHilite, bottomOfThirddHilite);

			// Try multi-para selection in paras in same div.
			var ip2_3 = para2.SelectAt(3, false);
			var ip3_4 = para3.SelectAt(4, true);
			var range3 = new RangeSelection(ip2_3, ip3_4);
			range3.Draw(m_gm.VwGraphics, ptrans);
			var sbox2_1 = para2.FirstBox as StringBox;
			int topOfPara2 = topYd + para1.Height;
			int bottomOfFirstLineP2 = topOfPara2 + engine.SegmentHeight;
			int bottomOfFirstHiliteP2 = bottomOfFirstLineP2 + (lineHeight - engine.SegmentHeight) / 2;
			VerifyRangeSegmentDrawing(para2, sbox2_1, range3, topOffset - para1.Height, topOfPara2, bottomOfFirstHiliteP2);
			var sbox2_2 = sbox2_1.Next as StringBox;
			int bottomOfSecondHiliteP2 = bottomOfFirstHiliteP2 + lineHeight;
			VerifyRangeSegmentDrawing(para2, sbox2_2, range3, topOffset - para1.Height - lineHeight,
				bottomOfFirstHiliteP2, bottomOfSecondHiliteP2);
			var sbox2_3 = sbox2_2.Next as StringBox;
			int bottomOfThirddHiliteP2 = bottomOfSecondHiliteP2 + lineHeight - para2.Ascent;
			VerifyRangeSegmentDrawing(para2, sbox2_3, range3, topOffset - para1.Height - lineHeight * 2,
				bottomOfSecondHiliteP2, bottomOfThirddHiliteP2);
			var sbox3_1 = para3.FirstBox as StringBox;
			int topOfPara3 = topOfPara2 + para2.Height;
			var bottomOfFirstLineP3 = topOfPara3 + engine.SegmentHeight;
			var bottomOfFirstHiliteP3 = bottomOfFirstLineP3 + (lineHeight - engine.SegmentHeight) / 2;
			VerifyRangeSegmentDrawing(para3, sbox3_1, range3, topOffset - para1.Height - para2.Height, topOfPara3, bottomOfFirstHiliteP3);
			// Currently the other two segments of para3 will also be asked to draw it, but we've already checked how tops and bottoms
			// are worked out, and we don't care if these beyond-the-end segments draw it or not. Better not to test, then we can
			// optimize freely.

			// Now try a range that is (backwards and) across a div boundary
			var range4 = new RangeSelection(ip3_4, ip2);
			Assert.That(range4.EndBeforeAnchor, Is.True);
			Assert.That(range4.Start.SameLocation(ip2), Is.True);
			Assert.That(range4.End.SameLocation(ip3_4), Is.True);
			ClearSegmentDrawing(sbox1_3);
			ClearSegmentDrawing(sbox2_1);
			ClearSegmentDrawing(sbox3_1);
			range4.Draw(m_gm.VwGraphics, ptrans);
			// Several others should get drawn as well, but I think it's sufficient to verify tha something gets done correct in each para.
			VerifyRangeSegmentDrawing(para1, sbox1_3, range4, topOffset - lineHeight * 2, bottomOfSecondHilite, bottomOfThirddHilite);
			VerifyRangeSegmentDrawing(para2, sbox2_1, range4, topOffset - para1.Height, topOfPara2, bottomOfFirstHiliteP2);
			VerifyRangeSegmentDrawing(para3, sbox3_1, range4, topOffset - para1.Height - para2.Height, topOfPara3, bottomOfFirstHiliteP3);

			var range5 = new RangeSelection(ip2, ip3_4);
			Assert.That(range5.EndBeforeAnchor, Is.False);
			Assert.That(range5.Start.SameLocation(ip2), Is.True);
			Assert.That(range5.End.SameLocation(ip3_4), Is.True);

			// While we've got these selections, it's a good chance to check out GetSelectionLocation
			// The first one is a simple rectangle in the first string box.
			SetSelectionLocation(sbox1_1, 15, 20);
			Assert.That(range1.GetSelectionLocation(m_gm.VwGraphics, ptrans), Is.EqualTo(
				new Rectangle(15, topYd, 20 - 15, bottomOfFirstHilite - topYd)));
			SetSelectionLocation(sbox1_2, 18, 25);
			Assert.That(range2.GetSelectionLocation(m_gm.VwGraphics, ptrans), Is.EqualTo(
				new Rectangle(15, topYd, 25 - 15, bottomOfSecondHilite - topYd)));
			SetSelectionLocation(sbox3_1, 22, 27);
			Assert.That(range4.GetSelectionLocation(m_gm.VwGraphics, ptrans), Is.EqualTo(
				new Rectangle(leftXd, topYd, para2.Width, bottomOfFirstHiliteP3 - topYd)));
		}
Beispiel #16
0
		public void DiffWS()
		{
			var tsf = TsStrFactoryClass.Create();
			var styles = new AssembledStyles();
			var root = new RootBoxFdo(styles);
			var mock1 = new MockData1(23, 23);
			mock1.SimpleTwo = tsf.MakeString("newoldcontents", 23);
			var bldr = mock1.SimpleTwo.GetBldr();
			bldr.SetIntPropValues(3, 6, (int)FwTextPropType.ktptWs,
				(int)FwTextPropVar.ktpvDefault, 24);
			bldr.SetIntPropValues(6, 14, (int)FwTextPropType.ktptWs,
				(int)FwTextPropVar.ktpvDefault, 25);
			mock1.SimpleTwo = bldr.GetString();
			var engine = new FakeRenderEngine() { Ws = 23, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(23, engine);
			root.Builder.Show(Display.Of(() => mock1.SimpleTwo));
			var layoutArgs = MakeLayoutInfo(Int32.MaxValue / 2, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
			MockSite site = new MockSite();
			site.m_transform = ptrans;
			site.m_vwGraphics = m_gm.VwGraphics;
			root.Site = site;

			int x = FakeRenderEngine.SimulatedWidth("ne") + 2;
			var location = new Point(x, 8);
			EventArgs e = new EventArgs();
			MouseEventArgs m = new MouseEventArgs(MouseButtons.Left, 1, location.X, location.Y, 0);

			root.OnMouseDown(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnMouseClick(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnDoubleClick(e);
			Assert.That(!root.Selection.IsInsertionPoint, "Should be ranged selection");
			Assert.That((root.Selection as RangeSelection).SelectedText(), Is.EqualTo("new"));

			x = FakeRenderEngine.SimulatedWidth("new") + 2;
			location = new Point(x, 8);
			m = new MouseEventArgs(MouseButtons.Left, 1, location.X, location.Y, 0);
			root.OnMouseDown(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnMouseClick(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnDoubleClick(e);
			Assert.That(!root.Selection.IsInsertionPoint, "Should be ranged selection");
			Assert.That((root.Selection as RangeSelection).SelectedText(), Is.EqualTo("old"));

			x = FakeRenderEngine.SimulatedWidth("newold") + 2;
			location = new Point(x, 8);
			m = new MouseEventArgs(MouseButtons.Left, 1, location.X, location.Y, 0);
			root.OnMouseDown(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnMouseClick(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnDoubleClick(e);
			Assert.That(!root.Selection.IsInsertionPoint, "Should be ranged selection");
			Assert.That((root.Selection as RangeSelection).SelectedText(), Is.EqualTo("contents"));

			x = FakeRenderEngine.SimulatedWidth("newold");
			location = new Point(x, 8); // at the right edge of the d at the end of newold
			m = new MouseEventArgs(MouseButtons.Left, 1, location.X, location.Y, 0);
			root.OnMouseDown(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnMouseClick(m, Keys.None, site.m_vwGraphics, site.m_transform);
			root.OnDoubleClick(e);
			Assert.That(!root.Selection.IsInsertionPoint, "Should be ranged selection");
			Assert.That((root.Selection as RangeSelection).SelectedText(), Is.EqualTo("old"));
		}
Beispiel #17
0
		public void BidiBacktracking()
		{
			var styles = new AssembledStyles();
			var layoutInfo = MakeLayoutInfo();

			var engine = new FakeRenderEngine() {Ws = 34, SegmentHeight = 13};
			var factory = new FakeRendererFactory();
			factory.SetRenderer(34, engine);
			var engine2 = new FakeRenderEngine() {Ws = 35, SegmentHeight = 13};
			factory.SetRenderer(35, engine2);
			engine2.RightToLeft = true;

			// This first test doesn't strictly require backtracking; it is an example of a similar
			// case where all the second client run fits, nothing of the following one fits, but
			// there is a satisfactory break at the end of the last thing that fit.
			// But, the space at the 'end' of "some mixed" will need to be moved to the end so it can 'disappear',
			// so it should become a separate segment.
			// That is, we should get something like
			// this is dexim emos_
			// text
			// Where the underline stands for the space after "some mixed" which is moved to the end of the line.
			var root = new RootBoxFdo(styles);
			root.Builder.Show(Paragraph.Containing(Display.Of("this is ", 34),
												   Display.Of("some mixed ", 35), Display.Of("text", 34)));
			int maxWidth = FakeRenderEngine.SimulatedWidth("this is some mixed t");
			var layoutArgs = MakeLayoutInfo(maxWidth, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			var para = (ParaBox) root.FirstBox;
			var secondChild = (StringBox) para.FirstBox.Next;
			Assert.That(secondChild.Text, Is.EqualTo("some mixed"));
			var thirdChild = (StringBox)secondChild.Next;
			Assert.That(thirdChild.Text, Is.EqualTo(" "));
			Assert.That(thirdChild.Top, Is.EqualTo(para.FirstBox.Top));

			// True backtracking: the second client run fits entirely, but nothing of the following text.
			// We must go back and find the break in the middle of that second run.
			root = new RootBoxFdo(styles);
			root.Builder.Show(Paragraph.Containing(Display.Of("this is ", 34),
												   Display.Of("some mixed", 35), Display.Of("text", 34)));
			maxWidth = FakeRenderEngine.SimulatedWidth("this is some mixedte");
			layoutArgs = MakeLayoutInfo(maxWidth, m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			para = (ParaBox)root.FirstBox;
			secondChild = (StringBox)para.FirstBox.Next;
			Assert.That(secondChild.Text, Is.EqualTo("some"));
			thirdChild = (StringBox)secondChild.Next;
			Assert.That(thirdChild.Text, Is.EqualTo(" "));
			Assert.That(thirdChild.Top, Is.EqualTo(para.FirstBox.Top));
			var fourthChild = (StringBox)thirdChild.Next;
			Assert.That(fourthChild.Text, Is.EqualTo("mixed"));
			Assert.That(fourthChild.Top, Is.GreaterThan(thirdChild.Top));
			var fifthChild = (StringBox)fourthChild.Next;
			Assert.That(fifthChild.Text, Is.EqualTo("text"));
			Assert.That(fifthChild.Top, Is.EqualTo(fourthChild.Top));
		}
Beispiel #18
0
		public void MouseEvents()
		{
			var string1 = "This is the day that the Lord has made.";

			var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 };
			var factory = new FakeRendererFactory();
			factory.SetRenderer(34, engine);
			var runStyle = new AssembledStyles().WithWs(34);

			var style = new AssembledStyles();
			var root = new RootBox(style);
			var para1 = MakePara(style, runStyle, string1);
			root.AddBox(para1);
			PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96);
			var layoutArgs = new LayoutInfo(2, 2, 96, 96, FakeRenderEngine.SimulatedWidth("This is the day "), m_gm.VwGraphics, factory);
			root.Layout(layoutArgs);
			var mouseArgs = new MouseEventArgs(MouseButtons.Left, 1, 2, 5, 0);
			root.OnMouseDown(mouseArgs, Keys.None, m_gm.VwGraphics, ptrans);
			Assert.That(root.Selection, Is.TypeOf(typeof(InsertionPoint)));
			Assert.That(((InsertionPoint)root.Selection).LogicalParaPosition, Is.EqualTo(0));
			Assert.That(((InsertionPoint)root.Selection).AssociatePrevious, Is.False);

			// In a different place, tests moving the selection and also getting AssociatePrevious true.
			int widthThis = FakeRenderEngine.SimulatedWidth("This");
			var mouseArgs2 = new MouseEventArgs(MouseButtons.Left, 1, 2 + widthThis - 1, 5, 0);
			root.OnMouseDown(mouseArgs2, Keys.None, m_gm.VwGraphics, ptrans);
			Assert.That(root.Selection, Is.TypeOf(typeof(InsertionPoint)));
			Assert.That(((InsertionPoint)root.Selection).LogicalParaPosition, Is.EqualTo(4));
			Assert.That(((InsertionPoint)root.Selection).AssociatePrevious, Is.True);

			// A click in the same place should not make a new selection.
			var sel = root.Selection;
			root.OnMouseDown(mouseArgs2, Keys.None, m_gm.VwGraphics, ptrans); // no change
			Assert.That(root.Selection, Is.EqualTo(sel));

			// A shift-click close enough to the same place to be the same character position but difference AssocPrevious
			// should make the appropriate new IP, not a range.
			var mouseArgs2b = new MouseEventArgs(MouseButtons.Left, 1, 2 + widthThis + 1, 5, 0);
			root.OnMouseDown(mouseArgs2b, Keys.Shift, m_gm.VwGraphics, ptrans);
			Assert.That(root.Selection, Is.TypeOf(typeof(InsertionPoint)));
			Assert.That(((InsertionPoint)root.Selection).LogicalParaPosition, Is.EqualTo(4));
			Assert.That(((InsertionPoint)root.Selection).AssociatePrevious, Is.False);

			// A shift-click should make a range.
			root.OnMouseDown(mouseArgs, Keys.Shift, m_gm.VwGraphics, ptrans);
			Assert.That(root.Selection, Is.TypeOf(typeof(RangeSelection)));
			var anchor = ((RangeSelection) root.Selection).Anchor;
			var drag = ((RangeSelection) root.Selection).DragEnd;
			Assert.That(anchor.LogicalParaPosition, Is.EqualTo(4));
			Assert.That(drag.LogicalParaPosition, Is.EqualTo(0));

			// shift-click further right: should move the drag end
			var mouseArgs3 = new MouseEventArgs(MouseButtons.Left, 1, 2 + 4, 5, 0);
			root.OnMouseDown(mouseArgs3, Keys.Shift, m_gm.VwGraphics, ptrans);
			Assert.That(root.Selection, Is.TypeOf(typeof(RangeSelection)));
			anchor = ((RangeSelection)root.Selection).Anchor;
			drag = ((RangeSelection)root.Selection).DragEnd;
			Assert.That(anchor.LogicalParaPosition, Is.EqualTo(4));
			Assert.That(drag.LogicalParaPosition, Is.EqualTo(1));

			// mouse move, to a different position
			root.OnMouseMove(mouseArgs, Keys.None, m_gm.VwGraphics, ptrans);
			sel = root.Selection;
			Assert.That(sel, Is.TypeOf(typeof(RangeSelection)));
			anchor = ((RangeSelection)root.Selection).Anchor;
			drag = ((RangeSelection)root.Selection).DragEnd;
			Assert.That(anchor.LogicalParaPosition, Is.EqualTo(4));
			Assert.That(drag.LogicalParaPosition, Is.EqualTo(0));

			// mouse move to the same position: no new selection.
			root.OnMouseMove(mouseArgs, Keys.None, m_gm.VwGraphics, ptrans); // no actual movement
			Assert.That(root.Selection, Is.EqualTo(sel));
			Assert.That(((RangeSelection)root.Selection).DragEnd, Is.EqualTo(drag));

			// mouse move to an IP at the anchor should return us to an IP
			root.OnMouseMove(mouseArgs2b, Keys.None, m_gm.VwGraphics, ptrans);
			Assert.That(root.Selection, Is.TypeOf(typeof(InsertionPoint)));
			Assert.That(((InsertionPoint)root.Selection).LogicalParaPosition, Is.EqualTo(4));
			Assert.That(((InsertionPoint)root.Selection).AssociatePrevious, Is.False);

			// mouse down on next line makes a selection there. Confirm proper passing of srcRect for vertical offset
			var mouseArgs4 = new MouseEventArgs(MouseButtons.Left, 1, 2 + 4, 2 + 16, 0);
			root.OnMouseDown(mouseArgs4, Keys.None, m_gm.VwGraphics, ptrans);
			var paraBox = (ParaBox) root.FirstBox;
			var seg2 = ((StringBox) paraBox.FirstBox.Next).Segment as FakeSegment;
			Assert.That(seg2, Is.Not.Null);
			Assert.That(seg2.LastPointToCharArgs, Is.Not.Null);
			var topOfseg2 = paraBox.FirstBox.Height;
			Assert.That(seg2.LastPointToCharArgs.RcSrc, Is.EqualTo(new Rect(-2, -2 - topOfseg2, 94, 94-topOfseg2)));
		}