private void DoMergeWords()
        {
            var cnt = SelectedTextParts.Count;

            if (cnt == 0)
            {
                Messenger.Default.Send("No selection");
                return;
            }

            TextPart mergedWords = null;
            var      toDelete    = new List <TextPart>();
            TextPart firstPart   = null;
            var      foundCount  = 0;

            var orderedParts = SelectedTextParts.Distinct().OrderBy(a => a.StartMills).ToList();

            foreach (var word in orderedParts)
            {
                //if (foundCount == cnt)
                //{
                //    break; // found all
                //}

                if (SelectedTextParts.Contains(word))
                {
                    if (mergedWords == null)
                    {
                        mergedWords = new TextPart {
                            StartMills = word.StartMills, Text = ""
                        };
                        firstPart = word;
                    }
                    else
                    {
                        toDelete.Add(word);
                    }
                    mergedWords.Text = mergedWords.Text.Trim() + " " + word.Text.Trim();
                    //mergedWords.TextWidth += word.TextWidth;
                    foundCount++;
                }
            }
            //mergedWords.Text = mergedWords.Text.Trim();

            firstPart.Text = mergedWords.Text;
            var lastPart = orderedParts[orderedParts.Count - 1];

            firstPart.TextWidth = (lastPart.StartMills + lastPart.TextWidth) - firstPart.StartMills;

            for (var ix = 0; ix < toDelete.Count; ix++)
            {
                TextParts.Remove(toDelete[ix]);
            }

            RaisePropertyChanged("FullText");
        }
        private async void DoSelectionMatch(object state)
        {
            SelectionChangedTimer.Change(Timeout.Infinite, Timeout.Infinite);

            await Application.Current.Dispatcher.Invoke(async() =>
            {
                var lastSelectionTextbox = lastRoutedArgs.OriginalSource as System.Windows.Controls.TextBox;

                SelectedTextParts.Clear();
                RaisePropertyChanged("SelectedTextParts");
                await Task.Delay(200).ConfigureAwait(false);

                for (var a = 0; a < TextParts.Count; a++)
                {
                    TextParts[a].IsSelected = false;
                }

                await Task.Delay(100).ConfigureAwait(false);

                var selectedText = lastSelectionTextbox.SelectedText.Trim();

                if (selectedText?.Length == 0)
                {
                    return;
                }

                var selectionStart = lastSelectionTextbox.SelectionStart;

                var beforeSelection = lastSelectionTextbox.Text.Substring(0, selectionStart);

                var cumulativeText = "";
                var foundText      = "";

                foreach (var txt in TextParts)
                {
                    cumulativeText += txt.Text + " ";
                    if (cumulativeText.Trim().Length > selectionStart)
                    {
                        txt.IsSelected = true;
                        SelectedTextParts.Add(txt);
                        foundText += txt.Text + " ";
                    }

                    if (foundText.Trim().Length >= selectedText.Length)
                    {
                        break;
                    }
                }
            });
        }
        private void DoSelectedDelete()
        {
            if (SelectedTextParts == null || SelectedTextParts.Count == 0)
            {
                return;
            }
            var copied = SelectedTextParts.ToList();

            var answ = System.Windows.MessageBox.Show($"Are you sure you want to delete {copied.Count} selected text bits?", "Confirm delete...", MessageBoxButton.YesNo);

            if (answ == MessageBoxResult.Yes)
            {
                for (var x = 0; x < copied.Count; x++)
                {
                    TextParts.Remove(copied[x]);
                }
            }

            RaisePropertyChanged("FullText");
        }
        internal void SelectedTextChange(double widthChangeDelta)
        {
            var scaledDelta     = widthChangeDelta / Scale;
            var cumulativeShift = scaledDelta / 2;

            var orderedSelectedParts = SelectedTextParts.OrderBy(a => a.StartMills);

            foreach (var part in orderedSelectedParts)
            {
                part.TextWidth += scaledDelta;

                if (part.TextWidth < 40)
                {
                    part.TextWidth = 40;
                }

                if (ChangeTimeWithSize)
                {
                    part.StartMills += cumulativeShift; // starts at half (for first) then shifts left "half * 2" for each next one
                    cumulativeShift += scaledDelta;
                }
            }
        }
        private void DoAddSpaceBefore()
        {
            if (SelectedTextParts.Count == 0)
            {
                Messenger.Default.Send("No selection");
                return;
            }

            TextPart firstWord       = SelectedTextParts.OrderBy(a => a.StartMills).First();
            int      collectionIndex = 0;

            TextPart newSpace = new TextPart
            {
                TextWidth = 500,
                Text      = "???"
            };

            newSpace.StartMills = firstWord.StartMills - newSpace.TextWidth - 100;

            TextParts.Insert(collectionIndex, newSpace);

            RaisePropertyChanged("FullText");
        }