new keyboard navigation method now is default
[far2l.git] / far2l / src / dialog.cpp
blobddfd46542c52fbbf12beead7a2fe79829af82e83
1 /*
2 dialog.cpp
4 Класс диалога
5 */
6 /*
7 Copyright (c) 1996 Eugene Roshal
8 Copyright (c) 2000 Far Group
9 All rights reserved.
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions
13 are met:
14 1. Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
16 2. Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in the
18 documentation and/or other materials provided with the distribution.
19 3. The name of the authors may not be used to endorse or promote products
20 derived from this software without specific prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "headers.hpp"
36 #include "dialog.hpp"
37 #include "lang.hpp"
38 #include "keyboard.hpp"
39 #include "macroopcode.hpp"
40 #include "keys.hpp"
41 #include "ctrlobj.hpp"
42 #include "chgprior.hpp"
43 #include "vmenu.hpp"
44 #include "dlgedit.hpp"
45 #include "help.hpp"
46 #include "scrbuf.hpp"
47 #include "manager.hpp"
48 #include "savescr.hpp"
49 #include "constitle.hpp"
50 #include "lockscrn.hpp"
51 #include "TPreRedrawFunc.hpp"
52 #include "syslog.hpp"
53 #include "interf.hpp"
54 #include "palette.hpp"
55 #include "message.hpp"
56 #include "strmix.hpp"
57 #include "history.hpp"
58 #include "InterThreadCall.hpp"
59 #include <VT256ColorTable.h>
60 #include <cwctype>
61 #include <atomic>
63 #define VTEXT_ADN_SEPARATORS 1
65 // Флаги для функции ConvertItem
66 enum CVTITEMFLAGS
68 CVTITEM_TOPLUGIN = 0,
69 CVTITEM_FROMPLUGIN = 1,
70 CVTITEM_TOPLUGINSHORT = 2,
71 CVTITEM_FROMPLUGINSHORT = 3
74 enum DLGEDITLINEFLAGS
76 DLGEDITLINE_CLEARSELONKILLFOCUS = 0x00000001, // управляет выделением блока при потере фокуса ввода
77 DLGEDITLINE_SELALLGOTFOCUS = 0x00000002, // управляет выделением блока при получении фокуса ввода
78 DLGEDITLINE_NOTSELONGOTFOCUS = 0x00000004, // не восстанавливать выделение строки редактирования при получении фокуса ввода
79 DLGEDITLINE_NEWSELONGOTFOCUS = 0x00000008, // управляет процессом выделения блока при получении фокуса
80 DLGEDITLINE_GOTOEOLGOTFOCUS = 0x00000010, // при получении фокуса ввода переместить курсор в конец строки
83 enum DLGITEMINTERNALFLAGS
85 DLGIIF_LISTREACTIONFOCUS = 0x00000001, // MouseReaction для фокусного элемента
86 DLGIIF_LISTREACTIONNOFOCUS = 0x00000002, // MouseReaction для не фокусного элемента
88 DLGIIF_COMBOBOXNOREDRAWEDIT = 0x00000008, // не прорисовывать строку редактирования при изменениях в комбо
89 DLGIIF_COMBOBOXEVENTKEY = 0x00000010, // посылать события клавиатуры в диалоговую проц. для открытого комбобокса
90 DLGIIF_COMBOBOXEVENTMOUSE = 0x00000020, // посылать события мыши в диалоговую проц. для открытого комбобокса
93 const wchar_t *fmtSavedDialogHistory = L"SavedDialogHistory/";
95 //////////////////////////////////////////////////////////////////////////
97 Функция, определяющая - "Может ли элемент диалога иметь фокус ввода"
99 static inline bool CanGetFocus(int Type)
101 switch (Type) {
102 case DI_EDIT:
103 case DI_FIXEDIT:
104 case DI_PSWEDIT:
105 case DI_COMBOBOX:
106 case DI_BUTTON:
107 case DI_CHECKBOX:
108 case DI_RADIOBUTTON:
109 case DI_LISTBOX:
110 case DI_MEMOEDIT:
111 case DI_USERCONTROL:
112 return true;
113 default:
114 return false;
118 bool IsKeyHighlighted(const wchar_t *Str, FarKey Key, int Translate, int AmpPos)
120 if (AmpPos == -1) {
121 if (!(Str = wcschr(Str, L'&')))
122 return false;
124 AmpPos = 1;
125 } else {
126 if (AmpPos >= StrLength(Str))
127 return false;
129 Str+= AmpPos;
130 AmpPos = 0;
132 if (Str[AmpPos] == L'&')
133 AmpPos++;
136 wchar_t UpperStrKey = Upper(Str[AmpPos]);
138 if (WCHAR_IS_VALID(Key)) {
139 return UpperStrKey == Upper(Key) || (Translate && KeyToKeyLayoutCompare(Upper(Key), UpperStrKey));
142 if (Key & KEY_ALT) {
143 uint32_t AltKey = Key & (~KEY_ALT);
145 if (WCHAR_IS_VALID(AltKey)) {
146 if (iswdigit(AltKey) != 0)
147 return (AltKey == (uint32_t)UpperStrKey);
149 if (AltKey > L' ')
150 // (AltKey=='-' || AltKey=='/' || AltKey==',' || AltKey=='.' ||
151 // AltKey=='\\' || AltKey=='=' || AltKey=='[' || AltKey==']' ||
152 // AltKey==':' || AltKey=='"' || AltKey=='~'))
154 return (UpperStrKey == Upper(AltKey)
155 || (Translate && KeyToKeyLayoutCompare(AltKey, UpperStrKey)));
160 return false;
163 void DialogItemExToDialogItemEx(DialogItemEx *pSrc, DialogItemEx *pDest)
165 pDest->Type = pSrc->Type;
166 pDest->X1 = pSrc->X1;
167 pDest->Y1 = pSrc->Y1;
168 pDest->X2 = pSrc->X2;
169 pDest->Y2 = pSrc->Y2;
170 pDest->Focus = pSrc->Focus;
171 pDest->Reserved = pSrc->Reserved;
172 pDest->strHistory = pSrc->strHistory;
173 pDest->strMask = pSrc->strMask;
174 pDest->Flags = pSrc->Flags;
175 pDest->DefaultButton = pSrc->DefaultButton;
176 pDest->nMaxLength = 0;
177 pDest->strData = pSrc->strData;
178 pDest->ID = pSrc->ID;
179 pDest->IFlags = pSrc->IFlags;
180 pDest->AutoCount = pSrc->AutoCount;
181 pDest->AutoPtr = pSrc->AutoPtr;
182 pDest->UserData = pSrc->UserData;
183 pDest->ObjPtr = pSrc->ObjPtr;
184 pDest->ListPtr = pSrc->ListPtr;
185 pDest->UCData = pSrc->UCData;
186 pDest->SelStart = pSrc->SelStart;
187 pDest->SelEnd = pSrc->SelEnd;
190 void ConvertItemSmall(FarDialogItem *Item, DialogItemEx *Data)
192 Item->Type = Data->Type;
193 Item->X1 = Data->X1;
194 Item->Y1 = Data->Y1;
195 Item->X2 = Data->X2;
196 Item->Y2 = Data->Y2;
197 Item->Focus = Data->Focus;
198 Item->Flags = Data->Flags;
199 Item->DefaultButton = Data->DefaultButton;
200 Item->MaxLen = Data->nMaxLength;
201 Item->PtrData = nullptr;
203 Item->Param.History = nullptr;
204 if (Data->Type == DI_LISTBOX || Data->Type == DI_COMBOBOX) {
205 Item->Param.ListPos = Data->ListPtr ? Data->ListPtr->GetSelectPos() : 0;
207 if ((Data->Type == DI_EDIT || Data->Type == DI_FIXEDIT) && Data->Flags & DIF_HISTORY) {
208 Item->Param.History = Data->strHistory;
209 } else if (Data->Type == DI_FIXEDIT && Data->Flags & DIF_MASKEDIT) {
210 Item->Param.Mask = Data->strMask;
211 } else {
212 Item->Param.Reserved = Data->Reserved;
216 size_t ItemStringAndSize(DialogItemEx *Data, FARString &ItemString)
218 DlgEdit *EditPtr;
219 if (FarIsEdit(Data->Type) && (EditPtr = (DlgEdit *)(Data->ObjPtr)) != nullptr)
220 EditPtr->GetString(ItemString);
221 else
222 ItemString = Data->strData;
224 size_t sz = ItemString.GetLength();
226 if (sz > Data->nMaxLength && Data->nMaxLength > 0)
227 sz = Data->nMaxLength;
229 return sz;
232 bool ConvertItemEx(CVTITEMFLAGS FromPlugin, FarDialogItem *Item, DialogItemEx *Data, unsigned Count)
234 unsigned I;
236 if (!Item || !Data)
237 return false;
239 switch (FromPlugin) {
240 case CVTITEM_TOPLUGIN:
241 case CVTITEM_TOPLUGINSHORT:
243 for (I = 0; I < Count; I++, ++Item, ++Data) {
244 ConvertItemSmall(Item, Data);
246 if (FromPlugin == CVTITEM_TOPLUGIN) {
247 FARString str;
248 size_t sz = ItemStringAndSize(Data, str);
250 wchar_t *p = (wchar_t *)malloc((sz + 1) * sizeof(wchar_t));
251 Item->PtrData = p;
253 if (!p) // TODO: may be needed message?
254 return false;
256 wmemcpy(p, str.CPtr(), sz);
257 p[sz] = L'\0';
262 break;
263 case CVTITEM_FROMPLUGIN:
264 case CVTITEM_FROMPLUGINSHORT:
266 for (I = 0; I < Count; I++, ++Item, ++Data) {
267 Data->X1 = Item->X1;
268 Data->Y1 = Item->Y1;
269 Data->X2 = Item->X2;
270 Data->Y2 = Item->Y2;
271 Data->Focus = Item->Focus;
272 Data->Reserved = 0;
273 if ((Item->Type == DI_EDIT || Item->Type == DI_FIXEDIT) && Item->Flags & DIF_HISTORY) {
274 Data->strHistory = Item->Param.History;
275 } else if (Item->Type == DI_FIXEDIT && Item->Flags & DIF_MASKEDIT) {
276 Data->strMask = Item->Param.Mask;
277 } else {
278 Data->Reserved = Item->Param.Reserved;
280 Data->Flags = Item->Flags;
281 Data->DefaultButton = Item->DefaultButton;
282 Data->Type = Item->Type;
284 if (FromPlugin == CVTITEM_FROMPLUGIN) {
285 Data->strData = Item->PtrData;
286 Data->nMaxLength = Item->MaxLen;
288 if (Data->nMaxLength > 0)
289 Data->strData.Truncate(Data->nMaxLength);
292 Data->ListItems = Item->Param.ListItems;
294 if (Data->X2 < Data->X1)
295 Data->X2 = Data->X1;
297 if (Data->Y2 < Data->Y1)
298 Data->Y2 = Data->Y1;
300 if ((Data->Type == DI_COMBOBOX || Data->Type == DI_LISTBOX) && !IsPtr(Item->Param.ListItems))
301 Data->ListItems = nullptr;
304 break;
307 return true;
310 size_t ConvertItemEx2(FarDialogItem *Item, DialogItemEx *Data)
312 size_t size = sizeof(*Item);
313 FARString str;
314 size_t sz = ItemStringAndSize(Data, str);
315 size+= (sz + 1) * sizeof(wchar_t);
317 if (Item) {
318 ConvertItemSmall(Item, Data);
320 wchar_t *p = (wchar_t *)(Item + 1);
321 Item->PtrData = p;
322 wmemcpy(p, str.CPtr(), sz);
323 p[sz] = L'\0';
326 return size;
329 void DataToItemEx(const DialogDataEx *Data, DialogItemEx *Item, int Count)
331 if (!Item || !Data)
332 return;
334 for (int i = 0; i < Count; i++) {
335 Item[i].Clear();
336 Item[i].ID = static_cast<WORD>(i);
337 Item[i].Type = Data[i].Type;
338 Item[i].X1 = Data[i].X1;
339 Item[i].Y1 = Data[i].Y1;
340 Item[i].X2 = Data[i].X2;
341 Item[i].Y2 = Data[i].Y2;
343 if (Item[i].X2 < Item[i].X1)
344 Item[i].X2 = Item[i].X1;
346 if (Item[i].Y2 < Item[i].Y1)
347 Item[i].Y2 = Item[i].Y1;
349 Item[i].Focus =
350 Item[i].Type != DI_SINGLEBOX && Item[i].Type != DI_DOUBLEBOX && (Data[i].Flags & DIF_FOCUS);
351 if ((Data[i].Type == DI_EDIT || Data[i].Type == DI_FIXEDIT) && Data[i].Flags & DIF_HISTORY) {
352 Item[i].strHistory = Data[i].History;
353 } else if (Data[i].Type == DI_FIXEDIT && Data[i].Flags & DIF_MASKEDIT) {
354 Item[i].strMask = Data[i].Mask;
355 } else {
356 Item[i].Reserved = Data[i].Reserved;
358 Item[i].Flags = Data[i].Flags;
359 Item[i].DefaultButton =
360 Item[i].Type != DI_TEXT && Item[i].Type != DI_VTEXT && (Data[i].Flags & DIF_DEFAULT);
361 Item[i].SelStart = -1;
363 if (!IsPtr(Data[i].Data)) // awful
364 Item[i].strData = FarLangMsg{(int)(DWORD_PTR)Data[i].Data};
365 else
366 Item[i].strData = Data[i].Data;
370 Dialog::Dialog(DialogItemEx *SrcItem, // Набор элементов диалога
371 unsigned SrcItemCount, // Количество элементов
372 FARWINDOWPROC DlgProc, // Диалоговая процедура
373 LONG_PTR InitParam) // Ассоцированные с диалогом данные
375 CMM(MACRO_DIALOG)
377 Dialog::Item = (DialogItemEx **)malloc(sizeof(DialogItemEx *) * SrcItemCount);
379 for (unsigned i = 0; i < SrcItemCount; i++) {
380 Dialog::Item[i] = new DialogItemEx;
381 Dialog::Item[i]->Clear();
382 DialogItemExToDialogItemEx(&SrcItem[i], Dialog::Item[i]);
385 Dialog::ItemCount = SrcItemCount;
386 Dialog::pSaveItemEx = SrcItem;
387 Init(DlgProc, InitParam);
390 Dialog::Dialog(FarDialogItem *SrcItem, // Набор элементов диалога
391 unsigned SrcItemCount, // Количество элементов
392 FARWINDOWPROC DlgProc, // Диалоговая процедура
393 LONG_PTR InitParam) // Ассоцированные с диалогом данные
395 CMM(MACRO_DIALOG)
397 Dialog::Item = (DialogItemEx **)malloc(sizeof(DialogItemEx *) * SrcItemCount);
399 for (unsigned i = 0; i < SrcItemCount; i++) {
400 Dialog::Item[i] = new DialogItemEx;
401 Dialog::Item[i]->Clear();
402 // BUGBUG add error check
403 ConvertItemEx(CVTITEM_FROMPLUGIN, &SrcItem[i], Dialog::Item[i], 1);
406 Dialog::ItemCount = SrcItemCount;
407 Dialog::pSaveItemEx = nullptr;
408 Init(DlgProc, InitParam);
411 void Dialog::Init(FARWINDOWPROC DlgProc, // Диалоговая процедура
412 LONG_PTR InitParam) // Ассоцированные с диалогом данные
414 SetDynamicallyBorn(FALSE); // $OT: По умолчанию все диалоги создаются статически
415 CanLoseFocus = FALSE;
416 HelpTopic = nullptr;
417 // Номер плагина, вызвавшего диалог (-1 = Main)
418 PluginNumber = -1;
419 Dialog::DataDialog = InitParam;
420 DialogMode.Set(DMODE_ISCANMOVE);
421 SetDropDownOpened(FALSE);
422 IsEnableRedraw = 0;
423 InCtlColorDlgItem = 0;
424 FocusPos = (unsigned)-1;
425 PrevFocusPos = (unsigned)-1;
427 if (!DlgProc) // функция должна быть всегда!!!
429 DlgProc = DefDlgProc;
430 // знать диалог в старом стиле - учтем этот факт!
431 DialogMode.Set(DMODE_OLDSTYLE);
434 Dialog::RealDlgProc = DlgProc;
436 //_SVS(SysLog(L"Dialog =%d",CtrlObject->Macro.GetMode()));
437 // запоминаем предыдущий заголовок консоли
438 OldTitle = new ConsoleTitle;
439 IdExist = false;
440 memset(&Id, 0, sizeof(Id));
443 //////////////////////////////////////////////////////////////////////////
445 Public, Virtual:
446 Деструктор класса Dialog
448 Dialog::~Dialog()
450 _tran(SysLog(L"[%p] Dialog::~Dialog()", this));
452 DeleteDialogObjects();
454 Hide();
455 ScrBuf.Flush();
457 if (HelpTopic)
458 delete[] HelpTopic;
460 for (unsigned i = 0; i < ItemCount; i++)
461 delete Item[i];
463 free(Item);
464 delete OldTitle;
466 if (!WinPortTesting()) {
467 INPUT_RECORD rec;
468 PeekInputRecord(&rec);
471 _DIALOG(CleverSysLog CL(L"Destroy Dialog"));
474 void Dialog::CheckDialogCoord()
476 CriticalSectionLock Lock(CS);
478 if (X1 == -1) // задано центрирование диалога по горизонтали?
479 { // X2 при этом = ширине диалога.
480 X1 = (ScrX - X2 + 1) / 2;
482 if (X1 < 0) // ширина диалога больше ширины экрана?
484 X1 = 0;
485 } else {
486 X2+= X1 - 1;
490 if (Y1 == -1) // задано центрирование диалога по вертикали?
491 { // Y2 при этом = высоте диалога.
492 Y1 = (ScrY - Y2 + 1) / 2;
494 if (!DialogMode.Check(DMODE_SMALLDIALOG)) //????
495 if (Y1 > 5)
496 Y1--;
498 if (Y1 < 0) {
499 Y1 = 0;
500 } else {
501 Y2+= Y1 - 1;
506 void Dialog::InitDialog()
508 CriticalSectionLock Lock(CS);
510 if (!DialogMode.Check(DMODE_INITOBJECTS)) // самодостаточный вариант, когда
511 { // элементы инициализируются при первом вызове.
512 CheckDialogCoord();
513 unsigned InitFocus = InitDialogObjects();
514 int Result = (int)DlgProc((HANDLE)this, DN_INITDIALOG, InitFocus, DataDialog);
516 if (ExitCode == -1) {
517 if (Result) {
518 // еще разок, т.к. данные могли быть изменены
519 InitFocus = InitDialogObjects(); // InitFocus=????
522 if (!DialogMode.Check(DMODE_KEEPCONSOLETITLE))
523 ConsoleTitle::SetFarTitle(GetDialogTitle());
526 // все объекты проинициализированы!
527 DialogMode.Set(DMODE_INITOBJECTS);
528 DialogInfo di = {sizeof(di)};
530 if (DlgProc(reinterpret_cast<HANDLE>(this), DN_GETDIALOGINFO, 0, reinterpret_cast<LONG_PTR>(&di))) {
531 Id = di.Id;
532 IdExist = true;
535 DlgProc((HANDLE)this, DN_GOTFOCUS, InitFocus, 0);
539 //////////////////////////////////////////////////////////////////////////
541 Public, Virtual:
542 Расчет значений координат окна диалога и вызов функции
543 ScreenObject::Show() для вывода диалога на экран.
545 void Dialog::Show()
547 CriticalSectionLock Lock(CS);
548 _tran(SysLog(L"[%p] Dialog::Show()", this));
550 if (!DialogMode.Check(DMODE_INITOBJECTS))
551 return;
553 if (!Locked() && DialogMode.Check(DMODE_RESIZED)) {
554 PreRedrawItem preRedrawItem = PreRedraw.Peek();
556 if (preRedrawItem.PreRedrawFunc)
557 preRedrawItem.PreRedrawFunc();
560 DialogMode.Clear(DMODE_RESIZED);
562 if (Locked())
563 return;
565 DialogMode.Set(DMODE_SHOW);
566 ScreenObject::Show();
569 // Цель перехвата данной функции - управление видимостью...
570 void Dialog::Hide()
572 CriticalSectionLock Lock(CS);
573 _tran(SysLog(L"[%p] Dialog::Hide()", this));
575 if (!DialogMode.Check(DMODE_INITOBJECTS))
576 return;
578 DialogMode.Clear(DMODE_SHOW);
579 ScreenObject::Hide();
582 //////////////////////////////////////////////////////////////////////////
584 Private, Virtual:
585 Инициализация объектов и вывод диалога на экран.
587 void Dialog::DisplayObject()
589 CriticalSectionLock Lock(CS);
591 if (DialogMode.Check(DMODE_SHOW)) {
592 ChangePriority ChPriority(ChangePriority::NORMAL);
593 ShowDialog(); // "нарисуем" диалог
597 // пересчитать координаты для элементов с DIF_CENTERGROUP
598 void Dialog::ProcessCenterGroup()
600 CriticalSectionLock Lock(CS);
602 for (unsigned I = 0; I < ItemCount; I++) {
604 Последовательно объявленные элементы с флагом DIF_CENTERGROUP
605 и одинаковой вертикальной позицией будут отцентрированы в диалоге.
606 Их координаты X не важны. Удобно использовать для центрирования
607 групп кнопок.
609 if ((Item[I]->Flags & DIF_CENTERGROUP)
610 && (I == 0 || (Item[I - 1]->Flags & DIF_CENTERGROUP) == 0
611 || Item[I - 1]->Y1 != Item[I]->Y1)) {
612 int Length = 0;
614 for (UINT J = I;
615 J < ItemCount && (Item[J]->Flags & DIF_CENTERGROUP) && Item[J]->Y1 == Item[I]->Y1; J++) {
616 Length+= LenStrItem(J);
618 if (!Item[J]->strData.IsEmpty())
619 switch (Item[J]->Type) {
620 case DI_BUTTON:
621 Length++;
622 break;
623 case DI_CHECKBOX:
624 case DI_RADIOBUTTON:
625 Length+= 5;
626 break;
630 if (!Item[I]->strData.IsEmpty())
631 switch (Item[I]->Type) {
632 case DI_BUTTON:
633 Length--;
634 break;
635 case DI_CHECKBOX:
636 case DI_RADIOBUTTON:
637 // Length-=5;
638 break;
639 } // Бля, це ж ботва какая-то
641 int StartX = Max(0, (X2 - X1 + 1 - Length) / 2);
643 for (UINT J = I;
644 J < ItemCount && (Item[J]->Flags & DIF_CENTERGROUP) && Item[J]->Y1 == Item[I]->Y1; J++) {
645 Item[J]->X1 = StartX;
646 StartX+= LenStrItem(J);
648 if (!Item[J]->strData.IsEmpty())
649 switch (Item[J]->Type) {
650 case DI_BUTTON:
651 StartX++;
652 break;
653 case DI_CHECKBOX:
654 case DI_RADIOBUTTON:
655 StartX+= 5;
656 break;
659 if (StartX == Item[J]->X1)
660 Item[J]->X2 = StartX;
661 else
662 Item[J]->X2 = StartX - 1;
668 //////////////////////////////////////////////////////////////////////////
670 Public:
671 Инициализация элементов диалога.
673 InitDialogObjects возвращает ID элемента с фокусом ввода
674 Параметр - для выборочной реинициализации элементов. ID = -1 - касаемо всех объектов
677 TODO: Необходимо применить ProcessRadioButton для исправления
678 кривых рук некоторых плагинописателей (а надо?)
680 unsigned Dialog::InitDialogObjects(unsigned ID)
682 CriticalSectionLock Lock(CS);
683 unsigned I, J;
684 int Type;
685 DialogItemEx *CurItem;
686 unsigned InitItemCount;
687 DWORD ItemFlags;
688 _DIALOG(CleverSysLog CL(L"Init Dialog"));
690 if (ID == (unsigned)-1) // инициализируем все?
692 ID = 0;
693 InitItemCount = ItemCount;
694 } else if (ID + 1 > ItemCount) {
695 return (unsigned)-1;
696 } else {
697 InitItemCount = ID + 1;
700 // если FocusPos в пределах и элемент задисаблен, то ищем сначала
701 if (FocusPos != (unsigned)-1 && FocusPos < ItemCount
702 && (Item[FocusPos]->Flags & (DIF_DISABLE | DIF_NOFOCUS | DIF_HIDDEN)))
703 FocusPos = (unsigned)-1; // будем искать сначала!
705 // предварительный цикл по поводу кнопок
706 for (I = ID; I < InitItemCount; I++) {
707 CurItem = Item[I];
708 ItemFlags = CurItem->Flags;
709 Type = CurItem->Type;
711 if (Type == DI_BUTTON && ItemFlags & DIF_SETSHIELD) {
712 CurItem->strData = FARString(L"\x2580\x2584 ") + CurItem->strData;
716 для кнопок не имеющи стиля "Показывает заголовок кнопки без скобок"
717 добавим энти самые скобки
719 if (Type == DI_BUTTON && !(ItemFlags & DIF_NOBRACKETS)) {
720 LPCWSTR Brackets[] = {L"[ ", L" ]", L"{ ", L" }"};
721 int Start = (CurItem->DefaultButton ? 2 : 0);
722 if (CurItem->strData.At(0) != *Brackets[Start]) {
723 CurItem->strData = Brackets[Start] + CurItem->strData + Brackets[Start + 1];
726 // предварительный поик фокуса
727 if (FocusPos == (unsigned)-1 && CanGetFocus(Type) && CurItem->Focus
728 && !(ItemFlags & (DIF_DISABLE | DIF_NOFOCUS | DIF_HIDDEN)))
729 FocusPos = I; // запомним первый фокусный элемент
731 CurItem->Focus = 0; // сбросим для всех, чтобы не оказалось,
732 // что фокусов - как у дурочка фантиков
734 // сбросим флаг DIF_CENTERGROUP для редакторов
735 switch (Type) {
736 case DI_BUTTON:
737 case DI_CHECKBOX:
738 case DI_RADIOBUTTON:
739 case DI_TEXT:
740 case DI_VTEXT: // ????
741 break;
742 default:
744 if (ItemFlags & DIF_CENTERGROUP)
745 CurItem->Flags&= ~DIF_CENTERGROUP;
750 Опять про фокус ввода - теперь, если "чудо" забыло выставить
751 хотя бы один, то ставим на первый подходящий
753 if (FocusPos == (unsigned)-1) {
754 for (I = 0; I < ItemCount; I++) // по всем!!!!
756 CurItem = Item[I];
758 if (CanGetFocus(CurItem->Type) && !(CurItem->Flags & (DIF_DISABLE | DIF_NOFOCUS | DIF_HIDDEN))) {
759 FocusPos = I;
760 break;
765 if (FocusPos == (unsigned)-1) // ну ни хрена себе - нет ни одного
766 { // элемента с возможностью фокуса
767 FocusPos = 0; // убится, блин
770 // ну вот и добрались до!
771 Item[FocusPos]->Focus = 1;
772 // а теперь все сначала и по полной программе...
773 ProcessCenterGroup(); // сначала отцентрируем
775 for (I = ID; I < InitItemCount; I++) {
776 CurItem = Item[I];
777 Type = CurItem->Type;
778 ItemFlags = CurItem->Flags;
780 if (Type == DI_LISTBOX) {
781 if (!DialogMode.Check(DMODE_CREATEOBJECTS)) {
782 CurItem->ListPtr = new VMenu(nullptr, nullptr, 0, CurItem->Y2 - CurItem->Y1 + 1,
783 VMENU_ALWAYSSCROLLBAR | VMENU_LISTBOX, nullptr, this);
786 if (CurItem->ListPtr) {
787 VMenu *ListPtr = CurItem->ListPtr;
788 ListPtr->SetVDialogItemID(I);
790 $ 13.09.2000 SVS
791 + Флаг DIF_LISTNOAMPERSAND. По умолчанию для DI_LISTBOX &
792 DI_COMBOBOX выставляется флаг MENU_SHOWAMPERSAND. Этот флаг
793 подавляет такое поведение
795 CurItem->IFlags.Set(DLGIIF_LISTREACTIONFOCUS | DLGIIF_LISTREACTIONNOFOCUS); // всегда!
796 ListPtr->ChangeFlags(VMENU_DISABLED, ItemFlags & DIF_DISABLE);
797 ListPtr->ChangeFlags(VMENU_SHOWAMPERSAND, !(ItemFlags & DIF_LISTNOAMPERSAND));
798 ListPtr->ChangeFlags(VMENU_SHOWNOBOX, ItemFlags & DIF_LISTNOBOX);
799 ListPtr->ChangeFlags(VMENU_WRAPMODE, ItemFlags & DIF_LISTWRAPMODE);
800 ListPtr->ChangeFlags(VMENU_AUTOHIGHLIGHT, ItemFlags & DIF_LISTAUTOHIGHLIGHT);
802 if (ItemFlags & DIF_LISTAUTOHIGHLIGHT)
803 ListPtr->AssignHighlights(FALSE);
805 ListPtr->SetDialogStyle(DialogMode.Check(DMODE_WARNINGSTYLE));
806 ListPtr->SetPosition(X1 + CurItem->X1, Y1 + CurItem->Y1, X1 + CurItem->X2, Y1 + CurItem->Y2);
807 ListPtr->SetBoxType(SHORT_SINGLE_BOX);
809 // поле FarDialogItem.Data для DI_LISTBOX используется как верхний заголовок листа
810 if (!(ItemFlags & DIF_LISTNOBOX) && !DialogMode.Check(DMODE_CREATEOBJECTS)) {
811 ListPtr->SetTitle(CurItem->strData);
814 // удалим все итемы
815 // ListBox->DeleteItems(); //???? А НАДО ЛИ ????
816 if (CurItem->ListItems && !DialogMode.Check(DMODE_CREATEOBJECTS)) {
817 ListPtr->AddItem(CurItem->ListItems);
820 ListPtr->ChangeFlags(VMENU_LISTHASFOCUS, CurItem->Focus);
823 // "редакторы" - разговор особый...
824 else if (FarIsEdit(Type)) {
826 сбросим флаг DIF_EDITOR для строки ввода, отличной от DI_EDIT,
827 DI_FIXEDIT и DI_PSWEDIT
829 if (Type != DI_COMBOBOX)
830 if ((ItemFlags & DIF_EDITOR) && Type != DI_EDIT && Type != DI_FIXEDIT && Type != DI_PSWEDIT)
831 ItemFlags&= ~DIF_EDITOR;
833 if (!DialogMode.Check(DMODE_CREATEOBJECTS)) {
834 CurItem->ObjPtr =
835 new DlgEdit(this, I, Type == DI_MEMOEDIT ? DLGEDIT_MULTILINE : DLGEDIT_SINGLELINE);
837 if (Type == DI_COMBOBOX) {
838 CurItem->ListPtr = new VMenu(L"", nullptr, 0, Opt.Dialogs.CBoxMaxHeight,
839 VMENU_ALWAYSSCROLLBAR | VMENU_NOTCHANGE, nullptr, this);
840 CurItem->ListPtr->SetVDialogItemID(I);
843 CurItem->SelStart = -1;
846 DlgEdit *DialogEdit = (DlgEdit *)CurItem->ObjPtr;
847 // Mantis#58 - символ-маска с кодом 0х0А - пропадает
848 // DialogEdit->SetDialogParent((Type != DI_COMBOBOX && (ItemFlags & DIF_EDITOR) || (CurItem->Type==DI_PSWEDIT || CurItem->Type==DI_FIXEDIT))?
849 // FEDITLINE_PARENT_SINGLELINE:FEDITLINE_PARENT_MULTILINE);
850 DialogEdit->SetDialogParent(
851 Type == DI_MEMOEDIT ? FEDITLINE_PARENT_MULTILINE : FEDITLINE_PARENT_SINGLELINE);
852 DialogEdit->SetReadOnly(0);
854 if (Type == DI_COMBOBOX) {
855 if (CurItem->ListPtr) {
856 VMenu *ListPtr = CurItem->ListPtr;
857 ListPtr->SetBoxType(SHORT_SINGLE_BOX);
858 DialogEdit->SetDropDownBox(ItemFlags & DIF_DROPDOWNLIST);
859 ListPtr->ChangeFlags(VMENU_WRAPMODE, ItemFlags & DIF_LISTWRAPMODE);
860 ListPtr->ChangeFlags(VMENU_DISABLED, ItemFlags & DIF_DISABLE);
861 ListPtr->ChangeFlags(VMENU_SHOWAMPERSAND, !(ItemFlags & DIF_LISTNOAMPERSAND));
862 ListPtr->ChangeFlags(VMENU_AUTOHIGHLIGHT, ItemFlags & DIF_LISTAUTOHIGHLIGHT);
864 if (ItemFlags & DIF_LISTAUTOHIGHLIGHT)
865 ListPtr->AssignHighlights(FALSE);
867 if (CurItem->ListItems && !DialogMode.Check(DMODE_CREATEOBJECTS))
868 ListPtr->AddItem(CurItem->ListItems);
870 ListPtr->SetFlags(VMENU_COMBOBOX);
871 ListPtr->SetDialogStyle(DialogMode.Check(DMODE_WARNINGSTYLE));
876 $ 15.10.2000 tran
877 строка редакторирование должна иметь максимум в 511 символов
878 выставляем максимальный размер в том случае, если он еще не выставлен
881 // BUGBUG
882 if (DialogEdit->GetMaxLength() == -1)
883 DialogEdit->SetMaxLength(CurItem->nMaxLength ? (int)CurItem->nMaxLength : -1);
885 DialogEdit->SetPosition(X1 + CurItem->X1, Y1 + CurItem->Y1, X1 + CurItem->X2, Y1 + CurItem->Y2);
888 DialogEdit->SetObjectColor(
889 FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE) ?
890 ((ItemFlags&DIF_DISABLE)?COL_WARNDIALOGEDITDISABLED:COL_WARNDIALOGEDIT):
891 ((ItemFlags&DIF_DISABLE)?COL_DIALOGEDITDISABLED:COL_DIALOGEDIT)),
892 FarColorToReal((ItemFlags&DIF_DISABLE)?COL_DIALOGEDITDISABLED:COL_DIALOGEDITSELECTED)
895 if (CurItem->Type == DI_PSWEDIT) {
896 DialogEdit->SetPasswordMode(TRUE);
897 // ...Что бы небыло повадно... и для повыщения защиты, т.с.
898 ItemFlags&= ~DIF_HISTORY;
901 if (Type == DI_FIXEDIT) {
902 // DIF_HISTORY имеет более высокий приоритет, чем DIF_MASKEDIT
903 if (ItemFlags & DIF_HISTORY)
904 ItemFlags&= ~DIF_MASKEDIT;
907 если DI_FIXEDIT, то курсор сразу ставится на замену...
908 ай-ай - было недокументированно :-)
910 DialogEdit->SetMaxLength(CurItem->X2 - CurItem->X1 + 1
911 + (CurItem->X2 == CurItem->X1 || !(ItemFlags & DIF_HISTORY) ? 0 : 1));
912 DialogEdit->SetOvertypeMode(TRUE);
914 $ 12.08.2000 KM
915 Если тип строки ввода DI_FIXEDIT и установлен флаг DIF_MASKEDIT
916 и непустой параметр CurItem->Mask, то вызываем новую функцию
917 для установки маски в объект DlgEdit.
920 // Маска не должна быть пустой (строка из пробелов не учитывается)!
921 if ((ItemFlags & DIF_MASKEDIT) && !CurItem->strMask.IsEmpty()) {
922 RemoveExternalSpaces(CurItem->strMask);
923 if (!CurItem->strMask.IsEmpty()) {
924 DialogEdit->SetInputMask(CurItem->strMask);
925 } else {
926 ItemFlags&= ~DIF_MASKEDIT;
929 } else
932 "мини-редактор"
933 Последовательно определенные поля ввода (edit controls),
934 имеющие этот флаг группируются в редактор с возможностью
935 вставки и удаления строк
937 if (!(ItemFlags & DIF_EDITOR) && CurItem->Type != DI_COMBOBOX) {
938 DialogEdit->SetEditBeyondEnd(FALSE);
940 if (!DialogMode.Check(DMODE_INITOBJECTS))
941 DialogEdit->SetClearFlag(1);
944 if (CurItem->Type == DI_COMBOBOX)
945 DialogEdit->SetClearFlag(1);
948 $ 01.08.2000 SVS
949 Еже ли стоит флаг DIF_USELASTHISTORY и непустая строка ввода,
950 то подстанавливаем первое значение из History
952 if (CurItem->Type == DI_EDIT
953 && (ItemFlags & (DIF_HISTORY | DIF_USELASTHISTORY))
954 == (DIF_HISTORY | DIF_USELASTHISTORY)) {
955 ProcessLastHistory(CurItem, -1);
958 if ((ItemFlags & DIF_MANUALADDHISTORY) && !(ItemFlags & DIF_HISTORY))
959 ItemFlags&= ~DIF_MANUALADDHISTORY; // сбросим нафиг.
962 $ 18.03.2000 SVS
963 Если это ComBoBox и данные не установлены, то берем из списка
964 при условии, что хоть один из пунктов имеет Selected
967 if (Type == DI_COMBOBOX && CurItem->strData.IsEmpty() && CurItem->ListItems) {
968 FarListItem *ListItems = CurItem->ListItems->Items;
969 unsigned Length = CurItem->ListItems->ItemsNumber;
970 // CurItem->ListPtr->AddItem(CurItem->ListItems);
972 for (J = 0; J < Length; J++) {
973 if (ListItems[J].Flags & LIF_SELECTED) {
974 if (ItemFlags & (DIF_DROPDOWNLIST | DIF_LISTNOAMPERSAND))
975 HiText2Str(CurItem->strData, ListItems[J].Text);
976 else
977 CurItem->strData = ListItems[J].Text;
979 break;
984 DialogEdit->SetCallbackState(false);
985 DialogEdit->SetString(CurItem->strData);
986 DialogEdit->SetCallbackState(true);
988 if (Type == DI_FIXEDIT)
989 DialogEdit->SetCurPos(0);
991 // Для обычных строк отрубим постоянные блоки
992 if (!(ItemFlags & DIF_EDITOR))
993 DialogEdit->SetPersistentBlocks(Opt.Dialogs.EditBlock);
995 DialogEdit->SetDelRemovesBlocks(Opt.Dialogs.DelRemovesBlocks);
997 if (ItemFlags & DIF_READONLY)
998 DialogEdit->SetReadOnly(1);
999 } else if (Type == DI_USERCONTROL) {
1000 if (!DialogMode.Check(DMODE_CREATEOBJECTS))
1001 CurItem->UCData = new DlgUserControl;
1004 CurItem->Flags = ItemFlags;
1007 // если будет редактор, то обязательно будет выделен.
1008 SelectOnEntry(FocusPos, TRUE);
1009 // все объекты созданы!
1010 DialogMode.Set(DMODE_CREATEOBJECTS);
1011 return FocusPos;
1014 const wchar_t *Dialog::GetDialogTitle()
1016 CriticalSectionLock Lock(CS);
1017 DialogItemEx *CurItem, *CurItemList = nullptr;
1019 for (unsigned I = 0; I < ItemCount; I++) {
1020 CurItem = Item[I];
1022 // по первому попавшемуся "тексту" установим заголовок консоли!
1023 if ((CurItem->Type == DI_TEXT || CurItem->Type == DI_DOUBLEBOX || CurItem->Type == DI_SINGLEBOX)) {
1024 const wchar_t *Ptr = CurItem->strData;
1026 for (; *Ptr; Ptr++)
1027 if (IsAlpha(*Ptr) || iswdigit(*Ptr))
1028 return (Ptr);
1029 } else if (CurItem->Type == DI_LISTBOX && !I)
1030 CurItemList = CurItem;
1033 if (CurItemList) {
1034 return CurItemList->ListPtr->GetPtrTitle();
1037 return nullptr; //""
1040 void Dialog::ProcessLastHistory(DialogItemEx *CurItem, int MsgIndex)
1042 CriticalSectionLock Lock(CS);
1043 FARString &strData = CurItem->strData;
1045 if (strData.IsEmpty()) {
1046 FARString strRegKey = fmtSavedDialogHistory;
1047 strRegKey+= CurItem->strHistory;
1048 History::ReadLastItem(strRegKey.GetMB().c_str(), strData);
1050 if (MsgIndex != -1) {
1051 // обработка DM_SETHISTORY => надо пропустить изменение текста через
1052 // диалоговую функцию
1053 FarDialogItemData IData;
1054 IData.PtrData = const_cast<wchar_t *>(strData.CPtr());
1055 IData.PtrLength = (int)strData.GetLength();
1056 SendDlgMessage(this, DM_SETTEXT, MsgIndex, (LONG_PTR)&IData);
1062 static int ToRange(int Val, int Min, int Max)
1064 return std::min(std::max(Val, Min), Max);
1067 // Изменение координат и/или размеров итема диалога.
1068 BOOL Dialog::SetItemRect(unsigned ID, SMALL_RECT *aRect)
1070 CriticalSectionLock Lock(CS);
1072 if (ID >= ItemCount)
1073 return FALSE;
1076 auto Rect = *aRect;
1077 Rect.Left = ToRange(Rect.Left, 0, X2-X1);
1078 Rect.Top = ToRange(Rect.Top, 0, Y2-Y1);
1079 Rect.Right = ToRange(Rect.Right, Rect.Left, X2-X1);
1080 Rect.Bottom = ToRange(Rect.Bottom, Rect.Top, Y2-Y1);
1082 DialogItemEx *CurItem = Item[ID];
1083 int Type = CurItem->Type;
1084 CurItem->X1 = Rect.Left;
1085 CurItem->Y1 = (Rect.Top < 0) ? 0 : Rect.Top;
1087 if (FarIsEdit(Type)) {
1088 DlgEdit *DialogEdit = (DlgEdit *)CurItem->ObjPtr;
1089 CurItem->X2 = Rect.Right;
1090 CurItem->Y2 = (Type == DI_MEMOEDIT ? Rect.Bottom : 0);
1091 DialogEdit->SetPosition(X1 + Rect.Left, Y1 + Rect.Top, X1 + Rect.Right, Y1 + Rect.Top);
1092 } else if (Type == DI_LISTBOX) {
1093 CurItem->X2 = Rect.Right;
1094 CurItem->Y2 = Rect.Bottom;
1095 CurItem->ListPtr->SetPosition(X1 + Rect.Left, Y1 + Rect.Top, X1 + Rect.Right, Y1 + Rect.Bottom);
1096 CurItem->ListPtr->SetMaxHeight(CurItem->Y2 - CurItem->Y1 + 1);
1099 switch (Type) {
1100 case DI_TEXT:
1101 CurItem->X2 = Rect.Right;
1102 CurItem->Y2 = 0; // ???
1103 break;
1104 case DI_VTEXT:
1105 CurItem->X2 = 0; // ???
1106 CurItem->Y2 = Rect.Bottom;
1107 case DI_DOUBLEBOX:
1108 case DI_SINGLEBOX:
1109 case DI_USERCONTROL:
1110 CurItem->X2 = Rect.Right;
1111 CurItem->Y2 = Rect.Bottom;
1112 break;
1115 if (DialogMode.Check(DMODE_SHOW)) {
1116 ShowDialog((unsigned)-1);
1117 ScrBuf.Flush();
1120 return TRUE;
1123 BOOL Dialog::GetItemRect(unsigned I, SMALL_RECT &Rect)
1125 CriticalSectionLock Lock(CS);
1127 if (I >= ItemCount)
1128 return FALSE;
1130 DialogItemEx *CurItem = Item[I];
1131 DWORD ItemFlags = CurItem->Flags;
1132 int Type = CurItem->Type;
1133 int Len = 0;
1134 Rect.Left = CurItem->X1;
1135 Rect.Top = CurItem->Y1;
1136 Rect.Right = CurItem->X2;
1137 Rect.Bottom = CurItem->Y2;
1139 switch (Type) {
1140 case DI_COMBOBOX:
1141 case DI_EDIT:
1142 case DI_FIXEDIT:
1143 case DI_PSWEDIT:
1144 case DI_LISTBOX:
1145 case DI_MEMOEDIT:
1146 break;
1147 default:
1148 Len = ((ItemFlags & DIF_SHOWAMPERSAND)
1149 ? (int)CurItem->strData.CellsCount()
1150 : HiStrCellsCount(CurItem->strData));
1151 break;
1154 switch (Type) {
1155 case DI_TEXT:
1157 if (CurItem->X1 == -1)
1158 Rect.Left = (X2 - X1 + 1 - Len) / 2;
1160 if (Rect.Left < 0)
1161 Rect.Left = 0;
1163 if (CurItem->Y1 == -1)
1164 Rect.Top = (Y2 - Y1 + 1) / 2;
1166 if (Rect.Top < 0)
1167 Rect.Top = 0;
1169 Rect.Bottom = Rect.Top;
1171 if (!Rect.Right || Rect.Right == Rect.Left)
1172 Rect.Right = Rect.Left + Len - (Len ? 1 : 0);
1174 if (ItemFlags & (DIF_SEPARATOR | DIF_SEPARATOR2)) {
1175 Rect.Bottom = Rect.Top;
1176 Rect.Left = (!DialogMode.Check(DMODE_SMALLDIALOG) ? 3 : 0); //???
1177 Rect.Right = X2 - X1 - (!DialogMode.Check(DMODE_SMALLDIALOG) ? 5 : 0); //???
1180 break;
1181 case DI_VTEXT:
1183 if (CurItem->X1 == -1)
1184 Rect.Left = (X2 - X1 + 1) / 2;
1186 if (Rect.Left < 0)
1187 Rect.Left = 0;
1189 if (CurItem->Y1 == -1)
1190 Rect.Top = (Y2 - Y1 + 1 - Len) / 2;
1192 if (Rect.Top < 0)
1193 Rect.Top = 0;
1195 Rect.Right = Rect.Left;
1197 // Rect.bottom=Rect.top+Len;
1198 if (!Rect.Bottom || Rect.Bottom == Rect.Top)
1199 Rect.Bottom = Rect.Top + Len - (Len ? 1 : 0);
1201 #if defined(VTEXT_ADN_SEPARATORS)
1203 if (ItemFlags & (DIF_SEPARATOR | DIF_SEPARATOR2)) {
1204 Rect.Right = Rect.Left;
1205 Rect.Top = (!DialogMode.Check(DMODE_SMALLDIALOG) ? 1 : 0); //???
1206 Rect.Bottom = Y2 - Y1 - (!DialogMode.Check(DMODE_SMALLDIALOG) ? 3 : 0); //???
1207 break;
1210 #endif
1211 break;
1212 case DI_BUTTON:
1213 Rect.Bottom = Rect.Top;
1214 Rect.Right = Rect.Left + Len;
1215 break;
1216 case DI_CHECKBOX:
1217 case DI_RADIOBUTTON:
1218 Rect.Bottom = Rect.Top;
1219 Rect.Right = Rect.Left + Len + ((Type == DI_CHECKBOX) ? 4 : (ItemFlags & DIF_MOVESELECT ? 3 : 4));
1220 break;
1221 case DI_COMBOBOX:
1222 case DI_EDIT:
1223 case DI_FIXEDIT:
1224 case DI_PSWEDIT:
1225 Rect.Bottom = Rect.Top;
1226 break;
1229 return TRUE;
1232 bool Dialog::ItemHasDropDownArrow(const DialogItemEx *Item)
1234 return ((!Item->strHistory.IsEmpty() && (Item->Flags & DIF_HISTORY) && Opt.Dialogs.EditHistory)
1235 || (Item->Type == DI_COMBOBOX && Item->ListPtr && Item->ListPtr->GetItemCount() > 0));
1238 //////////////////////////////////////////////////////////////////////////
1240 Private:
1241 Получение данных и удаление "редакторов"
1243 void Dialog::DeleteDialogObjects()
1245 CriticalSectionLock Lock(CS);
1246 DialogItemEx *CurItem;
1248 for (unsigned I = 0; I < ItemCount; I++) {
1249 CurItem = Item[I];
1251 switch (CurItem->Type) {
1252 case DI_EDIT:
1253 case DI_FIXEDIT:
1254 case DI_PSWEDIT:
1255 case DI_COMBOBOX:
1256 case DI_MEMOEDIT:
1258 if (CurItem->ObjPtr)
1259 delete (DlgEdit *)(CurItem->ObjPtr);
1261 case DI_LISTBOX:
1263 if ((CurItem->Type == DI_COMBOBOX || CurItem->Type == DI_LISTBOX) && CurItem->ListPtr)
1264 delete CurItem->ListPtr;
1266 break;
1267 case DI_USERCONTROL:
1269 if (CurItem->UCData)
1270 delete CurItem->UCData;
1272 break;
1275 if (CurItem->Flags & DIF_AUTOMATION)
1276 if (CurItem->AutoPtr)
1277 free(CurItem->AutoPtr);
1281 //////////////////////////////////////////////////////////////////////////
1283 Public:
1284 Сохраняет значение из полей редактирования.
1285 При установленном флаге DIF_HISTORY, сохраняет данные в реестре.
1287 void Dialog::GetDialogObjectsData()
1289 CriticalSectionLock Lock(CS);
1290 int Type;
1291 DialogItemEx *CurItem;
1293 for (unsigned I = 0; I < ItemCount; I++) {
1294 CurItem = Item[I];
1295 DWORD IFlags = CurItem->Flags;
1297 switch (Type = CurItem->Type) {
1298 case DI_MEMOEDIT:
1299 break; //????
1300 case DI_EDIT:
1301 case DI_FIXEDIT:
1302 case DI_PSWEDIT:
1303 case DI_COMBOBOX: {
1304 if (CurItem->ObjPtr) {
1305 FARString strData;
1306 DlgEdit *EditPtr = (DlgEdit *)(CurItem->ObjPtr);
1309 подготовим данные
1310 получим данные
1312 EditPtr->GetString(strData);
1314 if (ExitCode >= 0 && (IFlags & DIF_HISTORY) && !(IFlags & DIF_MANUALADDHISTORY) && // при мануале не добавляем
1315 !CurItem->strHistory.IsEmpty() && Opt.Dialogs.EditHistory) {
1316 AddToEditHistory(strData, CurItem->strHistory);
1320 $ 01.08.2000 SVS
1321 ! В History должно заносится значение (для DIF_EXPAND...) перед
1322 расширением среды!
1326 $ 05.07.2000 SVS $
1327 Проверка - этот элемент предполагает расширение переменных среды?
1328 т.к. функция GetDialogObjectsData() может вызываться самостоятельно
1329 Но надо проверить!
1333 $ 04.12.2000 SVS
1334 ! Для DI_PSWEDIT и DI_FIXEDIT обработка DIF_EDITEXPAND не нужна
1335 (DI_FIXEDIT допускается для случая если нету маски)
1338 if ((IFlags & DIF_EDITEXPAND) && Type != DI_PSWEDIT && Type != DI_FIXEDIT) {
1339 apiExpandEnvironmentStrings(strData, strData);
1340 // как бы грязный хак, нам нужно обновить строку чтоб отдавалась правильная строка
1341 // для различных DM_* после закрытия диалога, но ни в коем случае нельзя чтоб
1342 // высылался DN_EDITCHANGE для этого изменения, ибо диалог уже закрыт.
1343 EditPtr->SetCallbackState(false);
1344 EditPtr->SetString(strData);
1345 EditPtr->SetCallbackState(true);
1348 CurItem->strData = strData;
1351 break;
1353 case DI_LISTBOX:
1355 if(CurItem->ListPtr)
1357 CurItem->ListPos=CurItem->ListPtr->GetSelectPos();
1358 break;
1361 break;
1364 #if 0
1366 if ((Type == DI_COMBOBOX || Type == DI_LISTBOX) && CurItem->ListPtr && CurItem->ListItems && DlgProc == DefDlgProc)
1368 int ListPos=CurItem->ListPtr->GetSelectPos();
1370 if (ListPos < CurItem->ListItems->ItemsNumber)
1372 for (int J=0; J < CurItem->ListItems->ItemsNumber; ++J)
1373 CurItem->ListItems->Items[J].Flags&=~LIF_SELECTED;
1375 CurItem->ListItems->Items[ListPos].Flags|=LIF_SELECTED;
1379 #else
1381 if ((Type == DI_COMBOBOX || Type == DI_LISTBOX)) {
1382 CurItem->ListPos = CurItem->ListPtr ? CurItem->ListPtr->GetSelectPos() : 0;
1385 #endif
1389 // Функция формирования и запроса цветов.
1390 DWORD Dialog::CtlColorDlgItem(int ItemPos, const DialogItemEx *CurItem)
1392 CriticalSectionLock Lock(CS);
1393 const int Type = CurItem->Type;
1394 const int Focus = CurItem->Focus;
1395 const int Default = CurItem->DefaultButton;
1396 const DWORD Flags = CurItem->Flags;
1398 const bool DisabledItem = (Flags & DIF_DISABLE) != 0;
1399 DWORD Attr = 0;
1401 switch (Type) {
1402 case DI_SINGLEBOX:
1403 case DI_DOUBLEBOX: {
1404 if (Flags & DIF_SETCOLOR)
1405 Attr = Flags & DIF_COLORMASK;
1406 else {
1407 Attr = DialogMode.Check(DMODE_WARNINGSTYLE)
1408 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGBOX)
1409 : (DisabledItem ? COL_DIALOGDISABLED : COL_DIALOGBOX);
1412 Attr = MAKELONG(MAKEWORD(FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE)
1413 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGBOXTITLE)
1414 : (DisabledItem ? COL_DIALOGDISABLED
1415 : COL_DIALOGBOXTITLE)), // Title LOBYTE
1416 FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE)
1417 ? (DisabledItem ? COL_WARNDIALOGDISABLED
1418 : COL_WARNDIALOGHIGHLIGHTBOXTITLE)
1419 : (DisabledItem ? COL_DIALOGDISABLED
1420 : COL_DIALOGHIGHLIGHTBOXTITLE))), // HiText HIBYTE
1421 MAKEWORD(FarColorToReal(Attr), // Box LOBYTE
1422 0) // HIBYTE
1424 break;
1426 #if defined(VTEXT_ADN_SEPARATORS)
1427 case DI_VTEXT:
1428 #endif
1429 case DI_TEXT: {
1430 if (Flags & DIF_SETCOLOR)
1431 Attr = Flags & DIF_COLORMASK;
1432 else {
1433 if (Flags & DIF_BOXCOLOR)
1434 Attr = DialogMode.Check(DMODE_WARNINGSTYLE)
1435 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGBOX)
1436 : (DisabledItem ? COL_DIALOGDISABLED : COL_DIALOGBOX);
1437 else
1438 Attr = DialogMode.Check(DMODE_WARNINGSTYLE)
1439 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGTEXT)
1440 : (DisabledItem ? COL_DIALOGDISABLED : COL_DIALOGTEXT);
1443 Attr = MAKELONG(MAKEWORD(FarColorToReal(Attr),
1444 FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE)
1445 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGHIGHLIGHTTEXT)
1446 : (DisabledItem ? COL_DIALOGDISABLED
1447 : COL_DIALOGHIGHLIGHTTEXT) // HIBYTE HiText
1449 ((Flags & (DIF_SEPARATORUSER | DIF_SEPARATOR | DIF_SEPARATOR2)) ? (
1450 MAKEWORD(FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE)
1451 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGBOX)
1452 : (DisabledItem ? COL_DIALOGDISABLED
1453 : COL_DIALOGBOX) // Box LOBYTE
1456 : 0));
1457 break;
1459 #if !defined(VTEXT_ADN_SEPARATORS)
1460 case DI_VTEXT: {
1461 if (Flags & DIF_BOXCOLOR)
1462 Attr = DialogMode.Check(DMODE_WARNINGSTYLE)
1463 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGBOX)
1464 : (DisabledItem ? COL_DIALOGDISABLED : COL_DIALOGBOX);
1465 else if (Flags & DIF_SETCOLOR)
1466 Attr = (Flags & DIF_COLORMASK);
1467 else
1468 Attr = (DialogMode.Check(DMODE_WARNINGSTYLE)
1469 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGTEXT)
1470 : (DisabledItem ? COL_DIALOGDISABLED : COL_DIALOGTEXT));
1472 Attr = MAKEWORD(MAKEWORD(FarColorToReal(Attr), 0), MAKEWORD(0, 0));
1473 break;
1475 #endif
1476 case DI_CHECKBOX:
1477 case DI_RADIOBUTTON: {
1478 if (Flags & DIF_SETCOLOR)
1479 Attr = (Flags & DIF_COLORMASK);
1480 else
1481 Attr = (DialogMode.Check(DMODE_WARNINGSTYLE)
1482 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGTEXT)
1483 : (DisabledItem ? COL_DIALOGDISABLED : COL_DIALOGTEXT));
1485 Attr = MAKEWORD(FarColorToReal(Attr),
1486 FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE)
1487 ? (DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGHIGHLIGHTTEXT)
1488 : (DisabledItem ? COL_DIALOGDISABLED : COL_DIALOGHIGHLIGHTTEXT))); // HiText
1489 break;
1491 case DI_BUTTON: {
1492 if (Focus) {
1493 SetCursorType(0, 10);
1494 Attr = MAKEWORD((Flags & DIF_SETCOLOR)
1495 ? (Flags & DIF_COLORMASK)
1496 : FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE)
1497 ? (DisabledItem ? COL_WARNDIALOGDISABLED
1498 : (Default ? COL_WARNDIALOGSELECTEDDEFAULTBUTTON
1499 : COL_WARNDIALOGSELECTEDBUTTON))
1500 : (DisabledItem ? COL_DIALOGDISABLED
1501 : (Default ? COL_DIALOGSELECTEDDEFAULTBUTTON
1502 : COL_DIALOGSELECTEDBUTTON))), // TEXT
1503 FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE)
1504 ? (DisabledItem ? COL_WARNDIALOGDISABLED
1505 : (Default ? COL_WARNDIALOGHIGHLIGHTSELECTEDDEFAULTBUTTON
1506 : COL_WARNDIALOGHIGHLIGHTSELECTEDBUTTON))
1507 : (DisabledItem ? COL_DIALOGDISABLED
1508 : (Default ? COL_DIALOGHIGHLIGHTSELECTEDDEFAULTBUTTON
1509 : COL_DIALOGHIGHLIGHTSELECTEDBUTTON)))); // HiText
1510 } else {
1511 Attr = MAKEWORD((Flags & DIF_SETCOLOR)
1512 ? (Flags & DIF_COLORMASK)
1513 : FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE)
1514 ? (DisabledItem ? COL_WARNDIALOGDISABLED
1515 : (Default ? COL_WARNDIALOGDEFAULTBUTTON
1516 : COL_WARNDIALOGBUTTON))
1517 : (DisabledItem ? COL_DIALOGDISABLED
1518 : (Default ? COL_DIALOGDEFAULTBUTTON
1519 : COL_DIALOGBUTTON))), // TEXT
1520 FarColorToReal(DialogMode.Check(DMODE_WARNINGSTYLE)
1521 ? (DisabledItem ? COL_WARNDIALOGDISABLED
1522 : (Default ? COL_WARNDIALOGHIGHLIGHTDEFAULTBUTTON
1523 : COL_WARNDIALOGHIGHLIGHTBUTTON))
1524 : (DisabledItem ? COL_DIALOGDISABLED
1525 : (Default ? COL_DIALOGHIGHLIGHTDEFAULTBUTTON
1526 : COL_DIALOGHIGHLIGHTBUTTON)))); // HiText
1529 break;
1531 case DI_EDIT:
1532 case DI_FIXEDIT:
1533 case DI_PSWEDIT:
1534 case DI_COMBOBOX:
1535 case DI_MEMOEDIT: {
1536 if (Type == DI_COMBOBOX && (Flags & DIF_DROPDOWNLIST)) {
1537 if (DialogMode.Check(DMODE_WARNINGSTYLE))
1538 Attr = MAKELONG(MAKEWORD( // LOWORD
1539 // LOLO (Text)
1540 FarColorToReal(DisabledItem ? COL_WARNDIALOGEDITDISABLED
1541 : COL_WARNDIALOGEDIT),
1542 // LOHI (Select)
1543 FarColorToReal(DisabledItem ? COL_DIALOGEDITDISABLED
1544 : COL_DIALOGEDITSELECTED)),
1545 MAKEWORD( // HIWORD
1546 // HILO (Unchanged)
1547 FarColorToReal(DisabledItem ? COL_WARNDIALOGEDITDISABLED
1548 : COL_DIALOGEDITUNCHANGED), //???
1549 // HIHI (History)
1550 FarColorToReal(
1551 DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGTEXT)));
1552 else
1553 Attr = MAKELONG(MAKEWORD( // LOWORD
1554 // LOLO (Text)
1555 FarColorToReal(DisabledItem
1556 ? COL_DIALOGEDITDISABLED
1557 : (!Focus ? COL_DIALOGEDIT
1558 : COL_DIALOGEDITSELECTED)),
1559 // LOHI (Select)
1560 FarColorToReal(DisabledItem
1561 ? COL_DIALOGEDITDISABLED
1562 : (!Focus ? COL_DIALOGEDIT
1563 : COL_DIALOGEDITSELECTED))),
1564 MAKEWORD( // HIWORD
1565 // HILO (Unchanged)
1566 FarColorToReal(DisabledItem ? COL_DIALOGEDITDISABLED
1567 : COL_DIALOGEDITUNCHANGED), //???
1568 // HIHI (History)
1569 FarColorToReal(DisabledItem ? COL_DIALOGDISABLED : COL_DIALOGTEXT)));
1570 } else {
1571 if (DialogMode.Check(DMODE_WARNINGSTYLE))
1572 Attr = MAKELONG(MAKEWORD( // LOWORD
1573 // LOLO (Text)
1574 FarColorToReal(DisabledItem
1575 ? COL_WARNDIALOGEDITDISABLED
1576 : (Flags & DIF_NOFOCUS ? COL_DIALOGEDITUNCHANGED
1577 : COL_WARNDIALOGEDIT)),
1578 // LOHI (Select)
1579 FarColorToReal(DisabledItem ? COL_DIALOGEDITDISABLED
1580 : COL_DIALOGEDITSELECTED)),
1581 MAKEWORD( // HIWORD
1582 // HILO (Unchanged)
1583 FarColorToReal(DisabledItem ? COL_WARNDIALOGEDITDISABLED
1584 : COL_DIALOGEDITUNCHANGED), //???
1585 // HIHI (History)
1586 FarColorToReal(
1587 DisabledItem ? COL_WARNDIALOGDISABLED : COL_WARNDIALOGTEXT)));
1588 else
1589 Attr = MAKELONG(MAKEWORD( // LOWORD
1590 // LOLO (Text)
1591 FarColorToReal(DisabledItem
1592 ? COL_DIALOGEDITDISABLED
1593 : (Flags & DIF_NOFOCUS ? COL_DIALOGEDITUNCHANGED
1594 : COL_DIALOGEDIT)),
1595 // LOHI (Select)
1596 FarColorToReal(DisabledItem ? COL_DIALOGEDITDISABLED
1597 : COL_DIALOGEDITSELECTED)),
1598 MAKEWORD( // HIWORD
1599 // HILO (Unchanged)
1600 FarColorToReal(DisabledItem ? COL_DIALOGEDITDISABLED
1601 : COL_DIALOGEDITUNCHANGED), //???
1602 // HIHI (History)
1603 FarColorToReal(DisabledItem ? COL_DIALOGDISABLED : COL_DIALOGTEXT)));
1606 break;
1608 case DI_LISTBOX: {
1609 Item[ItemPos]->ListPtr->SetColors(nullptr);
1610 return 0;
1612 default: {
1613 return 0;
1617 ++InCtlColorDlgItem;
1618 DWORD out = DlgProc((HANDLE)this, DN_CTLCOLORDLGITEM, ItemPos, Attr);
1619 --InCtlColorDlgItem;
1620 return out;
1623 static void SetColorNormal(DWORD Attr, const std::unique_ptr<DialogItemTrueColors> &TrueColors)
1625 ComposeAndSetColor(Attr & 0xff, TrueColors ? &TrueColors->Normal : nullptr);
1628 static void SetColorFrame(DWORD Attr, const std::unique_ptr<DialogItemTrueColors> &TrueColors)
1630 ComposeAndSetColor(LOBYTE(HIWORD(Attr)), TrueColors ? &TrueColors->Frame : nullptr);
1634 //////////////////////////////////////////////////////////////////////////
1636 Private:
1637 Отрисовка элементов диалога на экране.
1639 void Dialog::ShowDialog(unsigned ID)
1641 CriticalSectionLock Lock(CS);
1643 if (Locked())
1644 return;
1646 FARString strStr;
1647 DialogItemEx *CurItem;
1648 int X, Y;
1649 unsigned I, DrawItemCount;
1650 DWORD Attr;
1652 // Если не разрешена отрисовка, то вываливаем.
1653 if (IsEnableRedraw || // разрешена прорисовка ?
1654 (ID + 1 > ItemCount) || // а номер в рамках дозволенного?
1655 DialogMode.Check(DMODE_DRAWING) || // диалог рисуется?
1656 !DialogMode.Check(DMODE_SHOW) || // если не видим, то и не отрисовываем.
1657 !DialogMode.Check(DMODE_INITOBJECTS))
1658 return;
1660 DialogMode.Set(DMODE_DRAWING); // диалог рисуется!!!
1661 ChangePriority ChPriority(ChangePriority::NORMAL);
1663 if (ID == (unsigned)-1) // рисуем все?
1665 // Перед прорисовкой диалога посылаем сообщение в обработчик
1666 if (!DlgProc((HANDLE)this, DN_DRAWDIALOG, 0, 0)) {
1667 DialogMode.Clear(DMODE_DRAWING); // конец отрисовки диалога!!!
1668 return;
1671 // перед прорисовкой подложки окна диалога
1672 if (!DialogMode.Check(DMODE_NODRAWSHADOW))
1673 Shadow(DialogMode.Check(DMODE_FULLSHADOW) != FALSE); // "наводим" тень
1675 if (!DialogMode.Check(DMODE_NODRAWPANEL)) {
1676 Attr = (DWORD)DlgProc((HANDLE)this, DN_CTLCOLORDIALOG, 0,
1677 DialogMode.Check(DMODE_WARNINGSTYLE) ? COL_WARNDIALOGTEXT : COL_DIALOGTEXT);
1678 SetScreen(X1, Y1, X2, Y2, L' ', Attr);
1681 ID = 0;
1682 DrawItemCount = ItemCount;
1683 } else {
1684 DrawItemCount = ID + 1;
1688 IFlags.Set(DIMODE_REDRAW)
1689 TODO:
1690 если рисуется контрол и по Z-order`у он пересекается с
1691 другим контролом (по координатам), то для "позднего"
1692 контрола тоже нужна прорисовка.
1695 bool CursorVisible = false;
1696 DWORD CursorSize = 0;
1698 if (ID != (unsigned)-1 && FocusPos != ID) {
1699 if (Item[FocusPos]->Type == DI_USERCONTROL && Item[FocusPos]->UCData->CursorPos.X != -1
1700 && Item[FocusPos]->UCData->CursorPos.Y != -1) {
1701 CursorVisible = Item[FocusPos]->UCData->CursorVisible;
1702 CursorSize = Item[FocusPos]->UCData->CursorSize;
1706 SetCursorType(CursorVisible, CursorSize);
1709 for (I = ID; I < DrawItemCount; I++) {
1710 CurItem = Item[I];
1712 if (CurItem->Flags & DIF_HIDDEN)
1713 continue;
1716 $ 28.07.2000 SVS
1717 Перед прорисовкой каждого элемента посылаем сообщение
1718 посредством функции SendDlgMessage - в ней делается все!
1720 if (!SendDlgMessage((HANDLE)this, DN_DRAWDLGITEM, I, 0))
1721 continue;
1723 int LenText;
1724 short CX1 = CurItem->X1;
1725 short CY1 = CurItem->Y1;
1726 short CX2 = CurItem->X2;
1727 short CY2 = CurItem->Y2;
1729 if (CX2 > X2 - X1)
1730 CX2 = X2 - X1;
1732 if (CY2 > Y2 - Y1)
1733 CY2 = Y2 - Y1;
1735 short CW = CX2 - CX1 + 1;
1736 short CH = CY2 - CY1 + 1;
1737 Attr = CtlColorDlgItem(I, CurItem);
1738 #if 0
1740 // TODO: прежде чем эту строку применять... нужно проверить _ВСЕ_ диалоги на предмет X2, Y2. !!!
1741 if (((CX1 > -1) && (CX2 > 0) && (CX2 > CX1)) &&
1742 ((CY1 > -1) && (CY2 > 0) && (CY2 > CY1)))
1743 SetScreen(X1+CX1,Y1+CY1,X1+CX2,Y1+CY2,' ',Attr&0xFF);
1745 #endif
1747 switch (CurItem->Type) {
1748 /* ***************************************************************** */
1749 case DI_SINGLEBOX:
1750 case DI_DOUBLEBOX: {
1751 BOOL IsDrawTitle = TRUE;
1752 GotoXY(X1 + CX1, Y1 + CY1);
1753 SetColorFrame(Attr, CurItem->TrueColors);
1755 if (CY1 == CY2) {
1756 DrawLine(CX2 - CX1 + 1, CurItem->Type == DI_SINGLEBOX ? 8 : 9); //???
1757 } else if (CX1 == CX2) {
1758 DrawLine(CY2 - CY1 + 1, CurItem->Type == DI_SINGLEBOX ? 10 : 11);
1759 IsDrawTitle = FALSE;
1760 } else {
1761 Box(X1 + CX1, Y1 + CY1, X1 + CX2, Y1 + CY2, LOBYTE(HIWORD(Attr)),
1762 (CurItem->Type == DI_SINGLEBOX) ? SINGLE_BOX : DOUBLE_BOX);
1765 if (!CurItem->strData.IsEmpty() && IsDrawTitle) {
1766 // ! Пусть диалог сам заботится о ширине собственного заголовка.
1767 strStr = CurItem->strData;
1768 TruncStrFromEnd(strStr, CW - 2); // 5 ???
1769 LenText = LenStrItem(I, strStr);
1771 if (LenText < CW - 2 && !strStr.Begins(L' ') ) {
1772 strStr.Insert(0, L' ');
1773 LenText = LenStrItem(I, strStr);
1776 if (LenText < CW - 2 && !strStr.Ends(L' ') ) { // пробел после текста заголовка и рамкой
1777 strStr.Append(L' ');
1778 LenText = LenStrItem(I, strStr);
1781 X = X1 + CX1 + (CW - LenText) / 2;
1783 if ((CurItem->Flags & DIF_LEFTTEXT) && X1 + CX1 + 1 < X)
1784 X = X1 + CX1 + 1;
1786 SetColorNormal(Attr, CurItem->TrueColors);
1787 GotoXY(X, Y1 + CY1);
1789 if (CurItem->Flags & DIF_SHOWAMPERSAND)
1790 Text(strStr);
1791 else if (CurItem->TrueColors)
1792 HiText(strStr, ComposeColor(HIBYTE(LOWORD(Attr)), &CurItem->TrueColors->Hilighted));
1793 else
1794 HiText(strStr, HIBYTE(LOWORD(Attr)));
1797 break;
1799 /* ***************************************************************** */
1800 case DI_TEXT: {
1801 strStr = CurItem->strData;
1802 LenText = LenStrItem(I, strStr);
1804 if (!(CurItem->Flags & (DIF_SEPARATORUSER | DIF_SEPARATOR | DIF_SEPARATOR2))
1805 && (CurItem->Flags & DIF_CENTERTEXT) && CX1 != -1)
1806 LenText = LenStrItem(I, CenterStr(strStr, strStr, CX2 - CX1 + 1));
1808 X = (CX1 == -1 || (CurItem->Flags & (DIF_SEPARATOR | DIF_SEPARATOR2)))
1809 ? (X2 - X1 + 1 - LenText) / 2
1810 : CX1;
1811 Y = (CY1 == -1) ? (Y2 - Y1 + 1) / 2 : CY1;
1813 if (X < 0)
1814 X = 0;
1816 if ((CX2 <= 0) || (CX2 < CX1))
1817 CW = LenText;
1819 if (X1 + X + LenText > X2) {
1820 int tmpCW = ObjWidth;
1822 if (CW < ObjWidth)
1823 tmpCW = CW + 1;
1825 strStr.TruncateByCells(tmpCW - 1);
1828 // нужно ЭТО
1829 // SetScreen(X1+CX1,Y1+CY1,X1+CX2,Y1+CY2,' ',Attr&0xFF);
1830 // вместо этого:
1831 if (CX1 > -1 && CX2 > CX1
1832 && !(CurItem->Flags & (DIF_SEPARATORUSER | DIF_SEPARATOR | DIF_SEPARATOR2))) { // половинчатое решение
1834 int CntChr = CX2 - CX1 + 1;
1835 SetColorNormal(Attr, CurItem->TrueColors);
1836 GotoXY(X1 + X, Y1 + Y);
1838 if (X1 + X + CntChr - 1 > X2)
1839 CntChr = X2 - (X1 + X) + 1;
1841 FS << fmt::Cells() << fmt::Expand(CntChr) << L"";
1843 if (CntChr < LenText)
1844 strStr.TruncateByCells(CntChr);
1847 if (CurItem->Flags & (DIF_SEPARATORUSER | DIF_SEPARATOR | DIF_SEPARATOR2)) {
1848 SetColorFrame(Attr, CurItem->TrueColors);
1849 GotoXY(X1
1850 + ((CurItem->Flags & DIF_SEPARATORUSER)
1852 : (!DialogMode.Check(DMODE_SMALLDIALOG) ? 3 : 0)),
1853 Y1 + Y); //????
1854 ShowUserSeparator((CurItem->Flags & DIF_SEPARATORUSER)
1855 ? X2 - X1 + 1
1856 : RealWidth - (!DialogMode.Check(DMODE_SMALLDIALOG) ? 6 : 0 /* -1 */),
1857 (CurItem->Flags & DIF_SEPARATORUSER)
1858 ? 12
1859 : (CurItem->Flags & DIF_SEPARATOR2 ? 3 : 1),
1860 CurItem->strMask);
1863 SetColorNormal(Attr, CurItem->TrueColors);
1864 GotoXY(X1 + X, Y1 + Y);
1866 if (CurItem->Flags & DIF_SHOWAMPERSAND) {
1867 // MessageBox(0, strStr, strStr, MB_OK);
1868 Text(strStr);
1869 } else {
1870 // MessageBox(0, strStr, strStr, MB_OK);
1871 HiText(strStr, HIBYTE(LOWORD(Attr)));
1874 break;
1876 /* ***************************************************************** */
1877 case DI_VTEXT: {
1878 strStr = CurItem->strData;
1879 LenText = LenStrItem(I, strStr);
1881 if (!(CurItem->Flags & (DIF_SEPARATORUSER | DIF_SEPARATOR | DIF_SEPARATOR2))
1882 && (CurItem->Flags & DIF_CENTERTEXT) && CY1 != -1)
1883 LenText = StrLength(CenterStr(strStr, strStr, CY2 - CY1 + 1));
1885 X = (CX1 == -1) ? (X2 - X1 + 1) / 2 : CX1;
1886 Y = (CY1 == -1 || (CurItem->Flags & (DIF_SEPARATOR | DIF_SEPARATOR2)))
1887 ? (Y2 - Y1 + 1 - LenText) / 2
1888 : CY1;
1890 if (Y < 0)
1891 Y = 0;
1893 if ((CY2 <= 0) || (CY2 < CY1))
1894 CH = LenStrItem(I, strStr);
1896 if (Y1 + Y + LenText > Y2) {
1897 int tmpCH = ObjHeight;
1899 if (CH < ObjHeight)
1900 tmpCH = CH + 1;
1902 strStr.TruncateByCells(tmpCH - 1);
1905 // нужно ЭТО
1906 // SetScreen(X1+CX1,Y1+CY1,X1+CX2,Y1+CY2,' ',Attr&0xFF);
1907 // вместо этого:
1908 if (CY1 > -1 && CY2 > 0 && CY2 > CY1
1909 && !(CurItem->Flags & (DIF_SEPARATORUSER | DIF_SEPARATOR | DIF_SEPARATOR2))) { // половинчатое решение
1911 int CntChr = CY2 - CY1 + 1;
1912 SetColorNormal(Attr, CurItem->TrueColors);
1913 GotoXY(X1 + X, Y1 + Y);
1915 if (Y1 + Y + CntChr - 1 > Y2)
1916 CntChr = Y2 - (Y1 + Y) + 1;
1918 vmprintf(L"%*ls", CntChr, L"");
1921 #if defined(VTEXT_ADN_SEPARATORS)
1923 if (CurItem->Flags & (DIF_SEPARATORUSER | DIF_SEPARATOR | DIF_SEPARATOR2)) {
1924 SetColorFrame(Attr, CurItem->TrueColors);
1925 GotoXY(X1 + X,
1927 + ((CurItem->Flags & DIF_SEPARATORUSER)
1929 : (!DialogMode.Check(DMODE_SMALLDIALOG) ? 1 : 0))); //????
1930 ShowUserSeparator((CurItem->Flags & DIF_SEPARATORUSER)
1931 ? Y2 - Y1 + 1
1932 : RealHeight - (!DialogMode.Check(DMODE_SMALLDIALOG) ? 2 : 0),
1933 (CurItem->Flags & DIF_SEPARATORUSER)
1934 ? 13
1935 : (CurItem->Flags & DIF_SEPARATOR2 ? 7 : 5),
1936 CurItem->strMask);
1939 #endif
1940 SetColorNormal(Attr, CurItem->TrueColors);
1941 GotoXY(X1 + X, Y1 + Y);
1943 if (CurItem->Flags & DIF_SHOWAMPERSAND)
1944 VText(strStr);
1945 else
1946 HiText(strStr, HIBYTE(LOWORD(Attr)), TRUE);
1948 break;
1950 /* ***************************************************************** */
1951 case DI_CHECKBOX:
1952 case DI_RADIOBUTTON: {
1953 SetColorNormal(Attr, CurItem->TrueColors);
1954 GotoXY(X1 + CX1, Y1 + CY1);
1956 if (CurItem->Type == DI_CHECKBOX) {
1957 const wchar_t Check[] = {L'[',
1958 (CurItem->Selected ? (((CurItem->Flags & DIF_3STATE) && CurItem->Selected == 2)
1959 ? *Msg::CheckBox2State
1960 : L'x')
1961 : L' '),
1962 L']', L'\0'};
1963 strStr = Check;
1965 if (CurItem->strData.GetLength())
1966 strStr+= L" ";
1967 } else {
1968 wchar_t Dot[] = {L' ', CurItem->Selected ? L'\x2022' : L' ', L' ', L'\0'};
1970 if (CurItem->Flags & DIF_MOVESELECT) {
1971 strStr = Dot;
1972 } else {
1973 Dot[0] = L'(';
1974 Dot[2] = L')';
1975 strStr = Dot;
1977 if (CurItem->strData.GetLength())
1978 strStr+= L" ";
1982 strStr+= CurItem->strData;
1983 LenText = LenStrItem(I, strStr);
1985 if (X1 + CX1 + LenText > X2)
1986 strStr.TruncateByCells(ObjWidth - 1);
1988 if (CurItem->Flags & DIF_SHOWAMPERSAND)
1989 Text(strStr);
1990 else
1991 HiText(strStr, HIBYTE(LOWORD(Attr)));
1993 if (CurItem->Focus) {
1994 // Отключение мигающего курсора при перемещении диалога
1995 if (!DialogMode.Check(DMODE_DRAGGED))
1996 SetCursorType(1, -1);
1998 MoveCursor(X1 + CX1 + 1, Y1 + CY1);
2001 break;
2003 /* ***************************************************************** */
2004 case DI_BUTTON: {
2005 strStr = CurItem->strData;
2006 SetColorNormal(Attr, CurItem->TrueColors);
2007 GotoXY(X1 + CX1, Y1 + CY1);
2009 if (CurItem->Flags & DIF_SHOWAMPERSAND)
2010 Text(strStr);
2011 else
2012 HiText(strStr, HIBYTE(LOWORD(Attr)));
2014 if (CurItem->Flags & DIF_SETSHIELD) {
2015 int startx = X1 + CX1 + (CurItem->Flags & DIF_NOBRACKETS ? 0 : 2);
2016 ScrBuf.ApplyColor(startx, Y1 + CY1, startx + 1, Y1 + CY1, 0xE9);
2018 break;
2020 /* ***************************************************************** */
2021 case DI_EDIT:
2022 case DI_FIXEDIT:
2023 case DI_PSWEDIT:
2024 case DI_COMBOBOX:
2025 case DI_MEMOEDIT: {
2026 DlgEdit *EditPtr = (DlgEdit *)(CurItem->ObjPtr);
2028 if (!EditPtr)
2029 break;
2031 EditPtr->SetObjectColor(Attr & 0xFF, HIBYTE(LOWORD(Attr)), LOBYTE(HIWORD(Attr)));
2033 if (CurItem->Focus) {
2034 // Отключение мигающего курсора при перемещении диалога
2035 if (!DialogMode.Check(DMODE_DRAGGED))
2036 SetCursorType(1, -1);
2038 EditPtr->Show();
2039 } else {
2040 EditPtr->FastShow();
2041 EditPtr->SetLeftPos(0);
2044 // Отключение мигающего курсора при перемещении диалога
2045 if (DialogMode.Check(DMODE_DRAGGED))
2046 SetCursorType(0, 0);
2048 if (ItemHasDropDownArrow(CurItem)) {
2049 int EditX1, EditY1, EditX2, EditY2;
2050 EditPtr->GetPosition(EditX1, EditY1, EditX2, EditY2);
2051 // Text((CurItem->Type == DI_COMBOBOX?"\x1F":"\x19"));
2052 Text(EditX2 + 1, EditY1, HIBYTE(HIWORD(Attr)), L"\x2193");
2055 if (CurItem->Type == DI_COMBOBOX && GetDropDownOpened() && CurItem->ListPtr->IsVisible()) // need redraw VMenu?
2057 CurItem->ListPtr->Hide();
2058 CurItem->ListPtr->Show();
2061 break;
2063 /* ***************************************************************** */
2064 case DI_LISTBOX: {
2065 if (CurItem->ListPtr) {
2066 // Перед отрисовкой спросим об изменении цветовых атрибутов
2067 BYTE RealColors[VMENU_COLOR_COUNT];
2068 FarListColors ListColors = {0};
2069 ListColors.ColorCount = VMENU_COLOR_COUNT;
2070 ListColors.Colors = RealColors;
2071 CurItem->ListPtr->GetColors(&ListColors);
2073 if (DlgProc((HANDLE)this, DN_CTLCOLORDLGLIST, I, (LONG_PTR)&ListColors))
2074 CurItem->ListPtr->SetColors(&ListColors);
2076 // Курсор запоминаем...
2077 bool CursorVisible = false;
2078 DWORD CursorSize = 0;
2079 GetCursorType(CursorVisible, CursorSize);
2080 CurItem->ListPtr->Show();
2082 // .. а теперь восстановим!
2083 if (FocusPos != I)
2084 SetCursorType(CursorVisible, CursorSize);
2087 break;
2089 /* 01.08.2000 SVS $ */
2090 /* ***************************************************************** */
2091 case DI_USERCONTROL:
2093 if (CurItem->VBuf) {
2094 PutText(X1 + CX1, Y1 + CY1, X1 + CX2, Y1 + CY2, CurItem->VBuf);
2096 // не забудем переместить курсор, если он позиционирован.
2097 if (FocusPos == I) {
2098 if (CurItem->UCData->CursorPos.X != -1 && CurItem->UCData->CursorPos.Y != -1) {
2099 MoveCursor(CurItem->UCData->CursorPos.X + CX1 + X1,
2100 CurItem->UCData->CursorPos.Y + CY1 + Y1);
2101 SetCursorType(CurItem->UCData->CursorVisible, CurItem->UCData->CursorSize);
2102 } else
2103 SetCursorType(0, -1);
2107 break; // уже наприсовали :-)))
2108 /* ***************************************************************** */
2109 //.........
2110 } // end switch(...
2111 } // end for (I=...
2113 // КОСТЫЛЬ!
2114 // но работает ;-)
2115 for (I = 0; I < ItemCount; I++) {
2116 CurItem = Item[I];
2118 if (CurItem->ListPtr && GetDropDownOpened() && CurItem->ListPtr->IsVisible()) {
2119 if ((CurItem->Type == DI_COMBOBOX)
2120 || ((CurItem->Type == DI_EDIT || CurItem->Type == DI_FIXEDIT)
2121 && !(CurItem->Flags & DIF_HIDDEN) && (CurItem->Flags & DIF_HISTORY))) {
2122 CurItem->ListPtr->Show();
2127 // Включим индикатор перемещения...
2128 if (!DialogMode.Check(DMODE_DRAGGED)) // если диалог таскается
2131 $ 03.06.2001 KM
2132 + При каждой перерисовке диалога, кроме режима перемещения, устанавливаем
2133 заголовок консоли, в противном случае он не всегда восстанавливался.
2135 if (!DialogMode.Check(DMODE_KEEPCONSOLETITLE))
2136 ConsoleTitle::SetFarTitle(GetDialogTitle());
2139 DialogMode.Clear(DMODE_DRAWING); // конец отрисовки диалога!!!
2140 DialogMode.Set(DMODE_SHOW); // диалог на экране!
2142 if (DialogMode.Check(DMODE_DRAGGED)) {
2144 - BugZ#813 - DM_RESIZEDIALOG в DN_DRAWDIALOG -> проблема: Ctrl-F5 - отрисовка только полозьев.
2145 Убираем вызов плагиновго обработчика.
2147 // DlgProc((HANDLE)this,DN_DRAWDIALOGDONE,1,0);
2148 DefDlgProc((HANDLE)this, DN_DRAWDIALOGDONE, 1, 0);
2149 } else
2150 DlgProc((HANDLE)this, DN_DRAWDIALOGDONE, 0, 0);
2153 int Dialog::LenStrItem(int ID, const wchar_t *lpwszStr)
2155 CriticalSectionLock Lock(CS);
2157 if (!lpwszStr)
2158 lpwszStr = Item[ID]->strData;
2160 return (Item[ID]->Flags & DIF_SHOWAMPERSAND) ? StrZCellsCount(lpwszStr) : HiStrCellsCount(lpwszStr);
2163 int Dialog::ProcessMoveDialog(DWORD Key)
2165 CriticalSectionLock Lock(CS);
2167 if (DialogMode.Check(DMODE_DRAGGED)) // если диалог таскается
2170 TODO: Здесь проверить "уже здесь" и не делать лишних движений
2171 Т.е., если нажали End, то при следующем End ненужно ничего делать! - сравнить координаты !!!
2173 int rr = 1;
2175 // При перемещении диалога повторяем поведение "бормандовых" сред.
2176 switch (Key) {
2177 case KEY_CTRLLEFT:
2178 case KEY_CTRLNUMPAD4:
2179 case KEY_CTRLHOME:
2180 case KEY_CTRLNUMPAD7:
2181 case KEY_HOME:
2182 case KEY_NUMPAD7:
2183 rr = Key == KEY_CTRLLEFT || Key == KEY_CTRLNUMPAD4 ? 10 : X1;
2184 case KEY_LEFT:
2185 case KEY_NUMPAD4:
2186 Hide();
2188 for (int i = 0; i < rr; i++)
2189 if (X2 > 0) {
2190 X1--;
2191 X2--;
2192 AdjustEditPos(-1, 0);
2195 if (!DialogMode.Check(DMODE_ALTDRAGGED))
2196 Show();
2198 break;
2199 case KEY_CTRLRIGHT:
2200 case KEY_CTRLNUMPAD6:
2201 case KEY_CTRLEND:
2202 case KEY_CTRLNUMPAD1:
2203 case KEY_END:
2204 case KEY_NUMPAD1:
2205 rr = Key == KEY_CTRLRIGHT || Key == KEY_CTRLNUMPAD6 ? 10 : Max(0, ScrX - X2);
2206 case KEY_RIGHT:
2207 case KEY_NUMPAD6:
2208 Hide();
2210 for (int i = 0; i < rr; i++)
2211 if (X1 < ScrX) {
2212 X1++;
2213 X2++;
2214 AdjustEditPos(1, 0);
2217 if (!DialogMode.Check(DMODE_ALTDRAGGED))
2218 Show();
2220 break;
2221 case KEY_PGUP:
2222 case KEY_NUMPAD9:
2223 case KEY_CTRLPGUP:
2224 case KEY_CTRLNUMPAD9:
2225 case KEY_CTRLUP:
2226 case KEY_CTRLNUMPAD8:
2227 rr = Key == KEY_CTRLUP || Key == KEY_CTRLNUMPAD8 ? 5 : Y1;
2228 case KEY_UP:
2229 case KEY_NUMPAD8:
2230 Hide();
2232 for (int i = 0; i < rr; i++)
2233 if (Y2 > 0) {
2234 Y1--;
2235 Y2--;
2236 AdjustEditPos(0, -1);
2239 if (!DialogMode.Check(DMODE_ALTDRAGGED))
2240 Show();
2242 break;
2243 case KEY_CTRLDOWN:
2244 case KEY_CTRLNUMPAD2:
2245 case KEY_CTRLPGDN:
2246 case KEY_CTRLNUMPAD3:
2247 case KEY_PGDN:
2248 case KEY_NUMPAD3:
2249 rr = Key == KEY_CTRLDOWN || Key == KEY_CTRLNUMPAD2 ? 5 : Max(0, ScrY - Y2);
2250 case KEY_DOWN:
2251 case KEY_NUMPAD2:
2252 Hide();
2254 for (int i = 0; i < rr; i++)
2255 if (Y1 < ScrY) {
2256 Y1++;
2257 Y2++;
2258 AdjustEditPos(0, 1);
2261 if (!DialogMode.Check(DMODE_ALTDRAGGED))
2262 Show();
2264 break;
2265 case KEY_NUMENTER:
2266 case KEY_ENTER:
2267 case KEY_CTRLF5:
2268 DialogMode.Clear(DMODE_DRAGGED); // закончим движение!
2270 if (!DialogMode.Check(DMODE_ALTDRAGGED)) {
2271 DlgProc((HANDLE)this, DN_DRAGGED, 1, 0);
2272 Show();
2275 break;
2276 case KEY_ESC:
2277 Hide();
2278 AdjustEditPos(OldX1 - X1, OldY1 - Y1);
2279 X1 = OldX1;
2280 X2 = OldX2;
2281 Y1 = OldY1;
2282 Y2 = OldY2;
2283 DialogMode.Clear(DMODE_DRAGGED);
2285 if (!DialogMode.Check(DMODE_ALTDRAGGED)) {
2286 DlgProc((HANDLE)this, DN_DRAGGED, 1, TRUE);
2287 Show();
2290 break;
2293 if (DialogMode.Check(DMODE_ALTDRAGGED)) {
2294 DialogMode.Clear(DMODE_DRAGGED | DMODE_ALTDRAGGED);
2295 DlgProc((HANDLE)this, DN_DRAGGED, 1, 0);
2296 Show();
2299 return (TRUE);
2302 if (Key == KEY_CTRLF5 && DialogMode.Check(DMODE_ISCANMOVE)) {
2303 if (DlgProc((HANDLE)this, DN_DRAGGED, 0, 0)) // если разрешили перемещать!
2305 // включаем флаг и запоминаем координаты
2306 DialogMode.Set(DMODE_DRAGGED);
2307 OldX1 = X1;
2308 OldX2 = X2;
2309 OldY1 = Y1;
2310 OldY2 = Y2;
2311 // # GetText(0,0,3,0,LV);
2312 Show();
2315 return (TRUE);
2318 return (FALSE);
2321 int64_t Dialog::VMProcess(MacroOpcode OpCode, void *vParam, int64_t iParam)
2323 switch (OpCode) {
2324 case MCODE_F_MENU_CHECKHOTKEY:
2325 case MCODE_F_MENU_GETHOTKEY:
2326 case MCODE_F_MENU_SELECT:
2327 case MCODE_F_MENU_GETVALUE:
2328 case MCODE_F_MENU_ITEMSTATUS:
2329 case MCODE_V_MENU_VALUE: {
2330 const wchar_t *str = (const wchar_t *)vParam;
2332 if (GetDropDownOpened() || Item[FocusPos]->Type == DI_LISTBOX) {
2333 if (Item[FocusPos]->ListPtr)
2334 return Item[FocusPos]->ListPtr->VMProcess(OpCode, vParam, iParam);
2335 } else if (OpCode == MCODE_F_MENU_CHECKHOTKEY)
2336 return (int64_t)(CheckHighlights(*str, (int)iParam) + 1);
2338 return 0;
2342 switch (OpCode) {
2343 case MCODE_C_EOF:
2344 case MCODE_C_BOF:
2345 case MCODE_C_SELECTED:
2346 case MCODE_C_EMPTY: {
2347 if (FarIsEdit(Item[FocusPos]->Type)) {
2348 if (Item[FocusPos]->Type == DI_COMBOBOX && GetDropDownOpened())
2349 return Item[FocusPos]->ListPtr->VMProcess(OpCode, vParam, iParam);
2350 else
2351 return ((DlgEdit *)(Item[FocusPos]->ObjPtr))->VMProcess(OpCode, vParam, iParam);
2352 } else if (Item[FocusPos]->Type == DI_LISTBOX && OpCode != MCODE_C_SELECTED)
2353 return Item[FocusPos]->ListPtr->VMProcess(OpCode, vParam, iParam);
2355 return 0;
2357 case MCODE_V_DLGITEMTYPE: {
2358 switch (Item[FocusPos]->Type) {
2359 case DI_BUTTON:
2360 return 7; // Кнопка (Push Button).
2361 case DI_CHECKBOX:
2362 return 8; // Контрольный переключатель (Check Box).
2363 case DI_COMBOBOX:
2364 return (DropDownOpened ? 0x800A : 10); // Комбинированный список.
2365 case DI_DOUBLEBOX:
2366 return 3; // Двойная рамка.
2367 case DI_EDIT:
2368 return DropDownOpened ? 0x8004 : 4; // Поле ввода.
2369 case DI_FIXEDIT:
2370 return 6; // Поле ввода фиксированного размера.
2371 case DI_LISTBOX:
2372 return 11; // Окно списка.
2373 case DI_PSWEDIT:
2374 return 5; // Поле ввода пароля.
2375 case DI_RADIOBUTTON:
2376 return 9; // Селекторная кнопка (Radio Button).
2377 case DI_SINGLEBOX:
2378 return 2; // Одиночная рамка.
2379 case DI_TEXT:
2380 return 0; // Текстовая строка.
2381 case DI_USERCONTROL:
2382 return 255; // Элемент управления, определяемый программистом.
2383 case DI_VTEXT:
2384 return 1; // Вертикальная текстовая строка.
2387 return -1;
2389 case MCODE_V_DLGITEMCOUNT: // Dlg.ItemCount
2391 return ItemCount;
2393 case MCODE_V_DLGCURPOS: // Dlg.CurPos
2395 return FocusPos + 1;
2397 case MCODE_V_DLGINFOID: // Dlg.Info.Id
2399 static FARString strId;
2400 strId.Format(L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", Id.Data1, Id.Data2, Id.Data3,
2401 Id.Data4[0], Id.Data4[1], Id.Data4[2], Id.Data4[3], Id.Data4[4], Id.Data4[5], Id.Data4[6],
2402 Id.Data4[7]);
2403 return reinterpret_cast<INT64>(strId.CPtr());
2405 case MCODE_V_ITEMCOUNT:
2406 case MCODE_V_CURPOS: {
2407 switch (Item[FocusPos]->Type) {
2408 case DI_COMBOBOX:
2410 if (DropDownOpened || (Item[FocusPos]->Flags & DIF_DROPDOWNLIST))
2411 return Item[FocusPos]->ListPtr->VMProcess(OpCode, vParam, iParam);
2413 case DI_EDIT:
2414 case DI_PSWEDIT:
2415 case DI_FIXEDIT:
2416 return ((DlgEdit *)(Item[FocusPos]->ObjPtr))->VMProcess(OpCode, vParam, iParam);
2417 case DI_LISTBOX:
2418 return Item[FocusPos]->ListPtr->VMProcess(OpCode, vParam, iParam);
2419 case DI_USERCONTROL:
2421 if (OpCode == MCODE_V_CURPOS)
2422 return Item[FocusPos]->UCData->CursorPos.X;
2424 case DI_BUTTON:
2425 case DI_CHECKBOX:
2426 case DI_RADIOBUTTON:
2427 return 0;
2430 return 0;
2432 case MCODE_F_EDITOR_SEL: {
2433 if (FarIsEdit(Item[FocusPos]->Type)
2434 || (Item[FocusPos]->Type == DI_COMBOBOX
2435 && !(DropDownOpened || (Item[FocusPos]->Flags & DIF_DROPDOWNLIST)))) {
2436 return ((DlgEdit *)(Item[FocusPos]->ObjPtr))->VMProcess(OpCode, vParam, iParam);
2439 return 0;
2443 return 0;
2446 //////////////////////////////////////////////////////////////////////////
2448 Public, Virtual:
2449 Обработка данных от клавиатуры.
2450 Перекрывает BaseInput::ProcessKey.
2452 int Dialog::ProcessKey(FarKey Key)
2454 CriticalSectionLock Lock(CS);
2455 _DIALOG(CleverSysLog CL(L"Dialog::ProcessKey"));
2456 _DIALOG(SysLog(L"Param: Key=%ls", _FARKEY_ToName(Key)));
2457 unsigned I;
2458 FARString strStr;
2460 if (Key == KEY_NONE || Key == KEY_IDLE) {
2461 DlgProc((HANDLE)this, DN_ENTERIDLE, 0, 0); // $ 28.07.2000 SVS Передадим этот факт в обработчик :-)
2462 return FALSE;
2465 if (Key == KEY_KILLFOCUS || Key == KEY_GOTFOCUS) {
2466 DlgProc((HANDLE)this, DN_ACTIVATEAPP, Key == KEY_KILLFOCUS ? FALSE : TRUE, 0);
2467 return FALSE;
2470 if (ProcessMoveDialog(Key))
2471 return TRUE;
2473 // BugZ#488 - Shift=enter
2474 if (ShiftPressed && (Key == KEY_ENTER || Key == KEY_NUMENTER) && !CtrlObject->Macro.IsExecuting()
2475 && Item[FocusPos]->Type != DI_BUTTON) {
2476 Key = Key == KEY_ENTER ? KEY_SHIFTENTER : KEY_SHIFTNUMENTER;
2479 if (!(
2480 /*(Key>=KEY_MACRO_BASE && Key <=KEY_MACRO_ENDBASE) ||*/
2481 ((unsigned int)Key >= KEY_OP_BASE && (unsigned int)Key <= KEY_OP_ENDBASE))
2482 && !DialogMode.Check(DMODE_KEY))
2483 if (DlgProc((HANDLE)this, DN_KEY, FocusPos, Key))
2484 return TRUE;
2486 if (!DialogMode.Check(DMODE_SHOW))
2487 return TRUE;
2489 // А ХЗ, может в этот момент изменилось состояние элемента!
2490 if (Item[FocusPos]->Flags & DIF_HIDDEN)
2491 return TRUE;
2493 // небольшая оптимизация
2494 if (Item[FocusPos]->Type == DI_CHECKBOX) {
2495 if (!(Item[FocusPos]->Flags & DIF_3STATE)) {
2496 if (Key == KEY_MULTIPLY) // в CheckBox 2-state Gray* не работает!
2497 Key = KEY_NONE;
2499 if ((Key == KEY_ADD && !Item[FocusPos]->Selected)
2500 || (Key == KEY_SUBTRACT && Item[FocusPos]->Selected))
2501 Key = KEY_SPACE;
2504 // блок else не нужен, т.к. ниже клавиши будут обработаны...
2505 } else if (Key == KEY_ADD)
2506 Key = '+';
2507 else if (Key == KEY_SUBTRACT)
2508 Key = '-';
2509 else if (Key == KEY_MULTIPLY)
2510 Key = '*';
2512 if (Item[FocusPos]->Type == DI_BUTTON && Key == KEY_SPACE)
2513 Key = KEY_ENTER;
2515 if (Item[FocusPos]->Type == DI_LISTBOX) {
2516 switch (Key) {
2517 case KEY_HOME:
2518 case KEY_NUMPAD7:
2519 case KEY_LEFT:
2520 case KEY_NUMPAD4:
2521 case KEY_END:
2522 case KEY_NUMPAD1:
2523 case KEY_RIGHT:
2524 case KEY_NUMPAD6:
2525 case KEY_UP:
2526 case KEY_NUMPAD8:
2527 case KEY_DOWN:
2528 case KEY_NUMPAD2:
2529 case KEY_PGUP:
2530 case KEY_NUMPAD9:
2531 case KEY_PGDN:
2532 case KEY_NUMPAD3:
2533 case KEY_MSWHEEL_UP:
2534 case KEY_MSWHEEL_DOWN:
2535 case KEY_MSWHEEL_LEFT:
2536 case KEY_MSWHEEL_RIGHT:
2537 case KEY_NUMENTER:
2538 case KEY_ENTER:
2539 VMenu *List = Item[FocusPos]->ListPtr;
2540 int CurListPos = List->GetSelectPos();
2541 auto CheckedListItem = List->GetCheck(-1);
2542 List->ProcessKey(Key);
2543 int NewListPos = List->GetSelectPos();
2545 if (NewListPos != CurListPos && !DlgProc((HANDLE)this, DN_LISTCHANGE, FocusPos, NewListPos)) {
2546 if (!DialogMode.Check(DMODE_SHOW))
2547 return TRUE;
2549 List->SetCheck(CheckedListItem, CurListPos);
2551 if (DialogMode.Check(DMODE_SHOW) && !(Item[FocusPos]->Flags & DIF_HIDDEN))
2552 ShowDialog(FocusPos); // FocusPos
2555 if (!(Key == KEY_ENTER || Key == KEY_NUMENTER) || (Item[FocusPos]->Flags & DIF_LISTNOCLOSE))
2556 return TRUE;
2560 switch (Key) {
2561 case KEY_F1:
2564 Перед выводом диалога посылаем сообщение в обработчик
2565 и если вернули что надо, то выводим подсказку
2567 if (!Help::MkTopic(PluginNumber,
2568 (const wchar_t *)DlgProc((HANDLE)this, DN_HELP, FocusPos,
2569 (HelpTopic ? (LONG_PTR)HelpTopic : 0)),
2570 strStr)
2571 .IsEmpty()) {
2572 Help::Present(strStr);
2575 return TRUE;
2576 case KEY_ESC:
2577 case KEY_BREAK:
2578 case KEY_F10:
2579 ExitCode = (Key == KEY_BREAK) ? -2 : -1;
2580 CloseDialog();
2581 return TRUE;
2582 case KEY_HOME:
2583 case KEY_NUMPAD7:
2585 if (Item[FocusPos]->Type == DI_USERCONTROL) // для user-типа вываливаем
2586 return TRUE;
2588 return Do_ProcessFirstCtrl();
2589 case KEY_TAB:
2590 case KEY_SHIFTTAB:
2591 return Do_ProcessTab(Key == KEY_TAB);
2592 case KEY_SPACE:
2593 return Do_ProcessSpace();
2594 case KEY_CTRLNUMENTER:
2595 case KEY_CTRLENTER: {
2596 for (I = 0; I < ItemCount; I++)
2597 if (Item[I]->DefaultButton) {
2598 if (Item[I]->Flags & DIF_DISABLE) {
2599 // ProcessKey(KEY_DOWN); // на твой вкус :-)
2600 return TRUE;
2603 if (!FarIsEdit(Item[I]->Type))
2604 Item[I]->Selected = 1;
2606 ExitCode = I;
2607 /* $ 18.05.2001 DJ */
2608 CloseDialog();
2609 /* DJ $ */
2610 return TRUE;
2613 if (!DialogMode.Check(DMODE_OLDSTYLE)) {
2614 DialogMode.Clear(DMODE_ENDLOOP); // только если есть
2615 return TRUE; // делать больше не чего
2618 case KEY_NUMENTER:
2619 case KEY_ENTER: {
2620 if (Item[FocusPos]->Type != DI_COMBOBOX && FarIsEdit(Item[FocusPos]->Type)
2621 && (Item[FocusPos]->Flags & DIF_EDITOR) && !(Item[FocusPos]->Flags & DIF_READONLY)) {
2622 unsigned EditorLastPos;
2624 for (EditorLastPos = I = FocusPos; I < ItemCount; I++)
2625 if (FarIsEdit(Item[I]->Type) && (Item[I]->Flags & DIF_EDITOR))
2626 EditorLastPos = I;
2627 else
2628 break;
2630 if (((DlgEdit *)(Item[EditorLastPos]->ObjPtr))->GetLength())
2631 return TRUE;
2633 for (I = EditorLastPos; I > FocusPos; I--) {
2634 int CurPos;
2636 if (I == FocusPos + 1)
2637 CurPos = ((DlgEdit *)(Item[I - 1]->ObjPtr))->GetCurPos();
2638 else
2639 CurPos = 0;
2641 ((DlgEdit *)(Item[I - 1]->ObjPtr))->GetString(strStr);
2642 int Length = (int)strStr.GetLength();
2643 ((DlgEdit *)(Item[I]->ObjPtr))
2644 ->SetString(CurPos >= Length ? L"" : strStr.CPtr() + CurPos);
2646 if (CurPos < Length)
2647 strStr.Truncate(CurPos);
2649 ((DlgEdit *)(Item[I]->ObjPtr))->SetCurPos(0);
2650 ((DlgEdit *)(Item[I - 1]->ObjPtr))->SetString(strStr);
2653 if (EditorLastPos > FocusPos) {
2654 ((DlgEdit *)(Item[FocusPos]->ObjPtr))->SetCurPos(0);
2655 Do_ProcessNextCtrl(FALSE, FALSE);
2658 ShowDialog();
2659 return TRUE;
2660 } else if (Item[FocusPos]->Type == DI_BUTTON) {
2661 Item[FocusPos]->Selected = 1;
2663 // сообщение - "Кнокна кликнута"
2664 if (SendDlgMessage((HANDLE)this, DN_BTNCLICK, FocusPos, 0))
2665 return TRUE;
2667 if (Item[FocusPos]->Flags & DIF_BTNNOCLOSE)
2668 return TRUE;
2670 ExitCode = FocusPos;
2671 CloseDialog();
2672 return TRUE;
2673 } else {
2674 ExitCode = -1;
2676 for (I = 0; I < ItemCount; I++) {
2677 if (Item[I]->DefaultButton && !(Item[I]->Flags & DIF_BTNNOCLOSE)) {
2678 if (Item[I]->Flags & DIF_DISABLE) {
2679 // ProcessKey(KEY_DOWN); // на твой вкус :-)
2680 return TRUE;
2683 // if (!(FarIsEdit(Item[I].Type) || Item[I].Type == DI_CHECKBOX || Item[I].Type == DI_RADIOBUTTON))
2684 // Item[I].Selected=1;
2685 ExitCode = I;
2686 break;
2691 if (ExitCode == -1)
2692 ExitCode = FocusPos;
2694 CloseDialog();
2695 return TRUE;
2698 3-х уровневое состояние
2699 Для чекбокса сюда попадем только в случае, если контрол
2700 имеет флаг DIF_3STATE
2702 case KEY_ADD:
2703 case KEY_SUBTRACT:
2704 case KEY_MULTIPLY:
2706 if (Item[FocusPos]->Type == DI_CHECKBOX) {
2707 unsigned int CHKState = (Key == KEY_ADD
2709 : (Key == KEY_SUBTRACT
2711 : ((Key == KEY_MULTIPLY) ? 2 : Item[FocusPos]->Selected)));
2713 if (Item[FocusPos]->Selected != (int)CHKState)
2714 if (SendDlgMessage((HANDLE)this, DN_BTNCLICK, FocusPos, CHKState)) {
2715 Item[FocusPos]->Selected = CHKState;
2716 ShowDialog();
2720 return TRUE;
2721 case KEY_LEFT:
2722 case KEY_NUMPAD4:
2723 case KEY_SHIFTNUMPAD4:
2724 case KEY_MSWHEEL_LEFT:
2725 case KEY_RIGHT:
2726 case KEY_NUMPAD6:
2727 case KEY_SHIFTNUMPAD6:
2728 case KEY_MSWHEEL_RIGHT: {
2729 if (Item[FocusPos]->Type == DI_USERCONTROL) // для user-типа вываливаем
2730 return TRUE;
2732 if (FarIsEdit(Item[FocusPos]->Type)) {
2733 ((DlgEdit *)(Item[FocusPos]->ObjPtr))->ProcessKey(Key);
2734 return TRUE;
2735 } else {
2736 return MoveToCtrlHorizontal(Key == KEY_RIGHT || Key == KEY_NUMPAD6);
2739 case KEY_UP:
2740 case KEY_NUMPAD8:
2741 case KEY_DOWN:
2742 case KEY_NUMPAD2: {
2743 if (Item[FocusPos]->Type == DI_USERCONTROL) // для user-типа вываливаем
2744 return TRUE;
2746 return MoveToCtrlVertical(Key == KEY_UP || Key == KEY_NUMPAD8);
2748 // $ 27.04.2001 VVM - Обработка колеса мышки
2749 case KEY_MSWHEEL_UP:
2750 case KEY_MSWHEEL_DOWN:
2751 case KEY_CTRLUP:
2752 case KEY_CTRLNUMPAD8:
2753 case KEY_CTRLDOWN:
2754 case KEY_CTRLNUMPAD2:
2755 return ProcessOpenComboBox(Item[FocusPos]->Type, Item[FocusPos], FocusPos);
2756 // ЭТО перед default предпоследний!!!
2757 case KEY_END:
2758 case KEY_NUMPAD1:
2760 if (Item[FocusPos]->Type == DI_USERCONTROL) // для user-типа вываливаем
2761 return TRUE;
2763 if (FarIsEdit(Item[FocusPos]->Type)) {
2764 ((DlgEdit *)(Item[FocusPos]->ObjPtr))->ProcessKey(Key);
2765 return TRUE;
2768 // ???
2769 // ЭТО перед default последний!!!
2770 case KEY_PGDN:
2771 case KEY_NUMPAD3:
2773 if (Item[FocusPos]->Type == DI_USERCONTROL) // для user-типа вываливаем
2774 return TRUE;
2776 if (!(Item[FocusPos]->Flags & DIF_EDITOR)) {
2777 for (I = 0; I < ItemCount; I++)
2778 if (Item[I]->DefaultButton) {
2779 ChangeFocus2(I);
2780 ShowDialog();
2781 return TRUE;
2784 return TRUE;
2786 break;
2788 case KEY_F11: {
2789 if (!CheckDialogMode(DMODE_NOPLUGINS)) {
2790 return FrameManager->ProcessKey(Key);
2792 } break;
2794 // для DIF_EDITOR будет обработано ниже
2795 default: {
2796 // if(Item[FocusPos].Type == DI_USERCONTROL) // для user-типа вываливаем
2797 // return TRUE;
2798 if (Item[FocusPos]->Type == DI_LISTBOX) {
2799 VMenu *List = Item[FocusPos]->ListPtr;
2800 int CurListPos = List->GetSelectPos();
2801 auto CheckedListItem = List->GetCheck(-1);
2802 List->ProcessKey(Key);
2803 int NewListPos = List->GetSelectPos();
2805 if (NewListPos != CurListPos && !DlgProc((HANDLE)this, DN_LISTCHANGE, FocusPos, NewListPos)) {
2806 if (!DialogMode.Check(DMODE_SHOW))
2807 return TRUE;
2809 List->SetCheck(CheckedListItem, CurListPos);
2811 if (DialogMode.Check(DMODE_SHOW) && !(Item[FocusPos]->Flags & DIF_HIDDEN))
2812 ShowDialog(FocusPos); // FocusPos
2815 return TRUE;
2818 if (FarIsEdit(Item[FocusPos]->Type)) {
2819 DlgEdit *edt = (DlgEdit *)Item[FocusPos]->ObjPtr;
2821 if (Key == KEY_CTRLL) // исключим смену режима RO для поля ввода с клавиатуры
2823 return TRUE;
2824 } else if (Key == KEY_CTRLU) {
2825 edt->SetClearFlag(0);
2826 edt->Select(-1, 0);
2827 edt->Show();
2828 return TRUE;
2829 } else if ((Item[FocusPos]->Flags & DIF_EDITOR) && !(Item[FocusPos]->Flags & DIF_READONLY)) {
2830 switch (Key) {
2831 case KEY_BS: {
2832 int CurPos = edt->GetCurPos();
2834 // В начале строки????
2835 if (!edt->GetCurPos()) {
2836 // а "выше" тоже DIF_EDITOR?
2837 if (FocusPos > 0 && (Item[FocusPos - 1]->Flags & DIF_EDITOR)) {
2838 // добавляем к предыдущему и...
2839 DlgEdit *edt_1 = (DlgEdit *)Item[FocusPos - 1]->ObjPtr;
2840 edt_1->GetString(strStr);
2841 CurPos = static_cast<int>(strStr.GetLength());
2842 FARString strAdd;
2843 edt->GetString(strAdd);
2844 strStr+= strAdd;
2845 edt_1->SetString(strStr);
2847 for (I = FocusPos + 1; I < ItemCount; I++) {
2848 if (Item[I]->Flags & DIF_EDITOR) {
2849 if (I > FocusPos) {
2850 ((DlgEdit *)(Item[I]->ObjPtr))->GetString(strStr);
2851 ((DlgEdit *)(Item[I - 1]->ObjPtr))->SetString(strStr);
2854 ((DlgEdit *)(Item[I]->ObjPtr))->SetString(L"");
2855 } else // ага, значит FocusPos это есть последний из DIF_EDITOR
2857 ((DlgEdit *)(Item[I - 1]->ObjPtr))->SetString(L"");
2858 break;
2862 Do_ProcessNextCtrl(TRUE);
2863 edt_1->SetCurPos(CurPos);
2865 } else {
2866 edt->ProcessKey(Key);
2869 ShowDialog();
2870 return TRUE;
2872 case KEY_CTRLY: {
2873 for (I = FocusPos; I < ItemCount; I++)
2874 if (Item[I]->Flags & DIF_EDITOR) {
2875 if (I > FocusPos) {
2876 ((DlgEdit *)(Item[I]->ObjPtr))->GetString(strStr);
2877 ((DlgEdit *)(Item[I - 1]->ObjPtr))->SetString(strStr);
2880 ((DlgEdit *)(Item[I]->ObjPtr))->SetString(L"");
2881 } else
2882 break;
2884 ShowDialog();
2885 return TRUE;
2887 case KEY_NUMDEL:
2888 case KEY_DEL: {
2890 $ 19.07.2000 SVS
2891 ! "...В редакторе команд меню нажмите home shift+end del
2892 блок не удаляется..."
2893 DEL у итемов, имеющих DIF_EDITOR, работал без учета
2894 выделения...
2896 if (FocusPos < ItemCount + 1 && (Item[FocusPos + 1]->Flags & DIF_EDITOR)) {
2897 int CurPos = edt->GetCurPos();
2898 int Length = edt->GetLength();
2899 int SelStart, SelEnd;
2900 edt->GetSelection(SelStart, SelEnd);
2901 edt->GetString(strStr);
2903 if (SelStart > -1) {
2904 FARString strEnd = strStr.CPtr() + SelEnd;
2905 strStr.Truncate(SelStart);
2906 strStr+= strEnd;
2907 edt->SetString(strStr);
2908 edt->SetCurPos(SelStart);
2909 ShowDialog();
2910 return TRUE;
2911 } else if (CurPos >= Length) {
2912 DlgEdit *edt_1 = (DlgEdit *)Item[FocusPos + 1]->ObjPtr;
2915 $ 12.09.2000 SVS
2916 Решаем проблему, если Del нажали в позиции
2917 большей, чем длина строки
2919 if (CurPos > Length) {
2920 strStr.Append(L' ', CurPos - Length);
2923 FARString strAdd;
2924 edt_1->GetString(strAdd);
2925 edt_1->SetString(strStr + strAdd);
2926 ProcessKey(KEY_CTRLY);
2927 edt->SetCurPos(CurPos);
2928 ShowDialog();
2929 return TRUE;
2933 break;
2935 case KEY_PGDN:
2936 case KEY_NUMPAD3:
2937 case KEY_PGUP:
2938 case KEY_NUMPAD9: {
2939 I = FocusPos;
2941 while (Item[I]->Flags & DIF_EDITOR)
2942 I = ChangeFocus(I, (Key == KEY_PGUP || Key == KEY_NUMPAD9) ? -1 : 1, FALSE);
2944 if (!(Item[I]->Flags & DIF_EDITOR))
2945 I = ChangeFocus(I, (Key == KEY_PGUP || Key == KEY_NUMPAD9) ? 1 : -1, FALSE);
2947 ChangeFocus2(I);
2948 ShowDialog();
2950 return TRUE;
2955 if (Key == KEY_OP_XLAT && !(Item[FocusPos]->Flags & DIF_READONLY)) {
2956 edt->SetClearFlag(0);
2957 edt->Xlat();
2959 // иначе неправильно работает ctrl-end
2960 edt->strLastStr = edt->GetStringAddr();
2961 edt->LastPartLength = static_cast<int>(edt->strLastStr.GetLength());
2963 Redraw(); // Перерисовка должна идти после DN_EDITCHANGE (imho)
2964 return TRUE;
2967 if (!(Item[FocusPos]->Flags & DIF_READONLY) || IsNavKey(Key)) {
2968 // "только что ломанулись и начинать выделение с нуля"?
2969 if ((Opt.Dialogs.EditLine & DLGEDITLINE_NEWSELONGOTFOCUS) && Item[FocusPos]->SelStart != -1
2970 && PrevFocusPos != FocusPos) { // && Item[FocusPos].SelEnd)
2972 edt->Flags().Clear(FEDITLINE_MARKINGBLOCK);
2973 PrevFocusPos = FocusPos;
2976 if (edt->ProcessKey(Key)) {
2977 if (Item[FocusPos]->Flags & DIF_READONLY)
2978 return TRUE;
2980 if ((Key == KEY_CTRLEND || Key == KEY_CTRLNUMPAD1)
2981 && edt->GetCurPos() == edt->GetLength()) {
2982 if (edt->LastPartLength == -1)
2983 edt->strLastStr = edt->GetStringAddr();
2985 strStr = edt->strLastStr;
2986 int CurCmdPartLength = static_cast<int>(strStr.GetLength());
2987 edt->HistoryGetSimilar(strStr, edt->LastPartLength);
2989 if (edt->LastPartLength == -1) {
2990 edt->strLastStr = edt->GetStringAddr();
2991 edt->LastPartLength = CurCmdPartLength;
2993 edt->DisableAC();
2994 edt->SetString(strStr);
2995 edt->Select(edt->LastPartLength, static_cast<int>(strStr.GetLength()));
2996 edt->RevertAC();
2997 Show();
2998 return TRUE;
3001 edt->LastPartLength = -1;
3003 if (Key == KEY_CTRLSHIFTEND || Key == KEY_CTRLSHIFTNUMPAD1) {
3004 edt->EnableAC();
3005 edt->AutoComplete(true, false);
3006 edt->RevertAC();
3009 Redraw(); // Перерисовка должна идти после DN_EDITCHANGE (imho)
3010 return TRUE;
3012 } else if (!(Key & (KEY_ALT | KEY_RALT)))
3013 return TRUE;
3016 if (ProcessHighlighting(Key, FocusPos, FALSE))
3017 return TRUE;
3019 return (Opt.XLat.EnableForDialogs && ProcessHighlighting(Key, FocusPos, TRUE));
3022 return FALSE;
3025 void Dialog::ProcessKey(FarKey Key, unsigned ItemPos)
3027 unsigned SavedFocusPos = FocusPos;
3028 FocusPos = ItemPos;
3029 ProcessKey(Key);
3030 if (FocusPos == ItemPos)
3031 FocusPos = SavedFocusPos;
3034 //////////////////////////////////////////////////////////////////////////
3036 Public, Virtual:
3037 Обработка данных от "мыши".
3038 Перекрывает BaseInput::ProcessMouse.
3041 $ 18.08.2000 SVS
3042 + DN_MOUSECLICK
3044 int Dialog::ProcessMouse(MOUSE_EVENT_RECORD *MouseEvent)
3046 CriticalSectionLock Lock(CS);
3047 unsigned I;
3048 int MsX, MsY;
3049 int Type;
3050 SMALL_RECT Rect;
3052 if (!DialogMode.Check(DMODE_SHOW))
3053 return FALSE;
3055 if (DialogMode.Check(DMODE_MOUSEEVENT)) {
3056 if (!DlgProc((HANDLE)this, DN_MOUSEEVENT, 0, (LONG_PTR)MouseEvent))
3057 return TRUE;
3060 if (!DialogMode.Check(DMODE_SHOW))
3061 return FALSE;
3063 MsX = MouseEvent->dwMousePosition.X;
3064 MsY = MouseEvent->dwMousePosition.Y;
3066 // for (I=0;I<ItemCount;I++)
3067 for (I = ItemCount - 1; I != (unsigned)-1; I--) {
3068 if (Item[I]->Flags & (DIF_DISABLE | DIF_HIDDEN))
3069 continue;
3071 Type = Item[I]->Type;
3073 if (Type == DI_LISTBOX && MsY >= Y1 + Item[I]->Y1 && MsY <= Y1 + Item[I]->Y2
3074 && MsX >= X1 + Item[I]->X1 && MsX <= X1 + Item[I]->X2) {
3075 VMenu *List = Item[I]->ListPtr;
3076 int Pos = List->GetSelectPos();
3077 auto CheckedListItem = List->GetCheck(-1);
3079 if ((MouseEvent->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED)) {
3080 if (FocusPos != I) {
3081 ChangeFocus2(I);
3082 ShowDialog();
3085 if (MouseEvent->dwEventFlags != DOUBLE_CLICK
3086 && !(Item[I]->IFlags.Flags
3087 & (DLGIIF_LISTREACTIONFOCUS | DLGIIF_LISTREACTIONNOFOCUS))) {
3089 List->ProcessMouse(MouseEvent);
3090 int NewListPos = List->GetSelectPos();
3092 if (NewListPos != Pos
3093 && !SendDlgMessage((HANDLE)this, DN_LISTCHANGE, I, (LONG_PTR)NewListPos)) {
3094 List->SetCheck(CheckedListItem, Pos);
3096 if (DialogMode.Check(DMODE_SHOW) && !(Item[I]->Flags & DIF_HIDDEN))
3097 ShowDialog(I); // FocusPos
3098 } else {
3099 Pos = NewListPos;
3101 } else if (!SendDlgMessage((HANDLE)this, DN_MOUSECLICK, I, (LONG_PTR)MouseEvent)) {
3102 #if 1
3103 List->ProcessMouse(MouseEvent);
3104 int NewListPos = List->GetSelectPos();
3105 int InScroolBar =
3106 (MsX == X1 + Item[I]->X2 && MsY >= Y1 + Item[I]->Y1 && MsY <= Y1 + Item[I]->Y2)
3107 && (List->CheckFlags(VMENU_LISTBOX | VMENU_ALWAYSSCROLLBAR)
3108 || Opt.ShowMenuScrollbar);
3110 if (!InScroolBar && // вне скроллбара и
3111 NewListPos != Pos && // позиция изменилась и
3112 !SendDlgMessage((HANDLE)this, DN_LISTCHANGE, I, (LONG_PTR)NewListPos)) // и плагин сказал в морг
3114 List->SetCheck(CheckedListItem, Pos);
3116 if (DialogMode.Check(DMODE_SHOW) && !(Item[I]->Flags & DIF_HIDDEN))
3117 ShowDialog(I); // FocusPos
3118 } else {
3119 Pos = NewListPos;
3121 if (!InScroolBar && !(Item[I]->Flags & DIF_LISTNOCLOSE)) {
3122 ExitCode = I;
3123 CloseDialog();
3124 return TRUE;
3128 #else
3130 if (SendDlgMessage((HANDLE)this, DN_LISTCHANGE, I, (LONG_PTR)Pos)) {
3131 if (MsX == X1 + Item[I]->X2 && MsY >= Y1 + Item[I]->Y1 && MsY <= Y1 + Item[I]->Y2)
3132 List->ProcessMouse(MouseEvent); // забыл проверить на клик на скролбар (KM)
3133 else
3134 ProcessKey(KEY_ENTER, I);
3137 #endif
3140 return TRUE;
3141 } else {
3142 if (!MouseEvent->dwButtonState
3143 || SendDlgMessage((HANDLE)this, DN_MOUSECLICK, I, (LONG_PTR)MouseEvent)) {
3144 if ((I == FocusPos && (Item[I]->IFlags.Flags & DLGIIF_LISTREACTIONFOCUS))
3145 || (I != FocusPos && (Item[I]->IFlags.Flags & DLGIIF_LISTREACTIONNOFOCUS))) {
3146 List->ProcessMouse(MouseEvent);
3147 int NewListPos = List->GetSelectPos();
3149 if (NewListPos != Pos
3150 && !SendDlgMessage((HANDLE)this, DN_LISTCHANGE, I, (LONG_PTR)NewListPos)) {
3151 List->SetCheck(CheckedListItem, Pos);
3153 if (DialogMode.Check(DMODE_SHOW) && !(Item[I]->Flags & DIF_HIDDEN))
3154 ShowDialog(I); // FocusPos
3155 } else
3156 Pos = NewListPos;
3161 return TRUE;
3165 if (MsX < X1 || MsY < Y1 || MsX > X2 || MsY > Y2) {
3166 if (DialogMode.Check(DMODE_CLICKOUTSIDE)
3167 && !DlgProc((HANDLE)this, DN_MOUSECLICK, -1, (LONG_PTR)MouseEvent)) {
3168 if (!DialogMode.Check(DMODE_SHOW))
3169 return FALSE;
3171 // if (!(MouseEvent->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) && PrevLButtonPressed && ScreenObject::CaptureMouseObject)
3172 if (!(MouseEvent->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED)
3173 && (PrevMouseButtonState & FROM_LEFT_1ST_BUTTON_PRESSED)
3174 && (Opt.Dialogs.MouseButton & DMOUSEBUTTON_LEFT))
3175 ProcessKey(KEY_ESC);
3176 // else if (!(MouseEvent->dwButtonState & RIGHTMOST_BUTTON_PRESSED) && PrevRButtonPressed && ScreenObject::CaptureMouseObject)
3177 else if (!(MouseEvent->dwButtonState & RIGHTMOST_BUTTON_PRESSED)
3178 && (PrevMouseButtonState & RIGHTMOST_BUTTON_PRESSED)
3179 && (Opt.Dialogs.MouseButton & DMOUSEBUTTON_RIGHT))
3180 ProcessKey(KEY_ENTER);
3183 if (MouseEvent->dwButtonState)
3184 DialogMode.Set(DMODE_CLICKOUTSIDE);
3186 // ScreenObject::SetCapture(this);
3187 return TRUE;
3190 if (!MouseEvent->dwButtonState) {
3191 DialogMode.Clear(DMODE_CLICKOUTSIDE);
3192 // ScreenObject::SetCapture(nullptr);
3193 return FALSE;
3196 if (!MouseEvent->dwEventFlags || MouseEvent->dwEventFlags == DOUBLE_CLICK) {
3197 // первый цикл - все за исключением рамок.
3198 // for (I=0; I < ItemCount;I++)
3199 for (I = ItemCount - 1; I != (unsigned)-1; I--) {
3200 if (Item[I]->Flags & (DIF_DISABLE | DIF_HIDDEN))
3201 continue;
3203 GetItemRect(I, Rect);
3204 Rect.Left+= X1;
3205 Rect.Top+= Y1;
3206 Rect.Right+= X1;
3207 Rect.Bottom+= Y1;
3208 //_D(SysLog(L"? %2d) Rect (%2d,%2d) (%2d,%2d) '%ls'",I,Rect.left,Rect.top,Rect.right,Rect.bottom,Item[I].Data));
3210 if (MsX >= Rect.Left && MsY >= Rect.Top && MsX <= Rect.Right && MsY <= Rect.Bottom) {
3211 // для прозрачных :-)
3212 if (Item[I]->Type == DI_SINGLEBOX || Item[I]->Type == DI_DOUBLEBOX) {
3213 // если на рамке, то...
3214 if (((MsX == Rect.Left || MsX == Rect.Right) && MsY >= Rect.Top && MsY <= Rect.Bottom)
3215 || // vert
3216 ((MsY == Rect.Top || MsY == Rect.Bottom) && MsX >= Rect.Left
3217 && MsX <= Rect.Right)) // hor
3219 if (DlgProc((HANDLE)this, DN_MOUSECLICK, I, (LONG_PTR)MouseEvent))
3220 return TRUE;
3222 if (!DialogMode.Check(DMODE_SHOW))
3223 return FALSE;
3224 } else
3225 continue;
3228 if (Item[I]->Type == DI_USERCONTROL) {
3229 // для user-типа подготовим координаты мыши
3230 MouseEvent->dwMousePosition.X-= Rect.Left;
3231 MouseEvent->dwMousePosition.Y-= Rect.Top;
3234 //_SVS(SysLog(L"+ %2d) Rect (%2d,%2d) (%2d,%2d) '%ls' Dbl=%d",I,Rect.left,Rect.top,Rect.right,Rect.bottom,Item[I].Data,MouseEvent->dwEventFlags==DOUBLE_CLICK));
3235 if (DlgProc((HANDLE)this, DN_MOUSECLICK, I, (LONG_PTR)MouseEvent))
3236 return TRUE;
3238 if (!DialogMode.Check(DMODE_SHOW))
3239 return TRUE;
3241 if (Item[I]->Type == DI_USERCONTROL) {
3242 ChangeFocus2(I);
3243 ShowDialog();
3244 return TRUE;
3247 break;
3251 if ((MouseEvent->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED)) {
3252 // for (I=0;I<ItemCount;I++)
3254 for (I = ItemCount - 1; I != (unsigned)-1; I--) {
3255 // Исключаем из списка оповещаемых о мыши недоступные элементы
3256 if (Item[I]->Flags & (DIF_DISABLE | DIF_HIDDEN))
3257 continue;
3259 Type = Item[I]->Type;
3261 GetItemRect(I, Rect);
3262 Rect.Left+= X1;
3263 Rect.Top+= Y1;
3264 Rect.Right+= X1;
3265 Rect.Bottom+= Y1;
3266 if (ItemHasDropDownArrow(Item[I]))
3267 Rect.Right++;
3269 if (MsX >= Rect.Left && MsY >= Rect.Top && MsX <= Rect.Right && MsY <= Rect.Bottom) {
3270 /* ********************************************************** */
3271 if (FarIsEdit(Type)) {
3273 $ 15.08.2000 SVS
3274 + Сделаем так, чтобы ткнув мышкой в DropDownList
3275 список раскрывался сам.
3276 Есть некоторая глюкавость - когда список раскрыт и мы
3277 мышой переваливаем на другой элемент, то список закрывается
3278 но перехода реального на указанный элемент диалога не происходит
3280 int EditX1, EditY1, EditX2, EditY2;
3281 DlgEdit *EditLine = (DlgEdit *)(Item[I]->ObjPtr);
3282 EditLine->GetPosition(EditX1, EditY1, EditX2, EditY2);
3284 if (MsY == EditY1 && Type == DI_COMBOBOX && (Item[I]->Flags & DIF_DROPDOWNLIST)
3285 && MsX >= EditX1 && MsX <= EditX2 + 1) {
3286 EditLine->SetClearFlag(0);
3288 ChangeFocus2(I);
3289 ShowDialog();
3291 ProcessOpenComboBox(Item[I]->Type, Item[I], I);
3293 return TRUE;
3296 ChangeFocus2(I);
3298 if (EditLine->ProcessMouse(MouseEvent)) {
3299 EditLine->SetClearFlag(0); // а может это делать в самом edit?
3302 $ 23.06.2001 KM
3303 ! Оказалось нужно перерисовывать весь диалог иначе
3304 не снимался признак активности с комбобокса с которго уходим.
3306 ShowDialog(); // нужен ли только один контрол или весь диалог?
3307 return TRUE;
3308 } else {
3309 // Проверка на DI_COMBOBOX здесь лишняя. Убрана (KM).
3310 if (MsX == EditX2 + 1 && MsY == EditY1 && ItemHasDropDownArrow(Item[I])) {
3311 EditLine->SetClearFlag(0); // раз уж покусились на, то и...
3313 ChangeFocus2(I);
3315 if (!(Item[I]->Flags & DIF_HIDDEN))
3316 ShowDialog(I);
3318 ProcessOpenComboBox(Item[I]->Type, Item[I], I);
3320 return TRUE;
3325 /* ********************************************************** */
3326 if (Type == DI_BUTTON && MsY == Y1 + Item[I]->Y1
3327 && MsX < X1 + Item[I]->X1 + HiStrCellsCount(Item[I]->strData)) {
3328 ChangeFocus2(I);
3329 ShowDialog();
3331 while (IsMouseButtonPressed())
3334 if (MouseX < X1 || MouseX > X1 + Item[I]->X1 + HiStrCellsCount(Item[I]->strData) + 4
3335 || MouseY != Y1 + Item[I]->Y1) {
3336 ChangeFocus2(I);
3337 ShowDialog();
3339 return TRUE;
3342 ProcessKey(KEY_ENTER, I);
3343 return TRUE;
3346 /* ********************************************************** */
3347 if ((Type == DI_CHECKBOX || Type == DI_RADIOBUTTON) && MsY == Y1 + Item[I]->Y1
3348 && MsX < (X1 + Item[I]->X1 + HiStrCellsCount(Item[I]->strData) + 4
3349 - ((Item[I]->Flags & DIF_MOVESELECT) != 0))) {
3350 ChangeFocus2(I);
3351 ProcessKey(KEY_SPACE, I);
3352 return TRUE;
3355 } // for (I=0;I<ItemCount;I++)
3357 // ДЛЯ MOUSE-Перемещалки:
3358 // Сюда попадаем в том случае, если мышь не попала на активные элементы
3361 if (DialogMode.Check(DMODE_ISCANMOVE)) {
3362 // DialogMode.Set(DMODE_DRAGGED);
3363 OldX1 = X1;
3364 OldX2 = X2;
3365 OldY1 = Y1;
3366 OldY2 = Y2;
3367 // запомним delta места хватания и Left-Top диалогового окна
3368 MsX = abs(X1 - MouseX);
3369 MsY = abs(Y1 - MouseY);
3370 int NeedSendMsg = 0;
3372 for (;;) {
3373 DWORD Mb = IsMouseButtonPressed();
3374 int mx, my, X0, Y0;
3376 if (Mb == FROM_LEFT_1ST_BUTTON_PRESSED) // still dragging
3378 int AdjX = 0, AdjY = 0;
3379 int OX1 = X1;
3380 int OY1 = Y1;
3381 int NX1 = X0 = X1;
3382 int NX2 = X2;
3383 int NY1 = Y0 = Y1;
3384 int NY2 = Y2;
3386 if (MouseX == PrevMouseX)
3387 mx = X1;
3388 else
3389 mx = MouseX - MsX;
3391 if (MouseY == PrevMouseY)
3392 my = Y1;
3393 else
3394 my = MouseY - MsY;
3396 NX2 = mx + (X2 - X1);
3397 NX1 = mx;
3398 AdjX = NX1 - X0;
3399 NY2 = my + (Y2 - Y1);
3400 NY1 = my;
3401 AdjY = NY1 - Y0;
3403 // "А был ли мальчик?" (про холостой ход)
3404 if (OX1 != NX1 || OY1 != NY1) {
3405 if (!NeedSendMsg) // тыкс, а уже посылку делали в диалоговую процедуру?
3407 NeedSendMsg++;
3409 if (!DlgProc((HANDLE)this, DN_DRAGGED, 0, 0)) // а может нас обломали?
3410 break; // валим отсель...плагин сказал - в морг перемещения
3412 if (!DialogMode.Check(DMODE_SHOW))
3413 break;
3416 // Да, мальчик был. Зачнем...
3418 LockScreen LckScr;
3419 Hide();
3420 X1 = NX1;
3421 X2 = NX2;
3422 Y1 = NY1;
3423 Y2 = NY2;
3425 if (AdjX || AdjY)
3426 AdjustEditPos(AdjX, AdjY); //?
3428 Show();
3431 } else if (Mb == RIGHTMOST_BUTTON_PRESSED) // abort
3433 LockScreen LckScr;
3434 Hide();
3435 AdjustEditPos(OldX1 - X1, OldY1 - Y1);
3436 X1 = OldX1;
3437 X2 = OldX2;
3438 Y1 = OldY1;
3439 Y2 = OldY2;
3440 DialogMode.Clear(DMODE_DRAGGED);
3441 DlgProc((HANDLE)this, DN_DRAGGED, 1, TRUE);
3443 if (DialogMode.Check(DMODE_SHOW))
3444 Show();
3446 break;
3447 } else // release key, drop dialog
3449 if (OldX1 != X1 || OldX2 != X2 || OldY1 != Y1 || OldY2 != Y2) {
3450 LockScreen LckScr;
3451 DialogMode.Clear(DMODE_DRAGGED);
3452 DlgProc((HANDLE)this, DN_DRAGGED, 1, 0);
3454 if (DialogMode.Check(DMODE_SHOW))
3455 Show();
3458 break;
3460 } // while (1)
3465 return FALSE;
3468 int Dialog::ProcessOpenComboBox(int Type, DialogItemEx *CurItem, unsigned CurFocusPos)
3470 CriticalSectionLock Lock(CS);
3471 FARString strStr;
3472 DlgEdit *CurEditLine;
3474 // для user-типа вываливаем
3475 if (Type == DI_USERCONTROL)
3476 return TRUE;
3478 CurEditLine = ((DlgEdit *)(CurItem->ObjPtr));
3480 if (FarIsEdit(Type) && (CurItem->Flags & DIF_HISTORY) && Opt.Dialogs.EditHistory
3481 && !CurItem->strHistory.IsEmpty() && !(CurItem->Flags & DIF_READONLY)) {
3482 // Передаем то, что в строке ввода в функцию выбора из истории для выделения нужного пункта в истории.
3483 CurEditLine->GetString(strStr);
3484 SelectFromEditHistory(CurItem, CurEditLine, CurItem->strHistory, strStr);
3486 // $ 18.07.2000 SVS: +обработка DI_COMBOBOX - выбор из списка!
3487 else if (Type == DI_COMBOBOX && CurItem->ListPtr && !(CurItem->Flags & DIF_READONLY)
3488 && CurItem->ListPtr->GetItemCount() > 0) //??
3490 SelectFromComboBox(CurItem, CurEditLine, CurItem->ListPtr);
3493 return TRUE;
3496 unsigned Dialog::ProcessRadioButton(unsigned CurRB)
3498 CriticalSectionLock Lock(CS);
3499 unsigned PrevRB = CurRB, J;
3500 unsigned I;
3502 for (I = CurRB;; I--) {
3503 if (!I)
3504 break;
3506 if (Item[I]->Type == DI_RADIOBUTTON && (Item[I]->Flags & DIF_GROUP))
3507 break;
3509 if (Item[I - 1]->Type != DI_RADIOBUTTON)
3510 break;
3513 do {
3515 $ 28.07.2000 SVS
3516 При изменении состояния каждого элемента посылаем сообщение
3517 посредством функции SendDlgMessage - в ней делается все!
3519 J = Item[I]->Selected;
3520 Item[I]->Selected = 0;
3522 if (J) {
3523 PrevRB = I;
3526 ++I;
3527 } while (I < ItemCount && Item[I]->Type == DI_RADIOBUTTON && !(Item[I]->Flags & DIF_GROUP));
3529 Item[CurRB]->Selected = 1;
3532 $ 28.07.2000 SVS
3533 При изменении состояния каждого элемента посылаем сообщение
3534 посредством функции SendDlgMessage - в ней делается все!
3536 if (!SendDlgMessage((HANDLE)this, DN_BTNCLICK, PrevRB, 0)
3537 || !SendDlgMessage((HANDLE)this, DN_BTNCLICK, CurRB, 1)) {
3538 // вернем назад, если пользователь не захотел...
3539 Item[CurRB]->Selected = 0;
3540 Item[PrevRB]->Selected = 1;
3541 return PrevRB;
3544 return CurRB;
3547 int Dialog::Do_ProcessFirstCtrl()
3549 CriticalSectionLock Lock(CS);
3551 if (FarIsEdit(Item[FocusPos]->Type)) {
3552 ((DlgEdit *)(Item[FocusPos]->ObjPtr))->ProcessKey(KEY_HOME);
3553 return TRUE;
3554 } else {
3555 for (unsigned I = 0; I < ItemCount; I++)
3556 if (CanGetFocus(Item[I]->Type)) {
3557 ChangeFocus2(I);
3558 ShowDialog();
3559 break;
3563 return TRUE;
3566 int Dialog::Do_ProcessNextCtrl(int Up, BOOL IsRedraw)
3568 CriticalSectionLock Lock(CS);
3569 unsigned OldPos = FocusPos;
3570 unsigned PrevPos = 0;
3572 if (FarIsEdit(Item[FocusPos]->Type) && (Item[FocusPos]->Flags & DIF_EDITOR))
3573 PrevPos = ((DlgEdit *)(Item[FocusPos]->ObjPtr))->GetCurPos();
3575 unsigned I = ChangeFocus(FocusPos, Up ? -1 : 1, FALSE);
3576 Item[FocusPos]->Focus = 0;
3577 Item[I]->Focus = 1;
3578 ChangeFocus2(I);
3580 if (FarIsEdit(Item[I]->Type) && (Item[I]->Flags & DIF_EDITOR))
3581 ((DlgEdit *)(Item[I]->ObjPtr))->SetCurPos(PrevPos);
3583 if (Item[FocusPos]->Type == DI_RADIOBUTTON && (Item[I]->Flags & DIF_MOVESELECT))
3584 ProcessKey(KEY_SPACE);
3585 else if (IsRedraw) {
3586 ShowDialog(OldPos);
3587 ShowDialog(FocusPos);
3590 return TRUE;
3593 int Dialog::MoveToCtrlHorizontal(int right)
3595 int MinDist = 1000, MinPos = 0;
3597 for (unsigned int I = 0; I < ItemCount; I++) {
3598 if (I != FocusPos && (!(Item[I]->Flags & (DIF_NOFOCUS | DIF_DISABLE | DIF_HIDDEN)))
3599 && (FarIsEdit(Item[I]->Type) || Item[I]->Type == DI_CHECKBOX
3600 || Item[I]->Type == DI_RADIOBUTTON)
3601 && Item[I]->Y1 == Item[FocusPos]->Y1)
3603 int Dist = Item[I]->X1 - Item[FocusPos]->X1;
3605 if ((!right && Dist < 0) || (right && Dist > 0)) {
3606 if (abs(Dist) < MinDist) {
3607 MinDist = abs(Dist);
3608 MinPos = I;
3614 if (MinDist < 1000) {
3615 ChangeFocus2(MinPos);
3617 if (Item[MinPos]->Flags & DIF_MOVESELECT) {
3618 Do_ProcessSpace();
3619 } else {
3620 ShowDialog();
3622 } else {
3623 return Do_ProcessNextCtrl(!right);
3627 return TRUE;
3630 int Dialog::MoveToCtrlVertical(int up)
3632 int MinDist = 1000, MinPos = 0;
3634 for (unsigned int I = 0; I < ItemCount; I++) {
3635 if (I != FocusPos && (!(Item[I]->Flags & (DIF_NOFOCUS | DIF_DISABLE | DIF_HIDDEN)))
3636 && (FarIsEdit(Item[I]->Type) || Item[I]->Type == DI_CHECKBOX
3637 || Item[I]->Type == DI_RADIOBUTTON)
3638 && Item[I]->X1 == Item[FocusPos]->X1)
3640 int Dist = Item[I]->Y1 - Item[FocusPos]->Y1;
3642 if ((up && Dist < 0) || (!up && Dist > 0)) {
3643 if (abs(Dist) < MinDist) {
3644 MinDist = abs(Dist);
3645 MinPos = I;
3651 if (MinDist < 1000) {
3652 ChangeFocus2(MinPos);
3654 if (Item[MinPos]->Flags & DIF_MOVESELECT) {
3655 Do_ProcessSpace();
3656 } else {
3657 ShowDialog();
3659 } else {
3660 return Do_ProcessNextCtrl(up);
3663 return TRUE;
3666 int Dialog::Do_ProcessTab(int Next)
3668 CriticalSectionLock Lock(CS);
3669 unsigned I;
3671 if (ItemCount > 1) {
3672 // Must check for DI_EDIT since DIF_EDITOR and DIF_LISTNOAMPERSAND are equal
3673 if (Item[FocusPos]->Type==DI_EDIT && (Item[FocusPos]->Flags & DIF_EDITOR)) {
3674 I = FocusPos;
3676 while (Item[I]->Type==DI_EDIT && (Item[I]->Flags & DIF_EDITOR))
3677 I = ChangeFocus(I, Next ? 1 : -1, TRUE);
3678 } else {
3679 I = ChangeFocus(FocusPos, Next ? 1 : -1, TRUE);
3681 if (!Next)
3682 while (I > 0
3683 && Item[I]->Type == DI_EDIT && Item[I - 1]->Type == DI_EDIT
3684 && (Item[I]->Flags & DIF_EDITOR) && (Item[I - 1]->Flags & DIF_EDITOR)
3685 && !((DlgEdit *)Item[I]->ObjPtr)->GetLength())
3686 I--;
3688 } else
3689 I = FocusPos;
3691 ChangeFocus2(I);
3692 ShowDialog();
3694 return TRUE;
3697 int Dialog::Do_ProcessSpace()
3699 CriticalSectionLock Lock(CS);
3700 int OldFocusPos;
3702 if (Item[FocusPos]->Type == DI_CHECKBOX) {
3703 int OldSelected = Item[FocusPos]->Selected;
3705 if (Item[FocusPos]->Flags & DIF_3STATE) {
3706 Item[FocusPos]->Selected = (Item[FocusPos]->Selected + 1) % 3;
3707 } else
3708 Item[FocusPos]->Selected = !Item[FocusPos]->Selected;
3710 OldFocusPos = FocusPos;
3712 if (!SendDlgMessage((HANDLE)this, DN_BTNCLICK, FocusPos, Item[FocusPos]->Selected))
3713 Item[OldFocusPos]->Selected = OldSelected;
3715 ShowDialog();
3716 return TRUE;
3717 } else if (Item[FocusPos]->Type == DI_RADIOBUTTON) {
3718 FocusPos = ProcessRadioButton(FocusPos);
3719 ShowDialog();
3720 return TRUE;
3721 } else if (FarIsEdit(Item[FocusPos]->Type) && !(Item[FocusPos]->Flags & DIF_READONLY)) {
3722 if (((DlgEdit *)(Item[FocusPos]->ObjPtr))->ProcessKey(KEY_SPACE)) {
3723 Redraw(); // Перерисовка должна идти после DN_EDITCHANGE (imho)
3726 return TRUE;
3729 return TRUE;
3732 //////////////////////////////////////////////////////////////////////////
3734 Private:
3735 Изменяет фокус ввода (воздействие клавишами
3736 KEY_TAB, KEY_SHIFTTAB, KEY_UP, KEY_DOWN,
3737 а так же Alt-HotKey)
3740 $ 28.07.2000 SVS
3741 Довесок для сообщений DN_KILLFOCUS & DN_SETFOCUS
3744 $ 24.08.2000 SVS
3745 Добавка для DI_USERCONTROL
3747 unsigned Dialog::ChangeFocus(unsigned CurFocusPos, int Step, int SkipGroup)
3749 CriticalSectionLock Lock(CS);
3750 int Type;
3751 unsigned OrigFocusPos = CurFocusPos;
3752 // int FucusPosNeed=-1;
3753 // В функцию обработки диалога здесь передаем сообщение,
3754 // что элемент - LostFocus() - теряет фокус ввода.
3755 // if(DialogMode.Check(DMODE_INITOBJECTS))
3756 // FucusPosNeed=DlgProc((HANDLE)this,DN_KILLFOCUS,FocusPos,0);
3757 // if(FucusPosNeed != -1 && CanGetFocus(Item[FucusPosNeed].Type))
3758 // FocusPos=FucusPosNeed;
3759 // else
3761 for (;;) {
3762 CurFocusPos+= Step;
3764 if ((int)CurFocusPos < 0)
3765 CurFocusPos = ItemCount - 1;
3767 if (CurFocusPos >= ItemCount)
3768 CurFocusPos = 0;
3770 Type = Item[CurFocusPos]->Type;
3772 if (!(Item[CurFocusPos]->Flags & (DIF_NOFOCUS | DIF_DISABLE | DIF_HIDDEN))) {
3773 if (Type == DI_LISTBOX || Type == DI_BUTTON || Type == DI_CHECKBOX || FarIsEdit(Type)
3774 || Type == DI_USERCONTROL)
3775 break;
3777 if (Type == DI_RADIOBUTTON && (!SkipGroup || Item[CurFocusPos]->Selected))
3778 break;
3781 // убираем зацикливание с последующим подвисанием :-)
3782 if (OrigFocusPos == CurFocusPos)
3783 break;
3786 // Dialog::FocusPos=FocusPos;
3787 // В функцию обработки диалога здесь передаем сообщение,
3788 // что элемент GotFocus() - получил фокус ввода.
3789 // Игнорируем возвращаемое функцией диалога значение
3790 // if(DialogMode.Check(DMODE_INITOBJECTS))
3791 // DlgProc((HANDLE)this,DN_GOTFOCUS,FocusPos,0);
3792 return (CurFocusPos);
3795 //////////////////////////////////////////////////////////////////////////
3797 Private:
3798 Изменяет фокус ввода между двумя элементами.
3799 Вынесен отдельно с тем, чтобы обработать DN_KILLFOCUS & DM_SETFOCUS
3801 void Dialog::ChangeFocus2(unsigned SetFocusPos)
3803 CriticalSectionLock Lock(CS);
3804 int FocusPosNeed = -1;
3806 if (!(Item[SetFocusPos]->Flags & (DIF_NOFOCUS | DIF_DISABLE | DIF_HIDDEN))) {
3807 if (DialogMode.Check(DMODE_INITOBJECTS)) {
3808 FocusPosNeed = (int)DlgProc((HANDLE)this, DN_KILLFOCUS, FocusPos, 0);
3810 if (!DialogMode.Check(DMODE_SHOW))
3811 return;
3814 if (FocusPosNeed != -1 && CanGetFocus(Item[FocusPosNeed]->Type))
3815 SetFocusPos = FocusPosNeed;
3817 Item[FocusPos]->Focus = 0;
3819 // "снимать выделение при потере фокуса?"
3820 if (FarIsEdit(Item[FocusPos]->Type)
3821 && !(Item[FocusPos]->Type == DI_COMBOBOX && (Item[FocusPos]->Flags & DIF_DROPDOWNLIST))) {
3822 DlgEdit *EditPtr = (DlgEdit *)Item[FocusPos]->ObjPtr;
3823 EditPtr->GetSelection(Item[FocusPos]->SelStart, Item[FocusPos]->SelEnd);
3825 if ((Opt.Dialogs.EditLine & DLGEDITLINE_CLEARSELONKILLFOCUS)) {
3826 EditPtr->Select(-1, 0);
3830 Item[SetFocusPos]->Focus = 1;
3832 // "не восстанавливать выделение при получении фокуса?"
3833 if (FarIsEdit(Item[SetFocusPos]->Type)
3834 && !(Item[SetFocusPos]->Type == DI_COMBOBOX
3835 && (Item[SetFocusPos]->Flags & DIF_DROPDOWNLIST))) {
3836 DlgEdit *EditPtr = (DlgEdit *)Item[SetFocusPos]->ObjPtr;
3838 if (!(Opt.Dialogs.EditLine & DLGEDITLINE_NOTSELONGOTFOCUS)) {
3839 if (Opt.Dialogs.EditLine & DLGEDITLINE_SELALLGOTFOCUS)
3840 EditPtr->Select(0, EditPtr->GetStrSize());
3841 else
3842 EditPtr->Select(Item[SetFocusPos]->SelStart, Item[SetFocusPos]->SelEnd);
3843 } else {
3844 EditPtr->Select(-1, 0);
3847 // при получении фокуса ввода переместить курсор в конец строки?
3848 if (Opt.Dialogs.EditLine & DLGEDITLINE_GOTOEOLGOTFOCUS) {
3849 EditPtr->SetCurPos(EditPtr->GetStrSize());
3853 // проинформируем листбокс, есть ли у него фокус
3854 if (Item[FocusPos]->Type == DI_LISTBOX)
3855 Item[FocusPos]->ListPtr->ClearFlags(VMENU_LISTHASFOCUS);
3857 if (Item[SetFocusPos]->Type == DI_LISTBOX)
3858 Item[SetFocusPos]->ListPtr->SetFlags(VMENU_LISTHASFOCUS);
3860 SelectOnEntry(FocusPos, FALSE);
3861 SelectOnEntry(SetFocusPos, TRUE);
3863 PrevFocusPos = FocusPos;
3864 FocusPos = SetFocusPos;
3866 if (DialogMode.Check(DMODE_INITOBJECTS))
3867 DlgProc((HANDLE)this, DN_GOTFOCUS, FocusPos, 0);
3872 Функция SelectOnEntry - выделение строки редактирования
3873 Обработка флага DIF_SELECTONENTRY
3875 void Dialog::SelectOnEntry(unsigned Pos, BOOL Selected)
3877 // if(!DialogMode.Check(DMODE_SHOW))
3878 // return;
3879 if (FarIsEdit(Item[Pos]->Type) && (Item[Pos]->Flags & DIF_SELECTONENTRY)
3880 // && PrevFocusPos != -1 && PrevFocusPos != Pos
3882 DlgEdit *edt = (DlgEdit *)Item[Pos]->ObjPtr;
3884 if (edt) {
3885 if (Selected)
3886 edt->Select(0, edt->GetLength());
3887 else
3888 edt->Select(-1, 0);
3890 //_SVS(SysLog(L"Selected=%d edt->GetLength()=%d",Selected,edt->GetLength()));
3895 int Dialog::SetAutomation(WORD IDParent, WORD id, FarDialogItemFlags UncheckedSet,
3896 FarDialogItemFlags UncheckedSkip, FarDialogItemFlags CheckedSet, FarDialogItemFlags CheckedSkip,
3897 FarDialogItemFlags Checked3Set, FarDialogItemFlags Checked3Skip)
3899 CriticalSectionLock Lock(CS);
3900 int Ret = FALSE;
3902 if (IDParent < ItemCount && (Item[IDParent]->Flags & DIF_AUTOMATION) && id < ItemCount
3903 && IDParent != id) // Сами себя не юзаем!
3905 Ret = Item[IDParent]->AddAutomation(id, UncheckedSet, UncheckedSkip, CheckedSet, CheckedSkip,
3906 Checked3Set, Checked3Skip);
3909 return Ret;
3912 //////////////////////////////////////////////////////////////////////////
3914 Private:
3915 Заполняем выпадающий список для ComboBox
3917 int Dialog::SelectFromComboBox(DialogItemEx *CurItem,
3918 DlgEdit *EditLine, // строка редактирования
3919 VMenu *ComboBox) // список строк
3921 CriticalSectionLock Lock(CS);
3922 // char *Str;
3923 FARString strStr;
3924 int EditX1, EditY1, EditX2, EditY2;
3925 int I, Dest, OriginalPos;
3926 unsigned CurFocusPos = FocusPos;
3927 // if((Str=(char*)malloc(MaxLen)) )
3929 EditLine->GetPosition(EditX1, EditY1, EditX2, EditY2);
3931 if (EditX2 - EditX1 < 20)
3932 EditX2 = EditX1 + 20;
3934 SetDropDownOpened(TRUE); // Установим флаг "открытия" комбобокса.
3935 SetComboBoxPos(CurItem);
3936 // Перед отрисовкой спросим об изменении цветовых атрибутов
3937 BYTE RealColors[VMENU_COLOR_COUNT];
3938 FarListColors ListColors = {0};
3939 ListColors.ColorCount = VMENU_COLOR_COUNT;
3940 ListColors.Colors = RealColors;
3941 ComboBox->SetColors(nullptr);
3942 ComboBox->GetColors(&ListColors);
3944 if (DlgProc((HANDLE)this, DN_CTLCOLORDLGLIST, CurItem->ID, (LONG_PTR)&ListColors))
3945 ComboBox->SetColors(&ListColors);
3947 // Выставим то, что есть в строке ввода!
3948 // if(EditLine->GetDropDownBox()) //???
3949 EditLine->GetString(strStr);
3951 if (CurItem->Flags & (DIF_DROPDOWNLIST | DIF_LISTNOAMPERSAND))
3952 HiText2Str(strStr, strStr);
3954 ComboBox->SetSelectPos(ComboBox->FindItem(0, strStr, LIFIND_EXACTMATCH), 1);
3955 ComboBox->Show();
3956 OriginalPos = Dest = ComboBox->GetSelectPos();
3957 CurItem->IFlags.Set(DLGIIF_COMBOBOXNOREDRAWEDIT);
3959 while (!ComboBox->Done()) {
3960 if (!GetDropDownOpened()) {
3961 ComboBox->ProcessKey(KEY_ESC);
3962 continue;
3965 INPUT_RECORD ReadRec;
3966 FarKey Key = ComboBox->ReadInput(&ReadRec);
3968 if (CurItem->IFlags.Check(DLGIIF_COMBOBOXEVENTKEY) && ReadRec.EventType == KEY_EVENT) {
3969 if (DlgProc((HANDLE)this, DN_KEY, FocusPos, Key))
3970 continue;
3971 } else if (CurItem->IFlags.Check(DLGIIF_COMBOBOXEVENTMOUSE) && ReadRec.EventType == MOUSE_EVENT)
3972 if (!DlgProc((HANDLE)this, DN_MOUSEEVENT, 0, (LONG_PTR)&ReadRec.Event.MouseEvent))
3973 continue;
3975 // здесь можно добавить что-то свое, например,
3976 I = ComboBox->GetSelectPos();
3978 if (Key == KEY_TAB) // Tab в списке - аналог Enter
3980 ComboBox->ProcessKey(KEY_ENTER);
3981 continue; //??
3984 if (I != Dest) {
3985 if (!DlgProc((HANDLE)this, DN_LISTCHANGE, CurFocusPos, I))
3986 ComboBox->SetSelectPos(Dest, Dest < I ? -1 : 1); //????
3987 else
3988 Dest = I;
3990 #if 0
3992 // во время навигации по DropDown листу - отобразим ЭТО дело в
3993 // связанной строке
3994 // ВНИМАНИЕ!!!
3995 // Очень медленная реакция!
3996 if (EditLine->GetDropDownBox())
3998 MenuItem *CurCBItem=ComboBox->GetItemPtr();
3999 EditLine->SetString(CurCBItem->Name);
4000 EditLine->Show();
4001 //EditLine->FastShow();
4004 #endif
4007 // обработку multiselect ComboBox
4008 // ...
4009 ComboBox->ProcessInput();
4012 CurItem->IFlags.Clear(DLGIIF_COMBOBOXNOREDRAWEDIT);
4013 ComboBox->ClearDone();
4014 ComboBox->Hide();
4016 if (GetDropDownOpened()) // Закрылся не программным путём?
4017 Dest = ComboBox->Modal::GetExitCode();
4018 else
4019 Dest = -1;
4021 if (Dest == -1)
4022 ComboBox->SetSelectPos(OriginalPos, 0); //????
4024 SetDropDownOpened(FALSE); // Установим флаг "закрытия" комбобокса.
4026 if (Dest < 0) {
4027 Redraw();
4028 // free(Str);
4029 return KEY_ESC;
4032 // ComboBox->GetUserData(Str,MaxLen,Dest);
4033 MenuItemEx *ItemPtr = ComboBox->GetItemPtr(Dest);
4035 if (CurItem->Flags & (DIF_DROPDOWNLIST | DIF_LISTNOAMPERSAND)) {
4036 HiText2Str(strStr, ItemPtr->strName);
4037 EditLine->SetString(strStr);
4038 } else
4039 EditLine->SetString(ItemPtr->strName);
4041 EditLine->SetLeftPos(0);
4042 Redraw();
4043 // free(Str);
4044 return KEY_ENTER;
4046 // return KEY_ESC;
4049 //////////////////////////////////////////////////////////////////////////
4051 Private:
4052 Заполняем выпадающий список из истории
4054 BOOL Dialog::SelectFromEditHistory(DialogItemEx *CurItem, DlgEdit *EditLine, const wchar_t *HistoryName,
4055 FARString &strIStr)
4057 CriticalSectionLock Lock(CS);
4059 if (!EditLine)
4060 return FALSE;
4062 FARString strStr;
4063 int ret = 0;
4064 FARString strRegKey = fmtSavedDialogHistory;
4065 strRegKey+= HistoryName;
4066 History DlgHist(HISTORYTYPE_DIALOG, Opt.DialogsHistoryCount, strRegKey.GetMB(), &Opt.Dialogs.EditHistory,
4067 false);
4068 DlgHist.ResetPosition();
4070 // создание пустого вертикального меню
4071 VMenu HistoryMenu(L"", nullptr, 0, Opt.Dialogs.CBoxMaxHeight,
4072 VMENU_ALWAYSSCROLLBAR | VMENU_COMBOBOX | VMENU_NOTCHANGE);
4073 HistoryMenu.SetFlags(VMENU_SHOWAMPERSAND);
4074 HistoryMenu.SetBoxType(SHORT_SINGLE_BOX);
4075 SetDropDownOpened(TRUE); // Установим флаг "открытия" комбобокса.
4076 // запомним (для прорисовки)
4077 CurItem->ListPtr = &HistoryMenu;
4078 ret = DlgHist.Select(HistoryMenu, Opt.Dialogs.CBoxMaxHeight, this, strStr);
4079 // забудим (не нужен)
4080 CurItem->ListPtr = nullptr;
4081 SetDropDownOpened(FALSE); // Установим флаг "закрытия" комбобокса.
4084 if (ret > 0) {
4085 EditLine->SetString(strStr);
4086 EditLine->SetLeftPos(0);
4087 EditLine->SetClearFlag(0);
4088 Redraw();
4089 return TRUE;
4092 return FALSE;
4095 //////////////////////////////////////////////////////////////////////////
4097 Private:
4098 Работа с историей - добавление и reorder списка
4100 int Dialog::AddToEditHistory(const wchar_t *AddStr, const wchar_t *HistoryName)
4102 CriticalSectionLock Lock(CS);
4104 if (!*AddStr) {
4105 return FALSE;
4108 FARString strRegKey = fmtSavedDialogHistory;
4109 strRegKey+= HistoryName;
4110 History DlgHist(HISTORYTYPE_DIALOG, Opt.DialogsHistoryCount, strRegKey.GetMB(), &Opt.Dialogs.EditHistory,
4111 false);
4112 DlgHist.AddToHistory(AddStr);
4113 return TRUE;
4116 int Dialog::CheckHighlights(WORD CheckSymbol, int StartPos)
4118 CriticalSectionLock Lock(CS);
4119 int Type, I;
4120 DWORD Flags;
4122 if (StartPos < 0)
4123 StartPos = 0;
4125 for (I = StartPos; I < (int)ItemCount; I++) {
4126 Type = Item[I]->Type;
4127 Flags = Item[I]->Flags;
4129 if ((!FarIsEdit(Type) || (Type == DI_COMBOBOX && (Flags & DIF_DROPDOWNLIST)))
4130 && !(Flags & (DIF_SHOWAMPERSAND | DIF_DISABLE | DIF_HIDDEN))) {
4131 const wchar_t *ChPtr = wcschr(Item[I]->strData, L'&');
4133 if (ChPtr) {
4134 WORD Ch = ChPtr[1];
4136 if (Ch && Upper(CheckSymbol) == Upper(Ch))
4137 return I;
4138 } else if (!CheckSymbol)
4139 return I;
4143 return -1;
4146 //////////////////////////////////////////////////////////////////////////
4148 Private:
4149 Если жмакнули Alt-???
4151 int Dialog::ProcessHighlighting(FarKey Key, unsigned FocusPos, int Translate)
4153 CriticalSectionLock Lock(CS);
4154 int Type;
4155 DWORD Flags;
4157 for (unsigned I = 0; I < ItemCount; I++) {
4158 Type = Item[I]->Type;
4159 Flags = Item[I]->Flags;
4161 if ((!FarIsEdit(Type) || (Type == DI_COMBOBOX && (Flags & DIF_DROPDOWNLIST)))
4162 && !(Flags & (DIF_SHOWAMPERSAND | DIF_DISABLE | DIF_HIDDEN)))
4163 if (IsKeyHighlighted(Item[I]->strData, Key, Translate)) {
4164 int DisableSelect = FALSE;
4166 // Если ЭТО: DlgEdit(пред контрол) и DI_TEXT в одну строку, то...
4167 if (I > 0 && Type == DI_TEXT && // DI_TEXT
4168 FarIsEdit(Item[I - 1]->Type) && // и редактор
4169 Item[I]->Y1 == Item[I - 1]->Y1 && // и оба в одну строку
4170 (I + 1 < ItemCount && Item[I]->Y1 != Item[I + 1]->Y1)) // ...и следующий контрол в другой строке
4172 // Сначала сообщим о случившемся факте процедуре обработки диалога, а потом...
4173 if (!DlgProc((HANDLE)this, DN_HOTKEY, I, Key))
4174 break; // сказали не продолжать обработку...
4176 // ... если предыдущий контрол задизаблен или невидим, тогда выходим.
4177 if ((Item[I - 1]->Flags & (DIF_DISABLE | DIF_HIDDEN))) // и не задисаблен
4178 break;
4180 I = ChangeFocus(I, -1, FALSE);
4181 DisableSelect = TRUE;
4182 } else if (Item[I]->Type == DI_TEXT || Item[I]->Type == DI_VTEXT
4183 || Item[I]->Type == DI_SINGLEBOX || Item[I]->Type == DI_DOUBLEBOX) {
4184 if (I + 1 < ItemCount) // ...и следующий контрол
4186 // Сначала сообщим о случившемся факте процедуре обработки диалога, а потом...
4187 if (!DlgProc((HANDLE)this, DN_HOTKEY, I, Key))
4188 break; // сказали не продолжать обработку...
4190 // ... если следующий контрол задизаблен или невидим, тогда выходим.
4191 if ((Item[I + 1]->Flags & (DIF_DISABLE | DIF_HIDDEN))) // и не задисаблен
4192 break;
4194 I = ChangeFocus(I, 1, FALSE);
4195 DisableSelect = TRUE;
4199 // Сообщим о случивщемся факте процедуре обработки диалога
4200 if (!DlgProc((HANDLE)this, DN_HOTKEY, I, Key))
4201 break; // сказали не продолжать обработку...
4203 ChangeFocus2(I);
4204 ShowDialog();
4206 if ((Item[I]->Type == DI_CHECKBOX || Item[I]->Type == DI_RADIOBUTTON)
4207 && (!DisableSelect || (Item[I]->Flags & DIF_MOVESELECT))) {
4208 Do_ProcessSpace();
4209 return TRUE;
4210 } else if (Item[I]->Type == DI_BUTTON) {
4211 ProcessKey(KEY_ENTER, I);
4212 return TRUE;
4214 // при ComboBox`е - "вываливаем" последний //????
4215 else if (Item[I]->Type == DI_COMBOBOX) {
4216 ProcessOpenComboBox(Item[I]->Type, Item[I], I);
4217 // ProcessKey(KEY_CTRLDOWN);
4218 return TRUE;
4221 return TRUE;
4225 return FALSE;
4228 //////////////////////////////////////////////////////////////////////////
4230 функция подравнивания координат edit классов
4232 void Dialog::AdjustEditPos(int dx, int dy)
4234 CriticalSectionLock Lock(CS);
4235 DialogItemEx *CurItem;
4236 int x1, x2, y1, y2;
4238 if (!DialogMode.Check(DMODE_CREATEOBJECTS))
4239 return;
4241 ScreenObject *DialogScrObject;
4243 for (unsigned I = 0; I < ItemCount; I++) {
4244 CurItem = Item[I];
4245 int Type = CurItem->Type;
4247 if ((CurItem->ObjPtr && FarIsEdit(Type)) || (CurItem->ListPtr && Type == DI_LISTBOX)) {
4248 if (Type == DI_LISTBOX)
4249 DialogScrObject = (ScreenObject *)CurItem->ListPtr;
4250 else
4251 DialogScrObject = (ScreenObject *)CurItem->ObjPtr;
4253 DialogScrObject->GetPosition(x1, y1, x2, y2);
4254 x1+= dx;
4255 x2+= dx;
4256 y1+= dy;
4257 y2+= dy;
4258 DialogScrObject->SetPosition(x1, y1, x2, y2);
4262 ProcessCenterGroup();
4265 //////////////////////////////////////////////////////////////////////////
4267 Работа с доп. данными экземпляра диалога
4268 Пока простое копирование (присвоение)
4270 void Dialog::SetDialogData(LONG_PTR NewDataDialog)
4272 DataDialog = NewDataDialog;
4275 //////////////////////////////////////////////////////////////////////////
4277 $ 29.06.2007 yjh\
4278 При расчётах времён копирования проще/надёжнее учитывать время ожидания
4279 пользовательских ответов в одном месте (здесь).
4280 Сброс этой переменной должен осуществляться перед общим началом операции
4282 long WaitUserTime;
4285 $ 11.08.2000 SVS
4286 + Для того, чтобы послать DM_CLOSE нужно переопределить Process
4288 static std::atomic<int> s_in_dialog{0};
4290 void Dialog::Process()
4292 // if(DialogMode.Check(DMODE_SMALLDIALOG))
4293 SetRestoreScreenMode(TRUE);
4294 ClearDone();
4295 InitDialog();
4297 if (ExitCode == -1) {
4298 clock_t btm = 0;
4299 long save = 0;
4300 DialogMode.Set(DMODE_BEGINLOOP);
4302 if (1 == ++s_in_dialog) {
4303 btm = GetProcessUptimeMSec();
4304 save = WaitUserTime;
4305 WaitUserTime = -1;
4308 FrameManager->ExecuteModal(this);
4309 save+= (GetProcessUptimeMSec() - btm);
4311 if (0 == --s_in_dialog)
4312 WaitUserTime = save;
4315 if (pSaveItemEx)
4316 for (unsigned i = 0; i < ItemCount; i++)
4317 DialogItemExToDialogItemEx(Item[i], &pSaveItemEx[i]);
4320 void Dialog::CloseDialog()
4322 CriticalSectionLock Lock(CS);
4323 GetDialogObjectsData();
4325 if (DlgProc((HANDLE)this, DN_CLOSE, ExitCode, 0)) {
4326 DialogMode.Set(DMODE_ENDLOOP);
4327 Hide();
4329 if (DialogMode.Check(DMODE_BEGINLOOP)
4330 && (DialogMode.Check(DMODE_MSGINTERNAL) || FrameManager->ManagerStarted())) {
4331 DialogMode.Clear(DMODE_BEGINLOOP);
4332 FrameManager->DeleteFrame(this);
4335 _DIALOG(CleverSysLog CL(L"Close Dialog"));
4340 $ 17.05.2001 DJ
4341 установка help topic'а и прочие радости, временно перетащенные сюда
4342 из Modal
4344 void Dialog::SetHelp(const wchar_t *Topic)
4346 CriticalSectionLock Lock(CS);
4348 if (HelpTopic)
4349 delete[] HelpTopic;
4351 HelpTopic = nullptr;
4353 if (Topic && *Topic) {
4354 HelpTopic = new (std::nothrow) wchar_t[wcslen(Topic) + 1];
4356 if (HelpTopic)
4357 wcscpy(HelpTopic, Topic);
4361 void Dialog::ShowHelp()
4363 CriticalSectionLock Lock(CS);
4365 if (HelpTopic && *HelpTopic) {
4366 Help::Present(HelpTopic);
4370 void Dialog::ClearDone()
4372 CriticalSectionLock Lock(CS);
4373 ExitCode = -1;
4374 DialogMode.Clear(DMODE_ENDLOOP);
4377 void Dialog::SetExitCode(int Code)
4379 CriticalSectionLock Lock(CS);
4380 ExitCode = Code;
4381 DialogMode.Set(DMODE_ENDLOOP);
4382 // CloseDialog();
4386 $ 19.05.2001 DJ
4387 возвращаем наше название для меню по F12
4389 int Dialog::GetTypeAndName(FARString &strType, FARString &strName)
4391 CriticalSectionLock Lock(CS);
4392 strType = Msg::DialogType;
4393 strName.Clear();
4394 const wchar_t *lpwszTitle = GetDialogTitle();
4396 if (lpwszTitle)
4397 strName = lpwszTitle;
4399 return MODALTYPE_DIALOG;
4402 int Dialog::GetMacroMode()
4404 return MACRO_DIALOG;
4407 int Dialog::FastHide()
4409 return Opt.AllCtrlAltShiftRule & CASR_DIALOG;
4412 void Dialog::ResizeConsole()
4414 CriticalSectionLock Lock(CS);
4416 DialogMode.Set(DMODE_RESIZED);
4418 if (IsVisible()) {
4419 Hide();
4422 COORD c = {(SHORT)(ScrX + 1), (SHORT)(ScrY + 1)};
4423 SendDlgMessage(reinterpret_cast<HANDLE>(this), DN_RESIZECONSOLE, 0, reinterpret_cast<LONG_PTR>(&c));
4425 int x1, y1, x2, y2;
4426 GetPosition(x1, y1, x2, y2);
4427 c.X = Min(x1, ScrX - 1);
4428 c.Y = Min(y1, ScrY - 1);
4429 if (c.X != x1 || c.Y != y1) {
4430 c.X = x1;
4431 c.Y = y1;
4432 SendDlgMessage(reinterpret_cast<HANDLE>(this), DM_MOVEDIALOG, TRUE, reinterpret_cast<LONG_PTR>(&c));
4433 Dialog::SetComboBoxPos();
4437 // void Dialog::OnDestroy()
4439 // /*
4440 // $ 21.04.2002 KM
4441 // Эта функция потеряла своё значение при текущем менеджере
4442 // и системе создания и уничтожения фреймов.
4443 // */
4444 // if(DialogMode.Check(DMODE_RESIZED))
4445 // {
4446 // Frame *BFrame=FrameManager->GetBottomFrame();
4447 // if(BFrame)
4448 // BFrame->UnlockRefresh();
4449 // /*
4450 // $ 21.04.2002 KM
4451 // А вот этот DM_KILLSAVESCREEN здесь только вредит. Удаление
4452 // диалога происходит без восстановления ShadowSaveScr и вот
4453 // они: "артефакты" непрорисовки.
4454 // */
4455 // SendDlgMessage((HANDLE)this,DM_KILLSAVESCREEN,0,0);
4456 // }
4457 // };
4459 LONG_PTR WINAPI Dialog::DlgProc(HANDLE hDlg, int Msg, int Param1, LONG_PTR Param2)
4461 if (DialogMode.Check(DMODE_ENDLOOP))
4462 return 0;
4464 LONG_PTR Result;
4465 FarDialogEvent de = {hDlg, Msg, Param1, Param2, 0};
4467 if (!reinterpret_cast<Dialog *>(hDlg)->CheckDialogMode(DMODE_NOPLUGINS)) {
4468 if (CtrlObject->Plugins.ProcessDialogEvent(DE_DLGPROCINIT, &de))
4469 return de.Result;
4471 Result = RealDlgProc(hDlg, Msg, Param1, Param2);
4472 if (!reinterpret_cast<Dialog *>(hDlg)->CheckDialogMode(DMODE_NOPLUGINS)) {
4473 de.Result = Result;
4474 if (CtrlObject->Plugins.ProcessDialogEvent(DE_DLGPROCEND, &de))
4475 return de.Result;
4477 return Result;
4480 //////////////////////////////////////////////////////////////////////////
4482 $ 28.07.2000 SVS
4483 функция обработки диалога (по умолчанию)
4484 Вот именно эта функция и является последним рубежом обработки диалога.
4485 Т.е. здесь должна быть ВСЯ обработка ВСЕХ сообщений!!!
4487 LONG_PTR WINAPI DefDlgProc(HANDLE hDlg, int Msg, int Param1, LONG_PTR Param2)
4489 _DIALOG(CleverSysLog CL(L"Dialog.DefDlgProc()"));
4490 _DIALOG(SysLog(L"hDlg=%p, Msg=%ls, Param1=%d (0x%08X), Param2=%d (0x%08X)", hDlg, _DLGMSG_ToName(Msg),
4491 Param1, Param1, Param2, Param2));
4493 if (!hDlg || hDlg == INVALID_HANDLE_VALUE)
4494 return 0;
4496 FarDialogEvent de = {hDlg, Msg, Param1, Param2, 0};
4498 if (!reinterpret_cast<Dialog *>(hDlg)->CheckDialogMode(DMODE_NOPLUGINS)) {
4499 if (CtrlObject->Plugins.ProcessDialogEvent(DE_DEFDLGPROCINIT, &de)) {
4500 return de.Result;
4503 Dialog *Dlg = (Dialog *)hDlg;
4504 CriticalSectionLock Lock(Dlg->CS);
4505 DialogItemEx *CurItem = nullptr;
4506 int Type = 0;
4508 switch (Msg) {
4509 case DN_INITDIALOG:
4510 return FALSE; // изменений не было!
4511 case DM_CLOSE:
4512 return TRUE; // согласен с закрытием
4513 case DN_KILLFOCUS:
4514 return -1; // "Согласен с потерей фокуса"
4515 case DN_GOTFOCUS:
4516 return 0; // always 0
4517 case DN_HELP:
4518 return Param2; // что передали, то и...
4519 case DN_DRAGGED:
4520 return TRUE; // согласен с перемещалкой.
4521 case DN_DRAWDIALOGDONE: {
4522 if (Param1 == 1) // Нужно отрисовать "салазки"?
4525 $ 03.08.2000 tran
4526 вывод текста в углу может приводить к ошибкам изображения
4527 1) когда диалог перемещается в угол
4528 2) когда диалог перемещается из угла
4529 сделал вывод красных палочек по углам
4531 Text(Dlg->X1, Dlg->Y1, 0xCE, L"\\");
4532 Text(Dlg->X1, Dlg->Y2, 0xCE, L"/");
4533 Text(Dlg->X2, Dlg->Y1, 0xCE, L"/");
4534 Text(Dlg->X2, Dlg->Y2, 0xCE, L"\\");
4537 return TRUE;
4539 case DN_DRAWDIALOG: {
4540 return TRUE;
4542 case DN_CTLCOLORDIALOG:
4543 return Param2;
4544 case DN_CTLCOLORDLGITEM:
4545 return Param2;
4546 case DN_CTLCOLORDLGLIST:
4547 return FALSE;
4548 case DN_ENTERIDLE:
4549 return 0; // always 0
4550 case DM_GETDIALOGINFO: {
4551 bool Result = false;
4553 if (Param2) {
4554 if (Dlg->IdExist) {
4555 DialogInfo *di = reinterpret_cast<DialogInfo *>(Param2);
4557 if (static_cast<size_t>(di->StructSize) >= offsetof(DialogInfo, Id) + sizeof(di->Id)) {
4558 di->Id = Dlg->Id;
4559 Result = true;
4564 return Result;
4568 // предварительно проверим...
4569 if (Param1 < 0 || (unsigned)Param1 >= Dlg->ItemCount || !Dlg->Item)
4570 return 0;
4572 CurItem = Dlg->Item[Param1];
4573 Type = CurItem->Type;
4575 switch (Msg) {
4576 case DN_MOUSECLICK:
4577 return FALSE;
4578 case DN_DRAWDLGITEM:
4579 return TRUE;
4580 case DN_HOTKEY:
4581 return TRUE;
4582 case DN_EDITCHANGE:
4583 return TRUE;
4584 case DN_BTNCLICK:
4585 return ((Type == DI_BUTTON && !(CurItem->Flags & DIF_BTNNOCLOSE)) ? FALSE : TRUE);
4586 case DN_LISTCHANGE:
4587 return TRUE;
4588 case DN_KEY:
4589 return FALSE;
4590 case DN_MOUSEEVENT:
4591 return TRUE;
4592 case DM_GETSELECTION: // Msg=DM_GETSELECTION, Param1=ID, Param2=*EditorSelect
4593 return FALSE;
4594 case DM_SETSELECTION:
4595 return FALSE;
4598 return 0;
4601 LONG_PTR Dialog::CallDlgProc(int nMsg, int nParam1, LONG_PTR nParam2)
4603 CriticalSectionLock Lock(CS);
4604 return Dialog::DlgProc((HANDLE)this, nMsg, nParam1, nParam2);
4607 //////////////////////////////////////////////////////////////////////////
4608 LONG_PTR SendDlgMessageSynched(HANDLE hDlg, int Msg, int Param1, LONG_PTR Param2)
4610 Dialog *Dlg = (Dialog *)hDlg;
4611 CriticalSectionLock Lock(Dlg->CS);
4612 _DIALOG(CleverSysLog CL(L"Dialog.SendDlgMessage()"));
4613 _DIALOG(SysLog(L"hDlg=%p, Msg=%ls, Param1=%d (0x%08X), Param2=%d (0x%08X)", hDlg, _DLGMSG_ToName(Msg),
4614 Param1, Param1, Param2, Param2));
4616 // Сообщения, касаемые только диалога и не затрагивающие элементы
4617 switch (Msg) {
4618 /*****************************************************************/
4619 case DM_RESIZEDIALOG:
4620 // изменим вызов RESIZE.
4621 Param1 = -1;
4622 /*****************************************************************/
4623 case DM_MOVEDIALOG: {
4624 int W1, H1;
4625 W1 = Dlg->X2 - Dlg->X1 + 1;
4626 H1 = Dlg->Y2 - Dlg->Y1 + 1;
4627 Dlg->OldX1 = Dlg->X1;
4628 Dlg->OldY1 = Dlg->Y1;
4629 Dlg->OldX2 = Dlg->X2;
4630 Dlg->OldY2 = Dlg->Y2;
4632 // переместили
4633 if (Param1 > 0) // абсолютно?
4635 Dlg->X1 = ((COORD *)Param2)->X;
4636 Dlg->Y1 = ((COORD *)Param2)->Y;
4637 Dlg->X2 = W1;
4638 Dlg->Y2 = H1;
4639 Dlg->CheckDialogCoord();
4640 } else if (!Param1) // значит относительно
4642 Dlg->X1+= ((COORD *)Param2)->X;
4643 Dlg->Y1+= ((COORD *)Param2)->Y;
4644 } else // Resize, Param2=width/height
4646 int OldW1, OldH1;
4647 OldW1 = W1;
4648 OldH1 = H1;
4649 W1 = ((COORD *)Param2)->X;
4650 H1 = ((COORD *)Param2)->Y;
4651 Dlg->RealWidth = W1;
4652 Dlg->RealHeight = H1;
4654 if (W1 < OldW1 || H1 < OldH1) {
4655 Dlg->DialogMode.Set(DMODE_DRAWING);
4656 DialogItemEx *Item;
4657 SMALL_RECT Rect;
4659 for (unsigned int I = 0; I < Dlg->ItemCount; I++) {
4660 Item = Dlg->Item[I];
4662 if (Item->Flags & DIF_HIDDEN)
4663 continue;
4665 Rect.Left = Item->X1;
4666 Rect.Top = Item->Y1;
4668 if (Item->X2 >= W1) {
4669 Rect.Right = Item->X2 - (OldW1 - W1);
4670 Rect.Bottom = Item->Y2;
4671 Dlg->SetItemRect(I, &Rect);
4674 if (Item->Y2 >= H1) {
4675 Rect.Right = Item->X2;
4676 Rect.Bottom = Item->Y2 - (OldH1 - H1);
4677 Dlg->SetItemRect(I, &Rect);
4681 Dlg->DialogMode.Clear(DMODE_DRAWING);
4685 // проверили и скорректировали
4686 if (Dlg->X1 + W1 < 0)
4687 Dlg->X1 = -W1 + 1;
4689 if (Dlg->Y1 + H1 < 0)
4690 Dlg->Y1 = -H1 + 1;
4692 if (Dlg->X1 > ScrX)
4693 Dlg->X1 = ScrX;
4695 if (Dlg->Y1 > ScrY)
4696 Dlg->Y1 = ScrY;
4698 Dlg->X2 = Dlg->X1 + W1 - 1;
4699 Dlg->Y2 = Dlg->Y1 + H1 - 1;
4701 if (Param1 > 0) // абсолютно?
4703 Dlg->CheckDialogCoord();
4706 if (Param1 < 0) // размер?
4708 ((COORD *)Param2)->X = Dlg->X2 - Dlg->X1 + 1;
4709 ((COORD *)Param2)->Y = Dlg->Y2 - Dlg->Y1 + 1;
4710 } else {
4711 ((COORD *)Param2)->X = Dlg->X1;
4712 ((COORD *)Param2)->Y = Dlg->Y1;
4715 int I = Dlg->IsVisible(); // && Dlg->DialogMode.Check(DMODE_INITOBJECTS);
4717 if (I)
4718 Dlg->Hide();
4720 // приняли.
4721 Dlg->AdjustEditPos(Dlg->X1 - Dlg->OldX1, Dlg->Y1 - Dlg->OldY1);
4723 if (I)
4724 Dlg->Show(); // только если диалог был виден
4726 return Param2;
4728 /*****************************************************************/
4729 case DM_REDRAW: {
4730 if (Dlg->DialogMode.Check(DMODE_INITOBJECTS))
4731 Dlg->Show();
4733 return 0;
4735 /*****************************************************************/
4736 case DM_ENABLEREDRAW: {
4737 int Prev = Dlg->IsEnableRedraw;
4739 if (Param1 == TRUE)
4740 Dlg->IsEnableRedraw++;
4741 else if (Param1 == FALSE)
4742 Dlg->IsEnableRedraw--;
4744 // Edit::DisableEditOut(!Dlg->IsEnableRedraw?FALSE:TRUE);
4746 if (!Dlg->IsEnableRedraw && Prev != Dlg->IsEnableRedraw)
4747 if (Dlg->DialogMode.Check(DMODE_INITOBJECTS)) {
4748 Dlg->ShowDialog();
4749 // Dlg->Show();
4750 ScrBuf.Flush();
4753 return Prev;
4756 case DM_ENABLEREDRAW:
4758 if(Param1)
4759 Dlg->IsEnableRedraw++;
4760 else
4761 Dlg->IsEnableRedraw--;
4763 if(!Dlg->IsEnableRedraw)
4764 if(Dlg->DialogMode.Check(DMODE_INITOBJECTS))
4766 Dlg->ShowDialog();
4767 ScrBuf.Flush();
4768 // Dlg->Show();
4770 return 0;
4773 /*****************************************************************/
4774 case DM_SHOWDIALOG: {
4775 // if(!Dlg->IsEnableRedraw)
4777 if (Param1) {
4779 $ 20.04.2002 KM
4780 Залочим прорисовку при прятании диалога, в противном
4781 случае ОТКУДА менеджер узнает, что отрисовывать
4782 объект нельзя!
4784 if (!Dlg->IsVisible()) {
4785 Dlg->Unlock();
4786 Dlg->Show();
4788 } else {
4789 if (Dlg->IsVisible()) {
4790 Dlg->Hide();
4791 Dlg->Lock();
4795 return 0;
4797 /*****************************************************************/
4798 case DM_SETDLGDATA: {
4799 LONG_PTR PrewDataDialog = Dlg->DataDialog;
4800 Dlg->DataDialog = Param2;
4801 return PrewDataDialog;
4803 /*****************************************************************/
4804 case DM_GETDLGDATA: {
4805 return Dlg->DataDialog;
4807 /*****************************************************************/
4808 case DM_KEY: {
4809 int *KeyArray = (int *)Param2;
4810 Dlg->DialogMode.Set(DMODE_KEY);
4812 for (unsigned int I = 0; I < (unsigned)Param1; ++I)
4813 Dlg->ProcessKey(KeyArray[I]);
4815 Dlg->DialogMode.Clear(DMODE_KEY);
4816 return 0;
4818 /*****************************************************************/
4819 case DM_CLOSE: {
4820 if (Param1 == -1)
4821 Dlg->ExitCode = Dlg->FocusPos;
4822 else
4823 Dlg->ExitCode = Param1;
4825 Dlg->CloseDialog();
4826 return TRUE; // согласен с закрытием
4828 /*****************************************************************/
4829 case DM_GETDLGRECT: {
4830 if (Param2) {
4831 int x1, y1, x2, y2;
4832 Dlg->GetPosition(x1, y1, x2, y2);
4833 ((SMALL_RECT *)Param2)->Left = x1;
4834 ((SMALL_RECT *)Param2)->Top = y1;
4835 ((SMALL_RECT *)Param2)->Right = x2;
4836 ((SMALL_RECT *)Param2)->Bottom = y2;
4837 return TRUE;
4840 return FALSE;
4842 /*****************************************************************/
4843 case DM_GETDROPDOWNOPENED: // Param1=0; Param2=0
4845 return Dlg->GetDropDownOpened();
4847 /*****************************************************************/
4848 case DM_KILLSAVESCREEN: {
4849 if (Dlg->SaveScr)
4850 Dlg->SaveScr->Discard();
4852 if (Dlg->ShadowSaveScr)
4853 Dlg->ShadowSaveScr->Discard();
4855 return TRUE;
4857 /*****************************************************************/
4859 Msg=DM_ALLKEYMODE
4860 Param1
4861 =-1 - получить состояние
4862 = 0 - выключить
4863 = 1 - включить
4864 Ret = состояние
4866 case DM_ALLKEYMODE: {
4867 if (Param1 == -1)
4868 return IsProcessAssignMacroKey;
4870 BOOL OldIsProcessAssignMacroKey = IsProcessAssignMacroKey;
4871 IsProcessAssignMacroKey = Param1;
4872 return OldIsProcessAssignMacroKey;
4874 /*****************************************************************/
4875 case DM_SETMOUSEEVENTNOTIFY: // Param1 = 1 on, 0 off, -1 - get
4877 int State = Dlg->DialogMode.Check(DMODE_MOUSEEVENT) ? TRUE : FALSE;
4879 if (Param1 != -1) {
4880 if (!Param1)
4881 Dlg->DialogMode.Clear(DMODE_MOUSEEVENT);
4882 else
4883 Dlg->DialogMode.Set(DMODE_MOUSEEVENT);
4886 return State;
4888 /*****************************************************************/
4889 case DN_RESIZECONSOLE: {
4890 return Dlg->CallDlgProc(Msg, Param1, Param2);
4892 case DM_GETDIALOGINFO: {
4893 return DefDlgProc(hDlg, DM_GETDIALOGINFO, Param1, Param2);
4897 /*****************************************************************/
4898 if (Msg >= DM_USER) {
4899 return Dlg->CallDlgProc(Msg, Param1, Param2);
4902 /*****************************************************************/
4903 DialogItemEx *CurItem = nullptr;
4904 int Type = 0;
4905 size_t Len = 0;
4908 предварительно проверим...
4909 $ 09.12.2001 DJ
4910 для DM_USER проверять _не_надо_!
4912 if ((unsigned)Param1 >= Dlg->ItemCount || !Dlg->Item)
4913 return 0;
4915 // CurItem=&Dlg->Item[Param1];
4916 CurItem = Dlg->Item[Param1];
4917 Type = CurItem->Type;
4918 const wchar_t *Ptr = CurItem->strData;
4920 if (FarIsEdit(Type) && CurItem->ObjPtr)
4921 Ptr = const_cast<const wchar_t *>(((DlgEdit *)(CurItem->ObjPtr))->GetStringAddr());
4923 switch (Msg) {
4924 /*****************************************************************/
4925 case DM_LISTSORT: // Param1=ID Param=Direct {0|1}
4926 case DM_LISTADD: // Param1=ID Param2=FarList: ItemsNumber=Count, Items=Src
4927 case DM_LISTADDSTR: // Param1=ID Param2=String
4928 case DM_LISTDELETE: // Param1=ID Param2=FarListDelete: StartIndex=BeginIndex, Count=количество (<=0 - все!)
4929 case DM_LISTGETITEM: // Param1=ID Param2=FarListGetItem: ItemsNumber=Index, Items=Dest
4930 case DM_LISTSET: // Param1=ID Param2=FarList: ItemsNumber=Count, Items=Src
4931 case DM_LISTGETCURPOS: // Param1=ID Param2=FarListPos
4932 case DM_LISTSETCURPOS: // Param1=ID Param2=FarListPos Ret: RealPos
4933 case DM_LISTUPDATE: // Param1=ID Param2=FarList: ItemsNumber=Index, Items=Src
4934 case DM_LISTINFO: // Param1=ID Param2=FarListInfo
4935 case DM_LISTFINDSTRING: // Param1=ID Param2=FarListFind
4936 case DM_LISTINSERT: // Param1=ID Param2=FarListInsert
4937 case DM_LISTGETDATA: // Param1=ID Param2=Index
4938 case DM_LISTSETDATA: // Param1=ID Param2=FarListItemData
4939 case DM_LISTSETTITLES: // Param1=ID Param2=FarListTitles: TitleLen=strlen(Title), BottomLen=strlen(Bottom)
4940 case DM_LISTGETTITLES: // Param1=ID Param2=FarListTitles: TitleLen=strlen(Title), BottomLen=strlen(Bottom)
4941 case DM_LISTGETDATASIZE: // Param1=ID Param2=Index
4942 case DM_LISTSETMOUSEREACTION: // Param1=ID Param2=FARLISTMOUSEREACTIONTYPE Ret=OldSets
4943 case DM_SETCOMBOBOXEVENT: // Param1=ID Param2=FARCOMBOBOXEVENTTYPE Ret=OldSets
4944 case DM_GETCOMBOBOXEVENT: // Param1=ID Param2=0 Ret=Sets
4946 if (Type == DI_LISTBOX || Type == DI_COMBOBOX) {
4947 VMenu *ListBox = CurItem->ListPtr;
4949 if (ListBox) {
4950 int Ret = TRUE;
4952 switch (Msg) {
4953 case DM_LISTINFO: // Param1=ID Param2=FarListInfo
4955 return ListBox->GetVMenuInfo((FarListInfo *)Param2);
4957 case DM_LISTSORT: // Param1=ID Param=Direct {0|1}
4959 ListBox->SortItems((int)Param2);
4960 break;
4962 case DM_LISTFINDSTRING: // Param1=ID Param2=FarListFind
4964 FarListFind *lf = reinterpret_cast<FarListFind *>(Param2);
4965 return ListBox->FindItem(lf->StartIndex, lf->Pattern, lf->Flags);
4967 case DM_LISTADDSTR: // Param1=ID Param2=String
4969 Ret = ListBox->AddItem((wchar_t *)Param2);
4970 break;
4972 case DM_LISTADD: // Param1=ID Param2=FarList: ItemsNumber=Count, Items=Src
4974 FarList *ListItems = (FarList *)Param2;
4976 if (!ListItems)
4977 return FALSE;
4979 Ret = ListBox->AddItem(ListItems);
4980 break;
4982 case DM_LISTDELETE: // Param1=ID Param2=FarListDelete: StartIndex=BeginIndex, Count=количество (<=0 - все!)
4984 int Count;
4985 FarListDelete *ListItems = (FarListDelete *)Param2;
4987 if (!ListItems || (Count = ListItems->Count) <= 0)
4988 ListBox->DeleteItems();
4989 else
4990 ListBox->DeleteItem(ListItems->StartIndex, Count);
4992 break;
4994 case DM_LISTINSERT: // Param1=ID Param2=FarListInsert
4996 if ((Ret = ListBox->InsertItem((FarListInsert *)Param2)) == -1)
4997 return -1;
4999 break;
5001 case DM_LISTUPDATE: // Param1=ID Param2=FarListUpdate: Index=Index, Items=Src
5003 if (Param2 && ListBox->UpdateItem((FarListUpdate *)Param2))
5004 break;
5006 return FALSE;
5008 case DM_LISTGETITEM: // Param1=ID Param2=FarListGetItem: ItemsNumber=Index, Items=Dest
5010 FarListGetItem *ListItems = (FarListGetItem *)Param2;
5012 if (!ListItems)
5013 return FALSE;
5015 MenuItemEx *ListMenuItem;
5017 if ((ListMenuItem = ListBox->GetItemPtr(ListItems->ItemIndex))) {
5018 // ListItems->ItemIndex=1;
5019 FarListItem *Item = &ListItems->Item;
5020 memset(Item, 0, sizeof(FarListItem));
5021 Item->Flags = ListMenuItem->Flags;
5022 Item->Text = ListMenuItem->strName;
5024 if(ListMenuItem->UserDataSize <= sizeof(DWORD)) //???
5025 Item->UserData=ListMenuItem->UserData;
5027 return TRUE;
5030 return FALSE;
5032 case DM_LISTGETDATA: // Param1=ID Param2=Index
5034 if (Param2 < ListBox->GetItemCount())
5035 return (LONG_PTR)ListBox->GetUserData(nullptr, 0, (int)Param2);
5037 return 0;
5039 case DM_LISTGETDATASIZE: // Param1=ID Param2=Index
5041 if (Param2 < ListBox->GetItemCount())
5042 return ListBox->GetUserDataSize((int)Param2);
5044 return 0;
5046 case DM_LISTSETDATA: // Param1=ID Param2=FarListItemData
5048 FarListItemData *ListItems = (FarListItemData *)Param2;
5050 if (ListItems && ListItems->Index < ListBox->GetItemCount()) {
5051 Ret = ListBox->SetUserData(ListItems->Data, ListItems->DataSize,
5052 ListItems->Index);
5054 if (!Ret && ListBox->GetUserData(nullptr, 0, ListItems->Index))
5055 Ret = sizeof(DWORD);
5057 return Ret;
5060 return 0;
5063 $ 02.12.2001 KM
5064 + Сообщение для добавления в список строк, с удалением
5065 уже существующих, т.с. "чистая" установка
5067 case DM_LISTSET: // Param1=ID Param2=FarList: ItemsNumber=Count, Items=Src
5069 FarList *ListItems = (FarList *)Param2;
5071 if (!ListItems)
5072 return FALSE;
5074 ListBox->DeleteItems();
5075 Ret = ListBox->AddItem(ListItems);
5076 break;
5078 // case DM_LISTINS: // Param1=ID Param2=FarList: ItemsNumber=Index, Items=Dest
5079 case DM_LISTSETTITLES: // Param1=ID Param2=FarListTitles
5081 FarListTitles *ListTitle = (FarListTitles *)Param2;
5082 ListBox->SetTitle(ListTitle->Title);
5083 ListBox->SetBottomTitle(ListTitle->Bottom);
5084 break; // return TRUE;
5086 case DM_LISTGETTITLES: // Param1=ID Param2=FarListTitles
5088 if (Param2) {
5089 FarListTitles *ListTitle = (FarListTitles *)Param2;
5090 FARString strTitle, strBottomTitle;
5091 ListBox->GetTitle(strTitle);
5092 ListBox->GetBottomTitle(strBottomTitle);
5094 if (!strTitle.IsEmpty() || !strBottomTitle.IsEmpty()) {
5095 if (ListTitle->Title && ListTitle->TitleLen)
5096 far_wcsncpy((wchar_t *)ListTitle->Title, strTitle,
5097 ListTitle->TitleLen);
5098 else
5099 ListTitle->TitleLen = (int)strTitle.GetLength() + 1;
5101 if (ListTitle->Bottom && ListTitle->BottomLen)
5102 far_wcsncpy((wchar_t *)ListTitle->Bottom, strBottomTitle,
5103 ListTitle->BottomLen);
5104 else
5105 ListTitle->BottomLen = (int)strBottomTitle.GetLength() + 1;
5107 return TRUE;
5111 return FALSE;
5113 case DM_LISTGETCURPOS: // Param1=ID Param2=FarListPos
5115 return Param2 ? ListBox->GetSelectPos((FarListPos *)Param2)
5116 : ListBox->GetSelectPos();
5118 case DM_LISTSETCURPOS: // Param1=ID Param2=FarListPos Ret: RealPos
5120 /* 26.06.2001 KM Подадим перед изменением позиции об этом сообщение */
5121 int CurListPos = ListBox->GetSelectPos();
5122 Ret = ListBox->SetSelectPos((FarListPos *)Param2);
5124 if (Ret != CurListPos)
5125 if (!Dlg->CallDlgProc(DN_LISTCHANGE, Param1, Ret))
5126 Ret = ListBox->SetSelectPos(CurListPos, 1);
5128 break; // т.к. нужно перерисовать!
5130 case DM_LISTSETMOUSEREACTION: // Param1=ID Param2=FARLISTMOUSEREACTIONTYPE Ret=OldSets
5132 int OldSets = CurItem->IFlags.Flags;
5134 if (Param2 == LMRT_ONLYFOCUS) {
5135 CurItem->IFlags.Clear(DLGIIF_LISTREACTIONNOFOCUS);
5136 CurItem->IFlags.Set(DLGIIF_LISTREACTIONFOCUS);
5137 } else if (Param2 == LMRT_NEVER) {
5138 CurItem->IFlags.Clear(DLGIIF_LISTREACTIONNOFOCUS | DLGIIF_LISTREACTIONFOCUS);
5139 // ListBox->ClearFlags(VMENU_MOUSEREACTION);
5140 } else {
5141 CurItem->IFlags.Set(DLGIIF_LISTREACTIONNOFOCUS | DLGIIF_LISTREACTIONFOCUS);
5142 // ListBox->SetFlags(VMENU_MOUSEREACTION);
5145 if ((OldSets & (DLGIIF_LISTREACTIONNOFOCUS | DLGIIF_LISTREACTIONFOCUS))
5146 == (DLGIIF_LISTREACTIONNOFOCUS | DLGIIF_LISTREACTIONFOCUS))
5147 OldSets = LMRT_ALWAYS;
5148 else if (!(OldSets & (DLGIIF_LISTREACTIONNOFOCUS | DLGIIF_LISTREACTIONFOCUS)))
5149 OldSets = LMRT_NEVER;
5150 else
5151 OldSets = LMRT_ONLYFOCUS;
5153 return OldSets;
5155 case DM_GETCOMBOBOXEVENT: // Param1=ID Param2=0 Ret=Sets
5157 return (CurItem->IFlags.Check(DLGIIF_COMBOBOXEVENTKEY) ? CBET_KEY : 0)
5158 | (CurItem->IFlags.Check(DLGIIF_COMBOBOXEVENTMOUSE) ? CBET_MOUSE : 0);
5160 case DM_SETCOMBOBOXEVENT: // Param1=ID Param2=FARCOMBOBOXEVENTTYPE Ret=OldSets
5162 int OldSets = CurItem->IFlags.Flags;
5163 CurItem->IFlags.Clear(DLGIIF_COMBOBOXEVENTKEY | DLGIIF_COMBOBOXEVENTMOUSE);
5165 if (Param2 & CBET_KEY)
5166 CurItem->IFlags.Set(DLGIIF_COMBOBOXEVENTKEY);
5168 if (Param2 & CBET_MOUSE)
5169 CurItem->IFlags.Set(DLGIIF_COMBOBOXEVENTMOUSE);
5171 return OldSets;
5175 // уточнение для DI_COMBOBOX - здесь еще и DlgEdit нужно корректно заполнить
5176 if (!CurItem->IFlags.Check(DLGIIF_COMBOBOXNOREDRAWEDIT) && Type == DI_COMBOBOX
5177 && CurItem->ObjPtr) {
5178 MenuItemEx *ListMenuItem;
5180 if ((ListMenuItem = ListBox->GetItemPtr(ListBox->GetSelectPos()))) {
5181 if (CurItem->Flags & (DIF_DROPDOWNLIST | DIF_LISTNOAMPERSAND))
5182 ((DlgEdit *)(CurItem->ObjPtr))->SetHiString(ListMenuItem->strName);
5183 else
5184 ((DlgEdit *)(CurItem->ObjPtr))->SetString(ListMenuItem->strName);
5186 ((DlgEdit *)(CurItem->ObjPtr))->Select(-1, -1); // снимаем выделение
5190 if (Dlg->DialogMode.Check(DMODE_SHOW) && ListBox->UpdateRequired()) {
5191 Dlg->ShowDialog(Param1);
5192 ScrBuf.Flush();
5195 return Ret;
5199 return FALSE;
5201 /*****************************************************************/
5202 case DM_SETHISTORY: // Param1 = ID, Param2 = LPSTR HistoryName
5204 if (Type == DI_EDIT || Type == DI_FIXEDIT) {
5205 if (Param2 && *(const wchar_t *)Param2) {
5206 CurItem->Flags|= DIF_HISTORY;
5207 CurItem->strHistory = (const wchar_t *)Param2;
5209 if (Type == DI_EDIT && (CurItem->Flags & DIF_USELASTHISTORY)) {
5210 Dlg->ProcessLastHistory(CurItem, Param1);
5212 } else {
5213 CurItem->Flags&= ~DIF_HISTORY;
5214 CurItem->strHistory.Clear();
5217 if (Dlg->DialogMode.Check(DMODE_SHOW)) {
5218 Dlg->ShowDialog(Param1);
5219 ScrBuf.Flush();
5222 return TRUE;
5225 return FALSE;
5227 /*****************************************************************/
5228 case DM_ADDHISTORY: {
5229 if (Param2 && (Type == DI_EDIT || Type == DI_FIXEDIT) && (CurItem->Flags & DIF_HISTORY)) {
5230 return Dlg->AddToEditHistory((const wchar_t *)Param2, CurItem->strHistory);
5233 return FALSE;
5235 /*****************************************************************/
5236 case DM_GETCURSORPOS: {
5237 if (!Param2)
5238 return FALSE;
5240 if (FarIsEdit(Type) && CurItem->ObjPtr) {
5241 ((COORD *)Param2)->X = ((DlgEdit *)(CurItem->ObjPtr))->GetCurPos();
5242 ((COORD *)Param2)->Y = 0;
5243 return TRUE;
5244 } else if (Type == DI_USERCONTROL && CurItem->UCData) {
5245 ((COORD *)Param2)->X = CurItem->UCData->CursorPos.X;
5246 ((COORD *)Param2)->Y = CurItem->UCData->CursorPos.Y;
5247 return TRUE;
5250 return FALSE;
5252 /*****************************************************************/
5253 case DM_SETCURSORPOS: {
5254 if (FarIsEdit(Type) && CurItem->ObjPtr && ((COORD *)Param2)->X >= 0) {
5255 DlgEdit *EditPtr = (DlgEdit *)(CurItem->ObjPtr);
5256 EditPtr->SetCurPos(((COORD *)Param2)->X);
5257 // EditPtr->Show();
5258 Dlg->ShowDialog(Param1);
5259 return TRUE;
5260 } else if (Type == DI_USERCONTROL && CurItem->UCData) {
5262 учтем, что координаты для этого элемента всегда относительные!
5263 и начинаются с 0,0
5265 COORD Coord = *(COORD *)Param2;
5266 Coord.X+= CurItem->X1;
5268 if (Coord.X > CurItem->X2)
5269 Coord.X = CurItem->X2;
5271 Coord.Y+= CurItem->Y1;
5273 if (Coord.Y > CurItem->Y2)
5274 Coord.Y = CurItem->Y2;
5276 // Запомним
5277 CurItem->UCData->CursorPos.X = Coord.X - CurItem->X1;
5278 CurItem->UCData->CursorPos.Y = Coord.Y - CurItem->Y1;
5280 // переместим если надо
5281 if (Dlg->DialogMode.Check(DMODE_SHOW) && Dlg->FocusPos == (unsigned)Param1) {
5282 // что-то одно надо убрать :-)
5283 MoveCursor(Coord.X + Dlg->X1, Coord.Y + Dlg->Y1); // ???
5284 Dlg->ShowDialog(Param1); // ???
5287 return TRUE;
5290 return FALSE;
5292 /*****************************************************************/
5293 case DM_GETEDITPOSITION: {
5294 if (Param2 && FarIsEdit(Type)) {
5295 if (Type == DI_MEMOEDIT) {
5296 // EditorControl(ECTL_GETINFO,(EditorSetPosition *)Param2);
5297 return TRUE;
5298 } else {
5299 EditorSetPosition *esp = (EditorSetPosition *)Param2;
5300 DlgEdit *EditPtr = (DlgEdit *)(CurItem->ObjPtr);
5301 esp->CurLine = 0;
5302 esp->CurPos = EditPtr->GetCurPos();
5303 esp->CurTabPos = EditPtr->GetCellCurPos();
5304 esp->TopScreenLine = 0;
5305 esp->LeftPos = EditPtr->GetLeftPos();
5306 esp->Overtype = EditPtr->GetOvertypeMode();
5307 return TRUE;
5311 return FALSE;
5313 /*****************************************************************/
5314 case DM_SETEDITPOSITION: {
5315 if (Param2 && FarIsEdit(Type)) {
5316 if (Type == DI_MEMOEDIT) {
5317 // EditorControl(ECTL_SETPOSITION,(EditorSetPosition *)Param2);
5318 return TRUE;
5319 } else {
5320 EditorSetPosition *esp = (EditorSetPosition *)Param2;
5321 DlgEdit *EditPtr = (DlgEdit *)(CurItem->ObjPtr);
5322 EditPtr->SetCurPos(esp->CurPos);
5323 EditPtr->SetCellCurPos(esp->CurTabPos);
5324 EditPtr->SetLeftPos(esp->LeftPos);
5325 EditPtr->SetOvertypeMode(esp->Overtype);
5326 Dlg->ShowDialog(Param1);
5327 ScrBuf.Flush();
5328 return TRUE;
5332 return FALSE;
5334 /*****************************************************************/
5335 // Param2=0
5336 // Return MAKELONG(Visible,Size)
5337 case DM_GETCURSORSIZE: {
5338 if (FarIsEdit(Type) && CurItem->ObjPtr) {
5339 bool Visible;
5340 DWORD Size;
5341 ((DlgEdit *)(CurItem->ObjPtr))->GetCursorType(Visible, Size);
5342 return MAKELONG(Visible, Size);
5343 } else if (Type == DI_USERCONTROL && CurItem->UCData) {
5344 return MAKELONG(CurItem->UCData->CursorVisible, CurItem->UCData->CursorSize);
5347 return FALSE;
5349 /*****************************************************************/
5350 // Param2=MAKELONG(Visible,Size)
5351 // Return MAKELONG(OldVisible,OldSize)
5352 case DM_SETCURSORSIZE: {
5353 bool Visible = false;
5354 DWORD Size = 0;
5356 if (FarIsEdit(Type) && CurItem->ObjPtr) {
5357 ((DlgEdit *)(CurItem->ObjPtr))->GetCursorType(Visible, Size);
5358 ((DlgEdit *)(CurItem->ObjPtr))->SetCursorType(LOWORD(Param2) != 0, HIWORD(Param2));
5359 } else if (Type == DI_USERCONTROL && CurItem->UCData) {
5360 Visible = CurItem->UCData->CursorVisible;
5361 Size = CurItem->UCData->CursorSize;
5362 CurItem->UCData->CursorVisible = LOWORD(Param2) != 0;
5363 CurItem->UCData->CursorSize = HIWORD(Param2);
5364 int CCX = CurItem->UCData->CursorPos.X;
5365 int CCY = CurItem->UCData->CursorPos.Y;
5367 if (Dlg->DialogMode.Check(DMODE_SHOW) && Dlg->FocusPos == (unsigned)Param1 && CCX != -1
5368 && CCY != -1)
5369 SetCursorType(CurItem->UCData->CursorVisible, CurItem->UCData->CursorSize);
5372 return MAKELONG(Visible, Size);
5374 /*****************************************************************/
5375 case DN_LISTCHANGE: {
5376 return Dlg->CallDlgProc(Msg, Param1, Param2);
5378 /*****************************************************************/
5379 case DN_EDITCHANGE: {
5380 FarDialogItem Item;
5382 if (!ConvertItemEx(CVTITEM_TOPLUGIN, &Item, CurItem, 1))
5383 return FALSE; // no memory TODO: may be needed diagnostic
5385 INT_PTR I = 0;
5386 if (CurItem->Type == DI_EDIT || CurItem->Type == DI_COMBOBOX || CurItem->Type == DI_FIXEDIT
5387 || CurItem->Type == DI_PSWEDIT) {
5388 reinterpret_cast<DlgEdit *>(CurItem->ObjPtr)->SetCallbackState(false);
5389 const wchar_t *original_PtrData = Item.PtrData;
5390 I = Dlg->CallDlgProc(DN_EDITCHANGE, Param1, (LONG_PTR)&Item);
5391 if (I) {
5392 if (Type == DI_COMBOBOX && CurItem->ListPtr)
5393 CurItem->ListPtr->ChangeFlags(VMENU_DISABLED, CurItem->Flags & DIF_DISABLE);
5395 if (original_PtrData)
5396 free((void *)original_PtrData);
5397 reinterpret_cast<DlgEdit *>(CurItem->ObjPtr)->SetCallbackState(true);
5400 return I;
5402 /*****************************************************************/
5403 case DN_BTNCLICK: {
5404 LONG_PTR Ret = Dlg->CallDlgProc(Msg, Param1, Param2);
5406 if (Ret && (CurItem->Flags & DIF_AUTOMATION) && CurItem->AutoCount && CurItem->AutoPtr) {
5407 DialogItemAutomation *Auto = CurItem->AutoPtr;
5408 Param2%= 3;
5410 for (UINT I = 0; I < CurItem->AutoCount; ++I, ++Auto) {
5411 DWORD NewFlags = Dlg->Item[Auto->ID]->Flags;
5412 Dlg->Item[Auto->ID]->Flags =
5413 (NewFlags & (~Auto->Flags[Param2][1])) | Auto->Flags[Param2][0];
5414 // здесь намеренно в обработчик не посылаются эвенты об изменении
5415 // состояния...
5419 return Ret;
5421 /*****************************************************************/
5422 case DM_GETCHECK: {
5423 if (Type == DI_CHECKBOX || Type == DI_RADIOBUTTON)
5424 return CurItem->Selected;
5426 return 0;
5428 /*****************************************************************/
5429 case DM_SET3STATE: {
5430 if (Type == DI_CHECKBOX) {
5431 int OldState = CurItem->Flags & DIF_3STATE ? TRUE : FALSE;
5433 if (Param2)
5434 CurItem->Flags|= DIF_3STATE;
5435 else
5436 CurItem->Flags&= ~DIF_3STATE;
5438 return OldState;
5441 return 0;
5443 /*****************************************************************/
5444 case DM_SETCHECK: {
5445 if (Type == DI_CHECKBOX) {
5446 int Selected = CurItem->Selected;
5448 if (Param2 == BSTATE_TOGGLE)
5449 Param2 = ++Selected;
5451 if (CurItem->Flags & DIF_3STATE)
5452 Param2%= 3;
5453 else
5454 Param2&= 1;
5456 CurItem->Selected = (int)Param2;
5458 if (Selected != (int)Param2 && Dlg->DialogMode.Check(DMODE_SHOW)) {
5459 // автоматизация
5460 if ((CurItem->Flags & DIF_AUTOMATION) && CurItem->AutoCount && CurItem->AutoPtr) {
5461 DialogItemAutomation *Auto = CurItem->AutoPtr;
5462 Param2%= 3;
5464 for (UINT I = 0; I < CurItem->AutoCount; ++I, ++Auto) {
5465 DWORD NewFlags = Dlg->Item[Auto->ID]->Flags;
5466 Dlg->Item[Auto->ID]->Flags =
5467 (NewFlags & (~Auto->Flags[Param2][1])) | Auto->Flags[Param2][0];
5468 // здесь намеренно в обработчик не посылаются эвенты об изменении
5469 // состояния...
5472 Param1 = -1;
5475 Dlg->ShowDialog(Param1);
5476 ScrBuf.Flush();
5479 return Selected;
5480 } else if (Type == DI_RADIOBUTTON) {
5481 Param1 = Dlg->ProcessRadioButton(Param1);
5483 if (Dlg->DialogMode.Check(DMODE_SHOW)) {
5484 Dlg->ShowDialog();
5485 ScrBuf.Flush();
5488 return Param1;
5491 return 0;
5493 /*****************************************************************/
5494 case DN_DRAWDLGITEM: {
5495 FarDialogItem Item;
5497 if (!ConvertItemEx(CVTITEM_TOPLUGIN, &Item, CurItem, 1))
5498 return FALSE; // no memory TODO: may be needed diagnostic
5500 INT_PTR I = Dlg->CallDlgProc(Msg, Param1, (LONG_PTR)&Item);
5502 if ((Type == DI_LISTBOX || Type == DI_COMBOBOX) && CurItem->ListPtr)
5503 CurItem->ListPtr->ChangeFlags(VMENU_DISABLED, CurItem->Flags & DIF_DISABLE);
5505 if (Item.PtrData)
5506 free((wchar_t *)Item.PtrData);
5508 return I;
5510 /*****************************************************************/
5511 case DM_SETFOCUS: {
5512 if (!CanGetFocus(Type))
5513 return FALSE;
5515 if (Dlg->FocusPos == (unsigned)Param1) // уже и так установлено все!
5516 return TRUE;
5518 Dlg->ChangeFocus2(Param1);
5520 if (Dlg->FocusPos == (unsigned)Param1) {
5521 Dlg->ShowDialog();
5522 return TRUE;
5525 return FALSE;
5527 /*****************************************************************/
5528 case DM_GETFOCUS: // Получить ID фокуса
5530 return Dlg->FocusPos;
5532 /*****************************************************************/
5533 case DM_GETCONSTTEXTPTR: {
5534 return (LONG_PTR)Ptr;
5536 /*****************************************************************/
5537 case DM_GETTEXTPTR:
5539 if (Param2) {
5540 FarDialogItemData IData = {0, (wchar_t *)Param2};
5541 return SendDlgMessage(hDlg, DM_GETTEXT, Param1, (LONG_PTR)&IData);
5544 /*****************************************************************/
5545 case DM_GETTEXT:
5547 if (Param2) // если здесь nullptr, то это еще один способ получить размер
5549 FarDialogItemData *did = (FarDialogItemData *)Param2;
5550 Len = 0;
5552 switch (Type) {
5553 case DI_MEMOEDIT:
5554 break;
5555 case DI_COMBOBOX:
5556 case DI_EDIT:
5557 case DI_PSWEDIT:
5558 case DI_FIXEDIT:
5560 if (!CurItem->ObjPtr)
5561 break;
5563 Ptr = const_cast<const wchar_t *>(((DlgEdit *)(CurItem->ObjPtr))->GetStringAddr());
5564 case DI_TEXT:
5565 case DI_VTEXT:
5566 case DI_SINGLEBOX:
5567 case DI_DOUBLEBOX:
5568 case DI_CHECKBOX:
5569 case DI_RADIOBUTTON:
5570 case DI_BUTTON:
5571 Len = StrLength(Ptr) + 1;
5573 if (Type == DI_BUTTON) {
5574 if (!(CurItem->Flags & DIF_NOBRACKETS)) {
5575 Ptr+= 2;
5576 Len-= 4;
5578 if (CurItem->Flags & DIF_SETSHIELD) {
5579 Ptr+= 2;
5583 if (!did->PtrLength)
5584 did->PtrLength = Len;
5585 else if (Len > did->PtrLength)
5586 Len = did->PtrLength + 1; // Прибавим 1, чтобы учесть нулевой байт.
5588 if (Len > 0 && did->PtrData) {
5589 wmemmove(did->PtrData, Ptr, Len);
5590 did->PtrData[Len - 1] = 0;
5593 break;
5594 case DI_USERCONTROL:
5595 /*did->PtrLength=CurItem->Ptr.PtrLength; BUGBUG
5596 did->PtrData=(char*)CurItem->Ptr.PtrData;*/
5597 break;
5598 case DI_LISTBOX: {
5599 // if(!CurItem->ListPtr)
5600 // break;
5601 // did->PtrLength=CurItem->ListPtr->GetUserData(did->PtrData,did->PtrLength,-1);
5602 break;
5604 default: // подразумеваем, что остались
5605 did->PtrLength = 0;
5606 break;
5609 return Len - (!Len ? 0 : 1);
5612 // здесь умышленно не ставим return, т.к. хотим получить размер
5613 // следовательно сразу должен идти "case DM_GETTEXTLENGTH"!!!
5614 /*****************************************************************/
5615 case DM_GETTEXTLENGTH: {
5616 switch (Type) {
5617 case DI_BUTTON:
5618 Len = StrLength(Ptr) + 1;
5620 if (!(CurItem->Flags & DIF_NOBRACKETS))
5621 Len-= 4;
5623 break;
5624 case DI_USERCONTROL:
5625 // Len=CurItem->Ptr.PtrLength; BUGBUG
5626 break;
5627 case DI_TEXT:
5628 case DI_VTEXT:
5629 case DI_SINGLEBOX:
5630 case DI_DOUBLEBOX:
5631 case DI_CHECKBOX:
5632 case DI_RADIOBUTTON:
5633 Len = StrLength(Ptr) + 1;
5634 break;
5635 case DI_COMBOBOX:
5636 case DI_EDIT:
5637 case DI_PSWEDIT:
5638 case DI_FIXEDIT:
5639 case DI_MEMOEDIT:
5641 if (CurItem->ObjPtr) {
5642 Len = ((DlgEdit *)(CurItem->ObjPtr))->GetLength() + 1;
5643 break;
5646 case DI_LISTBOX: {
5647 Len = 0;
5648 MenuItemEx *ListMenuItem;
5650 if ((ListMenuItem = CurItem->ListPtr->GetItemPtr(-1))) {
5651 Len = (int)ListMenuItem->strName.GetLength() + 1;
5654 break;
5656 default:
5657 Len = 0;
5658 break;
5661 return Len - (!Len ? 0 : 1);
5663 /*****************************************************************/
5664 case DM_SETTEXTPTR: {
5665 if (!Param2)
5666 return 0;
5668 FarDialogItemData IData = {(size_t)StrLength((wchar_t *)Param2), (wchar_t *)Param2};
5669 return SendDlgMessage(hDlg, DM_SETTEXT, Param1, (LONG_PTR)&IData);
5672 case DM_SETTEXTPTRSILENT: {
5673 if (!Param2)
5674 return 0;
5676 if (CurItem->Type != DI_FIXEDIT && CurItem->Type != DI_EDIT)
5677 return 0;
5679 reinterpret_cast<DlgEdit *>(CurItem->ObjPtr)->SetCallbackState(false);
5680 FarDialogItemData IData = {(size_t)StrLength((wchar_t *)Param2), (wchar_t *)Param2};
5681 intptr_t rv = SendDlgMessage(hDlg, DM_SETTEXT, Param1, (LONG_PTR)&IData);
5682 reinterpret_cast<DlgEdit *>(CurItem->ObjPtr)->SetCallbackState(true);
5684 return rv;
5687 /*****************************************************************/
5688 case DM_SETTEXT: {
5689 if (Param2) {
5690 int NeedInit = TRUE;
5691 FarDialogItemData *did = (FarDialogItemData *)Param2;
5693 switch (Type) {
5694 case DI_MEMOEDIT:
5695 break;
5696 case DI_COMBOBOX:
5697 case DI_EDIT:
5698 case DI_TEXT:
5699 case DI_VTEXT:
5700 case DI_SINGLEBOX:
5701 case DI_DOUBLEBOX:
5702 case DI_BUTTON:
5703 case DI_CHECKBOX:
5704 case DI_RADIOBUTTON:
5705 case DI_PSWEDIT:
5706 case DI_FIXEDIT:
5707 case DI_LISTBOX: // меняет только текущий итем
5708 CurItem->strData = did->PtrData;
5709 Len = (int)CurItem->strData.GetLength();
5710 break;
5711 default:
5712 Len = 0;
5713 break;
5716 switch (Type) {
5717 case DI_USERCONTROL:
5718 /*CurItem->Ptr.PtrLength=did->PtrLength;
5719 CurItem->Ptr.PtrData=did->PtrData;
5720 return CurItem->Ptr.PtrLength;*/
5721 return 0; // BUGBUG
5722 case DI_TEXT:
5723 case DI_VTEXT:
5724 case DI_SINGLEBOX:
5725 case DI_DOUBLEBOX:
5727 if (Dlg->DialogMode.Check(DMODE_SHOW)) {
5728 if (!Dlg->DialogMode.Check(DMODE_KEEPCONSOLETITLE))
5729 ConsoleTitle::SetFarTitle(Dlg->GetDialogTitle());
5730 Dlg->ShowDialog(Param1);
5731 ScrBuf.Flush();
5734 return Len - (!Len ? 0 : 1);
5735 case DI_BUTTON:
5736 case DI_CHECKBOX:
5737 case DI_RADIOBUTTON:
5738 break;
5739 case DI_MEMOEDIT:
5740 break;
5741 case DI_COMBOBOX:
5742 case DI_EDIT:
5743 case DI_PSWEDIT:
5744 case DI_FIXEDIT:
5745 NeedInit = FALSE;
5747 if (CurItem->ObjPtr) {
5748 DlgEdit *EditLine = (DlgEdit *)(CurItem->ObjPtr);
5749 int ReadOnly = EditLine->GetReadOnly();
5750 EditLine->SetReadOnly(0);
5751 EditLine->DisableAC();
5752 EditLine->SetString(CurItem->strData);
5753 EditLine->RevertAC();
5754 EditLine->SetReadOnly(ReadOnly);
5756 if (Dlg->DialogMode.Check(DMODE_INITOBJECTS)) // не меняем клеар-флаг, пока не проиницализировались
5757 EditLine->SetClearFlag(0);
5759 EditLine->Select(-1, 0); // снимаем выделение
5760 // ...оно уже снимается в DlgEdit::SetString()
5763 break;
5764 case DI_LISTBOX: // меняет только текущий итем
5766 VMenu *ListBox = CurItem->ListPtr;
5768 if (ListBox) {
5769 FarListUpdate LUpdate;
5770 LUpdate.Index = ListBox->GetSelectPos();
5771 MenuItemEx *ListMenuItem = ListBox->GetItemPtr(LUpdate.Index);
5773 if (ListMenuItem) {
5774 LUpdate.Item.Flags = ListMenuItem->Flags;
5775 LUpdate.Item.Text = Ptr;
5776 SendDlgMessage(hDlg, DM_LISTUPDATE, Param1, (LONG_PTR)&LUpdate);
5779 break;
5780 } else
5781 return 0;
5783 default: // подразумеваем, что остались
5784 return 0;
5787 if (NeedInit)
5788 Dlg->InitDialogObjects(Param1); // переинициализируем элементы диалога
5790 if (Dlg->DialogMode.Check(DMODE_SHOW)) // достаточно ли этого????!!!!
5792 Dlg->ShowDialog(Param1);
5793 ScrBuf.Flush();
5796 // CurItem->strData = did->PtrData;
5797 return CurItem->strData.GetLength(); //???
5800 return 0;
5802 /*****************************************************************/
5803 case DM_SETMAXTEXTLENGTH: {
5804 if ((Type == DI_EDIT || Type == DI_PSWEDIT
5805 || (Type == DI_COMBOBOX && !(CurItem->Flags & DIF_DROPDOWNLIST)))
5806 && CurItem->ObjPtr) {
5807 int MaxLen = ((DlgEdit *)(CurItem->ObjPtr))->GetMaxLength();
5808 // BugZ#628 - Неправильная длина редактируемого текста.
5809 ((DlgEdit *)(CurItem->ObjPtr))->SetMaxLength((int)Param2);
5810 // if (DialogMode.Check(DMODE_INITOBJECTS)) //???
5811 Dlg->InitDialogObjects(Param1); // переинициализируем элементы диалога
5812 if (!Dlg->DialogMode.Check(DMODE_KEEPCONSOLETITLE))
5813 ConsoleTitle::SetFarTitle(Dlg->GetDialogTitle());
5814 return MaxLen;
5817 return 0;
5819 /*****************************************************************/
5820 case DM_GETDLGITEM: {
5821 FarDialogItem *Item = (FarDialogItem *)Param2;
5822 return (LONG_PTR)ConvertItemEx2(Item, CurItem);
5824 /*****************************************************************/
5825 case DM_GETDLGITEMSHORT: {
5826 if (Param2 && ConvertItemEx(CVTITEM_TOPLUGINSHORT, (FarDialogItem *)Param2, CurItem, 1))
5827 return TRUE;
5828 return FALSE;
5830 /*****************************************************************/
5831 case DM_SETDLGITEM:
5832 case DM_SETDLGITEMSHORT: {
5833 if (!Param2)
5834 return FALSE;
5836 if (Type != ((FarDialogItem *)Param2)->Type) // пока нефига менять тип
5837 return FALSE;
5839 // не менять
5840 if (!ConvertItemEx((Msg == DM_SETDLGITEM) ? CVTITEM_FROMPLUGIN : CVTITEM_FROMPLUGINSHORT,
5841 (FarDialogItem *)Param2, CurItem, 1))
5842 return FALSE; // invalid parameters
5844 CurItem->Type = Type;
5846 if ((Type == DI_LISTBOX || Type == DI_COMBOBOX) && CurItem->ListPtr)
5847 CurItem->ListPtr->ChangeFlags(VMENU_DISABLED, CurItem->Flags & DIF_DISABLE);
5849 // еще разок, т.к. данные могли быть изменены
5850 Dlg->InitDialogObjects(Param1);
5851 if (!Dlg->DialogMode.Check(DMODE_KEEPCONSOLETITLE))
5852 ConsoleTitle::SetFarTitle(Dlg->GetDialogTitle());
5854 if (Dlg->DialogMode.Check(DMODE_SHOW)) {
5855 Dlg->ShowDialog(Param1);
5856 ScrBuf.Flush();
5859 return TRUE;
5861 /*****************************************************************/
5863 $ 03.01.2001 SVS
5864 + показать/скрыть элемент
5865 Param2:
5866 -1 - получить состояние
5867 0 - погасить
5868 1 - показать
5869 Return: предыдущее состояние
5871 case DM_SHOWITEM: {
5872 DWORD PrevFlags = CurItem->Flags;
5874 if (Param2 != -1) {
5875 if (Param2)
5876 CurItem->Flags&= ~DIF_HIDDEN;
5877 else
5878 CurItem->Flags|= DIF_HIDDEN;
5880 if (Dlg->DialogMode.Check(DMODE_SHOW)) // && (PrevFlags&DIF_HIDDEN) != (CurItem->Flags&DIF_HIDDEN))//!(CurItem->Flags&DIF_HIDDEN))
5882 if ((CurItem->Flags & DIF_HIDDEN) && Dlg->FocusPos == (unsigned)Param1) {
5883 Param2 = Dlg->ChangeFocus(Param1, 1, TRUE);
5884 Dlg->ChangeFocus2((int)Param2);
5887 // Либо все, либо... только 1
5888 Dlg->ShowDialog(Dlg->GetDropDownOpened() || (CurItem->Flags & DIF_HIDDEN) ? -1 : Param1);
5889 ScrBuf.Flush();
5893 return (PrevFlags & DIF_HIDDEN) ? FALSE : TRUE;
5895 /*****************************************************************/
5896 case DM_SETDROPDOWNOPENED: // Param1=ID; Param2={TRUE|FALSE}
5898 if (!Param2) // Закрываем любой открытый комбобокс или историю
5900 if (Dlg->GetDropDownOpened()) {
5901 Dlg->SetDropDownOpened(FALSE);
5902 WINPORT(Sleep)(10);
5905 return TRUE;
5908 $ 09.12.2001 DJ
5909 у DI_PSWEDIT не бывает хистори!
5911 else if (Param2
5912 && (Type == DI_COMBOBOX
5913 || ((Type == DI_EDIT || Type == DI_FIXEDIT) && (CurItem->Flags & DIF_HISTORY)))) /* DJ $ */
5915 // Открываем заданный в Param1 комбобокс или историю
5916 if (Dlg->GetDropDownOpened()) {
5917 Dlg->SetDropDownOpened(FALSE);
5918 WINPORT(Sleep)(10);
5921 if (SendDlgMessage(hDlg, DM_SETFOCUS, Param1, 0)) {
5922 Dlg->ProcessOpenComboBox(Type, CurItem, Param1); //?? Param1 ??
5923 // Dlg->ProcessKey(KEY_CTRLDOWN);
5924 return TRUE;
5925 } else
5926 return FALSE;
5929 return FALSE;
5931 /* KM $ */
5932 /*****************************************************************/
5933 case DM_SETITEMPOSITION: // Param1 = ID; Param2 = SMALL_RECT
5935 return Dlg->SetItemRect((int)Param1, (SMALL_RECT *)Param2);
5937 /*****************************************************************/
5939 $ 31.08.2000 SVS
5940 + переключение/получение состояния Enable/Disable элемента
5942 case DM_ENABLE: {
5943 DWORD PrevFlags = CurItem->Flags;
5945 if (Param2 != -1) {
5946 if (Param2)
5947 CurItem->Flags&= ~DIF_DISABLE;
5948 else
5949 CurItem->Flags|= DIF_DISABLE;
5951 if ((Type == DI_LISTBOX || Type == DI_COMBOBOX) && CurItem->ListPtr)
5952 CurItem->ListPtr->ChangeFlags(VMENU_DISABLED, CurItem->Flags & DIF_DISABLE);
5955 if (Dlg->DialogMode.Check(DMODE_SHOW)) //???
5957 Dlg->ShowDialog(Param1);
5958 ScrBuf.Flush();
5961 return (PrevFlags & DIF_DISABLE) ? FALSE : TRUE;
5964 case DM_GETCOLOR: {
5965 *(DWORD *)Param2 = (DWORD)Dlg->CtlColorDlgItem(Param1, CurItem);
5966 *(DWORD *)Param2|= (CurItem->Flags & DIF_SETCOLOR);
5967 return TRUE;
5970 case DM_SETCOLOR: {
5971 CurItem->Flags&= ~(DIF_SETCOLOR | DIF_COLORMASK);
5972 CurItem->Flags|= Param2 & (DIF_SETCOLOR | DIF_COLORMASK);
5974 if (Dlg->DialogMode.Check(DMODE_SHOW)) { //???
5975 Dlg->ShowDialog(Param1);
5976 ScrBuf.Flush();
5979 return TRUE;
5982 case DM_GETTRUECOLOR: {
5983 if (!CurItem->TrueColors) {
5984 memset((DialogItemTrueColors *)Param2, 0, sizeof(DialogItemTrueColors));
5985 } else {
5986 *(DialogItemTrueColors *)Param2 = *CurItem->TrueColors;
5988 return TRUE;
5991 case DM_SETTRUECOLOR: {
5992 if (!CurItem->TrueColors) {
5993 CurItem->TrueColors.reset(new DialogItemTrueColors);
5995 *CurItem->TrueColors = *(const DialogItemTrueColors *)Param2;
5996 if (Dlg->InCtlColorDlgItem == 0 && Dlg->DialogMode.Check(DMODE_SHOW)) { //???
5997 Dlg->ShowDialog(Param1);
5998 ScrBuf.Flush();
6000 return TRUE;
6003 case DM_SETREADONLY: {
6004 if (Param2) {
6005 CurItem->Flags|= DIF_READONLY;
6006 } else {
6007 CurItem->Flags&= ~DIF_READONLY;
6009 if (FarIsEdit(Type)) {
6010 DlgEdit *CurItemEdit = (DlgEdit *)CurItem->ObjPtr;
6011 if (CurItemEdit) {
6012 CurItemEdit->SetReadOnly(Param2 ? 1 : 0);
6014 } else {
6015 fprintf(stderr,
6016 "%s: DM_SETREADONLY invoked for non-edit item %u\n",
6017 __FUNCTION__, Param1);
6019 if (Dlg->DialogMode.Check(DMODE_SHOW)) { //???
6020 Dlg->ShowDialog(Param1);
6021 ScrBuf.Flush();
6023 return TRUE;
6026 /*****************************************************************/
6027 // получить позицию и размеры контрола
6028 case DM_GETITEMPOSITION: // Param1=ID, Param2=*SMALL_RECT
6030 if (Param2) {
6031 SMALL_RECT Rect;
6032 if (Dlg->GetItemRect(Param1, Rect)) {
6033 *reinterpret_cast<PSMALL_RECT>(Param2) = Rect;
6034 return TRUE;
6038 return FALSE;
6039 /*****************************************************************/
6040 case DM_SETITEMDATA: {
6041 LONG_PTR PrewDataDialog = CurItem->UserData;
6042 CurItem->UserData = Param2;
6043 return PrewDataDialog;
6045 /*****************************************************************/
6046 case DM_GETITEMDATA: {
6047 return CurItem->UserData;
6049 /*****************************************************************/
6050 case DM_EDITUNCHANGEDFLAG: // -1 Get, 0 - Skip, 1 - Set; Выделение блока снимается.
6052 if (FarIsEdit(Type)) {
6053 DlgEdit *EditLine = (DlgEdit *)(CurItem->ObjPtr);
6054 int ClearFlag = EditLine->GetClearFlag();
6056 if (Param2 >= 0) {
6057 EditLine->SetClearFlag((int)Param2);
6058 EditLine->Select(-1, 0); // снимаем выделение
6060 if (Dlg->DialogMode.Check(DMODE_SHOW)) //???
6062 Dlg->ShowDialog(Param1);
6063 ScrBuf.Flush();
6067 return ClearFlag;
6070 break;
6072 /*****************************************************************/
6073 case DM_GETSELECTION: // Msg=DM_GETSELECTION, Param1=ID, Param2=*EditorSelect
6074 case DM_SETSELECTION: // Msg=DM_SETSELECTION, Param1=ID, Param2=*EditorSelect
6076 if (FarIsEdit(Type) && Param2) {
6077 if (Msg == DM_GETSELECTION) {
6078 EditorSelect *EdSel = (EditorSelect *)Param2;
6079 DlgEdit *EditLine = (DlgEdit *)(CurItem->ObjPtr);
6080 EdSel->BlockStartLine = 0;
6081 EdSel->BlockHeight = 1;
6082 EditLine->GetSelection(EdSel->BlockStartPos, EdSel->BlockWidth);
6084 if (EdSel->BlockStartPos == -1 && !EdSel->BlockWidth)
6085 EdSel->BlockType = BTYPE_NONE;
6086 else {
6087 EdSel->BlockType = BTYPE_STREAM;
6088 EdSel->BlockWidth-= EdSel->BlockStartPos;
6091 return TRUE;
6092 } else {
6093 if (Param2) {
6094 EditorSelect *EdSel = (EditorSelect *)Param2;
6095 DlgEdit *EditLine = (DlgEdit *)(CurItem->ObjPtr);
6097 // EdSel->BlockType=BTYPE_STREAM;
6098 // EdSel->BlockStartLine=0;
6099 // EdSel->BlockHeight=1;
6100 if (EdSel->BlockType == BTYPE_NONE)
6101 EditLine->Select(-1, 0);
6102 else
6103 EditLine->Select(EdSel->BlockStartPos, EdSel->BlockStartPos + EdSel->BlockWidth);
6105 if (Dlg->DialogMode.Check(DMODE_SHOW)) //???
6107 Dlg->ShowDialog(Param1);
6108 ScrBuf.Flush();
6111 return TRUE;
6116 break;
6120 // Все, что сами не отрабатываем - посылаем на обработку обработчику.
6121 return Dlg->CallDlgProc(Msg, Param1, Param2);
6125 $ 28.07.2000 SVS
6126 Посылка сообщения диалогу
6127 Некоторые сообщения эта функция обрабатывает сама, не передавая управление
6128 обработчику диалога.
6130 LONG_PTR WINAPI SendDlgMessage(HANDLE hDlg, int Msg, int Param1, LONG_PTR Param2)
6132 if (!hDlg)
6133 return 0;
6135 return InterThreadCall<LONG_PTR, 0>(std::bind(SendDlgMessageSynched, hDlg, Msg, Param1, Param2));
6138 void Dialog::SetPosition(int X1, int Y1, int X2, int Y2)
6140 CriticalSectionLock Lock(CS);
6142 if (X1 >= 0)
6143 RealWidth = X2 - X1 + 1;
6144 else
6145 RealWidth = X2;
6147 if (Y1 >= 0)
6148 RealHeight = Y2 - Y1 + 1;
6149 else
6150 RealHeight = Y2;
6152 ScreenObject::SetPosition(X1, Y1, X2, Y2);
6154 //////////////////////////////////////////////////////////////////////////
6155 BOOL Dialog::IsInited()
6157 CriticalSectionLock Lock(CS);
6158 return DialogMode.Check(DMODE_INITOBJECTS);
6161 void Dialog::SetComboBoxPos(DialogItemEx *CurItem)
6163 if (GetDropDownOpened()) {
6164 if (!CurItem) {
6165 CurItem = Item[FocusPos];
6167 int EditX1, EditY1, EditX2, EditY2;
6168 ((DlgEdit *)CurItem->ObjPtr)->GetPosition(EditX1, EditY1, EditX2, EditY2);
6170 if (EditX2 - EditX1 < 20)
6171 EditX2 = EditX1 + 20;
6173 if (ScrY - EditY1 < Min(Opt.Dialogs.CBoxMaxHeight, CurItem->ListPtr->GetItemCount()) + 2
6174 && EditY1 > ScrY / 2)
6175 CurItem->ListPtr->SetPosition(EditX1,
6176 Max(0, EditY1 - 1 - Min(Opt.Dialogs.CBoxMaxHeight, CurItem->ListPtr->GetItemCount()) - 1),
6177 EditX2, EditY1 - 1);
6178 else
6179 CurItem->ListPtr->SetPosition(EditX1, EditY1 + 1, EditX2, 0);
6183 bool Dialog::ProcessEvents()
6185 return !DialogMode.Check(DMODE_ENDLOOP);
6188 void Dialog::SetId(const GUID &Id)
6190 this->Id = Id;
6191 IdExist = true;