Files
BoxPacker3D/ItemDatabaseEditor.cs
T
2026-06-05 22:02:32 +02:00

473 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
};
}
}
}