Skip to content

Commit 19f6b04

Browse files
authored
Merge branch 'alpha' into 2446-V100-build-workflow
2 parents cf565a1 + 347eaf7 commit 19f6b04

File tree

403 files changed

+28146
-512
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

403 files changed

+28146
-512
lines changed

Documents/Changelog/Changelog.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
## 2025-11-xx - Build 2511 (V10 - alpha) - November 2025
66
* Implemented [#2446](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2446), Add `build.yml` to `.github/workflows`.
7+
* Implemented [#648](https://github.com/Krypton-Suite/Standard-Toolkit/issues/648), SystemMenu to be theme related
8+
* Resolved [#2128](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2128), (feat) Add `ButtonSpecs` to `KDataGridView` cells when editing.
79
* Resolved [#2463](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2463), `KryptonForm` has incorrect title-bar button behaviour.
810
* Resolved [#2452](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2452), Fix: prevent resizing on fixed borders; gate Material hit-band by FormBorderStyle.
911
* Resolved [#2436](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2436), Guard GetResolvedPalette nulls; use CurrentGlobalPalette fallback.
@@ -16,7 +18,7 @@
1618
* Implemented [#984](https://github.com/Krypton-Suite/Standard-Toolkit/issues/984), `KryptonForm` using `SizeGripStyle` for grippie.
1719
- **Note:** This has a breaking change for custom themes as a new abstract method is introduced in the `PaletteBase` class for sizegrip images!
1820
* Implemented [#2396](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2396), Added ModernBuild terminal.gui app to solution
19-
* Resolved [#1022](https://github.com/Krypton-Suite/Standard-Toolkit/issues/1022), `Material - Dark` fixes for KDGV painting.
21+
* Resolved [#1022](https://github.com/Krypton-Suite/Standard-Toolkit/issues/1022), `Material - Dark` fixes for KDGV painting
2022
* Resolved [#413](https://github.com/Krypton-Suite/Standard-Toolkit/issues/413), `KryptonRibbon` controls do not react to MouseWheel scolling.
2123
* Resolved [#2424](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2424), Fix `NoClipping` in `AccurateText`; `Ellipsis` conditional.
2224
* Resolved [#2406](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2406), Enhance `KryptonProgressBar` options and painting.

Scripts/ModernBuild/classes/BuildLogic.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,11 @@ private static void StartNuGetPush(AppState state)
784784
var files = new List<string>();
785785
foreach (string f in GetCandidatePackageFolders(state))
786786
{
787-
if (!Directory.Exists(f)) continue;
787+
if (!Directory.Exists(f))
788+
{
789+
continue;
790+
}
791+
788792
files.AddRange(Directory.GetFiles(f, "*.nupkg", SearchOption.TopDirectoryOnly));
789793
if (state.NuGetIncludeSymbols)
790794
{
@@ -1002,11 +1006,17 @@ private static void RunNextNuGetPush(AppState state)
10021006
};
10031007
state.Process.OutputDataReceived += (_, e) =>
10041008
{
1005-
if (!string.IsNullOrEmpty(e.Data)) state.OnOutput?.Invoke(e.Data);
1009+
if (!string.IsNullOrEmpty(e.Data))
1010+
{
1011+
state.OnOutput?.Invoke(e.Data);
1012+
}
10061013
};
10071014
state.Process.ErrorDataReceived += (_, e) =>
10081015
{
1009-
if (!string.IsNullOrEmpty(e.Data)) state.OnOutput?.Invoke(e.Data);
1016+
if (!string.IsNullOrEmpty(e.Data))
1017+
{
1018+
state.OnOutput?.Invoke(e.Data);
1019+
}
10101020
};
10111021
state.Process.Exited += (_, __) =>
10121022
{
@@ -1040,7 +1050,11 @@ internal static void PreviewNuGetCommands(AppState state)
10401050
var files = new List<string>();
10411051
foreach (string f in GetCandidatePackageFolders(state))
10421052
{
1043-
if (!Directory.Exists(f)) continue;
1053+
if (!Directory.Exists(f))
1054+
{
1055+
continue;
1056+
}
1057+
10441058
files.AddRange(Directory.GetFiles(f, "*.nupkg", SearchOption.TopDirectoryOnly));
10451059
if (state.NuGetIncludeSymbols)
10461060
{
@@ -1062,7 +1076,11 @@ internal static void PreviewNuGetCommands(AppState state)
10621076
foreach (string pkg in files)
10631077
{
10641078
var cmd = new StringBuilder().Append("nuget.exe push \"").Append(pkg).Append("\" ");
1065-
if (state.NuGetSkipDuplicate) cmd.Append("-SkipDuplicate ");
1079+
if (state.NuGetSkipDuplicate)
1080+
{
1081+
cmd.Append("-SkipDuplicate ");
1082+
}
1083+
10661084
cmd.Append("-NonInteractive ");
10671085
if (!string.IsNullOrWhiteSpace(resolvedSource))
10681086
{

Scripts/ModernBuild/classes/BuildUI.cs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -774,13 +774,25 @@ string FormatAction(BuildAction a)
774774
{
775775
ui.Tx4.Text = "Page Ops (F4 to switch)";
776776
}
777-
if (ui.Tx6 != null) ui.Tx6.Text = $"Tail {state.TailLines}";
777+
if (ui.Tx6 != null)
778+
{
779+
ui.Tx6.Text = $"Tail {state.TailLines}";
780+
}
781+
778782
if (ui.Tx5 != null)
779783
{
780784
ui.Tx5.Text = $"Run/Stop {(state.IsRunning ? "Stop" : "Run")}";
781785
}
782-
if (ui.Tx7 != null) ui.Tx7.Text = "Clean Delete Bin/obj/Logs";
783-
if (ui.Tx8 != null) ui.Tx8.Text = "Clear Clear live output";
786+
if (ui.Tx7 != null)
787+
{
788+
ui.Tx7.Text = "Clean Delete Bin/obj/Logs";
789+
}
790+
791+
if (ui.Tx8 != null)
792+
{
793+
ui.Tx8.Text = "Clear Clear live output";
794+
}
795+
784796
if (ui.TxEsc != null)
785797
{
786798
ui.TxEsc.Text = "Exit Exit application";
@@ -803,7 +815,11 @@ string FormatAction(BuildAction a)
803815
{
804816
if (ui.Tx9 != null) { ui.Tx9.Text = "PackMode (Stable only)"; }
805817
}
806-
if (ui.TestBtn != null) ui.TestBtn.Visible = false;
818+
if (ui.TestBtn != null)
819+
{
820+
ui.TestBtn.Visible = false;
821+
}
822+
807823
if (ui.TxTest != null) { ui.TxTest.Visible = false; ui.TxTest.Text = string.Empty; }
808824
if (ui.Hint != null)
809825
{
@@ -843,8 +859,16 @@ string FormatAction(BuildAction a)
843859
{
844860
ui.Tx5.Text = $"Run/Stop {(state.IsRunning ? "Stop" : "Run")}";
845861
}
846-
if (ui.Tx6 != null) ui.Tx6.Text = $"Symbols {(state.NuGetIncludeSymbols ? "Yes" : "No")}";
847-
if (ui.Tx7 != null) ui.Tx7.Text = $"SkipDup {(state.NuGetSkipDuplicate ? "Yes" : "No")}";
862+
if (ui.Tx6 != null)
863+
{
864+
ui.Tx6.Text = $"Symbols {(state.NuGetIncludeSymbols ? "Yes" : "No")}";
865+
}
866+
867+
if (ui.Tx7 != null)
868+
{
869+
ui.Tx7.Text = $"SkipDup {(state.NuGetSkipDuplicate ? "Yes" : "No")}";
870+
}
871+
848872
if (ui.Tx8 != null)
849873
{
850874
string src = FormatNuGetSource(state.NuGetSource, state.NuGetCustomSource);
@@ -855,7 +879,11 @@ string FormatAction(BuildAction a)
855879
bool showZip = state.NuGetAction == NuGetAction.RebuildPack || state.NuGetAction == NuGetAction.PackPush || state.NuGetAction == NuGetAction.BuildPackPush;
856880
ui.CreateZip.Visible = showZip;
857881
}
858-
if (ui.TestBtn != null) ui.TestBtn.Visible = true;
882+
if (ui.TestBtn != null)
883+
{
884+
ui.TestBtn.Visible = true;
885+
}
886+
859887
if (ui.TxTest != null) { ui.TxTest.Visible = true; ui.TxTest.Text = "Test Preview commands"; }
860888
if (ui.Tx9 != null) { ui.Tx9.Text = "PackMode (Stable only)"; }
861889
if (ui.TxEsc != null)

Source/Krypton Components/Krypton Toolkit Suite 2022 - VS2022.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
<File Path="../../Documents/Development/Development-Workflow.md" />
6767
<File Path="../../Documents/Development/How to Manage Using Statements.md" />
6868
<File Path="../../Documents/Development/How-to-Build.md" />
69+
<File Path="Themed-System-Menu.md" />
6970
</Folder>
7071
<Folder Name="/Solution Items/Documentation/GitHub/" />
7172
<Folder Name="/Solution Items/Documentation/GitHub/Issue Templates/">

Source/Krypton Components/Krypton.Toolkit/ButtonSpec/ButtonSpecView.cs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#region BSD License
22
/*
3-
*
3+
*
44
* Original BSD 3-Clause License (https://github.com/ComponentFactory/Krypton/blob/master/LICENSE)
55
* © Component Factory Pty Ltd, 2006 - 2016, (Version 4.5.0.0) All rights reserved.
6-
*
6+
*
77
* New BSD 3-Clause License (https://github.com/Krypton-Suite/Standard-Toolkit/blob/master/LICENSE)
8-
* Modifications by Peter Wagner (aka Wagnerp), Simon Coghlan (aka Smurf-IV), Giduac & Ahmed Abdelhameed et al. 2017 - 2025. All rights reserved.
9-
*
8+
* Modifications by Peter Wagner (aka Wagnerp), Simon Coghlan (aka Smurf-IV), Giduac, Ahmed Abdelhameed, tobitege et al. 2017 - 2025. All rights reserved.
9+
*
1010
*/
1111
#endregion
1212

@@ -321,11 +321,30 @@ protected virtual void OnFinishDelegate(object? sender, EventArgs? e) =>
321321
// Get value from button spec passing inheritance redirector
322322
Image? baseImage = ButtonSpec.GetImage(_redirector, state);
323323

324+
if (baseImage == null)
325+
{
326+
return null;
327+
}
328+
329+
// Default behavior: DPI scale other ButtonSpec styles
324330
float dpiFactor = _controller?.Target.FactorDpiX ?? 1f;
325-
return (baseImage != null)
326-
? CommonHelper.ScaleImageForSizedDisplay(baseImage, baseImage.Width * dpiFactor,
327-
baseImage.Height * dpiFactor, true)
328-
: null;
331+
332+
// For InputControl buttons (editing controls), enforce a consistent 16px logical size (DPI-aware)
333+
// to avoid dependency on layout timing where client rectangles can be 0 during early passes.
334+
if (ButtonSpec.GetStyle(_redirector) == ButtonStyle.InputControl)
335+
{
336+
float target = 16f * dpiFactor;
337+
338+
// Preserve aspect ratio
339+
float scale = Math.Min(target / baseImage.Width, target / baseImage.Height);
340+
float targetW = Math.Max(1f, baseImage.Width * scale);
341+
float targetH = Math.Max(1f, baseImage.Height * scale);
342+
343+
return CommonHelper.ScaleImageForSizedDisplay(baseImage, targetW, targetH, true);
344+
}
345+
346+
return CommonHelper.ScaleImageForSizedDisplay(baseImage, baseImage.Width * dpiFactor,
347+
baseImage.Height * dpiFactor, true);
329348
}
330349

331350
/// <summary>

Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonCheckedListBox.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,7 +1974,10 @@ public List<object> CheckedItemList
19741974
{
19751975
var val = prop.GetValue(item);
19761976
if (val != null)
1977+
{
19771978
results.Add(val);
1979+
}
1980+
19781981
continue;
19791982
}
19801983
}

Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridView.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ private class ToolTipContent : IContentValues
156156
[Category(@"Property Changed")]
157157
[Description(@"Occurs when the value of the Palette property is changed.")]
158158
public event EventHandler? PaletteChanged;
159+
160+
/// <summary>
161+
/// Occurs when a ButtonSpec inside a cell's editing control is clicked.
162+
/// </summary>
163+
[Category(@"Action")]
164+
[Description(@"Occurs when a button specification is clicked in a cell's editing control.")]
165+
public event EventHandler<DataGridViewButtonSpecClickEventArgs>? EditingControlButtonSpecClick;
159166
#endregion
160167

161168
#region Identity
@@ -2905,6 +2912,11 @@ private void OnSyncBackPropertyChanged(object? sender, PropertyChangedEventArgs
29052912
#endregion
29062913

29072914
#region Menus
2915+
/// <summary>
2916+
/// Handles the opening of the assigned <see cref="ContextMenuStrip"/> to ensure the correct renderer is applied.
2917+
/// </summary>
2918+
/// <param name="sender">The source of the event.</param>
2919+
/// <param name="e">A <see cref="CancelEventArgs"/> that contains the event data.</param>
29082920
private void OnContextMenuStripOpening(object? sender, CancelEventArgs e)
29092921
{
29102922
// Get the actual strip instance
@@ -2988,4 +3000,50 @@ protected override void WndProc(ref Message m)
29883000
base.WndProc(ref m);
29893001
}
29903002
#endregion menus
3003+
3004+
#region Column ButtonSpec wiring
3005+
/// <summary>
3006+
/// Wire column-specific ButtonSpec click events when a column is added.
3007+
/// </summary>
3008+
/// <param name="e">Column event args.</param>
3009+
protected override void OnColumnAdded(DataGridViewColumnEventArgs e)
3010+
{
3011+
base.OnColumnAdded(e);
3012+
3013+
if (e.Column is KryptonDataGridViewIconColumn iconCol)
3014+
{
3015+
iconCol.ButtonSpecClick += OnColumnButtonSpecClick;
3016+
}
3017+
}
3018+
3019+
/// <summary>
3020+
/// Unwire column-specific ButtonSpec click events when a column is removed.
3021+
/// </summary>
3022+
/// <param name="e">Column event args.</param>
3023+
protected override void OnColumnRemoved(DataGridViewColumnEventArgs e)
3024+
{
3025+
if (e.Column is KryptonDataGridViewIconColumn iconCol)
3026+
{
3027+
iconCol.ButtonSpecClick -= OnColumnButtonSpecClick;
3028+
}
3029+
3030+
base.OnColumnRemoved(e);
3031+
}
3032+
3033+
/// <summary>
3034+
/// Forwards column-level ButtonSpec click notifications to the grid-level
3035+
/// <see cref="EditingControlButtonSpecClick"/> event while guarding disposal.
3036+
/// </summary>
3037+
/// <param name="sender">The source column raising the event.</param>
3038+
/// <param name="e">Event arguments containing column, cell and ButtonSpec.</param>
3039+
private void OnColumnButtonSpecClick(object? sender, DataGridViewButtonSpecClickEventArgs e)
3040+
{
3041+
if (IsDisposed || Disposing)
3042+
{
3043+
return;
3044+
}
3045+
3046+
EditingControlButtonSpecClick?.Invoke(this, e);
3047+
}
3048+
#endregion
29913049
}

Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxCell.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,18 @@ public override void InitializeEditingControl(int rowIndex,
355355
}
356356

357357
_selectedItemText = comboBox.Text;
358+
359+
if (KryptonOwningColumn is KryptonDataGridViewComboBoxColumn comboColumn)
360+
{
361+
KryptonDataGridViewUtilities.SyncEditorButtonSpecs(DataGridView as KryptonDataGridView, comboColumn, comboBox.ButtonSpecs);
362+
foreach (var spec in comboBox.ButtonSpecs.Enumerate().OfType<ButtonSpecAny>())
363+
{
364+
spec.Click += (s, e) =>
365+
comboColumn.RaiseButtonSpecClick(new DataGridViewButtonSpecClickEventArgs(comboColumn, this, spec));
366+
}
367+
comboBox.PerformLayout();
368+
comboBox.Invalidate();
369+
}
358370
}
359371
}
360372

@@ -381,11 +393,9 @@ public override void PositionEditingControl(bool setLocation,
381393

382394
if (DataGridView?.EditingControl is not null)
383395
{
384-
bool rtl = DataGridView.RightToLeft == RightToLeft.Yes;
385-
int locX = rtl ? editingControlBounds.X : editingControlBounds.X + IndicatorGap;
386-
int width = editingControlBounds.Width - IndicatorGap;
387-
DataGridView.EditingControl.Location = new Point(locX, editingControlBounds.Y);
388-
DataGridView.EditingControl.Size = new Size(width, IndicatorSize - 2);
396+
// Use full bounds during edit so the editor can layout its own adornments (drop button, ButtonSpecs)
397+
DataGridView.EditingControl.Location = new Point(editingControlBounds.X, editingControlBounds.Y);
398+
DataGridView.EditingControl.Size = new Size(editingControlBounds.Width, editingControlBounds.Height);
389399
}
390400
}
391401

Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxColumn.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace Krypton.Toolkit;
1818
/// Hosts a collection of KryptonDataGridViewComboBoxCell cells.
1919
/// </summary>
2020
[ToolboxBitmap(typeof(KryptonDataGridViewComboBoxColumn), "ToolboxBitmaps.KryptonComboBox.bmp")]
21+
[Designer(typeof(KryptonComboBoxColumnDesigner))]
2122
public partial class KryptonDataGridViewComboBoxColumn : KryptonDataGridViewIconColumn
2223
{
2324
#region Identity
@@ -74,6 +75,8 @@ public override object Clone()
7475

7576
cloned.AutoCompleteCustomSource.AddRange(strings);
7677

78+
cloned.SyncEditorOnButtonSpecClick = SyncEditorOnButtonSpecClick;
79+
7780
return cloned;
7881
}
7982
#endregion
@@ -100,6 +103,41 @@ public override DataGridViewCell? CellTemplate {
100103
}
101104
}
102105

106+
/// <summary>
107+
/// If true, synchronizes the editing control text from the cell Value after ButtonSpecClick handlers run.
108+
/// </summary>
109+
[Category(@"Behavior")]
110+
[DefaultValue(true)]
111+
[Description(@"If enabled, assigns the current cell Value to the active editor after ButtonSpec clicks.")]
112+
public bool SyncEditorOnButtonSpecClick { get; set; } = true;
113+
114+
/// <inheritdoc/>
115+
protected override void OnButtonSpecClickCore(DataGridViewButtonSpecClickEventArgs e)
116+
{
117+
base.OnButtonSpecClickCore(e);
118+
119+
if (!SyncEditorOnButtonSpecClick)
120+
{
121+
return;
122+
}
123+
124+
var grid = e.Column.DataGridView;
125+
if (grid is { IsDisposed: true } || grid?.Disposing == true)
126+
{
127+
return;
128+
}
129+
if (grid?.IsCurrentCellInEditMode == true
130+
&& ReferenceEquals(grid.CurrentCell, e.Cell)
131+
&& grid.EditingControl is Control editor)
132+
{
133+
var newText = Convert.ToString(e.Cell.FormattedValue, CultureInfo.CurrentCulture) ?? string.Empty;
134+
if (!string.Equals(editor.Text, newText, StringComparison.Ordinal))
135+
{
136+
editor.Text = newText;
137+
}
138+
}
139+
}
140+
103141
/// <summary>
104142
/// Gets the collection of allowable items of the domain up down.
105143
/// </summary>

0 commit comments

Comments
 (0)