diff --git a/PROMS/Volian.Controls.Library/StepPanel.cs b/PROMS/Volian.Controls.Library/StepPanel.cs index ee323169..278a463a 100644 --- a/PROMS/Volian.Controls.Library/StepPanel.cs +++ b/PROMS/Volian.Controls.Library/StepPanel.cs @@ -581,6 +581,151 @@ namespace Volian.Controls.Library } } #endregion + #region Cursor Movement Methods + /// + /// Finds the Displayed 'top' child for a given item. Used for down arrow. + /// + /// ItemInfo + /// + private ItemInfo TopPart(ItemInfo ii) + { + ExpandAsNeeded(ii); + if (ii.Cautions != null) return TopPart(ii.Cautions[0]); + if (ii.Notes != null) return TopPart(ii.Notes[0]); + return (ii); + } + /// + /// Finds the Displayed 'bottom' child for a given item. Used for up arrow. + /// + /// ItemInfo + /// + private ItemInfo BottomPart(ItemInfo ii) + { + ExpandAsNeeded(ii); + if (ii.RNOs != null && ii.RNOLevel >= ii.Columns - 1) return BottomPart(ii.RNOs[0]); + if (ii.Sections != null) return BottomPart(ii.Sections[0].LastSibling); + if (ii.Steps != null) return BottomPart(ii.Steps[0].LastSibling); + return ii; + } + /// + /// Supports cursor movement between richtext boxes, including arrow keys/page up,down/ + /// ctrl Home,End + /// + /// StepRTB + /// Point + /// E_ArrowKeys + public void CursorMovement(StepRTB rtb, Point position, E_ArrowKeys arrow) + { + ItemInfo ii = null; + switch (arrow) + { + case E_ArrowKeys.Up: + case E_ArrowKeys.CtrlUp: + ii = ArrowUp(rtb.MyItemInfo); + if (ii != null) SelectedStepRTB = _LookupStepItems[ii.ItemID].MyStepRTB; + break; + case E_ArrowKeys.Down: + case E_ArrowKeys.CtrlDown: + ii = ArrowDown(rtb.MyItemInfo); + if (ii != null) SelectedStepRTB = _LookupStepItems[ii.ItemID].MyStepRTB; + break; + case E_ArrowKeys.Right: + case E_ArrowKeys.CtrlRight: + if (rtb.MyItemInfo.RNOs != null) + SelectedStepRTB = _LookupStepItems[rtb.MyItemInfo.RNOs[0].ItemID].MyStepRTB; + break; + case E_ArrowKeys.Left: + case E_ArrowKeys.CtrlLeft: + if (!rtb.MyItemInfo.IsProcedure) + SelectedStepRTB = _LookupStepItems[rtb.MyItemInfo.MyParent.ItemID].MyStepRTB; + break; + default: + break; + } + } + private ItemInfo ArrowUp(ItemInfo ii) + { + // if on RNO, check display mode (1 column/2 column, etc) and how deep RNO is before going to + // parents substeps. + if (ii.IsRNO && ii.MyParent.Steps != null && ii.RNOLevel >= ii.Columns) return BottomPart(ii.MyParent.Steps[0].LastSibling); + + // If on top note and parent has cautions - go to bottom caution + if (ii.IsNoteStructure && ii.MyParent != null && ii.MyParent.Cautions != null) return BottomPart(ii.MyParent.Cautions[0].LastSibling); + if (ii.IsCautionStructure || ii.IsNoteStructure) + { + if (ii.MyParent.MyPrevious != null) return BottomPart(ii.MyParent.MyPrevious); + return ii.MyParent.MyParent; + } + + // If has note, BottomPart of last sibling of the note + if (ii.Notes != null) return BottomPart(ii.Notes[0].LastSibling); + // If has caution, BottomPart of last sibling of the caution + if (ii.Cautions != null) return BottomPart(ii.Cautions[0].LastSibling); + // If previous sibling, BottomPart of previous sibling + if (ii.MyPrevious != null) return BottomPart(ii.MyPrevious); + // Go to parent until at procedure + if (!ii.IsProcedure) return (ii.MyParent); + return null; + } + private ItemInfo ArrowDown(ItemInfo ii) + { + return ArrowDown(ii, true, true); + } + private ItemInfo ArrowDown(ItemInfo ii, bool lookAtSub, bool lookAtRNO) + { + if (ii.IsSection || ii.IsProcedure) + { + if (lookAtSub && ii.Sections != null) return TopPart(ii.Sections[0]); + if (lookAtSub && ii.Steps != null) return TopPart(ii.Steps[0]); + if (ii.IsSection && ii.NextItems != null) return TopPart(ii.NextItems[0]); + } + else + { + // Subitems - go to top part of subitem + // (the lookAtSub prevented looping within a substep group at same level) + if (lookAtSub && ii.Steps != null) return TopPart(ii.Steps[0]); + // RNOs: Use PMode (column) + if (lookAtRNO && ii.RNOs != null && ii.RNOLevel >= ii.Columns - 1) return TopPart(ii.RNOs[0]); + // Nextsibling - go to top part of sibling + if (ii.NextItems != null) return TopPart(ii.NextItems[0]); + // If on caution, if parent has note - go to note + if (ii.IsCautionStructureFirstSib && ii.MyParent.Notes != null) return ii.MyParent.Notes[0]; + // If on caution, if parent !has note or if on note go to parent + if ((ii.IsCautionStructureFirstSib && ii.MyParent.Notes == null) || ii.IsNoteStructureFirstSib) return ii.MyParent; + // Recursively call with parent until at procedure + if (!ii.IsProcedure) return (ArrowDown(ii.MyParent, false, ii.MyParent.RNOLevel==ii.RNOLevel)); + } + return null; + } + internal void StepCursorKeys(StepRTB rtb, KeyEventArgs keyargs) + { + ItemInfo ii = rtb.MyItemInfo; + if (ii.IsSection || ii.IsProcedure) return; + while (!ii.IsHigh) + { + ii = ii.MyParent; + } + switch (keyargs.KeyCode) + { + // for home/end, control key must be pressed too, but this is checked + // before here. + case Keys.Home: + ii = ii.FirstSibling; + break; + case Keys.End: + ii = ii.LastSibling; + break; + case Keys.PageDown: + ii = ii.NextItems == null ? null : ii.NextItems[0]; + break; + case Keys.PageUp: + ii = ii.MyPrevious; + break; + } + if (ii == null) return; + SelectedStepRTB = _LookupStepItems[ii.ItemID].MyStepRTB; + } + #endregion } [TypeConverter(typeof(ExpandableObjectConverter))] public partial class StepPanelSettings @@ -813,7 +958,7 @@ namespace Volian.Controls.Library private LinkText _MyLinkText; public LinkText MyLinkText { - get { return _MyLinkText; } + get { return _MyLinkText;} } public StepPanelLinkEventArgs(StepItem linkedStepItem, string linkInfoText) { diff --git a/PROMS/Volian.Controls.Library/StepRTB.cs b/PROMS/Volian.Controls.Library/StepRTB.cs index 5f3bc9b9..1f83f5bc 100644 --- a/PROMS/Volian.Controls.Library/StepRTB.cs +++ b/PROMS/Volian.Controls.Library/StepRTB.cs @@ -305,7 +305,7 @@ namespace Volian.Controls.Library } private void AddSymbol(string str) { - MessageBox.Show(SelectedRtf); + //MessageBox.Show(SelectedRtf); SelectedRtf = @"{\rtf1{\fonttbl{\f0\fcharset0 Arial Unicode MS;}}\f0\fs" + this.Font.SizeInPoints * 2 + " " + /* ConvertUnicodeChar(str) */ str + @"}"; } private void AddRtfLink(displayLinkElement myDisplayLinkElement) @@ -435,6 +435,7 @@ namespace Volian.Controls.Library } #endregion #region EventSupport + #region LinkEvents private StepPanelLinkEventArgs _MyLinkClickedEventArgs; public event StepRTBLinkEvent LinkChanged; @@ -486,7 +487,7 @@ namespace Volian.Controls.Library private bool IsControlChar = false; void StepRTB_KeyDown(object sender, KeyEventArgs e) { - if (e.Modifiers == Keys.Control) + if (e.Control) { IsControlChar = true; switch (e.KeyCode) @@ -496,59 +497,124 @@ namespace Volian.Controls.Library // check if insertable? Console.WriteLine(String.Format("in switch, keydata = {0}, keyvalue = {1}, buff = {2}", e.KeyData, e.KeyValue, buff)); + return; + case Keys.Home: + StepRTB_HomeEndPressed(e); + e.Handled = true; + break; + case Keys.End: + StepRTB_HomeEndPressed(e); + e.Handled = true; break; } } - else + switch (e.KeyCode) { - switch (e.KeyCode) - { - case Keys.Delete: - // if it's just a link, delete the link. if the text has embedded links, i.e. text and links - // use DeleteTextAndLink to delete it (just setting selectedrtf to "" fails because of the - // embedded protected text. If it's just text, let the richtextbox handle the delete. - if (_MyLinkText != null) + case Keys.Left: + if (e.Control || SelectionStart == 0) + { + StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlLeft : E_ArrowKeys.Left); + e.Handled = true; + } + break; + case Keys.Up: + int ln = GetLineFromCharIndex(SelectionStart); + if (e.Control || ln == 0) + { + StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlUp : E_ArrowKeys.Up); + e.Handled = true; + } + break; + case Keys.Right: + if (e.Control || SelectionStart == this.Text.Length) + { + StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlRight : E_ArrowKeys.Right); + e.Handled = true; + } + break; + case Keys.Down: + int l = GetLineFromCharIndex(SelectionStart); + Point pos = new Point(); + pos.X = ClientRectangle.Width; + pos.Y = ClientRectangle.Height; + int lastIndex = this.GetCharIndexFromPosition(pos); + int lastLine = this.GetLineFromCharIndex(lastIndex); + + if (e.Control || l == lastLine) + { + StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlDown : E_ArrowKeys.Down); + e.Handled = true; + } + break; + case Keys.PageUp: + StepRTB_PageKeyPressed(e); + e.Handled = true; + break; + case Keys.PageDown: + StepRTB_PageKeyPressed(e); + e.Handled = true; + break; + case Keys.Delete: + // if it's just a link, delete the link. if the text has embedded links, i.e. text and links + // use DeleteTextAndLink to delete it (just setting selectedrtf to "" fails because of the + // embedded protected text. If it's just text, let the richtextbox handle the delete. + if (_MyLinkText != null) + { + DeleteLink(); + e.Handled = true; + } + else if (SelectedRtf.IndexOf(@"\protect") > -1) + { + // unprotect and then delete text & links. + DeleteTextAndLink(); + e.Handled = true; + } + break; + case Keys.Back: + // if not a range, i.e. SelectionLength = 0, then see if backspacing a link + // or just regular text. If link, need to select link, unprotect before delete. + if (SelectionLength == 0 && SelectionStart > 0) + { + int tmpss = SelectionStart; + Select(SelectionStart - 1, 0); // see if previous char is protected + if (SelectionProtected) { + SelectLinkFromIndex(SelectionStart); DeleteLink(); e.Handled = true; } - else if (SelectedRtf.IndexOf(@"\protect") > -1) - { - // unprotect and then delete text & links. - DeleteTextAndLink(); - e.Handled = true; - } - break; - case Keys.Back: - // if not a range, i.e. SelectionLength = 0, then see if backspacing a link - // or just regular text. If link, need to select link, unprotect before delete. - if (SelectionLength == 0 && SelectionStart > 0) - { - int tmpss = SelectionStart; - Select(SelectionStart - 1, 0); // see if previous char is protected - if (SelectionProtected) - { - SelectLinkFromIndex(SelectionStart); - DeleteLink(); - e.Handled = true; - } - else - Select(tmpss, 0); // go back to original cursor position - } - // if a range, need to see if range includes protected text, if so this is a - // special case, so use DeleteTextAndLink. Otherwise, just let the richtextbox - // delete it. - else if (SelectionLength > 0 && (SelectedRtf.IndexOf(@"\protect") > -1)) - { - // unprotect and then delete text & links. - DeleteTextAndLink(); - e.Handled = true; - } - break; - } + else + Select(tmpss, 0); // go back to original cursor position + } + // if a range, need to see if range includes protected text, if so this is a + // special case, so use DeleteTextAndLink. Otherwise, just let the richtextbox + // delete it. + else if (SelectionLength > 0 && (SelectedRtf.IndexOf(@"\protect") > -1)) + { + // unprotect and then delete text & links. + DeleteTextAndLink(); + e.Handled = true; + } + break; } } - + private void StepRTB_HomeEndPressed(KeyEventArgs keyargs) + { + if (MyItemInfo.IsProcedure || MyItemInfo.IsSection) return; + // Cursor moves out of box only if control is pressed too - otherwise key is + // handled in rtb. + if (keyargs.Control)_MyStepItem.MyStepPanel.StepCursorKeys(this, keyargs); + } + private void StepRTB_PageKeyPressed(KeyEventArgs keyargs) + { + if (MyItemInfo.IsProcedure || MyItemInfo.IsSection) return; + _MyStepItem.MyStepPanel.StepCursorKeys(this, keyargs); + } + private void StepRTB_ArrowPressed(E_ArrowKeys key) + { + Point cp = PointToClient(Cursor.Position); + _MyStepItem.MyStepPanel.CursorMovement(this, cp, key); + } private void DeleteTextAndLink() { int start = SelectionStart;