2017-07-07 12:10:24 -07:00
|
|
|
|
/*
|
2017-11-08 23:24:10 -08:00
|
|
|
|
Copyright (c) 2017, Lars Brubaker, John Lewin
|
2017-07-07 12:10:24 -07:00
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
|
|
|
|
1. Redistributions of source code must retain the above copyright notice, this
|
|
|
|
|
|
list of conditions and the following disclaimer.
|
|
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
|
|
this list of conditions and the following disclaimer in the documentation
|
|
|
|
|
|
and/or other materials provided with the distribution.
|
|
|
|
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
|
|
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
|
|
|
|
The views and conclusions contained in the software and documentation are those
|
|
|
|
|
|
of the authors and should not be interpreted as representing official policies,
|
|
|
|
|
|
either expressed or implied, of the FreeBSD Project.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using MatterHackers.Agg;
|
|
|
|
|
|
using MatterHackers.Agg.UI;
|
|
|
|
|
|
|
|
|
|
|
|
namespace MatterHackers.MatterControl.CustomWidgets
|
|
|
|
|
|
{
|
2017-11-08 23:24:10 -08:00
|
|
|
|
public class InlineEditControl : GuiWidget
|
2017-07-07 12:10:24 -07:00
|
|
|
|
{
|
|
|
|
|
|
private TextWidget numberDisplay;
|
|
|
|
|
|
private NumberEdit numberEdit;
|
|
|
|
|
|
|
2017-11-08 23:24:10 -08:00
|
|
|
|
public InlineEditControl(string defaultSizeString = "-0000.00", Agg.Font.Justification justification = Agg.Font.Justification.Left)
|
2017-07-07 12:10:24 -07:00
|
|
|
|
{
|
2017-12-29 13:34:43 -08:00
|
|
|
|
base.Visible = false;
|
|
|
|
|
|
|
2017-07-07 12:10:24 -07:00
|
|
|
|
double pointSize = 12;
|
2018-03-29 17:58:17 -07:00
|
|
|
|
|
2017-07-07 16:50:47 -07:00
|
|
|
|
numberDisplay = new TextWidget(defaultSizeString, 0, 0, pointSize, justification: justification)
|
2017-07-07 12:10:24 -07:00
|
|
|
|
{
|
2017-12-29 13:34:43 -08:00
|
|
|
|
Visible = false,
|
2017-08-07 15:47:27 -07:00
|
|
|
|
VAnchor = VAnchor.Bottom,
|
|
|
|
|
|
HAnchor = HAnchor.Left,
|
2017-07-07 12:10:24 -07:00
|
|
|
|
Text = "0",
|
|
|
|
|
|
};
|
|
|
|
|
|
AddChild(numberDisplay);
|
2018-03-29 17:58:17 -07:00
|
|
|
|
|
2017-07-07 12:10:24 -07:00
|
|
|
|
numberEdit = new NumberEdit(0, 50, 50, pointSize, pixelWidth: numberDisplay.Width, allowNegatives: true, allowDecimals: true)
|
|
|
|
|
|
{
|
|
|
|
|
|
Visible = false,
|
2017-08-07 15:47:27 -07:00
|
|
|
|
VAnchor = VAnchor.Bottom,
|
|
|
|
|
|
HAnchor = HAnchor.Left,
|
2017-07-07 12:10:24 -07:00
|
|
|
|
SelectAllOnFocus = true,
|
|
|
|
|
|
};
|
|
|
|
|
|
numberEdit.InternalNumberEdit.TextChanged += (s, e) =>
|
|
|
|
|
|
{
|
2017-09-06 18:16:45 -07:00
|
|
|
|
numberDisplay.Text = GetDisplayString == null ? "None" : GetDisplayString.Invoke(Value);
|
2017-07-07 12:10:24 -07:00
|
|
|
|
base.OnTextChanged(e);
|
|
|
|
|
|
};
|
|
|
|
|
|
numberEdit.InternalNumberEdit.MaxDecimalsPlaces = 2;
|
|
|
|
|
|
|
|
|
|
|
|
numberEdit.EditComplete += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
EditComplete?.Invoke(this, e);
|
|
|
|
|
|
timeSinceMouseUp.Restart();
|
|
|
|
|
|
numberEdit.Visible = false;
|
|
|
|
|
|
numberDisplay.Visible = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
AddChild(numberEdit);
|
|
|
|
|
|
|
2017-08-07 15:47:27 -07:00
|
|
|
|
VAnchor = VAnchor.Fit;
|
|
|
|
|
|
HAnchor = HAnchor.Fit;
|
2017-07-07 12:10:24 -07:00
|
|
|
|
|
2018-11-16 08:44:56 -08:00
|
|
|
|
runningInterval = UiThread.SetInterval(HideIfApplicable, .1);
|
2017-07-07 12:10:24 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-03-29 13:38:37 -07:00
|
|
|
|
public Color TextColor { get; set; } = Color.Black;
|
|
|
|
|
|
|
2017-07-07 12:10:24 -07:00
|
|
|
|
public event EventHandler EditComplete;
|
|
|
|
|
|
|
|
|
|
|
|
public bool Editing
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2018-03-29 16:03:03 -07:00
|
|
|
|
return this.Visible && ((numberEdit.Visible && numberEdit.ContainsFocus) || this.UnderMouseState != UnderMouseState.NotUnderMouse);
|
2017-07-07 12:10:24 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Func<bool> ForceHide { get; set; }
|
|
|
|
|
|
|
2018-04-04 17:52:58 -07:00
|
|
|
|
private Func<double, string> _getDisplayString = (value) => "{0:0.0}".FormatWith(value);
|
2018-11-16 08:44:56 -08:00
|
|
|
|
private RunningInterval runningInterval;
|
|
|
|
|
|
|
2017-07-07 12:52:00 -07:00
|
|
|
|
public Func<double, string> GetDisplayString
|
|
|
|
|
|
{
|
2018-04-04 17:52:58 -07:00
|
|
|
|
get => _getDisplayString;
|
2017-07-07 12:52:00 -07:00
|
|
|
|
set
|
|
|
|
|
|
{
|
2018-04-04 17:52:58 -07:00
|
|
|
|
_getDisplayString = value;
|
|
|
|
|
|
if (_getDisplayString != null)
|
2017-07-07 12:52:00 -07:00
|
|
|
|
{
|
2018-04-04 17:52:58 -07:00
|
|
|
|
numberDisplay.Text = _getDisplayString?.Invoke(Value);
|
2017-07-07 12:52:00 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-07-07 12:10:24 -07:00
|
|
|
|
public double Value
|
|
|
|
|
|
{
|
2018-04-04 17:52:58 -07:00
|
|
|
|
get => numberEdit.Value;
|
2017-07-07 12:10:24 -07:00
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!numberEdit.ContainsFocus
|
|
|
|
|
|
&& numberEdit.Value != value)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeSinceMouseUp.Restart();
|
|
|
|
|
|
numberEdit.Value = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override bool Visible
|
|
|
|
|
|
{
|
|
|
|
|
|
get => base.Visible;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (value)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeSinceMouseUp.Restart();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
timeSinceMouseUp.Reset();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-07-07 12:52:00 -07:00
|
|
|
|
if (base.Visible != value)
|
|
|
|
|
|
{
|
|
|
|
|
|
base.Visible = value;
|
2018-04-04 17:52:58 -07:00
|
|
|
|
this.StopEditing();
|
2017-07-07 12:52:00 -07:00
|
|
|
|
}
|
2017-07-07 12:10:24 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-04 17:52:58 -07:00
|
|
|
|
public void StopEditing()
|
|
|
|
|
|
{
|
|
|
|
|
|
numberEdit.Visible = false;
|
|
|
|
|
|
numberDisplay.Visible = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-07-07 12:10:24 -07:00
|
|
|
|
protected double SecondsToShowNumberEdit { get; private set; } = 4;
|
2018-04-04 17:52:58 -07:00
|
|
|
|
|
2017-07-07 12:10:24 -07:00
|
|
|
|
protected Stopwatch timeSinceMouseUp { get; private set; } = new Stopwatch();
|
|
|
|
|
|
|
|
|
|
|
|
public override void OnDraw(Graphics2D graphics2D)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (UnderMouseState == UnderMouseState.UnderMouseNotFirst
|
|
|
|
|
|
|| UnderMouseState == UnderMouseState.FirstUnderMouse)
|
|
|
|
|
|
{
|
2017-10-31 11:43:25 -07:00
|
|
|
|
numberDisplay.TextColor = Color.Red;
|
2017-07-07 12:10:24 -07:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2018-03-29 13:38:37 -07:00
|
|
|
|
numberDisplay.TextColor = this.TextColor;
|
2017-07-07 12:10:24 -07:00
|
|
|
|
}
|
|
|
|
|
|
base.OnDraw(graphics2D);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void OnMouseDown(MouseEventArgs mouseEvent)
|
|
|
|
|
|
{
|
2017-08-21 16:14:38 -07:00
|
|
|
|
if (mouseEvent.Button == MouseButtons.Left
|
|
|
|
|
|
&& (UnderMouseState == UnderMouseState.UnderMouseNotFirst
|
|
|
|
|
|
|| UnderMouseState == UnderMouseState.FirstUnderMouse))
|
2017-07-07 12:10:24 -07:00
|
|
|
|
{
|
|
|
|
|
|
numberEdit.Visible = true;
|
|
|
|
|
|
numberDisplay.Visible = false;
|
|
|
|
|
|
numberEdit.Focus();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
base.OnMouseDown(mouseEvent);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-16 08:44:56 -08:00
|
|
|
|
public override void OnClosed(EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Unregister listeners
|
|
|
|
|
|
UiThread.ClearInterval(runningInterval);
|
|
|
|
|
|
|
|
|
|
|
|
base.OnClosed(e);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-03-29 17:58:17 -07:00
|
|
|
|
private void HideIfApplicable()
|
2017-07-07 12:10:24 -07:00
|
|
|
|
{
|
2018-03-29 17:58:17 -07:00
|
|
|
|
if (this.Visible)
|
2017-07-07 12:10:24 -07:00
|
|
|
|
{
|
2018-03-29 17:58:17 -07:00
|
|
|
|
if (!this.Editing
|
|
|
|
|
|
&& timeSinceMouseUp.IsRunning
|
|
|
|
|
|
&& timeSinceMouseUp.ElapsedMilliseconds > SecondsToShowNumberEdit * 1000)
|
2017-07-07 12:10:24 -07:00
|
|
|
|
{
|
2018-03-29 17:58:17 -07:00
|
|
|
|
Visible = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (this.ForceHide?.Invoke() == true)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Hide if custom ForceHide implementations say to do so
|
|
|
|
|
|
this.Visible = false;
|
2017-07-07 12:10:24 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|