/// <summary> /// Draw the entity. /// </summary> /// <param name="spriteBatch">Sprite batch to draw on.</param> override protected void DrawEntity(SpriteBatch spriteBatch) { // if size changed, update paragraphs list if ((_prevSize.Y != _destRectInternal.Size.Y) || _hadResizeWhileNotVisible) { OnResize(); } // store last known size _prevSize = _destRectInternal.Size; // call base draw function to draw the panel part base.DrawEntity(spriteBatch); // update paragraphs list values for (int i = 0; i < _paragraphs.Count; ++i) { // if paragraph is within items range: int item_index = i + (int)_scrollbar.Value; if (item_index < _list.Count) { // set paragraph text, make visible, and remove background. _paragraphs[i].Text = _list[item_index]; _paragraphs[i].Background = null; _paragraphs[i].Visible = true; // set locked state bool isLocked = false; LockedItems.TryGetValue(item_index, out isLocked); _paragraphs[i].Locked = isLocked; } // if paragraph out of range (eg more paragraphs than list items), make this paragraph invisible. else { _paragraphs[i].Visible = false; _paragraphs[i].Text = string.Empty; } } // highlight the currently selected item paragraph (eg the paragraph that represent the selected value, if currently visible) int selectedParagraphIndex = _index; if (selectedParagraphIndex != -1) { int i = selectedParagraphIndex - _scrollbar.Value; if (i >= 0 && i < _paragraphs.Count) { // add background to selected paragraph Paragraph paragraph = _paragraphs[i]; Rectangle destRect = paragraph.GetActualDestRect(); Vector2 size = new Vector2(0, destRect.Height * 1.35f / UserInterface.Active.GlobalScale); paragraph.State = EntityState.MouseDown; paragraph.Padding = new Vector2(-Padding.X, 0); paragraph.CalcDestRect(); paragraph.CalcInternalRect(); ColoredRectangle selectMark = new ColoredRectangle(GetActiveStyle("SelectedHighlightColor").asColor, size, Anchor.TopCenter, new Vector2(0, -4)); paragraph.Background = selectMark; } } }
/// <summary> /// Validate current text input after change (usually addition of text). /// </summary> /// <param name="newVal">New text value, to check validity.</param> /// <param name="oldVal">Previous text value, before the change.</param> /// <returns>True if new input is valid, false otherwise.</returns> private bool ValidateInput(ref string newVal, List <bool> modifiers, int pos, string oldVal) { // if new characters were added, and we now exceed characters limit, revet to previous value. if (CharactersLimit != 0 && newVal.Length > CharactersLimit) { newVal = oldVal; return(false); } // if not multiline and got line break, revet to previous value if (!_multiLine && newVal.Contains("\n")) { newVal = oldVal; return(false); } if (pos > 0 && pos <= newVal.Length && newVal[pos - 1] == '\n' && modifiers[pos - 1] != true) //only accept shift enter, not enter { newVal = oldVal; return(false); } // if set to limit by size make sure we don't exceed it if (LimitBySize) { // prepare display PrepareInputTextForDisplay(false, false); // get main paragraph actual size Rectangle textSize = TextParagraph.GetActualDestRect(); // if multiline, compare heights if (_multiLine && textSize.Height >= _destRectInternal.Height) { newVal = oldVal; return(false); } // if single line, compare widths else if (textSize.Width >= _destRectInternal.Width) { newVal = oldVal; return(false); } } // if got here we iterate over additional validators foreach (var validator in Validators) { if (!validator.ValidateText(ref newVal, oldVal)) { newVal = oldVal; return(false); } } // looks good! return(true); }
/// <summary> /// When list is resized (also called on init), create the labels to show item values and init graphical stuff. /// </summary> /// <param name="recalcDestRect">If true, will also recalculate destination rectangle.</param> protected virtual void OnResize(bool recalcDestRect = true) { // store current size _prevSize = _size; // remove all children before re-creating them ClearChildren(); // remove previous paragraphs list _paragraphs.Clear(); // calculate self destination rect if (recalcDestRect) { _destRect = CalcDestRect(); } // calculate paragraphs quantity int i = 0; while (true) { // create and add new paragraph Paragraph paragraph = new Paragraph(".", Anchor.Auto, new Vector2(0, 40)); // note: we set negative padding for the selected mark size so it won't be negative size paragraph.WrapWords = false; paragraph.UpdateStyle(DefaultParagraphStyle); paragraph.Scale = paragraph.Scale * ItemsScale; paragraph.SpaceAfter = paragraph.SpaceAfter + new Vector2(0, ExtraSpaceBetweenLines); paragraph.AttachedData = new ParagraphData(this, i++); paragraph.UseActualSizeForCollision = false; AddChild(paragraph); _paragraphs.Add(paragraph); OnCreatedListParagraph(paragraph); // add callback to selection paragraph.OnClick = (Entity entity) => { ParagraphData data = (ParagraphData)entity.AttachedData; if (!data.list.LockSelection) { data.list.Select(data.relativeIndex, true); } }; // to calculate paragraph actual bottom paragraph.CalcDestRect(); paragraph.PrepareForDraw(); // if out of list bounderies remove this paragraph and stop if ((paragraph.GetActualDestRect().Bottom > _destRect.Bottom - Padding.Y) || i > _list.Count) { RemoveChild(paragraph); _paragraphs.Remove(paragraph); break; } } // add scrollbar last, but only if needed if (_paragraphs.Count < _list.Count) { // add scrollbar to list AddChild(_scrollbar, false); // calc max scroll value _scrollbar.Max = (uint)(_list.Count - _paragraphs.Count); if (_scrollbar.Max < 2) { _scrollbar.Max = 2; } _scrollbar.StepsCount = _scrollbar.Max; _scrollbar.Visible = true; } // if no scrollbar is needed, hide it else { _scrollbar.Visible = false; if (_scrollbar.Value > 0) { _scrollbar.Value = 0; } } }
/// <summary> /// Draw the entity. /// </summary> /// <param name="spriteBatch">Sprite batch to draw on.</param> /// <param name="phase">The phase we are currently drawing.</param> override protected void DrawEntity(SpriteBatch spriteBatch, DrawPhase phase) { // if size changed, update paragraphs list if ((_prevSize.Y != _destRectInternal.Size.Y) || _hadResizeWhileNotVisible) { OnResize(); } // store last known size _prevSize = _destRectInternal.Size; // call base draw function to draw the panel part base.DrawEntity(spriteBatch, phase); // update paragraphs list values for (int i = 0; i < _paragraphs.Count; ++i) { // get item index int item_index = i + (int)_scrollbar.Value; // get current paragraph var par = _paragraphs[i]; // if we got an item to show for this paragraph index: if (item_index < _list.Count) { // set paragraph text, make visible, and remove background. par.Text = _list[item_index]; par.BackgroundColor.A = 0; par.Visible = true; // check if we need to trim size if (ClipTextIfOverflow) { // get width we need to clip and if we need to clip at all var charWidth = par.GetCharacterActualSize().X; var toClip = (charWidth * par.Text.Length) - _destRectInternal.Width; if (toClip > 0) { // calc how many chars we need to remove var charsToClip = (int)System.Math.Ceiling(toClip / charWidth) + AddWhenClipping.Length + 1; // remove them from text if (charsToClip < par.Text.Length) { par.Text = par.Text.Substring(0, par.Text.Length - charsToClip) + AddWhenClipping; } else { par.Text = AddWhenClipping; } } } // set locked state bool isLocked = false; LockedItems.TryGetValue(item_index, out isLocked); par.Locked = isLocked; } // if paragraph out of range (eg more paragraphs than list items), make this paragraph invisible. else { par.Visible = false; par.Text = string.Empty; } } // highlight the currently selected item paragraph (eg the paragraph that represent the selected value, if currently visible) int selectedParagraphIndex = _index; if (selectedParagraphIndex != -1) { int i = selectedParagraphIndex - _scrollbar.Value; if (i >= 0 && i < _paragraphs.Count) { // add background to selected paragraph Paragraph paragraph = _paragraphs[i]; Rectangle destRect = paragraph.GetActualDestRect(); paragraph.State = EntityState.MouseDown; paragraph.BackgroundColor = GetActiveStyle("SelectedHighlightColor").asColor; } } }
/// <summary> /// When list is resized (also called on init), create the labels to show item values and init graphical stuff. /// </summary> protected virtual void OnResize() { // if not visible, skip if (!IsVisible()) { _hadResizeWhileNotVisible = true; return; } // clear the _hadResizeWhileNotVisible flag _hadResizeWhileNotVisible = false; // remove all children before re-creating them ClearChildren(); // remove previous paragraphs list _paragraphs.Clear(); // make sure destination rect is up-to-date UpdateDestinationRects(); // calculate paragraphs quantity int i = 0; while (true) { // create and add new paragraph Paragraph paragraph = UserInterface.DefaultParagraph(".", Anchor.Auto); paragraph.PromiscuousClicksMode = true; paragraph.WrapWords = false; paragraph.UpdateStyle(DefaultParagraphStyle); paragraph.Scale = paragraph.Scale * ItemsScale; paragraph.SpaceAfter = paragraph.SpaceAfter + new Vector2(0, ExtraSpaceBetweenLines - 2); paragraph.ExtraMargin.Y = ExtraSpaceBetweenLines / 2 + 3; paragraph.AttachedData = new ParagraphData(this, i++); paragraph.UseActualSizeForCollision = false; paragraph.Size = new Vector2(0, paragraph.GetCharacterActualSize().Y + ExtraSpaceBetweenLines); paragraph.BackgroundColorPadding = new Point((int)Padding.X, 5); paragraph.BackgroundColorUseBoxSize = true; paragraph._hiddenInternalEntity = true; paragraph.PropagateEventsTo(this); AddChild(paragraph); // call the callback whenever a new paragraph is created OnCreatedListParagraph(paragraph); // add to paragraphs list _paragraphs.Add(paragraph); // add callback to selection paragraph.OnClick += (Entity entity) => { ParagraphData data = (ParagraphData)entity.AttachedData; if (!data.list.LockSelection) { data.list.Select(data.relativeIndex, true); } }; // to calculate paragraph actual bottom paragraph.UpdateDestinationRects(); // if out of list bounderies remove this paragraph and stop if ((paragraph.GetActualDestRect().Bottom > _destRect.Bottom - _scaledPadding.Y) || i > _list.Count) { RemoveChild(paragraph); _paragraphs.Remove(paragraph); break; } } // add scrollbar last, but only if needed if (_paragraphs.Count > 0 && _paragraphs.Count < _list.Count) { // add scrollbar to list AddChild(_scrollbar, false); // calc max scroll value _scrollbar.Max = (uint)(_list.Count - _paragraphs.Count); if (_scrollbar.Max < 2) { _scrollbar.Max = 2; } _scrollbar.StepsCount = _scrollbar.Max; _scrollbar.Visible = true; } // if no scrollbar is needed, hide it else { _scrollbar.Visible = false; if (_scrollbar.Value > 0) { _scrollbar.Value = 0; } } }