Add tab context menu and polish orders/price-list clear controls.

Right-click closes active or targeted document tabs, fix order items header overlap, and align the price-list search clear button with centered × glyph.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Magomed 2026-07-14 19:04:39 +03:00
parent 800b2971b8
commit 2e1b13fde6
7 changed files with 128 additions and 12 deletions

View File

@ -27,6 +27,9 @@ namespace Электронная_Фармация
private Panel _statusFooter;
private Label _lblCurrentUser;
private ContextMenuStrip _directoryMenu;
private ContextMenuStrip _documentTabMenu;
private ToolStripMenuItem _documentCloseTabMenuItem;
private ToolStripMenuItem _documentCloseAllTabsMenuItem;
partial void InitializeModernShell()
{
@ -111,6 +114,25 @@ namespace Электронная_Фармация
_appHeader.ItemSelected += OnAppHeaderItemSelected;
_documentTabStrip.TabSelected += OnDocumentTabSelected;
_documentTabStrip.TabClosed += OnDocumentTabClosed;
_documentTabStrip.TabCloseAllRequested += OnDocumentTabCloseAll;
_documentCloseTabMenuItem = new ToolStripMenuItem("Закрыть вкладку");
_documentCloseTabMenuItem.Click += (_, __) =>
{
var tabId = _documentTabStrip.ActiveTabId;
if (!string.IsNullOrEmpty(tabId))
{
CloseDocumentTab(tabId);
}
};
_documentCloseAllTabsMenuItem = new ToolStripMenuItem("Закрыть все вкладки");
_documentCloseAllTabsMenuItem.Click += (_, __) => ClearDocumentTabs();
_documentTabMenu = new ContextMenuStrip();
_documentTabMenu.Items.Add(_documentCloseTabMenuItem);
_documentTabMenu.Items.Add(_documentCloseAllTabsMenuItem);
ThemeManager.ThemeChanged += (_, __) => _themeService.Apply(this);
}
@ -207,6 +229,7 @@ namespace Электронная_Фармация
_documentContents[tabId] = content;
_documentHost.Controls.Add(content);
UiThemeHelper.ApplyToControlTree(content);
WireDocumentContextMenu(content);
_documentTabStrip.SelectTab(tabId);
ShowDocumentTab(tabId);
_appHeader.SetActive(navKey);
@ -226,6 +249,35 @@ namespace Электронная_Фармация
CloseDocumentTab(tabId);
}
private void OnDocumentTabCloseAll(object sender, EventArgs e)
{
ClearDocumentTabs();
}
private void WireDocumentContextMenu(Control control)
{
control.MouseUp -= OnDocumentContentMouseUp;
control.MouseUp += OnDocumentContentMouseUp;
foreach (Control child in control.Controls)
{
WireDocumentContextMenu(child);
}
}
private void OnDocumentContentMouseUp(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right || _documentTabStrip.Tabs.Count == 0)
{
return;
}
_documentCloseTabMenuItem.Enabled = !string.IsNullOrEmpty(_documentTabStrip.ActiveTabId);
_documentCloseAllTabsMenuItem.Enabled = _documentTabStrip.Tabs.Count > 0;
var screenPoint = (sender as Control)?.PointToScreen(e.Location) ?? Cursor.Position;
_documentTabMenu.Show(screenPoint);
}
private void CloseDocumentTab(string tabId)
{
if (_documentContents.TryGetValue(tabId, out var control))

View File

@ -113,13 +113,14 @@
// panelOrderItems
//
this.panelOrderItems.BackColor = System.Drawing.SystemColors.Control;
this.panelOrderItems.Controls.Add(this.label3);
this.panelOrderItems.Controls.Add(this.dataGridView1);
this.panelOrderItems.Controls.Add(this.dgvOrderItems);
this.panelOrderItems.Controls.Add(this.label3);
this.panelOrderItems.Dock = System.Windows.Forms.DockStyle.Fill;
this.panelOrderItems.Location = new System.Drawing.Point(0, 0);
this.panelOrderItems.Margin = new System.Windows.Forms.Padding(2);
this.panelOrderItems.Name = "panelOrderItems";
this.panelOrderItems.Padding = new System.Windows.Forms.Padding(8, 4, 8, 0);
this.panelOrderItems.Size = new System.Drawing.Size(1178, 194);
this.panelOrderItems.TabIndex = 0;
//
@ -134,7 +135,7 @@
this.dataGridView1.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dataGridView1.Margin = new System.Windows.Forms.Padding(4);
this.dataGridView1.Margin = new System.Windows.Forms.Padding(0);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.ReadOnly = true;
this.dataGridView1.RowHeadersVisible = false;
@ -165,12 +166,12 @@
// label3
//
this.label3.Dock = System.Windows.Forms.DockStyle.Top;
this.label3.Font = new System.Drawing.Font("Segoe UI", 10.2F);
this.label3.Location = new System.Drawing.Point(2, 4);
this.label3.Font = new System.Drawing.Font("Segoe UI Semibold", 10.2F, System.Drawing.FontStyle.Bold);
this.label3.Location = new System.Drawing.Point(8, 4);
this.label3.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label3.Name = "label3";
this.label3.Padding = new System.Windows.Forms.Padding(6, 4, 0, 4);
this.label3.Size = new System.Drawing.Size(1178, 31);
this.label3.Padding = new System.Windows.Forms.Padding(0, 2, 0, 8);
this.label3.Size = new System.Drawing.Size(1162, 34);
this.label3.TabIndex = 0;
this.label3.Text = "Позиции заказа";
//

View File

@ -46,6 +46,7 @@ namespace Электронная_Фармация.UserControls
ApplyToolbarLayout();
ModernButtonStyles.ApplyClear(btnClearGoodSearch);
ModernButtonStyles.ApplyClear(btnClearOrderNumberFilter);
label3.BringToFront();
panelToolbar.Resize += (_, __) => ApplyToolbarLayout();
}

View File

@ -367,9 +367,9 @@
//
this.btnClearSearchInPriceList.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnClearSearchInPriceList.Font = new System.Drawing.Font("Segoe UI", 9.75F);
this.btnClearSearchInPriceList.Location = new System.Drawing.Point(393, 7);
this.btnClearSearchInPriceList.Location = new System.Drawing.Point(393, 9);
this.btnClearSearchInPriceList.Name = "btnClearSearchInPriceList";
this.btnClearSearchInPriceList.Size = new System.Drawing.Size(32, 30);
this.btnClearSearchInPriceList.Size = new System.Drawing.Size(32, 32);
this.btnClearSearchInPriceList.TabIndex = 9;
this.btnClearSearchInPriceList.Text = "×";
this.btnClearSearchInPriceList.Click += new System.EventHandler(this.btnClearSearchInPriceList_Click);

View File

@ -10,6 +10,7 @@ using System.Windows.Forms;
using System.Data.SQLite;
using System.Data.OleDb;
using System.Data.Common;
using Elfisa.UI.Controls;
using Электроннаяармация.Classes;
using Электроннаяармация.HelpForms;
@ -52,9 +53,7 @@ namespace Электронная_Фармация.UserControls
Tag = "chrome-child";
btnDeleteGood.Height = 34;
btnClearSearchInPriceList.Height = 32;
txtSearchGoodNameInPriceList.Height = 32;
btnClearSupplierFilter.Height = 32;
AlignSearchRow();
panel1.SizeChanged += (_, __) => LayoutMarkupRow();
LayoutMarkupRow();
@ -70,6 +69,23 @@ namespace Электронная_Фармация.UserControls
txtSearchGoodNameInPriceList.Focus();
}
private void AlignSearchRow()
{
const int searchY = 9;
const int searchHeight = 32;
const int clearGap = 2;
txtSearchGoodNameInPriceList.SetBounds(78, searchY, 313, searchHeight);
btnClearSearchInPriceList.SetBounds(
txtSearchGoodNameInPriceList.Right + clearGap,
searchY,
32,
searchHeight);
ModernButtonStyles.ApplyClear(btnClearSearchInPriceList);
btnClearSupplierFilter.Height = searchHeight;
}
private void LayoutMarkupRow()
{
// Keep markup row readable at different DPI/window sizes.

View File

@ -426,11 +426,17 @@ namespace Elfisa.UI.Controls
{
if (_compactIconMode)
{
var textBounds = bounds;
if (Text == "×")
{
textBounds.Offset(1, -2);
}
TextRenderer.DrawText(
g,
Text,
Font,
bounds,
textBounds,
textColor,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine);
return;

View File

@ -30,6 +30,12 @@ namespace Elfisa.UI.Controls
public event EventHandler<string> TabSelected;
public event EventHandler<string> TabClosed;
public event EventHandler TabCloseAllRequested;
private readonly ContextMenuStrip _contextMenu;
private readonly ToolStripMenuItem _closeTabMenuItem;
private readonly ToolStripMenuItem _closeAllTabsMenuItem;
private string _contextMenuTabId;
public ModernDocumentTabStrip()
{
@ -40,6 +46,22 @@ namespace Elfisa.UI.Controls
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw, true);
_closeTabMenuItem = new ToolStripMenuItem("Закрыть вкладку");
_closeTabMenuItem.Click += (_, __) =>
{
if (!string.IsNullOrEmpty(_contextMenuTabId))
{
TabClosed?.Invoke(this, _contextMenuTabId);
}
};
_closeAllTabsMenuItem = new ToolStripMenuItem("Закрыть все вкладки");
_closeAllTabsMenuItem.Click += (_, __) => TabCloseAllRequested?.Invoke(this, EventArgs.Empty);
_contextMenu = new ContextMenuStrip();
_contextMenu.Items.Add(_closeTabMenuItem);
_contextMenu.Items.Add(_closeAllTabsMenuItem);
}
public IReadOnlyList<DocumentTabInfo> Tabs => _tabs;
@ -218,6 +240,11 @@ namespace Elfisa.UI.Controls
protected override void OnMouseClick(MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
{
return;
}
var tabId = HitTestClose(e.Location);
if (!string.IsNullOrEmpty(tabId))
{
@ -253,6 +280,19 @@ namespace Elfisa.UI.Controls
base.OnMouseLeave(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (e.Button == MouseButtons.Right && _tabs.Count > 0)
{
_contextMenuTabId = HitTest(e.Location) ?? _activeTabId;
_closeTabMenuItem.Enabled = !string.IsNullOrEmpty(_contextMenuTabId);
_closeAllTabsMenuItem.Enabled = _tabs.Count > 0;
_contextMenu.Show(this, e.Location);
}
base.OnMouseUp(e);
}
private string HitTest(Point location)
{
foreach (var pair in _hitAreas)