Add project files.

This commit is contained in:
roman
2026-06-05 22:02:32 +02:00
parent f09ad1b7c6
commit 274d607d54
25 changed files with 5462 additions and 0 deletions
+472
View File
@@ -0,0 +1,472 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace BoxPacker3D
{
/// <summary>
/// Modal dialog for managing the item template database.
/// Allows adding, editing, and deleting saved item templates.
/// </summary>
public class ItemDatabaseEditor : Form
{
private ItemDatabase _db;
private DataGridView _grid;
private TextBox _txtSearch;
private Button _btnAdd, _btnEdit, _btnDelete, _btnClose;
private List<ItemTemplate> _allTemplates = new List<ItemTemplate>();
public ItemDatabaseEditor(ItemDatabase db)
{
_db = db;
BuildUI();
LoadData();
}
private void BuildUI()
{
this.Text = "Správa databázy kusov";
this.Size = new Size(700, 500);
this.MinimumSize = new Size(600, 400);
this.StartPosition = FormStartPosition.CenterParent;
this.BackColor = Color.FromArgb(30, 30, 40);
this.AutoScaleMode = AutoScaleMode.Dpi;
// Bottom panel with Close button (add FIRST for proper docking)
var pnlBottom = new Panel
{
Dock = DockStyle.Bottom,
Height = 50,
BackColor = Color.FromArgb(25, 25, 35),
Padding = new Padding(10, 8, 10, 8)
};
_btnClose = MakeButton("✖ Zavrieť", Color.FromArgb(60, 60, 80));
_btnClose.Dock = DockStyle.Right;
_btnClose.Width = 120;
_btnClose.Click += (s, e) => this.Close();
pnlBottom.Controls.Add(_btnClose);
this.Controls.Add(pnlBottom);
// DataGridView (add SECOND so it fills remaining space)
_grid = new DataGridView
{
Dock = DockStyle.Fill,
BackgroundColor = Color.FromArgb(40, 40, 55),
GridColor = Color.FromArgb(60, 60, 80),
BorderStyle = BorderStyle.None,
RowHeadersVisible = false,
AllowUserToAddRows = false,
AllowUserToDeleteRows = false,
ReadOnly = true,
SelectionMode = DataGridViewSelectionMode.FullRowSelect,
MultiSelect = false,
AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill,
EnableHeadersVisualStyles = false
};
_grid.DefaultCellStyle.BackColor = Color.FromArgb(40, 40, 55);
_grid.DefaultCellStyle.ForeColor = Color.White;
_grid.DefaultCellStyle.SelectionBackColor = Color.FromArgb(60, 100, 160);
_grid.DefaultCellStyle.SelectionForeColor = Color.White;
_grid.ColumnHeadersDefaultCellStyle.BackColor = Color.FromArgb(30, 30, 45);
_grid.ColumnHeadersDefaultCellStyle.ForeColor = Color.FromArgb(100, 200, 255);
_grid.ColumnHeadersDefaultCellStyle.Font = new Font("Segoe UI", 9f, FontStyle.Bold);
_grid.Columns.Add("Id", "ID");
_grid.Columns.Add("Name", "Názov");
_grid.Columns.Add("Width", "Šírka (mm)");
_grid.Columns.Add("Height", "Výška (mm)");
_grid.Columns.Add("Depth", "Dĺžka (mm)");
_grid.Columns[0].Width = 60; // ID column narrow
_grid.DoubleClick += (s, e) => BtnEdit_Click(s, e); // double-click = edit
this.Controls.Add(_grid);
// Search panel (add THIRD - will dock at top but below button panel)
var pnlSearch = new Panel
{
Dock = DockStyle.Top,
Height = 45,
BackColor = Color.FromArgb(30, 30, 40),
Padding = new Padding(10, 8, 10, 8)
};
var lblSearch = new Label
{
Text = "🔍 Hľadať:",
ForeColor = Color.FromArgb(180, 180, 200),
AutoSize = true,
Location = new Point(10, 13)
};
_txtSearch = new TextBox
{
BackColor = Color.FromArgb(45, 45, 60),
ForeColor = Color.White,
BorderStyle = BorderStyle.FixedSingle,
Font = new Font("Segoe UI", 10f),
Location = new Point(95, 10),
Width = 300
};
_txtSearch.TextChanged += (s, e) => ApplyFilter(_txtSearch.Text);
pnlSearch.Controls.Add(lblSearch);
pnlSearch.Controls.Add(_txtSearch);
this.Controls.Add(pnlSearch);
// Top panel with buttons (add LAST - will be at the very top)
var pnlTop = new Panel
{
Dock = DockStyle.Top,
Height = 50,
BackColor = Color.FromArgb(25, 25, 35),
Padding = new Padding(10, 8, 10, 8)
};
var flow = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
FlowDirection = FlowDirection.LeftToRight,
WrapContents = false,
AutoSize = false
};
_btnAdd = MakeButton(" Pridať nový kus", Color.FromArgb(40, 120, 60));
_btnAdd.Click += BtnAdd_Click;
_btnEdit = MakeButton("✏️ Upraviť vybraný", Color.FromArgb(60, 100, 160));
_btnEdit.Click += BtnEdit_Click;
_btnDelete = MakeButton("🗑 Zmazať vybraný", Color.FromArgb(140, 40, 40));
_btnDelete.Click += BtnDelete_Click;
flow.Controls.Add(_btnAdd);
flow.Controls.Add(_btnEdit);
flow.Controls.Add(_btnDelete);
pnlTop.Controls.Add(flow);
this.Controls.Add(pnlTop);
}
private Button MakeButton(string text, Color bg)
{
return new Button
{
Text = text,
BackColor = bg,
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat,
Font = new Font("Segoe UI", 9f, FontStyle.Bold),
Height = 34,
Width = 160,
Margin = new Padding(0, 0, 8, 0),
Cursor = Cursors.Hand
};
}
private void LoadData()
{
_grid.Rows.Clear();
_allTemplates.Clear();
if (_db == null) return;
try
{
_allTemplates = _db.GetAll();
ApplyFilter(_txtSearch?.Text ?? "");
}
catch (Exception ex)
{
MessageBox.Show($"Chyba pri načítaní databázy:\n{ex.Message}", "Chyba",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ApplyFilter(string searchText)
{
_grid.Rows.Clear();
var filtered = string.IsNullOrWhiteSpace(searchText)
? _allTemplates
: _allTemplates.Where(t => t.Name.Contains(searchText, StringComparison.OrdinalIgnoreCase)).ToList();
foreach (var t in filtered)
_grid.Rows.Add(t.Id, t.Name, t.Width, t.Height, t.Depth);
}
private void BtnAdd_Click(object sender, EventArgs e)
{
using (var dlg = new ItemEditDialog(null))
{
if (dlg.ShowDialog(this) == DialogResult.OK)
{
try
{
// Check for duplicates
var duplicate = _db.FindDuplicate(dlg.Template);
if (duplicate != null)
{
string msg;
if (duplicate.Name.Equals(dlg.Template.Name, StringComparison.OrdinalIgnoreCase))
msg = $"Kus s názvom \"{duplicate.Name}\" už existuje v databáze.\n\nRozmery: {duplicate.Width}×{duplicate.Height}×{duplicate.Depth} mm";
else
msg = $"Kus s rovnakými rozmermi ({duplicate.Width}×{duplicate.Height}×{duplicate.Depth} mm) už existuje v databáze pod názvom \"{duplicate.Name}\".";
MessageBox.Show(msg, "Duplikát", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
_db.Upsert(dlg.Template);
LoadData();
}
catch (Exception ex)
{
MessageBox.Show($"Chyba pri ukladaní:\n{ex.Message}", "Chyba",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
private void BtnEdit_Click(object sender, EventArgs e)
{
if (_grid.SelectedRows.Count == 0)
{
MessageBox.Show("Vyberte kus na úpravu.", "Upozornenie",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var row = _grid.SelectedRows[0];
var template = new ItemTemplate
{
Id = Convert.ToInt32(row.Cells[0].Value),
Name = row.Cells[1].Value?.ToString() ?? "",
Width = Convert.ToDouble(row.Cells[2].Value),
Height = Convert.ToDouble(row.Cells[3].Value),
Depth = Convert.ToDouble(row.Cells[4].Value)
};
using (var dlg = new ItemEditDialog(template))
{
if (dlg.ShowDialog(this) == DialogResult.OK)
{
try
{
// Check for duplicates (excluding self)
var duplicate = _db.FindDuplicate(dlg.Template);
if (duplicate != null && duplicate.Id != dlg.Template.Id)
{
string msg;
if (duplicate.Name.Equals(dlg.Template.Name, StringComparison.OrdinalIgnoreCase))
msg = $"Kus s názvom \"{duplicate.Name}\" už existuje v databáze.\n\nRozmery: {duplicate.Width}×{duplicate.Height}×{duplicate.Depth} mm";
else
msg = $"Kus s rovnakými rozmermi ({duplicate.Width}×{duplicate.Height}×{duplicate.Depth} mm) už existuje v databáze pod názvom \"{duplicate.Name}\".";
MessageBox.Show(msg, "Duplikát", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
_db.Upsert(dlg.Template);
LoadData();
}
catch (Exception ex)
{
MessageBox.Show($"Chyba pri ukladaní:\n{ex.Message}", "Chyba",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
private void BtnDelete_Click(object sender, EventArgs e)
{
if (_grid.SelectedRows.Count == 0)
{
MessageBox.Show("Vyberte kus na zmazanie.", "Upozornenie",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var row = _grid.SelectedRows[0];
string name = row.Cells[1].Value?.ToString() ?? "";
var dr = MessageBox.Show(
$"Naozaj zmazať kus \"{name}\" z databázy?\n\nTáto akcia je nevratná.",
"Potvrdenie zmazania",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning);
if (dr == DialogResult.Yes)
{
try
{
_db.DeleteByName(name);
LoadData();
}
catch (Exception ex)
{
MessageBox.Show($"Chyba pri mazaní:\n{ex.Message}", "Chyba",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
/// <summary>
/// Small dialog for adding/editing a single item template.
/// </summary>
internal class ItemEditDialog : Form
{
public ItemTemplate Template { get; private set; }
private TextBox _txtName;
private NumericUpDown _nudW, _nudH, _nudD;
public ItemEditDialog(ItemTemplate existing)
{
Template = existing ?? new ItemTemplate();
BuildUI();
}
private void BuildUI()
{
this.Text = Template.Id == 0 ? "Nový kus" : "Úprava kusu";
this.Size = new Size(400, 280);
this.StartPosition = FormStartPosition.CenterParent;
this.FormBorderStyle = FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.BackColor = Color.FromArgb(35, 35, 48);
this.AutoScaleMode = AutoScaleMode.Dpi;
var tbl = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 5,
Padding = new Padding(15)
};
tbl.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 120));
tbl.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
tbl.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tbl.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tbl.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tbl.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tbl.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
tbl.Controls.Add(MakeLabel("Názov:"), 0, 0);
_txtName = new TextBox
{
Text = Template.Name,
Dock = DockStyle.Fill,
BackColor = Color.FromArgb(45, 45, 60),
ForeColor = Color.White,
BorderStyle = BorderStyle.FixedSingle,
Margin = new Padding(0, 3, 0, 8)
};
tbl.Controls.Add(_txtName, 1, 0);
tbl.Controls.Add(MakeLabel("Šírka (mm):"), 0, 1);
_nudW = MakeNUD(Template.Width);
tbl.Controls.Add(_nudW, 1, 1);
tbl.Controls.Add(MakeLabel("Výška (mm):"), 0, 2);
_nudH = MakeNUD(Template.Height);
tbl.Controls.Add(_nudH, 1, 2);
tbl.Controls.Add(MakeLabel("Dĺžka (mm):"), 0, 3);
_nudD = MakeNUD(Template.Depth);
tbl.Controls.Add(_nudD, 1, 3);
// Buttons
var pnlButtons = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
FlowDirection = FlowDirection.RightToLeft,
Margin = new Padding(0, 10, 0, 0)
};
var btnOk = new Button
{
Text = "✔ Uložiť",
DialogResult = DialogResult.OK,
BackColor = Color.FromArgb(40, 120, 60),
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat,
Font = new Font("Segoe UI", 9f, FontStyle.Bold),
Width = 100,
Height = 32
};
btnOk.Click += (s, e) =>
{
if (string.IsNullOrWhiteSpace(_txtName.Text))
{
MessageBox.Show("Názov nemôže byť prázdny.", "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Warning);
this.DialogResult = DialogResult.None;
return;
}
Template.Name = _txtName.Text.Trim();
Template.Width = (double)_nudW.Value;
Template.Height = (double)_nudH.Value;
Template.Depth = (double)_nudD.Value;
};
var btnCancel = new Button
{
Text = "✖ Zrušiť",
DialogResult = DialogResult.Cancel,
BackColor = Color.FromArgb(80, 80, 100),
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat,
Font = new Font("Segoe UI", 9f),
Width = 100,
Height = 32,
Margin = new Padding(0, 0, 8, 0)
};
pnlButtons.Controls.Add(btnOk);
pnlButtons.Controls.Add(btnCancel);
tbl.Controls.Add(pnlButtons, 0, 4);
tbl.SetColumnSpan(pnlButtons, 2);
this.Controls.Add(tbl);
this.AcceptButton = btnOk;
this.CancelButton = btnCancel;
}
private Label MakeLabel(string text)
{
return new Label
{
Text = text,
ForeColor = Color.FromArgb(180, 180, 200),
AutoSize = true,
Anchor = AnchorStyles.Left,
Margin = new Padding(0, 8, 8, 0)
};
}
private NumericUpDown MakeNUD(double val)
{
return new NumericUpDown
{
Value = (decimal)Math.Max(1, val),
Minimum = 1,
Maximum = 100000,
DecimalPlaces = 0,
Increment = 10,
BackColor = Color.FromArgb(45, 45, 60),
ForeColor = Color.White,
BorderStyle = BorderStyle.FixedSingle,
Dock = DockStyle.Fill,
Margin = new Padding(0, 3, 0, 8)
};
}
}
}