예제 #1
0
        private void setDiffContextText(Control diffContextControl)
        {
            double fontSizePx = WinFormsHelpers.GetFontSizeInPixels(diffContextControl);

            DiscussionNote note = getNoteFromControl(diffContextControl);

            Debug.Assert(note.Type == "DiffNote");
            DiffPosition position = PositionConverter.Convert(note.Position);

            Debug.Assert(diffContextControl is HtmlPanel);
            HtmlPanel htmlPanel = diffContextControl as HtmlPanel;

            // We need to zero the control size before SetText call to allow HtmlPanel to compute the size
            int prevWidth = htmlPanel.Width;

            htmlPanel.Width  = 0;
            htmlPanel.Height = 0;

            string html = getContext(_panelContextMaker, position, _diffContextDepth, fontSizePx, out string css);

            htmlPanel.BaseStylesheet = css;
            htmlPanel.Text           = html;
            resizeLimitedWidthHtmlPanel(htmlPanel, prevWidth);

            string tooltipHtml = getContext(_tooltipContextMaker, position,
                                            _tooltipContextDepth, fontSizePx, out string tooltipCSS);

            _htmlDiffContextToolTip.BaseStylesheet =
                String.Format("{0} .htmltooltip {{ padding: 1px; }}", tooltipCSS);
            _htmlDiffContextToolTip.SetToolTip(htmlPanel, tooltipHtml);
        }
예제 #2
0
        private void setServiceDiscussionNoteText(Control noteControl, DiscussionNote note)
        {
            if (note == null)
            {
                Debug.Assert(false);
                return;
            }

            // We need to zero the control size before SetText call to allow HtmlPanel to compute the size
            noteControl.Width  = 0;
            noteControl.Height = 0;

            Debug.Assert(noteControl is HtmlPanel);
            HtmlPanel htmlPanel = noteControl as HtmlPanel;

            htmlPanel.BaseStylesheet = String.Format("{0} body div {{ font-size: {1}px; }}",
                                                     Properties.Resources.Common_CSS,
                                                     WinFormsHelpers.GetFontSizeInPixels(noteControl));

            string body = MarkDownUtils.ConvertToHtml(note.Body, _imagePath, _specialDiscussionNoteMarkdownPipeline);

            noteControl.Text = String.Format(MarkDownUtils.HtmlPageTemplate, body);

            resizeFullSizeHtmlPanel(noteControl as HtmlPanel);
        }
예제 #3
0
        internal void setDiscussionNoteText(Control noteControl, DiscussionNote note)
        {
            if (note == null)
            {
                // this is possible when noteControl detaches from parent
                return;
            }

            Debug.Assert(noteControl is HtmlPanel);
            HtmlPanel htmlPanel = noteControl as HtmlPanel;

            htmlPanel.BaseStylesheet = String.Format(
                "{0} body div {{ font-size: {1}px; padding-left: 4px; padding-right: {2}px; }}",
                Properties.Resources.Common_CSS, WinFormsHelpers.GetFontSizeInPixels(noteControl),
                SystemInformation.VerticalScrollBarWidth * 2); // this is really weird

            // We need to zero the control size before SetText call to allow HtmlPanel to compute the size
            int prevWidth = noteControl.Width;

            noteControl.Width  = 0;
            noteControl.Height = 0;

            string body = MarkDownUtils.ConvertToHtml(note.Body, _imagePath, _specialDiscussionNoteMarkdownPipeline);

            noteControl.Text = String.Format(MarkDownUtils.HtmlPageTemplate, addPrefix(body, note, _firstNoteAuthor));
            resizeLimitedWidthHtmlPanel(htmlPanel, prevWidth);

            _htmlDiscussionNoteToolTip.BaseStylesheet =
                String.Format("{0} body div {{ font-size: {1}px; }}",
                              Properties.Resources.Common_CSS,
                              WinFormsHelpers.GetFontSizeInPixels(noteControl));
            _htmlDiscussionNoteToolTip.SetToolTip(noteControl, getNoteTooltipHtml(note));
        }
예제 #4
0
        private Color getNoteColor(DiscussionNote note)
        {
            Color defaultColor = Color.White;

            if (isServiceDiscussionNote(note))
            {
                return(_colorScheme.GetColorOrDefault("Discussions_ServiceMessages",
                                                      _colorScheme.GetColorOrDefault("Discussions_Comments", defaultColor)));
            }

            if (note.Resolvable)
            {
                if (note.Author.Id == _mergeRequestAuthor.Id)
                {
                    return(note.Resolved
                  ? _colorScheme.GetColorOrDefault("Discussions_Author_Notes_Resolved", defaultColor)
                  : _colorScheme.GetColorOrDefault("Discussions_Author_Notes_Unresolved", defaultColor));
                }
                else
                {
                    return(note.Resolved
                  ? _colorScheme.GetColorOrDefault("Discussions_NonAuthor_Notes_Resolved", defaultColor)
                  : _colorScheme.GetColorOrDefault("Discussions_NonAuthor_Notes_Unresolved", defaultColor));
                }
            }
            else
            {
                return(_colorScheme.GetColorOrDefault("Discussions_Comments", defaultColor));
            }
        }
예제 #5
0
        async private Task onEditDiscussionNoteAsync(Control noteControl)
        {
            DiscussionNote note = getNoteFromControl(noteControl);

            if (note == null || !canBeModified(note))
            {
                return;
            }

            string currentBody = StringUtils.ConvertNewlineUnixToWindows(note.Body);
            DiscussionNoteEditPanel actions = new DiscussionNoteEditPanel();

            using (TextEditForm form = new TextEditForm("Edit Discussion Note", currentBody, true, true, actions))
            {
                Point locationAtScreen = noteControl.PointToScreen(new Point(0, 0));
                form.StartPosition = FormStartPosition.Manual;
                form.Location      = locationAtScreen;

                actions.SetTextbox(form.TextBox);
                if (form.ShowDialog() == DialogResult.OK)
                {
                    if (form.Body.Length == 0)
                    {
                        MessageBox.Show("Note text cannot be empty", "Warning",
                                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        return;
                    }

                    string proposedBody = StringUtils.ConvertNewlineWindowsToUnix(form.Body);
                    await submitNewBodyAsync(noteControl, proposedBody);
                }
            }
        }
예제 #6
0
        async private Task onDeleteNoteAsync(DiscussionNote note)
        {
            if (note == null || !canBeModified(note))
            {
                return;
            }

            disableAllNoteControls();

            Discussion discussion = null;

            try
            {
                await _editor.DeleteNoteAsync(note.Id);
            }
            catch (DiscussionEditorException ex)
            {
                string message = "Cannot delete a note";
                ExceptionHandlers.Handle(message, ex);
                MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                discussion = Discussion;
            }

            await refreshDiscussion(discussion);
        }
예제 #7
0
        private HtmlPanel createDiffContext(DiscussionNote firstNote)
        {
            if (firstNote.Type != "DiffNote")
            {
                return(null);
            }

            int fontSizePx     = 12;
            int rowsVPaddingPx = 2;
            int rowHeight      = (fontSizePx + rowsVPaddingPx * 2 + 1 /* border of control */ + 2);
            // we're adding 2 extra pixels for each row because HtmlRenderer does not support CSS line-height property
            // this value was found experimentally

            int panelHeight = (_diffContextDepth.Size + 1) * rowHeight;

            HtmlPanel htmlPanel = new HtmlPanel
            {
                BorderStyle = BorderStyle.FixedSingle,
                Height      = panelHeight,
                MinimumSize = new Size(600, 0),
                TabStop     = false
            };

            DiffPosition position = convertToDiffPosition(firstNote.Position);

            htmlPanel.Text = getContext(_panelContextMaker, position,
                                        _diffContextDepth, fontSizePx, rowsVPaddingPx);
            _htmlToolTip.SetToolTip(htmlPanel, getContext(_tooltipContextMaker, position,
                                                          _tooltipContextDepth, fontSizePx, rowsVPaddingPx));

            return(htmlPanel);
        }
예제 #8
0
        async private Task onToggleResolveNoteAsync(DiscussionNote note)
        {
            if (note == null)
            {
                return;
            }

            disableAllNoteControls();

            Discussion discussion = null;

            try
            {
                bool wasResolved = note.Resolved;
                await _editor.ResolveNoteAsync(note.Id, !wasResolved);
            }
            catch (DiscussionEditorException ex)
            {
                string message = "Cannot toggle 'Resolved' state of a note";
                ExceptionHandlers.Handle(message, ex);
                MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                discussion = Discussion;
            }

            await refreshDiscussion(discussion);
        }
예제 #9
0
        async private Task deleteMostRecentNote(NewDiscussionParameters parameters)
        {
            Debug.Assert(parameters.Position != null);

            Trace.TraceInformation("[DicsussionCreator] Looking up for a note with bad position...");

            IEnumerable <Discussion> discussions;

            try
            {
                discussions = await _discussionOperator.GetDiscussionsAsync(_mergeRequestKey, null);
            }
            catch (OperatorException ex)
            {
                ExceptionHandlers.Handle("Cannot obtain discussions", ex);
                return;
            }

            int?deletedNoteId = new int?();

            foreach (Discussion discussion in discussions.Reverse())
            {
                if (discussion.Notes.Count() == 1)
                {
                    DiscussionNote note = discussion.Notes.First();
                    if (_currentUser != null &&
                        note != null &&
                        note.Type == "DiffNote" &&
                        note.Author != null &&
                        note.Author.Id == _currentUser.Id &&
                        note.Body == parameters.Body)
                    {
                        Trace.TraceInformation(
                            "[DicsussionCreator] Deleting discussion note." +
                            " Id: {0}, Author.Username: {1}, Created_At: {2}, Body:\n{3}",
                            note.Id.ToString(), note.Author.Username, note.Created_At, note.Body);

                        try
                        {
                            await _discussionOperator.DeleteNoteAsync(_mergeRequestKey, note.Id);

                            deletedNoteId = note.Id;
                        }
                        catch (OperatorException ex)
                        {
                            ExceptionHandlers.Handle("Cannot delete discussion note", ex);
                        }

                        break;
                    }
                }
            }

            string message = deletedNoteId.HasValue
            ? String.Format("[DicsussionCreator] Deleted note with Id {0}", deletedNoteId.Value)
            : "Could not find a note to delete (or could not delete it)";

            Trace.TraceInformation(message);
        }
예제 #10
0
        private void onCancelEditNote(TextBox textBox)
        {
            textBox.ReadOnly = true;

            DiscussionNote note = (DiscussionNote)(textBox.Tag);

            textBox.Text = note.Body.Replace("\n", "\r\n");
        }
예제 #11
0
 private bool canBeModified(DiscussionNote note)
 {
     if (note == null)
     {
         return(false);
     }
     return(note.Author.Id == _currentUser.Id && (!note.Resolvable || !note.Resolved));
 }
예제 #12
0
        // Collect discussions started for lines within DiffContextDepth range near `position`
        private IEnumerable <ReportedDiscussionNote> getRelatedDiscussions(
            MergeRequestKey mrk, ReportedDiscussionNoteKey?keyOpt, DiffPosition position)
        {
            // Obtain a context for a passed position.
            DiffContext ctx = getDiffContext <CombinedContextMaker>(position, UnchangedLinePolicy.TakeFromRight);

            if (!ctx.IsValid())
            {
                return(Array.Empty <ReportedDiscussionNote>());
            }

            string leftFileName  = position.LeftPath;
            string rightFileName = position.RightPath;

            Core.Matching.DiffRefs refs = position.Refs;
            List <DiffPosition>    neighborPositions = new List <DiffPosition>();

            // CombinedContextMaker provides a context where line numbers are matched so no need to
            // match them manually here.
            foreach (DiffContext.Line line in ctx.Lines)
            {
                Debug.Assert(line.Left.HasValue || line.Right.HasValue);
                string leftLineNumber  = null;
                string rightLineNumber = null;
                if (line.Left.HasValue)
                {
                    leftLineNumber = line.Left.Value.Number.ToString();
                }
                if (line.Right.HasValue)
                {
                    rightLineNumber = line.Right.Value.Number.ToString();
                }
                neighborPositions.Add(new DiffPosition(leftFileName, rightFileName, leftLineNumber, rightLineNumber, refs));
            }

            // Find discussions that reported on each line from the diff context.
            List <ReportedDiscussionNote> relatedNotes = new List <ReportedDiscussionNote>();

            foreach (Discussion discussion in _getDiscussions(mrk))
            {
                DiscussionNote firstNote         = discussion.Notes.First();
                DiffPosition   firstNotePosition = PositionConverter.Convert(firstNote.Position);
                if (firstNotePosition != null)
                {
                    foreach (DiffPosition neighbor in neighborPositions)
                    {
                        if (doPositionsReferenceTheSameLine(neighbor, firstNotePosition) &&
                            (!keyOpt.HasValue || keyOpt.Value.Id != firstNote.Id))
                        {
                            ReportedDiscussionNote note = new ReportedDiscussionNote(firstNote.Id, discussion.Id,
                                                                                     firstNotePosition, firstNote.Body, firstNote.Author.Name, firstNote.Created_At);
                            relatedNotes.Add(note);
                        }
                    }
                }
            }
            return(relatedNotes.GroupBy(note => note.Key.Id).Select(c => c.First()));
        }
예제 #13
0
        private ContextMenu createContextMenuForDiscussionNote(DiscussionNote note,
                                                               bool discussionResolved, TextBox textBox)
        {
            var contextMenu = new ContextMenu();

            MenuItem menuItemToggleDiscussionResolve = new MenuItem
            {
                Tag     = textBox,
                Text    = (discussionResolved ? "Unresolve" : "Resolve") + " Discussion",
                Enabled = note.Resolvable
            };

            menuItemToggleDiscussionResolve.Click += MenuItemToggleResolveDiscussion_Click;
            contextMenu.MenuItems.Add(menuItemToggleDiscussionResolve);

            MenuItem menuItemToggleResolve = new MenuItem
            {
                Tag     = textBox,
                Text    = (note.Resolvable && note.Resolved ? "Unresolve" : "Resolve") + " Note",
                Enabled = note.Resolvable
            };

            menuItemToggleResolve.Click += MenuItemToggleResolveNote_Click;
            contextMenu.MenuItems.Add(menuItemToggleResolve);

            MenuItem menuItemDeleteNote = new MenuItem
            {
                Tag     = textBox,
                Enabled = canBeModified(note),
                Text    = "Delete Note"
            };

            menuItemDeleteNote.Click += MenuItemDeleteNote_Click;
            contextMenu.MenuItems.Add(menuItemDeleteNote);

            MenuItem menuItemEditNote = new MenuItem
            {
                Tag     = textBox,
                Enabled = canBeModified(note),
                Text    = "Edit Note (F2)"
            };

            menuItemEditNote.Click += MenuItemEditNote_Click;
            contextMenu.MenuItems.Add(menuItemEditNote);

            MenuItem menuItemReply = new MenuItem
            {
                Tag     = textBox,
                Enabled = !Discussion.Individual_Note,
                Text    = "Reply"
            };

            menuItemReply.Click += MenuItemReply_Click;
            contextMenu.MenuItems.Add(menuItemReply);

            return(contextMenu);
        }
예제 #14
0
        private string addPrefix(string body, DiscussionNote note, User firstNoteAuthor)
        {
            bool appendNoteAuthor = note.Author.Id != _currentUser.Id && note.Author.Id != firstNoteAuthor.Id;

            Debug.Assert(!appendNoteAuthor || !canBeModified(note));

            string prefix = appendNoteAuthor ? String.Format("({0}) ", note.Author.Name) : String.Empty;

            return(prefix + body);
        }
예제 #15
0
        private bool isServiceDiscussionNote(DiscussionNote note)
        {
            if (note == null)
            {
                Debug.Assert(false);
                return(false);
            }

            return(note.Author.Username == Program.ServiceManager.GetServiceMessageUsername());
        }
예제 #16
0
 private void enableNoteControl(Control noteControl,
                                Color backColor, ContextMenu contextMenu, DiscussionNote note)
 {
     if (noteControl != null)
     {
         noteControl.BackColor   = backColor;
         noteControl.ContextMenu = contextMenu;
         noteControl.Tag         = note;
     }
 }
예제 #17
0
        // Create a label that shows discussion author
        private Control createLabelAuthor(DiscussionNote firstNote)
        {
            Label labelAuthor = new Label
            {
                Text         = firstNote.Author.Name,
                AutoEllipsis = true
            };

            return(labelAuthor);
        }
예제 #18
0
        private static string wrapTextFragmentInSpan(int startPosition, int length, DiscussionNote note)
        {
            string discussionText = note.Body;
            string prefix         = "<span class=\"highlight\">";
            string suffix         = "</span>";
            string newText        = discussionText
                                    .Insert(startPosition, prefix)
                                    .Insert(startPosition + length + prefix.Length, suffix);

            return(newText);
        }
예제 #19
0
        private string getNoteTooltipText(DiscussionNote note)
        {
            string result = string.Empty;

            if (note.Resolvable)
            {
                result += note.Resolved ? "Resolved." : "Not resolved.";
            }
            result += " Created by " + note.Author.Name + " at " + note.Created_At.ToLocalTime().ToString("g");
            return(result);
        }
예제 #20
0
        private DiscussionNote removeCodeBlocks(DiscussionNote note)
        {
            if (note == null)
            {
                return(null);
            }

            string oldBody = note.Body;
            string newBody = oldBody.Replace("`", "").Replace("~", "");

            return(cloneNoteWithNewText(note, newBody));
        }
예제 #21
0
        public void ClearHighlight()
        {
            DiscussionNote note = getOriginalNote();

            if (note == null)
            {
                return;
            }

            (Parent as DiscussionBox).setDiscussionNoteText(this, note);
            HighlightState = null;
        }
예제 #22
0
        public void ClearHighlight()
        {
            DiscussionNote note = getOriginalNote();

            if (note == null || HighlightState == null)
            {
                return;
            }

            // Unwrap a wrapped span (i.e. undo HihghlightFragment).
            // Don't reset HighlightState to remember a place where highlighting was located in order to continue search.
            (Parent as DiscussionBox).setDiscussionNoteText(this, note);
        }
예제 #23
0
 private string getNoteTooltipHtml(DiscussionNote note)
 {
     System.Text.StringBuilder result = new System.Text.StringBuilder();
     if (note.Resolvable)
     {
         string text  = note.Resolved ? "Resolved." : "Not resolved.";
         string color = note.Resolved ? "green" : "red";
         result.AppendFormat("<i style=\"color: {0}\">{1}&nbsp;&nbsp;&nbsp;</i>", color, text);
     }
     result.AppendFormat("Created by <b> {0} </b> at <span style=\"color: blue\">{1}</span>",
                         note.Author.Name, note.Created_At.ToLocalTime().ToString(Constants.TimeStampFormat));
     result.AppendFormat("<br><br>Use context menu to view note as <b>plain text</b>.");
     return(result.ToString());
 }
예제 #24
0
        private bool isDiscussionResolved()
        {
            bool result = true;

            foreach (Control textBox in _textboxesNotes)
            {
                DiscussionNote note = (DiscussionNote)(textBox.Tag);
                if (note.Resolvable && !note.Resolved)
                {
                    result = false;
                }
            }
            return(result);
        }
예제 #25
0
        private ContextMenu createContextMenuForFilename(DiscussionNote firstNote, TextBox textBox)
        {
            ContextMenu contextMenu = new ContextMenu();

            MenuItem menuItemToggleDiscussionResolve = new MenuItem
            {
                Tag     = textBox,
                Text    = "Resolve/Unresolve Thread",
                Enabled = isDiscussionResolvable()
            };

            menuItemToggleDiscussionResolve.Click += MenuItemToggleResolveDiscussion_Click;
            contextMenu.MenuItems.Add(menuItemToggleDiscussionResolve);

            contextMenu.MenuItems.Add("-");

            MenuItem menuItemReply = new MenuItem
            {
                Tag     = textBox,
                Enabled = true,
                Text    = "Reply"
            };

            menuItemReply.Click += MenuItemReply_Click;
            contextMenu.MenuItems.Add(menuItemReply);

            MenuItem menuItemReplyAndResolve = new MenuItem
            {
                Tag      = textBox,
                Enabled  = true,
                Text     = "Reply and Resolve/Unresolve Thread",
                Shortcut = Shortcut.F4
            };

            menuItemReplyAndResolve.Click += MenuItemReplyAndResolve_Click;
            contextMenu.MenuItems.Add(menuItemReplyAndResolve);

            MenuItem menuItemReplyDone = new MenuItem
            {
                Tag      = textBox,
                Enabled  = isDiscussionResolvable(),
                Text     = "Reply \"Done\" and Resolve/Unresolve Thread",
                Shortcut = Shortcut.ShiftF4
            };

            menuItemReplyDone.Click += MenuItemReplyDone_Click;
            contextMenu.MenuItems.Add(menuItemReplyDone);

            return(contextMenu);
        }
예제 #26
0
        public void HighlightFragment(int startPosition, int length)
        {
            DiscussionNote note = removeCodeBlocks(getOriginalNote());

            if (note == null)
            {
                return;
            }

            string         span        = wrapTextFragmentInSpan(startPosition, length, note);
            DiscussionNote updatedNote = cloneNoteWithNewText(getOriginalNote(), span);

            (Parent as DiscussionBox).setDiscussionNoteText(this, updatedNote);
            HighlightState = new HighlightState(startPosition, length);
        }
예제 #27
0
        private IEnumerable <ReportedDiscussionNote> getReportedDiscussions(MergeRequestKey mrk)
        {
            DiscussionFilter discussionFilter = new DiscussionFilter(
                _currentUser, null, DiscussionFilterState.CurrentUserOnly);

            return(_getDiscussions(mrk)
                   .Where(discussion => discussionFilter.DoesMatchFilter(discussion))
                   .Where(discussion => !discussion.Notes.First().System)
                   .Select(discussion =>
            {
                DiscussionNote firstNote = discussion.Notes.First();
                Core.Matching.DiffPosition firstNotePosition = PositionConverter.Convert(firstNote.Position);
                return new ReportedDiscussionNote(firstNote.Id, discussion.Id, firstNotePosition,
                                                  firstNote.Body, firstNote.Author.Name, firstNote.Created_At);
            }));
        }
예제 #28
0
        async private Task onDeleteNoteAsync(TextBox textBox)
        {
            DiscussionNote note = (DiscussionNote)(textBox.Tag);

            try
            {
                await _editor.DeleteNoteAsync(note.Id);
            }
            catch (DiscussionEditorException)
            {
                MessageBox.Show("Cannot delete a note", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            await refreshDiscussion();
        }
예제 #29
0
        async private void MenuItemToggleResolveNote_Click(object sender, EventArgs e)
        {
            MenuItem  menuItem  = (MenuItem)(sender);
            HtmlPanel htmlPanel = (HtmlPanel)(menuItem.Tag);

            if (htmlPanel?.Parent?.Parent == null)
            {
                return;
            }

            DiscussionNote note = getNoteFromControl(htmlPanel);

            Debug.Assert(note == null || note.Resolvable);

            await onToggleResolveNoteAsync(note);
        }
예제 #30
0
        private void resizeBoxContent(int width)
        {
            if (_textboxesNotes != null)
            {
                foreach (Control noteControl in _textboxesNotes)
                {
                    HtmlPanel      htmlPanel = noteControl as HtmlPanel;
                    DiscussionNote note      = getNoteFromControl(noteControl);
                    if (note != null && !isServiceDiscussionNote(note))
                    {
                        resizeLimitedWidthHtmlPanel(htmlPanel, width * NotesWidth / 100);
                    }
                    else
                    {
                        resizeFullSizeHtmlPanel(htmlPanel);
                    }
                }
            }

            int realLabelAuthorPercents = Convert.ToInt32(
                LabelAuthorWidth * ((Parent as CustomFontForm).CurrentFontMultiplier * LabelAuthorWidthMultiplier));

            if (_labelAuthor != null)
            {
                _labelAuthor.Width = width * realLabelAuthorPercents / 100;
            }

            if (_textboxFilename != null)
            {
                _textboxFilename.Width  = width * LabelFilenameWidth / 100;
                _textboxFilename.Height = (_textboxFilename as TextBoxEx).FullPreferredHeight;
            }

            int remainingPercents = 100
                                    - HorzMarginWidth - realLabelAuthorPercents
                                    - HorzMarginWidth - NotesWidth
                                    - HorzMarginWidth
                                    - HorzMarginWidth
                                    - HorzMarginWidth;

            if (_panelContext != null)
            {
                resizeLimitedWidthHtmlPanel(_panelContext as HtmlPanel, width * remainingPercents / 100);
                _htmlDiffContextToolTip.MaximumSize = new Size(_panelContext.Width, 0 /* auto-height */);
            }
        }