1254 lines
53 KiB
C#
1254 lines
53 KiB
C#
///
|
|
/// Copyright (c) 2023 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using log4net;
|
|
using Common;
|
|
using Results.Entities;
|
|
using TBF.Rig.GenericDevices;
|
|
using TBF.Resources;
|
|
using System.Threading;
|
|
using System.IO;
|
|
using static System.Net.Mime.MediaTypeNames;
|
|
|
|
namespace TBF.Rig.DataEntry.Uni
|
|
{
|
|
public partial class TestStartEndForm : Form, GenericDevices.IHasCompleted
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(TestStartEndForm));
|
|
|
|
const int PicSize = 480;
|
|
|
|
///
|
|
/// Static members and constructor
|
|
///
|
|
static int wmNr0b;
|
|
static Rotation imageRotation;
|
|
static bool[] isZoomed;
|
|
static Point[] zoomCenterLoc;
|
|
///
|
|
static TestStartEndForm()
|
|
{
|
|
wmNr0b = 0;
|
|
//imageRotation = new Rotation[40];
|
|
isZoomed = new bool[40];
|
|
zoomCenterLoc = new Point[40];
|
|
}
|
|
|
|
|
|
/// Arguments
|
|
public readonly IList<WaterMeter> waterMeters;
|
|
readonly IRegReader[] regReaders;
|
|
readonly int lineSize;
|
|
readonly FontSz sz;
|
|
readonly bool isStartBoxAlwaysEn;
|
|
readonly bool isLrOrder; /// true = controls obtain focus after ENTER key in left-right order, false = top-down order
|
|
readonly IList<DEItem> colItems;
|
|
readonly bool isCompound;
|
|
readonly string formCloseKeys;
|
|
public readonly string[] WMStartStateStr;
|
|
readonly bool isCameraPicture; /// true = camera picture displayed on the left side
|
|
readonly string[] startImages;
|
|
readonly string[] endImages;
|
|
readonly OcrVidi ocrVidi;
|
|
readonly string ocrMessage;
|
|
readonly string streamName;
|
|
readonly double refVolume;
|
|
readonly double warningLimLo; /// limit to display exclamation mark, typically 2x errLimLo
|
|
readonly double warningLimHi; /// limit to display exclamation mark, typically 2x errLimHi
|
|
|
|
/// Derived from arguments in the constructor
|
|
readonly bool isEnd;
|
|
readonly Tst mode; /// Start, End or Deferred
|
|
readonly WaterMeter firstValidWM;
|
|
readonly int wmsCount;
|
|
readonly int linesCount;
|
|
readonly bool fixedErrorLimits; /// false in case of calculated error limits
|
|
|
|
/// To be retrieved after the form closes
|
|
public double[] WMStartState;
|
|
public double[] WMEndState;
|
|
public Unit VolumeUnit;
|
|
int startStateColumn;
|
|
int startStateColumnAux;
|
|
int endStateColumn;
|
|
int endStateColumnAux;
|
|
|
|
/// Size and layout related values
|
|
readonly int meterHeight;
|
|
readonly int meterWidth;
|
|
readonly int margin;
|
|
readonly int spacing;
|
|
readonly int hdrHeight;
|
|
readonly int labelWid;
|
|
readonly int checkBoxWid;
|
|
|
|
/// UI elements
|
|
readonly Label[] labels; /// Labels for water meter numbers
|
|
readonly TextBox[,] textBoxes; /// Text boxes for values in columns
|
|
readonly Label[] exclamations;
|
|
|
|
/// Picture box related
|
|
PictureBox pictureBox1;
|
|
Label imageProcessingProgressLabel;
|
|
ProgressBar imageProcessingProgressBar;
|
|
|
|
string lastImageName;
|
|
int lastWmNr1;
|
|
Bitmap lastImage; /// non-zoomed image
|
|
Bitmap zoomedImage;
|
|
|
|
Thread imageProcessingThread; /// Thread to process images
|
|
public delegate void OcrTextObtainedDelegate(int ix, bool isEnd, string text);
|
|
OcrTextObtainedDelegate ocrTextObtained;
|
|
|
|
readonly LocalSettings ls;
|
|
|
|
bool isHandlersEnabled; /// Initially false, set to true after ComboBoxes are filled with data
|
|
|
|
/// Set to 'true' when the form closes
|
|
public bool Completed { get { return completed; } }
|
|
bool completed;
|
|
|
|
|
|
/// <summary>
|
|
/// Parameterless constructor for common functionality
|
|
/// </summary>
|
|
public TestStartEndForm()
|
|
{
|
|
InitializeComponent();
|
|
ControlBox = false;
|
|
imageProcessingThread = null;
|
|
completed = false;
|
|
StartForceCloseHandler();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="waterMeters">Water meters</param>
|
|
/// <param name="regReaders">Array of register readers</param>
|
|
/// <param name="lineSize">Number of water meters in one (test bencch) line</param>
|
|
/// <param name="title">Form title</param>
|
|
/// <param name="sz">Font size</param>
|
|
/// <param name="isStartBoxAlwaysEn">true = start box enabled at the end of a test</param>
|
|
/// <param name="isLrOrder">true = controls obtain focus in left-right order, forls = top-down order</param>
|
|
/// <param name="formCloseKeys">String containing keys to close this form</param>
|
|
/// <param name="colItems">Water meter items displayed in columns (in the matrix in the main part of the form)</param>
|
|
/// <param name="isCompound">true = Compound meters: StartStateAux and EndStateAux columns displayed</param>
|
|
/// <param name="initialVolumeUnit">Volume unit preset initially</param>
|
|
/// <param name="isCameraPicture">true = display camera pictures in this form</param>
|
|
/// <param name="startImages">Images before a standing start/stop test</param>
|
|
/// <param name="endImages">Images after a standing start/stop test</param>
|
|
/// <param name="ocrVidi">Reference to OCR objejct</param>
|
|
/// <param name="ocrMessage">Message to be displayed when OCR was not initialized properly</param>
|
|
/// <param name="streamName">OCR stream selection</param>
|
|
/// <param name="wmStartStateStr">Information entered on test start</param>
|
|
/// <param name="refVolume">Reference volume, it is used to verify the end state, show/hide exclamation if necessary</param>
|
|
/// <param name="errLimLo">Error limit low, it is used to verify the end state, show/hide exclamation if necessary</param>
|
|
/// <param name="errLimHi">Error limit high, it is used to verify the end state, show/hide exclamation if necessary</param>
|
|
public TestStartEndForm(IList<WaterMeter> waterMeters, IRegReader[] regReaders, int _lineSize, string title, FontSz sz,
|
|
bool isStartBoxAlwaysEn, bool isLrOrder, string formCloseKeys, IList<DEItem> colItems, bool isCompound,
|
|
Unit initialVolumeUnit, bool isCameraPicture, string[] startImages, string[] endImages,
|
|
OcrVidi ocrVidi, string ocrMessage, string streamName, string[] wmStartStateStr = null,
|
|
double refVolume = 0, double errLimLo = 0, double errLimHi = 0)
|
|
: this()
|
|
{
|
|
this.waterMeters = waterMeters;
|
|
this.regReaders = regReaders;
|
|
this.lineSize = Math.Min(waterMeters.Count, _lineSize);
|
|
this.Text = !string.IsNullOrEmpty(title) ? title : string.Empty;
|
|
this.sz = sz;
|
|
this.isStartBoxAlwaysEn = isStartBoxAlwaysEn;
|
|
this.isLrOrder = isLrOrder;
|
|
this.formCloseKeys = !string.IsNullOrEmpty(formCloseKeys) ? formCloseKeys : string.Empty;
|
|
this.colItems = colItems;
|
|
this.isCompound = isCompound;
|
|
this.VolumeUnit = initialVolumeUnit;
|
|
this.isCameraPicture = isCameraPicture;
|
|
this.startImages = startImages;
|
|
this.endImages = endImages;
|
|
this.ocrVidi = ocrVidi;
|
|
this.ocrMessage = ocrMessage;
|
|
this.streamName = streamName;
|
|
this.WMStartStateStr = wmStartStateStr;
|
|
this.refVolume = refVolume;
|
|
this.warningLimLo = 2 * errLimLo;
|
|
this.warningLimHi = 2 * errLimHi;
|
|
|
|
if (waterMeters == null || regReaders == null ||
|
|
(wmStartStateStr != null && wmStartStateStr.Length != (isCompound ? 2 : 1) * waterMeters.Count))
|
|
{
|
|
throw new Exception("Invalid argument");
|
|
}
|
|
|
|
ls = Program.LocalSettings;
|
|
|
|
/// Readonly variables derived from arguments
|
|
isEnd = (wmStartStateStr != null);
|
|
mode = isEnd ? Tst.End : Tst.Start;
|
|
wmsCount = waterMeters.Count;
|
|
if (WMStartStateStr == null) WMStartStateStr = new string[(isCompound ? 2 : 1) * wmsCount];
|
|
fixedErrorLimits = (errLimHi > errLimLo);
|
|
linesCount = (wmsCount + Math.Max(1, lineSize) - 1) / Math.Max(1, lineSize);
|
|
firstValidWM = waterMeters.FirstOrDefault(x => (x != null && !x.Disabled));
|
|
WMStartState = new double[(isCompound ? 2 : 1) * wmsCount];
|
|
WMEndState = new double[(isCompound ? 2 : 1) * wmsCount];
|
|
///
|
|
unitComboBox.Text = VolumeUnit.ToDescription();
|
|
for (Unit u = 0; u < Unit.Count; u++)
|
|
{
|
|
if (Units.IsVolume(u)) unitComboBox.Items.Add(u.ToDescription());
|
|
}
|
|
labels = new Label[wmsCount];
|
|
textBoxes = new TextBox[colItems.Count, wmsCount];
|
|
exclamations = new Label[wmsCount];
|
|
|
|
/// Layout related readonly variables derived from argument 'sz'
|
|
Font font;
|
|
Font exclamationFont;
|
|
switch (sz)
|
|
{
|
|
case FontSz.S:
|
|
font = new Font("Verdana", 12, FontStyle.Regular);
|
|
//exclamationFont = new Font("Verdana", 24F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(238)));
|
|
exclamationFont = new Font("Verdana", 18, FontStyle.Bold);
|
|
meterHeight = 26; /// Height of a ComboBox control
|
|
margin = 20;
|
|
spacing = 8;
|
|
hdrHeight = 160;
|
|
labelWid = 31;
|
|
checkBoxWid = 23;
|
|
break;
|
|
|
|
default:
|
|
case FontSz.M:
|
|
font = new Font("Verdana", 14, FontStyle.Regular);
|
|
exclamationFont = new Font("Verdana", 20, FontStyle.Bold);
|
|
meterHeight = 31; /// Height of a ComboBox control
|
|
margin = 25;
|
|
spacing = 10;
|
|
hdrHeight = 160;
|
|
labelWid = 34;
|
|
checkBoxWid = 23;
|
|
break;
|
|
|
|
case FontSz.L:
|
|
font = new Font("Verdana", 18, FontStyle.Regular);
|
|
exclamationFont = new Font("Verdana", 24, FontStyle.Bold);
|
|
meterHeight = 37; /// Height of a ComboBox control
|
|
margin = 30;
|
|
spacing = 12;
|
|
hdrHeight = 160;
|
|
labelWid = 40;
|
|
checkBoxWid = 23;
|
|
break;
|
|
}
|
|
meterWidth = labelWid + checkBoxWid + spacing;
|
|
foreach (var ci in colItems) { meterWidth += ci.Width + spacing; }
|
|
|
|
int tabIndex = 1;
|
|
|
|
///
|
|
/// Table
|
|
///
|
|
int columnsLeft = 0;
|
|
if (isCameraPicture)
|
|
{
|
|
columnsLeft = PicSize + 10;
|
|
|
|
largeTextBox.Left += columnsLeft;
|
|
largeExclamationLabel.Left += columnsLeft;
|
|
|
|
/// Picture box
|
|
pictureBox1 = new PictureBox
|
|
{
|
|
Location = new System.Drawing.Point(4, 5),
|
|
Name = "pictureBox1",
|
|
Size = new System.Drawing.Size(PicSize, PicSize),
|
|
SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage,
|
|
TabIndex = tabIndex++,
|
|
TabStop = false,
|
|
};
|
|
pictureBox1.Click += new System.EventHandler(pictureBox1_Click);
|
|
Controls.Add(pictureBox1);
|
|
|
|
/// Rotate image button
|
|
var rotateImageButton = new Button
|
|
{
|
|
Font = new System.Drawing.Font("Arial", 27.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238))),
|
|
Location = new System.Drawing.Point(24, PicSize + 31),
|
|
Name = "rotateImageButton",
|
|
Size = new System.Drawing.Size(50, 50),
|
|
TabIndex = tabIndex++,
|
|
Text = "↺",
|
|
UseVisualStyleBackColor = true,
|
|
};
|
|
rotateImageButton.Click += new System.EventHandler(rotateImageButton_Click);
|
|
Controls.Add(rotateImageButton);
|
|
|
|
/// Image processing progress bar
|
|
imageProcessingProgressBar = new ProgressBar
|
|
{
|
|
Location = new System.Drawing.Point(100, PicSize + 56),
|
|
Name = "imageProcessingProgressBar",
|
|
Size = new System.Drawing.Size(246, 23),
|
|
TabIndex = tabIndex++,
|
|
Visible = false,
|
|
};
|
|
Controls.Add(imageProcessingProgressBar);
|
|
|
|
/// Image processing progress label
|
|
imageProcessingProgressLabel = new Label
|
|
{
|
|
AutoSize = true,
|
|
Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))),
|
|
Location = new System.Drawing.Point(100, PicSize + 31),
|
|
Name = "imageProcessingProgressLabel",
|
|
Size = new System.Drawing.Size(249, 18),
|
|
TabIndex = tabIndex++,
|
|
Text = "Progress of image processing",
|
|
Visible = false,
|
|
};
|
|
Controls.Add(imageProcessingProgressLabel);
|
|
}
|
|
|
|
int columnsTop = hdrHeight;
|
|
|
|
for (int j = 0; j < linesCount; j++)
|
|
{
|
|
/// Captions
|
|
int capX = columnsLeft + margin + j * (meterWidth + margin / 2) + labelWid + spacing;
|
|
int capY = columnsTop - meterHeight;
|
|
for (int k = 0; k < colItems.Count; k++)
|
|
{
|
|
int labelWidth = Convert.ToInt32(Graphics.FromImage(new Bitmap(1, 1)).MeasureString(colItems[k].Caption, font).Width);
|
|
var label = new Label
|
|
{
|
|
Text = colItems[k].Caption,
|
|
Location = new Point(capX, capY),
|
|
Size = new Size(labelWidth + spacing, meterHeight),
|
|
Font = font,
|
|
TabIndex = tabIndex++,
|
|
Parent = this,
|
|
};
|
|
capX += colItems[k].Width + spacing;
|
|
Controls.Add(label);
|
|
}
|
|
|
|
/// Water meters
|
|
for (int i = 0; i < lineSize; i++)
|
|
{
|
|
int wmPos0 = i + lineSize * j;
|
|
if (wmPos0 > wmsCount) continue;
|
|
|
|
int left = columnsLeft + margin + j * (meterWidth + margin / 2);
|
|
int top = columnsTop + i * (meterHeight + spacing);
|
|
|
|
var label = new Label
|
|
{
|
|
Text = (wmPos0 + 1).ToString(),
|
|
Location = new Point(left, top),
|
|
Size = new Size(labelWid, meterHeight),
|
|
Font = font,
|
|
TextAlign = ContentAlignment.MiddleLeft,
|
|
TabIndex = tabIndex++,
|
|
Parent = this,
|
|
};
|
|
left += labelWid + spacing / 2;
|
|
labels[wmPos0] = label;
|
|
Controls.Add(label);
|
|
|
|
/// Columns
|
|
for (int k = 0; k < colItems.Count; k++)
|
|
{
|
|
DEItem ci = colItems[k];
|
|
var textBox = new TextBox
|
|
{
|
|
Name = string.Format("{0}~{1}", k, wmPos0),
|
|
Location = new Point(left, top),
|
|
Size = new Size(ci.Width, meterHeight),
|
|
Enabled = (ci.Action != Ac.LoadReadOnly && !waterMeters[wmPos0].Disabled),
|
|
Font = font,
|
|
TabIndex = tabIndex++,
|
|
Parent = this,
|
|
};
|
|
|
|
textBox.AcceptsTabChanged += new System.EventHandler(textBox_AcceptsTabChanged);
|
|
textBox.TextChanged += new System.EventHandler(textBox_TextChanged);
|
|
textBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(textBox_KeyPress);
|
|
textBox.MouseClick += new System.Windows.Forms.MouseEventHandler(textBox_MouseClick);
|
|
textBox.MouseDown += new System.Windows.Forms.MouseEventHandler(textBox_MouseDown);
|
|
|
|
left += ci.Width + spacing;
|
|
textBoxes[k, wmPos0] = textBox;
|
|
Controls.Add(textBox);
|
|
}
|
|
|
|
var exclamation = new Label
|
|
{
|
|
AutoSize = true,
|
|
Font = exclamationFont,
|
|
ForeColor = System.Drawing.Color.Red,
|
|
Location = new Point(left, top),
|
|
Parent = this,
|
|
TabIndex = tabIndex++,
|
|
Text = "!",
|
|
Visible = false,
|
|
};
|
|
exclamations[wmPos0] = exclamation;
|
|
Controls.Add(exclamation);
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Adjust window size
|
|
///
|
|
Rectangle screenRectangle = this.RectangleToScreen(this.ClientRectangle);
|
|
int titleBarHeight = screenRectangle.Top - this.Top;
|
|
Size = new Size(columnsLeft + Math.Max(meterWidth * linesCount + margin * (linesCount + 1), 1040),
|
|
titleBarHeight + Math.Max(columnsTop + lineSize * (meterHeight + spacing) + margin, isCameraPicture ? 590 : 0));
|
|
|
|
Localize();
|
|
InitializeBoxes();
|
|
|
|
/// Set focus to the first enabled ComboBox
|
|
}
|
|
|
|
private void TestStartEndForm_Load(object sender, EventArgs e)
|
|
{
|
|
if (!string.IsNullOrEmpty(ocrMessage))
|
|
{
|
|
MessageBox.Show(ocrMessage, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
}
|
|
|
|
int imagesCount = ImagesToProcessCount();
|
|
log.WarnFormat("Images to process count = {0}", imagesCount);
|
|
///
|
|
if (imagesCount > 0 && ocrVidi != null)
|
|
{
|
|
log.WarnFormat("Starting image processing thread with OcrVidi={0} and OcrStream={1}", ocrVidi, streamName);
|
|
|
|
/// Delegate for a thread->form communication
|
|
ocrTextObtained = new OcrTextObtainedDelegate(OnOcrTextObtained);
|
|
|
|
/// Show and initalize the progress bar
|
|
imageProcessingProgressLabel.Visible = true;
|
|
imageProcessingProgressBar.Visible = true;
|
|
imageProcessingProgressBar.Minimum = 0;
|
|
imageProcessingProgressBar.Value = 0;
|
|
imageProcessingProgressBar.Maximum = imagesCount;
|
|
|
|
/// Start the image processing thread
|
|
imageProcessingThread = new Thread(new ThreadStart(ImageProcessingThread));
|
|
imageProcessingThread.Start();
|
|
}
|
|
|
|
}
|
|
|
|
private void TestStartEndForm_FormClosed(object sender, FormClosedEventArgs e)
|
|
{
|
|
if (imageProcessingThread != null && imageProcessingThread.IsAlive)
|
|
{
|
|
imageProcessingThread.Join(2000);
|
|
}
|
|
}
|
|
|
|
void Localize()
|
|
{
|
|
okButton.Text = Strings.OkBtnText;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize combo boxes state defined by related 'Action'.
|
|
/// Clear check boxes.
|
|
/// </summary>
|
|
void InitializeBoxes()
|
|
{
|
|
isHandlersEnabled = false;
|
|
|
|
/// Table
|
|
startStateColumn = -1;
|
|
startStateColumnAux = -1;
|
|
endStateColumn = -1;
|
|
endStateColumnAux = -1;
|
|
for (int k = 0; k < colItems.Count; k++)
|
|
{
|
|
if (colItems[k].Content == Ct.StartState)
|
|
{
|
|
startStateColumn = k;
|
|
for (int i = 0; i < wmsCount; i++)
|
|
{
|
|
int rrIx = (isCompound ? 2 : 1) * i;
|
|
textBoxes[k, i].Text = (!isEnd || waterMeters[i] == null
|
|
|| waterMeters[i].Disabled
|
|
|| i >= regReaders.Length
|
|
|| regReaders[i] == null
|
|
|| string.IsNullOrEmpty(WMStartStateStr[i])) ? string.Empty : WMStartStateStr[rrIx];
|
|
|
|
textBoxes[k, i].Enabled = (isStartBoxAlwaysEn || !isEnd) && waterMeters[i] != null && !waterMeters[i].Disabled
|
|
&& rrIx < regReaders.Length && regReaders[rrIx] != null;
|
|
}
|
|
}
|
|
else if (colItems[k].Content == Ct.StartStateAux)
|
|
{
|
|
startStateColumnAux = k;
|
|
for (int i = 0; i < wmsCount; i++)
|
|
{
|
|
int rrIx = 2 * i + 1;
|
|
textBoxes[k, i].Text = (!isEnd || !isCompound
|
|
|| waterMeters[i] == null
|
|
|| waterMeters[i].Disabled
|
|
|| i >= regReaders.Length
|
|
|| regReaders[i] == null
|
|
|| string.IsNullOrEmpty(WMStartStateStr[i])) ? string.Empty : WMStartStateStr[rrIx];
|
|
|
|
textBoxes[k, i].Enabled = isCompound && (isStartBoxAlwaysEn || !isEnd) && waterMeters[i] != null && !waterMeters[i].Disabled
|
|
&& rrIx < regReaders.Length && regReaders[rrIx] != null;
|
|
}
|
|
}
|
|
else if (colItems[k].Content == Ct.EndState)
|
|
{
|
|
endStateColumn = k;
|
|
for (int i = 0; i < wmsCount; i++)
|
|
{
|
|
int rrIx = (isCompound ? 2 : 1) * i;
|
|
textBoxes[k, i].Text = string.Empty;
|
|
textBoxes[k, i].Enabled = isEnd && waterMeters[i] != null && !waterMeters[i].Disabled
|
|
&& rrIx < regReaders.Length && regReaders[rrIx] != null;
|
|
}
|
|
}
|
|
else if (colItems[k].Content == Ct.EndStateAux)
|
|
{
|
|
endStateColumn = k;
|
|
for (int i = 0; i < wmsCount; i++)
|
|
{
|
|
int rrIx = 2 * i + 1;
|
|
textBoxes[k, i].Text = string.Empty;
|
|
textBoxes[k, i].Enabled = isEnd && isCompound && waterMeters[i] != null && !waterMeters[i].Disabled
|
|
&& rrIx < regReaders.Length && regReaders[rrIx] != null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (colItems[k].Action)
|
|
{
|
|
default:
|
|
case Ac.Clear:
|
|
case Ac.HistoryLast:
|
|
for (int i = 0; i < wmsCount; i++) textBoxes[k, i].Text = string.Empty;
|
|
break;
|
|
|
|
case Ac.Load:
|
|
case Ac.LoadReadOnly:
|
|
for (int i = 0; i < wmsCount; i++)
|
|
{
|
|
textBoxes[k, i].Text = DEUtils.GetContent(colItems[k].Content, waterMeters[i]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isEnd && isStartBoxAlwaysEn)
|
|
{
|
|
int k = 0;
|
|
int j = 0;
|
|
if (!FindNextEnabledTextBox(textBoxes, ref k, ref j, isLrOrder, true))
|
|
{
|
|
ActiveControl = textBoxes[k, j];
|
|
}
|
|
|
|
}
|
|
|
|
isHandlersEnabled = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// When one combo box is updated using drop-down menu, all combo boxes
|
|
/// are updated by this function.
|
|
/// </summary>
|
|
void UpdateWMsFromBoxes()
|
|
{
|
|
for (int k = 0; k < colItems.Count; k++)
|
|
{
|
|
for (int i = 0; i < wmsCount; i++)
|
|
{
|
|
int rrIx = (isCompound ? 2 : 1) * i;
|
|
double volume;
|
|
|
|
if (colItems[k].Content == Ct.StartState)
|
|
{
|
|
if (textBoxes[k, i].Enabled && Utils.TryParseUDouble(textBoxes[k, i].Text, out volume))
|
|
{
|
|
WMStartStateStr[rrIx] = textBoxes[k, i].Text;
|
|
WMStartState[rrIx] = Units.ConvertFrom(VolumeUnit, volume);
|
|
}
|
|
}
|
|
else if (colItems[k].Content == Ct.StartStateAux)
|
|
{
|
|
if (isCompound && textBoxes[k, i].Enabled && Utils.TryParseUDouble(textBoxes[k, i].Text, out volume))
|
|
{
|
|
WMStartStateStr[rrIx + 1] = textBoxes[k, i].Text;
|
|
WMStartState[rrIx + 1] = Units.ConvertFrom(VolumeUnit, volume);
|
|
}
|
|
}
|
|
else if (colItems[k].Content == Ct.EndState)
|
|
{
|
|
if (textBoxes[k, i].Enabled && Utils.TryParseUDouble(textBoxes[k, i].Text, out volume))
|
|
{
|
|
WMEndState[rrIx] = Units.ConvertFrom(VolumeUnit, volume);
|
|
}
|
|
}
|
|
else if (colItems[k].Content == Ct.EndStateAux)
|
|
{
|
|
if (isCompound && textBoxes[k, i].Enabled && Utils.TryParseUDouble(textBoxes[k, i].Text, out volume))
|
|
{
|
|
WMEndState[rrIx + 1] = Units.ConvertFrom(VolumeUnit, volume);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/// Other value - store values to a water meter structure
|
|
DEUtils.PutContent(colItems[k].Content, waterMeters[i], textBoxes[k, i].Text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int ImagesToProcessCount()
|
|
{
|
|
int count = 0;
|
|
|
|
/// Count images
|
|
for (int i = 0; i < wmsCount; i++)
|
|
{
|
|
int rrIx = (isCompound ? 2 : 1) * i;
|
|
|
|
if (mode == Tst.Start || mode == Tst.Both)
|
|
{
|
|
if (startStateColumn >= 0 && textBoxes[startStateColumn, i].Enabled &&
|
|
startImages != null && startImages.Length > rrIx && !string.IsNullOrEmpty(startImages[rrIx]))
|
|
{
|
|
count++;
|
|
}
|
|
|
|
if (startStateColumnAux >= 0 && textBoxes[startStateColumnAux, i].Enabled &&
|
|
startImages != null && startImages.Length > rrIx + 1 && !string.IsNullOrEmpty(startImages[rrIx + 1]))
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (mode == Tst.End || mode == Tst.Both)
|
|
{
|
|
if (endStateColumn >= 0 && textBoxes[endStateColumn, i].Enabled &&
|
|
endImages != null && endImages.Length > rrIx && !string.IsNullOrEmpty(endImages[rrIx]))
|
|
{
|
|
count++;
|
|
}
|
|
|
|
if (endStateColumnAux >= 0 && textBoxes[endStateColumnAux, i].Enabled &&
|
|
endImages != null && endImages.Length > rrIx + 1 && !string.IsNullOrEmpty(endImages[rrIx + 1]))
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
void ImageProcessingThread()
|
|
{
|
|
double denominator; /// derived from PulsesPerLtr, passed to OcrVidi
|
|
string format; /// derived from PulsesPerLtr, passed to OcrVidi
|
|
|
|
Thread.Sleep(2000);
|
|
|
|
bool[] startImgProcessed = new bool[(isCompound ? 2 : 1) * wmsCount];
|
|
bool[] endImgProcessed = new bool[(isCompound ? 2 : 1) * wmsCount];
|
|
|
|
for (int attempt = 1; attempt <= 3; attempt++)
|
|
{
|
|
for (int i = 0; i < wmsCount; i++)
|
|
{
|
|
int rrIx = (isCompound ? 2 : 1) * i;
|
|
double pulsesPerLtr = (regReaders != null && regReaders.Length > rrIx && regReaders[rrIx] != null) ? regReaders[rrIx].PulsesPerLtr : 1;
|
|
double pulsesPerLtrAux = (regReaders != null && regReaders.Length > rrIx + 1 && regReaders[rrIx + 1] != null) ? regReaders[rrIx + 1].PulsesPerLtr : 1;
|
|
|
|
if (mode == Tst.Start || mode == Tst.Both)
|
|
{
|
|
if (startStateColumn >= 0 && textBoxes[startStateColumn, i].Enabled &&
|
|
startImages != null && startImages.Length > rrIx && !string.IsNullOrEmpty(startImages[rrIx]))
|
|
{
|
|
if (!startImgProcessed[rrIx])
|
|
{
|
|
try
|
|
{
|
|
/// Process a start image
|
|
GetOcrParameters(pulsesPerLtr, out denominator, out format);
|
|
var text = ocrVidi.Recognize(streamName, startImages[rrIx], denominator, format); /// OCR
|
|
this.Invoke(ocrTextObtained, new object[] { rrIx, false, text });
|
|
startImgProcessed[rrIx] = true;
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
if (startStateColumnAux >= 0 && textBoxes[startStateColumnAux, i].Enabled &&
|
|
startImages != null && startImages.Length > rrIx + 1 && !string.IsNullOrEmpty(startImages[rrIx + 1]))
|
|
{
|
|
if (!startImgProcessed[rrIx + 1])
|
|
{
|
|
try
|
|
{
|
|
/// Process a start image
|
|
GetOcrParameters(pulsesPerLtrAux, out denominator, out format);
|
|
var text = ocrVidi.Recognize(streamName, startImages[rrIx + 1], denominator, format); /// OCR
|
|
this.Invoke(ocrTextObtained, new object[] { rrIx + 1, false, text });
|
|
startImgProcessed[rrIx + 1] = true;
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mode == Tst.End || mode == Tst.Both)
|
|
{
|
|
if (endStateColumn >= 0 && textBoxes[endStateColumn, i].Enabled &&
|
|
endImages != null && endImages.Length > rrIx && !string.IsNullOrEmpty(endImages[rrIx]))
|
|
{
|
|
if (!endImgProcessed[rrIx])
|
|
{
|
|
try
|
|
{
|
|
/// Process an end image
|
|
GetOcrParameters(pulsesPerLtr, out denominator, out format);
|
|
var text = ocrVidi.Recognize(streamName, endImages[rrIx], denominator, format); /// OCR
|
|
this.Invoke(ocrTextObtained, new object[] { rrIx, true, text });
|
|
endImgProcessed[rrIx] = true;
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
if (endStateColumnAux >= 0 && textBoxes[endStateColumnAux, i].Enabled &&
|
|
endImages != null && endImages.Length > rrIx + 1 && !string.IsNullOrEmpty(endImages[rrIx + 1]))
|
|
{
|
|
if (!endImgProcessed[rrIx + 1])
|
|
{
|
|
try
|
|
{
|
|
/// Process an end image
|
|
GetOcrParameters(pulsesPerLtrAux, out denominator, out format);
|
|
var text = ocrVidi.Recognize(streamName, endImages[rrIx + 1], denominator, format); /// OCR
|
|
this.Invoke(ocrTextObtained, new object[] { rrIx + 1, true, text });
|
|
endImgProcessed[rrIx + 1] = true;
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GetOcrParameters(double pulsesPerLtr, out double denominator, out string format)
|
|
{
|
|
if (pulsesPerLtr == 0.1)
|
|
{
|
|
denominator = 100;
|
|
format = "F2";
|
|
}
|
|
else if (pulsesPerLtr == 0.01)
|
|
{
|
|
denominator = 10;
|
|
format = "F1";
|
|
}
|
|
else if (pulsesPerLtr == 10)
|
|
{
|
|
denominator = 10000;
|
|
format = "F4";
|
|
}
|
|
else // if (pulsesPerLtr == 1)
|
|
{
|
|
denominator = 1000;
|
|
format = "F3";
|
|
}
|
|
}
|
|
|
|
public void OnOcrTextObtained(int rrIx, bool _isEnd, string text)
|
|
{
|
|
if (!isCameraPicture) return;
|
|
|
|
if (_isEnd)
|
|
{
|
|
if (endStateColumn>= 0 && textBoxes[endStateColumn, rrIx].Enabled)
|
|
{
|
|
textBoxes[endStateColumn, rrIx].Text = text;
|
|
LoadImage(null, Tst.End, rrIx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (startStateColumn >= 0 && textBoxes[startStateColumn, rrIx].Enabled)
|
|
{
|
|
textBoxes[endStateColumn, rrIx].Text = text;
|
|
LoadImage(null, Tst.Start, rrIx);
|
|
}
|
|
}
|
|
|
|
imageProcessingProgressBar.Value++;
|
|
}
|
|
|
|
private void okButton_Click(object sender, EventArgs eArgs)
|
|
{
|
|
UpdateWMsFromBoxes();
|
|
|
|
completed = true;
|
|
Close();
|
|
}
|
|
|
|
private void unitComboBox_TextChanged(object sender, EventArgs e)
|
|
{
|
|
unitComboBox_SelectedIndexChanged(sender, e);
|
|
}
|
|
|
|
private void unitComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
var newUnit = Units.FromDescription(unitComboBox.Text);
|
|
|
|
if (Units.IsVolume(newUnit))
|
|
{
|
|
VolumeUnit = newUnit;
|
|
|
|
if (!isHandlersEnabled) return;
|
|
|
|
/// Update exclamation marks
|
|
if (isEnd && startStateColumn >= 0 && endStateColumn >= 0)
|
|
{
|
|
for (int i = 0; i < wmsCount; i++)
|
|
{
|
|
double startVol, endVol, startVolAux, endVolAux;
|
|
|
|
if (isCompound && startStateColumnAux >= 0 && endStateColumnAux >= 0)
|
|
{
|
|
/// Compound
|
|
if (Utils.TryParseUDouble(textBoxes[startStateColumn, i].Text, out startVol) &&
|
|
Utils.TryParseUDouble(textBoxes[startStateColumnAux, i].Text, out startVolAux) &&
|
|
Utils.TryParseUDouble(textBoxes[endStateColumn, i].Text, out endVol) &&
|
|
Utils.TryParseUDouble(textBoxes[endStateColumnAux, i].Text, out endVolAux))
|
|
{
|
|
double startState = Units.ConvertFrom(VolumeUnit, startVol + startVolAux);
|
|
double endState = Units.ConvertFrom(VolumeUnit, endVol + endVolAux);
|
|
double err = (refVolume != 0) ? 100.0 * (endState - startState - refVolume) / refVolume : 1000.0;
|
|
exclamations[i].Visible = fixedErrorLimits ? ((err < warningLimLo) || (warningLimHi < err)) : ((err < -6) || (+6 < err));
|
|
}
|
|
else
|
|
{
|
|
exclamations[i].Visible = !string.IsNullOrEmpty(textBoxes[endStateColumn, i].Text);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/// Single
|
|
if (Utils.TryParseUDouble(textBoxes[startStateColumn, i].Text, out startVol) &&
|
|
Utils.TryParseUDouble(textBoxes[endStateColumn, i].Text, out endVol))
|
|
{
|
|
double startState = Units.ConvertFrom(VolumeUnit, startVol);
|
|
double endState = Units.ConvertFrom(VolumeUnit, endVol);
|
|
double err = (refVolume != 0) ? 100.0 * (endState - startState - refVolume) / refVolume : 1000.0;
|
|
exclamations[i].Visible = fixedErrorLimits ? ((err < warningLimLo) || (warningLimHi < err)) : ((err < -6) || (+6 < err));
|
|
}
|
|
else
|
|
{
|
|
exclamations[i].Visible = !string.IsNullOrEmpty(textBoxes[endStateColumn, i].Text);
|
|
}
|
|
}
|
|
}
|
|
|
|
largeTextBox.Text = string.Empty;
|
|
largeExclamationLabel.Visible = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void textBox_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
if (!isHandlersEnabled) return;
|
|
|
|
string[] kj = (sender as TextBox).Name.Split(new char[] { '~' });
|
|
int k = int.Parse(kj[0]);
|
|
int j = int.Parse(kj[1]);
|
|
|
|
/// Close the form if any 'form close key' was pressed
|
|
if (!string.IsNullOrEmpty(formCloseKeys))
|
|
{
|
|
/// Close the form if any 'close form key' was pressed
|
|
for (int ix = 0; ix < formCloseKeys.Length; ix++)
|
|
{
|
|
if (e.KeyChar == formCloseKeys[ix])
|
|
{
|
|
okButton_Click(sender, e);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (e.KeyChar == '\r')
|
|
{
|
|
/// Change focus
|
|
if (FindNextEnabledTextBox(textBoxes, ref k, ref j, isLrOrder))
|
|
{
|
|
okButton.Focus();
|
|
}
|
|
else
|
|
{
|
|
largeTextBox.Text = string.Format("{0}: {1}", j + 1, textBoxes[k, j].Text);
|
|
largeExclamationLabel.Visible = false;
|
|
|
|
if (isCameraPicture && (k == startStateColumn || k == startStateColumnAux ||
|
|
k == endStateColumn || k == endStateColumnAux))
|
|
{
|
|
int rrIx = (isCompound ? 2 : 1) * j + ((k == startStateColumnAux || k == endStateColumnAux) ? 1 : 0);
|
|
LoadImage(sender, (k == startStateColumn || k == startStateColumnAux) ? Tst.Start : Tst.End, rrIx);
|
|
}
|
|
|
|
textBoxes[k, j].Focus();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Handle mouse clicks so that the large text box and the large exclamation mark are updated
|
|
private void textBox_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
textBox_TextChanged(sender, e);
|
|
}
|
|
|
|
private void textBox_TextChanged(object sender, EventArgs e)
|
|
{
|
|
if (!isHandlersEnabled) return;
|
|
|
|
string[] kj = (sender as TextBox).Name.Split(new char[] { '~' });
|
|
int k = int.Parse(kj[0]);
|
|
int j = int.Parse(kj[1]);
|
|
|
|
largeTextBox.Text = string.Format("{0}: {1}", j + 1, textBoxes[k, j].Text);
|
|
|
|
if (isEnd && (k == startStateColumn || k == startStateColumnAux || k == endStateColumn || k == endStateColumnAux))
|
|
{
|
|
UpdateExclamation(j);
|
|
}
|
|
else
|
|
{
|
|
largeExclamationLabel.Visible = false;
|
|
}
|
|
}
|
|
|
|
void UpdateExclamation(int j)
|
|
{
|
|
double startVol, startVolAux, endVol, endVolAux;
|
|
|
|
if (isCompound && startStateColumn >= 0 && Utils.TryParseUDouble(textBoxes[startStateColumn, j].Text, out startVol) &&
|
|
startStateColumnAux >= 0 && Utils.TryParseUDouble(textBoxes[startStateColumnAux, j].Text, out startVolAux) &&
|
|
endStateColumn >= 0 && Utils.TryParseUDouble(textBoxes[endStateColumn, j].Text, out endVol) &&
|
|
endStateColumnAux >= 0 && Utils.TryParseUDouble(textBoxes[endStateColumnAux, j].Text, out endVolAux))
|
|
{
|
|
double startState = Units.ConvertFrom(VolumeUnit, startVol + startVolAux);
|
|
double endState = Units.ConvertFrom(VolumeUnit, endVol + endVolAux);
|
|
double err = (refVolume != 0) ? 100.0 * (endState - startState - refVolume) / refVolume : 1000.0;
|
|
largeExclamationLabel.Visible = exclamations[j].Visible =
|
|
fixedErrorLimits ? ((err < warningLimLo) || (warningLimHi < err)) : ((err < -6) || (+6 < err));
|
|
}
|
|
else if (startStateColumn >= 0 && Utils.TryParseUDouble(textBoxes[startStateColumn, j].Text, out startVol) &&
|
|
endStateColumn >= 0 && Utils.TryParseUDouble(textBoxes[endStateColumn, j].Text, out endVol))
|
|
{
|
|
double startState = Units.ConvertFrom(VolumeUnit, startVol);
|
|
double endState = Units.ConvertFrom(VolumeUnit, endVol);
|
|
double err = (refVolume != 0) ? 100.0 * (endState - startState - refVolume) / refVolume : 1000.0;
|
|
largeExclamationLabel.Visible = exclamations[j].Visible =
|
|
fixedErrorLimits ? ((err < warningLimLo) || (warningLimHi < err)) : ((err < -6) || (+6 < err));
|
|
}
|
|
else
|
|
{
|
|
largeExclamationLabel.Visible = exclamations[j].Visible = false;
|
|
}
|
|
}
|
|
|
|
private void textBox_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
textBox_AcceptsTabChanged(sender, e);
|
|
}
|
|
|
|
private void textBox_AcceptsTabChanged(object sender, EventArgs e)
|
|
{
|
|
if (!isHandlersEnabled || !isCameraPicture) return;
|
|
|
|
string[] kj = (sender as TextBox).Name.Split(new char[] { '~' });
|
|
int k = int.Parse(kj[0]);
|
|
int j = int.Parse(kj[1]);
|
|
|
|
if (k == startStateColumn || k == endStateColumn)
|
|
{
|
|
LoadImage(sender, (k == startStateColumn) ? Tst.Start : Tst.End, j);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Find the next enabled combo box, update k and i.
|
|
/// Return true (=pastTheEndOfArray) when there is no such next combo box.
|
|
/// </summary>
|
|
/// <param name="textBoxes">2-dimensional array of combo boxes</param>
|
|
/// <param name="k">0-nased column </param>
|
|
/// <param name="i">0-based row</param>
|
|
/// <param name="isLrOrder">Order of progress to the next combo: true = left-right, false = top-down</param>
|
|
/// <returns>true (=pastTheEndOfArray) when there is no such next combo box, otherwise false</returns>
|
|
bool FindNextEnabledTextBox(TextBox[,] textBoxes, ref int k, ref int i, bool isLrOrder, bool skipStartColumn = false)
|
|
{
|
|
bool pastTheEndOfArray = false;
|
|
do
|
|
{
|
|
if (isLrOrder)
|
|
{
|
|
if (++k == textBoxes.GetLength(0))
|
|
{
|
|
k = 0;
|
|
if (++i == textBoxes.GetLength(1))
|
|
{
|
|
i = 0;
|
|
pastTheEndOfArray = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (++i == textBoxes.GetLength(1))
|
|
{
|
|
i = 0;
|
|
if (++k == textBoxes.GetLength(0))
|
|
{
|
|
k = 0;
|
|
pastTheEndOfArray = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (!textBoxes[k, i].Enabled || (skipStartColumn && k == startStateColumn));
|
|
|
|
return pastTheEndOfArray;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads appropriate image into pictureBox1.Image
|
|
/// Handles mouse clicks and Tab-changes inside text boxes.
|
|
/// </summary>
|
|
/// <param name="startOrEnd">Tst.Start or Tst.End</param>
|
|
/// <param name="rrIx">0-based WM position</param>
|
|
void LoadImage(object sender, Tst startOrEnd, int rrIx)
|
|
{
|
|
string imageFileName;
|
|
if (startOrEnd == Tst.Start && startImages[rrIx] != null)
|
|
imageFileName = startImages[rrIx];
|
|
else if (startOrEnd == Tst.End && endImages[rrIx] != null)
|
|
imageFileName = endImages[rrIx];
|
|
else
|
|
imageFileName = string.Empty;
|
|
|
|
if (imageFileName == lastImageName)
|
|
{
|
|
return;
|
|
}
|
|
|
|
lastImageName = imageFileName;
|
|
lastWmNr1 = rrIx + 1;
|
|
|
|
if (string.IsNullOrEmpty(imageFileName) || !File.Exists(imageFileName))
|
|
{
|
|
lastImage = null;
|
|
}
|
|
else
|
|
{
|
|
using (Bitmap tempBmp = System.Drawing.Image.FromFile(imageFileName) as Bitmap)
|
|
{
|
|
Rectangle rect;
|
|
if (tempBmp.Height < tempBmp.Width)
|
|
{
|
|
int hght = tempBmp.Height;
|
|
int leftMargin = (tempBmp.Width - hght) / 2;
|
|
rect = new Rectangle(leftMargin, 0, hght, hght);
|
|
}
|
|
else
|
|
{
|
|
int hght = tempBmp.Height;
|
|
int wdth = tempBmp.Width;
|
|
int margin = (hght - wdth) / 2;
|
|
rect = new Rectangle(0, margin, wdth, wdth);
|
|
}
|
|
//int hght = tempBmp.Height;
|
|
//int leftMargin = (tempBmp.Width - hght) / 2;
|
|
//lastImage = new Bitmap(tempBmp.Clone(new Rectangle(leftMargin, 0, hght, hght), tempBmp.PixelFormat));
|
|
lastImage = new Bitmap(tempBmp.Clone(rect, tempBmp.PixelFormat));
|
|
if (isZoomed[wmNr0b])
|
|
{
|
|
zoomedImage = MakeZoomedImage(lastImage, zoomCenterLoc[wmNr0b]);
|
|
}
|
|
}
|
|
}
|
|
|
|
ShowImage();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Left click = Zoom, Right click = Unzoom
|
|
/// </summary>
|
|
private void pictureBox1_Click(object sender, EventArgs e)
|
|
{
|
|
if (lastImage == null) return;
|
|
|
|
MouseEventArgs me = (MouseEventArgs)e;
|
|
|
|
if (me.Button == MouseButtons.Left && !isZoomed[wmNr0b])
|
|
{
|
|
switch (imageRotation)
|
|
{
|
|
case Rotation.R0:
|
|
zoomCenterLoc[wmNr0b] = me.Location;
|
|
break;
|
|
case Rotation.R90:
|
|
zoomCenterLoc[wmNr0b].X = pictureBox1.Size.Height - me.Location.Y - 1;
|
|
zoomCenterLoc[wmNr0b].Y = me.Location.X;
|
|
break;
|
|
case Rotation.R180:
|
|
zoomCenterLoc[wmNr0b].X = pictureBox1.Size.Width - me.Location.X - 1;
|
|
zoomCenterLoc[wmNr0b].Y = pictureBox1.Size.Height - me.Location.Y - 1;
|
|
break;
|
|
case Rotation.R270:
|
|
zoomCenterLoc[wmNr0b].X = me.Location.Y;
|
|
zoomCenterLoc[wmNr0b].Y = pictureBox1.Size.Width - me.Location.X - 1;
|
|
break;
|
|
}
|
|
|
|
zoomedImage = MakeZoomedImage(lastImage, zoomCenterLoc[wmNr0b]);
|
|
isZoomed[wmNr0b] = true;
|
|
ShowImage();
|
|
}
|
|
else if (me.Button == MouseButtons.Right)
|
|
{
|
|
isZoomed[wmNr0b] = false;
|
|
ShowImage();
|
|
}
|
|
}
|
|
|
|
private void rotateImageButton_Click(object sender, EventArgs e)
|
|
{
|
|
if (lastImage == null) return;
|
|
|
|
if (++imageRotation == Rotation.Count)
|
|
{
|
|
imageRotation = Rotation.R0;
|
|
}
|
|
ShowImage();
|
|
}
|
|
|
|
Bitmap MakeZoomedImage(Bitmap oriImage, Point centerLoc)
|
|
{
|
|
float picBoxW = (float)pictureBox1.Size.Width;
|
|
float picBoxH = (float)pictureBox1.Size.Height;
|
|
float newRelX = Math.Max(0, Math.Min(centerLoc.X / picBoxW - 0.25f, 0.5f));
|
|
float newRelY = Math.Max(0, Math.Min(centerLoc.Y / picBoxH - 0.25f, 0.5f));
|
|
|
|
Rectangle newRect = new Rectangle((int)(newRelX * oriImage.Width),
|
|
(int)(newRelY * oriImage.Height),
|
|
oriImage.Width / 2,
|
|
oriImage.Height / 2); /// image resolution, 1280 x 960
|
|
return lastImage.Clone(newRect, oriImage.PixelFormat);
|
|
}
|
|
|
|
///
|
|
/// Used by ShowImage()
|
|
///
|
|
Brush lightBrush = new SolidBrush(Color.LightGreen);
|
|
Brush darkBrush = new SolidBrush(Color.Green);
|
|
Font largeFont = new Font("arial", 24.0F, FontStyle.Bold); /// normal image
|
|
Font smallFont = new Font("arial", 12.0F, FontStyle.Bold); /// zoomed image
|
|
|
|
/// <summary>
|
|
/// Show selected image in the picture box.
|
|
/// lastWmNr1, lastImage, zoomedImage, isZoomed and imageRotation are used.
|
|
/// </summary>
|
|
void ShowImage()
|
|
{
|
|
if (pictureBox1 == null) return;
|
|
|
|
if (lastImage == null)
|
|
{
|
|
pictureBox1.Image = new Bitmap(TBF.Properties.Resources.Empty);
|
|
return;
|
|
}
|
|
|
|
Bitmap tempBmp = isZoomed[wmNr0b]
|
|
? new Bitmap(zoomedImage.Clone(new Rectangle(0, 0, zoomedImage.Width, zoomedImage.Height), zoomedImage.PixelFormat))
|
|
: new Bitmap(lastImage.Clone(new Rectangle(0, 0, lastImage.Width, lastImage.Height), lastImage.PixelFormat));
|
|
|
|
switch (imageRotation)
|
|
{
|
|
case Rotation.R90: tempBmp.RotateFlip(RotateFlipType.Rotate270FlipNone); break;
|
|
case Rotation.R180: tempBmp.RotateFlip(RotateFlipType.Rotate180FlipNone); break;
|
|
case Rotation.R270: tempBmp.RotateFlip(RotateFlipType.Rotate90FlipNone); break;
|
|
}
|
|
|
|
/// Write water meter number to the bitmap
|
|
using (var grph = Graphics.FromImage(tempBmp))
|
|
{
|
|
Font font = isZoomed[wmNr0b] ? smallFont : largeFont;
|
|
int margin = isZoomed[wmNr0b] ? 1 : 2;
|
|
|
|
int pixelsCount = 0;
|
|
int brightness = 0;
|
|
for (int x = margin; x <= 8 * margin; x += margin)
|
|
{
|
|
for (int y = margin; y <= 8 * margin; y += margin)
|
|
{
|
|
brightness += (int)tempBmp.GetPixel(x, y).G;
|
|
pixelsCount++;
|
|
}
|
|
}
|
|
brightness /= pixelsCount;
|
|
|
|
Brush brush = (brightness > 160) ? darkBrush : lightBrush;
|
|
|
|
grph.DrawString(lastWmNr1.ToString(), font, brush, margin, margin);
|
|
}
|
|
|
|
pictureBox1.Image = tempBmp;
|
|
}
|
|
|
|
#region Forced close handling
|
|
|
|
public void StartForceCloseHandler()
|
|
{
|
|
UiBridge.Bridge.CloseModelessFormHandler += delegate(object sender, EventArgs args)
|
|
{
|
|
if (InvokeRequired) { Invoke(new EventHandler<EventArgs>(OnForceClose), sender, args); }
|
|
else OnForceClose(sender, args);
|
|
};
|
|
}
|
|
|
|
void OnForceClose(object sender, EventArgs args)
|
|
{
|
|
DialogResult = DialogResult.Cancel;
|
|
Close();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|