using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; namespace BoxPacker3D { /// /// Modal dialog for managing the item template database. /// Allows adding, editing, and deleting saved item templates. /// public class ItemDatabaseEditor : Form { private ItemDatabase _db; private DataGridView _grid; private TextBox _txtSearch; private Button _btnAdd, _btnEdit, _btnDelete, _btnClose; private List _allTemplates = new List(); 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); } } } } /// /// Small dialog for adding/editing a single item template. /// 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) }; } } }