mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-29 15:58:33 +01:00
Compare commits
5 commits
f5ff96d348
...
10bea0f820
Author | SHA1 | Date | |
---|---|---|---|
10bea0f820 | |||
f8ebbdacdf | |||
f5be677b83 | |||
d6ab8061f3 | |||
179afbc428 |
5 changed files with 140 additions and 20 deletions
|
@ -1,15 +1,15 @@
|
|||
# Changelog
|
||||
MLEM tries to adhere to [semantic versioning](https://semver.org/). Breaking changes are written in **bold**.
|
||||
MLEM tries to adhere to [semantic versioning](https://semver.org/). Potentially breaking changes are written in **bold**.
|
||||
|
||||
Jump to version:
|
||||
- [6.1.0](#610)
|
||||
- [6.1.0 (Unreleased)](#610-unreleased)
|
||||
- [6.0.0](#600)
|
||||
- [5.3.0](#530)
|
||||
- [5.2.0](#520)
|
||||
- [5.1.0](#510)
|
||||
- [5.0.0](#500)
|
||||
|
||||
## 6.1.0
|
||||
## 6.1.0 (Unreleased)
|
||||
|
||||
### MLEM
|
||||
Additions
|
||||
|
@ -69,6 +69,7 @@ Improvements
|
|||
- Set cornflower blue as the default link color
|
||||
- Added TextField.OnCopyPasteException to allow handling exceptions thrown by TextCopy
|
||||
- Avoid paragraphs splitting or truncating their text unnecessarily
|
||||
- Automatically mark elements dirty when various member values are changed
|
||||
|
||||
Fixes
|
||||
- Fixed parents of elements that prevent spill not being notified properly
|
||||
|
|
|
@ -46,7 +46,13 @@ namespace MLEM.Ui.Elements {
|
|||
/// <summary>
|
||||
/// The width of the space between this checkbox and its <see cref="Label"/>
|
||||
/// </summary>
|
||||
public StyleProp<float> TextOffsetX;
|
||||
public StyleProp<float> TextOffsetX {
|
||||
get => this.textOffsetX;
|
||||
set {
|
||||
this.textOffsetX = value;
|
||||
this.SetAreaDirty();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether or not this checkbox is currently checked.
|
||||
/// </summary>
|
||||
|
@ -80,6 +86,7 @@ namespace MLEM.Ui.Elements {
|
|||
public override bool CanBePressed => base.CanBePressed && !this.IsDisabled;
|
||||
|
||||
private bool isChecked;
|
||||
private StyleProp<float> textOffsetX;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new checkbox with the given settings
|
||||
|
|
|
@ -233,34 +233,82 @@ namespace MLEM.Ui.Elements {
|
|||
/// <summary>
|
||||
/// Set this field to false to cause auto-anchored siblings to ignore this element as a possible anchor point.
|
||||
/// </summary>
|
||||
public virtual bool CanAutoAnchorsAttach { get; set; } = true;
|
||||
public virtual bool CanAutoAnchorsAttach {
|
||||
get => this.canAutoAnchorsAttach;
|
||||
set {
|
||||
if (this.canAutoAnchorsAttach != value) {
|
||||
this.canAutoAnchorsAttach = value;
|
||||
this.SetAreaDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Set this field to true to cause this element's width to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
||||
/// To use this element's <see cref="Size"/>'s X coordinate as a minimum or maximum width rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> or <see cref="TreatSizeAsMaximum"/> to true.
|
||||
/// </summary>
|
||||
public virtual bool SetWidthBasedOnChildren { get; set; }
|
||||
public virtual bool SetWidthBasedOnChildren {
|
||||
get => this.setWidthBasedOnChildren;
|
||||
set {
|
||||
if (this.setWidthBasedOnChildren != value) {
|
||||
this.setWidthBasedOnChildren = value;
|
||||
this.SetAreaDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Set this field to true to cause this element's height to be automatically calculated based on the area that its <see cref="Children"/> take up.
|
||||
/// To use this element's <see cref="Size"/>'s Y coordinate as a minimum or maximum height rather than ignoring it, set <see cref="TreatSizeAsMinimum"/> or <see cref="TreatSizeAsMaximum"/> to true.
|
||||
/// </summary>
|
||||
public virtual bool SetHeightBasedOnChildren { get; set; }
|
||||
public virtual bool SetHeightBasedOnChildren {
|
||||
get => this.setHeightBasedOnChildren;
|
||||
set {
|
||||
if (this.setHeightBasedOnChildren != value) {
|
||||
this.setHeightBasedOnChildren = value;
|
||||
this.SetAreaDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// If this field is set to true, and <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled, the resulting width or height will always be greather than or equal to this element's <see cref="Size"/>.
|
||||
/// For example, if an element's <see cref="Size"/>'s Y coordinate is set to 20, but there is only one child with a height of 10 in it, the element's height would be shrunk to 10 if this value was false, but would remain at 20 if it was true.
|
||||
/// Note that this value only has an effect if <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled.
|
||||
/// </summary>
|
||||
public virtual bool TreatSizeAsMinimum { get; set; }
|
||||
public virtual bool TreatSizeAsMinimum {
|
||||
get => this.treatSizeAsMinimum;
|
||||
set {
|
||||
if (this.treatSizeAsMinimum != value) {
|
||||
this.treatSizeAsMinimum = value;
|
||||
this.SetAreaDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// If this field is set to true, and <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/>are enabled, the resulting width or height weill always be less than or equal to this element's <see cref="Size"/>.
|
||||
/// Note that this value only has an effect if <see cref="SetWidthBasedOnChildren"/> or <see cref="SetHeightBasedOnChildren"/> are enabled.
|
||||
/// </summary>
|
||||
public virtual bool TreatSizeAsMaximum { get; set; }
|
||||
public virtual bool TreatSizeAsMaximum {
|
||||
get => this.treatSizeAsMaximum;
|
||||
set {
|
||||
if (this.treatSizeAsMaximum != value) {
|
||||
this.treatSizeAsMaximum = value;
|
||||
this.SetAreaDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Set this field to true to cause this element's final display area to never exceed that of its <see cref="Parent"/>.
|
||||
/// If the resulting area is too large, the size of this element is shrunk to fit the target area.
|
||||
/// This can be useful if an element should fill the remaining area of a parent exactly.
|
||||
/// </summary>
|
||||
public virtual bool PreventParentSpill { get; set; }
|
||||
public virtual bool PreventParentSpill {
|
||||
get => this.preventParentSpill;
|
||||
set {
|
||||
if (this.preventParentSpill != value) {
|
||||
this.preventParentSpill = value;
|
||||
this.SetAreaDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The transparency (alpha value) that this element is rendered with.
|
||||
/// Note that, when <see cref="Draw(Microsoft.Xna.Framework.GameTime,Microsoft.Xna.Framework.Graphics.SpriteBatch,float,MLEM.Graphics.SpriteBatchContext)"/> is called, this alpha value is multiplied with the <see cref="Parent"/>'s alpha value and passed down to this element's <see cref="Children"/>.
|
||||
|
@ -470,6 +518,12 @@ namespace MLEM.Ui.Elements {
|
|||
private StyleProp<UiStyle> style;
|
||||
private StyleProp<Padding> childPadding;
|
||||
private bool canBeSelected = true;
|
||||
private bool canAutoAnchorsAttach = true;
|
||||
private bool setWidthBasedOnChildren;
|
||||
private bool setHeightBasedOnChildren;
|
||||
private bool treatSizeAsMinimum;
|
||||
private bool treatSizeAsMaximum;
|
||||
private bool preventParentSpill;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new element with the given anchor and size and sets up some default event reactions.
|
||||
|
|
|
@ -46,7 +46,13 @@ namespace MLEM.Ui.Elements {
|
|||
/// <summary>
|
||||
/// The amount of pixels of room there should be between the <see cref="ScrollBar"/> and the rest of the content
|
||||
/// </summary>
|
||||
public StyleProp<float> ScrollBarOffset;
|
||||
public StyleProp<float> ScrollBarOffset {
|
||||
get => this.scrollBarOffset;
|
||||
set {
|
||||
this.scrollBarOffset = value;
|
||||
this.SetAreaDirty();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<Element> relevantChildren = new List<Element>();
|
||||
private readonly bool scrollOverflow;
|
||||
|
@ -54,6 +60,7 @@ namespace MLEM.Ui.Elements {
|
|||
private RenderTarget2D renderTarget;
|
||||
private bool relevantChildrenDirty;
|
||||
private float scrollBarChildOffset;
|
||||
private StyleProp<float> scrollBarOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new panel with the given settings.
|
||||
|
|
|
@ -47,12 +47,26 @@ namespace MLEM.Ui.Elements {
|
|||
/// The scale that the text will be rendered with.
|
||||
/// To add a multiplier rather than changing the scale directly, use <see cref="TextScaleMultiplier"/>.
|
||||
/// </summary>
|
||||
public StyleProp<float> TextScale;
|
||||
public StyleProp<float> TextScale {
|
||||
get => this.textScale;
|
||||
set {
|
||||
this.textScale = value;
|
||||
this.SetTextDirty();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// A multiplier that will be applied to <see cref="TextScale"/>.
|
||||
/// To change the text scale itself, use <see cref="TextScale"/>.
|
||||
/// </summary>
|
||||
public float TextScaleMultiplier = 1;
|
||||
public float TextScaleMultiplier {
|
||||
get => this.textScaleMultiplier;
|
||||
set {
|
||||
if (this.textScaleMultiplier != value) {
|
||||
this.textScaleMultiplier = value;
|
||||
this.SetTextDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The text to render inside of this paragraph.
|
||||
/// Use <see cref="GetTextCallback"/> if the text changes frequently.
|
||||
|
@ -62,22 +76,49 @@ namespace MLEM.Ui.Elements {
|
|||
this.CheckTextChange();
|
||||
return this.displayedText;
|
||||
}
|
||||
set => this.explicitlySetText = value;
|
||||
set {
|
||||
this.explicitlySetText = value;
|
||||
this.CheckTextChange();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// If this paragraph should automatically adjust its width based on the width of the text within it
|
||||
/// </summary>
|
||||
public bool AutoAdjustWidth;
|
||||
public bool AutoAdjustWidth {
|
||||
get => this.autoAdjustWidth;
|
||||
set {
|
||||
if (this.autoAdjustWidth != value) {
|
||||
this.autoAdjustWidth = value;
|
||||
this.SetAreaDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether this paragraph should be truncated instead of split if the displayed <see cref="Text"/>'s width exceeds the provided width.
|
||||
/// When the string is truncated, the <see cref="Ellipsis"/> is added to its end.
|
||||
/// </summary>
|
||||
public bool TruncateIfLong;
|
||||
public bool TruncateIfLong {
|
||||
get => this.truncateIfLong;
|
||||
set {
|
||||
if (this.truncateIfLong != value) {
|
||||
this.truncateIfLong = value;
|
||||
this.SetAlignSplitDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The ellipsis characters to use if <see cref="TruncateIfLong"/> is enabled and the string is truncated.
|
||||
/// If this is set to an empty string, no ellipsis will be attached to the truncated string.
|
||||
/// </summary>
|
||||
public string Ellipsis = "...";
|
||||
public string Ellipsis {
|
||||
get => this.ellipsis;
|
||||
set {
|
||||
if (this.ellipsis != value) {
|
||||
this.ellipsis = value;
|
||||
this.SetAlignSplitDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// An event that gets called when this paragraph's <see cref="Text"/> is queried.
|
||||
/// Use this event for setting this paragraph's text if it changes frequently.
|
||||
|
@ -106,9 +147,14 @@ namespace MLEM.Ui.Elements {
|
|||
private string explicitlySetText;
|
||||
private StyleProp<TextAlignment> alignment;
|
||||
private StyleProp<GenericFont> regularFont;
|
||||
private StyleProp<float> textScale;
|
||||
private TokenizedString tokenizedText;
|
||||
private float? lastAlignSplitWidth;
|
||||
private float? lastAlignSplitScale;
|
||||
private string ellipsis = "...";
|
||||
private bool truncateIfLong;
|
||||
private float textScaleMultiplier = 1;
|
||||
private bool autoAdjustWidth;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new paragraph with the given settings.
|
||||
|
@ -132,6 +178,7 @@ namespace MLEM.Ui.Elements {
|
|||
/// <inheritdoc />
|
||||
protected override Vector2 CalcActualSize(RectangleF parentArea) {
|
||||
var size = base.CalcActualSize(parentArea);
|
||||
this.CheckTextChange();
|
||||
this.TokenizeIfNecessary();
|
||||
this.AlignAndSplitIfNecessary(size);
|
||||
var textSize = this.tokenizedText.GetArea(Vector2.Zero, this.TextScale * this.TextScaleMultiplier * this.Scale).Size;
|
||||
|
@ -140,8 +187,8 @@ namespace MLEM.Ui.Elements {
|
|||
|
||||
/// <inheritdoc />
|
||||
public override void Update(GameTime time) {
|
||||
base.Update(time);
|
||||
this.TokenizedText?.Update(time);
|
||||
base.Update(time);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -196,8 +243,7 @@ namespace MLEM.Ui.Elements {
|
|||
|
||||
// tokenize the text
|
||||
this.tokenizedText = this.System.TextFormatter.Tokenize(this.RegularFont, this.Text, this.Alignment);
|
||||
this.lastAlignSplitWidth = null;
|
||||
this.lastAlignSplitScale = null;
|
||||
this.SetAlignSplitDirty();
|
||||
|
||||
// add links to the paragraph
|
||||
this.RemoveChildren(c => c is Link);
|
||||
|
@ -221,6 +267,11 @@ namespace MLEM.Ui.Elements {
|
|||
}
|
||||
}
|
||||
|
||||
private void SetAlignSplitDirty() {
|
||||
this.lastAlignSplitWidth = null;
|
||||
this.lastAlignSplitScale = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate method used for <see cref="Paragraph.GetTextCallback"/>
|
||||
/// </summary>
|
||||
|
|
Loading…
Reference in a new issue