Advertisement
Verevkin

Аццкий Сишник!

Jul 9th, 2015
413
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 105.73 KB | None | 0 0
  1. /******************************************************************************/
  2. /*                     Интерфейсная часть модуля CRT.h                        */
  3. /******************************************************************************/
  4.  
  5. #define CrtH
  6.  
  7. // Флаг настройки устройства/отладки программы
  8. // Если закомментарен - сдача по ТУ (нету вывода отладочной инфы)
  9. // в протокол и т.п. (для условной компиляции #ifdef debug)
  10. // #define debug
  11.  
  12. // ============= Цвета символов (0x00..0x0F) и фона (0x00..0x07) ===============
  13. #define clBlack           0x00             // Чёрный
  14. #define clNavy            0x01             // Тёмно-синий
  15. #define clGreen           0x02             // Тёмно-зелёный
  16. #define clTeal            0x03             // Сине-зелёный
  17. #define clMaroon          0x04             // Тёмно-красный
  18. #define clPurple          0x05             // Фиолетовый
  19. #define clOlive           0x06             // Охра
  20. #define clSilver          0x07             // Светло-серый
  21.  
  22. #define clGray            0x08             // Тёмно-серый
  23. #define clBlue            0x09             // Синий
  24. #define clLime            0x0A             // Салатовый
  25. #define clAqua            0x0B             // Голубой
  26. #define clRed             0x0C             // Красный
  27. #define clFuchsia         0x0D             // Ярко-фиолетовый
  28. #define clYellow          0x0E             // Жёлтый
  29. #define clWhite           0x0F             // Белый
  30. #define clBlink           0x80             // Мигание текста
  31.  
  32. // ================ Символы псевдографики (кодировка ISO) ======================
  33. #define Codepage_ISO
  34. //#define Codepage_DOS
  35.  
  36. #ifdef Codepage_ISO
  37.   #define HorzBorder1       0xA4             // Горизонтальная граница одинарная
  38.   #define VertBorder1       0xA5             // Вертикальная граница одинарная
  39.   #define CornerLU11        0xA0             // Левый верхний угол
  40.   #define CornerRU11        0xA1             // Правый верхний угол
  41.   #define CornerRD11        0xA2             // Правый нижний угол
  42.   #define CornerLD11        0xA3             // Левый нижний угол
  43.   #define DotBarLite        0x9B             // Слабозакрашенный прямоугольник
  44.   #define DotBarMiddle      0x9C             // Среднезакрашенный прямоугольник
  45.   #define DotBarDark        0x9D             // Сильнозакрашенный прямоугольник
  46.   #define SolidBar          0xAB             // Закрашенный прямоугольник
  47. #endif
  48.  
  49. // ================ Символы псевдографики (кодировка DOS) ======================
  50. #ifdef Codepage_DOS
  51.   #define HorzBorder1       0xC4             // Горизонтальная граница одинарная
  52.   #define VertBorder1       0xB3             // Вертикальная граница одинарная
  53.   #define CornerLU11        0xDA             // Левый верхний угол
  54.   #define CornerRU11        0xBF             // Правый верхний угол
  55.   #define CornerRD11        0xD9             // Правый нижний угол
  56.   #define CornerLD11        0xC0             // Левый нижний угол
  57.   #define DotBarLite        0xB0             // Слабозакрашенный прямоугольник
  58.   #define DotBarMiddle      0xB1             // Среднезакрашенный прямоугольник
  59.   #define DotBarDark        0xB2             // Сильнозакрашенный прямоугольник
  60.   #define SolidBar          0xDB             // Закрашенный прямоугольник
  61. #endif
  62.  
  63. // ============================ Кнопки диалогов ================================
  64. #define ButtonsCount        7                             // Количество возможных кнопок
  65.  
  66. #define btNoButtons         0                             // Без кнопок
  67. #define btOk                0x01                          // OK
  68. #define btYes               0x02                          // Да
  69. #define btNo                0x04                          // Нет
  70. #define btCancel            0x08                          // Отмена
  71. #define btAbort             0x10                          // Прервать
  72. #define btRetry             0x20                          // Повтор
  73. #define btIgnore            0x40                          // Пропустить
  74. #define btOkCancel          btOk | btCancel               // Ок, Отмена
  75. #define btYesNo             btYes | btNo                  // Да, Нет
  76. #define btYesNoCancel       btYesNo | btCancel            // Да, Нет, Отмена
  77. #define btAbortRetryIgnore  btAbort | btRetry | btIgnore  // Прервать, Повтор, Пропустить
  78.  
  79. // ========================= Результаты диалогов ===============================
  80. #define mrNone              0x00             // пустой ответ
  81. #define mrOk                0x01             // OK
  82. #define mrYes               0x02             // Да
  83. #define mrNo                0x03             // Нет
  84. #define mrCancel            0x04             // Отмена
  85. #define mrAbort             0x05             // Прервать
  86. #define mrRetry             0x06             // Повтор
  87. #define mrIgnore            0x07             // Пропустить
  88.  
  89. // ====================== Коды клавиатурных клавиш =============================
  90. #define kbBkSpc               8              // BackSpace
  91. #define kbTab                 9              // Tab
  92. #define kbEnter              13              // Enter
  93. #define kbEsc                27              // Escape
  94. #define kbSpace              32              // Пробел
  95. #define kbUp                 72              // Стрелка вверх
  96. #define kbLeft               75              // Стрелка влево
  97. #define kbRight              77              // Стрелка вправо
  98. #define kbDown               80              // Стрелка вниз
  99. #define kbF1                 59              // F1
  100. #define kbF2                 60              // F2
  101. #define kbF3                 61              // F3
  102. #define kbF4                 62              // F4
  103. #define kbF5                 63              // F5
  104. #define kbF6                 64              // F6
  105. #define kbF7                 65              // F7
  106. #define kbF8                 66              // F8
  107. #define kbF9                 67              // F9
  108. #define kbF10                68              // F10
  109. #define kbF11               133              // F11
  110. #define kbF12               134              // F12
  111. #define kb0                  48              // Клавиша "0"
  112. #define kb1                  49              // Клавиша "1"
  113. #define kb2                  50              // Клавиша "2"
  114. #define kb3                  51              // Клавиша "3"
  115. #define kb4                  52              // Клавиша "4"
  116. #define kb5                  53              // Клавиша "5"
  117. #define kb6                  54              // Клавиша "6"
  118. #define kb7                  55              // Клавиша "7"
  119. #define kb8                  56              // Клавиша "8"
  120. #define kb9                  57              // Клавиша "9"
  121.  
  122. // ======================== Логические константы ===============================
  123. #define true                  1
  124. #define false                 0
  125.  
  126. // ========================== Системы счисления ================================
  127. #define IntDec               10                        // Десятичный
  128. #define IntHex               16                        // Шестнадцатеричный
  129. #define IntOct                8                        // Восьмеричный
  130. #define IntBin                2                        // Двоичный
  131. #define DecDigits            "0123456789"              // Десятичные цифры
  132. #define HexDigits            "0123456789ABCDEFabcdef"  // Шестнадцатеричные цифры
  133. #define OctDigits            "01234567"                // Восьмеричные цифры
  134. #define BinDigids            "01"                      // Двоичные цифры
  135. #define FloatSymbols         "0123456789.eE-+"         // Цифры числе с плав. точкой
  136.  
  137. // ==================== Разновидности вводимых данных ==========================
  138. #define ivtInt                0         // Вводится целое число (10-чное со знаком | 16-чное | 8-чное)
  139. #define ivtFloat              1         // Вводится десятичное дробное со знаком
  140. #define ivtString             2         // Вводится любая строка
  141.  
  142. // ============= Строки сообщений об ошибках (кодировка ISO) ===================
  143. #ifdef Codepage_ISO
  144.   #define errIsNotIntValue       "Неверный ввод целого числа."
  145.   #define errIsNotFloatValue     "Неверный ввод десятичного числа."
  146.   #define errIsWider16Bit        "Число шире 16 бит. Оно должно быть в пределах:\n -32768...+32767 (dec)\n  0...0xFFFF (hex)\n  0...0177777 (oct)."
  147.   #define errIsWider32Bit        "Число шире 32 бит. Оно должно быть в пределах:\n -2147483648...+2147483647 (dec)\n  0...0xFFFFFFFF (hex)\n  0...37777777777 (oct)."
  148. #endif
  149.  
  150. // ============= Строки сообщений об ошибках (кодировка DOS) ===================
  151. #ifdef Codepage_DOS
  152.   #define errIsNotIntValue       "Is not integer value."
  153.   #define errIsNotFloatValue     "Is not floating-point value."
  154.   #define errIsWider16Bit        "This value is out of 16-bit bounds. It must be between:\n -32768...+32767 (dec)\n  0...0xFFFF (hex)\n  0...0177777 (oct)."
  155.   #define errIsWider32Bit        "This value is out of 32-bit bounds. It must be between:\n -2147483648...+2147483647 (dec)\n  0...0xFFFFFFFF (hex)\n  0...37777777777 (oct)."
  156. #endif
  157.  
  158. // ============== Параметры сообщений об ошибках по умолчанию ==================
  159. #ifdef Codepage_ISO
  160.   #define errTitle          " Ошибка "
  161. #endif
  162. #ifdef Codepage_DOS
  163.   #define errTitle          " Error "
  164. #endif
  165.  
  166. #define errBorderColor      clYellow
  167. #define errTextColor        clWhite
  168. #define errBackground       clMaroon
  169. #define errButtons          btOk
  170. #define errDefaultButton    1
  171. #define errbtForeground     clLime
  172. #define errbtBackground     clBlack
  173.  
  174. // ============== Параметры информационных сообщений по умолчанию ==============
  175. #ifdef Codepage_ISO
  176.   #define infTitle          " Информация "
  177. #endif
  178. #ifdef Codepage_DOS
  179.   #define infTitle          " Information "
  180. #endif
  181.  
  182. #define infBorderColor      clYellow
  183. #define infTextColor        clNavy
  184. #define infBackground       clTeal
  185. #define infButtons          btOk
  186. #define infDefaultButton    1
  187. #define infbtForeground     clLime
  188. #define infbtBackground     clBlack
  189.  
  190.  
  191. // =============== Параметры сообщений с запросами по умолчанию ================
  192. #ifdef Codepage_ISO
  193.   #define reqTitle          " Запрос "
  194. #endif
  195. #ifdef Codepage_DOS
  196.   #define reqTitle          " Request "
  197. #endif
  198.  
  199. #define reqBorderColor      clWhite
  200. #define reqTextColor        clYellow
  201. #define reqBackground       clPurple
  202. #define reqButtons          btYesNo
  203. #define reqDefaultButton    1
  204. #define reqbtForeground     clLime
  205. #define reqbtBackground     clBlack
  206.  
  207. // ============== Параметры сообщений с выбором опции по умолчанию =============
  208. #ifdef Codepage_ISO
  209.   #define selTitle          " Выбор "
  210. #endif
  211. #ifdef Codepage_DOS
  212.   #define selTitle          " Select "
  213. #endif
  214.  
  215. #define selBorderColor      clYellow
  216. #define selTextColor        clWhite
  217. #define selBackground       clPurple
  218. #define selButtons          btNoButtons
  219.  
  220. // =================== Параметры окон ввода по умолчанию =======================
  221. #ifdef Codepage_ISO
  222.   #define inpTitle          " Ввод "
  223. #endif
  224. #ifdef Codepage_DOS
  225.   #define inpTitle          " Input "
  226. #endif
  227.  
  228. #define inpBorderColor      clYellow
  229. #define inpTextColor        clWhite
  230. #define inpBackground       clNavy
  231. #define inpInpForeground    clLime
  232. #define inpInpBackground    clBlack
  233.  
  234. // ========================== Прочие константы =================================
  235. #define MaxMessageWidth     74        // Максимальная ширина окна сообщения
  236. #define MaxMessageHeight    19        // Максимальная высота окна сообщения
  237. #define GaugeWidth          40        // Длина индикатора прогресса включая \0
  238. #define LogDivider          "================================================================================\n"
  239. #define SysTimerFreq        0x1234DCL // тактовая частота системного таймера
  240.  
  241. // ============================ Типы данных ====================================
  242. typedef unsigned char UCHAR;          // 8 бит без знака
  243. typedef unsigned int  UINT;           // 16 бит без знака
  244. typedef unsigned long ULONG;          // 32 бита без знака
  245. typedef char          bool;           // true|false - логическое
  246. typedef char*         string;         // строка символов с нулём на конце
  247. typedef char          TColor;         // Цвет или фон
  248. typedef char          TModalResult;   // Результат показа диалога/запроса
  249.  
  250. // Координаты курсора и/или символа
  251. typedef struct
  252. {
  253.   char Col;    // X
  254.   char Row;    // Y
  255. } TTextPoint;
  256.  
  257. // Символ и его атрибуты
  258. typedef struct
  259. {
  260.   char Col;           // X
  261.   char Row;           // Y
  262.   TColor Foreground;  // Цвет
  263.   TColor Background;  // Фон
  264.   char Symbol;        // Сам символ
  265. } TSymbolAttribs;
  266.  
  267. // Прямоугольная область экрана в текстовом режиме
  268. typedef struct
  269. {
  270.   char Left;      // Левый и
  271.   char Top;       // верхний угол
  272.   char Width;     // Ширина и
  273.   char Height;    // высота в символах
  274. } TTextRect;
  275.  
  276. // Структура окна сообщения
  277. typedef struct  // Переделать !!!!!!!!!!!!!!!!!!!!!
  278. {
  279.   string Message;        // Текст сообщения
  280.   string Title;          // Заголовок сообщения
  281.   TColor BorderColor;    // Цвет рамки
  282.   TColor TextColor;      // Цвет текста
  283.   TColor Background;     // Фон окна сообщения
  284.   UINT   Buttons;        // Набор кнопок
  285.   char   DefaultButton;  // Номер кнопки по умолчанию (нумерация с единицы, 0 - нету кнопки по умолчанию)
  286.   TColor btForeground;   // Цвет текста кнопок
  287.   TColor btBackground;   // Фон текста кнопок
  288.   TColor InpForeground;  // Цвет текста поля ввода (для диалогов ввода)
  289.   TColor InpBackground;  // Фон текста поля ввода (для диалогов ввода)
  290.   string InputValue;     // Введённая строка (для диалогов ввода)
  291. } TMessageParams;
  292.  
  293. // Параметры для функции вывода прогресса выполнения
  294. typedef struct
  295. {
  296.   string Message;       // Текст сообщения
  297.   string Title;         // Заголовок сообщения
  298.   TColor clComplete;    // Цвет полосы выполнения
  299.   TColor clUncomplete;  // фон полосы выполнения
  300.   TColor Foreground;    // Цвет текста (XXX%)
  301.   TColor Background;    // Фон текста (XXX%)
  302.   TColor MsgColor;      // Цвет текста сообщения
  303.   float OldProgress;   // Предыдущее значение прогресса
  304.   TTextPoint From;      // Откуда начинается индикатор
  305.   TTextRect Rect;       // Место расположения окна
  306.   UINT* ScreenBuffer;   // Буфер для запоминания части экрана
  307. } TProgressParams;
  308.  
  309. // Типы окон (окна ввода и вывода сообщений об ошибках/информации)
  310. typedef enum
  311. {
  312.   wndError,          // Сообщение об ошибке
  313.   wndInfo,           // Простое сообщение
  314.   wndRequest,        // Запрос типа (да/нет)
  315.   wndSelect,         // Выбор опции
  316.   wndInput           // Ввод данных
  317. } TMessageStyle;
  318.  
  319. // Типы окон прогресса выполнения и задержки
  320. typedef enum
  321. {
  322.   wndProgress,       // Прогресс
  323.   wndDelay           // Задержка
  324. } TProgressStyle;
  325.  
  326. // Составляющие времени
  327. typedef struct
  328. {
  329.   UINT Hr;              // Часы
  330.   UINT Min;             // Минуты
  331.   UINT Sec;             // Секунды
  332.   UINT mSec;            // Миллисекунды
  333. } TTimeStamp;
  334.  
  335. // ======================== Прототипы функций ==================================
  336. // Работа с курсором
  337. char WhereX(void);
  338. char WhereY(void);
  339. void WhereXY(char*, char*);
  340. void GotoXY(char, char);
  341. void HideCursor(void);
  342. void ShowCursor(void);
  343.  
  344. // Вывод текста в цвете
  345. void ColorSymbol(char, char, char, TColor, TColor);
  346. void ColorPrint(string, TColor, TColor);
  347. void GetSymbolAttribs(TSymbolAttribs*);
  348. void InvertColors(TTextPoint, char);
  349. void ShadowSymbols(TTextPoint, char);
  350.  
  351. // Работа с областями экрана
  352. void MakeRect(TTextRect*, char, char, char, char);
  353. void FillTextRect(TTextRect, char, TColor, TColor);
  354. void ClearTextRect(TTextRect, TColor);
  355. void CenterRect(TTextRect* Rect);
  356.  
  357. // Диалоги, сообщения и пр
  358. void DrawFrame(TTextRect, string, TColor, TColor);
  359. int PrintTextbox(TTextRect, string, TColor, TColor);
  360. void GetWindowDefaults(TMessageParams*, TMessageStyle);
  361. TModalResult ShowMessage(TMessageParams*);
  362. TModalResult InputBox(TMessageParams*, char);                                   // Fix (04.06.2008)
  363. TModalResult InputBoxDef(TMessageParams*, string, char);                        // New (04.06.2008)
  364. bool InputInt(TMessageParams*, int*);
  365. bool InputFloat(TMessageParams*, float*);
  366. int SelectOption(TMessageParams*, int);
  367. void BeginProgress(TProgressParams*);
  368. void ShowProgressI(int, int, TProgressParams*);                                 // Fix (21.05.2009)
  369. void ShowProgressF(float, float, TProgressParams*);
  370. void EndProgress(TProgressParams*);
  371. void BeginMessageNonModal(TProgressParams*);                                    // New (06.10.2008)
  372. void UpdateMessageNonModal(TProgressParams*);                                   // New (06.10.2008)
  373. void EndMessageNonModal(TProgressParams*);                                      // New (06.10.2008)
  374. char GetButtonsSpace(UINT Buttons);
  375. void DrawButtons(TMessageParams*, TTextPoint);
  376. TModalResult GetModalResult(TMessageParams*, TTextPoint);
  377. TModalResult GetInputString(TMessageParams*, string, TTextPoint, char);         // Fix (04.06.2008)
  378. TModalResult GetInputStringDef(TMessageParams*, string, TTextPoint, char);      // New (04.06.2008)
  379. void Assert(const bool, string);                                                // New (02.06.2011)
  380.  
  381. // Работа с окнами и видеопамятью
  382. UINT CopyWindow(TTextRect, UINT*);
  383. void PasteWindow(TTextRect, UINT*);
  384. UINT SaveWindow2File(TTextRect, string);
  385. void SaveScreen2File(string);
  386.  
  387. // Работа с памятью
  388. void FillBufferInt(int*, int, ...);                                             // Fix (28.06.2011)
  389. void FillBufferChar(UCHAR*, int, ...);                                          // New (28.06.2011)
  390.  
  391. // Работа со строками
  392. int GetLinesCount(string, int*);
  393. bool CharInCharset(char, string);
  394. UINT GetCharCount(char, string);
  395. char CenterString(string, char);
  396. void MakeString(string, char, UINT);
  397. bool StrIsDec(string);
  398. bool StrIsHex(string);
  399. bool StrIsOct(string);
  400. bool StrIsFloat(string);
  401. bool TryStr2Int(string, int*);
  402. bool TryStr2Long(string, long*);
  403. bool TryStr2Float(string, float*);
  404. bool TryStr2Double(string, double*);
  405. bool CheckIntLength(string, char);
  406.  
  407.  
  408. // Математические и логические функции
  409. int RoundI(float);
  410. long RoundL(float);
  411. bool GetBitInt(UINT, char);
  412. char GetBitCountInt(UINT);
  413. bool BetweenInt(int, int, int);
  414. bool BetweenLong(long, long, long);
  415. bool BetweenFloat(float, float, float);
  416.  
  417. // Работа с лог-файлом
  418. bool OpenLog(string);
  419. void CloseLog(void);
  420. void Add2Log(string);
  421. void AddChar2Log(UCHAR, string);
  422. void AddInt2Log(int, string);
  423. void AddInt2LogF(int, string, char);
  424. void AddLong2Log(long, string);
  425. void AddFloat2Log(float, string);
  426. void AddDouble2Log(double, string);
  427. void AddBool2Log(bool, string);
  428. void AddModalResult2Log(TModalResult);
  429. void AddStr2Log(string, string);
  430. void AddRect2Log(TTextRect, string);
  431.  
  432. // Работа с датой и временем
  433. void DecodeTime(float, TTimeStamp*);
  434. void Sleep(ULONG);
  435. bool Delay(float, TProgressParams*);
  436.  
  437. // Работа со звуком
  438. void Beep(UINT, ULONG);
  439. void Sound(UINT);
  440. void NoSound(void);
  441.  
  442. // Работа с клавиатурой
  443. bool KeyPressed(UCHAR);                                                         // New (17.06.2010)
  444. bool EscapePressed(void);                                                       // New (17.06.2010)
  445.  
  446.  
  447.  
  448. /******************************************************************************/
  449.  
  450. /******************************************************************************/
  451. /* Модуль универсальных вспомогательных подпрограмм для СП "Базис" КАСАК-85   */
  452. /* Его захотел написать min@y™ aka "EXXON VALDES - чилавег и порохот",        */
  453. /* используя электронный вариант старинной книжки Герберта Шилдта             */
  454. /* "Си для профессиональных программистов".                                   */
  455. /* Начат в пятницу 30.11.2007                                                 */
  456. /*                       mailto:minay.tm@gmail.com                            */
  457. /*                    Версия файла 1.02 (21.05.2009)                          */
  458. /******************************************************************************/
  459.  
  460. #ifndef CrtH
  461.   #include "CRT.h"
  462. #endif
  463.  
  464. #include <dos.h>
  465. #include <stdio.h>
  466. #include <math.h>
  467. #include <malloc.h>
  468. #include <string.h>
  469. #include <time.h>
  470. #include <io.h>
  471. #include <fcntl.h>
  472. #include <stdarg.h>
  473.  
  474. #ifdef Codepage_ISO
  475.   string ButtonCaptions[ButtonsCount] = {" OK ",
  476.                                          " Да ",
  477.                                          " Нет ",
  478.                                          " Отмена ",
  479.                                          " Прервать ",
  480.                                          " Повтор ",
  481.                                          " Пропустить "};
  482.  
  483. #else
  484.   string ButtonCaptions[ButtonsCount] = {" OK ",
  485.                                          " Yes ",
  486.                                          " No ",
  487.                                          " Cancel ",
  488.                                          " Abort ",
  489.                                          " Retry ",
  490.                                          " Ignore "};
  491. #endif
  492.  
  493. // ========================== Глобальные переменные ============================
  494. //TProgressParams ProgressParams;
  495. //UINT* ScreenBuffer; // Буфер для запоминания части экрана
  496. FILE* LogFile;      // Файл лога
  497. TTextPoint OldCursor; // Координаты курсора до применения HideCursor()
  498. char* Ini;         // Буфер для загрузки/хранения/чтения файла настроек
  499.  
  500. //==============================================================================
  501. //============================= Работа с курсором ==============================
  502. //==============================================================================
  503.  
  504.  
  505. //------------------------- Чтение строки курсора ------------------------------
  506. char WhereX(void)
  507. {
  508.   union REGS r;
  509.  
  510.   r.h.ah = 3;  // чтение текущей позиции курсора
  511.   r.h.bh = 0;  // видеостраница
  512.   int86(0x10, &r, &r);
  513.   return r.h.dl;
  514. }
  515.  
  516. //------------------------ Чтение столбца курсора ------------------------------
  517. char WhereY(void)
  518. {
  519.   union REGS r;
  520.  
  521.   r.h.ah = 3;  // чтение текущей позиции курсора
  522.   r.h.bh = 0;  // видеостраница
  523.   int86(0x10, &r, &r);
  524.   return r.h.dh;
  525. }
  526.  
  527. //------------- Чтение текущих координат позиции курсора -----------------------
  528. void WhereXY(char *x, char *y)
  529. {
  530.   union REGS r;
  531.  
  532.   r.h.ah = 3;  // чтение текущей позиции курсора
  533.   r.h.bh = 0;  // видеостраница
  534.   int86(0x10, &r, &r);
  535.   *x = r.h.dl;
  536.   *y = r.h.dh;
  537. }
  538.  
  539. //----------------------- установка курсора в x,y ------------------------------
  540. void GotoXY(char x, char y)
  541. {
  542.   union REGS r;
  543.  
  544.   r.h.ah = 2; // функция установки курсора
  545.   r.h.dl = x; // координата колонки
  546.   r.h.dh = y; // координата строки
  547.   r.h.bh = 0; // видео страница
  548.  
  549.   int86(0x10, &r, &r);
  550. }
  551.  
  552. // ------------------------- Скрытие курсора -----------------------------------
  553. void HideCursor(void)
  554. {
  555.   OldCursor.Col = WhereX();
  556.   OldCursor.Row = WhereY();
  557.   GotoXY(0, 25);
  558. }
  559.  
  560. //----------- Восстановление курсора, скрытого функцией HideCursor() -----------
  561. void ShowCursor(void)
  562. {
  563.   GotoXY(OldCursor.Col, OldCursor.Row);
  564. }
  565.  
  566. //==============================================================================
  567. //======================= Ввод/вывод текста в цвете ============================
  568. //==============================================================================
  569.  
  570. //---------------- Печать символа с координатами Col, Row в цвете --------------
  571. void ColorSymbol(char Symbol,      // Символ
  572.                  char Col,         // Номер колонки
  573.                  char Row,         // Номер строки
  574.                  TColor Foreground,  // цвет текста
  575.                  TColor Background)  // цвет фона
  576. {
  577.   union REGS r;
  578.   char Color = (Foreground & 0x8F) | ((Background & 0x07) << 4);
  579.  
  580.   GotoXY(Col, Row);
  581.   r.h.ah = 9; // функция отображения символа и его атрибутов
  582.   r.h.al = Symbol;    // отображаемый символ
  583.   r.h.bl = Color;   // атрибуты цвета
  584.   r.h.bh = 0;       // видеостраница 0
  585.   r.x.cx = 1; // отобразить за единицу времени ( такт )
  586.   int86(0x10, &r, &r);
  587.   GotoXY(Col + 1, Row);
  588. }
  589.  
  590.  
  591. //------------------------- Печать строки в цвете ------------------------------
  592. void ColorPrint(string s,     // строка
  593.                 TColor Foreground,  // цвет текста
  594.                 TColor Background)  // цвет фона
  595. {
  596.   char x, y;
  597.   UCHAR Symbol;
  598.   TColor UserFG = Foreground; // пользовательский цвет символов
  599.   WhereXY(&x, &y); // получение текущей позиции курсора
  600.  
  601.   while (*s)
  602.   {
  603.     if (*s == '\n') // обработка символа новой строки
  604.     {
  605.       printf("\n");
  606.       s++;
  607.       x = 0, y++;  // переход на следующую строку
  608.       continue;
  609.     }
  610.  
  611.  
  612. /*  ИДЕЯ:
  613.     Если в строке встретился символ с кодом от 0x80 до 0x8F,
  614.     при выводе заменить его на пробел, а Foreground заменить на код_символа & 0x0F
  615.     для вывода текста другим цветом.
  616.     Если встретился символ 0x90, вернуть цвет обратно. */
  617.    
  618.     Symbol = *s++; // символ, который щас будет выводиться на консоль
  619.    
  620.     // ищу пользовательский цвет
  621.     if ((Symbol & 0xF0) == 0x80)
  622.     {
  623.       UserFG = Symbol & 0x0F;
  624.       //Symbol = ' '; // заменяю на пробел
  625.       continue;
  626.     }
  627.    
  628.     // ищу терминатор юзерского цвета
  629.     else if (Symbol == 0x90)
  630.          {
  631.            UserFG = Foreground;
  632.            //Symbol = ' '; // заменяю на пробел
  633.            continue;
  634.          }
  635.          //else if ((Symbol == '.') || (Symbol == ',') || (Symbol == ':') || (Symbol == ';'))
  636.          //       UserFG = Foreground;
  637.                
  638.     //ColorSymbol(*s++, x, y, UserFG, Background);
  639.     ColorSymbol(Symbol, x, y, UserFG, Background);
  640.     GotoXY(x++, y); // перемещение курсора
  641.   } // while
  642.   GotoXY(x++, y);
  643. }
  644.  
  645. // Чтение символа и его атрибутов
  646. // с позиции ((*SymbolAttribs).Row, (*SymbolAttribs).Col)
  647. void GetSymbolAttribs(TSymbolAttribs* SymbolAttribs)
  648. {
  649.   union REGS r;
  650.  
  651.   GotoXY((*SymbolAttribs).Col, (*SymbolAttribs).Row);
  652.   r.h.ah = 8; // функция чтения символа
  653.   r.h.bh = 0; // видео страница
  654.   int86(0x10, &r, &r); // Символ и атрибут - al и ah соответственно
  655.  
  656.   (*SymbolAttribs).Symbol = r.h.al;
  657.   (*SymbolAttribs).Foreground = (r.h.ah & 0x8F);
  658.   (*SymbolAttribs).Background = (r.h.ah & 0x70) >> 4;
  659. }
  660.  
  661. // Инвертирование цвета и фона строки символов экрана начиная с точки From
  662. void InvertColors(TTextPoint From, char Count)
  663. {
  664.   TSymbolAttribs SymbolAttribs;
  665.  
  666.   SymbolAttribs.Row = From.Row; // начальная
  667.   SymbolAttribs.Col = From.Col; // точка
  668.  
  669.   while ((SymbolAttribs.Col < 80) && Count)
  670.   {
  671.     GetSymbolAttribs(&SymbolAttribs); // читаю атрибуты символа
  672.    
  673.     ColorSymbol(SymbolAttribs.Symbol,
  674.                 SymbolAttribs.Col,
  675.                 SymbolAttribs.Row,
  676.                 ~(SymbolAttribs.Foreground) & 0x0F,
  677.                 ~(SymbolAttribs.Background) & 0x07);
  678.    
  679.     SymbolAttribs.Col++;
  680.     Count--;
  681.   } // while
  682. }
  683.  
  684. // Создание эффекта тени (используется для диалоговых окон) начиная с точки From
  685. void ShadowSymbols(TTextPoint From, char Count)
  686. {
  687.   TSymbolAttribs SymbolAttribs;
  688.  
  689.   SymbolAttribs.Row = From.Row; // начальная
  690.   SymbolAttribs.Col = From.Col; // точка
  691.  
  692.   while ((SymbolAttribs.Col < 80) && Count)
  693.   {
  694.     GetSymbolAttribs(&SymbolAttribs); // читаю атрибуты символа
  695.  
  696.     ColorSymbol(SymbolAttribs.Symbol,
  697.                 SymbolAttribs.Col,
  698.                 SymbolAttribs.Row,
  699.                 clGray,
  700.                 clBlack);
  701.  
  702.     SymbolAttribs.Col++;
  703.     Count--;
  704.   } // while
  705. }
  706.  
  707. //==============================================================================
  708. //======================== Работа с областями экрана ===========================
  709. //==============================================================================
  710. void MakeRect(TTextRect* R,
  711.               char Left,      // Левый и
  712.               char Top,       // верхний угол
  713.               char Width,     // Ширина и
  714.               char Height)    // высота в символах
  715. {
  716.   (*R).Left   = Left;
  717.   (*R).Top    = Top;
  718.   (*R).Width  = Width;
  719.   (*R).Height = Height;
  720. };
  721.  
  722. // Заливка части экрана Rect символом Symbol цвета Foreground и фона Background
  723. void FillTextRect(TTextRect Rect,
  724.                   char Symbol,
  725.                   TColor Foreground,
  726.                   TColor Background)
  727. {
  728.   int x, y, Count = 0;
  729.  
  730.   for (y = Rect.Top; y < Rect.Height + Rect.Top; y++)
  731.     for (x = Rect.Left; x < Rect.Width + Rect.Left; x++)
  732.     {
  733.       ColorSymbol(Symbol, x, y, Foreground, Background);
  734.       Count++;
  735.     }
  736. }
  737.  
  738. // Очистка части экрана Rect цветом фона Background
  739. void ClearTextRect(TTextRect Rect,
  740.                    TColor Background)
  741. {
  742.   FillTextRect(Rect, ' ', Background, Background);
  743. }
  744.  
  745. // Центрирование прямоугольника относительно центра экрана (80 х 25)
  746. void CenterRect(TTextRect* Rect)
  747. {
  748.   (*Rect).Top = 12 - (*Rect).Height / 2;
  749.   (*Rect).Left = 40 - (*Rect).Width / 2;
  750. }
  751.  
  752. //==============================================================================
  753. //========================= Диалоги, сообщения и пр ============================
  754. //==============================================================================
  755.  
  756.  
  757. // Рисование рамки, обрамляющей область Rect цветом Foreground
  758. // и фоном Background, а также очитстка области внутри рамки пробелами
  759. // + вывод заголовка Title вверху по центру
  760. void DrawFrame(TTextRect Rect,
  761.                string Title,       // Текст заголовка, если надо
  762.                TColor Foreground,
  763.                TColor Background)
  764. {
  765.   register int i;
  766.   char TitleCol;  // Относительная координата 0-го символа заголовка, если он задан
  767.   TTextPoint ShadFrom; // Точка начала строк затенения
  768.  
  769.   // Углы
  770.   ClearTextRect(Rect, Background);
  771.   ColorSymbol(CornerLU11, Rect.Left, Rect.Top, Foreground, Background); // левый верхний
  772.   ColorSymbol(CornerLD11, Rect.Left, Rect.Top + Rect.Height - 1, Foreground, Background); // левый нижний
  773.   ColorSymbol(CornerRU11, Rect.Left + Rect.Width - 1, Rect.Top, Foreground, Background); // правый верхний
  774.   ColorSymbol(CornerRD11, Rect.Left + Rect.Width - 1, Rect.Top + Rect.Height - 1, Foreground, Background); // правый нижний
  775.  
  776.   // Горизонтальные линии
  777.   for (i = 0; i != Rect.Width - 2; i++)
  778.   {
  779.     ColorSymbol(HorzBorder1, i + Rect.Left + 1, Rect.Top, Foreground, Background);
  780.     ColorSymbol(HorzBorder1, i + Rect.Left + 1, Rect.Top + Rect.Height - 1, Foreground, Background);
  781.   }
  782.  
  783.   // Вертикальные линии
  784.   for (i = 0; i != Rect.Height - 2; i++)
  785.   {
  786.     ColorSymbol(VertBorder1, Rect.Left, i + Rect.Top + 1, Foreground, Background);
  787.     ColorSymbol(VertBorder1, Rect.Left + Rect.Width - 1, i + Rect.Top + 1, Foreground, Background);
  788.   }
  789.  
  790.   // Вывод заголовка вверху по центру
  791.   if (*Title)
  792.   {
  793.     TitleCol = CenterString(Title, Rect.Width);
  794.     GotoXY(TitleCol + Rect.Left, Rect.Top);
  795.     ColorPrint(Title, Foreground, Background);
  796.   }
  797.  
  798.   // Вывод тени справа и внизу
  799.   ShadFrom.Col = Rect.Left + 2;
  800.   ShadFrom.Row = Rect.Top + Rect.Height;
  801.   ShadowSymbols(ShadFrom, Rect.Width);
  802.  
  803.   ShadFrom.Col = Rect.Left + Rect.Width;
  804.   for (i = 0; i != Rect.Height - 1; i++)
  805.   {
  806.     ShadFrom.Row = Rect.Top + 1 + i;
  807.     ShadowSymbols(ShadFrom, 2);
  808.   }
  809. }
  810.  
  811. // Печать цветного текста внутри прямоугольника Rect (исключая границы!)
  812. // Возвращает количество напечатанных символов
  813. /*
  814. int PrintTextbox(TTextRect Rect,
  815.                   string Text,
  816.                   TColor Foreground,
  817.                   TColor Background)
  818. {
  819.   int Count = 0; // номер текущего символа (кроме \n)
  820.   int Col = Rect.Left + 1, // номера строки и
  821.       Row = Rect.Top + 1;  // колонки (относительно начала координат [0, 0])
  822.  
  823.   while ((*Text) && (Row < Rect.Top + Rect.Height - 1))
  824.   {
  825.     // если перенос строки - перехожу на след. строку
  826.     if (*Text == '\n')
  827.     {
  828.       Text++;                      // Пропуск \n
  829.       Row++, Col = Rect.Left + 1;  // след. строка
  830.       continue;
  831.     }
  832.    
  833.     // Если упёрся в правый край области - перехожу на след. строку
  834.     if (Col == Rect.Left + Rect.Width - 1)
  835.       Row++, Col = Rect.Left + 1; // след. строка
  836.  
  837.     GotoXY(Col, Row);
  838.     ColorSymbol(*Text, Col, Row, Foreground, Background);
  839.     Count++;
  840.  
  841.     Col++;
  842.     Text++;
  843.   } // while
  844.  
  845.   return Count;
  846. }  */
  847.  
  848. int PrintTextbox(TTextRect Rect,
  849.                   string Text,
  850.                   TColor Foreground,
  851.                   TColor Background)
  852. {
  853.   int Count = 0; // номер текущего символа (кроме \n)
  854.   int Col = Rect.Left + 1, // номера строки и
  855.       Row = Rect.Top + 1;  // колонки (относительно начала координат [0, 0])
  856.      
  857.   UCHAR Symbol;
  858.   TColor UserFG = Foreground; // пользовательский цвет символов
  859.  
  860.   while ((*Text) && (Row < Rect.Top + Rect.Height - 1))
  861.   {
  862.     // если перенос строки - перехожу на след. строку
  863.     if (*Text == '\n')
  864.     {
  865.       Text++;                      // Пропуск \n
  866.       Row++, Col = Rect.Left + 1;  // след. строка
  867.       continue;
  868.     }
  869.  
  870.     // Если упёрся в правый край области - перехожу на след. строку
  871.     if (Col == Rect.Left + Rect.Width - 1)
  872.       Row++, Col = Rect.Left + 1; // след. строка
  873.      
  874.     /*  ИДЕЯ:
  875.     Если в строке встретился символ с кодом от 0x80 до 0x8F,
  876.     при выводе заменить его на пробел, а Foreground заменить на код_символа & 0x0F
  877.     для вывода текста другим цветом.
  878.     Если встретился символ 0x90 или символы-разделители (.,:;),
  879.     вернуть цвет обратно. */
  880.  
  881.     Symbol = *Text++; // символ, который щас будет выводиться на консоль
  882.  
  883.     // ищу пользовательский цвет
  884.     if ((Symbol & 0xF0) == 0x80)
  885.     {
  886.       UserFG = Symbol & 0x0F;
  887.       //Symbol = ' '; // заменяю на пробел
  888.       continue;
  889.     }
  890.  
  891.     // ищу терминатор юзерского цвета
  892.     else if (Symbol == 0x90)
  893.          {
  894.            UserFG = Foreground;
  895.            //Symbol = ' '; // заменяю на пробел
  896.            continue;
  897.          }
  898.          //else if ((Symbol == '.') || (Symbol == ',') || (Symbol == ':') || (Symbol == ';'))
  899.          //       UserFG = Foreground;
  900.  
  901.     GotoXY(Col, Row);
  902.     ColorSymbol(Symbol, Col, Row, UserFG, Background);
  903.     Count++;
  904.  
  905.     Col++;
  906.     //Text++;
  907.   } // while
  908.  
  909.   return Count;
  910. }
  911.  
  912. // Установка параметров сообщений по умолчанию
  913. // Style - тип окна сообщения:
  914. // typedef enum {wndError, wndInfo, wndSelect, wndInput} TMessageStyle;
  915. void GetWindowDefaults(TMessageParams* Params, TMessageStyle Style)
  916. {
  917.   switch (Style)
  918.   {
  919.     case wndError:
  920.       (*Params).Title =            errTitle;
  921.       (*Params).BorderColor =      errBorderColor;
  922.       (*Params).TextColor =        errTextColor;
  923.       (*Params).Background =       errBackground;
  924.       (*Params).Buttons =          errButtons;
  925.       (*Params).DefaultButton =    errDefaultButton;
  926.       (*Params).btForeground =     errbtForeground;
  927.       (*Params).btBackground =     errbtBackground;
  928.     break;
  929.    
  930.     case wndInfo:
  931.       (*Params).Title =            infTitle;
  932.       (*Params).BorderColor =      infBorderColor;
  933.       (*Params).TextColor =        infTextColor;
  934.       (*Params).Background =       infBackground;
  935.       (*Params).Buttons =          infButtons;
  936.       (*Params).DefaultButton =    infDefaultButton;
  937.       (*Params).btForeground =     infbtForeground;
  938.       (*Params).btBackground =     infbtBackground;
  939.     break;
  940.  
  941.     case wndRequest:
  942.       (*Params).Title =            reqTitle;
  943.       (*Params).BorderColor =      reqBorderColor;
  944.       (*Params).TextColor =        reqTextColor;
  945.       (*Params).Background =       reqBackground;
  946.       (*Params).Buttons =          reqButtons;
  947.       (*Params).DefaultButton =    reqDefaultButton;
  948.       (*Params).btForeground =     reqbtForeground;
  949.       (*Params).btBackground =     reqbtBackground;
  950.     break;
  951.    
  952.     case wndSelect:
  953.       (*Params).Title =            selTitle;
  954.       (*Params).BorderColor =      selBorderColor;
  955.       (*Params).TextColor =        selTextColor;
  956.       (*Params).Background =       selBackground;
  957.     break;
  958.    
  959.     case wndInput:
  960.       (*Params).Title =            inpTitle;
  961.       (*Params).BorderColor =      inpBorderColor;
  962.       (*Params).TextColor =        inpTextColor;
  963.       (*Params).Background =       inpBackground;
  964.       (*Params).InpForeground =    inpInpForeground;
  965.       (*Params).InpBackground =    inpInpBackground;
  966.       (*Params).Buttons =          btNoButtons;
  967.     break;
  968.   } // switch
  969. }
  970.  
  971. // Вывод на экран окна сообщения.
  972. TModalResult ShowMessage(TMessageParams* Params)
  973. {
  974.   int Len = strlen((*Params).Message); // Длина сообщения
  975.   int MaxLen; // длина самой длинной из строк сообщения
  976.   UINT* Buffer; // Буфер под сохранение участка экрана
  977.   TTextRect Rect;   // Область окна
  978.   char ButtonSpace; // Длина поля кнопок
  979.   TTextPoint ButtonsFrom; // Координата начала строки кнопок
  980.   TModalResult ModalResult; // Результат функции (какую кнопку нажали)
  981.  
  982.   // Вычисление координат окна, чтобы оно было по центру экрана
  983.   ButtonSpace = GetButtonsSpace((*Params).Buttons);
  984.   Rect.Height = GetLinesCount((*Params).Message, &MaxLen) + 2 + 2; // 2 - под рамку, 2 - под кнопки
  985.  
  986.   if (MaxLen > ButtonSpace)
  987.     Rect.Width = MaxLen + 2;      // Длина кнопок уже сообщения
  988.   else
  989.     Rect.Width = ButtonSpace + 2; // Длина кнопок шире сообщения
  990.  
  991.   //AddInt2Log(MaxLen, "MaxLen");
  992.   //AddInt2Log(ButtonSpace, "ButtonSpace");
  993.   //AddRect2Log(Rect, "Rect");
  994.  
  995.   CenterRect(&Rect); // Центрирование окна
  996.  
  997.   // Запоминаю часть экрана
  998.   //Buffer = malloc(Rect.Width * Rect.Height * 2);
  999.   // Выделение памяти под прямоугольник с учётом тени
  1000.   Buffer = malloc(2 * (Rect.Width * Rect.Height + 2 * Rect.Height + Rect.Width + 2));
  1001.   CopyWindow(Rect, Buffer);
  1002.  
  1003.   // Рисую рамку и выдаю текст
  1004.   DrawFrame(Rect, (*Params).Title, (*Params).BorderColor, (*Params).Background);
  1005.   PrintTextbox(Rect, (*Params).Message, (*Params).TextColor, (*Params).Background);
  1006.  
  1007.   // Кнопки
  1008.   ButtonsFrom.Col = (Rect.Left + 1) + ((Rect.Width - ButtonSpace) / 2) - 1;  // Центрирование кнопок относительно окна
  1009.   ButtonsFrom.Row = Rect.Top + Rect.Height - 2;
  1010.   DrawButtons(Params, ButtonsFrom); // Рисую кнопки
  1011.  
  1012.   // Опрос клавы
  1013.   ModalResult = GetModalResult(Params, ButtonsFrom);
  1014.   //AddModalResult2Log(ModalResult);
  1015.  
  1016.   // восстанавливаю чать экрана и курсор
  1017.   PasteWindow(Rect, Buffer);
  1018.   free(Buffer);                                                                 // Fix (08.07.2011)
  1019.   ShowCursor();
  1020.  
  1021.   return ModalResult;
  1022. }
  1023.  
  1024. // Вывод на экран окна ввода тестовой строки.
  1025. // По умолчанию отображается пустая строка. Максимальная длина = MaxLen.
  1026. // Результат возвращается в (*Params).InputValue.
  1027. TModalResult InputBox(TMessageParams* Params, char MaxLength)
  1028. {
  1029.   int Len = strlen((*Params).Message);               // Длина сообщения
  1030.   int MaxLen;                                        // длина самой длинной из строк сообщения
  1031.   UINT* Buffer;                                      // Буфер под сохранение участка экрана
  1032.   TTextRect Rect;                                    // Область окна
  1033.   TTextPoint InputFrom;                              // Координата начала поля ввода
  1034.   TModalResult ModalResult;                          // Результат функции
  1035.   string InputField = (string)malloc(MaxLength + 1); // строка поля ввода
  1036.  
  1037.   // Вычисление координат окна, чтобы оно было по центру экрана
  1038.   Rect.Height = GetLinesCount((*Params).Message, &MaxLen) + 2 + 2; // 2 - под рамку, 2 - под строку ввода
  1039.  
  1040.   if (MaxLen > MaxLength)
  1041.     Rect.Width = MaxLen + 2;      // Длина поля ввода уже сообщения
  1042.   else
  1043.     Rect.Width = MaxLength + 5;   // Длина поля ввода шире сообщения
  1044.  
  1045.   CenterRect(&Rect);              // Центрирование окна
  1046.  
  1047.   // Запоминаю часть экрана
  1048.   // Выделение памяти под прямоугольник с учётом тени
  1049.   Buffer = malloc(2 * (Rect.Width * Rect.Height + 2 * Rect.Height + Rect.Width + 2));
  1050.   CopyWindow(Rect, Buffer);
  1051.  
  1052.   // Рисую рамку и выдаю текст
  1053.   DrawFrame(Rect, (*Params).Title, (*Params).BorderColor, (*Params).Background);
  1054.   PrintTextbox(Rect, (*Params).Message, (*Params).TextColor, (*Params).Background);
  1055.  
  1056.   // Поле ввода
  1057.   InputFrom.Col = Rect.Left + 2;
  1058.   InputFrom.Row = Rect.Top + Rect.Height - 2;
  1059.  
  1060.   // Опрос клавы
  1061.   ModalResult = GetInputString(Params, InputField, InputFrom, MaxLength);
  1062.  
  1063.   // восстанавливаю часть экрана и курсор
  1064.   PasteWindow(Rect, Buffer);
  1065.  
  1066.   // Освобождаю память из-под (*Params).InputValue, если надо
  1067.   if ((*Params).InputValue) free((*Params).InputValue);
  1068.  
  1069.   if (ModalResult == mrOk) (*Params).InputValue = strdup(InputField);
  1070.   free(Buffer);                                                                 // Fix (08.07.2011)
  1071.   free(InputField);
  1072.   return ModalResult;
  1073. }
  1074.  
  1075. // Вывод на экран окна ввода тестовой строки.
  1076. // По умолчанию отображается Default. Максимальная длина = MaxLen.
  1077. // Результат возвращается в (*Params).InputValue.
  1078. TModalResult InputBoxDef(TMessageParams* Params, string Default, char MaxLength)
  1079. {
  1080.   int Len = strlen((*Params).Message);               // Длина сообщения
  1081.   int MaxLen;                                        // длина самой длинной из строк сообщения
  1082.   UINT* Buffer;                                      // Буфер под сохранение участка экрана
  1083.   TTextRect Rect;                                    // Область окна
  1084.   TTextPoint InputFrom;                              // Координата начала поля ввода
  1085.   TModalResult ModalResult;                          // Результат функции
  1086.   char InputField[80]; // = (string)malloc(MaxLength + 1); // строка поля ввода
  1087.  
  1088.   // Вычисление координат окна, чтобы оно было по центру экрана
  1089.   Rect.Height = GetLinesCount((*Params).Message, &MaxLen) + 2 + 2; // 2 - под рамку, 2 - под строку ввода
  1090.  
  1091.   if (MaxLen > MaxLength)
  1092.     Rect.Width = MaxLen + 2;      // Длина поля ввода уже сообщения
  1093.   else
  1094.     Rect.Width = MaxLength + 5;   // Длина поля ввода шире сообщения
  1095.  
  1096.   CenterRect(&Rect);              // Центрирование окна
  1097.  
  1098.   // Запоминаю часть экрана
  1099.   // Выделение памяти под прямоугольник с учётом тени
  1100.   Buffer = malloc(2 * (Rect.Width * Rect.Height + 2 * Rect.Height + Rect.Width + 2));
  1101.   CopyWindow(Rect, Buffer);
  1102.  
  1103.   // Рисую рамку и выдаю текст
  1104.   DrawFrame(Rect, (*Params).Title, (*Params).BorderColor, (*Params).Background);
  1105.   PrintTextbox(Rect, (*Params).Message, (*Params).TextColor, (*Params).Background);
  1106.  
  1107.   // Поле ввода
  1108.   InputFrom.Col = Rect.Left + 2;
  1109.   InputFrom.Row = Rect.Top + Rect.Height - 2;
  1110.  
  1111.   // Значение по умолчанию, передающееся в функцию GetInputStringDef()
  1112.   strcpy(InputField, Default);
  1113.  
  1114.   // Опрос клавы
  1115.   ModalResult = GetInputStringDef(Params, InputField, InputFrom, MaxLength);
  1116.  
  1117.   // восстанавливаю часть экрана и курсор
  1118.   PasteWindow(Rect, Buffer);
  1119.  
  1120.   // Освобождаю память из-под (*Params).InputValue, если надо
  1121.   if ((*Params).InputValue) free((*Params).InputValue);
  1122.  
  1123.   if (ModalResult == mrOk) (*Params).InputValue = strdup(InputField);
  1124.  
  1125.   free(Buffer);                                                                 // Fix (08.07.2011)
  1126.   return ModalResult;
  1127. }
  1128.  
  1129. // Вывод на экран окна ввода 16-битного целого.
  1130. // Максимальная длина = 13 символов (эдак с запасом).
  1131. // Результат возвращается в *Value. Результат = true, если юзер ввёл
  1132. // ПРАВИЛЬНОЕ число (в десятичном | шестнадцатеричном | восьмеричном) формате
  1133. // и нажал Enter. Esc - отмена, функция вернёт false.
  1134. bool InputInt(TMessageParams* Params, int* Value)
  1135. {
  1136.   TModalResult mr;
  1137.   TMessageParams ErrorParams;
  1138.   bool Result;
  1139.  
  1140.   do // пока юзер не введёт правильно число или не нажмёт отмену
  1141.   {
  1142.     mr = InputBox(Params, 13);
  1143.     if (mr == mrCancel) return false; // Нажали отмену
  1144.    
  1145.     // Перевод строки в число
  1146.     Result = TryStr2Int((*Params).InputValue, Value);
  1147.  
  1148.     // Если число корректно, то проверка на разрядность
  1149.     if (Result)
  1150.     {
  1151.       Result = CheckIntLength((*Params).InputValue, 16);
  1152.      
  1153.       // И если только проверена разрядность, то результат верен!
  1154.       if (Result) return true;
  1155.       else ErrorParams.Message = errIsWider16Bit; // Ошибка - число не лезет в 16 бит
  1156.     }
  1157.  
  1158.     // Если число некорректно - другое сообшение об ошибке
  1159.     else ErrorParams.Message = errIsNotIntValue; // Ошибка - строка не есть целое
  1160.    
  1161.     // Вывод сообщения об ошибке
  1162.     GetWindowDefaults(&ErrorParams, wndError); // параметры окна с ошибкой по умолчанию
  1163.     #ifdef Codepage_ISO
  1164.       ErrorParams.Title = " Неверный ввод ";
  1165.     #endif
  1166.     #ifdef Codepage_DOS
  1167.       ErrorParams.Title = " Input error ";
  1168.     #endif
  1169.     ShowMessage(&ErrorParams);
  1170.   }
  1171.   while (true);
  1172. }
  1173.  
  1174. // Вывод на экран окна ввода демятичного числа (с плав. точкой).
  1175. // Максимальная длина = 13 символов (для точности после точки).
  1176. // Результат возвращается в *Value. Результат = true, если юзер ввёл
  1177. // ПРАВИЛЬНОЕ число (т.е. корректное)
  1178. // и нажал Enter. Esc - отмена, функция вернёт false.
  1179. bool InputFloat(TMessageParams* Params, float* Value)
  1180. {
  1181.   TMessageParams ErrorParams;
  1182.  
  1183.   do // пока юзер не введёт правильно число или не нажмёт отмену
  1184.   {
  1185.     if (InputBox(Params, 13) == mrCancel) return false; // Нажали отмену
  1186.  
  1187.     // Перевод строки в число
  1188.     if (TryStr2Float((*Params).InputValue, Value)) return true;
  1189.     else  // Если число некорректно - сообшение об ошибке
  1190.     {
  1191.       GetWindowDefaults(&ErrorParams, wndError); // параметры окна с ошибкой по умолчанию
  1192.       #ifdef Codepage_ISO
  1193.         ErrorParams.Title = " Неверный ввод ";
  1194.       #endif
  1195.       #ifdef Codepage_DOS
  1196.         ErrorParams.Title = " Input error ";
  1197.       #endif
  1198.       ErrorParams.Message = errIsNotFloatValue; // Ошибка - строка не есть число с пл. точкой
  1199.       ShowMessage(&ErrorParams);
  1200.     } // else
  1201.   }
  1202.   while (true);
  1203. }
  1204.  
  1205. // Вывод на экран окна выбора одной из опций. Сами опции задаются в
  1206. // Params.Message и разделяются символами "\n".
  1207. // DefaultOption - опция по умолчанию.
  1208. // Результат функции - номер выбранной опции (нумерация с единицы).
  1209. int SelectOption(TMessageParams* Params, int DefaultOption)
  1210. {
  1211.   int MaxLen; // длина самой длинной из строк сообщения
  1212.   UINT* Buffer; // Буфер под сохранение участка экрана
  1213.   TTextRect Rect;   // Область окна
  1214.   int OptionsCount = GetLinesCount((*Params).Message, &MaxLen); // Кол-во опций
  1215.   char Key; // Код нажатой клавиши
  1216.   int Selection; // Текущая выбранная опция
  1217.   TTextPoint InvertFrom; // Точка, откуда выделять (инвертировать) текущую опцию
  1218.   int Result = 0; // Результат функции (номер выбраной опции)
  1219.   bool Redraw = true; // Перерисовывать меню или нет (в случае нажатия не тех клавиш)
  1220.  
  1221.   // Вычисление координат окна, чтобы оно было по центру экрана
  1222.   Rect.Height = OptionsCount + 2; // Высота окна, 2 - под рамку
  1223.   Rect.Width = MaxLen + 2;      // Ширина окна, 2 - под рамку
  1224.  
  1225.   CenterRect(&Rect); // Центрирование окна
  1226.   InvertFrom.Col = Rect.Left + 1; // Координата Х выделения опции
  1227.  
  1228.   // Запоминаю часть экрана
  1229.   //Buffer = malloc(Rect.Width * Rect.Height * 2);
  1230.   // Выделение памяти под прямоугольник с учётом тени
  1231.   Buffer = malloc(2 * (Rect.Width * Rect.Height + 2 * Rect.Height + Rect.Width + 2));
  1232.   CopyWindow(Rect, Buffer);
  1233.  
  1234.   // Рисую рамку и выдаю текст
  1235.   DrawFrame(Rect, (*Params).Title, (*Params).BorderColor, (*Params).Background);
  1236.   PrintTextbox(Rect, (*Params).Message, (*Params).TextColor, (*Params).Background);
  1237.  
  1238.   // Выделение по умолчанию
  1239.   if ((DefaultOption > 0) && (DefaultOption <= OptionsCount))
  1240.     Selection = DefaultOption;
  1241.   else Selection = 1;
  1242.  
  1243.   // Опрос клавы
  1244.   while (!Result)
  1245.   {
  1246.     // выделяю опцию
  1247.     if (Redraw)
  1248.     {
  1249.       InvertFrom.Row = Rect.Top + Selection;
  1250.       InvertColors(InvertFrom, MaxLen);
  1251.       HideCursor();
  1252.     }
  1253.  
  1254.     Key = getch(); // Код клавиши
  1255.    
  1256.     switch (Key)
  1257.     {
  1258.       case 0: // Клавиши со стрелками
  1259.         Key = getch(); // Скан-код клавиши
  1260.  
  1261.         if ((Key == kbUp) || (Key == kbLeft)) // стрелка вверх или влево
  1262.         {
  1263.           InvertColors(InvertFrom, MaxLen); // Снятие выделения с текущей опции
  1264.           if (Selection > 1) Selection--;
  1265.           else               Selection = OptionsCount;
  1266.          
  1267.           Redraw = true;
  1268.         }
  1269.        
  1270.         else if ((Key == kbDown) || (Key == kbRight)) // стрелка вниз или вправо
  1271.                {
  1272.                  InvertColors(InvertFrom, MaxLen); // Снятие выделения с текущей опции
  1273.                  if (Selection < OptionsCount) Selection++;
  1274.                  else                          Selection = 1;
  1275.  
  1276.                  Redraw = true;
  1277.                }
  1278.              else Redraw = false;
  1279.       break;
  1280.  
  1281.       case 13: // Enter
  1282.         Result = Selection;
  1283.       break;
  1284.      
  1285.       case kb1: // Клавиши "1"..."9"
  1286.       case kb2:
  1287.       case kb3:
  1288.       case kb4:
  1289.       case kb5:
  1290.       case kb6:
  1291.       case kb7:
  1292.       case kb8:
  1293.       case kb9:
  1294.         if ((Key - kb0) <= OptionsCount)
  1295.           Result = (Key - kb0);
  1296.       break;
  1297.      
  1298.       default: Redraw = false;
  1299.     } // switch
  1300.   } // while
  1301.  
  1302.   // восстанавливаю чать экрана и курсор
  1303.   PasteWindow(Rect, Buffer);
  1304.   free(Buffer);                                                                 // Fix (08.07.2011)
  1305.   ShowCursor();
  1306.  
  1307.   return Result;
  1308. }
  1309.  
  1310. // Показ окна прогресса выполнения (по центру экрана)
  1311. void BeginProgress(TProgressParams* Params)
  1312. {
  1313.   TTextRect Rect;  // Область окна
  1314.   int MaxLen;      // для GetLinesCount()
  1315.  
  1316.   //Rect.Height = GetLinesCount((*Params).Message, &MaxLen) + 2 + 2 + 2; // 2 - под рамку, 2 - под индикатор, 2 - под разделители;
  1317.   Rect.Height = GetLinesCount((*Params).Message, &MaxLen) + 2 + 2;
  1318.  
  1319.   if (MaxLen > (GaugeWidth + 9))
  1320.     Rect.Width = MaxLen + 2;      // Длина кнопок уже сообщения
  1321.   else
  1322.     Rect.Width = GaugeWidth + 11; // Длина кнопок шире сообщения
  1323.  
  1324.   //MakeRect(&Rect, 0, 0, GaugeWidth + 11, RectHeight);
  1325.   CenterRect(&Rect);
  1326.  
  1327.   // Запоминаю участок экрана для последующего восстановления
  1328.   //(*Params).ScreenBuffer = malloc(Rect.Width * Rect.Height * 2);
  1329.   // Выделение памяти под прямоугольник с учётом тени
  1330.   (*Params).ScreenBuffer = malloc(2 * (Rect.Width * Rect.Height + 2 * Rect.Height + Rect.Width + 2));
  1331.   CopyWindow(Rect, (*Params).ScreenBuffer);
  1332.  
  1333.   // Запоминаю параметры прогресса
  1334.   (*Params).OldProgress    = -1;
  1335.   (*Params).From.Col       = Rect.Left + 2;
  1336.   (*Params).From.Row       = Rect.Top + Rect.Height - 2;
  1337.   (*Params).Rect           = Rect;
  1338.  
  1339.   // Рисую окно прогресса с текстом и индикатором
  1340.   DrawFrame(Rect,(*Params).Title, (*Params).Foreground, (*Params).Background);
  1341.   PrintTextbox(Rect, (*Params).Message, (*Params).MsgColor, (*Params).Background);
  1342.   ShowProgressI(0, 100, Params);
  1343. }
  1344.  
  1345. // Показ прогресса выполнения относительно целой величины
  1346. void ShowProgressI(int Current, int Total, TProgressParams* Params)
  1347. {
  1348.   char Gauge[GaugeWidth + 1], Percent[10];
  1349.   int i, Space;
  1350.   double Progress = 100.0 * Current / Total;                                    // Fix (21.05.2009)
  1351.  
  1352.   if (Progress > 100.0) Progress = 100.0;
  1353.   if (Progress == (*Params).OldProgress) return;
  1354.  
  1355.   (*Params).OldProgress = Progress;
  1356.  
  1357.   // Вывожу переменный текст сообщения над индикатором
  1358.   PrintTextbox((*Params).Rect, (*Params).Message, (*Params).MsgColor, (*Params).Background);
  1359.  
  1360.   // Отступ между индикатором и числом процентов
  1361.   if (Progress < 9.95) Space = 3;                                               // Fix (21.05.2009)
  1362.   else if (Progress < 100.0) Space = 2;
  1363.        else                  Space = 1;
  1364.  
  1365.   GotoXY((*Params).From.Col, (*Params).From.Row);
  1366.  
  1367.   GotoXY((*Params).From.Col, (*Params).From.Row);
  1368.  
  1369.   // Заполнение индикатора символами
  1370.   for (i = 0; i < GaugeWidth; ++i)
  1371.     Gauge[i] = SolidBar;
  1372.  
  1373.   // Вычисление номера символа, где надо поставить \0x00
  1374.   i = (int)(Progress * (GaugeWidth / 100.0));                       // ЗАМЕНИТЬ на MakeStr()  !!!!!!!!!!!!!!!!!!!!!!!!!!
  1375.   if (i <= GaugeWidth)
  1376.     Gauge[i] = 0;
  1377.    
  1378.   // Вывод индикатора выполненного
  1379.   ColorPrint(Gauge, (*Params).clComplete, (*Params).clComplete);
  1380.  
  1381.   Gauge[i] = SolidBar; // Возвращаю сивол назад
  1382.  
  1383.   // Вычисление номера символа, где надо поставить \0x00
  1384.   i = GaugeWidth - (int)(Progress * (GaugeWidth / 100.0));
  1385.   Gauge[i] = 0;
  1386.  
  1387.   // Вывод индикатора НЕвыполненного
  1388.   ColorPrint(Gauge, (*Params).clUncomplete, (*Params).clUncomplete);
  1389.  
  1390.   // Вывод процентов
  1391.   //sprintf(Percent, "%.1f%%", Progress);
  1392.   //sprintf(Percent, "%4.1f%%", Progress);
  1393.   sprintf(Percent, "  %d%%", (int)Progress);
  1394.   //GotoXY((*Params).From.Col + GaugeWidth + 1, WhereY()); // Вывод строки пробелов (поверх процентов)
  1395.   //ColorPrint("      ", (*Params).Foreground, (*Params).Background);
  1396.   GotoXY((*Params).From.Col + GaugeWidth + Space, WhereY());
  1397.   ColorPrint(Percent, (*Params).Foreground, (*Params).Background);
  1398. }
  1399.  
  1400. // Показ прогресса выполнения относительно дробной величины
  1401. void ShowProgressF(float Current, float Total, TProgressParams* Params)
  1402. {
  1403.   char Gauge[GaugeWidth + 1], Percent[10];
  1404.   int i, Space;
  1405.   float Progress = 100.0 * Current / Total;
  1406.  
  1407.   if (Progress > 100.0) Progress = 100.0;
  1408.   if (Progress == (*Params).OldProgress) return;
  1409.  
  1410.   (*Params).OldProgress = Progress;
  1411.  
  1412.   // Вывожу переменный текст сообщения над индикатором
  1413.   PrintTextbox((*Params).Rect, (*Params).Message, (*Params).MsgColor, (*Params).Background);
  1414.  
  1415.   // Отступ между индикатором и числом процентов
  1416.   if (Progress < 10.0)
  1417.     Space = 3;
  1418.   else if (Progress < 100.0)
  1419.          Space = 2;
  1420.        else Space = 1;
  1421.  
  1422.   GotoXY((*Params).From.Col, (*Params).From.Row);
  1423.  
  1424.   // Заполнение индикатора символами
  1425.   for (i = 0; i < GaugeWidth; ++i)
  1426.     Gauge[i] = SolidBar;
  1427.  
  1428.   // Вычисление номера символа, где надо поставить \0x00
  1429.   i = (int)(Progress * (GaugeWidth / 100.0));                       // ЗАМЕНИТЬ на MakeStr()  !!!!!!!!!!!!!!!!!!!!!!!!!!
  1430.   if (i <= GaugeWidth)
  1431.     Gauge[i] = 0;
  1432.  
  1433.   // Вывод индикатора выполненного
  1434.   ColorPrint(Gauge, (*Params).clComplete, (*Params).clComplete);
  1435.  
  1436.   Gauge[i] = SolidBar; // Возвращаю сивол назад
  1437.  
  1438.   // Вычисление номера символа, где надо поставить \0x00
  1439.   i = GaugeWidth - (int)(Progress * (GaugeWidth / 100.0));
  1440.   Gauge[i] = 0;
  1441.  
  1442.   // Вывод индикатора НЕвыполненного
  1443.   ColorPrint(Gauge, (*Params).clUncomplete, (*Params).clUncomplete);
  1444.  
  1445.   // Вывод процентов
  1446.   //sprintf(Percent, "%4.1f%%", Progress);                                         // todo : поковырять форматирование
  1447.   sprintf(Percent, "  %d%%", (int)Progress);
  1448.   GotoXY((*Params).From.Col + GaugeWidth + Space, WhereY());
  1449.   ColorPrint(Percent, (*Params).Foreground, (*Params).Background);
  1450. }
  1451.  
  1452. // Скрытие окна прогресса и восстановление области экрана из-под него
  1453. void EndProgress(TProgressParams* Params)
  1454. {
  1455.   PasteWindow((*Params).Rect, (*Params).ScreenBuffer);
  1456.   free((*Params).ScreenBuffer);
  1457. }
  1458.  
  1459. // Показ немодального окна сообщения (окна сообщения с ожиданием)
  1460. void BeginMessageNonModal(TProgressParams* Params)
  1461. {
  1462.   TTextRect Rect;  // Область окна
  1463.   int MaxLen;      // для GetLinesCount()
  1464.  
  1465.   Rect.Height = GetLinesCount((*Params).Message, &MaxLen) + 2;
  1466.   Rect.Width = MaxLen + 2;      // Длина окна
  1467.   CenterRect(&Rect);
  1468.  
  1469.   // Запоминаю участок экрана для последующего восстановления
  1470.   // Выделение памяти под прямоугольник с учётом тени
  1471.   (*Params).ScreenBuffer = malloc(2 * (Rect.Width * Rect.Height + 2 * Rect.Height + Rect.Width + 2));
  1472.   CopyWindow(Rect, (*Params).ScreenBuffer);
  1473.  
  1474.   // Запоминаю параметры прогресса
  1475.   (*Params).Rect           = Rect;
  1476.  
  1477.   // Рисую окно ожидания с текстом
  1478.   DrawFrame(Rect,(*Params).Title, (*Params).Foreground, (*Params).Background);
  1479.   PrintTextbox(Rect, (*Params).Message, (*Params).MsgColor, (*Params).Background);
  1480. }
  1481.  
  1482. // Обновление немодального окна сообщения (окна сообщения с ожиданием)
  1483. void UpdateMessageNonModal(TProgressParams* Params)
  1484. {
  1485.   // Вывожу переменный текст сообщения над индикатором
  1486.   PrintTextbox((*Params).Rect, (*Params).Message, (*Params).MsgColor, (*Params).Background);
  1487. }
  1488.  
  1489. // Скрытие немодального окна сообщения (окна сообщения с ожиданием)
  1490. void EndMessageNonModal(TProgressParams* Params)
  1491. {
  1492.   PasteWindow((*Params).Rect, (*Params).ScreenBuffer);
  1493.   free((*Params).ScreenBuffer);
  1494. }
  1495.  
  1496.  
  1497. // Расчёт длины кнопок диалога в символах
  1498. char GetButtonsSpace(UINT Buttons)
  1499. {
  1500.   int Index, Count = 0, Space = 0;
  1501.  
  1502.   for (Index = 0; Index != ButtonsCount; Index++)
  1503.     if (GetBitInt(Buttons, Index))
  1504.     {
  1505.       Space = Space + strlen(ButtonCaptions[Index]);
  1506.       Count++;
  1507.     }
  1508.    
  1509.   if (Count > 1)
  1510.     Space = Space + Count - 1; // Кнопки разделены одним пробелом
  1511.    
  1512.   return Space;
  1513. }
  1514.  
  1515. // Вывод строки кнопок окна сообщения начиная с точки From
  1516. void DrawButtons(TMessageParams* Params, TTextPoint From)
  1517. {
  1518.   int Index, Len = 0;
  1519.   int Count = 0; // Количество кнопок
  1520.  
  1521.   GotoXY(From.Col, From.Row);
  1522.  
  1523.   for (Index = 0; Index != ButtonsCount; Index++)
  1524.     if (GetBitInt((*Params).Buttons, Index))
  1525.     {
  1526.       Count++;
  1527.       Len += strlen(ButtonCaptions[Index]) + 1;
  1528.  
  1529.       if (Count != (*Params).DefaultButton) // Кнопка не по умолчанию - рисую цвет текста кнопки = цвет текста, фон кнопки = цвету фона
  1530.         ColorPrint(ButtonCaptions[Index], (*Params).TextColor, (*Params).Background);
  1531.       /*else  // Кнопка по умолчанию - рисую инвертированной
  1532.         ColorPrint(ButtonCaptions[Index], ~((*Params).btForeground) & 0x0F, ~((*Params).btBackground) & 0x07);*/
  1533.       else // Кнопка по умолчанию (выделенная)
  1534.         ColorPrint(ButtonCaptions[Index], (*Params).btForeground, (*Params).btBackground);
  1535.        
  1536.       GotoXY(From.Col + Len, From.Row);
  1537.     }
  1538.    
  1539.   HideCursor(); // Скрытие курсора
  1540. }
  1541.  
  1542. TModalResult GetModalResult(TMessageParams* Params, TTextPoint From)
  1543. {
  1544.   char Key, Result, Bit, Count;
  1545.   char ButtonCount = GetBitCountInt((*Params).Buttons); // Количество кнопок
  1546.  
  1547.   do // цикл опроса клавиатуры
  1548.   {
  1549.     Key = getch();
  1550.    
  1551.     if (!Key) Key = getch(); // Вторичный опрос (для кнопок со стрелками)
  1552.    
  1553.     //AddInt2LogF(Key, "Key", IntHex);
  1554.    
  1555.     switch (Key)
  1556.     {
  1557.       case kbTab:   // Tab - переключение активной кнопки
  1558.       case kbRight: // а также клавиши
  1559.       case kbDown:  // "вправо" и "вниз"
  1560.         if ((*Params).DefaultButton < ButtonCount) ((*Params).DefaultButton)++;
  1561.         else (*Params).DefaultButton = 1;
  1562.         DrawButtons(Params, From);
  1563.       break;
  1564.      
  1565.       case kbLeft: //  клавиши
  1566.       case kbUp:   // "влево" и "вверх"
  1567.         if ((*Params).DefaultButton > 1) ((*Params).DefaultButton)--;
  1568.         else (*Params).DefaultButton = ButtonCount;
  1569.         DrawButtons(Params, From);
  1570.       break;
  1571.      
  1572.       // Если среди кнопок есть кнопка "Отмена", то реакция на ESC
  1573.       case kbEsc:
  1574.         if ((*Params).Buttons & btCancel) return mrCancel;
  1575.       break;
  1576.      
  1577.       // Нажатие на активную кнопку (реакция на ENTER)
  1578.       // Номер кнопки - это номер установленного бита в (*Params).Buttons
  1579.       // справа налево плюс 1
  1580.       case kbEnter:
  1581.         Count = 0;
  1582.         for (Bit = 0; Bit < ButtonsCount; Bit++) // Считаю единицы
  1583.         {
  1584.           if (((*Params).Buttons >> Bit) & 1) Count++;
  1585.           if (Count == (*Params).DefaultButton) return Bit + 1;
  1586.         } // for
  1587.       break;
  1588.     } // switch
  1589.   } while (true);
  1590. }
  1591.  
  1592. // Ввод строки
  1593. TModalResult GetInputString(TMessageParams* Params, string S, TTextPoint From, char MaxLength)
  1594. {
  1595.   UCHAR Key;
  1596.   int i, Len;
  1597.   char P[80]; // = (string)malloc(MaxLength + 1);
  1598.   char E[80]; // = (string)malloc(MaxLength + 2);  // Строка пробелов для затирки вводимых данных при BkSpc
  1599.   MakeString(E, ' ', MaxLength + 1);
  1600.   MakeString(P, 0, MaxLength);
  1601.   //strcpy(P, S);
  1602.   //for (i = 0; i < MaxLength; i++) P[i] = 0;
  1603.  
  1604.   GotoXY(From.Col, From.Row);
  1605.   ColorPrint(E, (*Params).InpForeground, (*Params).InpBackground);
  1606.   GotoXY(From.Col, From.Row);
  1607.   ColorPrint(P, (*Params).InpForeground, (*Params).InpBackground);
  1608.  
  1609.   do // цикл опроса клавиатуры
  1610.   {
  1611.     Key = getch();
  1612.    
  1613.     if (!Key) // Пропускаю функциональные клавиши
  1614.     {
  1615.       getch();
  1616.       continue;
  1617.     }
  1618.  
  1619.     Len = strlen(P);
  1620.  
  1621.     if ((Key > 31) && (Len < MaxLength))
  1622.     {
  1623.       P[Len] = Key;
  1624.       P[Len + 1] = 0;
  1625.       GotoXY(From.Col, From.Row);
  1626.       ColorPrint(P, (*Params).InpForeground, (*Params).InpBackground);
  1627.     }
  1628.     else if ((Key == kbBkSpc) && strlen(P))
  1629.          {
  1630.            P[strlen(P) - 1] = 0;
  1631.            GotoXY(From.Col, From.Row);
  1632.            ColorPrint(E, (*Params).InpForeground, (*Params).InpBackground);
  1633.            GotoXY(From.Col, From.Row);
  1634.            ColorPrint(P, (*Params).InpForeground, (*Params).InpBackground);
  1635.          }
  1636.   } while ((Key != 13) && (Key != 27));
  1637.  
  1638.   if (Key == 13)
  1639.   {
  1640.     strcpy(S, P);
  1641.     return mrOk;
  1642.   }
  1643.   else return mrCancel;
  1644. }
  1645.  
  1646. // Ввод строки со значением по умолчанию.
  1647. TModalResult GetInputStringDef(TMessageParams* Params,
  1648.                                string S,
  1649.                                TTextPoint From,
  1650.                                char MaxLength)
  1651. {
  1652.   UCHAR Key;
  1653.   int i, Len;
  1654.   char P[80]; // = (string)malloc(MaxLength + 1);
  1655.   char E[80]; // = (string)malloc(MaxLength + 2);  // Строка пробелов для затирки вводимых данных при BkSpc
  1656.   MakeString(E, ' ', MaxLength + 1);
  1657.   strcpy(P, S);
  1658.  
  1659.   GotoXY(From.Col, From.Row);
  1660.   ColorPrint(E, (*Params).InpForeground, (*Params).InpBackground);
  1661.   GotoXY(From.Col, From.Row);
  1662.   ColorPrint(P, (*Params).InpForeground, (*Params).InpBackground);
  1663.  
  1664.   do // цикл опроса клавиатуры
  1665.   {
  1666.     Key = getch();
  1667.  
  1668.     if (!Key) // Пропускаю функциональные клавиши
  1669.     {
  1670.       getch();
  1671.       continue;
  1672.     }
  1673.  
  1674.     Len = strlen(P);
  1675.  
  1676.     if ((Key > 31) && (Len < MaxLength))
  1677.     {
  1678.       P[Len] = Key;
  1679.       P[Len + 1] = 0;
  1680.       GotoXY(From.Col, From.Row);
  1681.       ColorPrint(P, (*Params).InpForeground, (*Params).InpBackground);
  1682.     }
  1683.     else if ((Key == kbBkSpc) && strlen(P))
  1684.          {
  1685.            P[Len - 1] = 0;
  1686.            GotoXY(From.Col, From.Row);
  1687.            ColorPrint(E, (*Params).InpForeground, (*Params).InpBackground);
  1688.            GotoXY(From.Col, From.Row);
  1689.            ColorPrint(P, (*Params).InpForeground, (*Params).InpBackground);
  1690.          }
  1691.   }
  1692.   while ((Key != 13) && (Key != 27));
  1693.  
  1694.   if (Key == 13)
  1695.   {
  1696.     strcpy(S, P);
  1697.     return mrOk;
  1698.   }
  1699.   else return mrCancel;
  1700. }
  1701.  
  1702. // Отладочная функция. Выводит сообщение об ошибке с текстом Msg,
  1703. // если Condition == false.
  1704. void Assert(const bool Condition, string Msg)                                   // New (02.06.2011)
  1705. {
  1706.   TMessageParams EP;
  1707.   if (Condition) return;
  1708.   GetWindowDefaults(&EP, wndError);
  1709.   EP.Title = " Assert ";
  1710.   EP.Message = Msg;
  1711.   ShowMessage(&EP);
  1712. }
  1713.  
  1714. //==============================================================================
  1715. //=================== Работа с окнами и видеопамятью ===========================
  1716. //==============================================================================
  1717.  
  1718. // Сохранение части экрана в буфере ScreenBuffer
  1719. // Возвращает количество сохранённых символов
  1720. UINT CopyWindow(TTextRect Rect, UINT* Buffer)
  1721. {
  1722.   union REGS r;
  1723.   register int i, j;
  1724.   UINT Saved = 0;
  1725.  
  1726.   for (i = Rect.Top; i < Rect.Height + Rect.Top + 1; i++)    // + 1 - с учётом тени внизу (1 символ)
  1727.     for (j = Rect.Left; j < Rect.Width + Rect.Left + 2; j++) // + 2 - с учётом тени справа (2 символа)
  1728.     {
  1729.       GotoXY(j, i);
  1730.       r.h.ah = 8; // функция чтения символа
  1731.       r.h.bh = 0; // видео страница
  1732.       *Buffer++ = int86(0x10, &r, &r); // Символ и атрибут - al и ah соответственно
  1733.       Saved++;
  1734.     } // for
  1735.    
  1736.   return Saved;
  1737. }
  1738.  
  1739.  
  1740. // Восстановление части экрана из буфера ScreenBuffer
  1741. void PasteWindow(TTextRect Rect, UINT *ScreenBuffer)
  1742. {
  1743.   union REGS r;
  1744.   register int i, j;
  1745.  
  1746.   for (i = Rect.Top; i < Rect.Height + Rect.Top + 1; i++)     // + 1 - с учётом тени внизу (1 символ)
  1747.     for (j = Rect.Left; j < Rect.Width + Rect.Left + 2; j++)  // + 2 - с учётом тени справа (2 символа)
  1748.     {
  1749.       GotoXY(j, i);
  1750.       r.h.ah = 9; // функция записи символа
  1751.       r.h.bh = 0; // видео страница
  1752.       r.x.cx = 1; /* число повторений символа */
  1753.       r.h.al = (*ScreenBuffer) & 0xFF;          /* символ */
  1754.       r.h.bl = ((*ScreenBuffer) >> 8) & 0xFF;   /* атрибут */
  1755.       *ScreenBuffer++;
  1756.       int86(0x10, &r, &r);
  1757.     } // for
  1758. }
  1759.  
  1760. UINT SaveWindow2File(TTextRect Rect, string FileName)
  1761. {
  1762.   union REGS r;
  1763.   register int i, j;
  1764.   UINT Saved = 0;
  1765.   FILE* f;
  1766.  
  1767.   if (!(f = fopen(FileName, "w")))
  1768.   {
  1769.     printf(" Ошибка при открытии файла %s. ", FileName);
  1770.     return 0;
  1771.   };
  1772.  
  1773.   for (i = Rect.Top; i < Rect.Height + Rect.Top; i++)
  1774.   {
  1775.     for (j = Rect.Left; j < Rect.Width + Rect.Left; j++)
  1776.     {
  1777.       GotoXY(j, i);
  1778.       r.h.ah = 8; // функция чтения символа
  1779.       r.h.bh = 0; // видео страница
  1780.       int86(0x10, &r, &r);
  1781.       putc(r.h.al, f);
  1782.       Saved++;
  1783.     } // for
  1784.     putc('\n', f);
  1785.   }
  1786.   fclose(f);
  1787.   return Saved;
  1788. }
  1789.  
  1790. /* сохранение содержимого экрана в дисковом файле */
  1791. void SaveScreen2File(char *fname)
  1792. {
  1793.   FILE *fp;
  1794.   union REGS r;
  1795.   register char x,y;
  1796.  
  1797.   if (!(fp=fopen(fname,"w")))
  1798.   {
  1799.     printf(" Файл не может быть открыт ");
  1800.     exit(1);
  1801.   }
  1802.  
  1803.   for (y = 0; y<25; y++)
  1804.   {
  1805.     for (x=0; x<80; x++)
  1806.     {
  1807.       GotoXY(x, y);
  1808.       r.h.ah = 8; /* чтение символа */
  1809.       r.h.bh = 0; /* видеостраница */
  1810.       int86(0x10, &r, &r);
  1811.       putc(r.h.al, fp); /* выдача (печать) символа */
  1812.     }
  1813.     putc('\n', fp);
  1814.   }
  1815.   fclose(fp);
  1816. }
  1817.  
  1818.  
  1819. //==============================================================================
  1820. //============================= Работа спамятью ================================
  1821. //==============================================================================
  1822.  
  1823. // Заполнение буфера значениями int.
  1824. // Осторожно! Размер буфера должен быть не меньше Len!
  1825. void FillBufferInt(int* Buffer, int Len,...)                                    // Fix (28.06.2011)
  1826. {
  1827.   //int x; // Аргумент(ы) со значениями
  1828.   va_list Ptr; // указатель на аргументы
  1829.   int Index = 0;
  1830.  
  1831.   va_start(Ptr, Len);
  1832.  
  1833.   // Заполнение буфера
  1834.   while (Index < Len)
  1835.   {
  1836.     Buffer[Index] = va_arg(Ptr, int);
  1837.     Index++;
  1838.   }
  1839.  
  1840.   va_end(Ptr);
  1841. }
  1842.  
  1843. // Заполнение буфера значениями char.
  1844. // Осторожно! Размер буфера должен быть не меньше Len!
  1845. void FillBufferChar(UCHAR* Buffer, int Len,...)                                    // New (28.06.2011)
  1846. {
  1847.   //int x; // Аргумент(ы) со значениями
  1848.   va_list Ptr; // указатель на аргументы
  1849.   int Index = 0;
  1850.  
  1851.   va_start(Ptr, Len);
  1852.  
  1853.   // Заполнение буфера
  1854.   while (Index < Len)
  1855.   {
  1856.     Buffer[Index] = (UCHAR)va_arg(Ptr, int);
  1857.     Index++;
  1858.   }
  1859.  
  1860.   va_end(Ptr);
  1861. }
  1862. //==============================================================================
  1863. //============================ Работа со строками ==============================
  1864. //==============================================================================
  1865.  
  1866. // Подсчёт количества строк в сообщении и длины самой длинной из строк MaxLen
  1867. int GetLinesCount(string S, int* MaxLen)
  1868. {
  1869.   int Count = 1;
  1870.   int max = 0;
  1871.   int LineLen = 0; // длина текущей строки сообщения (с учётом \n)
  1872.   *MaxLen = 0;
  1873.  
  1874.   if (!*S) return 0;
  1875.  
  1876.   while (*S)
  1877.   {
  1878.     // пропускаю символы пользователького цвета текста
  1879.     if ((*S >= 0x80) && (*S <= 0x90))
  1880.       continue;
  1881.  
  1882.     max++, LineLen++;
  1883.  
  1884.     // если перенос строки
  1885.     if (*S++ == '\n')
  1886.     {
  1887.       LineLen = 0;
  1888.       Count++;
  1889.  
  1890.       if ((max - 1) > *MaxLen)
  1891.         *MaxLen = max - 1; // -1, чтобы не считать \n
  1892.  
  1893.       max = 0;
  1894.     } // if
  1895.  
  1896.     // если длина строки превышает пределы (вылазит за окно сообщения)
  1897.     else if (LineLen == (MaxMessageWidth - 2))
  1898.     {
  1899.       LineLen = 0;
  1900.       Count++;
  1901.       *MaxLen = MaxMessageWidth - 2;
  1902.     } // else
  1903.   } // while
  1904.  
  1905.   // Если не проходит по высоте - обрезаю кол-во строк
  1906.   if (Count > MaxMessageHeight - 2)
  1907.     Count = MaxMessageHeight - 2;
  1908.    
  1909.   // Если сообщение однострочное без \n, то MaxLen присваиваю значение здесь
  1910.   if (LineLen > *MaxLen)
  1911.     *MaxLen = LineLen;
  1912.  
  1913.   return Count;
  1914. }
  1915.  
  1916. // Вхождение символа C в состав набора символов Charset
  1917. bool CharInCharset(char C, string Charset)
  1918. {
  1919.   while (*Charset)
  1920.     if (*Charset++ == C) return true;
  1921.    
  1922.   return false;
  1923. }
  1924.  
  1925. // Подсчёт количества вхождений символа C в строке S
  1926. UINT GetCharCount(char C, string S)
  1927. {
  1928.   UINT Count = 0;
  1929.  
  1930.   while (*S)
  1931.     if (*S++ == C) Count++;
  1932.    
  1933.   return Count;
  1934. }
  1935.  
  1936. // Центрирование строки относительно ширины поля для её вывода.
  1937. // Возвращает количество символов - смещение влево первого символа строки,
  1938. // чтобы при выводе строка оказалась в середине поля для её вывода
  1939. char CenterString(string S, char Width)
  1940. {
  1941.   int L = strlen(S);
  1942.   if (L >= Width) // Если строка по длине равна или больше области вывода
  1943.     return 0;
  1944.   else
  1945.     return (Width - L) / 2;
  1946. }
  1947.  
  1948. // Заполнение сроки S символами C и вставка нуля в конец
  1949. // Внимание! Длина строки не проверяется и должна быть больше Count - 1 !!!
  1950. void MakeString(string S, char C, UINT Count)
  1951. {
  1952.   UINT Index;
  1953.   for (Index = 0; Index < Count; Index++)
  1954.     *S++ = C;
  1955.    
  1956.   *S = 0;
  1957. }
  1958.  
  1959. // Проверка: строка есть целое десятичное число
  1960. bool StrIsDec(string S)
  1961. {
  1962.   if (!*S) return false; // строка пустая?
  1963.   if (*S == '0') return false; // с нуля - только восьмеричные числа
  1964.   if ((*S == '-') || (*S == '+')) S++; // Впереди может быть знак минус или плюс
  1965.  
  1966.   while (*S)
  1967.     if (!CharInCharset(*S++, DecDigits)) return false;
  1968.    
  1969.   return true;
  1970. }
  1971.  
  1972. // Проверка: строка есть целое шестнадцатеричное число
  1973. bool StrIsHex(string S)
  1974. {
  1975.   if (!*S) return false; // строка пустая?
  1976.   if (strnicmp(S, "0x", 2)) return false; // строка начинается на (0x | 0X)?
  1977.  
  1978.   S += 2; // Продвигаю указатель на 2 символа (пропускаю 0x)
  1979.  
  1980.   while (*S)
  1981.     if (!CharInCharset(*S++, HexDigits)) return false;
  1982.  
  1983.   return true;
  1984. }
  1985.  
  1986. // Проверка: строка есть целое восьмеричное число
  1987. bool StrIsOct(string S)
  1988. {
  1989.   if (!*S) return false; // строка пустая?
  1990.   if (strncmp(S, "0", 1)) return false; // строка начинается на 0?
  1991.  
  1992.   while (*S)
  1993.     if (!CharInCharset(*S++, OctDigits)) return false;
  1994.  
  1995.   return true;
  1996. }
  1997.  
  1998. // Проверка: строка есть число с плавающей точкой (дробное)
  1999. bool StrIsFloat(string S)
  2000. {
  2001.   int eCount = 0;
  2002.  
  2003.   if (!*S) return false; // строка пустая?
  2004.   if ((*S == '-') || (*S == '+')) S++; // Впереди может быть знак минус или плюс
  2005.  
  2006.   // Строка должна начинаться цифрой (если есть знак - после знака):
  2007.   if (!CharInCharset(*S, DecDigits)) return false;
  2008.  
  2009.   // Строка должна кончаться цифрой:
  2010.   if (!CharInCharset(S[strlen(S) - 1], DecDigits)) return false;
  2011.  
  2012.   // Десятичная точка может быть одна или не быть совсем
  2013.   if (GetCharCount('.', S) > 1) return false;
  2014.  
  2015.   // Показатель 10^x (e или E) может быть только 1 шт.
  2016.   eCount = GetCharCount('e', S) + GetCharCount('E', S);
  2017.   if (eCount > 1) return false;
  2018.  
  2019.   // Проверка валидности символов
  2020.   while (*S)
  2021.     if (!CharInCharset(*S++, FloatSymbols)) return false;
  2022.  
  2023.   return true;
  2024. }
  2025.  
  2026. // Перевод строки в 16-битное целое со знаком.
  2027. // Возвращает true, если строка есть (10-чное | 16-чное | 8-чное)
  2028. bool TryStr2Int(string S, int* Value)
  2029. {
  2030.   string Format;
  2031.   if (StrIsDec(S)) Format = "%d";
  2032.   else if (StrIsHex(S)) Format = "0x%x";
  2033.        else if (StrIsOct(S)) Format = "%o";
  2034.             else return false;
  2035.  
  2036.   return sscanf(S, Format, Value);
  2037. }
  2038.  
  2039. // Перевод строки в 32-битное целое со знаком.
  2040. // Возвращает true, если строка есть (10-чное | 16-чное | 8-чное)
  2041. bool TryStr2Long(string S, long* Value)
  2042. {
  2043.   string Format;
  2044.   if (StrIsDec(S)) Format = "%ld";
  2045.   else if (StrIsHex(S)) Format = "0x%lx";
  2046.        else if (StrIsOct(S)) Format = "%lo";
  2047.             else return false;
  2048.  
  2049.   return sscanf(S, Format, Value);
  2050. }
  2051.  
  2052. // Перевод строки в десятичное (с пл. точкой) со знаком
  2053. bool TryStr2Float(string S, float* Value)
  2054. {
  2055.   //AddStr2Log(S, "S"); // для отладки
  2056.  
  2057.   if (StrIsFloat(S))
  2058.     return sscanf(S, "%f", Value);
  2059.   else
  2060.     return false;
  2061. }
  2062.  
  2063. // Перевод строки в десятичное (с пл. точкой) со знаком двойной точности
  2064. bool TryStr2Double(string S, double* Value)
  2065. {
  2066.   //AddStr2Log(S, "S");
  2067.  
  2068.   if (StrIsFloat(S))
  2069.     return sscanf(S, "%lf", Value);
  2070.   else
  2071.     return false;
  2072. }
  2073.  
  2074. // Проверка длины введённого числа на разрядность
  2075. // BitCount = (16 | 32)
  2076. // ==== интервалы для 16 бит: ====
  2077. //  - -32768...+32767
  2078. //  - 0x0000...0xFFFF
  2079. //  - 0000000...0177777
  2080. // ==== интервалы для 32 бит: ====
  2081. //  - -2147483648...+2147483647
  2082. //  - 0x00000000...0xFFFFFFFF
  2083. //  - 00000000000...37777777777
  2084. bool CheckIntLength(string Value, char BitCount)
  2085. {
  2086.   string Limit; // Эталон
  2087.  
  2088.   // ----------- 16-битные ------------
  2089.   if (BitCount == 16)
  2090.   {
  2091.     if (StrIsDec(Value)) // Десятичные
  2092.     {
  2093.       if (*Value == '-')           Limit = "-32768";  // отрицательное
  2094.       else if (*Value == '+')      Limit = "+32767";  // положительное с плюсом
  2095.              else                  Limit = "32767";   // положительное, начинающееся с цифры
  2096.     } // if
  2097.     else if (StrIsHex(Value))      Limit = "0xFFFF";  // 16-ричные
  2098.          else if (StrIsOct(Value)) Limit = "0177777"; // 8-ричные
  2099.                 else return false;                    // Ваще не число!
  2100.   } // if (BitCount == 16)
  2101.  
  2102.   // ----------- 32-битные ------------
  2103.   else
  2104.   {
  2105.     if (StrIsDec(Value)) // Десятичные
  2106.     {
  2107.       if (*Value == '-')           Limit = "-2147483648";  // отрицательное
  2108.       else if (*Value == '+')      Limit = "+2147483647";  // положительное с плюсом
  2109.              else                  Limit = "2147483647";   // положительное, начинающееся с цифры
  2110.     } // if
  2111.     else if (StrIsHex(Value))      Limit = "0xFFFFFFFF";   // 16-ричные
  2112.          else if (StrIsOct(Value)) Limit = "37777777777";  // 8-ричные
  2113.                 else return false;                         // Ваще не число!
  2114.   } // else
  2115.  
  2116.   //--- Вывод в лог ----
  2117.   //AddStr2Log(Value, "Value");
  2118.   //AddStr2Log(Limit, "Limit");
  2119.  
  2120.   // сразу на выход, если длина строки не равна длине эталона
  2121.   // функция strcmpi() выдаёт тогда неверный результат, а мне оно не надо
  2122.   if (strlen(Limit) < strlen(Value)) return false;
  2123.   if (strlen(Limit) > strlen(Value)) return true;
  2124.  
  2125.   // И только при равенстве длин этих строк их можно нормально сравнивайть побайтно
  2126.   if (strcmpi(Value, Limit) > 0) return false;
  2127.   else                           return true;
  2128. }
  2129.  
  2130. // Загрузка текстового файла в строку с выделением памяти под неё.
  2131. // Символы <cr><lf> заменяются на <lf>, в конце добавляется 0.
  2132. // В параметре Len возвращается длина строки (исключая последний 0).
  2133. // Функция возвращает указатель на строку. Для освобождения памяти
  2134. // используй функцию free().
  2135. // В случае ошибки функция возвратит NULL.
  2136. /*string LoadStrFromFile(string FileName)
  2137. {
  2138.   UINT iSize; // 16 бит (вполне, чтоб не путаться с лонгами, это геморрой)
  2139.   UINT Readed; // сколько прочитано
  2140.   string Result = NULL;
  2141.   int hFile = open(FileName, O_RDONLY | O_TEXT);
  2142.   if (hFile != -1)
  2143.  
  2144.   //AddInt2Log(hFile, "hFile");
  2145.  
  2146.   if (Result)
  2147.   {
  2148.     iSize = ((UINT)(filelength(hFile) & 0xFFFF));
  2149.     //AddInt2Log(iSize, "iSize");
  2150.     Result = malloc(iSize + 1); // +1 - для завершающего нуля, это же строка!
  2151.  
  2152.     if (Result)
  2153.     {
  2154.       Readed = read(hFile, Result, iSize);
  2155.       Result[Readed] = 0; // Заверщающий ноль
  2156.       close(hFile);
  2157.     }
  2158.     else Result = false;
  2159.   }
  2160.  
  2161.   return Result;
  2162. } */
  2163.  
  2164. //==============================================================================
  2165. //================= Математические и логические функции ========================
  2166. //==============================================================================
  2167.  
  2168. // Функции НОРМАЛЬНОГО округления дробного числа до целого с учётом знака
  2169. // Не нашёл аналога в стандартных функциях, поэтому пришлось написать
  2170. // аналог паскалевской функции Round().
  2171. int RoundI(float X)
  2172. {
  2173.   double IntPart;
  2174.   double Frac = modf(X, &IntPart);
  2175.  
  2176.   if (fabs(Frac) < 0.5) return (int)floor(X); // Округление до меньшего целого
  2177.   else                  return (int)ceil(X);  // Округление до большего целого
  2178. }
  2179.  
  2180. long RoundL(float X)
  2181. {
  2182.   double IntPart;
  2183.   double Frac = modf(X, &IntPart);
  2184.  
  2185.   if (fabs(Frac) < 0.5) return (long)floor(X); // Округление до меньшего целого
  2186.   else                  return (long)ceil(X);  // Округление до большего целого
  2187. }
  2188.  
  2189. // Проверка, установлен ли бит номер Bit в 16-битном целом
  2190. bool GetBitInt(UINT Value, char Bit)
  2191. {
  2192.   return ((1 << Bit) & Value);
  2193. }
  2194.  
  2195. // Подсчёт количества установленных бит в 16-битном целом
  2196. char GetBitCountInt(UINT Value)
  2197. {
  2198.   char Index, Count = 0;
  2199.  
  2200.   for (Index = 0; Index != 16; Index++)
  2201.     if ((Value >> Index) & 1) Count++;
  2202.    
  2203.   return Count;
  2204. }
  2205.  
  2206. // Является ли 16-битное целое Value в пределах LoLimit <= Value <= HiLimit
  2207. bool BetweenInt(int Value, int LoLimit, int HiLimit)
  2208. {
  2209.   //if ((Value >= LoLimit) && (Value <= HiLimit)) return true;
  2210.   //else                                          return false;
  2211.   return ((Value >= LoLimit) && (Value <= HiLimit));                            // fix (17.08.2010)
  2212. }
  2213.  
  2214. // Является ли 32-битное целое Value в пределах LoLimit <= Value <= HiLimit
  2215. bool BetweenLong(long Value, long LoLimit, long HiLimit)
  2216. {
  2217.   //if ((Value >= LoLimit) && (Value <= HiLimit)) return true;
  2218.   //else                                          return false;
  2219.   return ((Value >= LoLimit) && (Value <= HiLimit));                            // fix (17.08.2010)
  2220. }
  2221.  
  2222. // Является ли дробное Value в пределах LoLimit <= Value <= HiLimit
  2223. bool BetweenFloat(float Value, float LoLimit, float HiLimit)
  2224. {
  2225.   //AddFloat2Log(Value, "Value");
  2226.   //AddFloat2Log(LoLimit, "LoLimit");
  2227.   //AddFloat2Log(HiLimit, "HiLimit");
  2228.  
  2229.   //if (((Value - LoLimit) >= 0) && ((Value - HiLimit) <= 0)) return true;
  2230.   //else                                                      return false;
  2231.   //if ((Value >= LoLimit) && (Value <= HiLimit)) return true;
  2232.   //else                                          return false;
  2233.   return ((Value >= LoLimit) && (Value <= HiLimit));                            // fix (17.08.2010)
  2234. }
  2235.  
  2236. //==============================================================================
  2237. //========================== Работа с лог-файлом ===============================
  2238. //==============================================================================
  2239.  
  2240. // Открытие лог-файла
  2241. bool OpenLog(string FileName)
  2242. {
  2243.   char Time[10];
  2244.  
  2245.   LogFile = fopen(FileName, "w");
  2246.   if (LogFile)
  2247.   {
  2248.     _strtime(Time);
  2249.     fprintf(LogFile, LogDivider);
  2250.     fprintf(LogFile, "                                Лог начат %s\n", Time);
  2251.     fprintf(LogFile, LogDivider);
  2252.   }
  2253.  
  2254.   return (LogFile != 0);
  2255. }
  2256.  
  2257. // Закрытие лог-файла
  2258. void CloseLog(void)
  2259. {
  2260.   if (LogFile)
  2261.   {
  2262.     fprintf(LogFile, LogDivider);
  2263.     fclose(LogFile);
  2264.   }
  2265. }
  2266.  
  2267. // Добавление в лог простой строки
  2268. void Add2Log(string S)
  2269. {
  2270.   if (LogFile)
  2271.   {
  2272.     fprintf(LogFile, "%s\n", S);
  2273.     fflush(LogFile);
  2274.   }
  2275. }
  2276.  
  2277. // Добавление в лог значения 8-битного char:
  2278. //  - в формате Name = 'Value' [0xXX] при Value > 31;
  2279. //  - в формате Name = {Value} [0xXX] при Value <= 31;
  2280. void AddChar2Log(UCHAR Value, string Name)
  2281. {
  2282.   if (LogFile)
  2283.   {
  2284.     if (Value > 31) fprintf(LogFile, " %s = '%c' [0x%02X]\n", Name, Value, Value);
  2285.     else            fprintf(LogFile, " %s = {%d} [0x%02X]\n", Name, Value, Value);
  2286.     fflush(LogFile);
  2287.   }
  2288. }
  2289.  
  2290. // Добавление в лог значение 16-битного целого в формате Name = Value
  2291. void AddInt2Log(int Value, string Name)
  2292. {
  2293.   if (LogFile)
  2294.   {
  2295.     fprintf(LogFile, " %s = %d\n", Name, Value);
  2296.     fflush(LogFile);
  2297.   }
  2298. }
  2299.  
  2300. // Добавление в лог значение 16-битного целого в формате Name = Value
  2301. // в системе счисления F = (IntDec | IntHex | IntOct)
  2302. void AddInt2LogF(int Value, string Name, char F)
  2303. {
  2304.   if (LogFile)
  2305.   {
  2306.     switch (F)
  2307.     {
  2308.       case IntDec:
  2309.         fprintf(LogFile, " %s = %d\n", Name, Value);
  2310.         break;
  2311.  
  2312.       case IntHex:
  2313.         fprintf(LogFile, " %s = 0x%04X\n", Name, Value);
  2314.         break;
  2315.        
  2316.       case IntOct:
  2317.         fprintf(LogFile, " %s = %07o\n", Name, Value);
  2318.         break;
  2319.     } // switch
  2320.    
  2321.     fflush(LogFile);
  2322.   }
  2323. }
  2324.  
  2325. // Добавление в лог значение 32-битного целого в формате Name = Value
  2326. void AddLong2Log(long Value, string Name)
  2327. {
  2328.   if (LogFile)
  2329.   {
  2330.     fprintf(LogFile, " %s = %ld\n", Name, Value);
  2331.     fflush(LogFile);
  2332.   }
  2333. }
  2334.  
  2335. // Добавление в лог значения с плав. точкой в формате Name = Value
  2336. void AddFloat2Log(float Value, string Name)
  2337. {
  2338.   if (LogFile)
  2339.   {
  2340.     fprintf(LogFile, " %s = %f\n", Name, Value);
  2341.     fflush(LogFile);
  2342.   }
  2343. }
  2344.  
  2345. // Добавление в лог значения с плав. точкой double в формате Name = Value
  2346. void AddDouble2Log(double Value, string Name)
  2347. {
  2348.   if (LogFile)
  2349.   {
  2350.     fprintf(LogFile, " %s = %lf\n", Name, Value);
  2351.     fflush(LogFile);
  2352.   }
  2353. }
  2354.  
  2355. // Добавление в лог значения логического типа в формате Name = (true | false)
  2356. void AddBool2Log(bool Value, string Name)
  2357. {
  2358.   if (LogFile)
  2359.   {
  2360.     if (Value) fprintf(LogFile, " %s = true\n", Name);
  2361.     else       fprintf(LogFile, " %s = false\n", Name);
  2362.     fflush(LogFile);
  2363.   }
  2364. }
  2365.  
  2366. // Добавление в лог строкового эквивалента TModalResult
  2367. void AddModalResult2Log(TModalResult Value)
  2368. {
  2369.   if (LogFile && (Value <= ButtonsCount))
  2370.   {
  2371.     if (Value)
  2372.       fprintf(LogFile, " ModalResult = %s (%d)\n", ButtonCaptions[Value - 1], Value);
  2373.     else
  2374.       fprintf(LogFile, " ModalResult = mrNone (0)\n");
  2375.  
  2376.     fflush(LogFile);
  2377.   }
  2378. }
  2379.  
  2380. // Добавление в лог значения строки в формате Name = Value
  2381. void AddStr2Log(string Value, string Name)
  2382. {
  2383.   if (LogFile)
  2384.   {
  2385.     fprintf(LogFile, " %s = %s\n", Name, Value);
  2386.     fflush(LogFile);
  2387.   }
  2388. }
  2389.  
  2390. void AddRect2Log(TTextRect Value, string Name)
  2391. {
  2392.   if (LogFile)
  2393.   {
  2394.     fprintf(LogFile, " %s: Left = %d, Top = %d, Width = %d, Height = %d\n",
  2395.             Name, Value.Left, Value.Top, Value.Width, Value.Height);
  2396.     fflush(LogFile);
  2397.   }
  2398. }
  2399.  
  2400. //==============================================================================
  2401. //======================= Работа с файлом настроек =============================
  2402. //==============================================================================
  2403.  
  2404. // Загрузка настроек в буфер
  2405. /*bool LoadIni(string FileName)
  2406. {
  2407.   int hFile = open(FileName, O_RDONLY | O_TEXT);
  2408.   bool Result = (hFile != -1);
  2409.   UINT iSize; // 16 бит (вполне, чтоб не путаться с лонгами, это геморрой)
  2410.   UINT Readed; // сколько прочитано
  2411.   int i;
  2412.  
  2413.   AddInt2Log(hFile, "hFile");
  2414.  
  2415.   if (Result)
  2416.   {
  2417.     iSize = ((UINT)(filelength(hFile) & 0xFFFF));
  2418.     AddInt2Log(iSize, "iSize");
  2419.     Ini = malloc(iSize + 1); // +1 - для завершающего нуля, это же строка!
  2420.     //for (i = 0; i != (iSize + 1); i++) Ini[i] = 0; // Обнуление буфера
  2421.    
  2422.     if (Ini)
  2423.     {
  2424.       Readed = read(hFile, Ini, iSize);
  2425.       Result = (Readed != -1);
  2426.       Ini[Readed] = 0; // Заверщающий ноль
  2427.       close(hFile);
  2428.     }
  2429.     else Result = false;
  2430.   }
  2431.  
  2432.   return Result;
  2433. }
  2434.  
  2435. // Освобождение памяти из-под буфера Ini
  2436. void FreeIni(void)
  2437. {
  2438.   if (Ini) free(Ini);
  2439. }
  2440.  
  2441. // Чтение целого параметра с именем Name из Ini в Value.
  2442. // Если чтение произвести невозможно по причинам:
  2443. //   * буфер не инициализирован (NULL);
  2444. //   * параметра с именем Name не существует;
  2445. //   * строку, сопоставленную имени параметра не удалось перевести в число,
  2446. // функция возвращает значение Default.
  2447. int IniReadInt(string Name, int Default)
  2448. {
  2449.  
  2450. }     */
  2451.  
  2452. //==============================================================================
  2453. //====================== Работа с датой и временем =============================
  2454. //==============================================================================
  2455.  
  2456. // ================== Декодирование времени ========================
  2457. void DecodeTime(float Seconds, TTimeStamp* T)
  2458. {
  2459.    double Trunc;                                  // Секунды
  2460.    long  Sec;                                     // Целое число секунд всего
  2461.    double Frac = modf(Seconds, &Trunc);           // миллисекунды
  2462.  
  2463.    if (Frac < 0.0) Frac = 0.0;                    // Чтобы не было отрицательного времени
  2464.  
  2465.    Sec = (long)floor(Trunc);                      // Целое число секунд всего
  2466.  
  2467.    (*T).Hr      = Sec / 3600;                     // Часы
  2468.    (*T).Min     = (Sec % 3600) / 60;              // Минуты в часе
  2469.    (*T).Sec     = Sec % 60;                       // Секунды в минуте
  2470.    (*T).mSec    = (UINT)floor(Frac * 1e+3);       // Целое число миллисекунд
  2471. }
  2472.  
  2473.  
  2474. // Задержка не менее mSeconds миллисекунд
  2475. void Sleep(ULONG mSeconds)
  2476. {
  2477.   ULONG Estimated = 0;
  2478.   ULONG Begin = clock();
  2479.   // clock() - кол-во миллисекунд, прошедших от запуска программы
  2480.   long Cycles = 0; // Debug
  2481.   do
  2482.   {
  2483.     Estimated = labs(clock() - Begin);
  2484.     Cycles++;
  2485.   } while (Estimated < mSeconds);
  2486. }
  2487.  
  2488. // Задержка Seconds секунд (дробное число) с показом прогресса выполнения.
  2489. // Возвращает false, если юзер нажал "отмену". При Seconds < 0.5 окно прогресса
  2490. // не показывается.
  2491. bool Delay(float Seconds, TProgressParams* Params)
  2492. {
  2493.   char Key = 0;
  2494.   float Estimated = 0.0; // кол-во СЕКУНД, прошедших от запуска функции
  2495.   float Remained;        // кол-во СЕКУНД, оставшихся до конца задержки
  2496.   float Begin = clock() / 1000.0; // кол-во СЕКУНД, прошедших от запуска проги
  2497.   long Count = 0; // для отладки
  2498.   TTimeStamp T; // Для отображения оставшегося времени и заголовка
  2499.   char Title[40]; // Для формирования заголовка окна
  2500.  
  2501.   // При Seconds < 0.5 окно прогресса не показывается
  2502.   if (Seconds < 0.5)
  2503.   {
  2504.     Sleep((ULONG)RoundL(Seconds * 1000));
  2505.     return true;
  2506.   }
  2507.  
  2508.   // Перевод Seconds в строку типа HH:MM:SS.mS и вывод в заголовок
  2509.   DecodeTime(Seconds, &T);
  2510.   #ifdef Codepage_DOS
  2511.   sprintf(Title, " Delay %02d:%02d:%02d.%03d ", T.Hr, T.Min, T.Sec, T.mSec);
  2512.   #endif
  2513.   #ifdef Codepage_ISO
  2514.   sprintf(Title, " Задержка %02d:%02d:%02d.%03d ", T.Hr, T.Min, T.Sec, T.mSec);
  2515.   #endif
  2516.   (*Params).Title = Title;
  2517.  
  2518.   // Вывод онка задержки
  2519.   BeginProgress(Params);
  2520.  
  2521.   // Цикл задержки с выводом прогресса выполнения
  2522.   do
  2523.   {
  2524.     Estimated = fabs((clock() / 1000.0) - Begin);
  2525.     Remained  = Seconds - Estimated;
  2526.    
  2527.     // Перевод Remained в строку типа HH:MM:SS.mS и вывод, сколько осталось времени
  2528.     DecodeTime(Remained, &T);
  2529.     #ifdef Codepage_DOS
  2530.     sprintf(Title, " Remain time %02d:%02d:%02d.%03d ", T.Hr, T.Min, T.Sec, T.mSec);
  2531.     #endif
  2532.     #ifdef Codepage_ISO
  2533.     sprintf(Title, " Осталось %02d:%02d:%02d.%03d ", T.Hr, T.Min, T.Sec, T.mSec);
  2534.     #endif
  2535.     (*Params).Message = Title;
  2536.    
  2537.     ShowProgressF(Estimated, Seconds, Params);
  2538.    
  2539.     // Проверка клавиши ESC
  2540.     if (kbhit()) Key = getch();
  2541.     Count++;
  2542.   }
  2543.   while ((Estimated < Seconds) && (Key != 27)); // do
  2544.  
  2545.   // Скрытие окна задержки
  2546.   EndProgress(Params);
  2547.   //AddLong2Log(Count, "Count");
  2548.  
  2549.   return (Key != 27);
  2550. }
  2551.  
  2552. //==============================================================================
  2553. //========================== Работа со звуком ==================================
  2554. //=========(не поверил бы, что работает в WinXP, пока не сам не проверил)=======
  2555. //==============================================================================
  2556.  
  2557. // Звучание динамика на частоте Frequency в течение Pause миллисекунд
  2558. void Beep(UINT Frequency, ULONG Pause)
  2559. {
  2560.   UCHAR Temp;
  2561.  
  2562.   union // Счётчик
  2563.   {
  2564.     ULONG Divisor;
  2565.     UCHAR Bytes[2];
  2566.   }
  2567.   Count;
  2568.  
  2569.   Count.Divisor = SysTimerFreq / Frequency; // вычисление небходимого значения счетчика
  2570.  
  2571.   outp(0x43, 0xB6);        // обращение к таймеру 8253 после установки счетчика
  2572.   outp(0x42, Count.Bytes[0]);  // пересылка младшего байта
  2573.   outp(0x42, Count.Bytes[1]);  // пересылка старшего байта
  2574.  
  2575.   Temp = inp(0x61);           // чтение существующего шаблона бит
  2576.  
  2577.   outp(0x61, (Temp | 0x03));  // установка битов 0 и 1
  2578.   Sleep(Pause);            // Задержка в миллисекундах
  2579.   outp(0x61, Temp);           // восстановление первоначального значения шаблона бит для отключения динамика
  2580. }
  2581.  
  2582. UCHAR sndTemp; // Для след. 2х функций (содержимое порта 0x61)
  2583.  
  2584. // Включение звучания динамика на частоте Frequency
  2585. void Sound(UINT Frequency)
  2586. {
  2587.   union // Счётчик
  2588.   {
  2589.     ULONG Divisor;
  2590.     UCHAR Bytes[2];
  2591.   }
  2592.   Count;
  2593.  
  2594.   Count.Divisor = SysTimerFreq / Frequency; // вычисление небходимого значения счетчика
  2595.  
  2596.   outp(0x43, 0xB6);        // обращение к таймеру 8253 после установки счетчика
  2597.   outp(0x42, Count.Bytes[0]);  // пересылка младшего байта
  2598.   outp(0x42, Count.Bytes[1]);  // пересылка старшего байта
  2599.  
  2600.   sndTemp = inp(0x61);           // чтение существующего шаблона бит
  2601.  
  2602.   outp(0x61, (sndTemp | 0x03));  // установка битов 0 и 1
  2603. }
  2604.  
  2605. // Включение звучания динамика
  2606. void NoSound(void)
  2607. {
  2608.   outp(0x61, sndTemp); // восстановление первоначального значения шаблона бит для отключения динамика
  2609. }
  2610.  
  2611.  
  2612.  
  2613. /*
  2614. ================================== Памятка ===================================
  2615.    1. Сделать нормальную работу со строками через realloc(), т.е. чтоб были
  2616.       функции Insert(), Delete() и прочие.
  2617.  + 2. Сделать звук типа Sound(Frequency).
  2618.  + 3. Сделать функции ввода целого, дробного.
  2619.  + 4. При вводе под DOS первого символа какая-то херня творится со строкой ввода.
  2620.    5. Сделать работу с файлом настроек.
  2621.    6. Сделать функцию, возвращающую текущую версию модуля и дату компиляции.
  2622.    7. Сделать функции ввода с пределами.
  2623. */
  2624.  
  2625. //==============================================================================
  2626. //=========================== Работа с клавиатурой =============================
  2627. //==============================================================================
  2628.  
  2629. // Проверка нажатия клавиши с кодом Key
  2630. bool KeyPressed(UCHAR Key)  // New (17.06.2010)
  2631. {
  2632.   if (kbhit())
  2633.     if (getch() == Key) return true;
  2634.  
  2635.   return false;
  2636. }
  2637.  
  2638. // Проверка нажатия клавиши Escape
  2639. bool EscapePressed(void)  // New (17.06.2010)
  2640. {
  2641.   if (kbhit())
  2642.     if (getch() == kbEsc) return true;
  2643.  
  2644.   return false;
  2645. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement