# AlfaToad.DefaultScreens

NuGet-пакет **готовых экранных форм** для типового WinForms-приложения с ролевым доступом.

Использует [AlfaToad.CustomControls](https://www.nuget.org/packages/AlfaToad.CustomControls) и [AlfaToad.DataSetCRUDS](https://www.nuget.org/packages/AlfaToad.DataSetCRUDS).

## Возможности

| Экран | Описание |
|-------|----------|
| `LoginScreenForm` | Вход по логину/паролю из DataSet + режим гостя |
| `MainShellForm` | Главная форма с логотипом, навигацией, кнопкой «Назад» и отображением текущего экрана в заголовке |
| `CatalogScreenForm` | Каталог на `ScrollableDetailPanel` с учётом роли |
| `OrderListScreenForm` | Заказы на `ScrollableOrderPanel` |
| `ApplicationNavigator` | Полный сценарий: вход → главная → экраны |

### Настройка через `ApplicationScreenSettings`

- Заголовки окон, тексты кнопок, подписи полей входа
- `Appearance` — палитра цветов (#FFFFFF, #F5DEB3, #DEB887, Arial)
- `LogoImagePath`, `ApplicationIconPath`, `NoImagePath` + `ApplyResourcePaths()`
- `LoginFormWidth`, `LoginFormHeight`, `LoginLogoHeight`
- `DetailFields`, `OrderFields` — карты столбцов БД
- `CreateCatalogCrudOptions()` / `CreateOrderCrudOptions()` — параметры CRUD-форм
- `BackMenuText` — текст кнопки «Назад»
- `ImageResizeWidth` / `ImageResizeHeight` — ресайз фото товара (300×200)

Сообщения пользователю — через `AppDialog` (ошибка / предупреждение / информация).

## Установка

```bash
dotnet add package AlfaToad.DefaultScreens --version 1.0.5
```

## Пример `Program.cs` (Typed DataSet + view persistence)

```csharp
using System;
using System.Drawing;
using System.Windows.Forms;
using AlfaToad.CustomControls.Theme;              // AppearancePalette — цвета и шрифты
using AlfaToad.DataSetCRUDS.Configuration;      // DetailRecordFieldMap, OrderRecordFieldMap
using AlfaToad.DefaultScreens.Configuration;      // ApplicationScreenSettings, WithViewDataPersistence
using AlfaToad.DefaultScreens.Navigation;         // ApplicationDataContext, ApplicationNavigator
using YourApp;                                    // ваш Typed DataSet (MirIgryshkiDataSet)
using YourApp.YourDataSetTableAdapters;

namespace YourApp
{
    internal static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            // ═══════════════════════════════════════════════════════════════
            // ШАГ 1. DataSet и TableAdapter-ы
            // Для view достаточно Fill() — Insert/Update/Delete делает пакет
            // ═══════════════════════════════════════════════════════════════
            var dataSet = new MirIgryshkiDataSet(); // замените на ваш Typed DataSet
            var tovarTableAdapter = new vCatalogTableAdapter();
            var ordersTableAdapter = new vOrdersTableAdapter();
            var usersTableAdapter = new vw_UsersLoginTableAdapter();

            // Строка подключения — задайте свои значения или используйте User Secrets / App.config
            var connectionString = "Server=YOUR_SERVER;Database=YOUR_DATABASE;Trusted_Connection=True;";
            /*
              Server=YOUR_SERVER;Database=YOUR_DATABASE;User Id=YOUR_USER;Password=YOUR_PASSWORD;
              Server=YOUR_SERVER;Database=YOUR_DATABASE;Trusted_Connection=True;
            */

            // ═══════════════════════════════════════════════════════════════
            // ШАГ 2. ApplicationScreenSettings — все настройки приложения
            // ═══════════════════════════════════════════════════════════════
            var settings = ApplicationScreenSettings.CreateDefault();

            // ── Заголовки окон ──────────────────────────────────────────
            settings.LoginWindowTitle = "Вход в систему";           // Заголовок формы входа
            settings.MainWindowTitle = "Информационная система";   // Заголовок главной формы (оболочка)
            settings.CatalogWindowTitle = "Каталог товаров";          // Заголовок экрана каталога
            settings.OrdersWindowTitle = "Список заказов";           // Заголовок экрана заказов

            // ── Тексты кнопок и пунктов меню ────────────────────────────
            settings.LoginButtonText = "Войти";              // Кнопка «Войти» на форме входа
            settings.GuestButtonText = "Войти как гость";    // Кнопка гостевого входа
            settings.CatalogMenuText = "Каталог";            // Пункт меню «Каталог» на главной форме
            settings.OrdersMenuText = "Заказы";             // Пункт меню «Заказы»
            settings.LogoutMenuText = "Выход";              // Пункт меню «Выход» (повторный вход)
            settings.BackMenuText = "Назад";                // Кнопка возврата на главную форму

            // ── Экран входа: подписи и размеры ──────────────────────────
            settings.LoginCaptionLogin = "Логин:";    // Подпись слева от поля логина
            settings.LoginCaptionPassword = "Пароль:";   // Подпись слева от поля пароля
            settings.LoginFormWidth = 480;         // Ширина формы входа (px)
            settings.LoginFormHeight = 420;         // Высота формы входа (px) — чтобы кнопки не обрезались
            settings.LoginLogoHeight = 110;         // Высота области логотипа на форме входа (px)

            // ── Пути к ресурсам (загружаются через ApplyResourcePaths) ──
            settings.LogoImagePath = @"C:\Path\To\Your\Resources\icon.png";   // Логотип → settings.LogoImage
            settings.ApplicationIconPath = @"C:\Path\To\Your\Resources\icon.ico";    // Иконка приложения → settings.ApplicationIcon
            settings.NoImagePath = @"C:\Path\To\Your\Resources\picture.png"; // Заглушка «нет фото» → settings.NoImage
            // Либо задайте Image/Icon напрямую (без путей):
            // settings.LogoImage = Image.FromFile(@"C:\Path\To\Your\Resources\logo.png");
            // settings.ApplicationIcon = new Icon(@"C:\Path\To\Your\Resources\app.ico");
            settings.ApplicationIcon = Icon.FromHandle(new Bitmap(@"C:\Path\To\Your\Resources\icon.png").GetHicon()); // Иконка из PNG
            // settings.NoImage = Image.FromFile(@"C:\Path\To\Your\Resources\picture.png");
            settings.ApplyResourcePaths(); // Подставляет LogoImage, NoImage, ApplicationIcon из путей выше

            // ── Папка изображений товаров ───────────────────────────────
            settings.ImagesFolder = @"C:\Path\To\Your\Resources\import"; // Папка с файлами фото (1.jpg, 2.jpg…)
            // Если пусто — используется подпапка Images рядом с exe

            // ── Ресайз фото при добавлении/редактировании товара ──────
            settings.ImageResizeWidth = 300; // Ширина сохраняемого изображения (px)
            settings.ImageResizeHeight = 200; // Высота сохраняемого изображения (px)

            // ── Заголовки CRUD-форм ─────────────────────────────────────
            settings.CatalogAddFormTitle = "Добавление товара";
            settings.CatalogEditFormTitle = "Редактирование товара";
            settings.OrderAddFormTitle = "Добавление заказа";
            settings.OrderEditFormTitle = "Редактирование заказа";

            // ═══════════════════════════════════════════════════════════════
            // ШАГ 3. AppearancePalette — цвета, шрифты, пороги (стиль экзамена)
            // Применяется ко всем экранам: вход, главная, каталог, заказы, CRUD-формы
            // ═══════════════════════════════════════════════════════════════
            settings.Appearance = new AppearancePalette
            {
                // ── Цвета ───────────────────────────────────────────────
                MainBackground = ColorTranslator.FromHtml("#FFFFFF"), // Основной фон форм и строк списка
                SectionBackground = ColorTranslator.FromHtml("#F5DEB3"), // Фон заголовков, панели кнопок, меню
                AccentBackground = ColorTranslator.FromHtml("#DEB887"), // Кнопки, акцентные элементы
                HighlightBackground = ColorTranslator.FromHtml("#FFDEAD"), // Подсветка товара со скидкой > порога
                SelectedRowBackground = ColorTranslator.FromHtml("#E8EEF8"), // Фон выбранной строки в списке
                PrimaryText = Color.Black,                         // Основной цвет текста
                SeparatorText = Color.Gray,                          // Текст разделителей
                BorderColor = Color.Black,                         // Рамка карточек/строк
                RowSeparatorColor = Color.Silver,                          // Линия между строками
                OutOfStockBackground = ColorTranslator.FromHtml("#ADD8E6"), // Фон строки при кол-ве ≤ 0
                StrikethroughPriceColor = Color.Red,                         // Зачёркнутая цена (при скидке)
                FinalPriceColor = Color.Black,                         // Итоговая цена со скидкой
                // ── Шрифты ──────────────────────────────────────────────
                FontFamily = "Arial",  // Семейство шрифта (по заданию экзамена)
                BaseFontSize = 9f,       // Базовый размер текста в списках и формах
                TitleFontSize = 10f,      // Размер заголовков и имён товаров
                // ── Пороги ──────────────────────────────────────────────
                HighlightThresholdPercent = 17m // Скидка > 17% → подсветка HighlightBackground
            };

            // ═══════════════════════════════════════════════════════════════
            // ШАГ 4. Имена столбцов БД — сопоставление с формами редактирования
            // ═══════════════════════════════════════════════════════════════
            settings.DetailFields = new DetailRecordFieldMap
            {
                PrimaryKeyField = "Article",              // Ключ товара (readonly при редактировании)
                NameField = "Наименование товара",  // Название
                CategoryField = "Категория товара",     // Выпадающий список
                DescriptionField = "Описание товара",      // Многострочное описание
                ManufacturerField = "Производитель",        // Выпадающий список
                SupplierField = "Поставщик",              // Выпадающий список
                PriceField = "Цена",                   // ≥ 0, не более 2 знаков после запятой
                UnitField = "Единица измерения",    // шт., упак. и т.д.
                StockField = "Кол-во на складе",       // Целое ≥ 0
                DiscountField = "Действующая скидка",   // 0–100 %
                ImageField = "Фото"                    // Имя файла изображения в БД
            };
            settings.OrderFields = new OrderRecordFieldMap
            {
                OrderNumberField = "OrderId",                    // MAX+1 при добавлении, readonly при ред.
                ArticleField = "Артикул заказа",                  // Состав заказа (только просмотр/текст)
                StatusField = "Статус заказа",                   // Выпадающий список
                AddressField = "Адрес пункта выдачи",             // ID пункта выдачи (int)
                OrderDateField = "Дата заказа",                     // DateTimePicker
                DeliveryDateField = "Дата доставки",                   // Опционально (чекбокс)
                ClientNameField = "ФИО авторизированного клиента",   // Клиент заказа (ComboBox)
                PickupCodeField = "Код для получения"                // Код выдачи
            };

            // ═══════════════════════════════════════════════════════════════
            // ШАГ 5. Авторизация — имена столбцов и ролей из vw_UsersLogin
            // ═══════════════════════════════════════════════════════════════
            settings.LoginFieldName = "Логин";                      // Столбец логина в DataTable
            settings.PasswordFieldName = "Пароль";                     // Столбец пароля
            settings.RoleFieldName = "Роль";            // Столбец роли
            settings.FullNameFieldName = "ФИО";                        // Отображаемое имя пользователя
            // Строковые значения ролей в БД → уровень доступа:
            settings.AdministratorRoleName = "Администратор";             // Полный CRUD каталог + заказы
            settings.ManagerRoleName = "Менеджер";                  // Каталог с фильтром + просмотр заказов
            settings.ClientRoleName = "Авторизированный клиент";   // Только просмотр каталога

            // ═══════════════════════════════════════════════════════════════
            // ШАГ 6. ApplicationDataContext — DataSet, загрузка, сохранение
            // ═══════════════════════════════════════════════════════════════
            var data = new ApplicationDataContext
            {
                // ── DataSet и имена таблиц ──────────────────────────────
                CatalogDataSet = dataSet,
                CatalogTableName = "vCatalog",       // Таблица каталога в DataSet
                OrdersDataSet = dataSet,           // Можно один DataSet на всё приложение
                OrdersTableName = "vOrders",
                UsersDataSet = dataSet,
                UsersTableName = "vw_UsersLogin",
                // ── Загрузка данных (только Fill — Update в TableAdapter не нужен) ──
                LoadUsers = () => usersTableAdapter.Fill(dataSet.vw_UsersLogin),
                LoadCatalog = () => tovarTableAdapter.Fill(dataSet.vCatalog),
                LoadOrders = () => ordersTableAdapter.Fill(dataSet.vOrders),
                // PersistCatalogChanges / PersistOrderChanges можно не задавать —
                // подключатся автоматически через WithViewDataPersistence ниже
            }
            // Insert/Update/Delete для view без правки .xsd:
            // ViewPersistenceProfile.NormalizedCatalogView — каталог (Product + справочники)
            // ViewPersistenceProfile.NormalizedOrdersView — заказы ([Order] + OrderItem + справочники)
            .WithViewDataPersistence(connectionString, settings);

            // ═══════════════════════════════════════════════════════════════
            // ШАГ 7. Запуск: вход → главная форма → каталог / заказы
            // ApplicationNavigator передаёт UsersDataSet в форму заказов
            // для ComboBox клиентов (роль ClientRoleName из settings)
            // ═══════════════════════════════════════════════════════════════
            new ApplicationNavigator(settings, data).Start();
        }
    }
}
```

### CreateCatalogCrudOptions — параметры изображений

Метод `CreateCatalogCrudOptions()` возвращает `DataSetCrudOptions` с полями:

- `AutoResizeImages` — масштабирование в `ScrollableDetailPanel` (также задаётся на панели через settings)
- `DeleteImageFileOnRemove` — удаление файла с диска при очистке поля «Фото»
- `DeleteOldImageOnReplace` — удаление предыдущего файла при замене изображения
- `ConnectionString` — строка подключения для проверки связанных записей при удалении
- `ImageResizeWidth` / `ImageResizeHeight` — размер сохраняемого изображения (300×200)

### TableAdapter: только Fill(), без Update в Designer

Для view **не нужно** добавлять Insert/Update/Delete в `.xsd`.  
Сохранение выполняет `ViewDataTablePersistence` (см. `.WithViewDataPersistence()`).

### Typed DataSet: что настроить

1. Создайте Typed DataSet с view-таблицами (каталог, заказы, пользователи).
2. Укажите имена таблиц в `ApplicationDataContext`.
3. Сопоставьте столбцы через `DetailRecordFieldMap` / `OrderRecordFieldMap`.
4. Подключите `.WithViewDataPersistence(connectionString, settings)`.

## Платформы

- .NET Framework 4.8
- .NET 8 (Windows)
