ReactOS 0.4.15-dev-7788-g1ad9096
treelist.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS GUI first stage setup application
3 * LICENSE: GPL-3.0-or-later (https://spdx.org/licenses/GPL-3.0-or-later)
4 * PURPOSE: Implements a TreeList control: a tree window with columns.
5 * COPYRIGHT: Copyright (C) Anton Zechner (az_software@inode.at) 2007
6 * Copyright (C) Sébastien Kirche (sebastien.kirche@free.fr) 2014
7 *
8 * NOTE: Taken from the TreeList code found at https://github.com/sebkirche/treelist
9 */
10
11//*****************************************************************************
12//*
13//*
14//* TreeListWnd.cpp
15//*
16//*
17//*****************************************************************************
18//
19// This code creates a tree window with a list
20//
21//
22// Copyright (C) Anton Zechner (az_software@inode.at) 2007
23// Copyright (C) Sébastien Kirche (sebastien.kirche@free.fr) 2014
24//
25// TreeListWnd is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
26// Sourcecode which use TreeListWnd must be published. Commercial users
27// must published their code too, or make an licence agreement with me.
28//
29//
30// TreeListWnd wird unter GNU GENERAL PUBLIC LICENSE (GPL) vertreiben.
31// Sourcecode welcher TreeListWnd verwendet muss veröffendlicht werden.
32// Komerzielle Nutzer müssen ihren Code ebenfalls veröffentlichen, oder
33// eine Nutzungsvereinbarung mit mir treffen.
34//
35//
36// Version: 2.04
37//
38#ifdef UNICODE
39#ifndef _UNICODE
40#define _UNICODE
41#endif
42#endif
43
44#if 0
45 #include <stdio.h>
46 #include <windows.h>
47 #include <string.h>
48 #include <malloc.h>
49 #include <tchar.h>
50#else
51 #include "reactos.h"
52#endif
53
54#define new(TYPE, numElems) \
55 HeapAlloc(GetProcessHeap(), 0, (numElems) * sizeof(TYPE))
56#define delete(ptr) \
57 HeapFree(GetProcessHeap(), 0, (ptr))
58
59
60#include "treelist.h"
61
62#ifndef GWLP_USERDATA
63#define GWLP_USERDATA GWL_USERDATA
64#endif
65#ifndef GWLP_WNDPROC
66#define GWLP_WNDPROC GWL_WNDPROC
67#endif
68#ifndef _WIN64
69#ifndef SetWindowLongPtr
70#define SetWindowLongPtr SetWindowLong
71#endif
72#ifndef GetWindowLongPtr
73#define GetWindowLongPtr GetWindowLong
74#endif
75#ifndef DWORD_PTR
76#define DWORD_PTR DWORD
77#endif
78#ifndef LONG_PTR
79#define LONG_PTR LONG
80#endif
81#endif
82#ifdef UNICODE
83#define str_len (unsigned)wcslen
84#define str_cmp wcscmp
85#define str_ncpy wcsncpy
86#define str_ncmp wcsncmp
87#define str_icmp _wcsicmp
88#else
89#define str_len (unsigned)strlen
90#define str_cmp strcmp
91#define str_ncpy strncpy
92#define str_ncmp strncmp
93#define str_icmp _stricmp
94#endif
95#ifndef WM_MOUSEWHEEL
96#define WM_MOUSEWHEEL 0x020A
97#endif
98#ifndef WHEEL_DELTA
99#define WHEEL_DELTA 120
100#endif
101#ifndef MAX_COLUMNS
102#define MAX_COLUMNS 32
103#endif
104#define MAX_COLORS 16
105#define EN_SETTEXT 0x1000
106#define EN_RETURN 0x1578
107#define EN_ESCAPE 0x1579
108#define ID_TOOLTIPCHECK 0x3912
109#define SORT_NOUPDATE 1234567
110#define VK_ISACHAR 0x01000000
111#define FIRST_LINE 0xFFFFFFFE
112#define FROM_HEADER 0x88776655
113#define I_CCB I_CHILDRENCALLBACK
114#define U(h) ((unsigned)(ULONG_PTR)(h))
115#define THEMEIMGLIST ((HIMAGELIST)1)
116#define GetHandle(h) ((TreeListData*)GetWindowLongPtr(h,0))
117#define TVIF_ALL (TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT)
118#define UNLOCK(d) ReleaseSemaphore(d->hSem,1,NULL)
119#define LOCK(d) WaitForSingleObject(d->hSem,INFINITE)
120#define TVIS_EDIT(m) ((1<<m)&((1<<TVAX_EDIT)|(1<<TVAX_COMBO)|(1<<TVAX_STEPED)|(1<<TVAX_CHECKED)))
121#define TVIS_BASEFLAGS (TVIS_EXPANDED|TVIS_EXPANDEDONCE|TVIS_EXPANDPARTIAL|TVIS_SELECTED)
122#define TVIS_TRACKED (TVIX_TRACKED<<16)
123#define TVIS_BKCOLOR (TVIX_BKCOLOR<<16)
124#undef TVIS_FOCUSED
125#define TVIS_FOCUSED (TVIX_FOCUSED<<16)
126#define TVIS_TEXTCOLOR (TVIX_TEXTCOLOR<<16)
127#define TVC_ONLYFOCUS TVIF_ONLYFOCUS
128#define TVC_UNSELECT 0x4000
129#define TVC_DESELECT 0x8000
130#define DEFAULT_IDENT 19
131#define DEFAULT_SHIFT 7
132#ifndef BPBF_COMPATIBLEBITMAP
133#define BPBF_COMPATIBLEBITMAP 0
134#endif
135#ifndef TVP_GLYPH
136#define TVP_GLYPH 2
137#endif
138#ifndef GLPS_CLOSED
139#define GLPS_CLOSED 1
140#endif
141#ifndef GLPS_OPENED
142#define GLPS_OPENED 2
143#endif
144#ifndef BP_CHECKBOX
145#define BP_CHECKBOX 3
146#endif
147#ifndef CBS_UNCHECKEDNORMAL
148#define CBS_UNCHECKEDNORMAL 1
149#endif
150#ifndef CBS_CHECKEDNORMAL
151#define CBS_CHECKEDNORMAL 5
152#endif
153
154
155#define TVAX_NONE (TVAE_NONE >>TVAE_MODEPOS)// No automatic edit
156#define TVAX_EDIT (TVAE_EDIT >>TVAE_MODEPOS)// automatic edit with edit
157#define TVAX_COMBO (TVAE_COMBO >>TVAE_MODEPOS)// automatic edit with ComboBox
158#define TVAX_CBLIST (TVAE_CBLIST >>TVAE_MODEPOS)// automatic edit with ComboListBox
159#define TVAX_STEP (TVAE_STEP >>TVAE_MODEPOS)// Einzelnes Weiterschalten mit Enter
160#define TVAX_STEPED (TVAE_STEPED >>TVAE_MODEPOS)// Einzelnes Weiterschalten mit Enter und Edit
161#define TVAX_CHECK (TVAE_CHECK >>TVAE_MODEPOS)// automatic edit with CheckBox
162#define TVAX_CHECKED (TVAE_CHECKED>>TVAE_MODEPOS)// automatic edit with CheckBox and Edit
163
164#define TVIX_VARBUTTON 0x01 // buttons are not permanent
165#define TVIX_HASBUTTON 0x02 // entry has button
166#define TVIX_HASIMAGE 0x04 // entry has icon
167#define TVIX_TRACKED 0x08 // entry under the cursor
168#define TVIX_TEXTCOLOR 0x10 // entry has its own text color
169#define TVIX_BKCOLOR 0x20 // entry has its own backround color
170#define TVIX_FOCUSED 0x40 // entry has the focus
171
172typedef struct {
173 LPARAM lParam; // LPARAM argument for the item
174 LPTSTR pText; // pointer to the item text
175 UINT uState; // item state
176 int iImage; // item image index
177 int iSelectedImage; // item selected image index
178 unsigned uShowPos; // Ist die Position in der Sichtbarliste (0=unsichtbar)
179 unsigned uFirstChild; // Ist die Nummer des ersten Kind-Eintrages (0=keines)
180 unsigned uLastChild; // Ist die Nummer des letzten Kind-Eintrages (0=keines)
181 unsigned uPrevItem; // Ist die Nummer des vorherigen Eintrages (0=keines)
182 unsigned uNextItem; // Ist die Nummer des nächsten Eintrages (0=keines)
183 unsigned uParent; // Ist die Nummer des Elterneintrages (0=Root)
184 unsigned uLevel; // Ist die Ebene des Eintrages (0=Root)
185 int iTextPixels; // Ist die Breites des Textes in Pixel
186 WORD uTextSize; // Länge des Textes in Zeichen
187 BYTE bCallback; // Sind Bits für Callbacks
188 BYTE bFlags; // Diverse Flags
189 COLORREF uColorText; // Spezielle Textfarbe
190 COLORREF uColorBk; // Spezielle Hintergrundfarbe
191} BaseItem;
192
193typedef struct {
194 LPTSTR pText; // Zeiger auf Tree-Text
195 UINT uState; // Zustand des Eintrages
196 int iImage; // Ist die Nummer des an zu zeigenden Icons
197 int iTextPixels; // Ist die Breites des Textes in Pixel
198 WORD uTextSize; // Länge des Textes in Zeichen
199 BYTE bCallback; // Sind Bits für Callbacks
200 BYTE bFlags; // Diverse Flags
201 COLORREF uColorText; // Spezielle Textfarbe
202 COLORREF uColorBk; // Spezielle Hintergrundfarbe
203} ExtraItem;
204
205typedef struct {
206 void *pCbData; // Data for autoedit
207 INT iCbIcon; // Starting offset for in icon list for autoedit
208 short sSize; // width of the column
209 short sReal; // real width of the column
210 short sMin; // minimum width
211 short sFixed; // fixed width
212 BYTE bMinEx; // the width cannot be less than min width
213 BYTE bWeight; // weight for variable columns
214 BYTE bNext; // Ist die Spalte die nach der eigenen sichtbar ist (gespeicherte Reihenfolge)
215 BYTE bIndex; // Ist die Spalte in der diese Reihe sichtbar ist (sichtbarer Index)
216 BYTE bAlign; // Text alignment
217 BYTE bEdit; // Automaisches Editiern einer Spalte (siehe TVAE_???>>7)
218 BYTE bFlags; // Automaisches Editiern einer Spalte (siehe TVAE_???)
219 BYTE bEnable; // Automaisches einer mit Statebits aktivieren
220 BYTE bCbSize; // Maximum number of entries in the data list
221 BYTE bCbChar; // separator for the data list
222 BYTE bMark; // is column marked ?
223 BYTE bDummy[32 - 23 - sizeof(void *)]; // padding bytes - 32 bytes alignment
224} ColumnData;
225
226typedef struct {
227 HWND hWnd; // handle of the control
228 HANDLE hSem; // access semaphore
229 LPVOID hTheme; // Handle für benutztes Thema (TREELIST)
230 LPVOID hThemeBt; // Handle für benutztes Thema (BUTTON)
231 WNDPROC pProcId3; // Fenster Funktion für ID3 Fenster
232 HIMAGELIST hStates; // Handle der Icon-Liste für States und Overlay
233 HIMAGELIST hImages; // Handle der Icon-Liste
234 HIMAGELIST hChecks; // Handle der Icon-Liste für die Checkboxen in den Spalten
235 HIMAGELIST hSubImg; // Handle der Icon-Liste für die Spalten
236 HIMAGELIST hHeadImg; // Handle for header images
237 HFONT hFontN; // Normal font
238 HFONT hFontB; // Bold fonts
239 HFONT hFontL; // Last used font
240 HFONT hFontT; // Tooltip font
241 HWND hEdit; // Handle des Edit-Fensters
242 HWND hHeader; // Handle des Header Fensters
243 HWND hToolTip; // Handle des Tooltip-Fensters
244 WNDPROC pToolProc; // Alte Fensterfunktion des Tooltips
245 COLORREF uColors[MAX_COLORS]; // 0=Hintergrundfarbe 1=Abwechselnte Farbe 2=Farbe für Trennlinien 3=Textfarbe
246 int iFontHeight; // Ist die Höhe des Fonts
247 int iFontLine; // Ist die Position der Linie beim unterstreichen
248 int iFontOff; // Ist die Position um der ein Text horizontal verschoben wird
249 int iStatesMode; // Die hStates Image-Liste wurde für die Checkboxen erzeugt
250 int iStatesXsize; // Breite der States und Overlay Icons
251 int iStatesYsize; // Höhe der States und Overlay Icons
252 int iChecksMode; // Die hChecks Image-Liste wurde für die Checkboxen erzeugt
253 int iChecksXsize; // Breite der States und Overlay Icons
254 int iChecksYsize; // Höhe der States und Overlay Icons
255 int iImagesXsize; // Breite der Icons
256 int iImagesYsize; // Höhe der Icons
257 int iSubImgMode; // Die SubImg Image-Liste ist nicht die hImages Liste
258 int iSubImgXsize; // Breite der Icons
259 int iSubImgYsize; // Höhe der Icons
260 int iRowHeight; // Ist die Höhe einer Zeile
261 int iAllWeight; // Das Gewicht aller variablen Spalten
262 int iVarSize; // Ist die Breite aller variablen Spalten
263 int iFixSize; // Ist die Breite aller fixen Spalten
264 int iIndent; // Einrückung der Kindereintäge
265 int iShift; // Einrückung der vertikalen Linien
266 int iAutoAdd; // Offset zum Open-Icon für TVS_EX_AUTOEXPANDICON
267 int iMaxSizeX; // Die Größe des breitesten sichtbaren Eintrages
268 unsigned uItemPosCount; // Anzahl der sichtbaren Einträge
269 unsigned *pItemPos; // Liste mit den Offsets der sichtbaren Einträge
270 BaseItem **pTreeItems; // Zeiger auf Item Zeiger
271 ExtraItem **pExtraItems[MAX_COLUMNS - 1]; // Zeiger auf die Spalteneinträge
272 unsigned uTreeItemsMax; // Größe der Liste mit den vorhanden Einträge (alociert um 1 größer)
273 unsigned uTreeItemsCount; // Anzahl der vorhanden Einträge
274 unsigned uNextSeachPos; // Nächste Position zum suchen von freien Einträgen
275 unsigned uUserDataSize; // Ist die Größe der Userdaten in einem Eintrag
276 unsigned uFirstChild; // Ist die Nummer des ersten Kind-Eintrages (0=keines)
277 unsigned uLastChild; // Ist die Nummer des letzten Kind-Eintrages (0=keines)
278 unsigned uSingleSel; // Ist die Nummer des gewählten Eintrages (bei Checkboxen)
279 unsigned uScrollX; // Aktuelle X-Scroll-Position
280 unsigned uScrollY; // Aktuelle Y-Scroll-Position
281 unsigned uSizeX; // Aktuelle X-Fenster-Größe
282 unsigned uSizeY; // Aktuelle Y-Fenster-Größe
283 unsigned uSizeYsub; // Aktuelle Y-Fenster-Größe ohne Header
284 unsigned uStyle; // Ist der aktuele Style des Fensters
285 unsigned uStyleEx; // Erweiterte Sytle-Flags (siehe TVS_EX_???)
286 unsigned uStartPixel; // Ist die Y-Koordinate bei der der erste Eintrag beginnt
287 unsigned uMaxEnties; // Anzahl der sichtbaren Einträge (inkl. halbsichtbare)
288 unsigned uPageEnties; // Anzahl der sichtbaren Einträge (ohne halbsichtbare)
289 unsigned uColumnCount; // Anzahl der Spalten
290 unsigned uColumnCountVar; // Anzahl der variabeln Spalten
291 unsigned uSelectedCount; // Anzahl der ausgewählten Einträge
292 unsigned uSelectedBase; // Ist der Eintrag ab dem gewählt wurde
293 unsigned uSelectedItem; // Ist der Eintrag der gerade gewählt ist
294 unsigned uSelectedSub; // Ist die Spalte die gerade gewählt ist
295 unsigned uFocusItem; // Ist der Eintrag der einen leeren Focus hat
296 unsigned uFocusSub; // Ist die Spalte die einen leeren Focus hat
297 unsigned uToolTipItem; // Ist der ToolTip-Eintrag der gerade gewählt ist
298 unsigned uToolTipShow; // Ist die Zeitverzögerung in 500 ms Schritten für das Tooltip
299 unsigned uToolTipSub; // Ist die ToolTip-Spalte die gerade gewählt ist
300 POINT sToolTipPos; // Ist die globale Koordinate des ToolTips
301 unsigned uEditMode; // Ist der Modus des Editfensters (0=Edit 1=ComboBox 2=ComboBox fix)
302 unsigned uEditItem; // Ist der Eintrag der gerade editiert wird
303 unsigned uEditSub; // Ist die Spalte die gerade editiert wird
304 unsigned uOldXPage; // Alte Werte für X-Scroll-Bar
305 unsigned uOldXCount; // *
306 unsigned uOldYPage; // Alte Werte für Y-Scroll-Bar
307 unsigned uOldYCount; // *
308 unsigned uTrippleB; // Bereite des "..." Strings für den fetten Fonts
309 unsigned uTrippleN; // Bereite des "..." Strings für den normalen Fonts
310 unsigned uTrackedItem; // Ist der Eintrag der unterstrichen werden soll
311 unsigned uTrackedSub; // Ist die Spalte des Eintrages der unterstrichen werden soll
312 unsigned uInsertMark; // Ist der Eintrag mit der Einfügemarke
313 unsigned uMarkedCols; // Anzahl der markierten Spalten
314 unsigned uDragFlags; // Welche Maustasten sind an
315 unsigned uDragItem; // Eintrag für Dragoperation
316 unsigned uDragSub; // Untereintrag für Dragoperation
317 unsigned uLastSel; // Letzte Textauswahl beim Editieren
318 unsigned uLastMove; // Letzte Cursorposition bei WM_MOUSEMOVE
319 unsigned uButtonPos; // Wo wurde eine Maustaste wurde zuletzt gedrückt
320 unsigned uButtonLast; // Wann wurde eine Maustaste wurde zuletzt gedrückt
321 unsigned uToolTipSize; // Textspeichergröße für Tooltip
322 LPTSTR pToolTipText; // Textspeicher für Tooltip
323 TCHAR cTempText1 [260]; // Erster Textpuffer für Callbacks
324 TCHAR cTempText2 [260]; // Zeiter Textpuffer für Callbacks
325 ColumnData aColumn [MAX_COLUMNS]; // Daten der Spalten
326 int aColumnXpos [MAX_COLUMNS + 2]; // Array mit den Positionen der Spalten
327 BYTE aColumnPos [MAX_COLUMNS + 2]; // Array mit Anzeigepositionen der Spalten
328 char cColorChanged[MAX_COLORS ]; // Welche Farbe wurden verändert
329 char cColumnStart; // Wurde das Autoeditiren mit einer WM_CHAR Eingabe gestartet
330 char cFixedHeight; // Ist eine fixe Höhe eingestellt
331 char cLockChanges; // Sperren von Fensteränderungen
332 char cHasRootRow; // Wird gesetzt wenn eine Root-Spalte eingefügt wird
333 char cKeyIgnore; // Die nächste Taste nicht für Sucher verwenden
334 char cClickFlag; // Merker für LBUTTON-DOWN bei Multiselect
335 char cClickEdit; // Merker für LBUTTON-DOWN bei Edit-Click
336 char cIsEnabled; // Ist das Fenster freigegeben
337 char cHasFocus; // Hat das Fenster den Focus
338 char cReSelect; // Soll die Auswahl neu selektiert werden
339 char cGlyphOk; // Die Schaltfäche über Themen zeichnen
340 char cEditCb; // Muss das Edit-Fenster einen Callback aufrufen
341 char cButtonFlag; // Welche Maustaste wurde zuletzt gedrückt
343
349typedef LPVOID (WINAPI *OpenThemeDataT)(HWND hwnd, LPCWSTR pszClassList);
351typedef HRESULT(WINAPI *DrawThemeBackgT)(LPVOID, HDC, int, int, const RECT *, const RECT *);
355
368static HPEN hPatternPen = NULL;
371static LONG lWindowCount = -1;
372#ifndef __REACTOS__
373static RECT sToolRect = { -2, 0, 2, 64};
374#endif
375static TCHAR cKeyData[16];
376static unsigned uKeyLast;
377static unsigned uKeyPos;
378static void TreeListDraw(HWND hWnd, HDC hDc, RECT *pRect);
380static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int iMode);
381static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT *pRect);
382static int TreeListStartNotifyEdit(TreeListData *pData, unsigned uItem, unsigned uSub, WPARAM wParam, LPARAM lParam);
383static int TreeListStartAutoEdit(TreeListData *pData, unsigned uColumn, WPARAM wParam, LPARAM lParam);
386
387//*****************************************************************************
388//*
389//* TreeListRegister
390//*
391//*****************************************************************************
392// Registiert das TreeList Fenster.
393// Ergibt 1 wenn das Fenster erfolgreich registiert wurde.
395
396 static int iIsRegistered = FALSE;
397 WNDCLASSEX sClass;
398
399 OutputDebugString(TEXT("TreeListRegister() - before checking\n"));
400
401 if(iIsRegistered)
402 return TRUE;
403
404 OutputDebugString(TEXT("TreeListRegister() - before registration\n"));
405
406 memset(&sClass, 0, sizeof(sClass));
407 sClass.cbSize = sizeof(sClass);
409 sClass.lpfnWndProc = TreeListProc;
410 sClass.cbClsExtra = 0;
411 sClass.cbWndExtra = sizeof(TreeListData *);
412 sClass.hInstance = hInstance;
413 sClass.hIcon = NULL;
414 sClass.hCursor = LoadCursor(NULL, IDC_ARROW);
415 sClass.hbrBackground = NULL;
416 sClass.lpszMenuName = NULL;
417 sClass.hIconSm = NULL;
419
420 if(!RegisterClassEx(&sClass))
421 return 0;
422
423 OutputDebugString(TEXT("TreeListRegister() - registration done\n"));
424 iIsRegistered = TRUE;
425
426 return TRUE;
427}
428
431}
432
433//*****************************************************************************
434//*
435//* GlobalInit
436//*
437//*****************************************************************************
438static void GlobalInit() {
439
440 LOGBRUSH sLog;
441 long lCount;
442
443
444
446 if(lCount > 0)
447 return;
448
450 sLog.lbStyle = PS_SOLID;
451 sLog.lbHatch = 0;
453
454 if(!hPatternPen) {
455 hPatternPen = CreatePen(PS_DOT, 1, RGB(0, 0, 0));
456 }
457
458
459 if(!hUxThemeDll) {
460 hUxThemeDll = LoadLibrary(_T("UxTheme.dll"));
461 if(hUxThemeDll) {
470 pGetThemeBackgRc = (GetThemeBackgRcT)GetProcAddress(hUxThemeDll, "GetThemeBackgroundContentRect");
473
476 }
477 }
478
479 if(pBufferedPtInit) {
481 }
482
483}
484
485
486//*****************************************************************************
487//*
488//* GlobalDeinit
489//*
490//*****************************************************************************
491static void GlobalDeinit() {
492
493 int lCount;
494
496 if(lCount >= 0)
497 return;
498
499 if(hDefaultFontN) {
502 }
503
504 if(hDefaultFontB) {
507 }
508
509 if(hPatternPen) {
512 }
513
514 if(pBufferedPtExit) {
516 }
517
518}
519
520
521//*****************************************************************************
522//*
523//* SendNotify
524//*
525//*****************************************************************************
526// Sendet eine WM_NOTIFY Nachricht and das Elternfenster
527// pData : Zeiger auf die Fensterdaten
528// pNotify : Zeiger auf die Notify-Daten
529// Ergibt den Rückgabewert der WM_NOTIFY Nachrich
531
532 pNotify->hwndFrom = pData->hWnd;
533 pNotify->idFrom = GetWindowLong(pNotify->hwndFrom, GWL_ID);
534
535 return SendMessage(GetParent(pNotify->hwndFrom), WM_NOTIFY, pNotify->idFrom, (LPARAM)pNotify);
536}
537
538
539//*****************************************************************************
540//*
541//* CallbackEntry
542//*
543//*****************************************************************************
544// Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen
545// pData : Zeiger auf die Fensterdaten
546// pEntry : Zeiger auf den Eintrag
547// uItem : Nummer des Eintrages
548// uFlags : Welche Daten sollen abgefragt werden
549// Ergibt den Rückgabewert der WM_NOTIFY Nachrich
550static void CallbackEntry(TreeListData *pData, BaseItem *pEntry, unsigned uItem, unsigned uFlags, int *iImage, unsigned *uTextSize, LPCTSTR *pText) {
551
552 NMTVDISPINFO sInfo;
553
554 sInfo.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | uFlags;
555 sInfo.item.lParam = pEntry->lParam;
556 sInfo.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
557 sInfo.item.state = pEntry->uState;
558 sInfo.item.stateMask = 0xFFFFFFFF;
559 sInfo.item.iImage = I_IMAGECALLBACK;
560 sInfo.item.iSelectedImage = I_IMAGECALLBACK;
561 sInfo.item.cChildren = I_CHILDRENCALLBACK;
562
563 if(uFlags & TVIF_TEXT) {
564 if(*uTextSize) {
565 pData->cTempText2[sizeof(pData->cTempText2) / sizeof(TCHAR) - 1] = 0;
566 pData->cTempText2[0] = 0;
567 sInfo.item.pszText = pData->cTempText2;
568 sInfo.item.cchTextMax = sizeof(pData->cTempText2) / sizeof(TCHAR) - 1;
569 } else {
570 pData->cTempText1[sizeof(pData->cTempText1) / sizeof(TCHAR) - 1] = 0;
571 pData->cTempText1[0] = 0;
572 sInfo.item.pszText = pData->cTempText1;
573 sInfo.item.cchTextMax = sizeof(pData->cTempText1) / sizeof(TCHAR) - 1;
574 }
575 } else {
576 sInfo.item.pszText = 0;
577 sInfo.item.cchTextMax = 0;
578 }
579
580 sInfo.hdr.hwndFrom = pData->hWnd;
581 sInfo.hdr.idFrom = GetWindowLong(pData->hWnd, GWL_ID);
582 sInfo.hdr.code = TVN_GETDISPINFO;
583
584 UNLOCK(pData);
585 SendMessage(GetParent(sInfo.hdr.hwndFrom), WM_NOTIFY, sInfo.hdr.idFrom, (LPARAM)&sInfo);
586 LOCK(pData);
587
588 if(uFlags & TVIF_IMAGE) {
589 if(!(pEntry->uState & TVIS_SELECTED))
590 *iImage = sInfo.item.iImage;
591 } else
593 if(pEntry->uState & TVIS_SELECTED)
594 *iImage = sInfo.item.iSelectedImage;
595 }
596
597 if(uFlags & TVIF_CHILDREN) {
598 switch(sInfo.item.cChildren) {
599 case 0:
600 pEntry->bFlags &= ~TVIX_HASBUTTON;
601 pEntry->bFlags |= TVIX_VARBUTTON;
602 break;
603
604 case 1:
605 pEntry->bFlags &= ~TVIX_VARBUTTON;
606 pEntry->bFlags |= TVIX_HASBUTTON;
607 break;
608
609 default
610 :
611 pEntry->bFlags |= TVIX_VARBUTTON;
612
613 if(pEntry->uFirstChild)
614 pEntry->bFlags |= TVIX_HASBUTTON;
615 else
616 pEntry->bFlags &= ~TVIX_HASBUTTON;
617 }
618 }
619
620 if(uFlags & TVIF_TEXT) {
621 *pText = sInfo.item.pszText;
622 *uTextSize = str_len(sInfo.item.pszText);
623 pEntry->iTextPixels = 0;
624 }
625
626}
627
628//*****************************************************************************
629//*
630//* CallbackExtra
631//*
632//*****************************************************************************
633// Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen
634// pData : Zeiger auf die Fensterdaten
635// pEntry : Zeiger auf den Eintrag
636// uItem : Nummer des Eintrages
637// uFlags : Welche Daten sollen abgefragt werden
638// Ergibt den Rückgabewert der WM_NOTIFY Nachrich
639static void CallbackExtra(TreeListData *pData, BaseItem *pEntry, ExtraItem *pExtra, unsigned uItem, unsigned uSub, unsigned uFlags, int *iImage, unsigned *uTextSize, LPCTSTR *pText) {
640
641 NMTVDISPINFO sInfo;
642
643 sInfo.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | uFlags;
644 sInfo.item.lParam = pEntry->lParam;
645 sInfo.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
646 sInfo.item.state = pExtra->uState;
647 sInfo.item.state |= (pEntry->uState & TVIS_BASEFLAGS);
648 sInfo.item.stateMask = 0xFFFFFFFF;
649 sInfo.item.iImage = I_IMAGECALLBACK;
650 sInfo.item.iSelectedImage = I_IMAGECALLBACK;
651 sInfo.item.cChildren = uSub;
652
653 if(uFlags & TVIF_TEXT) {
654 pData->cTempText1[sizeof(pData->cTempText1) / sizeof(TCHAR) - 1] = 0;
655 pData->cTempText1[0] = 0;
656 sInfo.item.pszText = pData->cTempText1;
657 sInfo.item.cchTextMax = sizeof(pData->cTempText1) / sizeof(TCHAR) - 1;
658 } else {
659 sInfo.item.pszText = 0;
660 sInfo.item.cchTextMax = 0;
661 }
662
663 sInfo.hdr.hwndFrom = pData->hWnd;
664 sInfo.hdr.idFrom = GetWindowLong(pData->hWnd, GWL_ID);
665 sInfo.hdr.code = TVN_GETDISPINFO;
666
667 UNLOCK(pData);
668 SendMessage(GetParent(sInfo.hdr.hwndFrom), WM_NOTIFY, sInfo.hdr.idFrom, (LPARAM)&sInfo);
669 LOCK(pData);
670
671
672 if(uFlags & TVIF_IMAGE)
673 *iImage = sInfo.item.iImage;
674 if(uFlags & TVIF_TEXT) {
675 *pText = sInfo.item.pszText;
676 *uTextSize = str_len(sInfo.item.pszText);
677 }
678
679}
680
681//*****************************************************************************
682//*
683//* EditProc
684//*
685//*****************************************************************************
686// Ist die Fensterfunktion für das Edit Fenster
688
690 WNDPROC pProc;
691 DWORD dwStop;
692 DWORD dwStart;
693 DWORD dwCount;
694 LRESULT lResult;
695 HWND hParent;
696 HWND hCombo;
697 int iDelta;
698 int iState;
699 int iPos;
700 int iId;
701
702
703 hParent = GetParent(hWnd);
704 iId = GetWindowLong(hWnd, GWL_ID);
705
706 if(iId == 3) {
707 hCombo = hWnd;
708 pData = GetHandle(hParent);
709 pProc = pData->pProcId3;
710 } else {
711 hCombo = hParent;
712 hParent = GetParent(hParent);
713 pData = GetHandle(hParent);
715 }
716
717 if(uMsg == WM_KEYDOWN) {
718 if(wParam == VK_RETURN) {
720 return 0;
721 }
722
723 if(wParam == VK_ESCAPE) {
725 return 0;
726 }
727
728 if((pData->uStyleEx & TVS_EX_STEPOUT) && !(GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
729 switch(wParam) { // Aus Fenster springen
730
731 case VK_UP:
732 if(pData->uEditMode)
733 break;
735 PostMessage(hParent, WM_KEYDOWN, VK_UP , 0x00500001);
736 PostMessage(hParent, WM_KEYUP , VK_UP , 0x00500001);
737 return 0;
738
739 case VK_DOWN:
740 if(pData->uEditMode)
741 break;
743 PostMessage(hParent, WM_KEYDOWN, VK_DOWN, 0x00500001);
744 PostMessage(hParent, WM_KEYUP , VK_DOWN, 0x00500001);
745 return 0;
746
747 case VK_LEFT:
748 if(pData->uEditMode && iId == 3)
749 break;
750 SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwStop);
751 if(dwStart || dwStop)
752 break;
754 PostMessage(hParent, WM_KEYDOWN, VK_LEFT, 0x00500001);
755 PostMessage(hParent, WM_KEYUP , VK_LEFT, 0x00500001);
756 return 0;
757
758 case VK_RIGHT:
759 if(pData->uEditMode && iId == 3)
760 break;
761 SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwStop);
762 dwCount = (DWORD)SendMessage(hWnd, EM_LINELENGTH, 0, 0);
763 if(dwCount > dwStart)
764 break;
765 if(dwCount > dwStop)
766 break;
767
769 PostMessage(hParent, WM_KEYDOWN, VK_RIGHT, 0x00500001);
770 PostMessage(hParent, WM_KEYUP , VK_RIGHT, 0x00500001);
771 return 0;
772 }
773 }
774
775 if(wParam == VK_DOWN && pData->uEditMode) {
776 if(!SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0)) {
777 SendMessage(hCombo, CB_SHOWDROPDOWN, 1, 0);
778 return 0;
779 }
780 }
781 } else
782 if(uMsg == WM_CHAR) {
783 if(wParam == VK_RETURN) {
784 return 0;
785 }
786
787 if(wParam == VK_ESCAPE) {
788 return 0;
789 }
790 } else
791 if(uMsg == WM_COMMAND) {
792 if(wParam == MAKELONG(3, EN_ESCAPE) || wParam == MAKELONG(3, EN_RETURN)) {
794 return 0;
795 }
796 } else
797 if(uMsg == WM_MOUSEWHEEL) {
798 iState = (int)CallWindowProc(pProc, hWnd, CB_GETDROPPEDSTATE, 0, 0);
799 if(iState) {
800 iDelta = (short)HIWORD(wParam);
801 iDelta /= WHEEL_DELTA;
802 iPos = (int)CallWindowProc(pProc, hWnd, CB_GETTOPINDEX, 0, 0);
803 iPos -= iDelta;
804 CallWindowProc(pProc, hWnd, CB_SETTOPINDEX, iPos, 0);
805 return 0;
806 }
807 } else
808 if(uMsg == WM_GETDLGCODE) { // Welche Tasten werden im Dialog benutzt
809 return DLGC_WANTALLKEYS;
810 } else
811 if(uMsg == WM_SETTEXT) {
812 lResult = CallWindowProc(pProc, hWnd, uMsg, wParam, lParam);;
814 return lResult;
815 }
816
817 return CallWindowProc(pProc, hWnd, uMsg, wParam, lParam);
818}
819
820//*****************************************************************************
821//*
822//* ToolProc
823//*
824//*****************************************************************************
825// Ist die Fensterfunktion für das ToolTip Fenster
827
829 POINT sPoint;
830 UINT uPos;
831
832 if(uMsg == WM_SETFOCUS) {
834 return 0;
835 }
836
838
839 if(uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) { // Mausklicks auf Tooltip zum Elternfenster
840 sPoint.x = LOWORD(lParam);
841 sPoint.y = HIWORD(lParam);
842
843 ClientToScreen(hWnd , &sPoint);
844 ScreenToClient(pData->hWnd, &sPoint);
845
846 uPos = MAKELONG(sPoint.x, sPoint.y);
847
848 return TreeListProc(pData->hWnd, uMsg, wParam, uPos);
849 }
850
851 return CallWindowProc(pData->pToolProc, hWnd, uMsg, wParam, lParam);
852}
853
854//*****************************************************************************
855//*
856//* ChangeColSize
857//*
858//*****************************************************************************
859// Ändert die Größe der variablen Spalten
860// pData : Zeiger auf die Fensterdaten
861// iDelta : Ist die Größenänderung in Pixel
862static void ChangeColSize(TreeListData *pData, int iDelta) {
863
864 unsigned uPos;
865 HDITEM sItem;
866 RECT sRect;
867 TV_COLSIZE sNotify;
868 int iWeight;
869 int iValue;
870 int iPoint;
871 int iStart;
872 int iSize;
873 int iRest;
874 int iOff;
875 int iNum;
876 int iCnt;
877 int iAll;
878 int iVar;
879 int iFix;
880
881 sItem.mask = HDI_WIDTH;
882 iAll = pData->iAllWeight;
883 iCnt = pData->uColumnCountVar;
884
885 if(iCnt <= 1) { // Nur eine variable Spalte
886 for(uPos = 0; uPos < pData->uColumnCount; uPos++) {
887 iWeight = pData->aColumn[uPos].bWeight;
888 if(!iWeight)
889 continue;
890
891 iValue = pData->aColumn[uPos].sSize;
892 iValue += iDelta;
893 sItem.cxy = iValue;
894
895 pData->aColumn[uPos].sSize = (short)iValue;
896 pData->iVarSize = iValue;
897
898 if(sItem.cxy < pData->aColumn[uPos].sMin) {
899 sItem.cxy = pData->aColumn[uPos].sMin;
900 }
901
902 if(pData->aColumn[uPos].sReal != sItem.cxy) { // Ändert sich die Breite
903 pData->aColumn[uPos].sReal = (short)sItem.cxy;
904 Header_SetItem(pData->hHeader, uPos, &sItem);
905
906 if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) {
907 sNotify.hdr.code = TVN_COLUMNCHANGED;
908 sNotify.uColumn = uPos;
909 sNotify.uIndex = pData->aColumn[uPos].bIndex;
910 sNotify.uPosX = pData->aColumnXpos[uPos];
911 sNotify.iSize = sItem.cxy;
912
913 UNLOCK(pData);
914 SendNotify(pData, &sNotify.hdr);
915 LOCK(pData);
916 }
917 }
918
919 break;
920 }
921
922 return;
923 }
924
925 if(iDelta > 0)
926 iStart = (pData->uSizeX) % iAll;
927 else
928 iStart = (pData->uSizeX - iDelta) % iAll;
929
930 iOff = 0;
931
932 for(uPos = 0;; uPos++) { // Suchen die Anfangsspalte
933 iWeight = pData->aColumn[uPos].bWeight;
934 if(!iWeight)
935 continue;
936
937 iOff += iWeight;
938 if(iOff > iStart)
939 break;
940 }
941
942
943 iPoint = 0;
944 iSize = iDelta / iAll;
945 iRest = iDelta % iAll;
946 iNum = iRest;
947 iOff -= iStart;
948
949 iWeight = iOff;
950 iValue = pData->aColumn[uPos].sSize;
951 iValue += iSize * iWeight;
952 iPoint += iRest * iWeight;
953 iValue += iPoint / iAll;
954 iNum -= iPoint / iAll;
955 iPoint %= iAll;
956
957 pData->aColumn[uPos].sSize = (short)iValue;
958
959
960 if(iWeight >= pData->aColumn[uPos].bWeight) { // Wurde die ganze Spalte berechnet
961 iCnt--;
962 iOff = 0;
963 }
964
965 while(iCnt > 0) {
966 uPos++;
967
968 if(uPos >= pData->uColumnCount)
969 uPos = 0;
970 iWeight = pData->aColumn[uPos].bWeight;
971 if(!iWeight)
972 continue;
973
974 iValue = pData->aColumn[uPos].sSize;
975
976 iCnt--;
977 if(iCnt) {
978 iValue += iSize * iWeight;
979 iPoint += iRest * iWeight;
980 iValue += iPoint / iAll;
981 iNum -= iPoint / iAll;
982 iPoint %= iAll;
983 } else {
984 iWeight -= iOff;
985 iValue += iSize * iWeight;
986 iValue += iNum;
987 }
988
989 pData->aColumn[uPos].sSize = (short)iValue;
990 }
991
992 iVar = 0;
993 iFix = 0;
994 iCnt = pData->uColumnCountVar;
995
996 for(uPos = 0; iCnt > 0; uPos++) { // Ausgeben der neuen Breiten
997 iWeight = pData->aColumn[uPos].bWeight;
998 if(!iWeight) {
999 iFix += pData->aColumn[uPos].sSize;
1000 continue;
1001 }
1002
1003 iVar += pData->aColumn[uPos].sSize;
1004 sItem.cxy = pData->aColumn[uPos].sSize;
1005
1006 if(sItem.cxy < pData->aColumn[uPos].sMin) {
1007 sItem.cxy = pData->aColumn[uPos].sMin;
1008 }
1009
1010 if(pData->aColumn[uPos].sReal != sItem.cxy) { // Ändert sich die Breite
1011 pData->aColumn[uPos].sReal = (short)sItem.cxy;
1012 Header_SetItem(pData->hHeader, uPos, &sItem);
1013
1014 if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) {
1015 sNotify.hdr.code = TVN_COLUMNCHANGED;
1016 sNotify.uColumn = uPos;
1017 sNotify.uIndex = pData->aColumn[uPos].bIndex;
1018 sNotify.uPosX = pData->aColumnXpos[uPos];
1019 sNotify.iSize = sItem.cxy;
1020
1021 UNLOCK(pData);
1022 SendNotify(pData, &sNotify.hdr);
1023 LOCK(pData);
1024 }
1025 }
1026
1027 iCnt--;
1028 }
1029
1030 pData->iFixSize = iFix;
1031 pData->iVarSize = iVar;
1032
1033 if(iDelta > 0) {
1034 GetClientRect(pData->hHeader, &sRect);
1035 InvalidateRect(pData->hHeader, NULL, FALSE);
1036 }
1037
1038}
1039
1040//*****************************************************************************
1041//*
1042//* CreateToolTip
1043//*
1044//*****************************************************************************
1045// Erzeugt ein ToolTip Fenster
1046// pData : Zeiger auf die Fensterdaten
1048
1049 TOOLINFO sInfo;
1050
1051 if(pData->hToolTip)
1052 return;
1053
1055 pData->pToolProc = (WNDPROC)GetWindowLongPtr(pData->hToolTip, GWLP_WNDPROC);
1056
1057 sInfo.cbSize = sizeof(TOOLINFO);
1058 sInfo.uFlags = TTF_ABSOLUTE | TTF_TRACK | TTF_IDISHWND;
1059 sInfo.hwnd = pData->hWnd;
1060 sInfo.hinst = NULL;
1061 sInfo.uId = (LPARAM)(pData->hWnd);
1062 sInfo.lpszText = LPSTR_TEXTCALLBACK;
1063
1064 GetClientRect(pData->hWnd, &sInfo.rect);
1065 SendMessage(pData->hToolTip, TTM_ADDTOOL, 0, (LPARAM)&sInfo);
1066 SendMessage(pData->hToolTip, TTM_SETMAXTIPWIDTH, 0, 10000);
1067 SetWindowLong(pData->hToolTip, GWL_ID, 2);
1070}
1071
1072//*****************************************************************************
1073//*
1074//* CreateStateImageList
1075//*
1076//*****************************************************************************
1077// Erzeugt eine Image-Liste mit zwei Checkboxen
1078// pData : Zeiger auf die Fensterdaten
1079// iMode : Welche Imageliste soll erzeugt werden (0=hStates 1=hChecks)
1081
1082 BITMAPINFO sInfo;
1083 BYTE aMem[0x1000];
1084 HDC hDcSrc;
1085 HDC hDc;
1086 HBITMAP hBmp;
1087 HBITMAP hBmpNew;
1088 RECT sRect;
1089 int iBits;
1090
1091 if(pOpenThemeData) { // Über Thema zeichnen
1092 if(!pData->hThemeBt) {
1093 pData->hThemeBt = pOpenThemeData(pData->hWnd, L"BUTTON");
1094 }
1095
1096 if(pData->hThemeBt) {
1097 if(iMode) {
1098 if(pData->hChecks && pData->hChecks != THEMEIMGLIST) {
1099 ImageList_Destroy(pData->hChecks);
1100 }
1101
1102 pData->hChecks = THEMEIMGLIST;
1103 pData->iChecksXsize = 16;
1104 pData->iChecksYsize = 16;
1105 pData->iChecksMode = 1;
1106 } else {
1107 if(pData->hStates && pData->hStates != THEMEIMGLIST) {
1108 ImageList_Destroy(pData->hStates);
1109 }
1110
1111 pData->hStates = THEMEIMGLIST;
1112 pData->iStatesXsize = 16;
1113 pData->iStatesYsize = 16;
1114 pData->iStatesMode = 1;
1115 }
1116
1117 return;
1118 }
1119 }
1120
1121 if(iMode) {
1122 if(pData->hChecks && pData->hChecks != THEMEIMGLIST)
1123 return;
1124 } else {
1125 if(pData->hStates && pData->hStates != THEMEIMGLIST)
1126 return;
1127 }
1128
1129 hDcSrc = GetDC(NULL);
1130 hDc = CreateCompatibleDC(NULL);
1131 hBmp = CreateCompatibleBitmap(hDcSrc, 16 * 3, 16);
1132
1133 SelectObject(hDc, hBmp);
1135 SetBkMode(hDc, OPAQUE);
1138 Rectangle(hDc, -1, -1, 16 * 3 + 2, 16 + 2);
1139
1140 sRect.top = 8 - 6;
1141 sRect.bottom = 8 + 7;
1142 sRect.left = 16 * 1 + 8 - 7;
1143 sRect.right = 16 * 1 + 8 + 6;
1144
1146
1147 sRect.left = 16 * 2 + 8 - 7;
1148 sRect.right = 16 * 2 + 8 + 6;
1149
1151
1152 iBits = GetDeviceCaps(hDc, BITSPIXEL);
1153
1154 sInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1155 sInfo.bmiHeader.biWidth = 16 * 3;
1156 sInfo.bmiHeader.biHeight = 16;
1157 sInfo.bmiHeader.biPlanes = 1;
1158 sInfo.bmiHeader.biBitCount = (WORD)iBits;
1160 sInfo.bmiHeader.biSizeImage = 0;
1161 sInfo.bmiHeader.biXPelsPerMeter = 0;
1162 sInfo.bmiHeader.biYPelsPerMeter = 0;
1163 sInfo.bmiHeader.biClrUsed = (iBits > 8) ? 0 : 1 << iBits;;
1164 sInfo.bmiHeader.biClrImportant = (iBits > 8) ? 0 : 1 << iBits;;
1165
1166 GetDIBits(hDc, hBmp, 0, 0 , NULL, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1167 GetDIBits(hDc, hBmp, 0, 16, aMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1168
1169 hBmpNew = CreateCompatibleBitmap(hDc, 16 * 3, 16);
1170
1171 SetDIBits(hDc, hBmpNew, 0, 16, aMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1172
1173 if(iMode == 0) {
1174 pData->hStates = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 3, 14);
1175 pData->iStatesXsize = 16;
1176 pData->iStatesYsize = 16;
1177 pData->iStatesMode = 1;
1178
1180 } else {
1181 pData->hChecks = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 3, 14);
1182 pData->iChecksXsize = 16;
1183 pData->iChecksYsize = 16;
1184 pData->iChecksMode = 1;
1185
1187 }
1188
1189 DeleteObject(hBmpNew);
1190 DeleteObject(hBmp);
1191 DeleteDC(hDc);
1192 ReleaseDC(NULL, hDcSrc);
1193}
1194
1195//*****************************************************************************
1196//*
1197//* CreateDragImage
1198//*
1199//*****************************************************************************
1200// Erzeugt eine Image-Liste mit zwei Checkboxen
1201// pData : Zeiger auf die Fensterdaten
1202// uSub : Ist die Spalte für die das Drag-Image erzeugt werden soll
1203// Ergibt ein Handle mit der Imageliste oder NULL bei einem Fehler
1204static HIMAGELIST CreateDragImage(TreeListData *pData, unsigned uItem, unsigned uSub) {
1205
1206 ExtraItem *pExtra;
1209 BITMAPINFO sInfo;
1210 BYTE *pMem;
1211 HDC hDcSrc;
1212 HDC hDc;
1213 HBITMAP hBmp;
1214 HBITMAP hBmpNew;
1215 RECT sRect;
1216 unsigned uTSize;
1217 int iAdd;
1218 int iBits;
1219 int iWidth;
1220 int iHeigh;
1221 int iImage;
1222 int iYpos;
1223 LPCTSTR pText;
1224
1225 if(uItem > pData->uTreeItemsMax)
1226 return NULL;
1227
1228 pEntry = pData->pTreeItems[uItem];
1229 if(!pEntry)
1230 return 0;
1231
1232 iHeigh = pData->iFontHeight;
1233
1234 if(uSub) { // Image für Extraeintrag erzeugen
1235 if(uSub >= pData->uColumnCount)
1236 return 0;
1237
1238 pExtra = pData->pExtraItems[uSub - 1][uItem];
1239 if(!pExtra) {
1240 pText = _T("????");
1241 uTSize = 4;
1242 iImage = -1;
1243 iWidth = pData->iFontHeight * 4;
1244 } else {
1245 pText = pExtra->pText;
1246 uTSize = pExtra->uTextSize;
1247 iImage = pExtra->iImage;
1248 iWidth = pExtra->iTextPixels;
1249
1250 if(pExtra->bCallback & (TVIF_IMAGE | TVIF_TEXT)) {
1251 CallbackExtra(pData, pEntry, pExtra, uItem, uSub, pExtra->bCallback, &iImage, &uTSize, &pText);
1252 }
1253 }
1254 } else { // Image für Haupteintrag erzeugen
1255 pText = pEntry->pText;
1256 uTSize = pEntry->uTextSize;
1257 iImage = pEntry->iImage;
1258 iWidth = pEntry->iTextPixels;
1259
1260 if(pEntry->bCallback & (TVIF_IMAGE | TVIF_TEXT)) {
1261 CallbackEntry(pData, pEntry, uItem, pEntry->bCallback, &iImage, &uTSize, &pText);
1262 }
1263 }
1264
1265 if(pData->hImages && iImage >= 0) { // Größen für Images anpassen
1266 if(iHeigh < pData->iImagesYsize)
1267 iHeigh = pData->iImagesYsize;
1268 iAdd = pData->iImagesXsize + 2;
1269 iWidth += iAdd;
1270 } else {
1271 iAdd = 0;
1272 iImage = 1;
1273 }
1274
1275 if(iWidth > 240)
1276 iWidth = 240;
1277 if(iHeigh > 32)
1278 iHeigh = 32;
1279
1280 pMem = new(BYTE, iHeigh * (iWidth + 4) * 4 + 1024);
1281 if(!pMem)
1282 return NULL;
1283
1284 hDcSrc = GetDC(NULL);
1285 hDc = CreateCompatibleDC(NULL);
1286 hBmp = CreateCompatibleBitmap(hDcSrc, iWidth, iHeigh);
1287
1288 SelectObject(hDc, hBmp);
1290 SelectObject(hDc, (pEntry->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN);
1291 SetTextColor(hDc, pData->uColors[TVC_TEXT]);
1292 SetBkColor(hDc, RGB(123, 77, 91));
1293
1294 sRect.top = 0;
1295 sRect.bottom = iHeigh;
1296 sRect.left = 0;
1297 sRect.right = iWidth;
1298 iYpos = (iHeigh - pData->iFontHeight) / 2;
1299
1300 ExtTextOut(hDc, iAdd, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sRect, pText, uTSize, NULL);
1301
1302 if(iImage >= 0) {
1304 ImageList_Draw(pData->hImages, iImage, hDc, 0, 0, ILD_TRANSPARENT);
1305 }
1306
1307 iBits = GetDeviceCaps(hDc, BITSPIXEL);
1308
1309 sInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1310 sInfo.bmiHeader.biWidth = iWidth;
1311 sInfo.bmiHeader.biHeight = iHeigh;
1312 sInfo.bmiHeader.biPlanes = 1;
1313 sInfo.bmiHeader.biBitCount = (WORD)iBits;
1315 sInfo.bmiHeader.biSizeImage = 0;
1316 sInfo.bmiHeader.biXPelsPerMeter = 0;
1317 sInfo.bmiHeader.biYPelsPerMeter = 0;
1318 sInfo.bmiHeader.biClrUsed = (iBits > 8) ? 0 : 1 << iBits;;
1319 sInfo.bmiHeader.biClrImportant = (iBits > 8) ? 0 : 1 << iBits;;
1320
1321 GetDIBits(hDc, hBmp, 0, 0 , NULL, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1322 GetDIBits(hDc, hBmp, 0, iHeigh, pMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1323
1324 hBmpNew = CreateCompatibleBitmap(hDc, iWidth, iHeigh);
1325
1326 SetDIBits(hDc, hBmpNew, 0, iHeigh, pMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1327
1328 hList = ImageList_Create(iWidth, iHeigh, ILC_COLORDDB | ILC_MASK, 1, 0);
1329
1330 ImageList_AddMasked(hList, hBmpNew, RGB(123, 77, 91));
1331
1332 DeleteObject(hBmpNew);
1333 DeleteObject(hBmp);
1334 DeleteDC(hDc);
1335 ReleaseDC(NULL, hDcSrc);
1336
1337 delete(pMem);
1338
1339 return hList;
1340}
1341
1342
1343//*****************************************************************************
1344//*
1345//* UpdateColorsList
1346//*
1347//*****************************************************************************
1348// Aktualisiert alle Farben
1349// pData : Zeiger auf die Fensterdaten
1351
1352 unsigned uColOdd;
1353 unsigned uColor;
1354 int iDiff;
1355 int iSum;
1356
1357 if(!pData->cColorChanged[TVC_BK ])
1358 pData->uColors[TVC_BK ] = GetSysColor(COLOR_WINDOW);
1359 if(!pData->cColorChanged[TVC_BOX ])
1361 if(!pData->cColorChanged[TVC_EVEN ])
1362 pData->uColors[TVC_EVEN ] = GetSysColor(COLOR_WINDOW);
1363 if(!pData->cColorChanged[TVC_TEXT ])
1365 if(!pData->cColorChanged[TVC_LINE ])
1367 if(!pData->cColorChanged[TVC_FRAME ])
1369 if(!pData->cColorChanged[TVC_TRACK ])
1370 pData->uColors[TVC_TRACK ] = GetSysColor(COLOR_WINDOWTEXT) ^ RGB(0, 0, 255);
1371 if(!pData->cColorChanged[TVC_INSERT ])
1373 if(!pData->cColorChanged[TVC_ODD ])
1374 pData->uColors[TVC_ODD ] = GetSysColor(COLOR_INFOBK);
1375 if(!pData->cColorChanged[TVC_BOXBG ])
1377 if(!pData->cColorChanged[TVC_COLBK ])
1379 if(!pData->cColorChanged[TVC_COLODD ])
1381 if(!pData->cColorChanged[TVC_COLEVEN])
1383 if(!pData->cColorChanged[TVC_GRAYED ])
1385
1386
1387 if(pData->hTheme && !pData->cColorChanged[TVC_BOXBG] && !pData->cColorChanged[TVC_BOX] && !pData->cColorChanged[TVC_LINE]) {
1388 pData->cGlyphOk = 1;
1389 } else {
1390 pData->cGlyphOk = 0;
1391 }
1392
1393
1394 if(!pData->cColorChanged[TVC_GRAYED]) {
1395 pData->uColors[TVC_GRAYED] = (GetSysColor(COLOR_SCROLLBAR) & 0x00FEFEFE) >> 1;
1396 pData->uColors[TVC_GRAYED] += (GetSysColor(COLOR_WINDOW) & 0x00FEFEFE) >> 1;
1397 }
1398
1399 if(!pData->cColorChanged[TVC_ODD]) {
1400 uColOdd = pData->uColors[TVC_ODD];
1401 iDiff = ((uColOdd) & 0xFF) - ((pData->uColors[TVC_EVEN]) & 0xFF);
1402 iSum = iDiff * iDiff;
1403 iDiff = ((uColOdd >> 8) & 0xFF) - ((pData->uColors[TVC_EVEN] >> 8) & 0xFF);
1404 iSum += iDiff * iDiff;
1405 iDiff = ((uColOdd >> 16) & 0xFF) - ((pData->uColors[TVC_EVEN] >> 16) & 0xFF);
1406 iSum += iDiff * iDiff;
1407
1408 if(iSum < 64) { // Ist die alternierente Farbe fast gleich ?
1409 uColOdd = pData->uColors[TVC_EVEN] & 0x0000FFFF;
1410 uColOdd |= ((pData->uColors[TVC_EVEN] & 0x00FF0000) - 0x00080000) & 0x00FF0000;
1411 }
1412
1413 pData->uColors[TVC_ODD] = uColOdd;
1414 }
1415
1416 if(!pData->cColorChanged[TVC_COLBK]) {
1417 uColor = GetSysColor(COLOR_WINDOW);
1418 if(uColor & 0x00F00000)
1419 uColor -= 0x00100000;
1420 if(uColor & 0x0000F000)
1421 uColor -= 0x00001000;
1422 if(uColor & 0x000000F0)
1423 uColor -= 0x00000010;
1424
1425 pData->uColors[TVC_COLBK] = uColor;
1426 }
1427
1428 if(!pData->cColorChanged[TVC_COLODD]) {
1429 uColor = pData->uColors[TVC_ODD];
1430 if(uColor & 0x00F00000)
1431 uColor -= 0x00100000;
1432 if(uColor & 0x0000F000)
1433 uColor -= 0x00001000;
1434 if(uColor & 0x000000F0)
1435 uColor -= 0x00000010;
1436
1437 pData->uColors[TVC_COLODD] = uColor;
1438 }
1439
1440 if(!pData->cColorChanged[TVC_COLEVEN]) {
1441 uColor = GetSysColor(COLOR_WINDOW);
1442 if(uColor & 0x00F00000)
1443 uColor -= 0x00100000;
1444 if(uColor & 0x0000F000)
1445 uColor -= 0x00001000;
1446 if(uColor & 0x000000F0)
1447 uColor -= 0x00000010;
1448
1449 pData->uColors[TVC_COLEVEN] = uColor;
1450 }
1451
1452 if(!pData->cColorChanged[TVC_MARKODD ])
1453 pData->uColors[TVC_MARKODD ] = ((pData->uColors[TVC_ODD ] >> 3) & 0x1F1F1F) * 7;
1454 if(!pData->cColorChanged[TVC_MARKODD ])
1455 pData->uColors[TVC_MARKODD ] += ((GetSysColor(COLOR_HIGHLIGHT) >> 3) & 0x1F1F1F) * 1;
1456 if(!pData->cColorChanged[TVC_MARKEVEN])
1457 pData->uColors[TVC_MARKEVEN] = ((pData->uColors[TVC_EVEN ] >> 3) & 0x1F1F1F) * 7;
1458 if(!pData->cColorChanged[TVC_MARKEVEN])
1459 pData->uColors[TVC_MARKEVEN] += ((GetSysColor(COLOR_HIGHLIGHT) >> 3) & 0x1F1F1F) * 1;
1460}
1461
1462//*****************************************************************************
1463//*
1464//* UpdateHeight
1465//*
1466//*****************************************************************************
1467// Checks if the row height has changed
1468// pData : pointer to the window data
1469// Returns 1 if changed or 0 else.
1471
1472 int iHeight;
1473 RECT sRect;
1474
1475 if(pData->cFixedHeight)
1476 return 0;
1477
1478 iHeight = 10;
1479
1480 if(pData->hChecks)
1481 if(iHeight < pData->iChecksYsize + 2)
1482 iHeight = pData->iChecksYsize + 2;
1483 if(pData->hStates)
1484 if(iHeight < pData->iStatesYsize + 2)
1485 iHeight = pData->iStatesYsize + 2;
1486 if(iHeight < pData->iSubImgYsize + 2)
1487 iHeight = pData->iSubImgYsize + 2;
1488 if(iHeight < pData->iImagesYsize + 2)
1489 iHeight = pData->iImagesYsize + 2;
1490 if(iHeight < pData->iFontHeight + 2)
1491 iHeight = pData->iFontHeight + 2;
1492 if(pData->uStyleEx & TVS_EX_ITEMLINES)
1493 iHeight++;
1494 if(pData->uStyle & TVS_NONEVENHEIGHT && (iHeight & 1))
1495 iHeight++;
1496 if(pData->iRowHeight == iHeight)
1497 return 0;
1498
1499 pData->iRowHeight = iHeight;
1500
1501 if(pData->uSizeY > pData->uStartPixel) {
1502 pData->uMaxEnties = pData->uSizeY;
1503 pData->uMaxEnties -= pData->uStartPixel;
1504 } else {
1505 pData->uMaxEnties = 0;
1506 }
1507
1508 pData->uPageEnties = pData->uMaxEnties;
1509 pData->uMaxEnties += pData->iRowHeight - 1;
1510 pData->uMaxEnties /= pData->iRowHeight;
1511 pData->uPageEnties /= pData->iRowHeight;
1512
1513 GetClientRect(pData->hWnd, &sRect);
1514 InvalidateRect(pData->hWnd, &sRect, FALSE);
1515
1516 return 1;
1517}
1518
1519//*****************************************************************************
1520//*
1521//* UpdateRect
1522//*
1523//*****************************************************************************
1524// Zeichnet einen Eintrag neu
1525// pData : Zeiger auf die Fensterdaten
1526// uItem : Ist die Nummer des Eintrages
1527// uSub : Ist die Spaltennummer
1528// Ergibt 1 wenn der Eintrag sichtbar war
1529static int UpdateRect(TreeListData *pData, unsigned uItem, unsigned uSub) {
1530
1532 RECT sRect;
1533 UINT uNext;
1534 UINT uPos;
1535
1536 pEntry = pData->pTreeItems[uItem];
1537 if(!pEntry || !pEntry->uShowPos)
1538 return 0; // Ist der Eintrag aufgeklappt
1539
1540 uPos = pEntry->uShowPos - pData->uScrollY - 1;
1541 if(uPos >= pData->uMaxEnties)
1542 return 0; // Eintrag im Fenster sichtbar
1543
1544 uNext = pData->aColumn[uSub].bNext;
1545 sRect.left = pData->aColumnXpos[uSub ];
1546 sRect.left -= pData->uScrollX;
1547 sRect.right = pData->aColumnXpos[uNext];
1548 sRect.right -= pData->uScrollX;
1549 sRect.top = pData->uStartPixel;
1550 sRect.top += pData->iRowHeight * uPos;
1551 sRect.bottom = pData->iRowHeight + sRect.top;
1552
1553 InvalidateRect(pData->hWnd, &sRect, FALSE);
1554
1555 return 1;
1556}
1557
1558//*****************************************************************************
1559//*
1560//* UpdateColRect
1561//*
1562//*****************************************************************************
1563// Zeichnet einen ganze Spalte neu
1564// pData : Zeiger auf die Fensterdaten
1565// uColumn : Die nummer der Spalte
1566// Ergibt 1 wenn der Eintrag sichtbar war
1567static int UpdateColRect(TreeListData *pData, unsigned uColumn) {
1568
1569 RECT sRect;
1570 UINT uNext;
1571
1572 if(uColumn >= pData->uColumnCount)
1573 return 0;
1574
1575 sRect.left = pData->aColumnXpos[uColumn];
1576 sRect.left -= pData->uScrollX;
1577 if(sRect.left > (int)pData->uSizeX)
1578 return 0;
1579
1580 uNext = pData->aColumn[uColumn].bNext;
1581
1582 sRect.right = pData->aColumnXpos[uNext];
1583 sRect.right -= pData->uScrollX;
1584 if(sRect.right < 0)
1585 return 0;
1586
1587 sRect.top = 0;
1588 sRect.bottom = pData->uSizeY;
1589
1590 InvalidateRect(pData->hWnd, &sRect, FALSE);
1591
1592 return 1;
1593}
1594
1595//*****************************************************************************
1596//*
1597//* UpdateRow
1598//*
1599//*****************************************************************************
1600// Zeichnet einen Eintrag über die ganze Zeile neu
1601// pData : Zeiger auf die Fensterdaten
1602// uItem : Ist die Nummer des Eintrages
1603// Ergibt 1 wenn der Eintrag sichtbar war
1604static int UpdateRow(TreeListData *pData, unsigned uItem) {
1605
1607 RECT sRect;
1608 unsigned uPos;
1609
1610 pEntry = pData->pTreeItems[uItem];
1611 if(!pEntry || !pEntry->uShowPos)
1612 return 0; // Ist der Eintrag aufgeklappt
1613
1614 uPos = pEntry->uShowPos - pData->uScrollY - 1;
1615 if(uPos >= pData->uMaxEnties)
1616 return 0; // Eintrag im Fenster sichtbar
1617
1618 sRect.left = 0;
1619 sRect.right = pData->uSizeX;
1620 sRect.top = pData->uStartPixel;
1621 sRect.top += pData->iRowHeight * uPos;
1622 sRect.bottom = pData->iRowHeight + sRect.top;
1623 InvalidateRect(pData->hWnd, &sRect, FALSE);
1624
1625 return 1;
1626}
1627
1628//*****************************************************************************
1629//*
1630//* UpdateView
1631//*
1632//*****************************************************************************
1633// Redraw the whole window
1634// pData : Zeiger auf die Fensterdaten
1635// Ergibt 1 wenn der Eintrag sichtbar war
1637
1638 RECT sRect;
1639
1640 GetClientRect(pData->hWnd, &sRect);
1641 sRect.top = pData->uStartPixel;
1642 InvalidateRect(pData->hWnd, &sRect, FALSE);
1643
1644 if(pData->hHeader && ((pData->uStyleEx & TVS_EX_HIDEHEADERS) == 0)){
1645 GetClientRect(pData->hHeader, &sRect);
1646 InvalidateRect(pData->hHeader, &sRect, FALSE);
1647 }
1648}
1649
1650//*****************************************************************************
1651//*
1652//* UpdateScrollX
1653//*
1654//*****************************************************************************
1655// Aktualisiert die X-Scroolbar
1656// pData : Zeiger auf die Fensterdaten
1657// Ergibt 1 wenn der sich Einstellungen verändert haben
1659
1660 SCROLLINFO sInfo;
1661 unsigned uSize;
1662 unsigned uCols;
1663
1664 uCols = pData->uColumnCount;
1665 if(uCols)
1666 uSize = pData->aColumnXpos[uCols] - 1;
1667 else
1668 uSize = pData->iMaxSizeX - 1;
1669
1670
1671 if(pData->uOldXCount == uSize)
1672 if(pData->uOldXPage == pData->uSizeX) {
1673 return;
1674 }
1675
1676 pData->uOldXPage = pData->uSizeX;
1677 pData->uOldXCount = uSize;
1678
1679 UNLOCK(pData);
1680
1681 sInfo.cbSize = sizeof(SCROLLINFO);
1682 sInfo.fMask = SIF_ALL;
1683 sInfo.nMin = 0;
1684 sInfo.nMax = uSize;
1685 sInfo.nPage = pData->uSizeX;
1686 sInfo.nPos = pData->uScrollX;
1687 sInfo.nTrackPos = 0;
1688
1689 if(pData->uStyle & TVS_NOSCROLL) {
1690 sInfo.nMax = 0;
1691 } else
1692 if(pData->uStyleEx & TVS_EX_AUTOHSCROLL) {
1693 sInfo.nMax = 0;
1694 } else
1695 if(sInfo.nMax > 0) {
1696 sInfo.nMax--;
1697 }
1698
1699
1700 if((int)sInfo.nPage >= sInfo.nMax && pData->uScrollX > 0) {
1701 sInfo.nPos = 0;
1702 pData->uScrollX = 0;
1703
1705
1706 if(pData->hHeader) {
1707 MoveWindow(pData->hHeader, 0, 0, pData->uSizeX, pData->uStartPixel, TRUE);
1708 }
1709 }
1710
1711 SetScrollInfo(pData->hWnd, SB_HORZ, &sInfo, TRUE);
1712
1713 LOCK(pData);
1714}
1715
1716//*****************************************************************************
1717//*
1718//* UpdateScrollY
1719//*
1720//*****************************************************************************
1721// Aktualisiert die Y-Scroolbar
1722// pData : Zeiger auf die Fensterdaten
1723// Ergibt 1 wenn der sich Einstellungen verändert haben
1725
1726 SCROLLINFO sInfo;
1727
1728 if(pData->uOldYCount == pData->uItemPosCount)
1729 if(pData->uOldYPage == pData->uPageEnties) {
1730 return;
1731 }
1732
1733 pData->uOldYPage = pData->uPageEnties;
1734 pData->uOldYCount = pData->uItemPosCount;
1735
1736 UNLOCK(pData);
1737
1738 sInfo.cbSize = sizeof(SCROLLINFO);
1739 sInfo.fMask = SIF_ALL;
1740 sInfo.nMin = 0;
1741 sInfo.nMax = pData->uItemPosCount;
1742 sInfo.nPage = pData->uPageEnties;
1743 sInfo.nPos = pData->uScrollY;
1744 sInfo.nTrackPos = 0;
1745
1746 if(pData->uStyle & TVS_NOSCROLL) {
1747 sInfo.nMax = 0;
1748 }
1749
1750 if((int)sInfo.nPage >= sInfo.nMax && pData->uScrollY > 0) {
1751 sInfo.nPos = 0;
1752 pData->uScrollY = 0;
1753
1755 }
1756
1757 SetScrollInfo(pData->hWnd, SB_VERT, &sInfo, TRUE);
1758
1759 LOCK(pData);
1760}
1761
1762//*****************************************************************************
1763//*
1764//* UpdateToolTip
1765//*
1766//*****************************************************************************
1767// Aktualisiert den Text für das Tootip
1768// pData : Zeiger auf Fensterdaten
1769// uItem : Item auf den der Mauszeiger zeigt
1770// uFlags : Flags vom HitTest
1771static void UpdateToolTip(TreeListData *pData, unsigned uItem, unsigned uFlags) {
1772
1773 TCHAR cTemp[INFOTIPSIZE];
1774#ifndef __REACTOS__
1775 HWND hToolTip;
1776#endif
1777 NMTVGETINFOTIP sToolNv;
1778 NMTREEVIEW sNotify;
1779 TOOLINFO sInfo;
1780 ExtraItem *pExtra;
1782 LPCTSTR pText;
1783 RECT sRect;
1784 unsigned uSize;
1785 unsigned uCol;
1786 unsigned uLen;
1787 LRESULT lRet;
1788 int iTemp;
1789 // Tooltip ausbelnden
1790 if(!uItem || (uItem == pData->uEditItem && TVHT_SUBTOCOL(uFlags) == pData->uEditSub)) {
1791 if(pData->uToolTipItem)
1792 goto ExitTip;
1793 return;
1794 }
1795
1796 pEntry = pData->pTreeItems[uItem];
1797
1798 if(uFlags & TVHT_ONITEM) {
1799 if(pData->uToolTipItem != uItem || pData->uToolTipSub != 0) {
1800 if(!pData->pTreeItems[uItem]) { // Existiert der Eintag noch ?
1801 goto ExitTip;
1802 }
1803
1805
1806 if(sRect.right > (int)pData->uSizeX) {
1807 sRect.right = pData->uSizeX;
1808 }
1809
1810 lRet = 0;
1811
1812 if(pData->uStyleEx & TVS_EX_TOOLTIPNOTIFY) { // Tooltip-Daten via speziellem Notify holen
1813 sNotify.hdr.code = TVN_ITEMTOOLTIP;
1814 sNotify.action = 0;
1815 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
1816 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
1817 sNotify.itemNew.stateMask = 0xFFFFFFFF;
1818 sNotify.itemNew.state = pEntry->uState;
1819 sNotify.itemNew.lParam = pEntry->lParam;
1820 sNotify.itemNew.pszText = pEntry->pText;
1821 sNotify.itemNew.cchTextMax = pEntry->uTextSize;
1822 sNotify.itemNew.cChildren = 0;
1823 sNotify.itemOld.mask = 0;
1824 sNotify.ptDrag.x = sRect.left;
1825 sNotify.ptDrag.y = sRect.top;
1826
1827 UNLOCK(pData);
1828 lRet = SendNotify(pData, &sNotify.hdr);
1829 LOCK(pData);
1830
1831 if(lRet)
1832 goto UserTip;
1833 } else
1834 if(pData->uStyle & TVS_INFOTIP) { // Tooltip-Daten via normalem Notify holen
1835 sToolNv.hdr.code = TVN_GETINFOTIP;
1836 sToolNv.cchTextMax = INFOTIPSIZE;
1837 sToolNv.hItem = (HTREEITEM)(ULONG_PTR)uItem;
1838 sToolNv.lParam = pEntry->lParam;
1839 sToolNv.pszText = cTemp;
1840
1841 str_ncpy(cTemp, pEntry->pText, INFOTIPSIZE);
1842 cTemp[INFOTIPSIZE - 1] = 0;
1843
1844 UNLOCK(pData);
1845 lRet = SendNotify(pData, &sNotify.hdr);
1846 LOCK(pData);
1847
1848 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
1849 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
1850 sNotify.itemNew.pszText = sToolNv.pszText;
1851 sNotify.itemNew.cchTextMax = str_len(sToolNv.pszText);
1852 sNotify.itemNew.cChildren = 0;
1853 sNotify.itemNew.stateMask = 0xFFFFFFFF;
1854 sNotify.itemNew.state = pEntry->uState;
1855 sNotify.itemNew.lParam = pEntry->lParam;
1856 sNotify.ptDrag.x = sRect.left;
1857 sNotify.ptDrag.y = sRect.top;
1858
1859 goto UserTip;
1860 }
1861 // Passt der Text in die Spalte
1862 if(sRect.right - sRect.left <= pEntry->iTextPixels + 4) {
1863 pText = pEntry->pText;
1864 uSize = pEntry->uTextSize;
1865
1866 if(pEntry->bCallback & TVIF_TEXT) {
1867 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iTemp, &uSize, &pText);
1868 }
1869
1870 if(!pText || *pText == 0)
1871 goto ExitTip;
1872
1873 uLen = str_len(pText) + 1;
1874 if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergrößern
1875 delete(pData->pToolTipText);
1876 pData->uToolTipSize = (uLen + 255)&~0xFF;
1877 pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4);
1878 }
1879
1880 memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR));
1881 pData->hFontT = (pEntry->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
1882
1883#ifndef __REACTOS__
1884 hToolTip = pData->hToolTip;
1885#endif
1886 pData->sToolTipPos.x = sRect.left;
1887 pData->sToolTipPos.y = sRect.top;
1888
1889 ClientToScreen(pData->hWnd, &pData->sToolTipPos);
1890
1891 UNLOCK(pData);
1892
1893 sInfo.cbSize = sizeof(sInfo);
1894 sInfo.hwnd = pData->hWnd;
1895 sInfo.uId = (UINT_PTR)pData->hWnd;
1896
1897 if(pData->uToolTipItem) {
1898 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
1899 pData->uToolTipItem = 0;
1900 }
1901
1902 SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y));
1903 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
1904
1905 LOCK(pData);
1906
1907 pData->uToolTipItem = uItem;
1908 pData->uToolTipShow = 0;
1909 pData->uToolTipSub = 0;
1910
1911 SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);
1912 } else {
1913 if(pData->uToolTipItem)
1914 goto ExitTip;
1915 }
1916 }
1917
1918 return;
1919 }
1920
1922 if(pData->uToolTipItem != uItem || TVHT_SUBTOCOL(uFlags) != pData->uToolTipSub) {
1923 lRet = 0;
1924 uCol = TVHT_SUBTOCOL(uFlags);
1925 pExtra = pData->pExtraItems[uCol - 1][uItem];
1926
1927 if(pData->uStyleEx & TVS_EX_TOOLTIPNOTIFY) { // Tooltip-Daten via Notify holen
1929
1930 if(sRect.right > (int)pData->uSizeX) {
1931 sRect.right = pData->uSizeX;
1932 }
1933
1934 if(pExtra) {
1935 sNotify.itemNew.state = pExtra->uState;
1936 sNotify.itemNew.pszText = pExtra->pText;
1937 sNotify.itemNew.cchTextMax = pExtra->uTextSize;
1938 } else {
1939 sNotify.itemNew.state = 0;
1940 sNotify.itemNew.cchTextMax = 0;
1941 sNotify.itemNew.pszText = _T("");
1942 }
1943
1944 sNotify.hdr.code = TVN_ITEMTOOLTIP;
1945 sNotify.action = 0;
1946 sNotify.itemNew.lParam = pEntry->lParam;
1947 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
1948 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
1949 sNotify.itemNew.stateMask = 0xFFFFFFFF;
1950 sNotify.itemNew.cChildren = uCol;
1951 sNotify.itemOld.mask = 0;
1952 sNotify.ptDrag.x = sRect.left;
1953 sNotify.ptDrag.y = sRect.top;
1954
1955 UNLOCK(pData);
1956 lRet = SendNotify(pData, &sNotify.hdr);
1957 LOCK(pData);
1958
1959 if(lRet)
1960 goto UserTip;
1961 }
1962
1963 if(pExtra) { // Tooltip auf Unterspalte ?
1965
1966 if(sRect.right > (int)pData->uSizeX) {
1967 sRect.right = pData->uSizeX;
1968 }
1969
1970 if(sRect.right - sRect.left <= pExtra->iTextPixels + 4) {
1971 pText = pExtra->pText;
1972 uSize = pExtra->uTextSize;
1973
1974 if(pExtra->bCallback & TVIF_TEXT) {
1975 CallbackExtra(pData, pEntry, pExtra, uItem, uCol, TVIF_TEXT, &iTemp, &uSize, &pText);
1976 }
1977
1978 if(!pText || *pText == 0)
1979 goto ExitTip;
1980
1981 uLen = str_len(pText) + 1;
1982 if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergrößern
1983 delete(pData->pToolTipText);
1984 pData->uToolTipSize = (uLen + 255)&~0xFF;
1985 pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4);
1986 }
1987
1988 memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR));
1989 pData->hFontT = (pExtra->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
1990
1991 pData->sToolTipPos.x = sRect.left;
1992 pData->sToolTipPos.y = sRect.top;
1993#ifndef __REACTOS__
1994 hToolTip = pData->hToolTip;
1995#endif
1996
1997 ClientToScreen(pData->hWnd, &pData->sToolTipPos);
1998
1999 UNLOCK(pData);
2000
2001 sInfo.cbSize = sizeof(sInfo);
2002 sInfo.hwnd = pData->hWnd;
2003 sInfo.uId = (UINT_PTR)pData->hWnd;
2004
2005 if(pData->uToolTipItem) {
2006 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
2007 pData->uToolTipItem = 0;
2008 }
2009
2010 SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y));
2011 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
2012
2013 LOCK(pData);
2014
2015 pData->uToolTipItem = uItem;
2016 pData->uToolTipSub = uCol;
2017 pData->uToolTipShow = 0;
2018
2019 SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);
2020 } else {
2021 if(pData->uToolTipItem)
2022 goto ExitTip;
2023 }
2024 } else {
2025 if(pData->uToolTipItem)
2026 goto ExitTip;
2027 }
2028 }
2029
2030 return;
2031 }
2032
2033ExitTip:
2034
2035 if(pData->uToolTipItem) { // Tooltip ausblenden
2036 UNLOCK(pData);
2037
2038 sInfo.cbSize = sizeof(sInfo);
2039 sInfo.hwnd = pData->hWnd;
2040 sInfo.uId = (UINT_PTR)pData->hWnd;
2041
2042 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
2043
2044 LOCK(pData);
2045
2046 pData->uToolTipItem = 0;
2047 pData->uToolTipSub = 0;
2048 pData->uToolTipShow = 0;
2049
2051 }
2052
2053 return;
2054
2055UserTip:
2056
2057 pText = sNotify.itemNew.pszText; // Soll ein User-Tooltip angezeigt werden
2058 uSize = sNotify.itemNew.cchTextMax;
2059 sRect.left = sNotify.ptDrag.x;
2060 sRect.top = sNotify.ptDrag.y;
2061
2062 if(!pText || *pText == 0)
2063 goto ExitTip;
2064
2065 uLen = str_len(pText) + 1;
2066 if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergrößern
2067
2068 delete(pData->pToolTipText);
2069 pData->uToolTipSize = (uLen + 255)&~0xFF;
2070 pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4);
2071 }
2072
2073 memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR));
2074 pData->hFontT = (pEntry->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
2075
2076 ClientToScreen(pData->hWnd, &sNotify.ptDrag);
2077 pData->sToolTipPos = sNotify.ptDrag;
2078#ifndef __REACTOS__
2079 hToolTip = pData->hToolTip;
2080#endif
2081 // Tooltip verzögert anzeigen
2082 if((sNotify.itemNew.mask & TVIF_TOOLTIPTIME) && sNotify.itemNew.lParam > 0) {
2083 pData->uToolTipShow = (unsigned)(sNotify.itemNew.lParam + 499) / 500;
2084 pData->uToolTipSub = sNotify.itemNew.cChildren;
2085 pData->uToolTipItem = uItem;
2086
2087 SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 500, NULL);
2088
2089 return;
2090 }
2091
2092 UNLOCK(pData);
2093
2094 sInfo.cbSize = sizeof(sInfo);
2095 sInfo.hwnd = pData->hWnd;
2096 sInfo.uId = (UINT_PTR)pData->hWnd;
2097
2098 if(pData->uToolTipItem) { // Tooltip Fenster aktivieren
2099 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
2100 pData->uToolTipItem = 0;
2101 }
2102
2103 SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(sNotify.ptDrag.x, sNotify.ptDrag.y));
2104 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
2105
2106 LOCK(pData);
2107
2108 pData->uToolTipShow = 0;
2109 pData->uToolTipItem = uItem;
2110 pData->uToolTipSub = sNotify.itemNew.cChildren;
2111
2112 SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);
2113}
2114
2115//*****************************************************************************
2116//*
2117//* CreateFontset
2118//*
2119//*****************************************************************************
2120// Create the font set (normal, bold, etc...) from the given HFONT
2122 LOGFONT sLog;
2123 HFONT hBold;
2124 int iRet = 0;
2125
2126 if(GetObject(hFont, sizeof(sLog), &sLog)){
2127 sLog.lfWeight = FW_BOLD;
2128 if((hBold = CreateFontIndirect(&sLog))){
2129 pData->hFontN = hFont; //store the given font
2130 if(pData->hFontB != hDefaultFontB){
2131 //if the current bold is not the default bold, free it
2132 DeleteObject(pData->hFontB);
2133 }
2134 pData->hFontB = hBold; //store the created bold
2135 iRet = 1;
2136 }
2137 }
2138 return iRet;
2139}
2140
2141//*****************************************************************************
2142//*
2143//* UpdateFont
2144//*
2145//*****************************************************************************
2146// Erzeugt einen den fetten Font für das Fenster
2147// pData : Zeiger auf die Fensterdaten
2148// iRedraw : Soll das Fenster neugezeichnet werden
2149// Ergibt 1 wenn der Font verändert wurde
2151
2152 int iPos;
2153 int iRet;
2154 HDC hDc;
2155 LOGFONT sLog;
2156 SIZE sSize;
2157 TEXTMETRIC sMetrics;
2159 BaseItem **pList;
2160 ExtraItem *pExtra;
2161 ExtraItem **pItems;
2162 unsigned uSub;
2163
2164 if(!hDefaultFontN) { // Den Standard-Font erzeugen
2165 SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(sLog), &sLog, 0);
2166 sLog.lfWeight = FW_NORMAL;
2168 sLog.lfWeight = FW_BOLD;
2170 }
2171
2172
2173 if(!pData->hFontN)
2174 pData->hFontN = hDefaultFontN;
2175 if(!pData->hFontB)
2176 pData->hFontB = hDefaultFontB;
2177
2178/*
2179 if(pData->hFontN == hDefaultFontN) { // Ist der Standard-Font eingestellt
2180 pData->hFontB = hDefaultFontB;
2181 } else {
2182 pData->hFontB = pData->hFontN;
2183 }
2184*/
2185
2186 if(pData->hFontN != pData->hFontL) {
2187 pData->hFontL = pData->hFontN;
2188
2189 hDc = GetDC(NULL);
2190 SelectObject(hDc, pData->hFontN);
2191 GetTextMetrics(hDc, &sMetrics);
2192 pData->iFontHeight = sMetrics.tmHeight;
2193 pData->iFontLine = sMetrics.tmAscent + 1;
2194 pData->iFontOff = (sMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH) ? 0 : -1;
2195 ReleaseDC(NULL, hDc);
2196
2197 pList = pData->pTreeItems;
2198 iPos = pData->uTreeItemsMax;
2199
2200 for(; iPos >= 0; iPos--) { // Alle Textbreiten zurücksetzen
2201 pEntry = pList[iPos];
2202 if(!pEntry)
2203 continue;
2204
2205 pEntry->iTextPixels = 0;
2206 }
2207
2208
2209 for(uSub = 1; uSub < pData->uColumnCount; uSub++) {
2210 iPos = pData->uTreeItemsMax;
2211 pItems = pData->pExtraItems[uSub - 1];
2212
2213 for(; iPos >= 0; iPos--) {
2214 pExtra = pItems[iPos];
2215 if(!pExtra)
2216 continue;
2217
2218 pExtra->iTextPixels = 0;
2219 }
2220 }
2221
2222 iRet = 1;
2223 } else {
2224 iRet = 0;
2225 }
2226
2227 // compute Width of "..." text
2228 hDc = GetDC(NULL);
2229 SelectObject(hDc, pData->hFontN);
2230 GetTextExtentExPoint(hDc, _T("..."), 3, 256, NULL, NULL, &sSize);
2231 pData->uTrippleN = sSize.cx;
2232 SelectObject(hDc, pData->hFontB);
2233 GetTextExtentExPoint(hDc, _T("..."), 3, 256, NULL, NULL, &sSize);
2234 pData->uTrippleB = sSize.cx;
2235 ReleaseDC(NULL, hDc);
2236
2237 return iRet;
2238}
2239
2240
2241//*****************************************************************************
2242//*
2243//* UpdateItems
2244//*
2245//*****************************************************************************
2246// Berechnet die Positionen der Zeilen für die sichtbaren Einträge
2247// pData : Zeiger auf die Fensterdaten
2248// uItem : Ist der Eintrag ab dem begonnen wird
2249static void UpdateItems(TreeListData *pData, unsigned uItem) {
2250
2251 unsigned uPos;
2252 unsigned uOld;
2253 unsigned uNum;
2254 unsigned uTemp;
2255 unsigned uStart;
2256 unsigned *pLines;
2257 BaseItem **pItems;
2259 BaseItem *pTemp;
2260 RECT sRect;
2261
2262 uOld = pData->uItemPosCount;
2263 pLines = pData->pItemPos;
2264 pItems = pData->pTreeItems;
2265
2266 if(!uItem) { // Am Anfang beginnen
2267 uItem = pData->uFirstChild;
2268 if(!uItem) { // Leere Liste
2269 if(!uOld)
2270 return;
2271
2272 for(uNum = 0; uNum < uOld; uNum++) { // Die alten Einträge zurücksetzen
2273 uTemp = pLines[uNum];
2274 if(!uTemp)
2275 continue;
2276 pLines[uNum] = 0;
2277 pTemp = pItems[uTemp];
2278 if(!pTemp)
2279 continue;
2280 pTemp->uShowPos = 0;
2281 }
2282
2283 pData->uItemPosCount = 0;
2284
2285 GetClientRect(pData->hWnd, &sRect);
2286 InvalidateRect(pData->hWnd, &sRect, TRUE);
2287
2288 memset(pLines, 0, sizeof(unsigned)*uOld);
2289 return;
2290 }
2291
2292 for(uNum = 0; uNum < uOld; uNum++) { // Die alten Einträge zurücksetzen
2293 uTemp = pLines[uNum];
2294 if(!uTemp)
2295 continue;
2296 pLines[uNum] = 0;
2297 pTemp = pItems[uTemp];
2298 if(!pTemp)
2299 continue;
2300 pTemp->uShowPos = 0;
2301 }
2302
2303 pEntry = pItems[uItem];
2304 pEntry->uShowPos = 1;
2305 pLines[0] = uItem;
2306 uPos = 1;
2307 uStart = 0;
2308 } else { // Bei einem Eintrag beginnen
2309 pEntry = pItems[uItem];
2310 uPos = pEntry->uShowPos;
2311 if(uPos)
2312 uStart = uPos - 1;
2313 else
2314 uStart = 0;
2315
2316 for(uNum = uPos; uNum < uOld; uNum++) { // Die alten Einträge zurücksetzen
2317 uTemp = pLines[uNum];
2318 if(!uTemp)
2319 continue;
2320 pLines[uNum] = 0;
2321 pTemp = pItems[uTemp];
2322 if(!pTemp)
2323 continue;
2324 pTemp->uShowPos = 0;
2325 }
2326 }
2327
2328 for(;;) { // Die Zeilen neu zuordnen
2329 if(pEntry->uFirstChild && (pEntry->uState & TVIS_EXPANDED)) {
2330 uItem = pEntry->uFirstChild;
2331 } else
2332 if(pEntry->uNextItem) {
2333 uItem = pEntry->uNextItem;
2334 } else {
2335 for(;;) {
2336 uItem = pEntry->uParent;
2337 if(!uItem)
2338 break;
2339
2340 pEntry = pItems[uItem];
2341 if(pEntry->uNextItem) { // Gibt es etwas in der gleichen Ebene
2342 uItem = pEntry->uNextItem;
2343 break;
2344 }
2345 }
2346
2347 if(!uItem)
2348 break;
2349 }
2350
2351 pEntry = pItems[uItem];
2352
2353 if(pLines[uPos] != uItem) {
2354 pLines[uPos] = uItem;
2355 } else {
2356 if(uStart == uPos)
2357 uStart++;
2358 }
2359
2360 uPos++;
2361 pEntry->uShowPos = uPos;
2362 }
2363
2364 pData->uItemPosCount = uPos;
2365
2366 if(uStart > pData->uScrollY) // Neu zu zeichnenten Bereich bestimmen
2367 uStart -= pData->uScrollY;
2368 else
2369 uStart = 0;
2370
2371 GetClientRect(pData->hWnd, &sRect);
2372
2373 sRect.top = pData->uStartPixel + pData->iRowHeight * uStart;
2374
2375 if(sRect.top <= sRect.bottom) {
2376 InvalidateRect(pData->hWnd, &sRect, FALSE);
2377 }
2378
2379 if(uOld != uPos)
2381}
2382
2383//*****************************************************************************
2384//*
2385//* UpdateColumns
2386//*
2387//*****************************************************************************
2388// Prüft ob es Veränderungen in Spaltenbreiten gab
2389// pData : Zeiger auf die Fensterdaten
2390// Ergibt die Breite ab der die Spalten verändert wurden oder 0x10000
2392#ifndef __REACTOS__
2393 HWND hHeader;
2394#endif
2395 UINT uNext;
2396 UINT uCol;
2397 UINT uSub;
2398 int iSize;
2399 int iNum;
2400 int iNow;
2401 int iOld;
2402 int iRet;
2403
2404#ifndef __REACTOS__
2405 hHeader = pData->hHeader;
2406#endif
2407 pData->aColumnXpos[0] = 0;
2408
2409 iRet = 0x10000;
2410 iOld = 0;
2411 iNow = 0;
2412
2413 for(uCol = 0; uCol < pData->uColumnCount;) { // Suche die erste geänderte Spalte
2414 uSub = pData->aColumnPos[uCol];
2415 iSize = pData->aColumn[uSub].sReal;
2416 uSub = pData->aColumn[uSub].bNext;
2417 iOld = iNow;
2418 iNow += iSize;
2419 uCol += 1;
2420
2421 if(uCol == 1)
2422 iNow -= 1;
2423 if(iNow < iOld)
2424 iNow = iOld;
2425 if(uSub == pData->uColumnCount)
2426 if(iNow >= (int)pData->uSizeX - 1) {
2427 iNow++;
2428 }
2429
2430 iNum = pData->aColumnXpos[uSub];
2431
2432 if(iNum == iNow)
2433 continue;
2434 if(iNum == 0)
2435 iNum = iOld;
2436 if(iNum >= iNow) {
2437 iRet = iOld;
2438 } else {
2439 iRet = iOld;
2440
2441 if(pData->uSelectedItem) { // Problem bei ausgewählten leeren Einträgen
2442 uNext = pData->aColumn[pData->uSelectedSub].bNext;
2443 if(uNext == uSub) {
2444 UpdateRect(pData, pData->uSelectedItem, pData->uSelectedSub);
2445 }
2446 }
2447
2448 if(pData->uTrackedItem) {
2449 uNext = pData->aColumn[pData->uTrackedSub].bNext;
2450 if(uNext == uSub) {
2451 UpdateRect(pData, pData->uTrackedItem, pData->uTrackedSub);
2452 }
2453 }
2454 }
2455
2456 pData->aColumnXpos[uSub] = iNow;
2457 break;
2458 }
2459
2460 while(uCol < pData->uColumnCount) { // Restliche Spalten berechen
2461 iOld = iNow;
2462 uSub = pData->aColumnPos[uCol];
2463 iNow += pData->aColumn[uSub].sReal;
2464 uSub = pData->aColumn[uSub].bNext;
2465 uCol += 1;
2466
2467 if(uCol == pData->uColumnCount)
2468 if(iNow >= (int)pData->uSizeX - 1) {
2469 iNow++;
2470 }
2471
2472 pData->aColumnXpos[uSub] = iNow;
2473 }
2474
2475 pData->aColumnXpos[pData->uColumnCount + 1] = pData->uSizeX + 1;
2476
2477 return iRet;
2478}
2479
2480//*****************************************************************************
2481//*
2482//* TreeListSetOrderArray
2483//*
2484//*****************************************************************************
2485// Stellt die anzeige Reihenfolge der Spalten ein
2486// pData : Zeiger auf die Fensterdaten
2487// uItems : Ist die Nummer des Eintrages
2488// pArray : Zeiger auf die Einträge. Null steht für die Standartreihenfolge.
2489// z.B. {0,2,1} meint die sichtbare Reihenfolge Col0,Col2,Col1
2490// Der erste Eintrag muss 0 immer sein.
2491// Ergibt 1 = Ok
2492// 0 = Fehler
2493static int TreeListSetOrderArray(TreeListData *pData, unsigned uItems, unsigned *pArray) {
2494
2495 BYTE aFlags[MAX_COLUMNS + 1];
2496 UINT aArray[MAX_COLUMNS + 1];
2497 TV_COLSIZE sNotify;
2498 UINT uDiff;
2499 UINT uCol;
2500 UINT uSub;
2501
2502 if(!pArray) { // Spezialreihenfolge setzen
2503 if(uItems == FROM_HEADER) { // Array aus Header holen
2504 if(!Header_GetOrderArray(pData->hHeader, pData->uColumnCount, aArray)) {
2505 return 0;
2506 }
2507
2508 if(aArray[0] != 0) {
2509 return 0;
2510 }
2511 } else {
2512 for(uCol = pData->uColumnCount; uCol > 0; uCol++) { // Standartreihenfolge
2513 uCol--;
2514 aArray[uCol] = uCol;
2515 }
2516 }
2517
2518 uItems = pData->uColumnCount;
2519 pArray = aArray;
2520 } else { // Prüfe Array
2521 if(pData->uColumnCount != uItems || uItems == 0 || *pArray) {
2522 return 0;
2523 }
2524 }
2525
2526 memset(aFlags, 0, sizeof(aFlags) - 1);
2527
2528 for(uCol = 0, uDiff = 0; uCol < uItems; uCol++) { // Die Einträge prüfen
2529 uSub = pArray[uCol];
2530 if(uSub >= uItems)
2531 return 0;
2532 if(aFlags[uSub])
2533 return 0;
2534
2535 aFlags[uSub] = (BYTE)uCol;
2536
2537 uDiff |= uCol ^ pData->aColumnPos[uSub];
2538 }
2539
2540 if(uDiff == 0) { // Alles blieb gleich
2541 return 1;
2542 }
2543
2544 aFlags[0 ] = 0;
2545 aFlags[uItems] = (BYTE)uItems;
2546
2547 for(uCol = 1; uCol < uItems; uCol++) { // Die Einträge anpassen
2548 pData->aColumnPos[uCol] = (BYTE)pArray[uCol];
2549 }
2550
2551 for(uCol = 0; uCol < uItems; uCol++) {
2552 uSub = aFlags[uCol];
2553 pData->aColumn[uCol].bIndex = (BYTE)uSub;
2554 pData->aColumn[uCol].bNext = pData->aColumnPos[uSub + 1];
2555 }
2556
2557 Header_SetOrderArray(pData->hHeader, uItems, pArray);
2560
2561 if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) { // Alle Spalten haben sich verändert
2562 UNLOCK(pData);
2563
2564 for(uCol = 0; uCol < uItems; uCol++) {
2565 sNotify.hdr.code = TVN_COLUMNCHANGED;
2566 sNotify.uColumn = uCol;
2567 sNotify.uIndex = pData->aColumn[uCol].bIndex;
2568 sNotify.uPosX = pData->aColumnXpos[uCol];
2569 sNotify.iSize = pData->aColumn[uCol].sReal;
2570
2571 SendNotify(pData, &sNotify.hdr);
2572 }
2573
2574 LOCK(pData);
2575 }
2576
2577 return 1;
2578}
2579
2580//*****************************************************************************
2581//*
2582//* TreeListToggleItem
2583//*
2584//*****************************************************************************
2585// Klappt bei einem Eintrag die Kinder um, und schickt alle Notify-Nachrichten.
2586// pData : Zeiger auf die Fensterdaten
2587// uItem : Ist die Nummer des Eintrages
2588// uAddFlags : Sind die State-Flags die hinzugefügt werden sollen
2589// Bits 0..3 entahlen das Kommando, bei automatisch ermitteln
2590// Ergibt -1 = Fehler
2591// 0 = Ausgeführt
2592// 1 = Abbruch
2593static int TreeListToggleItem(TreeListData *pData, unsigned uItem, unsigned uAddFlags) {
2594
2595 NMTREEVIEW sNotify;
2596 BaseItem **pList;
2598 BaseItem *pTemp;
2599 unsigned uAction;
2600 unsigned uLevel;
2601 unsigned uNext;
2602 LRESULT lRet;
2603 BOOL bDo;
2604
2605 if(uItem > pData->uTreeItemsMax)
2606 return 0;
2607
2608 pList = pData->pTreeItems;
2609 pEntry = pList[uItem];
2610 if(!pEntry)
2611 return -1;
2612
2613 uAction = uAddFlags & 0x0F;
2614 if(!uAction) {
2616 }
2617
2618 sNotify.action = uAction;
2619 sNotify.hdr.code = TVN_ITEMEXPANDING;
2620 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
2621 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
2622 sNotify.itemNew.stateMask = 0xFFFFFFFF;
2623 sNotify.itemNew.state = pEntry->uState;
2624 sNotify.itemNew.lParam = pEntry->lParam;
2625 sNotify.itemNew.pszText = (LPTSTR) - 1;
2626 sNotify.itemNew.cchTextMax = -1;
2627 sNotify.itemOld.mask = 0;
2628 sNotify.ptDrag.x = 0;
2629 sNotify.ptDrag.y = 0;
2630
2631 UNLOCK(pData);
2632
2633 lRet = SendNotify(pData, &sNotify.hdr);
2634
2635 LOCK(pData);
2636
2637 pList = pData->pTreeItems;
2638 pEntry = pList[uItem];
2639
2640 if(pEntry == 0)
2641 return -1; // Eintrag inzischen gelöscht ?
2642 if(lRet != 0)
2643 return 1; // User-Abbruch ?
2644
2645 if(uAction == TVE_EXPAND) { // Aufklappen
2646 if(pEntry->uState & TVIS_EXPANDED) {
2647 bDo = FALSE; // Nur von + auf -
2648 } else {
2649 pEntry->uState |= TVIS_EXPANDED; // Kinder Aufklappen
2650 bDo = TRUE;
2651 }
2652 } else { // Zuklappen
2653 pEntry->uState &= ~TVIS_EXPANDED;
2654 bDo = TRUE;
2655 }
2656
2657 pEntry->uState &= ~TVIS_EXPANDPARTIAL;
2658 pEntry->uState |= uAddFlags&~0x0F;
2659
2660 if(pEntry->uShowPos && bDo) {
2661 if(pEntry->uState & TVIS_EXPANDED) { // Kinderfenster aktuallisieren
2662 uLevel = 0;
2663 uNext = pEntry->uFirstChild;
2664
2665 while(uNext) {
2666 pTemp = pList[uNext];
2667 pTemp->uShowPos = 0;
2668
2669 if(pTemp->uFirstChild) {
2670 uNext = pTemp->uFirstChild;
2671 uLevel++;
2672 continue;
2673 }
2674
2675 if(pTemp->uNextItem) {
2676 uNext = pTemp->uNextItem;
2677 continue;
2678 }
2679
2680 if(uLevel == 0)
2681 break;
2682
2683 uNext = pList[pTemp->uParent]->uNextItem;
2684 uLevel--;
2685 }
2686 }
2687
2688 UpdateItems(pData, uItem);
2689 }
2690
2691 sNotify.action = uAction;
2692 sNotify.hdr.code = TVN_ITEMEXPANDED;
2693 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
2694 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
2695 sNotify.itemNew.stateMask = 0xFFFFFFFF;
2696 sNotify.itemNew.state = pEntry->uState;
2697 sNotify.itemNew.lParam = pEntry->lParam;
2698 sNotify.itemNew.pszText = (LPTSTR) - 1;
2699 sNotify.itemNew.cchTextMax = -1;
2700 sNotify.itemOld.mask = 0;
2701 sNotify.ptDrag.x = 0;
2702 sNotify.ptDrag.y = 0;
2703
2704 UNLOCK(pData);
2705
2706 SendNotify(pData, &sNotify.hdr);
2707
2708 LOCK(pData);
2709
2710 pList = pData->pTreeItems;
2711 pEntry = pData->pTreeItems[uItem];
2712
2713 if(!pEntry)
2714 return -1; // Eintrag inzischen gelöscht ?
2715
2716 if(uAction == TVE_EXPAND) { // ONCE setzen nach Expandieren
2717 pEntry->uState |= TVIS_EXPANDEDONCE;
2718 }
2719
2720 if(pData->uSelectedItem && bDo) { // Ist der ausgewählten Eintrag sichtbar ?
2721 pEntry = pList[pData->uSelectedItem];
2722 if(!pEntry) {
2723 pData->uSelectedItem = 0;
2724 pData->uSelectedSub = 0;
2725 } else
2726 if(!pEntry->uShowPos) {
2727 while(!pEntry->uShowPos) {
2728 uItem = pEntry->uParent;
2729 pEntry = pList[uItem];
2730 }
2731
2732 TreeListSelectItem(pData, uItem, pData->uSelectedSub, TVC_UNKNOWN);
2733 }
2734 }
2735
2736 if(bDo == FALSE) { // Nur von + auf -
2737 UpdateRect(pData, uItem, 0);
2738 }
2739
2740 return 0;
2741}
2742
2743//*****************************************************************************
2744//*
2745//* TreeListGetItemRect
2746//*
2747//*****************************************************************************
2748// Holt das Rechteck eines Eintrages
2749// pData : Zeiger auf die Fensterdaten
2750// uItem : Ist die Nummer des Eintrages
2751// uFlags : Bit 0 : 0=volle Zeile 1=nur Text
2752// Bit 7 : 1=nur Spalte
2753// Bit 24.. : Spaltennummer
2754// Ergibt 1 wenn der Eintrag sichtbar war
2755static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT *pRect) {
2756
2757 ExtraItem *pExtra;
2759 unsigned uNext;
2760 unsigned uPos;
2761 unsigned uSub;
2762
2763 if(uItem > pData->uTreeItemsMax) {
2764 memset(pRect, 0, sizeof(RECT));
2765 return 0;
2766 }
2767
2768 pEntry = pData->pTreeItems[uItem];
2769 if(!pEntry->uShowPos) { // Ist der Eintrag aufgeklappt
2770 memset(pRect, 0, sizeof(RECT));
2771 return 0;
2772 }
2773
2774 uPos = pEntry->uShowPos - pData->uScrollY - 1;
2775 if(uPos >= pData->uMaxEnties) { // Eintrag im Fenster sichtbar
2776 memset(pRect, 0, sizeof(RECT));
2777 return 0;
2778 }
2779
2780 pRect->top = pData->uStartPixel;
2781 pRect->top += pData->iRowHeight * uPos;
2782 pRect->bottom = pData->iRowHeight + pRect->top;
2783
2784 if((uFlags & 0xFC) == TVIR_GETCOLUMN) { // Nur Spalten
2785 uSub = uFlags >> 24;
2786 if(uSub >= pData->uColumnCount)
2787 uSub = 0;
2788
2789 uNext = pData->aColumn[uSub].bNext;
2790 pRect->left = pData->aColumnXpos[uSub];
2791 pRect->left -= pData->uScrollX;
2792 pRect->right = pData->aColumnXpos[uNext];
2793 pRect->right -= pData->uScrollX;
2794 } else {
2795 uSub = 0;
2796 pRect->left = 0;
2797 pRect->left -= pData->uScrollX;
2798 pRect->right = pData->uSizeX;
2799 }
2800
2801 if(uFlags & TVIR_TEXT) { // Nur Text ausgeben
2802 if(uSub > 0) {
2803 pExtra = pData ->pExtraItems[uSub - 1][uItem];
2804
2805 if(pData->aColumn[uSub].bEdit == TVAX_CHECK) {
2806 pRect->left += pData->iChecksXsize;
2807 if(pRect->left > pRect->right)
2808 pRect->left = pRect->right;
2809 } else
2810 if(pExtra && pExtra->bFlags & TVIX_HASIMAGE) {
2811 pRect->left += pData->iImagesXsize;
2812 if(pRect->left > pRect->right)
2813 pRect->left = pRect->right;
2814 }
2815 } else {
2816 if(pData->cHasRootRow) { // Root-Linien ausgleichen
2817 pRect->left += pData->iIndent;
2818 }
2819
2820 pRect->left += pData->iIndent * pEntry->uLevel;
2821
2822 if(pData->hStates) {
2823 pRect->left += pData->iStatesXsize;
2824 }
2825
2826 if(!(pData->uStyle & TVS_HASLINES)) {
2827 pRect->left -= 1;
2828 }
2829
2830 if(pData->uStyleEx & TVS_EX_ITEMLINES) {
2831 pRect->left += 1;
2832 if(pEntry->bFlags & TVIX_HASIMAGE)
2833 pRect->left++;
2834 }
2835
2836 if(pEntry->bFlags & TVIX_HASIMAGE) {
2837 pRect->left += pData->iImagesXsize;
2838 }
2839
2840 if(pRect->left > pRect->right) {
2841 pRect->left = pRect->right;
2842 }
2843 }
2844 }
2845
2846 return 1;
2847}
2848
2849//*****************************************************************************
2850//*
2851//* TreeListEnsureVisible
2852//*
2853//*****************************************************************************
2854// Macht einen Eintrag sichtbar
2855// pData : Zeiger auf die Fensterdaten
2856// uItem : Ist die Nummer des Eintrages
2857// uSub : Untereintrag der sichtbar sein soll
2858// 0xFFFFFFFF nur Zeile
2859// FIRST_LINE als oberster Eintrag
2860// Ergibt 1 wenn nur zum Eintrag gescrollt wurde bzw. 0 wenn aufgeklapt wurde
2861static int TreeListEnsureVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
2862
2864 BaseItem *pTemp;
2865 unsigned uTemp;
2866 unsigned uNext;
2867 unsigned uPos;
2868 int iNum;
2869 int iAnf;
2870 int iOff;
2871 int iEnd;
2872 int iMax;
2873 int iRet;
2874
2875 if(uItem > pData->uTreeItemsMax)
2876 return -1;
2877
2878 pEntry = pData->pTreeItems[uItem];
2879 if(!pEntry)
2880 return -1;
2881
2882 uPos = pEntry->uShowPos;
2883 if(!uPos) { // Zweige aufklappen wenn Eintrag zugeklappt
2884
2885 iRet = 0;
2886
2887 for(pTemp = pEntry;;) {
2888 uTemp = pTemp->uParent;
2889 pTemp = pData->pTreeItems[uTemp];
2890 if(!pTemp)
2891 break;
2892 if((pTemp->uState & TVIS_EXPANDED) == 0) {
2893 if(TreeListToggleItem(pData, uTemp, 0))
2894 return 0;
2895 }
2896 }
2897
2898 pEntry = pData->pTreeItems[uItem];
2899 if(!pEntry)
2900 return 0;
2901
2902 uPos = pEntry->uShowPos;
2903 if(!uPos)
2904 return 0;
2905 } else { // Nur Scrollen
2906 iRet = 1;
2907 }
2908
2909 uPos--;
2910 if(uPos < pData->uScrollY) { // Vor erster Zeile
2911 pData->uScrollY = uPos;
2912 SetScrollPos(pData->hWnd, SB_VERT, uPos, TRUE);
2914 } else
2915 if(uSub == FIRST_LINE) { // Als ersten Eintrag
2916 if(uPos != pData->uScrollY) {
2917 pData->uScrollY = uPos;
2918 SetScrollPos(pData->hWnd, SB_VERT, uPos, TRUE);
2920 }
2921
2922 return iRet;
2923 } else
2924 if(uPos >= pData->uScrollY + pData->uPageEnties) { // Nach letzter Zeile
2925 iOff = uPos - (pData->uPageEnties - 1);
2926 iMax = pData->uItemPosCount;
2927 iMax -= pData->uPageEnties - 1;
2928
2929 if(iOff >= iMax)
2930 iOff = iMax;
2931 if(iOff < 0)
2932 iOff = 0;
2933 if(iOff != (int)pData->uScrollY) {
2934 pData->uScrollY = iOff;
2935 SetScrollPos(pData->hWnd, SB_VERT, iOff, TRUE);
2937 }
2938 }
2939
2940 if(uSub < pData->uColumnCount) { // Horizontal einrichten
2941 uNext = pData->aColumn[uSub].bNext;
2942 iNum = pData->uSizeX;
2943 iOff = pData->uScrollX;
2944 iAnf = pData->aColumnXpos[uSub ];
2945 iEnd = pData->aColumnXpos[uNext];
2946
2947 if(iOff + iNum < iAnf)
2948 iOff = iAnf;
2949 if(iOff >= iEnd)
2950 iOff = iAnf;
2951 if(iOff + iNum < iEnd)
2952 iOff = iEnd - iNum;
2953 if(iOff > iAnf)
2954 iOff = iAnf;
2955
2956 iMax = pData->aColumnXpos[pData->uColumnCount];
2957 iMax -= pData->uSizeX / 2;
2958
2959 if(iOff > iMax)
2960 iOff = iMax;
2961 if(iOff < 0)
2962 iOff = 0;
2963 if(iOff != (int)pData->uScrollX) {
2964 pData->uScrollX = iOff;
2965 SetScrollPos(pData->hWnd, SB_HORZ, iOff, TRUE);
2967 MoveWindow(pData->hHeader, -iOff, 0, iNum + iOff, pData->uStartPixel, TRUE);
2968 }
2969 }
2970 return iRet;
2971}
2972
2973//*****************************************************************************
2974//*
2975//* TreeListIsVisible
2976//*
2977//*****************************************************************************
2978// Prüft ob ein Eintrag sichtbar ist
2979// pData : Zeiger auf die Fensterdaten
2980// uItem : Ist die Nummer des Eintrages
2981// uSub : Untereintrag der geprüft werden soll
2982// 0xFFFFFFFF nur Zeile prüfen
2983// Ergibt den Zustand des Eintrages:
2984// -1 = Unbekannter Eintrag
2985// 0 = Eintrag ist zugeklappt
2986// 1 = Eintrag ist aufgeklappt aber nicht sichtbar
2987// 2 = Eintrag ist aufgeklappt und teilweise sichtbar
2988// 3 = Eintrag ist aufgeklappt und Spalte ist nur teilweise sichtbar
2989// 4 = Eintrag ist aufgeklappt und ganz sichtbar
2990static int TreeListIsVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
2991
2993 unsigned uNext;
2994 unsigned uPos;
2995 int iNum;
2996 int iAnf;
2997 int iOff;
2998 int iEnd;
2999
3000 if(uItem > pData->uTreeItemsMax)
3001 return -1;
3002
3003 pEntry = pData->pTreeItems[uItem];
3004 if(!pEntry)
3005 return -1;
3006
3007 uPos = pEntry->uShowPos;
3008 if(!uPos) { // Ist der Eintrag zugeklappt
3009 return 0;
3010 }
3011
3012 uPos--;
3013 if(uPos < pData->uScrollY) { // Vor erster Zeile
3014
3015 return 1;
3016 }
3017
3018 if(uPos >= pData->uScrollY + pData->uMaxEnties) { // Nach letzter Zeile
3019 return 1;
3020 }
3021
3022 if(uPos == pData->uScrollY + pData->uPageEnties) { // Auf halbsichtbarer Zeile
3023 if(uSub < pData->uColumnCount) {
3024 uNext = pData->aColumn[uSub].bNext;
3025 iNum = pData->uSizeX;
3026 iOff = pData->uScrollX;
3027 iAnf = pData->aColumnXpos[uSub ];
3028 iEnd = pData->aColumnXpos[uNext];
3029
3030 if(iOff + iNum < iAnf)
3031 return 1;
3032 if(iOff >= iEnd)
3033 return 1;
3034 }
3035
3036 return 2;
3037 }
3038
3039 if(uSub < pData->uColumnCount) { // Spalte prüfen
3040 uNext = pData->aColumn[uSub].bNext;
3041 iNum = pData->uSizeX;
3042 iOff = pData->uScrollX;
3043 iAnf = pData->aColumnXpos[uSub ];
3044 iEnd = pData->aColumnXpos[uNext];
3045
3046 if(iOff + iNum < iAnf)
3047 return 1;
3048 if(iOff >= iEnd)
3049 return 1;
3050 if(iOff + iNum < iEnd)
3051 return 3;
3052 if(iOff > iAnf)
3053 return 3;
3054 }
3055
3056 return 4;
3057}
3058
3059//*****************************************************************************
3060//*
3061//* TreeListDeleteItem
3062//*
3063//*****************************************************************************
3064// Löscht einen Eintrag aus dem Fenster
3065// pData : Zeiger auf die Fensterdaten
3066// uItem : Ist die Nummer des Eintrages der gelöscht werden soll
3067// iMode : Wie soll der Eintrag gelöscht werden
3068// 0 = Eintrag löschen und nicht neu zeichnen
3069// 1 = Eintrag löschen und neu zeichnen
3070// 2 = Nur Kindereinträge löschen und neu zeichnen
3071// Ergibt 1 wenn der Eintrag gelöscht wurde.
3072static int TreeListDeleteItem(TreeListData *pData, unsigned uItem, int iMode) {
3073
3074 NMTREEVIEW sNotify;
3075 ExtraItem **pList;
3076 ExtraItem *pExtra;
3078 BaseItem *pTemp;
3079 unsigned uPos;
3080 int iOff;
3081 int iMax;
3082
3083 if(pData->cLockChanges)
3084 return 0;
3085
3086 if(uItem > pData->uTreeItemsMax) { // Prüfe den Eintrag
3087 if(uItem != U(TVI_ROOT))
3088 return 0; // Alles löschen
3089 if(pData->uLastChild == 0)
3090 return 0;
3091
3092 while(pData->uLastChild) {
3093 TreeListDeleteItem(pData, pData->uLastChild, 0);
3094 }
3095
3096 pData->uItemPosCount = 0;
3097
3100
3101 return 1;
3102 }
3103
3104 pEntry = pData->pTreeItems[uItem];
3105 if(!pEntry) { // Prüfe den Eintrag
3106 if(uItem != 0)
3107 return 0; // Alles löschen
3108 if(pData->uLastChild == 0)
3109 return 0;
3110
3111 while(pData->uLastChild) {
3112 TreeListDeleteItem(pData, pData->uLastChild, 0);
3113 }
3114
3115 pData->uItemPosCount = 0;
3116
3119
3120 return 1;
3121 }
3122
3123 if(iMode == 2) { // Nur Kindereinträge löschen
3124 if(!pEntry->uFirstChild) {
3125 return 0;
3126 }
3127
3128 while(pEntry->uLastChild) { // Alle Kinder löschen
3129 TreeListDeleteItem(pData, pEntry->uLastChild, 0);
3130 }
3131
3132 uPos = pEntry->uShowPos;
3133 if(uPos) {
3134 UpdateItems(pData, uItem);
3135 }
3136
3137 return 1;
3138 }
3139
3140 while(pEntry->uLastChild) { // Alle Kinder löschen
3141 TreeListDeleteItem(pData, pEntry->uLastChild, 0);
3142 }
3143
3144 if(uItem == pData->uSelectedItem) { // Einen ausgewählten Eintrag löschen
3145 sNotify.hdr.code = TVN_SELCHANGED;
3146 sNotify.action = TVC_UNKNOWN;
3147 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3148 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3149 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3150 sNotify.itemOld.state = pEntry->uState&~TVIS_SELECTED;
3151 sNotify.itemOld.lParam = pEntry->lParam;
3152 sNotify.itemOld.cChildren = 0;
3153 sNotify.itemOld.pszText = (LPTSTR) - 1;
3154 sNotify.itemOld.cchTextMax = -1;
3155 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3156 sNotify.itemNew.hItem = NULL;
3157 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3158 sNotify.itemNew.state = 0;
3159 sNotify.itemNew.lParam = 0;
3160 sNotify.itemNew.cChildren = 0;
3161 sNotify.itemNew.pszText = (LPTSTR) - 1;
3162 sNotify.itemNew.cchTextMax = -1;
3163 sNotify.ptDrag.x = 0;
3164 sNotify.ptDrag.y = 0;
3165
3166 UNLOCK(pData);
3167 SendNotify(pData, &sNotify.hdr); // Bekant geben das der Eintrag nicht mehr ausgewählt ist
3168 LOCK(pData);
3169
3170 pData->uSelectedItem = 0;
3171 pData->uSelectedSub = 0;
3172 }
3173
3174 sNotify.hdr.code = TVN_DELETEITEM;
3175 sNotify.itemNew.mask = 0;
3176 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
3177 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3178 sNotify.itemOld.lParam = pEntry->lParam;
3179 sNotify.itemOld.pszText = (LPTSTR) - 1;
3180 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3181 sNotify.itemNew.state = pEntry->uState;
3182 sNotify.itemOld.cchTextMax = -1;
3183 sNotify.ptDrag.x = 0;
3184 sNotify.ptDrag.y = 0;
3185
3186 UNLOCK(pData);
3187 SendNotify(pData, &sNotify.hdr);
3188 LOCK(pData);
3189
3190 pEntry = pData->pTreeItems[uItem]; // Prüfen ob der Eintrag noch existiert
3191 if(!pEntry)
3192 return 0;
3193
3194 if(uItem == pData->uTrackedItem) { // Einen unterstrichenen Eintrag löschen
3195 pData->uTrackedItem = 0;
3196 pData->uTrackedSub = 0;
3197 }
3198
3199 if(pData->uInsertMark == uItem) {
3200 pData->uInsertMark = 0;
3201 }
3202
3203 if(pData->uSingleSel == uItem) {
3204 pData->uSingleSel = 0;
3205 }
3206
3207 if(pEntry->uPrevItem) { // Gibt es einen vorherigen Eintrag
3208 pTemp = pData->pTreeItems[pEntry->uPrevItem];
3209 pTemp->uNextItem = pEntry->uNextItem;
3210 } else {
3211 if(pEntry->uParent) { // Neues erstes Kind in Elterneintrag
3212 pTemp = pData->pTreeItems[pEntry->uParent];
3213 pTemp->uFirstChild = pEntry->uNextItem;
3214 } else {
3215 pData->uFirstChild = pEntry->uNextItem;
3216 }
3217 }
3218
3219 if(pEntry->uNextItem) { // Gibt es einen vorherigen Eintrag
3220 pTemp = pData->pTreeItems[pEntry->uNextItem];
3221 pTemp->uPrevItem = pEntry->uPrevItem;
3222 } else {
3223 if(pEntry->uParent) { // Neues letztes Kind in Elterneintrag
3224 pTemp = pData->pTreeItems[pEntry->uParent];
3225 pTemp->uLastChild = pEntry->uPrevItem;
3226
3227 if(pTemp->uFirstChild == 0 && pTemp->uLastChild == 0) {
3228 pTemp->bFlags &= ~TVIX_HASBUTTON;
3229 }
3230 } else {
3231 pData->uLastChild = pEntry->uPrevItem;
3232 }
3233 }
3234
3235 for(uPos = 1; uPos < pData->uColumnCount; uPos++) { // Alle Extraeinträge löschen
3236 pList = pData->pExtraItems[uPos - 1];
3237
3238 pExtra = pList[uItem];
3239 if(!pExtra)
3240 continue;
3241
3242 pList[uItem] = NULL;
3243
3244 if(pExtra->pText) {
3245 pExtra->uTextSize = 0;
3246 delete(pExtra->pText);
3247 }
3248
3249 delete(pExtra);
3250 }
3251
3252
3253 pData->pTreeItems[uItem] = NULL; // Den Eintrag löschen
3254
3255 if(pEntry->pText) {
3256 pEntry->uTextSize = 0;
3257 delete(pEntry->pText);
3258 }
3259
3260 if(iMode) { // Den Eintrag neuzeichnen
3261 uItem = pEntry->uPrevItem;
3262 if(!uItem && !pEntry->uNextItem) {
3263 uItem = pEntry->uParent;
3264 if(!uItem)
3265 uPos = 1;
3266 else
3267 uPos = pData->pTreeItems[uItem]->uShowPos;
3268 } else {
3269 uPos = pEntry->uShowPos;
3270 }
3271
3272 if(uPos) {
3273 UpdateItems(pData, uItem);
3274 }
3275 }
3276
3277 if(pEntry->uState & TVIS_SELECTED) // Ausgewählte Einträge runterzählen
3278 if(pData->uSelectedCount > 0) {
3279 pData->uSelectedCount--;
3280 }
3281
3282 delete(pEntry);
3283
3284 pData->uTreeItemsCount--;
3285
3286 iOff = pData->uScrollY; // Prüfe die Scrollposition
3287 iMax = pData->uItemPosCount;
3288 iMax -= pData->uPageEnties - 1;
3289
3290 if(iOff >= iMax)
3291 iOff = iMax;
3292 if(iOff < 0)
3293 iOff = 0;
3294 if(iOff != (int)pData->uScrollY) {
3295 pData->uScrollY = iOff;
3296 SetScrollPos(pData->hWnd, SB_VERT, iOff, TRUE);
3298 }
3299
3300 return 1;
3301}
3302
3303//*****************************************************************************
3304//*
3305//* TreeListXorSelectItem
3306//*
3307//*****************************************************************************
3308// Wählt einen Eintrag ab bzw. an
3309// pData : Zeiger auf die Fensterdaten
3310// uItem : Ist die Nummer des Eintrages der ausgewählt werden soll
3311// iMode : Ist der Grund für die Änderung
3312// TVC_BYKEYBOARD
3313// TVC_BYMOUSE
3314// TVC_UNKNOWN
3315// Ergibt 1 wenn der Eintrag ab/angewählt wurde
3316// 0 wenn der Eintrag nicht verändert wurde
3317static int TreeListXorSelectItem(TreeListData *pData, unsigned uItem, int iMode) {
3318
3319 NMTREEVIEW sNotify;
3321 unsigned uOld;
3322 unsigned uRet;
3323
3324 pEntry = pData->pTreeItems[uItem];
3325 if(!pEntry)
3326 return 0;
3327 if(uItem == pData->uSelectedItem)
3328 return 0;
3329
3330 uOld = pEntry->uState;
3331
3332 sNotify.hdr.code = TVN_SELCHANGING;
3333 sNotify.action = iMode;
3334 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3335 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3336 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3337 sNotify.itemNew.state = pEntry->uState;
3338 sNotify.itemNew.lParam = pEntry->lParam;
3339 sNotify.itemNew.cChildren = 0;
3340 sNotify.itemNew.pszText = (LPTSTR) - 1;
3341 sNotify.itemNew.cchTextMax = -1;
3342 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3343 sNotify.itemOld.hItem = NULL;
3344 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3345 sNotify.itemOld.state = 0;
3346 sNotify.itemOld.lParam = 0;
3347 sNotify.itemOld.cChildren = 0;
3348 sNotify.itemOld.pszText = (LPTSTR) - 1;
3349 sNotify.itemOld.cchTextMax = -1;
3350 sNotify.ptDrag.x = 0;
3351 sNotify.ptDrag.y = 0;
3352
3353 UNLOCK(pData);
3354 uRet = U(SendNotify(pData, &sNotify.hdr));
3355 LOCK(pData);
3356
3357 if(uRet)
3358 return 0;
3359
3360 pEntry = pData->pTreeItems[uItem];
3361 if(!pEntry)
3362 return 0;
3363 pEntry->uState ^= TVIS_SELECTED;
3364
3365 sNotify.hdr.code = TVN_SELCHANGED;
3366 sNotify.action = iMode;
3367 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3368 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3369 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3370 sNotify.itemNew.state = pEntry->uState;
3371 sNotify.itemNew.lParam = pEntry->lParam;
3372 sNotify.itemNew.cChildren = 0;
3373 sNotify.itemNew.pszText = (LPTSTR) - 1;
3374 sNotify.itemNew.cchTextMax = -1;
3375 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3376 sNotify.itemOld.hItem = NULL;
3377 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3378 sNotify.itemOld.state = 0;
3379 sNotify.itemOld.lParam = 0;
3380 sNotify.itemOld.cChildren = 0;
3381 sNotify.itemOld.pszText = (LPTSTR) - 1;
3382 sNotify.itemOld.cchTextMax = -1;
3383 sNotify.ptDrag.x = 0;
3384 sNotify.ptDrag.y = 0;
3385
3386 UNLOCK(pData);
3387 SendNotify(pData, &sNotify.hdr);
3388 LOCK(pData);
3389
3390 pEntry = pData->pTreeItems[uItem];
3391 if(!pEntry)
3392 return 0;
3393 if(pEntry->uShowPos) {
3394 if(pData->uStyleEx & TVS_EX_FULLROWMARK)
3395 UpdateRow(pData, uItem);
3396 else
3397 UpdateRect(pData, uItem, 0);
3398 }
3399
3400 if((uOld ^ pEntry->uState)&TVIS_SELECTED) {
3401 if(pEntry->uState & TVIS_SELECTED)
3402 pData->uSelectedCount++;
3403 else
3404 pData->uSelectedCount--;
3405 }
3406
3407 return 1;
3408}
3409
3410
3411//*****************************************************************************
3412//*
3413//* TreeListRemoveFocus
3414//*
3415//*****************************************************************************
3416// Wählt den Focus ab
3417// pData : Zeiger auf die Fensterdaten
3419
3420 ExtraItem *pExtra;
3422 unsigned uItem;
3423 unsigned uSub;
3424
3425 if(!pData->uFocusItem)
3426 return;
3427
3428 uItem = pData->uFocusItem;
3429 pEntry = pData->pTreeItems[uItem];
3430
3431 if(pEntry) {
3432 pEntry->bFlags &= ~TVIX_FOCUSED;
3433
3434 uSub = pData->uFocusSub;
3435
3436 if(uSub) {
3437 pExtra = pData->pExtraItems[uSub - 1][uItem];
3438 if(pExtra)
3439 pExtra->bFlags &= ~TVIX_FOCUSED;
3440 }
3441
3442 UpdateRect(pData, uItem, uSub);
3443 }
3444
3445 pData->uFocusItem = 0;
3446 pData->uFocusSub = 0;
3447}
3448
3449//*****************************************************************************
3450//*
3451//* TreeListSetFocus
3452//*
3453//*****************************************************************************
3454// Wählt den Focus-Eintrag
3455// pData : Zeiger auf die Fensterdaten
3456// uItem : Eintrag für den Focus (0xFFFFFFFF=keine Änderung)
3457// uSub : Spalte für den Focus (0xFFFFFFFF=keine Änderung)
3458// Ergibt 1 wenn der Focus gesetzt wurde, bzw 0 bei einem Fehler
3459static int TreeListSetFocus(TreeListData *pData, unsigned uItem, unsigned uSub) {
3460
3461 ExtraItem *pExtra;
3463 BaseItem *pTemp;
3464 unsigned uTemp;
3465 unsigned uCol;
3466
3467 if(pData->uFocusItem) {
3468 if(uSub == 0xFFFFFFFF)
3469 uSub = pData->uFocusSub;
3470 if(uItem == 0xFFFFFFFF)
3471 uItem = pData->uFocusItem;
3472 } else {
3473 if(uSub == 0xFFFFFFFF)
3474 uSub = pData->uSelectedSub;
3475 if(uItem == 0xFFFFFFFF)
3476 uItem = pData->uSelectedItem;
3477 }
3478
3479 if(pData->uFocusItem == uItem)
3480 if(pData->uFocusSub == uSub)
3481 return 1;
3482
3483 if(!uItem) { // Focus abwählen
3485 return 1;
3486 }
3487
3488
3489 if(uItem > pData->uTreeItemsMax) { // Den Eintrag prüfen
3490 return 0;
3491 }
3492
3493 pEntry = pData->pTreeItems[uItem];
3494 if(!pEntry) {
3495 return 0;
3496 }
3497
3498 if(!(pData->uStyleEx & TVS_EX_SUBSELECT))
3499 uSub = 0;
3500
3501 if(!(pData->uStyleEx & TVS_EX_MULTISELECT)) { // Einzel auswahl
3502 return TreeListSelectItem(pData, uItem, uSub, TVC_UNKNOWN);
3503 }
3504
3505 uTemp = pData->uFocusItem;
3506 pTemp = pData->pTreeItems[uTemp];
3507
3508 if(pTemp) { // Den alten Eintrag abwählen
3509 pTemp->bFlags &= ~TVIX_FOCUSED;
3510 uCol = pData->uFocusSub;
3511
3512 if(uCol) {
3513 pExtra = pData->pExtraItems[uCol - 1][uTemp];
3514 if(pExtra)
3515 pExtra->bFlags &= ~TVIX_FOCUSED;
3516 }
3517
3518 UpdateRect(pData, uItem, uSub);
3519 }
3520
3521
3522 if(uSub) { // Neuen Eintrag wählen
3523 pExtra = pData->pExtraItems[uSub - 1][uItem];
3524 if(pExtra)
3525 pExtra->bFlags |= TVIX_FOCUSED;
3526 } else {
3527 pEntry->bFlags |= TVIX_FOCUSED;
3528 }
3529
3530 pData->uFocusItem = uItem;
3531 pData->uFocusSub = uSub;
3532
3533 if(pEntry->uState & TVIS_SELECTED) { // Auch die Auswahl nachziehen
3534 if(pData->uSelectedItem != uItem) {
3535 uTemp = pData->uSelectedItem;
3536 uCol = pData->uSelectedSub;
3537 } else {
3538 uTemp = 0;
3539 uCol = pData->uSelectedSub;
3540 }
3541
3542 pData->uSelectedItem = uItem;
3543 pData->uSelectedSub = uSub;
3544
3545 if(pData->uStyleEx & TVS_EX_FULLROWMARK) {
3546 uCol = uSub + 1;
3547 }
3548
3549 if(uTemp) {
3550 if(uCol != uSub)
3551 UpdateRow(pData, uTemp);
3552 else
3553 UpdateRect(pData, uTemp, uCol);
3554 }
3555
3556
3557 if(uCol != uSub)
3558 UpdateRow(pData, uItem);
3559 else
3560 UpdateRect(pData, uItem, uCol);
3561 } else {
3562 UpdateRect(pData, uItem, uSub);
3563 }
3564
3565 return 1;
3566}
3567
3568//*****************************************************************************
3569//*
3570//* TreeListSelectItem
3571//*
3572//*****************************************************************************
3573// Wählt einen Eintrag aus
3574// pData : Zeiger auf die Fensterdaten
3575// uItem : Ist die Nummer des Eintrages der ausgewählt werden soll
3576// uSubItem : Ist die Spalte die gewählt werden soll
3577// iMode : Ist der Grund für die Änderung
3578// TVC_BYKEYBOARD
3579// TVC_BYMOUSE
3580// TVC_UNKNOWN
3581// TVC_ONLYFOCUS (nur der Focus hat sich verändert)
3582// TVC_DESELECT (dieses Flag löscht die alte Auswahl)
3583// TVC_UNSELECT (dieses Flag löscht Auswahl bei MultiSel)
3584// Ergibt 2 wenn der Eintrag gewählt und umgeklapt wurde
3585// 1 wenn der Eintrag gewählt wurde
3586// 0 wenn der Eintrag nicht gewählt wurde
3587static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int iMode) {
3588
3589 NMTREEVIEW sNotify;
3590 ExtraItem *pExtra;
3592 BaseItem *pTemp;
3593 LPARAM lParam;
3594 LPARAM lPaOld;
3595 unsigned uState;
3596 unsigned uStOld;
3597 unsigned uNext;
3598 unsigned uPos;
3599 unsigned uOld;
3600 unsigned uSub;
3601 unsigned uRet;
3602 int iDel;
3603 int iSel;
3604
3605 uOld = pData->uSelectedItem;
3606 uSub = pData->uSelectedSub;
3607
3608 if(uSubItem >= pData->uColumnCount && uSubItem > 0)
3609 return 0;
3610 if(uItem > pData->uTreeItemsMax)
3611 return 0;
3612 if(uItem == uOld)
3613 if(uSubItem == uSub)
3614 if(pData->uSelectedCount <= 1 || !(pData->uStyleEx & TVS_EX_MULTISELECT)) {
3615 return 1;
3616 }
3617
3618 if(pData->uStyleEx & TVS_EX_MULTISELECT) { // Ist die Mehrfachauswahl möglich
3619 iSel = iMode & TVC_UNSELECT;
3620 iDel = iMode & TVC_DESELECT;
3621 if(!iDel) {
3622 if(pData->uStyleEx & (TVS_EX_FULLROWMARK | TVS_EX_SUBSELECT))
3623 UpdateRow(pData, uOld);
3624 else
3625 UpdateRect(pData, uOld, uSub);
3626
3627 uOld = 0;
3628 uSub = 0;
3629 } else { // Alle gewählten Einträge abwählen
3630 if(pData->uSelectedCount > 1 && pData->uTreeItemsMax) {
3631 for(uPos = pData->uTreeItemsMax; uPos; uPos--) {
3632 pEntry = pData->pTreeItems[uPos];
3633 if(!pEntry || !(pEntry->uState & TVIS_SELECTED))
3634 continue;
3636 if(!pData->uSelectedCount)
3637 break; // Wurden alle Einträge abgewählt
3638 }
3639 }
3640 }
3641 } else { // Altes Select löschen
3642 iMode &= ~TVC_ONLYFOCUS;
3643 iDel = 1;
3644 iSel = 0;
3645 }
3646
3648
3649 pEntry = pData->pTreeItems[uItem];
3650 if(!pEntry) { // Neuen Statatus holen
3651 if(uItem)
3652 return 0;
3653 uState = 0;
3654 lParam = 0;
3655 } else {
3656 uState = pEntry->uState;
3657 lParam = pEntry->lParam;
3658
3659 if(uSubItem) {
3660 uState &= TVIS_BASEFLAGS;
3661 pExtra = pData->pExtraItems[uSubItem - 1][uItem];
3662 if(pExtra)
3663 uState |= pExtra->uState;
3664 }
3665 }
3666
3667 pTemp = pData->pTreeItems[uOld];
3668 if(!pTemp) { // Alten Status holen
3669 uStOld = 0;
3670 lPaOld = 0;
3671 } else {
3672 uStOld = pTemp->uState;
3673 lPaOld = pTemp->lParam;
3674
3675 if(uSub) {
3676 uStOld &= TVIS_BASEFLAGS;
3677 pExtra = pData->pExtraItems[uSub - 1][uOld];
3678 if(pExtra)
3679 uStOld |= pExtra->uState;
3680 }
3681 }
3682
3683 sNotify.hdr.code = TVN_SELCHANGING;
3684 sNotify.action = iMode;
3685 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3686 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3687 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3688 sNotify.itemNew.state = uState;
3689 sNotify.itemNew.lParam = lParam;
3690 sNotify.itemNew.cChildren = uSubItem;
3691 sNotify.itemNew.pszText = (LPTSTR) - 1;
3692 sNotify.itemNew.cchTextMax = -1;
3693 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3694 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uOld;
3695 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3696 sNotify.itemOld.state = uStOld;
3697 sNotify.itemNew.lParam = lPaOld;
3698 sNotify.itemOld.cChildren = uSub;
3699 sNotify.itemOld.pszText = (LPTSTR) - 1;
3700 sNotify.itemOld.cchTextMax = -1;
3701 sNotify.ptDrag.x = 0;
3702 sNotify.ptDrag.y = 0;
3703
3704
3705 UNLOCK(pData);
3706
3707 if(SendNotify(pData, &sNotify.hdr)) { // Abfragen ob der Eintrag gewählt werden darf
3708 LOCK(pData);
3709 return 0;
3710 }
3711
3712 LOCK(pData);
3713
3714 if(uItem) { // Prüfen ob der Eintrag noch existiert
3715 pEntry = pData->pTreeItems[uItem];
3716 if(!pEntry)
3717 return 0;
3718 }
3719
3720 if(iDel) {
3721 uOld = pData->uSelectedItem;
3722 pTemp = pData->pTreeItems[uOld];
3723 }
3724
3725
3726 if(pTemp) { // Den alten Eintrag abwählen
3727 if(pTemp->uShowPos) { // Den Eintrag neu zeichnen
3728 if((pData->uStyleEx & TVS_EX_FULLROWMARK) || pData->uSelectedSub)
3729 UpdateRow(pData, uOld);
3730 else
3731 UpdateRect(pData, uOld, uSub);
3732 }
3733
3734 if(pTemp->uState & TVIS_SELECTED) {
3735 uStOld &= ~TVIS_SELECTED;
3736 pTemp->uState &= ~TVIS_SELECTED;
3737
3738 if(pData->uSelectedCount > 0) {
3739 pData->uSelectedCount -= 1;
3740 }
3741 }
3742
3743 pData->uSelectedSub = 0;
3744 pData->uSelectedItem = 0;
3745 } else {
3746 uOld = 0;
3747 }
3748
3749
3750 if(uItem) { // Den neuen Eintrag wählen
3751 if(iSel) {
3752 if(pEntry->uState & TVIS_SELECTED) {
3753 uState &= ~TVIS_SELECTED;
3754 pEntry->uState &= ~TVIS_SELECTED;
3755 if(pData->uSelectedCount)
3756 pData->uSelectedCount--;
3757 }
3758 } else {
3759 if(!(pEntry->uState & TVIS_SELECTED)) {
3760 uState |= TVIS_SELECTED;
3761 pEntry->uState |= TVIS_SELECTED;
3762 pData->uSelectedCount += 1;
3763 }
3764 }
3765
3766 if(uSubItem && uSubItem < pData->uColumnCount) {
3767 pExtra = pData->pExtraItems[uSubItem - 1][uItem];
3768 if(!pExtra) {
3769 pExtra = new(ExtraItem, 1);
3770 memset(pExtra, 0, sizeof(ExtraItem));
3771 pExtra->iImage = TV_NOIMAGE;
3772 pExtra->uState = pEntry->uState & (TVIS_BOLD | TVIS_UNDERLINE);
3773 pData->pExtraItems[uSubItem - 1][uItem] = pExtra;
3774 }
3775
3776 uState = pExtra->uState;
3777 uState |= pEntry->uState & TVIS_BASEFLAGS;
3778 } else {
3779 uState = pEntry->uState;
3780 }
3781
3782 if(pEntry->uShowPos) { // Den Eintrag neu zeichnen
3783 if(pData->uStyleEx & (TVS_EX_FULLROWMARK | TVS_EX_SUBSELECT))
3784 UpdateRow(pData, uItem);
3785 else
3786 UpdateRect(pData, uItem, uSubItem);
3787 }
3788
3789 pData->uSelectedSub = uSubItem;
3790 pData->uSelectedItem = uItem;
3791 } else {
3792 pData->uSelectedItem = 0;
3793 pData->uSelectedSub = 0;
3794 uState = 0;
3795 }
3796
3797 sNotify.hdr.code = TVN_SELCHANGED;
3798 sNotify.action = iMode;
3799 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3800 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3801 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3802 sNotify.itemNew.state = uState;
3803 sNotify.itemNew.lParam = lParam;
3804 sNotify.itemNew.cChildren = uSubItem;
3805 sNotify.itemNew.pszText = (LPTSTR) - 1;
3806 sNotify.itemNew.cchTextMax = -1;
3807 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3808 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uOld;
3809 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3810 sNotify.itemOld.state = uStOld;
3811 sNotify.itemOld.lParam = lPaOld;
3812 sNotify.itemOld.cChildren = uSub;
3813 sNotify.itemOld.pszText = (LPTSTR) - 1;
3814 sNotify.itemOld.cchTextMax = -1;
3815 sNotify.ptDrag.x = 0;
3816 sNotify.ptDrag.y = 0;
3817
3818 UNLOCK(pData);
3819 SendNotify(pData, &sNotify.hdr);
3820 LOCK(pData);
3821
3822 if(!(pData->uStyle & TVS_SINGLEEXPAND)) { // Einzelmodus aktiv
3823 if(pData->uStyle & TVS_SHOWSELALWAYS)
3824 if(pData->uSelectedItem) {
3825 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
3826 }
3827
3828 return 1;
3829 }
3830
3831
3832 //*****************************************************************************
3833
3834
3835 sNotify.hdr.code = TVN_SINGLEEXPAND;
3836 sNotify.action = iMode;
3837 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
3838 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3839 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3840 sNotify.itemNew.state = (pEntry) ? pEntry->uState : 0;
3841 sNotify.itemNew.cChildren = 0;
3842 sNotify.itemNew.pszText = (LPTSTR) - 1;
3843 sNotify.itemNew.cchTextMax = -1;
3844 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
3845 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uOld;
3846 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3847 sNotify.itemOld.state = (pTemp) ? pTemp->uState : 0;
3848 sNotify.itemOld.cChildren = 0;
3849 sNotify.itemOld.pszText = (LPTSTR) - 1;
3850 sNotify.itemOld.cchTextMax = -1;
3851 sNotify.ptDrag.x = 0;
3852 sNotify.ptDrag.y = 0;
3853
3854 UNLOCK(pData);
3855 uRet = U(SendNotify(pData, &sNotify.hdr)); // Anfragen ob die Zweige umgeklappt werden dürfen
3856 LOCK(pData);
3857
3858
3859 pTemp = pData->pTreeItems[uOld ]; // Zeiger neu holen falls es Änderungen gab
3860 pEntry = pData->pTreeItems[uItem];
3861
3862 while(pTemp && pEntry) { // Beide Zweige sysnchronisieren
3863 if(pEntry->uLevel > pTemp->uLevel) {
3864 uNext = pEntry->uParent;
3865
3866 if(!(uRet & TVNRET_SKIPNEW))
3867 if(!(pEntry->uState & TVIS_EXPANDED)) {
3868 TreeListToggleItem(pData, uItem, 0);
3869 }
3870
3871 pEntry = pData->pTreeItems[uNext];
3872 uItem = uNext;
3873
3874 if(!uItem)
3875 break;
3876
3877 continue;
3878 }
3879
3880 if(uItem == uOld)
3881 goto EndSel; // Bis zum gleichen Knoten
3882
3883 uNext = pTemp->uParent;
3884
3885 if(!(uRet & TVNRET_SKIPOLD))
3886 if(pTemp->uState & TVIS_EXPANDED) {
3887 TreeListToggleItem(pData, uOld, 0);
3888 }
3889
3890 pTemp = pData->pTreeItems[uNext];
3891 uOld = uNext;
3892 }
3893
3894 if(!uItem) {
3895 if(!(uRet & TVNRET_SKIPOLD))
3896 while(pTemp) { // Alten Zweig zuklappen
3897 uNext = pTemp->uParent;
3898
3899 if(pTemp->uState & TVIS_EXPANDED) {
3900 TreeListToggleItem(pData, uOld, 0);
3901 }
3902
3903 pTemp = pData->pTreeItems[uNext];
3904 uOld = uNext;
3905 }
3906
3907 goto EndSel;
3908 }
3909
3910 if(!uOld) {
3911 if(!(uRet & TVNRET_SKIPNEW))
3912 while(pEntry) { // Neuen Zweig aufklappen
3913 uNext = pEntry->uParent;
3914
3915 if(!(pEntry->uState & TVIS_EXPANDED)) {
3916 TreeListToggleItem(pData, uItem, 0);
3917 }
3918
3919 pEntry = pData->pTreeItems[uNext];
3920 uItem = uNext;
3921 }
3922 }
3923
3924EndSel:
3925
3926 if(pData->uStyle & TVS_SHOWSELALWAYS)
3927 if(pData->uSelectedItem) {
3928 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
3929 }
3930
3931 return 2;
3932}
3933
3934//*****************************************************************************
3935//*
3936//* TreeListSelectChilds
3937//*
3938//*****************************************************************************
3939// Wählt einen Eintrag aus
3940// pData : Zeiger auf die Fensterdaten
3941// uItem : Ist die Nummer des Eintrages der ausgewählt werden soll
3942// iMode : Bit 0 = Untereintäge auch ändern
3943// Bit 1 = Einträge abwählen
3944// Ergibt 1 wenn die Auswahl funktioniert hat, bzw. 0 bei einem Fehler
3945static int TreeListSelectChilds(TreeListData *pData, unsigned uItem, int iMode) {
3946
3948 unsigned uLevel;
3949 unsigned uXor;
3950
3951 if(!(pData->uStyleEx & TVS_EX_MULTISELECT))
3952 return 0;
3953
3954 uLevel = 0;
3955
3956 if(uItem == U(TVI_ROOT)) {
3957 uItem = pData->uFirstChild;
3958 } else {
3959 if(uItem > pData->uTreeItemsMax)
3960 return 0;
3961 }
3962
3963 if(!pData->pTreeItems[uItem]) {
3964 return 0;
3965 }
3966
3967
3968 uXor = (iMode & TVIS_DESELECT) ? 0 : TVIS_SELECTED;
3970
3971 for(;;) {
3972 pEntry = pData->pTreeItems[uItem];
3973
3974 if((pEntry->uState ^ uXor)&TVIS_SELECTED) {
3976 }
3977
3978 if(iMode && pEntry->uFirstChild) { // Auch Kinder ändern
3979 uItem = pEntry->uFirstChild;
3980 uLevel++;
3981 continue;
3982 }
3983
3984 for(;;) { // Eine Ebene höher
3985 uItem = pEntry->uNextItem;
3986 if(uItem != 0)
3987 break;
3988 if(uLevel == 0)
3989 return 1;
3990
3991 uLevel--;
3992
3993 uItem = pEntry->uParent;
3994 pEntry = pData->pTreeItems[uItem];
3995 }
3996 }
3997}
3998
3999//*****************************************************************************
4000//*
4001//* TreeListInsertItem
4002//*
4003//*****************************************************************************
4004// Fügt einen Eintrag ins Fenster ein
4005// pData : Zeiger auf die Fensterdaten
4006// pInsert : Zeiger auf die ein zu fügenden Daten
4007// Ergibt die Einfügeposition des neuen Eintrages oder 0 bei einem Fehler
4009
4010 char *pTemp;
4011 BYTE bFlag;
4012 LPCTSTR pText;
4013 LPCTSTR pTextTemp;
4014 PFNTVSORTEX pCompare;
4015 ExtraItem **pExOld[MAX_COLUMNS];
4016 ExtraItem **pExNew[MAX_COLUMNS];
4017 BaseItem *pNew;
4018 BaseItem **pOld;
4019 BaseItem **pItems;
4022 unsigned *pPosNew;
4023 unsigned *pPosOld;
4024 unsigned *pFirst;
4025 unsigned *pLast;
4026 unsigned uBefore;
4027 unsigned uParent;
4028 unsigned uAfter;
4029 unsigned uFirst;
4030 unsigned uSize;
4031 unsigned uBits;
4032 unsigned uItem;
4033 unsigned uNext;
4034 unsigned uMax;
4035 unsigned uPos;
4036 unsigned uNum;
4037 int iCmp;
4038 int iNone;
4039 int iCount;
4040 int iShift;
4041
4042 if(pData->cLockChanges)
4043 return 0;
4044
4045 uParent = U(pInsert->hParent);
4046 if(uParent > pData->uTreeItemsMax) { // Prüfe das Elternelement
4047 if(pInsert->hParent != TVI_ROOT) {
4048 return 0;
4049 }
4050
4051 pParent = NULL;
4052 } else {
4053 pParent = pData->pTreeItems[uParent];
4054 if(!pParent) {
4055 if(uParent)
4056 return 0;
4057 pParent = NULL;
4058 }
4059 }
4060
4061 if(pData->uTreeItemsCount + 1 > pData->uTreeItemsMax) { // Größe der Liste erhöhen
4062 pPosOld = pData->pItemPos;
4063 pOld = pData->pTreeItems;
4064 uMax = pData->uTreeItemsMax;
4065 uMax += pData->uTreeItemsMax / 2;
4066 uMax += 64;
4067 pItems = new(BaseItem*, uMax + 1);
4068
4069 if(!pItems) {
4070 return 0;
4071 }
4072
4073 pPosNew = new(unsigned, uMax);
4074 if(!pPosNew) {
4075 delete(pItems);
4076 return 0;
4077 }
4078
4079 for(uPos = 1; uPos < pData->uColumnCount; uPos++) {
4080 pExOld[uPos] = pData->pExtraItems[uPos - 1];
4081 pExNew[uPos] = new(ExtraItem*, uMax + 1);
4082
4083 if(!pExNew[uPos]) {
4084 for(uPos--; uPos > 0; uPos--)
4085 delete(pExNew[uPos]);
4086 delete(pPosNew);
4087 delete(pItems);
4088 return 0;
4089 }
4090 }
4091
4092 memcpy(pItems , pData->pTreeItems , sizeof(BaseItem *) * (pData->uTreeItemsMax + 1));
4093 memset(pItems + pData->uTreeItemsMax + 1, 0, sizeof(BaseItem *) * (uMax - pData->uTreeItemsMax));
4094 memcpy(pPosNew, pData->pItemPos , sizeof(unsigned) * (pData->uTreeItemsCount));
4095 memset(pPosNew + pData->uTreeItemsCount, 0, sizeof(unsigned) * (uMax - pData->uTreeItemsCount));
4096
4097 for(uPos = 1; uPos < pData->uColumnCount; uPos++) {
4098 memcpy(pExNew[uPos], pExOld[uPos] , sizeof(ExtraItem *) * (pData->uTreeItemsMax + 1));
4099 memset(pExNew[uPos] + pData->uTreeItemsMax + 1, 0, sizeof(ExtraItem *) * (uMax - pData->uTreeItemsMax));
4100 pData->pExtraItems[uPos - 1] = pExNew[uPos];
4101 delete(pExOld[uPos]);
4102 }
4103
4104 pData->uTreeItemsMax = uMax;
4105 pData->pTreeItems = pItems;
4106 pData->pItemPos = pPosNew;
4107 delete(pPosOld);
4108 delete(pOld);
4109 }
4110
4111 //******************** Den neuen Eintrag erzeugen *****************************
4112 pItems = pData->pTreeItems;
4113 uPos = pData->uNextSeachPos + 1;
4114 pTemp = new(char, sizeof(BaseItem) + pData->uUserDataSize);
4115 pNew = (BaseItem *)pTemp;
4116
4117 if(!pNew) { // Konnte der Speicher reserviert werden
4118 return 0;
4119 }
4120
4121 if(pData->uUserDataSize) { // Die Userdaten auf 0 setzen
4122 memset(pTemp + sizeof(BaseItem), 0, pData->uUserDataSize);
4123 }
4124
4125 for(;; uPos++) { // Suche freie Position
4126 if(uPos > pData->uTreeItemsMax)
4127 uPos = 1;
4128 if(pItems[uPos] == NULL)
4129 break;
4130 }
4131
4132 pData->uNextSeachPos = uPos;
4133
4134 memset(pNew, 0, sizeof(BaseItem)); // Erstelle den neuen Eintrag
4135 pNew->iImage = TV_NOIMAGE;
4136 pNew->iSelectedImage = TV_NOIMAGE;
4137
4138 uBits = pInsert->item.mask;
4139
4140 if(uBits & TVIF_STATE) {
4141 pNew->uState = pInsert->item.state & pInsert->item.stateMask;
4142 } else {
4143 if(pData->uStyle & TVS_CHECKBOXES)
4144 if(!(pData->uStyleEx & TVS_EX_BITCHECKBOX)) {
4145 pNew->uState = 0x1000;
4146 }
4147 }
4148
4149 if(uBits & TVIF_PARAM) {
4150 pNew->lParam = pInsert->item.lParam;
4151 }
4152
4153 if(uBits & TVIF_IMAGE) {
4154 pNew->iImage = pInsert->item.iImage;
4155 if(pNew->iImage == I_IMAGECALLBACK)
4156 pNew->bCallback |= TVIF_IMAGE;
4157 }
4158
4159 if(uBits & TVIF_SELECTEDIMAGE) {
4160 pNew->iSelectedImage = pInsert->item.iSelectedImage;
4161 if(pNew->iSelectedImage == I_IMAGECALLBACK)
4163 }
4164
4165 if(uBits & TVIF_CHILDREN) { // Art der Schaltflächen
4166 switch(pInsert->item.cChildren) {
4167 case 0:
4168 break;
4169 case 1:
4170 pNew->bFlags |= TVIX_HASBUTTON;
4171 break;
4172 case I_CCB:
4173 pNew->bCallback |= TVIF_CHILDREN;
4174 break;
4175 default
4176 :
4177 pNew->bFlags |= TVIX_VARBUTTON;
4178 break;
4179 }
4180 } else {
4181 pNew->bFlags |= TVIX_VARBUTTON;
4182 }
4183
4184 if(pData->uStyle & TVS_SINGLEEXPAND) { // Nicht aufklappen bei Einzelmodus
4185 pNew->uState &= ~TVIS_EXPANDED;
4186 }
4187
4188 if(uBits & TVIF_TEXT) { // Text einfügen
4189 if(pInsert->item.pszText == LPSTR_TEXTCALLBACK) {
4190 pNew->bCallback |= TVIF_TEXT;
4191 pNew->uTextSize = 0;
4192 pNew->pText = 0;
4193 } else {
4194 pNew->uTextSize = (WORD)str_len(pInsert->item.pszText);
4195 pNew->pText = new(TCHAR, pNew->uTextSize + 1);
4196 memcpy(pNew->pText, pInsert->item.pszText, sizeof(TCHAR) * (pNew->uTextSize + 1));
4197 }
4198 } else {
4199 pNew->pText = new(TCHAR, 1);
4200 pNew->pText[0] = 0;
4201 pNew->uTextSize = 0;
4202 }
4203
4204 if(!pParent) { // Einen Root-Eintrag einfügen
4205 pNew->uParent = 0;
4206 uParent = 0;
4207 bFlag = 0;
4208 uFirst = 0xFFFFFFFF;
4209 pFirst = &pData->uFirstChild;
4210 pLast = &pData->uLastChild;
4211 } else { // Einen Tree-Eintrag einfügen
4212 pNew->uParent = uParent;
4213 pNew->uLevel = pParent->uLevel + 1;
4214 uFirst = pParent->uFirstChild;
4215 pFirst = &pParent->uFirstChild;
4216 pLast = &pParent->uLastChild;
4217 bFlag = pParent->bFlags;
4218
4219 if(pParent->bFlags & TVIX_VARBUTTON) {
4220 pParent->bFlags |= TVIX_HASBUTTON;
4221 }
4222 }
4223
4224 //******************** Eintrage einfügen **************************************
4225 uAfter = U(pInsert->hInsertAfter);
4226
4227 switch(uAfter) {
4228 case U(TVI_BEFORE): // Nach einem Eintrag einfügen
4229 if(pParent) { // Einen Root-Eintrag einfügen
4230 pEntry = pParent;
4231 pParent ->bFlags = bFlag;
4232 uParent = pParent->uParent;
4233 pParent = pItems [uParent];
4234
4235 if(!pParent) {
4236 pNew->uParent = 0;
4237 pNew->uLevel = 0;
4238 uParent = 0;
4239 uFirst = 0xFFFFFFFF;
4240 pFirst = &pData->uFirstChild;
4241 pLast = &pData->uLastChild;
4242 } else { // Einen Tree-Eintrag einfügen
4243 pNew->uParent = uParent;
4244 pNew->uLevel = pParent->uLevel + 1;
4245 uFirst = pParent->uFirstChild;
4246 pFirst = &pParent->uFirstChild;
4247 pLast = &pParent->uLastChild;
4248
4249 if(pParent->bFlags & TVIX_VARBUTTON) {
4250 pParent->bFlags |= TVIX_HASBUTTON;
4251 }
4252 }
4253
4254 if(pEntry->uPrevItem) {
4255 uAfter = pEntry->uPrevItem;
4256 goto DoInsert;
4257 }
4258 }
4259
4260 case U(TVI_FIRST): // Am Anfang einfügen
4261 if(pFirst[0]) { // Gibt es schon Einträge
4262 pEntry = pItems[pFirst[0]];
4263 pEntry->uPrevItem = uPos;
4264 } else {
4265 pFirst[0] = uPos;
4266 pLast [0] = uPos;
4267 break;
4268 }
4269
4270 pNew ->uNextItem = pFirst[0]; // Eintrag einfügen
4271 pFirst[0] = uPos;
4272 break;
4273
4274 case U(TVI_ROOT): // Als Root-Eintrag einfügen
4275 pNew->uParent = 0;
4276 uParent = 0;
4277 pFirst = &pData->uFirstChild;
4278 pLast = &pData->uLastChild;
4279
4280 case U(TVI_LAST): // Am Ende einfügen
4281 if(pLast[0]) { // Gibt es schon Einträge
4282 pEntry = pItems[pLast[0]];
4283 pEntry->uNextItem = uPos;
4284 } else {
4285 pFirst[0] = uPos;
4286 pLast [0] = uPos;
4287 break;
4288 }
4289
4290 pNew ->uPrevItem = pLast[0]; // Eintrag einfügen
4291 pLast[0] = uPos;
4292 break;
4293
4294
4295 case U(TVI_SORTEX): // Einfügen mittels Funktion
4296 uItem = pFirst[0];
4297 if(!uItem) { // Gibt es keine Kindeinträge
4298 pFirst[0] = uPos;
4299 pLast [0] = uPos;
4300 break;
4301 }
4302
4303 if(pNew->bCallback & TVIF_TEXT) { // Text über Callback holen
4304 uSize = 1;
4305 LOCK(pData);
4306 CallbackEntry(pData, pNew, uPos, TVIF_TEXT, &iNone, &uSize, &pText);
4307 UNLOCK(pData);
4308 } else {
4309 pText = pNew->pText;
4310 }
4311
4312 pData->cLockChanges = 1;
4313
4314 pCompare = (PFNTVSORTEX)(pInsert->item.hItem);
4315 if(!pCompare)
4316 break;
4317 uNext = uItem;
4318 iCount = 0;
4319 uBefore = 0;
4320
4321 while(uNext) { // Zähle die Einträge
4322 iCount++;
4323 uNext = pItems[uNext]->uNextItem;
4324 }
4325
4326 while(iCount > 0) { // Binary-Seach Algorithnus
4327 iShift = iCount / 2;
4328 uNext = uItem;
4329
4330 while(iShift > 0) {
4331 uNext = pItems[uNext]->uNextItem;
4332 iShift--;
4333 }
4334
4335 pEntry = pItems[uNext];
4336 if(pEntry->bCallback & TVIF_TEXT) { // Text über Callback holen
4337 uSize = 0;
4338 LOCK(pData);
4339 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pTextTemp);
4340 UNLOCK(pData);
4341 } else {
4342 pTextTemp = pEntry->pText;
4343 }
4344
4345 iCmp = pCompare(pData->hWnd, (HTREEITEM)(ULONG_PTR)uNext, pTextTemp, pText, pEntry->lParam, pInsert->item.lParam);
4346 if(iCmp < 0) {
4347 iCount -= (iCount + 1) / 2;
4348 continue;
4349 }
4350
4351 if(iCmp > 0) {
4352 iCount -= iCount / 2 + 1;
4353 uBefore = uNext;
4354 uItem = pItems[uNext]->uNextItem;
4355 continue;
4356 }
4357
4358 uBefore = pEntry->uPrevItem;
4359 uItem = uNext;
4360 break;
4361 }
4362
4363 pData->cLockChanges = 0;
4364
4365 pNew->uNextItem = uItem;
4366 pNew->uPrevItem = uBefore;
4367
4368 if(uBefore) { // Vorherigen Eintrag anpassen
4369 pEntry = pItems[uBefore];
4370 pEntry->uNextItem = uPos;
4371 } else { // Am Anfang einfügen
4372 pFirst[0] = uPos;
4373 }
4374
4375 if(uItem) { // Nächsten Eintrag anpassen
4376 pEntry = pItems[uItem];
4377 pEntry->uPrevItem = uPos;
4378 } else { // Am Ende anhängen
4379 pLast[0] = uPos;
4380 }
4381 break;
4382
4383 case U(TVI_SORT): // Alphapetisch einfügen
4384 uItem = pFirst[0];
4385 if(!uItem) { // Gibt es keine Kindeinträge
4386 pFirst[0] = uPos;
4387 pLast [0] = uPos;
4388 break;
4389 }
4390
4391 if(pNew->bCallback & TVIF_TEXT) { // Text über Callback holen
4392 uSize = 1;
4393 LOCK(pData);
4394 CallbackEntry(pData, pNew, uPos, TVIF_TEXT, &iNone, &uSize, &pText);
4395 UNLOCK(pData);
4396 } else {
4397 pText = pNew->pText;
4398 }
4399
4400 pData->cLockChanges = 1;
4401
4402 uNext = uItem;
4403 iCount = 0;
4404 uBefore = 0;
4405
4406 while(uNext) { // Zähle die Einträge
4407 iCount++;
4408 uNext = pItems[uNext]->uNextItem;
4409 }
4410
4411 while(iCount > 0) { // Binary-Seach Algorithnus
4412 iShift = iCount / 2;
4413 uNext = uItem;
4414
4415 while(iShift > 0) {
4416 uNext = pItems[uNext]->uNextItem;
4417 iShift--;
4418 }
4419
4420
4421 pEntry = pItems[uNext];
4422 if(pEntry->bCallback & TVIF_TEXT) { // Text über Callback holen
4423 uSize = 0;
4424 LOCK(pData);
4425 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pTextTemp);
4426 UNLOCK(pData);
4427 } else {
4428 pTextTemp = pEntry->pText;
4429 }
4430
4431 iCmp = str_icmp(pText, pTextTemp);
4432
4433 if(iCmp < 0) {
4434 iCount -= (iCount + 1) / 2;
4435 continue;
4436 }
4437
4438 if(iCmp > 0) {
4439 iCount -= iCount / 2 + 1;
4440 uBefore = uNext;
4441 uItem = pItems[uNext]->uNextItem;
4442 continue;
4443 }
4444
4445 uBefore = pEntry->uPrevItem;
4446 uItem = uNext;
4447 break;
4448 }
4449
4450
4451 pData->cLockChanges = 0;
4452
4453 pNew->uNextItem = uItem;
4454 pNew->uPrevItem = uBefore;
4455
4456 if(uBefore) { // Vorherigen Eintrag anpassen
4457 pEntry = pItems[uBefore];
4458 pEntry->uNextItem = uPos;
4459 } else { // Am Anfang einfügen
4460 pFirst[0] = uPos;
4461 }
4462
4463 if(uItem) { // Nächsten Eintrag anpassen
4464 pEntry = pItems[uItem];
4465 pEntry->uPrevItem = uPos;
4466 } else { // Am Ende anhängen
4467 pLast[0] = uPos;
4468 }
4469 break;
4470
4471 case U(TVI_AFTER): // Nach einem Eintrag einfügen
4472 uAfter = uParent;
4473
4474 if(pParent) { // Einen Root-Eintrag einfügen
4475 pParent ->bFlags = bFlag;
4476 uParent = pParent->uParent;
4477 pParent = pItems [uParent];
4478
4479 if(!pParent) {
4480 pNew->uParent = 0;
4481 pNew->uLevel = 0;
4482 uParent = 0;
4483 uFirst = 0xFFFFFFFF;
4484 pFirst = &pData->uFirstChild;
4485 pLast = &pData->uLastChild;
4486 } else { // Einen Tree-Eintrag einfügen
4487 pNew->uParent = uParent;
4488 pNew->uLevel = pParent->uLevel + 1;
4489 uFirst = pParent->uFirstChild;
4490 pFirst = &pParent->uFirstChild;
4491 pLast = &pParent->uLastChild;
4492
4493 if(pParent->bFlags & TVIX_VARBUTTON) {
4494 pParent->bFlags |= TVIX_HASBUTTON;
4495 }
4496 }
4497 }
4498
4499 default
4500 : // Hinter einen Eintrag einfügen
4501DoInsert:
4502 uItem = pFirst[0];
4503 if(!uItem) { // Gibt es keine Kindeinträge
4504 pFirst[0] = uPos;
4505 pLast [0] = uPos;
4506 break;
4507 }
4508
4509 if(uAfter > pData->uTreeItemsMax) {
4510 if((uAfter & 0xFFF00000) == 0xFFE00000) { // In einer genauen Reihe nach Patent einfügen
4511 uAfter &= 0xFFFFF;
4512
4513 uItem = pFirst[0];
4514 if(!uItem) { // Gibt es keine Kindeinträge
4515 pFirst[0] = uPos;
4516 pLast [0] = uPos;
4517 break;
4518 }
4519
4520 if(uAfter == 0) { // In die erste Reihe einfügen
4521 pEntry = pItems[uItem];
4522 pEntry->uPrevItem = uPos;
4523 pNew ->uNextItem = uItem;
4524 pFirst[0] = uPos;
4525 break;
4526 }
4527
4528 uNum = 1;
4529 uBefore = 0;
4530 // Suche Einfügereihe
4531 for(; uItem; uItem = pItems[uItem]->uNextItem) {
4532 uBefore = uItem;
4533
4534 if(uNum == uAfter) {
4535 uItem = pItems[uItem]->uNextItem;
4536 break;
4537 }
4538
4539 uNum++;
4540 }
4541
4542 pNew->uNextItem = uItem;
4543 pNew->uPrevItem = uBefore;
4544
4545 if(uBefore) { // Vorherigen Eintrag anpassen
4546 pEntry = pItems[uBefore];
4547 pEntry->uNextItem = uPos;
4548 } else { // Am Anfang einfügen
4549 pFirst[0] = uPos;
4550 }
4551
4552 if(uItem) { // Nächsten Eintrag anpassen
4553 pEntry = pItems[uItem];
4554 pEntry->uPrevItem = uPos;
4555 } else { // Am Ende anhängen
4556 pLast[0] = uPos;
4557 }
4558
4559 break;
4560 }
4561
4562 pEntry = NULL;
4563 } else {
4564 pEntry = pItems[uAfter];
4565 }
4566
4567 if(pEntry && uParent == pEntry->uParent) { // Stimmt der Elterneintrag ?
4568 uItem = pEntry->uNextItem;
4569 uBefore = uAfter;
4570 } else {
4571 uItem = 0;
4572 uBefore = pLast[0];
4573 pEntry = pItems[uBefore];
4574 }
4575
4576 pNew->uNextItem = uItem;
4577 pNew->uPrevItem = uBefore;
4578
4579 if(uBefore) { // Vorherigen Eintrag anpassen
4580 pEntry->uNextItem = uPos;
4581 } else { // Am Anfang einfügen
4582 pFirst[0] = uPos;
4583 }
4584
4585 if(uItem) { // Nächsten Eintrag anpassen
4586 pEntry = pItems[uItem];
4587 pEntry->uPrevItem = uPos;
4588 } else { // Am Ende anhängen
4589 pLast[0] = uPos;
4590 }
4591
4592 break;
4593 }
4594
4595 pItems[uPos] = pNew;
4596 pData->uTreeItemsCount++;
4597 // Die Anzeigezeilen akualisieren
4598 if(!pParent || !uFirst || (pParent->uState & TVIS_EXPANDED)) {
4599 uItem = pNew->uPrevItem;
4600 if(!uItem)
4601 uItem = uParent;
4602
4603 if(!uItem)
4604 UpdateItems(pData, 0);
4605 else {
4606 pEntry = pItems[uItem];
4607 if(pEntry && pEntry->uShowPos)
4608 UpdateItems(pData, uItem);
4609 }
4610 }
4611
4612 if(pNew->uState & TVIS_SELECTED) { // Den ausgewählten Eintrag auswählen
4614 }
4615
4616 return uPos;
4617}
4618
4619//*****************************************************************************
4620//*
4621//* TreeListSetItem
4622//*
4623//*****************************************************************************
4624// Ändert einen Eintrag im Fenster
4625// pData : Zeiger auf die Fensterdaten
4626// pItem : Zeiger auf die ein zu ändernden Daten
4627// Ergibt 1 wenn ok oder 0 bei einem Fehler
4628static int TreeListSetItem(TreeListData *pData, const TV_ITEM *pItem) {
4629
4630 BYTE bCall;
4631 BYTE bFlags;
4632 ExtraItem **pList;
4633 ExtraItem *pExtra;
4635 unsigned uChange;
4636 unsigned uMask;
4637 unsigned uBits;
4638 unsigned uItem;
4639 unsigned uSub;
4640 unsigned uLen;
4641 int iVal;
4642 int iRet;
4643
4644 uChange = 0;
4645
4646 uItem = U(pItem->hItem);
4647 if(uItem > pData->uTreeItemsMax)
4648 return 0;
4649
4650 pEntry = pData->pTreeItems[uItem];
4651 if(!pEntry)
4652 return 0;
4653
4654 uBits = pItem->mask;
4655
4656 if(uBits & TVIF_SUBITEM) { // Einen Extraeintrag ändern
4657 uSub = pItem->cChildren;
4658 if(uSub > 0) {
4659 if(uSub >= pData->uColumnCount)
4660 return 0;
4661 pList = pData->pExtraItems[uSub - 1];
4662 pExtra = pList[uItem];
4663
4664 if(!pExtra) { // Einen neuen Eintrag erzeugen
4665 pExtra = new(ExtraItem, 1);
4666 memset(pExtra, 0, sizeof(ExtraItem));
4667 pExtra->iImage = TV_NOIMAGE;
4668 pExtra->uState = pEntry->uState & (TVIS_BOLD | TVIS_UNDERLINE);
4669 pList[uItem] = pExtra;
4670 }
4671
4672 if(uBits & TVIF_PARAM) {
4673 pEntry->lParam = pItem->lParam;
4674 }
4675
4676 if((uBits & TVIF_IMAGE) && pExtra->iImage != pItem->iImage) {
4677 if(pData->hImages)
4678 uChange = 1;
4679 pExtra->iImage = pItem->iImage;
4680 if(pExtra->iImage == I_IMAGECALLBACK)
4681 pExtra->bCallback |= TVIF_IMAGE;
4682 else
4683 pExtra->bCallback &= TVIF_IMAGE;
4684 }
4685
4686 if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen
4687 if(pItem->pszText == LPSTR_TEXTCALLBACK) {
4688 if(pExtra->pText)
4689 delete(pExtra->pText);
4690 pExtra->bCallback |= TVIF_TEXT;
4691 pExtra->uTextSize = 0;
4692 pExtra->pText = 0;
4693 uChange = 1;
4694 } else {
4695 uLen = str_len(pItem->pszText);
4696
4697 if(uLen > pExtra->uTextSize || !pExtra->pText) {
4698 if(pExtra->pText)
4699 delete(pExtra->pText);
4700 pExtra->pText = new(TCHAR, uLen + 1);
4701 }
4702
4703 memcpy(pExtra->pText, pItem->pszText, (uLen + 1)*sizeof(TCHAR));
4704 pExtra->bCallback &= ~TVIF_TEXT;
4705 pExtra->uTextSize = (WORD)uLen;
4706 pExtra->iTextPixels = 0;
4707 uChange = 1;
4708 }
4709 }
4710
4711 if(uBits & TVIF_STATE) { // Den Status ändern
4712 uMask = pItem->stateMask&~TVIS_BASEFLAGS;
4713 uBits = uMask & (pExtra->uState ^ pItem->state);
4714 uBits |= (pItem->stateMask & TVIS_BASEFLAGS) & (pEntry->uState ^ pItem->state);
4715 pExtra->uState &= ~uMask;
4716 pExtra->uState |= uMask & pItem->state;
4717
4718 if((uBits & (TVIS_OVERLAYMASK | TVIS_CUT)) && (pData->hImages || pData->aColumn[uSub].bEdit >= TVAX_CHECK)) {
4719 uChange = 1; // Ein Icon hats sich verändert
4720 }
4721
4722 if(uBits & (TVIS_BOLD | TVIS_DROPHILITED)) {
4723 pExtra->iTextPixels = 0;
4724 uChange = 1;
4725 }
4726
4727 if((uBits & TVIS_EXPANDED) && pEntry->uFirstChild) {
4728 iVal = TreeListToggleItem(pData, uItem, 0);
4729 if(iVal < 0)
4730 return 0;
4731
4732 pEntry = pData->pTreeItems[uItem];
4733 if(!pEntry)
4734 return 0;
4735 }
4736
4737 if(uBits & TVIS_SELECTED) { // Hat sich die Auswahl geändert
4738 iVal = (pData->uStyleEx & TVS_EX_SUBSELECT) ? uSub : 0;
4739
4740 if(pItem->state & TVIS_SELECTED) {
4741 iRet = TreeListSelectItem(pData, uItem, iVal, TVC_UNKNOWN);
4742 } else
4743 if(pData->uStyleEx & TVS_EX_MULTISELECT) {
4745 iRet = TreeListXorSelectItem(pData, uItem, TVC_UNKNOWN);
4746 } else {
4747 iRet = TreeListSelectItem(pData, 0, 0, TVC_UNKNOWN);
4748 }
4749
4750 pEntry = pData->pTreeItems[uItem];
4751 if(!pEntry)
4752 return 0;
4753
4754 if(iRet >= 2) {
4755 pList = pData->pExtraItems[uSub - 1];
4756 pExtra = pList[uItem];
4757 if(!pExtra)
4758 return 0;
4759 } else
4760 if(iRet == 1) {
4761 uChange = 1;
4762 }
4763 }
4764 }
4765
4766 if(!uChange || !pEntry->uShowPos)
4767 return 1; // Neuzeichnen des Eintrages
4768
4769 UpdateRect(pData, uItem, uSub);
4770
4771 return 1;
4772 }
4773
4774 uBits &= ~TVIF_CHILDREN;
4775 }
4776
4777 //******************** Einen Basis Eintrag ändern *****************************
4778 if(uBits & TVIF_PARAM) {
4779 pEntry->lParam = pItem->lParam;
4780 }
4781
4782 if((uBits & TVIF_IMAGE) && pEntry->iImage != pItem->iImage) {
4783 pEntry->iImage = pItem->iImage;
4784 if(!(pEntry->uState & TVIS_SELECTED) && pData->hImages)
4785 uChange = 1;
4786 if(pEntry->iImage == I_IMAGECALLBACK)
4787 pEntry->bCallback |= TVIF_IMAGE;
4788 else
4789 pEntry->bCallback &= TVIF_IMAGE;
4790 }
4791
4792 if((uBits & TVIF_SELECTEDIMAGE) && pEntry->iSelectedImage != pItem->iSelectedImage) {
4793 pEntry->iSelectedImage = pItem->iSelectedImage;
4794 if((pEntry->uState & TVIS_SELECTED) && pData->hImages)
4795 uChange = 1;
4796 if(pEntry->iSelectedImage == I_IMAGECALLBACK)
4797 pEntry->bCallback |= TVIF_SELECTEDIMAGE;
4798 else
4799 pEntry->bCallback &= TVIF_SELECTEDIMAGE;
4800 }
4801
4802 if(uBits & TVIF_CHILDREN) {
4803 bCall = pEntry->bCallback;
4804 bFlags = pEntry->bFlags;
4805
4806 switch(pItem->cChildren) {
4807 case 0:
4808 pEntry->bCallback &= ~TVIF_CHILDREN;
4809 pEntry->bFlags &= ~TVIX_HASBUTTON;
4810 pEntry->bFlags |= TVIX_VARBUTTON;
4811 break;
4812
4813 case 1:
4814 pEntry->bCallback &= ~TVIF_CHILDREN;
4815 pEntry->bFlags &= TVIX_VARBUTTON;
4816 pEntry->bFlags |= TVIX_HASBUTTON;
4817 break;
4818
4819 case I_CCB:
4820 pEntry->bCallback |= TVIF_CHILDREN;
4821 pEntry->bFlags &= ~TVIX_VARBUTTON;
4822 break;
4823
4824 default
4825 :
4826 pEntry->bCallback &= ~TVIF_CHILDREN;
4827 pEntry->bFlags |= TVIX_VARBUTTON;
4828
4829 if(pEntry->uFirstChild)
4830 pEntry->bFlags |= TVIX_HASBUTTON;
4831 else
4832 pEntry->bFlags &= ~TVIX_HASBUTTON;
4833 }
4834
4835 if(bCall != pEntry->bCallback || bFlags != pEntry->bFlags) {
4836 uChange = 1;
4837 }
4838 }
4839
4840 if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen
4841 if(pItem->pszText == LPSTR_TEXTCALLBACK) {
4842 if(pEntry->pText)
4843 delete(pEntry->pText);
4844 pEntry->bCallback |= TVIF_TEXT;
4845 pEntry->uTextSize = 0;
4846 pEntry->pText = 0;
4847 uChange = 1;
4848 } else {
4849 uLen = str_len(pItem->pszText);
4850
4851 if(uLen > pEntry->uTextSize) {
4852 if(pEntry->pText)
4853 delete(pEntry->pText);
4854 pEntry->pText = new(TCHAR, uLen + 1);
4855 }
4856
4857 memcpy(pEntry->pText, pItem->pszText, (uLen + 1)*sizeof(TCHAR));
4858 pEntry->bCallback &= ~TVIF_TEXT;
4859 pEntry->uTextSize = (WORD)uLen;
4860 pEntry->iTextPixels = 0;
4861 uChange = 1;
4862 }
4863 }
4864
4865 if(uBits & TVIF_STATE) {
4866 uMask = pItem->stateMask;
4867
4868 if(pData->uStyle & TVS_SINGLEEXPAND) { // Nicht aufklappen bei Einzelmodus
4869 uMask &= ~TVIS_EXPANDED;
4870 }
4871
4872 uBits = uMask & (pEntry->uState ^ pItem->state);
4873 pEntry->uState &= ~uMask;
4874 pEntry->uState |= uMask & pItem->state;
4875
4876
4877 if((uBits & (TVIS_OVERLAYMASK | TVIS_CUT)) && pData->hImages) {
4878 uChange = 1;
4879 }
4880
4881 if(uBits & TVIS_STATEIMAGEMASK) { // Haben sich die State-Bits verändert
4882 if(pData->hStates) {
4883 uChange = 1;
4884 }
4885
4886 if(pData->uStyleEx & TVS_EX_BITCHECKBOX) {
4887 if(pEntry->uState & 0x1000) {
4888 pData->uSingleSel = uItem;
4889 } else
4890 if(pData->uSingleSel == uItem) {
4891 pData->uSingleSel = 0;
4892 }
4893 } else {
4894 if((pEntry->uState & TVIS_STATEIMAGEMASK) == 0x2000) {
4895 pData->uSingleSel = uItem;
4896 } else
4897 if(pData->uSingleSel == uItem) {
4898 pData->uSingleSel = 0;
4899 }
4900 }
4901 }
4902
4903 if(uBits & (TVIS_BOLD | TVIS_DROPHILITED)) {
4904 pEntry->iTextPixels = 0;
4905 uChange = 1;
4906 }
4907
4908 if(uBits & TVIS_SELECTED) { // Hat sich die Auswahl geändert
4909 pEntry->uState ^= TVIS_SELECTED;
4910
4911 if(pItem->state & TVIS_SELECTED) {
4912 iRet = TreeListSelectItem(pData, uItem, 0, TVC_UNKNOWN);
4913 } else
4914 if(pData->uStyleEx & TVS_EX_MULTISELECT) {
4916 iRet = TreeListXorSelectItem(pData, uItem, TVC_UNKNOWN);
4917 } else {
4918 iRet = TreeListSelectItem(pData, 0, 0, TVC_UNKNOWN);
4919 }
4920
4921 pEntry = pData->pTreeItems[uItem];
4922 if(!pEntry)
4923 return 0;
4924
4925 if(iRet == 1) {
4926 uChange = 1;
4927 }
4928 }
4929
4930 if((uBits & TVIS_EXPANDED) && pEntry->uFirstChild) { // Sollen Teile auf/zugeklappt werden
4932 pEntry->uState ^= TVIS_EXPANDED;
4933 pEntry->uState ^= uBits & uMask;
4934 iVal = uMask & pItem->state;
4935
4936 iRet = TreeListToggleItem(pData, uItem, iVal);
4937 if(iRet) { // Abbruch oder Fehler beim Auf/Zuklappen
4938 if(uChange && pEntry->uShowPos) { // Neuzeichnen des Eintrages
4939 UpdateRect(pData, uItem, 0);
4940 }
4941
4942 return 0;
4943 }
4944
4945 pEntry->uState &= ~uMask;
4946 pEntry->uState |= iVal;
4947 }
4948 }
4949
4950 if(uChange && pEntry->uShowPos) { // Neuzeichnen des Eintrages
4951 UpdateRect(pData, uItem, 0);
4952 }
4953 return 1;
4954}
4955
4956
4957//*****************************************************************************
4958//*
4959//* TreeListGetItem
4960//*
4961//*****************************************************************************
4962// Daten vone einem Eintrag abfragen
4963// pData : Zeiger auf die Fensterdaten
4964// pItem : Zeiger auf die den Datenspeicher
4965// Ergibt 1 wenn ok oder 0 bei einem Fehler
4966static unsigned TreeListGetItem(TreeListData *pData, TV_ITEM *pItem) {
4967
4968 ExtraItem **pList;
4969 ExtraItem *pExtra;
4971 unsigned uBits;
4972 unsigned uItem;
4973 unsigned uSub;
4974 unsigned uLen;
4975
4976 uItem = U(pItem->hItem);
4977 if(uItem > pData->uTreeItemsMax)
4978 return 0;
4979
4980 pEntry = pData->pTreeItems[uItem];
4981 if(!pEntry)
4982 return 0;
4983
4984 uBits = pItem->mask;
4985
4986 if(uBits & TVIF_SUBITEM) { // Einen Extraeintrag abfragen
4987 uSub = pItem->cChildren;
4988 if(uSub > 0) {
4989 if(uSub >= pData->uColumnCount)
4990 return 0;
4991 pList = pData->pExtraItems[uSub - 1];
4992 pExtra = pList[uItem];
4993
4994 if(!pExtra) { // Einen neuen Eintrag erzeugen
4995 pExtra = new(ExtraItem, 1);
4996 memset(pExtra, 0, sizeof(ExtraItem));
4997 pExtra->iImage = TV_NOIMAGE;
4998 pExtra->uState = pEntry->uState & (TVIS_BOLD | TVIS_UNDERLINE);
4999 pList[uItem] = pExtra;
5000 }
5001
5002 if(uBits & TVIF_PARAM) {
5003 pItem->lParam = pEntry->lParam;
5004 }
5005
5006 if(uBits & TVIF_IMAGE) {
5007 pItem->iImage = pExtra->iImage;
5008 }
5009
5010 if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen
5011 if(pExtra->pText == LPSTR_TEXTCALLBACK) {
5012 pItem->pszText = LPSTR_TEXTCALLBACK;
5013 } else
5014 if(uBits & TVIF_TEXTPTR) {
5015 if(!pExtra->pText) {
5016 pItem->pszText = _T("");
5017 pItem->cchTextMax = 0;
5018 } else {
5019 pItem->pszText = pExtra->pText;
5020 pItem->cchTextMax = pExtra->uTextSize + 1;
5021 }
5022 } else {
5023 if(pExtra->pText) {
5024 uLen = pExtra->uTextSize + 1;
5025 if(pItem->cchTextMax < (int)uLen) {
5026 if(pItem->cchTextMax <= 0) {
5027 uLen = 0;
5028 } else {
5029 uLen = pItem->cchTextMax - 1;
5030 pItem->pszText[uLen] = 0;
5031 }
5032 }
5033
5034 memcpy(pItem->pszText, pExtra->pText, uLen * sizeof(TCHAR));
5035 } else {
5036 if(pItem->cchTextMax > 0) {
5037 pItem->pszText[0] = 0;
5038 }
5039 }
5040 }
5041 }
5042
5043 if(uBits & TVIF_STATE) {
5044 pItem->state = pExtra->uState&~TVIS_BASEFLAGS;
5045 pItem->state &= pItem->stateMask;
5046 }
5047
5048 return 1;
5049 }
5050
5051 if(pEntry->bCallback & TVIF_CHILDREN)
5052 pItem->cChildren = I_CHILDRENCALLBACK;
5053 else
5054 pItem->cChildren = (pEntry->uFirstChild) ? 1 : 0;
5055
5056 uBits &= ~TVIF_CHILDREN;
5057 }
5058
5059
5060 //******************** Einen Basis Eintrag ändern *****************************
5061 if(uBits & TVIF_PARAM) {
5062 pItem->lParam = pEntry->lParam;
5063 }
5064
5065 if(uBits & TVIF_IMAGE) {
5066 pItem->iImage = pEntry->iImage;
5067 }
5068
5069 if(uBits & TVIF_SELECTEDIMAGE) {
5070 pItem->iSelectedImage = pEntry->iSelectedImage;
5071 }
5072
5073 if(uBits & TVIF_CHILDREN) {
5074 if(pEntry->bCallback & TVIF_CHILDREN)
5075 pItem->cChildren = I_CHILDRENCALLBACK;
5076 else
5077 pItem->cChildren = (pEntry->uFirstChild) ? 1 : 0;
5078 }
5079
5080 if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen
5081 if(pEntry->pText == LPSTR_TEXTCALLBACK) {
5082 pItem->pszText = LPSTR_TEXTCALLBACK;
5083 } else
5084 if(uBits & TVIF_TEXTPTR) {
5085 pItem->pszText = pEntry->pText;
5086 pItem->cchTextMax = pEntry->uTextSize + 1;
5087 } else {
5088 uLen = pEntry->uTextSize + 1;
5089 if(pItem->cchTextMax < (int)uLen) {
5090 if(pItem->cchTextMax <= 0) {
5091 uLen = 0;
5092 } else {
5093 uLen = pItem->cchTextMax - 1;
5094 pItem->pszText[uLen] = 0;
5095 }
5096 }
5097
5098 memcpy(pItem->pszText, pEntry->pText, uLen * sizeof(TCHAR));
5099 }
5100 }
5101
5102 if(uBits & TVIF_STATE) {
5103 pItem->state = pEntry->uState;
5104 pItem->state &= pItem->stateMask;
5105 }
5106
5107 return 1;
5108}
5109
5110//*****************************************************************************
5111//*
5112//* TreeListDeleteColumn
5113//*
5114//*****************************************************************************
5115// Löscht eine Spalte aus dem Header
5116// pData : Zeiger auf die Fensterdaten
5117// uCol : Ist die Nummer der Spalte die gelöscht werden soll
5118// Ergibt 1 wenn die Spalte gelöscht wurde
5119static int TreeListDeleteColumn(TreeListData *pData, unsigned uCol) {
5120
5121 ExtraItem **pList;
5122 ExtraItem *pExtra;
5123 RECT sRect;
5124 BYTE bItem;
5125 BYTE bByte;
5126 unsigned uPos;
5127 unsigned uSub;
5128 unsigned uItem;
5129 unsigned uIndex;
5130 int iDelta;
5131 int iXoff;
5132 int iNum;
5133 int iCnt;
5134 int iVar;
5135 int iSub;
5136 int iAll;
5137 int iFix;
5138
5139 if(uCol >= pData->uColumnCount)
5140 return 0;
5141
5142 if(uCol && uCol == pData->uSelectedSub) { // Ist die Auswahl in der Spalte
5143 TreeListSelectItem(pData, pData->uSelectedItem, 0, TVC_UNKNOWN);
5144 }
5145
5146 if(uCol && uCol == pData->uEditSub) {
5147 pData->uEditSub = 0;
5148 pData->uEditItem = 0;
5150 }
5151
5152 if(uCol && uCol == pData->uFocusSub) {
5153 pData->uFocusSub = 0;
5154 pData->uFocusItem = 0;
5155 }
5156
5157 if(uCol == pData->uTrackedSub) {
5158 pData->uTrackedSub = 0;
5159 pData->uTrackedItem = 0;
5160 }
5161
5162 GetClientRect(pData->hWnd, &sRect);
5163
5164 iDelta = pData->aColumn[uCol].sSize;
5165 iSub = pData->aColumn[uCol].bWeight;
5166 iCnt = 0;
5167 iVar = 0;
5168 iFix = 0;
5169 iAll = 0;
5170
5171 for(uPos = 0; uPos < pData->uColumnCount; uPos++) { // Zählern der variablen Spalten
5172 if(uPos == uCol)
5173 continue;
5174 if(pData->aColumn[uPos].bWeight == 0) {
5175 iFix += pData->aColumn[uPos].sSize;
5176 continue;
5177 }
5178
5179 iVar += pData->aColumn[uPos].sSize;
5180 iAll += pData->aColumn[uPos].bWeight;
5181 iCnt += 1;
5182 }
5183
5184 Header_DeleteItem(pData->hHeader, uCol);
5185 pData->uColumnCount--;
5186
5187 if(pData->uColumnCount > 0) { // Liste mit Extraeinträgen löschen
5188 iNum = uCol - 1;
5189 if(iNum < 0)
5190 iNum = 0;
5191
5192 pList = pData->pExtraItems[iNum];
5193 if(pList) {
5194 for(uItem = 0; uItem <= pData->uTreeItemsMax; uItem++) { // Alle Einträge aus der Liste löschen
5195 pExtra = pList[uItem];
5196 if(!pExtra)
5197 continue;
5198
5199 if(pExtra->pText) {
5200 pExtra->uTextSize = 0;
5201 delete(pExtra->pText);
5202 }
5203
5204 delete(pExtra);
5205 }
5206
5207 memmove(pData->pExtraItems + iNum, pData->pExtraItems + iNum + 1, sizeof(pList) * (MAX_COLUMNS - 1 - iNum));
5208 pData->pExtraItems[pData->uColumnCount] = NULL;
5209 delete(pList);
5210 }
5211 } else {
5212 iNum = MAX_COLUMNS;
5213 }
5214
5215 if(pData->aColumn[uCol].bWeight) {
5216 pData->uColumnCountVar--;
5217 }
5218
5219 if(pData->aColumn[uCol].bMark) {
5220 pData->uMarkedCols--;
5221 }
5222
5223 uSub = pData->aColumnPos[uCol];
5224
5225 memmove(pData->aColumn + uCol, pData->aColumn + uCol + 1, (MAX_COLUMNS - 1 - uCol)*sizeof(ColumnData));
5226
5227 for(uIndex = 0; uIndex < uSub; uIndex++) { // Zuordnungs-Array anpassen
5228 bItem = pData->aColumnPos[uIndex - 1];
5229 if(bItem < uCol)
5230 continue;
5231
5232 bItem++;
5233 pData->aColumnPos[uIndex] = bItem;
5234 }
5235
5236 for(; uIndex <= pData->uColumnCount; uIndex++) { // Spaltenpositionen verschieben
5237 bItem = pData->aColumnPos[uIndex + 1];
5238
5239 if(bItem >= uCol) {
5240 uCol--;
5241 }
5242
5243 pData->aColumnPos[uIndex] = bItem;
5244 }
5245
5246 for(uIndex = pData->uColumnCount; uIndex > 0;) {
5247 uIndex--;
5248 bByte = pData->aColumn[uIndex].bIndex;
5249
5250 if(bByte >= uSub) {
5251 bByte--;
5252 pData->aColumn[uIndex].bIndex = bByte;
5253 }
5254
5255 pData->aColumn[uIndex].bNext = pData->aColumnPos[bByte + 1];
5256 }
5257
5258 pData->iFixSize = iFix;
5259 pData->iAllWeight = iAll;
5260 pData->aColumn[pData->uColumnCount].bWeight = 0;
5261
5262 if(iCnt && iDelta) { // Variable Breiten anpassen
5263 ChangeColSize(pData, iDelta);
5264 } else {
5265 if(iSub && !iCnt) {
5266 pData->iVarSize = 0;
5267 }
5268 }
5269
5270 if(pData->uSelectedSub > uCol) { // Ist die Auswahl vor der Spalte
5271 pData->uSelectedSub--;
5272 }
5273
5274 if(pData->uEditSub > uCol) {
5275 pData->uEditSub--;
5276 }
5277
5278 if(pData->uFocusSub > uCol) {
5279 pData->uFocusSub--;
5280 }
5281
5282 if(pData->uTrackedSub > uCol) {
5283 pData->uTrackedSub--;
5284 }
5285
5286 if(!pData->uColumnCount) { // Den Header löschen
5287 DestroyWindow(pData->hHeader);
5288 pData->hHeader = NULL;
5289 pData->uStartPixel = 0;
5290 pData->iRowHeight = 1;
5292 InvalidateRect(pData->hWnd, &sRect, FALSE);
5293 }
5294
5295 iXoff = UpdateColumns(pData); // Hat sich die Spaltenbreiten verändert
5296 if(iXoff < 0x10000) {
5297 sRect.left = iXoff;
5298 sRect.left -= pData->uScrollX;
5299 sRect.top = pData->uStartPixel;
5300 InvalidateRect(pData->hWnd, &sRect, FALSE);
5301 }
5302
5304
5305 return 1;
5306}
5307
5308
5309//*****************************************************************************
5310//*
5311//* TreeListInsertColumn
5312//*
5313//*****************************************************************************
5314// Adds a new column in the header
5315// pData : Zeiger auf die Fensterdaten
5316// uCol : Ist die Nummer der Spalte die eingefügt wird
5317// pInsert : Zeiger auf die ein zu fügenden Daten
5318// Returns the positio of the new column or -1 if an error occurs.
5319static int TreeListInsertColumn(TreeListData *pData, unsigned uCol, TV_COLUMN *pColumn) {
5320
5321 ExtraItem **pList;
5322 TV_COLSIZE sNotify;
5323 HDITEM sItem;
5324 RECT sRect;
5325 short sFixed;
5326 UINT uIndex;
5327 BYTE bByte;
5328 BYTE bItem;
5329 BYTE bMark;
5330 BYTE bMinEx;
5331 BYTE bAlign;
5332 int iWeight;
5333 int iDelta;
5334 int iStart;
5335 int iSize;
5336 int iXoff;
5337 int iYoff;
5338 int iNum;
5339 int iVar;
5340 int iAll;
5341 int iAdd;
5342 int iMin;
5343 int iFix;
5344
5345 GetClientRect(pData->hWnd, &sRect);
5346
5347 if(!pData->hHeader) { // Create a new header
5348 iStart = bDrawWithTheme ? GetSystemMetrics(SM_CYHSCROLL) : 17; //SM_CYHSCROLL is not enough tall with themes disabled apps;
5349 iYoff = sRect.top + iStart;
5350
5351 if(pData->uStyleEx & TVS_EX_HIDEHEADERS) {
5352 iYoff = 0;
5353 }
5354
5355 pData->hHeader = CreateWindow(WC_HEADER, NULL, WS_VISIBLE | WS_CHILD | HDS_HORZ | HDS_BUTTONS | HDS_DRAGDROP, sRect.left, sRect.top, sRect.right, iYoff, pData->hWnd, (HMENU)1, NULL, NULL);
5356 if(!pData->hHeader)
5357 return -1;
5358
5359 pData->uStartPixel = (pData->uStyleEx & TVS_EX_HIDEHEADERS) ? 0 : iStart;
5360 pData->iRowHeight = 1;
5362
5363 InvalidateRect(pData->hWnd, &sRect, FALSE);
5364 if(pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST){
5365 SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hHeadImg);
5366 } else {
5367 SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hImages);
5368 }
5370
5371 if(pData->uSizeX <= pData->uStartPixel)
5372 pData->uSizeYsub = 0;
5373 else
5374 pData->uSizeYsub = pData->uSizeX - pData->uStartPixel;
5375 }
5376
5377 if(pData->uColumnCount >= MAX_COLUMNS) { // Prüfe die Anzahl der Spalten
5378 return -1;
5379 }
5380
5381 memset(&sItem, 0, sizeof(sItem)); // Die Spaltendaten zusammenstellen
5382
5383 if(uCol >= pData->uColumnCount) {
5384 uCol = pData->uColumnCount;
5385 }
5386
5387 if(pColumn->mask & TVCF_FMT) { // text alignment
5388 sItem.mask |= HDI_FORMAT;
5389 sItem.fmt = pColumn->fmt;
5390
5391 switch(sItem.fmt & HDF_JUSTIFYMASK) {
5392 case HDF_CENTER:
5393 bAlign = DT_CENTER;
5394 break;
5395 case HDF_RIGHT:
5396 bAlign = DT_RIGHT;
5397 break;
5398 default:
5399 bAlign = DT_LEFT;
5400 break;
5401 }
5402 } else {
5403 bAlign = DT_LEFT;
5404 }
5405
5406 if(pColumn->mask & TVCF_IMAGE) { // Hat die Spalte auch ein Icon
5407 sItem.mask |= HDI_IMAGE;
5408 sItem.iImage = pColumn->iImage;
5409 }
5410
5411 if(pColumn->mask & TVCF_TEXT) { // Auch einen Text übergeben
5412 sItem.mask |= HDI_TEXT;
5413 sItem.pszText = pColumn->pszText;
5414 }
5415
5416 if(pColumn->mask & TVCF_MIN) { // Auch einen Min-Wert übergeben
5417 iMin = pColumn->iOrder;
5418 bMinEx = 1;
5419
5420 if(iMin < 0) {
5421 iMin = -iMin;
5422 bMinEx = 0;
5423 }
5424 } else {
5425 iMin = 16;
5426 bMinEx = 0;
5427 }
5428
5429 if(pColumn->mask & TVCF_WIDTH) { // Fixe Breite für die Spalte
5430 iWeight = 0;
5431 sItem.mask |= HDI_WIDTH;
5432 sItem.cxy = pColumn->cx;
5433 iSize = pColumn->cx;
5434 iDelta = -pColumn->cx;
5435 iAdd = 0;
5436 } else { // Variable vordefinierte Breite
5437 if(pColumn->mask & TVCF_VWIDTH)
5438 iWeight = pColumn->cx;
5439 else
5440 iWeight = 1;
5441
5442 iVar = pData->iVarSize;
5443 iFix = pData->iFixSize;
5444 iAll = pData->iAllWeight;
5445 iSize = pData->uSizeX - iVar - iFix;
5446
5447 if(iWeight <= 0)
5448 iWeight = 1;
5449 if(iWeight > 255)
5450 iWeight = 255;
5451
5452 if(pData->uColumnCountVar) { // Gibt es schon variable Spalten
5453 iSize = (iVar * iWeight) / (iAll + iWeight);
5454 iDelta = -iSize;
5455 } else {
5456 iDelta = 0;
5457 }
5458
5459 sItem.mask |= HDI_WIDTH;
5460 sItem.cxy = iSize;
5461 iAdd = 1;
5462
5463 if(sItem.cxy < iMin)
5464 sItem.cxy = iMin;
5465 }
5466
5467 uCol = Header_InsertItem(pData->hHeader, uCol, &sItem);
5468 if(uCol & 0x80000000)
5469 return -1;
5470
5471 if(pData->uColumnCount > 0) { // Liste mit Extraeinträgen erzeugen
5472 pList = new(ExtraItem*, pData->uTreeItemsMax + 1);
5473 if(!pList) {
5474 Header_DeleteItem(pData->hHeader, uCol);
5475 return -1;
5476 }
5477
5478 memset(pList, 0, sizeof(ExtraItem *) * (pData->uTreeItemsMax + 1));
5479
5480 iNum = uCol - 1;
5481 if(iNum < 0)
5482 iNum = 0;
5483
5484 memmove(pData->pExtraItems + iNum + 1, pData->pExtraItems + iNum, sizeof(pList) * (MAX_COLUMNS - 2 - iNum));
5485 pData->pExtraItems[iNum] = pList;
5486 }
5487
5488 memmove(pData->aColumn + uCol + 1, pData->aColumn + uCol, (MAX_COLUMNS - 1 - uCol)*sizeof(ColumnData));
5489
5490 for(uIndex = pData->uColumnCount + 2; uIndex > uCol; uIndex--) { // Zuordnungs-Array anpassen
5491 bItem = pData->aColumnPos[uIndex - 1];
5492 if(bItem >= uCol)
5493 bItem++;
5494
5495 pData->aColumnPos[uIndex] = bItem;
5496 }
5497
5498 pData->aColumnPos[uCol] = (BYTE)uCol;
5499
5500 while(uIndex > 0) {
5501 uIndex--;
5502
5503 bItem = pData->aColumnPos[uIndex];
5504 if(bItem < uCol)
5505 continue;
5506
5507 bItem++;
5508 pData->aColumnPos[uIndex] = bItem;
5509 }
5510
5511 for(uIndex = pData->uColumnCount;;) { // Folgende Spalten verschieben
5512 bByte = pData->aColumn[uIndex].bIndex;
5513
5514 if(bByte >= uCol) {
5515 bByte++;
5516 pData->aColumn[uIndex].bIndex = bByte;
5517 }
5518
5519 if(uIndex == 0)
5520 break;
5521 uIndex--;
5522 }
5523
5524 bMark = 0;
5525 sFixed = 0;
5526
5527 if(pColumn->mask & TVCF_MARK) // Ist die Spalte markiert
5528 if(pColumn->fmt & TVCFMT_MARK) {
5529 bMark = 1;
5530 }
5531
5532 if(pColumn->mask & TVCF_FIXED) // Ist die Spalte fixiert
5533 if(pColumn->fmt & TVCFMT_FIXED) {
5534 sFixed = (short)((sItem.cxy > 0) ? sItem.cxy : 100);
5535 }
5536
5537 pData->aColumn[uCol].bWeight = (BYTE)iWeight;
5538 pData->aColumn[uCol].sReal = (short)sItem.cxy;
5539 pData->aColumn[uCol].sSize = (short)iSize;
5540 pData->aColumn[uCol].sMin = (short)iMin;
5541 pData->aColumn[uCol].bIndex = (BYTE)uCol;
5542 pData->aColumn[uCol].bMinEx = bMinEx;
5543 pData->aColumn[uCol].bAlign = bAlign;
5544 pData->aColumn[uCol].bMark = bMark;
5545 pData->aColumn[uCol].sFixed = sFixed;
5546 pData->uMarkedCols += bMark;
5547
5548
5549 for(uIndex = pData->uColumnCount;;) { // Nächste sichtbare Spalten aktualisieren
5550 bByte = pData->aColumn[uIndex].bIndex;
5551 pData->aColumn[uIndex].bNext = pData->aColumnPos[bByte + 1];
5552 if(uIndex == 0)
5553 break;
5554 uIndex--;
5555 }
5556
5557 if(pData->uColumnCountVar) { // Variable Breiten anpassen
5558 if(iDelta) {
5559 ChangeColSize(pData, iDelta);
5560 pData->iVarSize -= iDelta;
5561 } else
5562 if(!iAdd) {
5563 pData->iFixSize += iSize;
5564 }
5565 } else {
5566 if(iAdd)
5567 pData->iVarSize = iSize;
5568 else
5569 pData->iFixSize += iSize;
5570 }
5571
5572 pData->iAllWeight += iWeight;
5573 pData->uColumnCountVar += iAdd;
5574 pData->uColumnCount += 1;
5575
5576 if(pData->uSelectedSub > 0 && pData->uSelectedSub >= uCol) {
5577 pData->uSelectedSub++;
5578 }
5579
5580 if(pData->uTrackedSub > 0 && pData->uTrackedSub >= uCol) {
5581 pData->uTrackedSub++;
5582 }
5583
5584 if(pData->uFocusSub > 0 && pData->uFocusSub >= uCol) {
5585 pData->uFocusSub++;
5586 }
5587
5588 if(pData->uEditSub > 0 && pData->uEditSub >= uCol) {
5589 pData->uEditSub++;
5590 }
5591
5592 iXoff = UpdateColumns(pData); // Hat sich die Spaltenbreiten verändert
5593 if(iXoff < 0x10000) {
5594 sRect.left = iXoff;
5595 sRect.left -= pData->uScrollX;
5596 sRect.top = pData->uStartPixel;
5597 InvalidateRect(pData->hWnd, &sRect, FALSE);
5598 }
5599
5601
5602 if(pData->uInsertMark) { // Fehlende Infomarken einfügen
5603 TV_ITEM sSet;
5604 ExtraItem *pExtra;
5605
5606 sSet.mask = TVIF_SUBITEM;
5607 sSet.hItem = (HTREEITEM)(ULONG_PTR)pData->uInsertMark;
5608 sSet.cChildren = uCol;
5609
5610 TreeListSetItem(pData, &sSet);
5611
5612 pExtra = pData->pExtraItems[uCol - 1][pData->uInsertMark];
5613 if(pExtra) {
5614 pExtra->uColorBk = pData->uColors[TVC_INSERT];
5615 pExtra->bFlags |= TVIX_BKCOLOR;
5616 }
5617 }
5618
5619 if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) { // Geänderte Spalten melden
5620 sNotify.hdr.code = TVN_COLUMNCHANGED;
5621 sNotify.uColumn = uCol;
5622 sNotify.uIndex = pData->aColumn[uCol].bIndex;
5623 sNotify.uPosX = pData->aColumnXpos[uCol];
5624 sNotify.iSize = pData->aColumn[uCol].sReal;
5625
5626 UNLOCK(pData);
5627 SendNotify(pData, &sNotify.hdr);
5628 LOCK(pData);
5629 }
5630
5631 return uCol;
5632}
5633
5634//*****************************************************************************
5635//*
5636//* TreeListScanColumn
5637//*
5638//*****************************************************************************
5639// Berechnet die Breite der sichtbaren Einträge einer Spalte
5640// pData : Zeiger auf die Fensterdaten
5641// uSub : Ist die Spalte
5642// Ergibt sie gescannte Breite
5643static int TreeListScanColumn(TreeListData *pData, unsigned uSub) {
5644
5645 BaseItem **pList;
5647 ExtraItem *pExtra;
5648 ExtraItem **pItems;
5649 unsigned *pPList;
5650 unsigned uPos;
5651 int iMax;
5652 int iPos;
5653
5654 if(uSub >= pData->uColumnCount)
5655 return 0;
5656
5657 if(uSub > 0) { // Extraspalte
5658 pItems = pData->pExtraItems[uSub - 1];
5659 pPList = pData->pItemPos;
5660 iMax = 0;
5661
5662 for(uPos = 0; uPos < pData->uItemPosCount; uPos++) {
5663 pExtra = pItems[pPList[uPos]];
5664 if(!pExtra) {
5665 if(iMax < 8)
5666 iMax = 8;
5667 continue;
5668 }
5669
5670 if(pData->hSubImg && (pExtra->bFlags & TVIX_HASIMAGE))
5671 iPos = pData->iSubImgXsize;
5672 else
5673 iPos = 0;
5674
5675 iPos += pExtra->iTextPixels + 8;
5676 if(iPos > iMax)
5677 iMax = iPos;
5678 }
5679
5680 return iMax;
5681 }
5682
5683 pList = pData->pTreeItems;
5684 pPList = pData->pItemPos;
5685 iMax = 0;
5686
5687 for(uPos = 0; uPos < pData->uItemPosCount; uPos++) { // Erste Spalte
5688 pEntry = pList[pPList[uPos]];
5689
5690 if(pEntry->bFlags & TVIX_HASIMAGE)
5691 iPos = pData->iImagesXsize;
5692 else
5693 iPos = 0;
5694
5695 iPos += pEntry->uLevel * pData->iIndent;
5696 iPos += pEntry->iTextPixels + 8;
5697 if(iPos > iMax)
5698 iMax = iPos;
5699 }
5700
5701 if(pData->uStyleEx & TVS_EX_ITEMLINES) {
5702 iMax += 1;
5703 }
5704
5705 if(pData->cHasRootRow) {
5706 iMax += pData->iIndent;
5707 }
5708
5709 if(pData->hStates) {
5710 iMax += pData->iStatesXsize;
5711 }
5712
5713 return iMax;
5714}
5715
5716
5717//*****************************************************************************
5718//*
5719//* TreeListHitTest
5720//*
5721//*****************************************************************************
5722// Prüft wo eine Koordinate im Fenster ist
5723// pData : Zeiger auf die Fensterdaten
5724// pInfo : Zeiger auf die ein zu fügenden Daten
5725// Ergibt das Item auf dem die Koordinate zeigt
5727
5729 ExtraItem *pExtra;
5730 unsigned uItem;
5731 unsigned uNext;
5732 unsigned uSub;
5733 unsigned uCol;
5734 int iXpos;
5735 int iYpos;
5736 int iZpos;
5737 int iWidth;
5738 int iIcon;
5739
5740 iXpos = pInfo->pt.x;
5741 iYpos = pInfo->pt.y;
5742
5743 if((unsigned)iXpos >= pData->uSizeX) {
5744 pInfo->hItem = NULL;
5745 pInfo->flags = (iXpos < 0) ? TVHT_TOLEFT : TVHT_TORIGHT;
5746 return 0;
5747 }
5748
5749 iYpos -= pData->uStartPixel;
5750
5751 if((unsigned)iYpos >= pData->uSizeY) {
5752 pInfo->hItem = NULL;
5753 pInfo->flags = (iYpos < 0) ? TVHT_ABOVE : TVHT_BELOW;
5754 return 0;
5755 }
5756
5757 iZpos = iYpos / pData->iRowHeight;
5758 iZpos += pData->uScrollY;
5759
5760 if((unsigned)iZpos >= pData->uItemPosCount) {
5761 pInfo->hItem = NULL;
5762 pInfo->flags = TVHT_NOWHERE;
5763 return 0;
5764 }
5765
5766 iXpos += pData->uScrollX;
5767 uItem = pData->pItemPos [iZpos];
5768 pEntry = pData->pTreeItems[uItem];
5769 pInfo->hItem = (HTREEITEM)(ULONG_PTR)uItem;
5770
5771 if(!pEntry)
5772 return 0;
5773
5774 uSub = pData->aColumnPos[1];
5775
5776 if(iXpos >= pData->aColumnXpos[uSub]) { // Auf Extraeintrag
5777 for(uCol = 1; uCol < pData->uColumnCount; uCol++) {
5778 uSub = pData->aColumnPos[uCol ];
5779 uNext = pData->aColumnPos[uCol + 1];
5780
5781 if(iXpos >= pData->aColumnXpos[uNext])
5782 continue;
5783 iXpos -= pData->aColumnXpos[uSub ];
5784
5785 pExtra = pData->pExtraItems[uSub - 1][uItem];
5786
5787
5788 if(pData->aColumn[uSub].bEdit >= TVAX_CHECK) { // Hat der Extraeintrag ein Icon
5789 iIcon = pData->iChecksXsize;
5790 } else
5791 if(pExtra && (pExtra->bFlags & TVIX_HASIMAGE)) {
5792 iIcon = pData->iImagesXsize;
5793 } else {
5794 iIcon = 0;
5795 }
5796
5797 pInfo->flags = uSub << 24;
5798
5799 if(iXpos < iIcon) { // Auf Icon
5800 pInfo->flags |= TVHT_ONSUBICON;
5801 return uItem;
5802 }
5803
5804 if(!pExtra || !pExtra->uTextSize) { // Auf Text wenn leerer Eintrag
5805 pInfo->flags |= TVHT_ONSUBLABEL;
5806 return uItem;
5807 }
5808
5809 switch(pData->aColumn[uSub].bAlign) { // Textausrichtung
5810 default
5811 :
5812 if(iXpos - iIcon < pExtra->iTextPixels + 5) {
5813 pInfo->flags |= TVHT_ONSUBLABEL;
5814 return uItem;
5815 }
5816 break;
5817
5818 case DT_RIGHT:
5819 iWidth = pData->aColumnXpos[uNext];
5820 iWidth -= pData->aColumnXpos[uSub ];
5821
5822 if(iXpos >= iWidth - pExtra->iTextPixels - 5) {
5823 pInfo->flags |= TVHT_ONSUBLABEL;
5824 return uItem;
5825 }
5826 break;
5827
5828 case DT_CENTER:
5829 iWidth = pData->aColumnXpos[uNext];
5830 iWidth -= pData->aColumnXpos[uSub ];
5831 iWidth += iIcon;
5832 iWidth /= 2;
5833
5834 if(iXpos >= iWidth - pExtra->iTextPixels / 2 - 3)
5835 if(iXpos <= iWidth + pExtra->iTextPixels / 2 + 3) {
5836 pInfo->flags |= TVHT_ONSUBLABEL;
5837 return uItem;
5838 }
5839 break;
5840 }
5841
5842 pInfo->flags |= TVHT_ONSUBRIGHT;
5843
5844 return uItem;
5845 }
5846
5847 pInfo->flags = TVHT_ONRIGHTSPACE;
5848
5849 return uItem;
5850 }
5851
5852 if(!pData->cHasRootRow) { // Root-Linien ausgleichen
5853 iXpos += pData->iIndent;
5854 }
5855
5856 iXpos -= pData->iIndent * pEntry->uLevel;
5857
5858 if(iXpos < pData->iIndent) { // Auf eingerücktem Bereich
5859 if(pData->uStyle & TVS_HASBUTTONS)
5860 if(pEntry->bFlags & TVIX_HASBUTTON) {
5861 if(iXpos >= pData->iShift - 6)
5862 if(iXpos <= pData->iShift + 7) {
5863 iYpos %= pData->iRowHeight;
5864 iYpos -= pData->iRowHeight / 2;
5865
5866 if(iYpos >= -6 && iYpos <= 7) {
5867 pInfo->flags = TVHT_ONITEMBUTTON;
5868 return uItem;
5869 }
5870 }
5871 }
5872
5873 pInfo->flags = TVHT_ONITEMINDENT;
5874 return uItem;
5875 }
5876
5877 iXpos -= pData->iIndent;
5878
5879 if(pData->uStyleEx & TVS_EX_ITEMLINES) {
5880 iXpos--;
5881 }
5882
5883 if(pData->hStates) { // Auf der Auswahl-Box
5884 iXpos -= pData->iStatesXsize;
5885
5886 if(iXpos < 0) {
5887 pInfo->flags = TVHT_ONITEMSTATEICON;
5888 return uItem;
5889 }
5890 }
5891
5892 if(pEntry->bFlags & TVIX_HASIMAGE) { // Auf dem Icon
5893 iXpos -= pData->iImagesXsize;
5894
5895 if(pData->uStyleEx & TVS_EX_ITEMLINES)
5896 iXpos--;
5897
5898 if(iXpos < 0) {
5899 pInfo->flags = TVHT_ONITEMICON;
5900 return uItem;
5901 }
5902 }
5903 // Auf Text
5904 if(iXpos < pEntry->iTextPixels + 5 || !pEntry->pText || !pEntry->pText[0]) {
5905 pInfo->flags = TVHT_ONITEMLABEL;
5906 } else {
5907 pInfo->flags = TVHT_ONITEMRIGHT;
5908 }
5909
5910 return uItem;
5911}
5912
5913//*****************************************************************************
5914//*
5915//* TreeListSetTrackItem
5916//*
5917//*****************************************************************************
5918// Setzt das den Einfügeeintrag
5919// pData : Zeiger auf die Fensterdaten
5920// uItem : Ist die Nummer des Eintrages bei dem eingefügt werden soll
5921// iMode : 0=davor einfügen 1=nachher einfügen
5922// Ergibt 1 wenn der Eintrag eingefügt wurde
5923static unsigned TreeListSetInsertMark(TreeListData *pData, unsigned uItem, int iMode) {
5924
5925 TV_INSERTSTRUCT sInsert;
5926 ExtraItem *pExtra;
5928 unsigned uSub;
5929 int iRet;
5930
5931 if(pData->uInsertMark) {
5932 iRet = TreeListDeleteItem(pData, pData->uInsertMark, 1);
5933 pData->uInsertMark = 0;
5934 } else {
5935 iRet = 0;
5936 }
5937
5938 if(uItem == 0)
5939 return iRet;
5940 if(uItem > pData->uTreeItemsMax)
5941 return 0;
5942
5943 pEntry = pData->pTreeItems[uItem];
5944 if(!pEntry)
5945 return 0;
5946
5947 if(iMode) {
5948 uItem = pEntry->uPrevItem;
5949 if(!uItem)
5950 uItem = U(TVI_FIRST);
5951 }
5952
5953 sInsert.hParent = (HTREEITEM)(ULONG_PTR)pEntry->uParent;
5954 sInsert.hInsertAfter = (HTREEITEM)(ULONG_PTR)uItem;
5955 sInsert.item.mask = TVIF_SELECTEDIMAGE | TVIF_IMAGE;
5956 sInsert.item.iImage = TV_NOIMAGE;
5957 sInsert.item.iSelectedImage = TV_NOIMAGE;
5958
5959 uItem = TreeListInsertItem(pData, &sInsert);
5960 if(!uItem)
5961 return 0;
5962
5963 pEntry = pData->pTreeItems[uItem];
5964 pEntry->uColorBk = pData->uColors[TVC_INSERT];
5965 pEntry->bFlags |= TVIX_BKCOLOR;
5966 sInsert.item.mask |= TVIF_SUBITEM;
5967 sInsert.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
5968
5969 for(uSub = 1; uSub < pData->uColumnCount; uSub++) {
5970 sInsert.item.cChildren = uSub;
5971
5972 TreeListSetItem(pData, &sInsert.item);
5973
5974 pExtra = pData->pExtraItems[uSub - 1][uItem];
5975 pExtra->uColorBk = pData->uColors[TVC_INSERT];
5976 pExtra->bFlags |= TVIX_BKCOLOR;
5977 }
5978
5979 pData->uInsertMark = uItem;
5980
5981 return uItem;
5982}
5983
5984//*****************************************************************************
5985//*
5986//* TreeListGetItemColor
5987//*
5988//*****************************************************************************
5989// Holt die Farbe eins Feldes
5990// pData : Zeiger auf die Fensterdaten
5991// uItem : Ist die Nummer des Eintrages
5992// uSub : Ist die Spalte
5993// iMode : 0=Hintergrundfarbe 1=Textfarbe abfragen
5994// Ergibt die alte Farbe oder TV_NOCOLOR wenn keine Farbe eingestellt war
5995static LRESULT TreeListGetItemColor(TreeListData *pData, unsigned uItem, unsigned uSub, int iMode) {
5996
5997 COLORREF uColor;
5998 ExtraItem *pExtra;
6000
6001 if(uItem > pData->uTreeItemsMax)
6002 return TV_NOCOLOR;
6003
6004 pEntry = pData->pTreeItems[uItem];
6005 if(!pEntry)
6006 return TV_NOCOLOR;
6007
6008 if(uSub) { // Extra-Eintrag abfragen
6009 if(uSub >= pData->uColumnCount)
6010 return TV_NOCOLOR;
6011
6012 pExtra = pData->pExtraItems[uSub - 1][uItem];
6013 if(!pExtra)
6014 return TV_NOCOLOR;
6015
6016 if(iMode)
6017 uColor = (pExtra->bFlags & TVIX_TEXTCOLOR) ? pExtra->uColorText : TV_NOCOLOR;
6018 else
6019 uColor = (pExtra->bFlags & TVIX_BKCOLOR) ? pExtra->uColorBk : TV_NOCOLOR;
6020 } else {
6021 if(iMode)
6022 uColor = (pEntry->bFlags & TVIX_TEXTCOLOR) ? pEntry->uColorText : TV_NOCOLOR;
6023 else
6024 uColor = (pEntry->bFlags & TVIX_BKCOLOR) ? pEntry->uColorBk : TV_NOCOLOR;
6025 }
6026
6027 return (LRESULT)uColor;
6028}
6029
6030//*****************************************************************************
6031//*
6032//* TreeListSetItemColor
6033//*
6034//*****************************************************************************
6035// Setzt die Farbe eines Feldes
6036// pData : Zeiger auf die Fensterdaten
6037// uItem : Ist die Nummer des Eintrages
6038// uSub : Ist die Spalte
6039// uColor : Ist die neue Farbe
6040// iMode : 0=Hintergrundfarbe 1=Textfarbe einstellen
6041// Ergibt die alte Farbe oder TV_NOCOLOR wenn keine Farbe eingestellt war
6042static COLORREF TreeListSetItemColor(TreeListData *pData, unsigned uItem, unsigned uSub, COLORREF uColor, int iMode) {
6043
6044 TV_ITEM sSet;
6045 COLORREF uOld;
6046 ExtraItem *pExtra;
6048
6049 if(uItem > pData->uTreeItemsMax)
6050 return TV_NOCOLOR;
6051
6052 pEntry = pData->pTreeItems[uItem];
6053 if(!pEntry)
6054 return TV_NOCOLOR;
6055
6056 if(uSub >= 255) { // Die Ganze Zeile ändern
6057 if(pData->uColumnCount) {
6058 for(uSub = pData->uColumnCount; uSub > 0; uSub--) {
6059 TreeListSetItemColor(pData, uItem, uSub, uColor, iMode);
6060 }
6061 }
6062
6063 uSub = 0;
6064 }
6065
6066 if(uSub) { // Extra-Eintrag verändern
6067 if(uSub >= pData->uColumnCount)
6068 return TV_NOCOLOR;
6069
6070 pExtra = pData->pExtraItems[uSub - 1][uItem];
6071 if(!pExtra) { // Extra-Eintrag erzeugen
6072 sSet.mask = TVIF_SUBITEM;
6073 sSet.hItem = (HTREEITEM)(ULONG_PTR)uItem;
6074 sSet.cChildren = uSub;
6075
6076 if(!TreeListSetItem(pData, &sSet))
6077 return TV_NOCOLOR;
6078
6079 pExtra = pData->pExtraItems[uSub - 1][uItem];
6080 }
6081
6082 if(iMode) { // Textfarbe
6083 uOld = (pExtra->bFlags & TVIX_TEXTCOLOR) ? pExtra->uColorText : TV_NOCOLOR;
6084
6085 if(uColor == TV_NOCOLOR) {
6086 pExtra->bFlags &= ~TVIX_TEXTCOLOR;
6087 } else {
6088 pExtra->bFlags |= TVIX_TEXTCOLOR;
6089 pExtra->uColorText = uColor;
6090 }
6091 } else { // Hintergrund
6092 uOld = (pExtra->bFlags & TVIX_BKCOLOR) ? pExtra->uColorBk : TV_NOCOLOR;
6093
6094 if(uColor == TV_NOCOLOR) {
6095 pExtra->bFlags &= ~TVIX_BKCOLOR;
6096 } else {
6097 pExtra->bFlags |= TVIX_BKCOLOR;
6098 pExtra->uColorBk = uColor;
6099 }
6100 }
6101 } else {
6102 if(iMode) { // Textfarbe
6103 uOld = (pEntry->bFlags & TVIX_TEXTCOLOR) ? pEntry->uColorText : TV_NOCOLOR;
6104
6105 if(uColor == TV_NOCOLOR) {
6106 pEntry->bFlags &= ~TVIX_TEXTCOLOR;
6107 } else {
6108 pEntry->bFlags |= TVIX_TEXTCOLOR;
6109 pEntry->uColorText = uColor;
6110 }
6111 } else { // Hintergrund
6112 uOld = (pEntry->bFlags & TVIX_BKCOLOR) ? pEntry->uColorBk : TV_NOCOLOR;
6113
6114 if(uColor == TV_NOCOLOR) {
6115 pEntry->bFlags &= ~TVIX_BKCOLOR;
6116 } else {
6117 pEntry->bFlags |= TVIX_BKCOLOR;
6118 pEntry->uColorBk = uColor;
6119 }
6120 }
6121 }
6122
6123 if(uColor != uOld) { // Neu zeichnen
6124 UpdateRect(pData, uItem, uSub);
6125 }
6126
6127 return uOld;
6128}
6129
6130//*****************************************************************************
6131//*
6132//* TreeListSetTrackItem
6133//*
6134//*****************************************************************************
6135// Setzt das unterstrichene Item
6136// pData : Zeiger auf die Fensterdaten
6137// uItem : Ist die Nummer des Eintrages
6138// uSub : Ist die Spalte
6139// Ergibt 1 wenn der Eintrag unterstrichen wurde
6140static int TreeListSetTrackItem(TreeListData *pData, unsigned uItem, unsigned uSub) {
6141
6142 ExtraItem *pExtra;
6144 int iRet = 1;
6145
6146 if(!(pData->uStyleEx & TVS_EX_SUBSELECT)) {
6147 uSub = 0;
6148 } else {
6149 if(uSub >= pData->uColumnCount) {
6150 uItem = 0;
6151 uSub = 0;
6152 iRet = 0;
6153 }
6154 }
6155
6156 if(uItem > pData->uTreeItemsMax) {
6157 uItem = 0;
6158 uSub = 0;
6159 iRet = 0;
6160 } else {
6161 if(uItem == pData->uTrackedItem)
6162 if(uSub == pData->uTrackedSub) {
6163 return iRet;
6164 }
6165 }
6166
6167 if(pData->uTrackedItem) { // Den alten Eintrag zurücksetzen
6168 if(pData->uTrackedSub) {
6169 pExtra = pData->pExtraItems[pData->uTrackedSub - 1][pData->uTrackedItem];
6170 if(pExtra) {
6171 pExtra->bFlags &= ~TVIX_TRACKED;
6172 UpdateRect(pData, pData->uTrackedItem, pData->uTrackedSub);
6173 }
6174 } else {
6175 pEntry = pData->pTreeItems[pData->uTrackedItem];
6176 if(pEntry) {
6177 pEntry->bFlags &= ~TVIX_TRACKED;
6178 UpdateRect(pData, pData->uTrackedItem, 0);
6179 }
6180 }
6181 }
6182
6183 if(uItem) { // Den neuen Eintrag setzen
6184 if(uSub) {
6185 pExtra = pData->pExtraItems[uSub - 1][uItem];
6186 if(pExtra) {
6187 pData->uTrackedSub = uSub;
6188 pData->uTrackedItem = uItem;
6189 pExtra->bFlags |= TVIX_TRACKED;
6190 UpdateRect(pData, uItem, uSub);
6191 } else {
6192 iRet = 0;
6193 }
6194 } else {
6195 pEntry = pData->pTreeItems[uItem];
6196 if(pEntry) {
6197 pData->uTrackedSub = 0;
6198 pData->uTrackedItem = uItem;
6199 pEntry->bFlags |= TVIX_TRACKED;
6200 UpdateRect(pData, uItem, 0);
6201 } else {
6202 iRet = 0;
6203 }
6204 }
6205 } else { // Keine Untersteichung
6206 pData->uTrackedSub = 0;
6207 pData->uTrackedItem = 0;
6208 }
6209
6210 return iRet;
6211}
6212
6213//*****************************************************************************
6214//*
6215//* TreeListGetNextItem
6216//*
6217//*****************************************************************************
6218// Sucht den nächsten Eintrag
6219// pData : Zeiger auf die Fensterdaten
6220// uItem : Ist die Nummer des Eintrages
6221// uFlags : Bestimmt nach welchem Eintrag gesucht werden soll
6222// Ergibt 1 wenn der Eintrag unterstrichen wurde
6223static unsigned TreeListGetNextItem(TreeListData *pData, unsigned uItem, unsigned uFlags) {
6225 unsigned uStop;
6226 unsigned uPos;
6227
6228 switch(uFlags) {
6229 case TVGN_ROOT:
6230 return pData->uFirstChild;
6231
6232 case TVGN_NEXT:
6233 if(uItem > pData->uTreeItemsMax) {
6234 return 0;
6235 }
6236
6237 pEntry = pData->pTreeItems[uItem];
6238 if(!pEntry)
6239 return 0;
6240
6241 return pEntry->uNextItem;
6242
6243 case TVGN_PREVIOUS:
6244 if(uItem > pData->uTreeItemsMax) {
6245 return 0;
6246 }
6247
6248 pEntry = pData->pTreeItems[uItem];
6249 if(!pEntry)
6250 return 0;
6251
6252 return pEntry->uPrevItem;
6253
6254 case TVGN_PARENT:
6255 if(uItem > pData->uTreeItemsMax) {
6256 return 0;
6257 }
6258
6259 pEntry = pData->pTreeItems[uItem];
6260 if(!pEntry)
6261 return 0;
6262
6263 return pEntry->uParent;
6264
6265 case TVGN_CHILD:
6266 if(uItem > pData->uTreeItemsMax) {
6267 if(uItem == U(TVI_ROOT))
6268 return pData->uFirstChild;
6269 return 0;
6270 }
6271
6272 pEntry = pData->pTreeItems[uItem];
6273 if(!pEntry)
6274 return 0;
6275
6276 return pEntry->uFirstChild;
6277
6278 case TVGN_LASTCHILD:
6279 if(uItem > pData->uTreeItemsMax) {
6280 if(uItem == U(TVI_ROOT))
6281 return pData->uLastChild;
6282 return 0;
6283 }
6284
6285 pEntry = pData->pTreeItems[uItem];
6286 if(!pEntry)
6287 return 0;
6288
6289 return pEntry->uLastChild;
6290
6291 case TVGN_FIRSTVISIBLE:
6292 if(pData->uItemPosCount <= 0)
6293 return 0;
6294 if(pData->uItemPosCount <= pData->uScrollY)
6295 return 0;
6296
6297 uItem = pData->pItemPos[pData->uScrollY];
6298
6299 if(uItem > pData->uTreeItemsMax || !pData->pTreeItems[uItem]) {
6300 return 0;
6301 }
6302
6303 return uItem;
6304
6305 case TVGN_NEXTVISIBLE:
6306 if(uItem > pData->uTreeItemsMax) {
6307 if(uItem != U(TVI_ROOT))
6308 return 0;
6309 if(pData->uFirstChild == 0)
6310 return 0;
6311
6312 pEntry = pData->pTreeItems[pData->uFirstChild];
6313
6314 uPos = pEntry->uShowPos;
6315 if(uPos <= pData->uScrollY)
6316 return 0;
6317
6318 return pData->uFirstChild;
6319 }
6320
6321 pEntry = pData->pTreeItems[uItem];
6322 if(!pEntry)
6323 return 0;
6324
6325 uPos = pEntry->uShowPos;
6326 if(uPos <= pData->uScrollY)
6327 return 0;
6328 if(uPos > pData->uScrollY + pData->uPageEnties)
6329 return 0;
6330
6331 uItem = pData->pItemPos[uPos];
6332
6333 if(uItem > pData->uTreeItemsMax || !pData->pTreeItems[uItem]) {
6334 return 0;
6335 }
6336
6337 return uItem;
6338
6339 case TVGN_NEXTSELECTED:
6340 if(uItem > pData->uTreeItemsMax) {
6341 if(uItem != U(TVI_ROOT))
6342 return 0;
6343
6344 uItem = pData->uFirstChild;
6345
6346 pEntry = pData->pTreeItems[uItem];
6347 if(!pEntry)
6348 return 0;
6349 if(pEntry->uState & TVIS_SELECTED)
6350 return uItem;
6351 }
6352
6353 pEntry = pData->pTreeItems[uItem];
6354 if(!pEntry)
6355 return 0;
6356
6357 for(;;) {
6358 if(pEntry->uFirstChild) {
6359 uItem = pEntry->uFirstChild;
6360 } else
6361 if(pEntry->uNextItem) {
6362 uItem = pEntry->uNextItem;
6363 } else {
6364 for(;;) {
6365 uItem = pEntry->uParent;
6366 pEntry = pData ->pTreeItems[uItem];
6367 if(!pEntry)
6368 return 0;
6369 if(pEntry->uNextItem) {
6370 uItem = pEntry->uNextItem;
6371 break;
6372 }
6373 }
6374 }
6375
6376 pEntry = pData->pTreeItems[uItem];
6377 if(!pEntry)
6378 break;
6379 if(pEntry->uState & TVIS_SELECTED)
6380 return uItem;
6381 }
6382
6383 return 0;
6384
6385 case TVGN_NEXTSELCHILD:
6386 if(uItem > pData->uTreeItemsMax) {
6387 if(uItem != U(TVI_ROOT))
6388 return 0;
6389
6390 uItem = pData->uFirstChild;
6391
6392 pEntry = pData->pTreeItems[uItem];
6393 if(!pEntry)
6394 return 0;
6395 if(pEntry->uState & TVIS_SELECTED)
6396 return uItem;
6397
6398 uStop = 0;
6399 } else {
6400 pEntry = pData->pTreeItems[uItem];
6401 if(!pEntry || !pEntry->uFirstChild)
6402 return 0;
6403
6404 uStop = uItem;
6405 }
6406
6407 for(;;) {
6408 if(pEntry->uFirstChild) {
6409 uItem = pEntry->uFirstChild;
6410 } else
6411 if(pEntry->uNextItem) {
6412 uItem = pEntry->uNextItem;
6413 } else {
6414 for(;;) {
6415 uItem = pEntry->uParent;
6416 if(uItem == uStop)
6417 return 0;
6418 pEntry = pData ->pTreeItems[uItem];
6419 if(!pEntry)
6420 return 0;
6421 if(pEntry->uNextItem) {
6422 uItem = pEntry->uNextItem;
6423 break;
6424 }
6425 }
6426 }
6427
6428 pEntry = pData ->pTreeItems[uItem];
6429 if(!pEntry)
6430 break;
6431 if(pEntry->uState & TVIS_SELECTED)
6432 return uItem;
6433 }
6434
6435 return 0;
6436
6437 case TVGN_NEXTITEM:
6438 if(uItem > pData->uTreeItemsMax) {
6439 if(uItem != U(TVI_ROOT))
6440 return 0;
6441
6442 uItem = pData->uFirstChild;
6443
6444 pEntry = pData->pTreeItems[uItem];
6445 if(!pEntry)
6446 return 0;
6447
6448 return uItem;
6449 }
6450
6451 pEntry = pData->pTreeItems[uItem];
6452 if(!pEntry)
6453 return 0;
6454
6455 for(;;) {
6456 if(pEntry->uFirstChild) {
6457 uItem = pEntry->uFirstChild;
6458 } else
6459 if(pEntry->uNextItem) {
6460 uItem = pEntry->uNextItem;
6461 } else {
6462 for(;;) {
6463 uItem = pEntry->uParent;
6464 pEntry = pData ->pTreeItems[uItem];
6465 if(!pEntry)
6466 return 0;
6467 if(pEntry->uNextItem) {
6468 uItem = pEntry->uNextItem;
6469 break;
6470 }
6471 }
6472 }
6473
6474 pEntry = pData->pTreeItems[uItem];
6475 if(!pEntry)
6476 break;
6477
6478 return uItem;
6479 }
6480
6481 return 0;
6482
6484 if(uItem > pData->uTreeItemsMax) {
6485 return 0;
6486 }
6487
6488 pEntry = pData->pTreeItems[uItem];
6489 if(!pEntry)
6490 return 0;
6491
6492 uPos = pEntry->uShowPos - 1;
6493 if(uPos <= pData->uScrollY)
6494 return 0;
6495 if(uPos > pData->uScrollY + pData->uPageEnties)
6496 return 0;
6497
6498 return pData->pItemPos[uPos - 1];
6499
6500 case TVGN_LASTVISIBLE:
6501 uPos = pData->uItemPosCount;
6502 if(uPos <= 0)
6503 return 0;
6504 return pData->pItemPos[uPos - 1];
6505
6506 case TVGN_DROPHILITE:
6507 return pData->uTrackedItem;
6508
6509 case TVGN_DROPHILITESUB:
6510 return pData->uTrackedSub;
6511
6512 case TVGN_CARET:
6513 return pData->uSelectedItem;
6514
6515 case TVGN_CARETSUB:
6516 return pData->uSelectedSub;
6517
6518 case TVGN_FOCUS:
6519 return (pData->uFocusItem) ? pData->uFocusItem : pData->uSelectedItem;
6520
6521 case TVGN_FOCUSSUB:
6522 return (pData->uFocusItem) ? pData->uFocusSub : pData->uSelectedSub;
6523 }
6524
6525 return 0;
6526}
6527
6528
6529//*****************************************************************************
6530//*
6531//* TreeListFindItem
6532//*
6533//*****************************************************************************
6534// Sucht einen Kindeintrag mit einem bestimmten Text
6535// pData : Zeiger auf die Fensterdaten
6536// uItem : Ist die Nummer des Elterneintrages
6537// pFind : Die Struktur mit den Suchparametern
6538// Ergibt die Nummer des Eintrages bzw. 0 wenn nicht gefunden wurde
6539static unsigned TreeListFindItem(TreeListData *pData, unsigned uItem, TVFIND *pFind) {
6540 int iImage;
6542 ExtraItem *pExtra;
6543 LPCTSTR pCmpText;
6544 unsigned uTextSize;
6545 unsigned uChkParam;
6546 unsigned uChkState;
6547 unsigned uChkText;
6548 unsigned uChkCase;
6549 unsigned uTextLen;
6550 unsigned uSub;
6551
6552 if(pFind->uFlags & TVIF_CHILD) { // In den Kindern suchen
6553 if(uItem > pData->uTreeItemsMax) {
6554 if(uItem != U(TVI_ROOT))
6555 return 0;
6556 uItem = pData->uFirstChild;
6557 } else {
6558 pEntry = pData->pTreeItems[uItem];
6559 if(!pEntry)
6560 return 0;
6561
6562 uItem = pEntry->uFirstChild;
6563 }
6564 } else {
6565 if(uItem > pData->uTreeItemsMax) { // Ist der Eintrag gültig
6566 return 0;
6567 }
6568
6569 if(pFind->uFlags & TVIF_NEXT) { // Beim nächsten Eintrag weitersuchen
6570 pEntry = pData->pTreeItems[uItem];
6571 if(!pEntry)
6572 return 0;
6573
6574 uItem = pEntry->uNextItem;
6575 }
6576 }
6577
6578 uChkParam = pFind->uFlags & TVIF_PARAM;
6579 uChkState = pFind->uFlags & TVIF_STATE;
6580 uChkText = pFind->uFlags & TVIF_TEXT;
6581 uChkCase = pFind->uFlags & TVIF_CASE;
6582 uSub = pFind->uColumn;
6583 uTextLen = 0;
6584
6585 if(uChkText) {
6586 uTextLen = str_len(pFind->pText);
6587 }
6588
6589 for(; uItem; uItem = pEntry->uNextItem) { // Durchlaufe alle Kinder
6590 pEntry = pData->pTreeItems[uItem];
6591 if(!pEntry)
6592 return 0;
6593
6594 if(uChkParam && pFind->lParam != pEntry->lParam) { // Vergleiche lParam
6595 continue;
6596 }
6597 // Vergleiche die State-Bits
6598 if(uChkState && ((pEntry->uState ^ pFind->uState)&pFind->uStateMask)) {
6599 continue;
6600 }
6601
6602 if(uChkText == 0)
6603 break;
6604
6605 if(uSub) { // Text von Spalten
6606 if(uSub >= pData->uColumnCount)
6607 continue;
6608
6609 pExtra = pData->pExtraItems[uSub - 1][uItem];
6610 if(!pExtra) {
6611 pCmpText = _T("");
6612 uTextSize = 0;
6613 } else {
6614 pCmpText = pExtra->pText;
6615 if(!pCmpText)
6616 pCmpText = _T("");
6617 uTextSize = pExtra->uTextSize;
6618 }
6619 } else { // Text vom Haupteintrag
6620 if(pEntry->bCallback & TVIF_TEXT) {
6621 CallbackEntry(pData, pEntry, uItem, pEntry->bCallback, &iImage, &uTextSize, &pCmpText);
6622 } else {
6623 pCmpText = pEntry->pText;
6624 if(!pCmpText)
6625 pCmpText = _T("");
6626 uTextSize = pEntry->uTextSize;
6627 }
6628 }
6629
6630 if(uTextLen != uTextSize)
6631 continue;
6632
6633 if(uChkCase) { // Zwischen Groß/Kleinbuchstaben unterscheiden
6634 if(!str_icmp(pCmpText, pFind->pText))
6635 break;
6636 } else {
6637 if(!memcmp(pCmpText, pFind->pText, uTextSize * sizeof(TCHAR)))
6638 break;
6639 }
6640 }
6641
6642 return uItem;
6643}
6644
6645//*****************************************************************************
6646//*
6647//* TreeListNextSelUntil
6648//*
6649//*****************************************************************************
6650// Sucht rekursiv ausgewählte Einträge
6651// pData : Zeiger auf die Fensterdaten
6652// uItem : Ist die Nummer des Eintrages nach dem mit der Suche begonnen werden soll
6653// uStop : Bestimmt bei welchem Eintrag abgebrochen werden soll werden soll
6654// Ergibt die Nummer des Eintrages oder 0 wenn keiner gefunden wurde
6655static unsigned TreeListNextSelUntil(TreeListData *pData, unsigned uItem, unsigned uStop) {
6656
6658
6659 if(uItem > pData->uTreeItemsMax) {
6660 if(uItem != U(TVI_ROOT))
6661 return 0;
6662
6663 uItem = pData->uFirstChild;
6664
6665 pEntry = pData->pTreeItems[uItem];
6666 if(!pEntry)
6667 return 0;
6668 if(pEntry->uState & TVIS_SELECTED)
6669 return uItem;
6670
6671 uStop = 0;
6672 } else {
6673 pEntry = pData->pTreeItems[uItem];
6674 if(!pEntry)
6675 return 0;
6676 if(!pEntry->uFirstChild && uItem == uStop)
6677 return 0;
6678 }
6679
6680 for(;;) {
6681 if(pEntry->uFirstChild) {
6682 uItem = pEntry->uFirstChild;
6683 if(uItem == uStop)
6684 return 0;
6685 } else
6686 if(pEntry->uNextItem) {
6687 uItem = pEntry->uNextItem;
6688 if(uItem == uStop)
6689 return 0;
6690 } else {
6691 for(;;) {
6692 uItem = pEntry->uParent;
6693 if(uItem == uStop)
6694 return 0;
6695 pEntry = pData ->pTreeItems[uItem];
6696 if(!pEntry)
6697 return 0;
6698 if(pEntry->uNextItem) {
6699 uItem = pEntry->uNextItem;
6700 if(uItem == uStop)
6701 return 0;
6702 break;
6703 }
6704 }
6705 }
6706
6707 pEntry = pData ->pTreeItems[uItem];
6708 if(!pEntry)
6709 break;
6710 if(pEntry->uState & TVIS_SELECTED)
6711 return uItem;
6712 }
6713
6714 return 0;
6715}
6716
6717//*****************************************************************************
6718//*
6719//* TreeListNextUnselUntil
6720//*
6721//*****************************************************************************
6722// Sucht rekursiv nicht ausgewählte Einträge
6723// pData : Zeiger auf die Fensterdaten
6724// uItem : Ist die Nummer des Eintrages nach dem mit der Suche begonnen werden soll
6725// uStop : Bestimmt bei welchem Eintrag abgebrochen werden soll werden soll
6726// Ergibt die Nummer des Eintrages oder 0 wenn keiner gefunden wurde
6727static unsigned TreeListNextUnselUntil(TreeListData *pData, unsigned uItem, unsigned uStop) {
6728
6730
6731 if(uItem > pData->uTreeItemsMax) {
6732 if(uItem != U(TVI_ROOT))
6733 return 0;
6734
6735 uItem = pData->uFirstChild;
6736
6737 pEntry = pData->pTreeItems[uItem];
6738 if(!pEntry)
6739 return 0;
6740 if((pEntry->uState & TVIS_SELECTED) == 0)
6741 return uItem;
6742
6743 uStop = 0;
6744 } else {
6745 pEntry = pData->pTreeItems[uItem];
6746 if(!pEntry)
6747 return 0;
6748 if(!pEntry->uFirstChild && uItem == uStop)
6749 return 0;
6750 }
6751
6752 for(;;) {
6753 if(pEntry->uFirstChild) {
6754 uItem = pEntry->uFirstChild;
6755 if(uItem == uStop)
6756 return 0;
6757 } else
6758 if(pEntry->uNextItem) {
6759 uItem = pEntry->uNextItem;
6760 if(uItem == uStop)
6761 return 0;
6762 } else {
6763 for(;;) {
6764 uItem = pEntry->uParent;
6765 if(uItem == uStop)
6766 return 0;
6767 pEntry = pData->pTreeItems[uItem];
6768 if(!pEntry)
6769 return 0;
6770 if(pEntry->uNextItem) {
6771 uItem = pEntry->uNextItem;
6772 if(uItem == uStop)
6773 return 0;
6774 break;
6775 }
6776 }
6777 }
6778
6779 pEntry = pData->pTreeItems[uItem];
6780 if(!pEntry)
6781 break;
6782 if((pEntry->uState & TVIS_SELECTED) == 0)
6783 return uItem;
6784 }
6785
6786 return 0;
6787}
6788
6789//*****************************************************************************
6790//*
6791//* TreeListChangeCheckbox
6792//*
6793//*****************************************************************************
6794// Schaltet eine Checkboc um
6795// pData : Zeiger auf die Fensterdaten
6796// uItem : Ist der Eintrag der geändert werden soll
6797// pInfo :
6798static void TreeListChangeCheckbox(TreeListData *pData, UINT uItem, int iPosX, int iPosY) {
6799
6800 BaseItem *pTemp;
6802 NMTREEVIEW sNotify;
6803 TV_ITEM sItem;
6804 UINT uBits;
6805
6806 sNotify.itemOld.mask = 0;
6807 sNotify.itemOld.hItem = 0;
6808
6809 pEntry = pData->pTreeItems[uItem];
6810 uBits = pEntry->uState & TVIS_STATEIMAGEMASK;
6811
6812 if(pData->uStyleEx & TVS_EX_SINGLECHECKBOX) { // Einzelauswahl
6813 pTemp = pData->pTreeItems[pData->uSingleSel];
6814
6815 if(pData->uSingleSel == uItem) {
6816 if(pData->uStyleEx & TVS_EX_BITCHECKBOX) {
6817 if(uBits & 0x1000)
6818 return;
6819 } else {
6820 if(uBits == 0x2000)
6821 return;
6822 }
6823 } else
6824 if(pData->uSingleSel && pTemp) { // Anderer Eintrag gewählt
6825 sItem.hItem = (HTREEITEM)(ULONG_PTR)pData->uSingleSel;
6826 sItem.mask = TVIF_STATE;
6827 sItem.stateMask = TVIS_STATEIMAGEMASK;
6828 sItem.state = (pData->uStyleEx & TVS_EX_BITCHECKBOX) ? 0x0000 : 0x1000;
6829
6830 TreeListSetItem(pData, &sItem);
6831
6832 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT;
6833 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)pData->uSingleSel;
6834 sNotify.itemOld.stateMask = 0xFFFFFFFF;
6835 sNotify.itemOld.state = pTemp->uState;
6836 sNotify.itemOld.lParam = pTemp->lParam;
6837 sNotify.itemOld.pszText = pTemp->pText;
6838 sNotify.itemOld.cchTextMax = pTemp->uTextSize;
6839 sNotify.itemOld.cChildren = 0;
6840 }
6841 }
6842
6843 sItem.hItem = (HTREEITEM)(ULONG_PTR)uItem;
6844 sItem.mask = TVIF_STATE;
6845 sItem.stateMask = TVIS_STATEIMAGEMASK;
6846
6847 if(pData->uStyleEx & TVS_EX_BITCHECKBOX)
6848 sItem.state = (uBits ^ 0x1000);
6849 else
6850 sItem.state = (uBits & 0x1000) ? 0x2000 : 0x1000;
6851
6852 TreeListSetItem(pData, &sItem);
6853 pData->uSingleSel = uItem;
6854
6855 sNotify.hdr.code = TVN_CBSTATECHANGED;
6856 sNotify.action = VK_DBLCLK;
6857 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT;
6858 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
6859 sNotify.itemNew.stateMask = 0xFFFFFFFF;
6860 sNotify.itemNew.state = pEntry->uState;
6861 sNotify.itemNew.lParam = pEntry->lParam;
6862 sNotify.itemNew.pszText = pEntry->pText;
6863 sNotify.itemNew.cchTextMax = pEntry->uTextSize;
6864 sNotify.itemNew.cChildren = 0;
6865 sNotify.ptDrag.x = iPosX;
6866 sNotify.ptDrag.y = iPosY;
6867
6868 UNLOCK(pData);
6869 SendNotify(pData, &sNotify.hdr);
6870 LOCK(pData);
6871}
6872
6873//*****************************************************************************
6874//*
6875//* TreeListMouseNotify
6876//*
6877//*****************************************************************************
6878// Soll für einen Mausklick eine
6879// pData : Zeiger auf die Fensterdaten
6880// uMsg : Message des Mausklicks
6881// wParam : WPARAM des Mausklicks
6882// lParam : LPARAM des Mausklicks
6884
6885 TV_HITTESTINFO sInfo;
6886 NMTREEVIEW sNotify;
6888 unsigned uItem;
6889
6890 sInfo.flags = (UINT) wParam;
6891 sInfo.pt.x = LOWORD(lParam);
6892 sInfo.pt.y = HIWORD(lParam);
6893 uItem = TreeListHitTest(pData, &sInfo);
6894
6895 if(uItem) {
6896 pEntry = pData->pTreeItems[uItem];
6897 sNotify.itemNew.stateMask = 0xFFFFFFFF;
6898 sNotify.itemNew.state = pEntry->uState;
6899 sNotify.itemNew.lParam = pEntry->lParam;
6900 sNotify.itemNew.cChildren = TVHT_SUBTOCOL(sInfo.flags);
6901 } else {
6902 sNotify.itemNew.stateMask = 0;
6903 sNotify.itemNew.state = 0;
6904 sNotify.itemNew.lParam = 0;
6905 }
6906
6907 sNotify.action = 0;
6908 sNotify.hdr.code = uMsg;
6909 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBNUMBER;
6910 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
6911 sNotify.itemNew.pszText = (LPTSTR) - 1;
6912 sNotify.itemNew.cchTextMax = -1;
6913 sNotify.itemOld.mask = 0;
6914 sNotify.ptDrag.x = LOWORD(lParam);
6915 sNotify.ptDrag.y = HIWORD(lParam);
6916
6917 SendNotify(pData, &sNotify.hdr);
6918
6919}
6920
6921//*****************************************************************************
6922//*
6923//* TreeListMouseClick
6924//*
6925//*****************************************************************************
6926// Soll ein Mausklick ausgeführt werden. ACHTUNG UNLOCK wird ausgeführt
6927// pData : Zeiger auf die Fensterdaten
6928// uMsg : Message des Mausklicks
6929// wParam : WPARAM des Mausklicks
6930// lParam : LPARAM des Mausklicks
6932 ExtraItem *pExtra;
6934 BaseItem *pTemp;
6935 TV_HITTESTINFO sInfo;
6936 NMTREEVIEW sNotify;
6937 unsigned uOldSub;
6938 unsigned uOldItem;
6939 unsigned uMaskItem;
6940 unsigned uMaskSub;
6941 unsigned uMsgOld;
6942 unsigned uToggle;
6943 unsigned uItem;
6944 unsigned uLine;
6945 unsigned uTemp;
6946 unsigned uStop;
6947 unsigned uSub;
6948 unsigned uSel;
6949 unsigned uPos;
6950 unsigned uNum;
6951 int iMode;
6952 int iAdd;
6953
6954 if(!pData->cIsEnabled) { // Ist das Fenster freigegeben
6955 return;
6956 }
6957
6958 if(!pData->cHasFocus) { // Hat das Fenster den Focus
6959 if(GetFocus() != pData->hWnd) {
6960 UNLOCK(pData);
6961 SetFocus(pData->hWnd);
6962 LOCK(pData);
6963
6964 if(GetFocus() != pData->hWnd) {
6965 UNLOCK(pData);
6966 return;
6967 }
6968 } else {
6969 pData->cHasFocus = 1;
6970 }
6971 }
6972
6973 sInfo.flags = (UINT) wParam;
6974 sInfo.pt.x = LOWORD(lParam);
6975 sInfo.pt.y = HIWORD(lParam);
6976 uItem = TreeListHitTest(pData, &sInfo);
6977 uMsgOld = uMsg;
6978 uToggle = 0;
6979
6980 if(uItem) { // Wurde auf einen Eintrag getrückt
6981 pEntry = pData->pTreeItems[uItem];
6982
6983 if(pData->uStyle & TVS_FULLROWSELECT) {
6986 } else {
6988 uMaskSub = TVHT_ONSUBICON | TVHT_ONSUBLABEL;
6989 }
6990
6991 if(sInfo.flags & TVHT_ONITEMBUTTON) { // Eintrag aufklappen
6992 if(uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK) {
6993 pEntry = pData->pTreeItems[uItem];
6995 TreeListToggleItem(pData, uItem, 0); // Von + auf - umschalten
6996 } else {
6997 uToggle = 1; // Eintrag auflappen
6998 }
6999 }
7000 } else
7001 if(sInfo.flags & TVHT_ONITEMSTATEICON) { // Checkbox umschalten
7002 if(pData->uStyle & TVS_CHECKBOXES)
7003 if(uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK) {
7004 TreeListChangeCheckbox(pData, uItem, sInfo.pt.x, sInfo.pt.y);
7005 }
7006 } else
7007 if(sInfo.flags & uMaskItem) { // Eintrag auswählen
7008 if(!(pData->uStyle & TVS_DISABLEDRAGDROP)) {
7009 if(uMsg == WM_LBUTTONDOWN) {
7010 pData->uDragFlags = MK_LBUTTON;
7011 pData->uDragItem = uItem;
7012 pData->uDragSub = 0;
7013 }
7014
7015 if(uMsg == WM_RBUTTONDOWN) {
7016 pData->uDragFlags = MK_RBUTTON;
7017 pData->uDragItem = uItem;
7018 pData->uDragSub = 0;
7019 }
7020 }
7021
7022 if(pData->uStyleEx & TVS_EX_MULTISELECT) { // Mehrfachauswahl erlaubt
7023 if(uMsg == WM_RBUTTONDOWN) // Keine Abwahl wenn mehrer Einträge aus gewählt
7024 if(pData->uSelectedCount > 1) {
7025 pEntry = pData->pTreeItems[uItem];
7026 if(pEntry->uState & TVIS_SELECTED) {
7027 goto End;
7028 }
7029 }
7030
7031 if(uMsg == WM_LBUTTONDOWN) // Spezialsteuerung für Multiselect bei Darg
7032 if(!(wParam & (MK_CONTROL | MK_SHIFT)))
7033 if(pData->uSelectedCount > 0) {
7034 pEntry = pData->pTreeItems[uItem];
7035 if(pEntry && (pEntry->uState & TVIS_SELECTED)) {
7036 pData->cClickFlag = 1;
7037 pData->cClickEdit = 0;
7038 goto End;
7039 }
7040 }
7041
7042 if(uMsg == WM_LBUTTONUP && pData->cClickFlag) {
7043 wParam &= ~(MK_CONTROL | MK_SHIFT);
7044 uMsg = WM_LBUTTONDOWN;
7045 }
7046
7047 if(wParam & MK_SHIFT) { // Bis zum angeklicken Auswählen
7048 if(uMsg != WM_LBUTTONDOWN)
7049 if(uMsg != WM_LBUTTONDBLCLK)
7050 goto End;
7051
7052 pData->cClickEdit = 0;
7053
7054 uTemp = pData->uSelectedItem;
7055 if(!uTemp) {
7056 uTemp = pData->uFocusItem;
7057 if(!uTemp || !pData->cReSelect)
7058 goto End;
7059 }
7060
7061 pEntry = pData->pTreeItems[uTemp];
7062 uLine = pEntry->uShowPos;
7063 if(!uLine)
7064 goto End;
7065
7066 pEntry = pData->pTreeItems[uItem];
7067 uStop = pEntry->uShowPos;
7068 if(!uStop)
7069 goto End;
7070
7071 if(pData->uSelectedCount <= 1) {
7072 pData->uSelectedBase = uTemp;
7073 }
7074
7075 // Shift-Select neu auswählen
7076 if(pData->cReSelect && pData->uSelectedBase) {
7078 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
7079
7080 uTemp = pData->uSelectedBase;
7081 pTemp = pData->pTreeItems[uTemp];
7082 uStop = uItem;
7083
7084 while(pTemp && pTemp->uShowPos == 0) {
7085 pTemp = pData->pTreeItems[pTemp->uParent];
7086 if(!pTemp)
7087 break;
7088 }
7089
7090 if(pTemp) {
7091 if(!(pTemp->uState & TVIS_SELECTED)) {
7093 }
7094
7095 if(pTemp->uShowPos < pEntry->uShowPos) {
7096 uStop = uItem;
7097 } else {
7098 uStop = uTemp;
7099 uTemp = uItem;
7100 }
7101
7102 for(;;) {
7103 uTemp = TreeListNextUnselUntil(pData, uTemp, uStop);
7104 if(!uTemp)
7105 break;
7107 }
7108 }
7109
7110 pData->cReSelect = 0;
7111 goto End;
7112 }
7113
7115
7116 iAdd = (uLine > uStop) ? -1 : 1;
7117 uPos = uLine;
7118
7119 if(uPos != uStop) {
7120 pEntry = pData->pTreeItems[pData->uSelectedBase];
7121
7122 while(pEntry && pEntry->uShowPos == 0) {
7123 pEntry = pData->pTreeItems[pEntry->uParent];
7124 }
7125
7126 if(pEntry) {
7127 if(iAdd < 0){
7128 if(pEntry->uShowPos > uPos && uPos > uStop)
7129 uPos--;
7130 }
7131 else {
7132 if(pEntry->uShowPos < uPos && uPos < uStop)
7133 uPos++;
7134 }
7135 }
7136 }
7137
7138 for(;; uPos += iAdd) { // Einträge wählen
7139 uTemp = pData->pItemPos [uPos - 1];
7140 pEntry = pData->pTreeItems[uTemp ];
7141 uSel = pEntry->uState & TVIS_SELECTED;
7142
7143 if(uTemp != pData->uSelectedBase || !uSel) {
7145 uSel = pEntry->uState & TVIS_SELECTED;
7146 }
7147
7148 // Auch unsichtbare Kinder wählen
7149 pTemp = pData->pTreeItems[pEntry->uFirstChild];
7150 if(pTemp && !pTemp->uShowPos) {
7151 if(uSel) {
7152 for(uNum = uTemp;;) { // Kinder auswählen
7153 uNum = TreeListNextUnselUntil(pData, uNum, uTemp);
7154 if(!uNum)
7155 break;
7157 }
7158 } else {
7159 for(uNum = uTemp;;) { // Kinder abwählen
7160 uNum = TreeListNextSelUntil(pData, uNum, uTemp);
7161 if(!uNum)
7162 break;
7164 }
7165 }
7166 }
7167
7168 if(uPos == uStop)
7169 break;
7170 }
7171
7173
7174 pEntry = pData->pTreeItems[uItem];
7175 uSub = TVHT_SUBTOCOL(sInfo.flags);
7176 if(!(pData->uStyleEx & TVS_EX_SUBSELECT))
7177 uSub = 0;
7178
7179 pData->uFocusSub = uSub;
7180 pData->uFocusItem = uItem;
7181
7182 if(uSub) {
7183 pExtra = pData->pExtraItems[uSub - 1][uItem];
7184 if(pExtra)
7185 pExtra->bFlags |= TVIX_FOCUSED;
7186 } else {
7187 pEntry->bFlags |= TVIX_FOCUSED;
7188 }
7189
7190 UpdateRect(pData, uItem, uSub);
7191
7193 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
7194
7195 goto End;
7196 }
7197
7198 if(wParam & MK_CONTROL) { // Einzelen Eintrag umschalten
7199 pData->uSelectedBase = uItem;
7200 pData->cReSelect = 1;
7201 pData->cClickEdit = 0;
7202
7203 pEntry = pData->pTreeItems[uItem];
7204 if(pEntry && (pEntry->uState & TVIS_SELECTED)) {
7205 if(uMsg != WM_LBUTTONDOWN)
7206 if(uMsg != WM_LBUTTONDBLCLK)
7207 goto End;
7208
7210
7212 // Auch unsichtbare Kinder abwählen
7213 pTemp = pData->pTreeItems[pEntry->uFirstChild];
7214 if(pTemp && !pTemp->uShowPos)
7215 for(uTemp = uItem;;) {
7216 uTemp = TreeListNextSelUntil(pData, uTemp, uItem);
7217 if(!uTemp)
7218 break;
7220 }
7221 }
7222
7223 uTemp = pData->uFocusItem;
7224 if(uTemp) { // Ist ein Focus definiert
7226 }
7227
7228 uSub = TVHT_SUBTOCOL(sInfo.flags);
7229 if(!(pData->uStyleEx & TVS_EX_SUBSELECT))
7230 uSub = 0;
7231
7232 pData->uFocusItem = uItem;
7233 pData->uFocusSub = uSub;
7234
7235 if(uSub) {
7236 pExtra = pData->pExtraItems[uSub - 1][uItem];
7237 if(pExtra)
7238 pExtra->bFlags |= TVIX_FOCUSED;
7239 } else {
7240 pEntry->bFlags |= TVIX_FOCUSED;
7241 }
7242
7243 UpdateRect(pData, uItem, uSub);
7244
7245 goto End;
7246 }
7247 }
7248 }
7249
7250 if(wParam & MK_CONTROL) { // Ist die Ctrl-Taste gedrückt
7252 } else {
7254 }
7255
7256 uOldSub = pData->uSelectedSub;
7257 uOldItem = pData->uSelectedItem;
7258
7260 TreeListSelectItem(pData, uItem, 0, iMode);
7261 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
7262 pEntry = pData->pTreeItems[uItem];
7263
7264 if(uMsg == WM_LBUTTONDBLCLK) {
7265 // Auto-Edit mit Doppelklick
7266 if(pData->aColumn[0].bFlags & TVAE_DBLCLICK && pData->aColumn[0].bEdit) {
7268 } else
7269 if(TreeListStartNotifyEdit(pData, pData->uSelectedItem, 0, VK_DBLCLK, lParam)) {
7270
7271 } else
7273 TreeListToggleItem(pData, uItem, 0); // Von + auf - umschalten
7274 } else {
7275 uToggle = 1; // Eintrag auflappen
7276 }
7277 } else
7278 if(uMsgOld == WM_LBUTTONDOWN) {
7279 if(pData->uStyleEx & TVS_EX_EDITCLICK)
7280 if(!(wParam & (MK_CONTROL | MK_SHIFT)))
7281 if(sInfo.flags & uMaskItem&~TVHT_ONITEMICON)
7282 if(uOldSub == pData->uSelectedSub && uOldItem == pData->uSelectedItem) {
7283 pData->cClickEdit = 1;
7284 }
7285 } else
7286 if(uMsgOld == WM_LBUTTONUP) {
7287 if(pData->uStyleEx & TVS_EX_EDITCLICK)
7288 if(pData->cClickFlag && !pData->cClickEdit)
7289 if(!(wParam & (MK_CONTROL | MK_SHIFT)))
7290 if(sInfo.flags & uMaskItem&~TVHT_ONITEMICON)
7291 if(uOldSub == pData->uSelectedSub && uOldItem == pData->uSelectedItem) {
7292 pData->cClickEdit = 1;
7293 }
7294
7295 if(pData->cClickEdit) {
7296 pData->cClickEdit = 0;
7297
7298 if(pData->aColumn[0].bEdit) {
7300 } else {
7301 TreeListStartNotifyEdit(pData, pData->uSelectedItem, 0, VK_EDITCLK, lParam);
7302 }
7303 }
7304 }
7305 } else
7306 if(sInfo.flags & uMaskSub) { // Extra-Eintrag auswählen
7307 if(pData->uStyleEx & TVS_EX_SUBSELECT)
7308 uSub = TVHT_SUBTOCOL(sInfo.flags);
7309 else
7310 uSub = 0;
7311
7312 if(!(pData->uStyle & TVS_DISABLEDRAGDROP)) {
7313 if(uMsg == WM_LBUTTONDOWN) {
7314 pData->uDragFlags = MK_LBUTTON;
7315 pData->uDragItem = uItem;
7316 pData->uDragSub = uSub;
7317 }
7318
7319 if(uMsg == WM_RBUTTONDOWN) {
7320 pData->uDragFlags = MK_RBUTTON;
7321 pData->uDragItem = uItem;
7322 pData->uDragSub = uSub;
7323 }
7324 }
7325
7326 if(wParam & MK_CONTROL) {
7327 if(pData->uStyleEx & TVS_EX_MULTISELECT) { // Auswahl umschalten
7328 pEntry = pData->pTreeItems[uItem];
7329 if(pEntry && (pEntry->uState & TVIS_SELECTED)) {
7330 if(uMsg != WM_LBUTTONDOWN)
7331 if(uMsg != WM_LBUTTONDBLCLK)
7332 goto End;
7333
7335
7337 // Auch unsichtbare Kinder abwählen
7338 pTemp = pData->pTreeItems[pEntry->uFirstChild];
7339 if(pTemp && !pTemp->uShowPos)
7340 for(uTemp = uItem;;) {
7341 uTemp = TreeListNextSelUntil(pData, uTemp, uItem);
7342 if(!uTemp)
7343 break;
7345 }
7346 }
7347
7349
7350 pData->cClickEdit = 0;
7351 pData->uFocusItem = uItem;
7352 pData->uFocusSub = uSub;
7353
7354 if(uSub) {
7355 pExtra = pData->pExtraItems[uSub - 1][uItem];
7356 if(pExtra)
7357 pExtra->bFlags |= TVIX_FOCUSED;
7358 } else {
7359 pEntry->bFlags |= TVIX_FOCUSED;
7360 }
7361
7362 UpdateRect(pData, uItem, uSub);
7363
7364 goto End;
7365 }
7366 }
7367
7369 } else {
7371 }
7372
7373 uOldSub = pData->uSelectedSub;
7374 uOldItem = pData->uSelectedItem;
7375
7378 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
7379 pEntry = pData->pTreeItems[uItem];
7380
7381 if(uMsg == WM_LBUTTONDBLCLK) {
7382 if(pData->aColumn[uSub].bEdit && // Auto-Edit mit Doppelklick
7383 ((pData->aColumn[uSub].bFlags & TVAE_DBLCLICK) ||
7384 ((pData->aColumn[uSub].bFlags & TVAE_ICONCLICK) && (sInfo.flags & TVHT_ONSUBICON)))) {
7386 } else
7387 if(TreeListStartNotifyEdit(pData, uItem, uSub, VK_DBLCLK, lParam)) {
7388
7389 } else {
7390 uToggle = 1; // Eintrag auflappen
7391 }
7392 } else
7393 if(uMsg == WM_LBUTTONDOWN) {
7394 if(pData->aColumn[uSub].bEdit) // Auto-Edit mit Klick auf Icon
7395 if(pData->aColumn[uSub].bFlags & TVAE_ICONCLICK)
7396 if(sInfo.flags & TVHT_ONSUBICON) {
7398 }
7399
7400 if(pData->uStyleEx & TVS_EX_EDITCLICK)
7401 if(uSub && !(wParam & (MK_CONTROL | MK_SHIFT)))
7402 if(sInfo.flags & uMaskSub&~TVHT_ONSUBICON)
7403 if(uOldSub == pData->uSelectedSub && uOldItem == pData->uSelectedItem) {
7404 pData->cClickEdit = 1;
7405 }
7406 } else
7407 if(uMsg == WM_LBUTTONUP) {
7408 if(pData->cClickEdit) {
7409 pData->cClickEdit = 0;
7410
7411 if(pData->aColumn[uSub].bEdit) {
7413 } else {
7415 }
7416 }
7417 }
7418 }
7419 } else {
7420 pEntry = NULL;
7421 uSub = 0;
7422 }
7423
7424End:
7425
7426 switch(uMsgOld) {
7427 case WM_LBUTTONUP:
7428 sNotify.hdr.code = TVN_LBUTTONUP;
7429 break;
7430 case WM_LBUTTONDOWN:
7431 sNotify.hdr.code = NM_CLICK;
7432 break;
7433 case WM_LBUTTONDBLCLK:
7434 sNotify.hdr.code = NM_DBLCLK;
7435 break;
7436 case WM_RBUTTONUP:
7437 sNotify.hdr.code = TVN_RBUTTONUP;
7438 break;
7439 case WM_RBUTTONDOWN:
7440 sNotify.hdr.code = NM_RCLICK;
7441 break;
7442 case WM_RBUTTONDBLCLK:
7443 sNotify.hdr.code = NM_RDBLCLK;
7444 break;
7445 default
7446 :
7447 UNLOCK(pData);
7448 return;
7449 }
7450
7451 if(pEntry) {
7452 sNotify.itemNew.stateMask = 0xFFFFFFFF;
7453 sNotify.itemNew.state = pEntry->uState;
7454 sNotify.itemNew.lParam = pEntry->lParam;
7455 sNotify.itemNew.cChildren = TVHT_SUBTOCOL(sInfo.flags);
7456 } else {
7457 sNotify.itemNew.stateMask = 0;
7458 sNotify.itemNew.state = 0;
7459 sNotify.itemNew.lParam = 0;
7460 }
7461
7462 sNotify.action = 0;
7463 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBNUMBER;
7464 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
7465 sNotify.itemNew.pszText = (LPTSTR) - 1;
7466 sNotify.itemNew.cchTextMax = -1;
7467 sNotify.itemOld.mask = 0;
7468 sNotify.ptDrag.x = LOWORD(lParam);
7469 sNotify.ptDrag.y = HIWORD(lParam);
7470
7471 UNLOCK(pData);
7472
7473 if(!SendNotify(pData, &sNotify.hdr)) {
7474 if(uToggle) { // Aufklappen nur wenn Notify nicht abgefangen
7475 LOCK(pData);
7476 TreeListToggleItem(pData, uItem, 0);
7477 UNLOCK(pData);
7478 }
7479 }
7480
7481}
7482
7483//*****************************************************************************
7484//*
7485//* TreeListChar
7486//*
7487//*****************************************************************************
7488// Eingabe von Buchstaben über die WM_CHAR Nachricht
7489// pData : Zeiger auf die Fensterdaten
7490// nChar : Ist das Zeichen das eingegeben wurde
7492
7493 LPTSTR pName;
7494 ExtraItem *pExtra;
7496 unsigned uDelta;
7497 unsigned uItem;
7498 unsigned uTick;
7499 unsigned uSub;
7500 unsigned uPos;
7501 unsigned uVal;
7502 int iNum;
7503 int iMax;
7504 int i;
7505
7506 if(nChar >= ' ') {
7507 if(pData->cKeyIgnore)
7508 return; // Taste soll ignoriert werden
7509
7510 iMax = pData->uItemPosCount;
7511 uSub = pData->uSelectedSub;
7512 i = 0;
7513
7514 if(TVIS_EDIT(pData->aColumn[uSub].bEdit)) // Bei AutoEdit keine Auswahl
7515 if(!(pData->aColumn[uSub].bFlags & TVAE_ONLYRETURN)) {
7516 TreeListStartAutoEdit(pData, uSub, nChar, 0);
7517 return;
7518 }
7519
7520 if(TreeListStartNotifyEdit(pData, pData->uSelectedItem, uSub, nChar | VK_ISACHAR, lParam)) {
7521 return;
7522 }
7523
7524 if(iMax <= 0)
7525 return;
7526
7527 iNum = pData->uSelectedItem; // Hole die Startzeile
7528 if(iNum > 0) {
7529 iNum = pData->pTreeItems[iNum]->uShowPos - 1;
7530 if(iNum < 0)
7531 iNum = 0;
7532 }
7533
7534 if((nChar >= 'a' && nChar <= 'z') || // In Grosbuchstaben umwandeln
7535 (nChar >= 224 && nChar <= 254)) {
7536 nChar -= 'a' - 'A';
7537 }
7538
7539 if(!(pData->uStyleEx & TVS_EX_NOCHARSELCET))
7540 for(;;) { // Suche Anfangsbuchstaben
7541 uTick = GetTickCount();
7542 uDelta = (uKeyPos > 0) ? 750 : 500;
7543
7544 if(uKeyPos >= 3)
7545 uDelta = 1000;
7546 if(uTick - uKeyLast > uDelta)
7547 uKeyPos = 0;
7548 if(uKeyPos >= 16)
7549 uKeyPos = 0;
7550 if(uKeyPos == 1 && cKeyData[0] == (TCHAR)nChar) {
7551 uKeyPos = 0;
7552 }
7553
7554 cKeyData[uKeyPos] = (TCHAR)nChar;
7555 uKeyLast = uTick;
7556 uKeyPos += 1;
7557
7558 if(uKeyPos > 1) {
7559 iNum--;
7560 if(iNum < 0)
7561 iNum = iMax - 1;
7562 }
7563
7564 if(iMax <= 0)
7565 break;
7566
7567 for(i = iNum + 1; i != iNum; i++) { // Suche Übereinstimmung
7568 if(i >= iMax) {i = -1; continue;}
7569 uItem = pData->pItemPos[i];
7570
7571 if(uSub) {
7572#ifndef __REACTOS__
7573 pExtra = pExtra = pData->pExtraItems[uSub - 1][uItem];
7574#else
7575 pExtra = pData->pExtraItems[uSub - 1][uItem];
7576#endif
7577 pName = (pExtra && pExtra->pText) ? pExtra->pText : _T("");
7578 } else {
7579 pEntry = pData->pTreeItems[uItem];
7580 pName = (pEntry && pEntry->pText) ? pEntry->pText : _T("");
7581 }
7582
7583 for(uPos = 0; uPos < uKeyPos; uPos++) { // Vergleiche die Texte
7584#if UNICODE
7585 uVal = pName[uPos];
7586#else
7587 uVal = ((unsigned char *)pName)[uPos];
7588#endif
7589
7590 if((uVal >= 'a' && uVal <= 'z') || // In Grosbuchstaben umwandeln
7591 (uVal >= 224 && uVal <= 254)) {
7592 uVal -= 'a' - 'A';
7593 }
7594
7595 if(cKeyData[uPos] != (TCHAR)uVal) {
7596 break;
7597 }
7598 }
7599
7600 if(uPos < uKeyPos)
7601 continue;
7602
7603 if(TreeListSelectItem(pData, uItem, uSub, TVC_UNKNOWN | TVC_DESELECT)) {
7604 TreeListEnsureVisible(pData, uItem, uSub);
7605 }
7606
7607 return;
7608 }
7609
7610 if(i != iNum)
7611 break;
7612 if(uKeyPos <= 1)
7613 break;
7614
7615 iNum++;
7616 if(iNum >= iMax)
7617 iNum = iMax - 1;
7618
7619 uKeyPos = 0;
7620 }
7621 }
7622
7623}
7624
7625//*****************************************************************************
7626//*
7627//* TreeListKeyDown
7628//*
7629//*****************************************************************************
7630// Soll ein Tastentruck ausgeführt werden. ACHTUNG UNLOCK wird ausgeführt
7631// pData : Zeiger auf die Fensterdaten
7632// wParam : WPARAM des Mausklicks
7633// lParam : LPARAM des Mausklicks
7634// Ergibt 0 wenn die Taste verarbeitet wurde
7636
7637 BaseItem *pTemp;
7639 TV_KEYDOWN_EX sNotify;
7640 unsigned uTemp;
7641 unsigned uItem;
7642 unsigned uStop;
7643 unsigned uVal;
7644 int iLineCmp;
7645 int iOldLine;
7646 int iOldCol;
7647 int iFocus;
7648 int iShift;
7649 int iBase;
7650 int iLine;
7651 int iAdd;
7652 int iPos;
7653 int iSub;
7654 int iCol;
7655 int iMax;
7656 int iDel;
7657 int iScr;
7658 int iSel;
7659
7660 if(!pData->cIsEnabled) { // Ist das Fenster freigegeben
7661 return;
7662 }
7663
7664 if(!pData->cHasFocus) { // Hat das Fenster den Focus
7665 if(GetFocus() != pData->hWnd) {
7666 UNLOCK(pData);
7667 SetFocus(pData->hWnd);
7668 LOCK(pData);
7669
7670 if(GetFocus() != pData->hWnd) {
7671 return;
7672 }
7673 } else {
7674 pData->cHasFocus = 1;
7675 }
7676 }
7677
7678 if(wParam == VK_RETURN) { // Wurde Enter gedrückt
7679 UNLOCK(pData);
7680
7681 sNotify.hdr.code = NM_RETURN;
7682 sNotify.wVKey = (WORD)(wParam);
7683 sNotify.wScan = (WORD)(wParam >> 16);
7684 sNotify.flags = (UINT)(lParam);
7685
7686 SendNotify(pData, &sNotify.hdr);
7687
7688 iSub = pData->uSelectedSub;
7689
7690 if(pData->aColumn[iSub].bEdit) { // Auto-Edit starten
7691 if(GetAsyncKeyState(VK_CONTROL) & 0x8000) {
7693 lParam = 0;
7694 }
7695
7697 } else {
7698 TreeListStartNotifyEdit(pData, pData->uSelectedItem, iSub, wParam, lParam);
7699 }
7700
7701 return;
7702 }
7703
7704 pEntry = pData->pTreeItems[pData->uSelectedItem];
7705 iDel = (GetAsyncKeyState(VK_SHIFT) & 0x8000) ? 0 : TVC_DESELECT;
7706 iScr = GetAsyncKeyState(VK_CONTROL) & 0x8000;
7707
7708 if(iDel && iScr) // Ende oder Anfang wählen
7709 if(wParam == VK_HOME || wParam == VK_END)
7710 if(pData->uStyleEx & TVS_EX_HOMEENDSELECT) {
7711 iDel = TVC_DESELECT;
7712 iScr = 0;
7713 }
7714
7715 if(iDel && iScr) { // Das Fenster scrollen
7716 iLine = pData->uScrollY;
7717 iSub = pData->uScrollX;
7718
7719 switch(wParam) {
7720 case VK_END:
7721 iLine = pData->uTreeItemsCount; // Ans Ende scrollen
7722 iLine -= pData->uPageEnties;
7723 break;
7724
7725 case VK_HOME:
7726 iLine = 0; // Zum Anfang scrollen
7727 break;
7728
7729 case VK_LEFT:
7730 iSub -= 16; // Links scrollen
7731 break;
7732
7733 case VK_RIGHT:
7734 iSub += 16; // Rechts scrollen
7735 break;
7736
7737 case VK_UP:
7738 iLine--; // Nach oben scrollen
7739 break;
7740
7741 case VK_DOWN:
7742 iLine++; // Nach unten scrollen
7743 break;
7744
7745 case VK_PRIOR:
7746 iLine -= pData->uSizeX; // Eine Seite nach oben
7747 break;
7748
7749 case VK_NEXT:
7750 iLine += pData->uSizeX; // Eine Seite nach unten
7751 break;
7752
7753 case VK_SPACE:
7754 if(pEntry == NULL)
7755 break; // Expantieren und schließen
7756 if(pEntry->bFlags & TVIX_HASBUTTON) {
7757 TreeListToggleItem(pData, pData->uSelectedItem, 0);
7758 }
7759
7760 break;
7761
7762 default
7763 :
7764 goto Exit;
7765 }
7766
7767 if(iLine != (int)pData->uScrollY) {
7768 iMax = pData->uItemPosCount;
7769 iMax -= pData->uPageEnties - 1;
7770
7771 if(iLine >= iMax)
7772 iLine = iMax;
7773 if(iLine < 0)
7774 iLine = 0;
7775 if(iLine != (int)pData->uScrollY)
7776 if(!(pData->uStyle & TVS_NOSCROLL)) {
7777 pData->uScrollY = iLine;
7780 }
7781 }
7782
7783 if(iSub != (int)pData->uScrollX) {
7784 uVal = pData->uColumnCount;
7785 if(uVal)
7786 iMax = pData->aColumnXpos[uVal] - pData->uSizeX / 2;
7787 else
7788 iMax = pData->iMaxSizeX;
7789 iMax -= pData->uSizeX - pData->uSizeX / 2;
7790
7791 if(iSub >= iMax)
7792 iSub = iMax;
7793 if(iSub < 0)
7794 iSub = 0;
7795 if(iSub != (int)pData->uScrollX)
7796 if(!(pData->uStyle & TVS_NOSCROLL)) {
7797 pData->uScrollX = iSub;
7798 SetScrollPos(pData->hWnd, SB_HORZ, iSub, TRUE);
7800
7801 if(pData->hHeader) {
7802 MoveWindow(pData->hHeader, -iSub, 0, pData->uSizeX + iSub, pData->uStartPixel, TRUE);
7803 }
7804 }
7805 }
7806 } else { // Einen anderen Eintrag auswählen
7807 iSub = pData->uSelectedSub;
7808 iCol = pData->aColumn[iSub].bIndex;
7809
7810 if(!pEntry) {
7811 iLine = 0;
7812 iCol = 0;
7813 iOldCol = 0;
7814 iOldLine = -1;
7815
7816 uTemp = pData->uFocusItem;
7817 if(uTemp) { // Ist ein Focus definiert
7818 pTemp = pData->pTreeItems[uTemp];
7819
7820 while(pTemp && !pTemp->uShowPos) {
7821 pTemp = pData->pTreeItems[pTemp->uParent];
7822 }
7823
7824 if(pTemp) {
7825 iLine = pTemp->uShowPos - 1;
7826 iSub = pData->uFocusSub;
7827 iCol = pData->aColumn[iSub].bIndex;
7828 }
7829
7830 if(pData->uSelectedCount > 1) {
7831 iOldCol = iCol;
7832 iOldLine = iLine;
7833 } else {
7835 }
7836 }
7837 } else {
7838 iLine = pEntry->uShowPos - 1;
7839 if(iLine < 0)
7840 iLine = 0;
7841
7842 uTemp = pData->uSelectedItem;
7843 iOldLine = iLine;
7844 iOldCol = iCol;
7845 }
7846
7847 switch(wParam) {
7848 case VK_END:
7849 iLine = pData->uItemPosCount - 1;
7850 break;
7851 case VK_HOME:
7852 iLine = 0;
7853 break;
7854 case VK_LEFT:
7855 if(pData->uColumnCount > 1 && (pData->uStyleEx & TVS_EX_SUBSELECT)) {
7856 while(iCol > 0) {
7857 iCol--;
7858 iSub = pData->aColumnPos[iCol];
7859 if(pData->aColumn[iSub].sReal > 0)
7860 break;
7861 }
7862 } else {
7863 if(! pEntry)
7864 break;
7865 if(!(pEntry->uState & TVIS_EXPANDED) || !pEntry->uFirstChild) {
7866 pTemp = pData->pTreeItems[pEntry->uParent];
7867 if(pTemp)
7868 iLine = pTemp->uShowPos - 1;
7869 break;
7870 }
7871
7872 if(pEntry->bFlags & TVIX_HASBUTTON) {
7873 TreeListToggleItem(pData, pData->uSelectedItem, 0);
7874 }
7875 }
7876
7877 break;
7878
7879 case VK_RIGHT:
7880 if(pData->uColumnCount > 1 && (pData->uStyleEx & TVS_EX_SUBSELECT)) {
7881 while(iCol + 1 < (int)pData->uColumnCount) {
7882 iCol++;
7883 iSub = pData->aColumnPos[iCol];
7884 if(pData->aColumn[iSub].sReal > 0)
7885 break;
7886 }
7887 } else {
7888 if(!pEntry)
7889 break;
7890 if(pEntry->uState & TVIS_EXPANDED) {
7891 iLine++;
7892 break;
7893 }
7894
7895 if(pEntry->bFlags & TVIX_HASBUTTON) {
7896 TreeListToggleItem(pData, pData->uSelectedItem, 0);
7897 }
7898 }
7899
7900 break;
7901
7902 case VK_UP:
7903 iLine--;
7904 break;
7905 case VK_DOWN:
7906 iLine++;
7907 break;
7908
7909 case VK_PRIOR:
7910 iAdd = pData->uPageEnties - 1; // Eine Seite nach oben
7911 if(iAdd <= 0)
7912 iAdd = 1;
7913 iLine -= iAdd;
7914 break;
7915
7916 case VK_NEXT:
7917 iAdd = pData->uPageEnties - 1; // Eine Seite nach unten
7918 if(iAdd <= 0)
7919 iAdd = 1;
7920 iLine += iAdd;
7921 break;
7922
7923 case VK_BACK: // Eine Ebene höher
7924 if(pEntry) {
7925 uItem = pEntry->uParent;
7926 if(!uItem)
7927 iLine = 0;
7928 else {
7929 iLine = pData->pTreeItems[uItem]->uShowPos - 1;
7930 if(iLine < 0)
7931 iLine = 0;
7932 }
7933 }
7934
7935 break;
7936
7937 case VK_SPACE:
7938 if(pEntry && iCol == 0 && (pData->uStyle & TVS_CHECKBOXES)) {
7939 TreeListChangeCheckbox(pData, pData->uSelectedItem, 0, 0);
7940 }
7941
7942 break;
7943
7944 default
7945 :
7946 goto Exit;
7947 }
7948
7949 if(iCol >= (int)pData->uColumnCount)
7950 iCol = pData->uColumnCount - 1;
7951 if(iCol < 0)
7952 iCol = 0;
7953 if(iLine >= (int)pData->uItemPosCount)
7954 iLine = pData->uItemPosCount - 1;
7955 if(iLine < 0)
7956 iLine = 0;
7957
7958 if(!(pData->uStyleEx & TVS_EX_SUBSELECT))
7959 iCol = 0;
7960
7961 if(pData->uItemPosCount > 0)
7962 if(iLine != iOldLine || iCol != iOldCol) { // Wurde ein anderer Eintrag ausgewählt
7963 if(pData->uSelectedCount > 1) {
7965 } else {
7966 pData->uSelectedBase = uTemp;
7967 }
7968
7969 iShift = iDel;
7970
7971 if(pData->cReSelect) { // Die Shift-Auswahl neu erstellen
7972 iDel = TVC_DESELECT;
7973 }
7974
7975 uItem = pData->pItemPos [iLine];
7976 pTemp = pData->pTreeItems[uItem];
7977 iSub = pData->aColumnPos[iCol ];
7978 iFocus = (pTemp && (pTemp->uState & TVIS_SELECTED)) ? TVC_ONLYFOCUS : 0;
7979
7980 TreeListSelectItem(pData, uItem, iSub, TVC_BYKEYBOARD | iDel | iFocus);
7981
7982 if(!(pData->uStyle & TVS_NOSCROLL)) {
7983 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
7984 }
7985
7986 if(pData->cReSelect && pData->uSelectedBase) { // Shift-Select neu auswählen
7987 uTemp = pData->uSelectedBase;
7988 pTemp = pData->pTreeItems[uTemp];
7989 uStop = uItem;
7990
7991 while(pTemp && pTemp->uShowPos == 0) {
7992 pTemp = pData->pTreeItems[pTemp->uParent];
7993 if(!pTemp)
7994 break;
7995 }
7996
7997 if(pTemp && !iShift) {
7998 if(!(pTemp->uState & TVIS_SELECTED)) {
8000 }
8001
8002 iLineCmp = pTemp->uShowPos - 1;
8003 if(iLineCmp < iLine) {
8004 uStop = uItem;
8005 } else {
8006 uStop = uTemp;
8007 uTemp = uItem;
8008 }
8009
8010 for(;;) {
8011 uTemp = TreeListNextUnselUntil(pData, uTemp, uStop);
8012 if(!uTemp)
8013 break;
8015 }
8016 }
8017
8018 pData->cReSelect = 0;
8019 }
8020
8021 if((pData->uStyleEx & TVS_EX_MULTISELECT) && !iDel) {
8022 uVal = pData->uSelectedBase;
8023 pTemp = pData->pTreeItems[uVal];
8024 iBase = (pTemp) ? pTemp->uShowPos - 1 : -1;
8025
8026 if(iLine > iOldLine) { // Nach oben oder nach unten
8027 iMax = (iOldLine > iBase) ? iOldLine + 1 : iOldLine;
8028 if(iMax < 0)
8029 iMax = 0;
8030 iPos = iLine;
8031 } else {
8032 iMax = iLine;
8033 iPos = (iOldLine < iBase) ? iOldLine - 1 : iOldLine;
8034 if(iPos < 0)
8035 iPos = 0;
8036 }
8037
8038 for(; iPos >= iMax; iPos--) { // Übersprungene Einträge mit aus/abwählen
8039 uItem = pData->pItemPos[iPos];
8040
8041 if(iPos != iLine && iPos != iBase) {
8043 continue;
8044 }
8045
8046 pTemp = pData->pTreeItems[uItem]; // Auch unsichtbare Kinder abwählen
8047 if(pTemp) {
8048 iSel = pTemp->uState & TVIS_SELECTED;
8049 pTemp = pData->pTreeItems[pTemp->uFirstChild];
8050 if(!pTemp || pTemp->uShowPos)
8051 continue;
8052 if(!iSel) {
8053 for(uTemp = uItem;;) {
8054 uTemp = TreeListNextSelUntil(pData, uTemp, uItem);
8055 if(!uTemp)
8056 break;
8058 }
8059 } else {
8060 for(uTemp = uItem;;) {
8061 uTemp = TreeListNextUnselUntil(pData, uTemp, uItem);
8062 if(!uTemp)
8063 break;
8065 }
8066 }
8067 }
8068 }
8069 }
8070 }
8071 }
8072
8073Exit:
8074
8075 sNotify.hdr.code = TVN_KEYDOWN;
8076 sNotify.wVKey = (WORD)(wParam);
8077 sNotify.wScan = (WORD)(wParam >> 16);
8078 sNotify.flags = (UINT)(lParam);
8079
8080 UNLOCK(pData);
8081
8082 pData->cKeyIgnore = (char)SendNotify(pData, &sNotify.hdr);
8083
8084}
8085
8086//*****************************************************************************
8087//*
8088//* TreeListSortItemsEx
8089//*
8090//*****************************************************************************
8091// Sortiert die Kindereinträge eines Eintrages mitteles einer Funktion
8092// pData : Zeiger auf die Fensterdaten
8093// pSortData : Ist ein Zeiger auf die Sortiertaten
8094// iMode : 1=Rekursiv sortieren
8095// Ergibt 1 wenn ok sonst 0
8097
8098 TV_SORTEX sSort;
8099 unsigned uNum;
8100 unsigned uItem;
8101 unsigned uLast;
8102 unsigned uFirst;
8103 unsigned uParent;
8106 BaseItem *pNext;
8107 BaseItem **pList;
8108
8109 unsigned *pItemList;
8110 unsigned *pItemNew;
8111 unsigned uEnties[128];
8112 unsigned uPos;
8113 unsigned uMax;
8114
8115 PFNTVCOMPAREEX pCompare;
8116 HTREEITEM hItemTemp;
8117 LPARAM lParamTemp;
8118 LPARAM lParamSort;
8119 HWND hTreeWnd;
8120 int iLower, iUpper, iMiddle, iCmp;
8121 int uMemL[30], uMemU[30];
8122 int iStart, iLast;
8123 int iLevel;
8124 unsigned uTemp;
8125
8126
8127 pList = pData->pTreeItems;
8128
8129 uParent = U(pSortData->hParent);
8130 if(uParent > pData->uTreeItemsMax) { // Root-Eintrag sortieren
8131 if(uParent != U(TVI_ROOT))
8132 return 0;
8133
8134 uLast = pData->uLastChild;
8135 uFirst = pData->uFirstChild;
8136 if(uFirst == 0)
8137 return 1;
8138 if(uFirst == uLast) { // Einzelner Eintrag
8139 pNext = pList[uFirst];
8140 if(!pNext->uFirstChild)
8141 return 1;
8142
8143 sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst;
8144 sSort.lParam = pSortData->lParam;
8145 sSort.lpfnCompare = pSortData->lpfnCompare;
8147 return 1;
8148 }
8149
8150 pParent = 0;
8151 uParent = 0;
8152 } else { // Untereintrag sortieren
8153 pParent = pList[uParent];
8154 if(pParent == NULL)
8155 return 0;
8156
8157 uLast = pParent->uLastChild;
8158 uFirst = pParent->uFirstChild;
8159 if(uFirst == 0)
8160 return 1;
8161 if(uFirst == uLast) { // Einzelner Eintrag
8162 pNext = pList[uFirst];
8163 if(!pNext->uFirstChild)
8164 return 1;
8165
8166 sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst;
8167 sSort.lParam = pSortData->lParam;
8168 sSort.lpfnCompare = pSortData->lpfnCompare;
8170 return 1;
8171 }
8172 }
8173
8174 if(iMode) { // Sortiere die Untereinträge
8175 pNext = pList[uFirst];
8176 sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst;
8177 sSort.lParam = pSortData->lParam;
8178 sSort.lpfnCompare = pSortData->lpfnCompare;
8179
8180 while(pNext) {
8181 if(pNext->uFirstChild) {
8183 }
8184
8185 sSort.hParent = (HTREEITEM)(ULONG_PTR)pNext->uNextItem;
8186 pNext = pList[pNext->uNextItem];
8187 }
8188 }
8189
8190 if(uFirst == uLast)
8191 return 1;
8192
8193//******************** Erzeuge Eintragsliste **********************************
8194 uItem = uFirst;
8195 pItemList = uEnties;
8196 uMax = 128;
8197 uPos = 0;
8198
8199 do { // Alle Kindeinträge suchen
8200 if(uPos >= uMax) {
8201 uMax *= 2;
8202 pItemNew = new(unsigned, uMax);
8203 memcpy(pItemNew, pItemList, uPos * sizeof(pItemList[0]));
8204 if(uPos > 128)
8205 delete(pItemList);
8206 pItemList = pItemNew;
8207 }
8208
8209 pItemList[uPos] = uItem;
8210 pNext = pList[uItem];
8211 uItem = pNext->uNextItem;
8212 uPos++;
8213 } while(uItem);
8214
8215
8216//************************* Qsort-Algorithmus *********************************
8217#define XCHANGE_MEM(a,b) uTemp=pItemList[a];pItemList[a]=pItemList[b];pItemList[b]=uTemp;
8218
8219 pData->cLockChanges = 1;
8220 UNLOCK(pData);
8221
8222 hTreeWnd = pData->hWnd;
8223 pCompare = pSortData->lpfnCompare;
8224 lParamSort = pSortData->lParam;
8225 iLast = uPos - 1;
8226 iStart = 0;
8227 iLevel = 0;
8228
8229 for(;;) {
8230 iLower = iStart;
8231 iMiddle = (iStart + iLast) >> 1; // Mitte bereichnen
8232 iUpper = iLast + 1;
8233
8234 XCHANGE_MEM(iMiddle, iLower);
8235
8236 uItem = pItemList[iStart];
8237 hItemTemp = (HTREEITEM)(ULONG_PTR)uItem;
8238 lParamTemp = pList[uItem]->lParam;
8239
8240 for(;;) {
8241 do {
8242 iLower++;
8243 if(iLower > iLast)
8244 break;
8245 uItem = pItemList[iLower];
8246 iCmp = pCompare(hTreeWnd, (HTREEITEM)(ULONG_PTR)uItem, hItemTemp, pList[uItem]->lParam, lParamTemp, lParamSort);
8247 } while(iCmp <= 0);
8248
8249 do {
8250 iUpper--;
8251 if(iUpper <= iStart)
8252 break;
8253 uItem = pItemList[iUpper];
8254 iCmp = pCompare(hTreeWnd, (HTREEITEM)(ULONG_PTR)uItem, hItemTemp, pList[uItem]->lParam, lParamTemp, lParamSort);
8255 } while(iCmp >= 0);
8256
8257 if(iUpper < iLower)
8258 break;
8259
8260 XCHANGE_MEM(iUpper, iLower);
8261 }
8262
8263 XCHANGE_MEM(iStart, iUpper);
8264
8265 if(iUpper - 1 - iStart >= iLast - iLower) {
8266 if(iStart + 1 < iUpper) {
8267 uMemL[iLevel] = iStart;
8268 uMemU[iLevel] = iUpper - 1;
8269 iLevel++;
8270 }
8271 if(iLower < iLast) {
8272 iStart = iLower;
8273 continue;
8274 }
8275 } else {
8276 if(iLower < iLast) {
8277 uMemL[iLevel] = iLower;
8278 uMemU[iLevel] = iLast;
8279 iLevel++;
8280 }
8281
8282 if(iStart + 1 < iUpper) {
8283 iLast = iUpper - 1;
8284 continue;
8285 }
8286 }
8287 // Eine Ebene absteigen
8288 iLevel--;
8289
8290 if(iLevel >= 0) { // Noch Ebenen vorhanden
8291 iStart = uMemL[iLevel];
8292 iLast = uMemU[iLevel];
8293 continue;
8294 }
8295
8296 break;
8297 }
8298
8299 LOCK(pData);
8300 pData->cLockChanges = 0;
8301
8302//******************** Einträge neu einsortirenen *****************************
8303 uPos--;
8304
8305 pEntry = pList[uParent];
8306 if(!pEntry) {
8307 pData->uFirstChild = pItemList[ 0 ];
8308 pData->uLastChild = pItemList[uPos];
8309 } else {
8310 pEntry->uFirstChild = pItemList[ 0 ];
8311 pEntry->uLastChild = pItemList[uPos];
8312 }
8313
8314 uLast = 0;
8315 uItem = pItemList[0];
8316
8317 for(uNum = 0; uNum < uPos;) { // Kinder neu einhängen
8318 pEntry = pList[uItem];
8319 pEntry->uPrevItem = uLast;
8320
8321 uNum++;
8322 uLast = uItem;
8323 uItem = pItemList[uNum];
8324
8325 pEntry->uNextItem = uItem;
8326 }
8327
8328 pEntry = pList[uItem];
8329 pEntry->uPrevItem = uLast;
8330 pEntry->uNextItem = 0;
8331
8332 if(iMode != SORT_NOUPDATE) // Ausgabeliste neuerstellen
8333 if(uParent == 0 || (pParent->uShowPos && (pParent->uState & TVIS_EXPANDED))) {
8334 UpdateItems(pData, uParent);
8335
8336 if(pData->uStyle & TVS_SHOWSELALWAYS)
8337 if(pData->uSelectedItem) {
8338 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
8339 }
8340 }
8341
8342 if(uMax > 128)
8343 delete(pItemList);
8344
8345 return 1;
8346}
8347
8348//*****************************************************************************
8349//*
8350//* TreeListSortItemsCb
8351//*
8352//*****************************************************************************
8353// Sortiert die Kindereinträge eines Eintrages mitteles einer Funktion
8354// pData : Zeiger auf die Fensterdaten
8355// pSortData : Ist ein Zeiger auf die Sortiertaten
8356// iMode : 1=Rekursiv sortieren
8357// Ergibt 1 wenn ok sonst 0
8359
8360 TV_SORTCB sSort;
8361 unsigned uNum;
8362 unsigned uItem;
8363 unsigned uLast;
8364 unsigned uFirst;
8365 unsigned uParent;
8368 BaseItem *pNext;
8369 BaseItem **pList;
8370
8371 unsigned *pItemList;
8372 unsigned *pItemNew;
8373 unsigned uEnties[128];
8374 unsigned uPos;
8375 unsigned uMax;
8376
8377 PFNTVCOMPARE pCompare;
8378 LPARAM lParamTemp;
8379 LPARAM lParamSort;
8380 int iLower, iUpper, iMiddle, iCmp;
8381 int uMemL[30], uMemU[30];
8382 int iStart, iLast;
8383 int iLevel;
8384 unsigned uTemp;
8385
8386 pList = pData->pTreeItems;
8387
8388 uParent = U(pSortData->hParent);
8389 if(uParent > pData->uTreeItemsMax) { // Root-Eintrag sortieren
8390 if(uParent != U(TVI_ROOT))
8391 return 0;
8392
8393 uLast = pData->uLastChild;
8394 uFirst = pData->uFirstChild;
8395 if(uFirst == 0)
8396 return 1;
8397 if(uFirst == uLast) { // Einzelner Eintrag
8398 pNext = pList[uFirst];
8399 if(!pNext->uFirstChild)
8400 return 1;
8401
8402 sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst;
8403 sSort.lParam = pSortData->lParam;
8404 sSort.lpfnCompare = pSortData->lpfnCompare;
8406 return 1;
8407 }
8408
8409 pParent = 0;
8410 uParent = 0;
8411 } else { // Untereintrag sortieren
8412 pParent = pList[uParent];
8413 if(pParent == NULL)
8414 return 0;
8415
8416 uLast = pData->uLastChild;
8417 uFirst = pParent->uFirstChild;
8418 if(uFirst == 0)
8419 return 1;
8420 if(uFirst == uLast) { // Einzelner Eintrag
8421 pNext = pList[uFirst];
8422 if(!pNext->uFirstChild)
8423 return 1;
8424
8425 sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst;
8426 sSort.lParam = pSortData->lParam;
8427 sSort.lpfnCompare = pSortData->lpfnCompare;
8429 return 1;
8430 }
8431 }
8432
8433 if(iMode) { // Sortiere die Untereinträge
8434 pNext = pList[uFirst];
8435 sSort.hParent = (HTREEITEM)(ULONG_PTR)uFirst;
8436 sSort.lParam = pSortData->lParam;
8437 sSort.lpfnCompare = pSortData->lpfnCompare;
8438
8439 while(pNext) {
8440 if(pNext->uFirstChild) {
8442 }
8443
8444 sSort.hParent = (HTREEITEM)(ULONG_PTR)pNext->uNextItem;
8445 pNext = pList[pNext->uNextItem];
8446 }
8447 }
8448
8449 if(uFirst == uLast)
8450 return 1;
8451
8452//******************** Erzeuge Eintragsliste **********************************
8453 uItem = uFirst;
8454 pItemList = uEnties;
8455 uMax = 128;
8456 uPos = 0;
8457
8458 do { // Alle Kindeinträge suchen
8459 if(uPos >= uMax) {
8460 uMax *= 2;
8461 pItemNew = new(unsigned, uMax);
8462 memcpy(pItemNew, pItemList, uPos * sizeof(pItemList[0]));
8463 if(uPos > 128)
8464 delete(pItemList);
8465 pItemList = pItemNew;
8466 }
8467
8468 pItemList[uPos] = uItem;
8469 pNext = pList[uItem];
8470 uItem = pNext->uNextItem;
8471 uPos++;
8472 } while(uItem);
8473
8474//************************* Qsort-Algorithmus *********************************
8475#define XCHANGE_MEM(a,b) uTemp=pItemList[a];pItemList[a]=pItemList[b];pItemList[b]=uTemp;
8476
8477 pData->cLockChanges = 1;
8478 UNLOCK(pData);
8479
8480 pCompare = pSortData->lpfnCompare;
8481 lParamSort = pSortData->lParam;
8482 iLast = uPos - 1;
8483 iStart = 0;
8484 iLevel = 0;
8485
8486 for(;;) {
8487 iLower = iStart;
8488 iMiddle = (iStart + iLast) >> 1; // Mitte bereichnen
8489 iUpper = iLast + 1;
8490
8491 XCHANGE_MEM(iMiddle, iLower);
8492
8493 uItem = pItemList[iStart];
8494 lParamTemp = pList[uItem]->lParam;
8495
8496 for(;;) {
8497 do {
8498 iLower++;
8499 if(iLower > iLast)
8500 break;
8501 uItem = pItemList[iLower];
8502 iCmp = pCompare(pList[uItem]->lParam, lParamTemp, lParamSort);
8503 } while(iCmp <= 0);
8504
8505 do {
8506 iUpper--;
8507 if(iUpper <= iStart)
8508 break;
8509 uItem = pItemList[iUpper];
8510 iCmp = pCompare(pList[uItem]->lParam, lParamTemp, lParamSort);
8511 } while(iCmp >= 0);
8512
8513 if(iUpper < iLower)
8514 break;
8515
8516 XCHANGE_MEM(iUpper, iLower);
8517 }
8518
8519 XCHANGE_MEM(iStart, iUpper);
8520
8521 if(iUpper - 1 - iStart >= iLast - iLower) {
8522 if(iStart + 1 < iUpper) {
8523 uMemL[iLevel] = iStart;
8524 uMemU[iLevel] = iUpper - 1;
8525 iLevel++;
8526 }
8527 if(iLower < iLast) {
8528 iStart = iLower;
8529 continue;
8530 }
8531 } else {
8532 if(iLower < iLast) {
8533 uMemL[iLevel] = iLower;
8534 uMemU[iLevel] = iLast;
8535 iLevel++;
8536 }
8537
8538 if(iStart + 1 < iUpper) {
8539 iLast = iUpper - 1;
8540 continue;
8541 }
8542 }
8543 // Eine Ebene absteigen
8544 iLevel--;
8545
8546 if(iLevel >= 0) { // Noch Ebenen vorhanden
8547 iStart = uMemL[iLevel];
8548 iLast = uMemU[iLevel];
8549 continue;
8550 }
8551
8552 break;
8553 }
8554
8555 LOCK(pData);
8556 pData->cLockChanges = 0;
8557
8558//******************** Einträge neu einsortirenen *****************************
8559 uPos--;
8560
8561 pEntry = pList[uParent];
8562 if(!pEntry) {
8563 pData->uFirstChild = pItemList[ 0 ];
8564 pData->uLastChild = pItemList[uPos];
8565 } else {
8566 pEntry->uFirstChild = pItemList[ 0 ];
8567 pEntry->uLastChild = pItemList[uPos];
8568 }
8569
8570 uLast = 0;
8571 uItem = pItemList[0];
8572
8573 for(uNum = 0; uNum < uPos;) { // Kinder neu einhängen
8574 pEntry = pList[uItem];
8575 pEntry->uPrevItem = uLast;
8576
8577 uNum++;
8578 uLast = uItem;
8579 uItem = pItemList[uNum];
8580
8581 pEntry->uNextItem = uItem;
8582 }
8583
8584 pEntry = pList[uItem];
8585 pEntry->uPrevItem = uLast;
8586 pEntry->uNextItem = 0;
8587
8588 if(iMode != SORT_NOUPDATE) // Ausgabeliste neuerstellen
8589 if(uParent == 0 || (pParent->uShowPos && (pParent->uState & TVIS_EXPANDED))) {
8590 UpdateItems(pData, uParent);
8591
8592 if(pData->uStyle & TVS_SHOWSELALWAYS)
8593 if(pData->uSelectedItem) {
8594 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
8595 }
8596 }
8597
8598 if(uMax > 128)
8599 delete(pItemList);
8600
8601 return 1;
8602}
8603
8604//*****************************************************************************
8605//*
8606//* TreeListSortItems
8607//*
8608//*****************************************************************************
8609// Sortiert die Kindereinträge eines Eintrages via Text
8610// pData : Zeiger auf die Fensterdaten
8611// pSortData : Ist ein Zeiger auf die Sortiertaten
8612// iMode : 1=Rekursiv sortieren
8613// Ergibt 1 wenn ok sonst 0
8614static int TreeListSortItems(TreeListData *pData, unsigned uParent, int iMode) {
8615
8616 unsigned uNum;
8617 unsigned uItem;
8618 unsigned uLast;
8619 unsigned uFirst;
8622 BaseItem *pNext;
8623 BaseItem **pList;
8624
8625 unsigned *pItemList;
8626 unsigned *pItemNew;
8627 unsigned uEnties[128];
8628 unsigned uPos;
8629 unsigned uMax;
8630
8631 LPCTSTR pTextTemp;
8632 LPCTSTR pText;
8633 int iLower, iUpper, iMiddle, iCmp;
8634 int uMemL[30], uMemU[30];
8635 int iStart, iLast;
8636 int iLevel;
8637 int iNone;
8638 unsigned uSize;
8639 unsigned uTemp;
8640
8641 pList = pData->pTreeItems;
8642
8643 if(uParent > pData->uTreeItemsMax) { // Root-Eintrag sortieren
8644 if(uParent != U(TVI_ROOT))
8645 return 0;
8646
8647 uLast = pData->uLastChild;
8648 uFirst = pData->uFirstChild;
8649 if(uFirst == 0)
8650 return 1;
8651 if(uFirst == pData->uLastChild) { // Einzelner Eintrag
8652 pNext = pList[uFirst];
8653 if(!pNext->uFirstChild)
8654 return 1;
8655
8656 TreeListSortItems(pData, uFirst, iMode);
8657 return 1;
8658 }
8659
8660 pList = pData->pTreeItems;
8661 pParent = 0;
8662 uParent = 0;
8663 } else { // Untereintrag sortieren
8664 pParent = pList[uParent];
8665 if(pParent == NULL)
8666 return 0;
8667
8668 uLast = pParent->uLastChild;
8669 uFirst = pParent->uFirstChild;
8670 if(uFirst == 0)
8671 return 1;
8672 if(uFirst == pParent->uLastChild) { // Einzelner Eintrag
8673 pNext = pList[uFirst];
8674 if(!pNext->uFirstChild)
8675 return 1;
8676
8677 TreeListSortItems(pData, uFirst, iMode);
8678 return 1;
8679 }
8680 }
8681
8682 if(iMode) { // Sortiere die Untereinträge
8683 uItem = uFirst;
8684
8685 while(uItem) {
8686 pNext = pList[uItem];
8687 if(pNext->uFirstChild) {
8689 }
8690
8691 uItem = pNext->uNextItem;
8692 }
8693 }
8694
8695 if(uLast == uFirst)
8696 return 1;
8697
8698//******************** Erzeuge Eintragsliste **********************************
8699 uItem = uFirst;
8700 pItemList = uEnties;
8701 uMax = 128;
8702 uPos = 0;
8703
8704 do { // Alle Kindeinträge suchen
8705 if(uPos >= uMax) {
8706 uMax *= 2;
8707 pItemNew = new(unsigned, uMax);
8708 memcpy(pItemNew, pItemList, uPos * sizeof(pItemList[0]));
8709 if(uPos > 128)
8710 delete(pItemList);
8711 pItemList = pItemNew;
8712 }
8713
8714 pItemList[uPos] = uItem;
8715 pNext = pList[uItem];
8716 uItem = pNext->uNextItem;
8717 uPos++;
8718 } while(uItem);
8719
8720//************************* Qsort-Algorithmus *********************************
8721#define XCHANGE_MEM(a,b) uTemp=pItemList[a];pItemList[a]=pItemList[b];pItemList[b]=uTemp;
8722
8723 pData->cLockChanges = 1;
8724 UNLOCK(pData);
8725
8726 iLast = uPos - 1;
8727 iStart = 0;
8728 iLevel = 0;
8729
8730 for(;;) {
8731 iLower = iStart;
8732 iMiddle = (iStart + iLast) >> 1; // Mitte bereichnen
8733 iUpper = iLast + 1;
8734
8735 XCHANGE_MEM(iMiddle, iLower);
8736
8737 uItem = pItemList[iStart];
8738 pEntry = pList[uItem];
8739 if(pEntry->bCallback & TVIF_TEXT) {
8740 uSize = 0;
8741 LOCK(pData);
8742 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pTextTemp);
8743 UNLOCK(pData);
8744 } else {
8745 pTextTemp = pEntry->pText;
8746 }
8747
8748 for(;;) {
8749 do {
8750 iLower++;
8751 if(iLower > iLast)
8752 break;
8753
8754 uItem = pItemList[iLower];
8755 pEntry = pList[uItem];
8756 if(pEntry->bCallback & TVIF_TEXT) {
8757 uSize = 1;
8758 LOCK(pData);
8759 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pText);
8760 UNLOCK(pData);
8761 } else {
8762 pText = pEntry->pText;
8763 }
8764
8765 iCmp = str_icmp(pText, pTextTemp);
8766 } while(iCmp <= 0);
8767
8768 do {
8769 iUpper--;
8770
8771 if(iUpper <= iStart)
8772 break;
8773 uItem = pItemList[iUpper];
8774 pEntry = pList[uItem];
8775 if(pEntry->bCallback & TVIF_TEXT) {
8776 LOCK(pData);
8777 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pText);
8778 UNLOCK(pData);
8779 } else {
8780 pText = pEntry->pText;
8781 }
8782
8783 iCmp = str_icmp(pText, pTextTemp);
8784 } while(iCmp >= 0);
8785
8786 if(iUpper < iLower)
8787 break;
8788
8789 XCHANGE_MEM(iUpper, iLower);
8790 }
8791
8792 XCHANGE_MEM(iStart, iUpper);
8793
8794 if(iUpper - 1 - iStart >= iLast - iLower) {
8795 if(iStart + 1 < iUpper) {
8796 uMemL[iLevel] = iStart;
8797 uMemU[iLevel] = iUpper - 1;
8798 iLevel++;
8799 }
8800 if(iLower < iLast) {
8801 iStart = iLower;
8802 continue;
8803 }
8804 } else {
8805 if(iLower < iLast) {
8806 uMemL[iLevel] = iLower;
8807 uMemU[iLevel] = iLast;
8808 iLevel++;
8809 }
8810
8811 if(iStart + 1 < iUpper) {
8812 iLast = iUpper - 1;
8813 continue;
8814 }
8815 }
8816 // Eine Ebene absteigen
8817 iLevel--;
8818
8819 if(iLevel >= 0) { // Noch Ebenen vorhanden
8820 iStart = uMemL[iLevel];
8821 iLast = uMemU[iLevel];
8822 continue;
8823 }
8824
8825 break;
8826 }
8827
8828 LOCK(pData);
8829 pData->cLockChanges = 0;
8830
8831//******************** Einträge neu einsortirenen *****************************
8832 uPos--;
8833
8834 pEntry = pList[uParent];
8835 if(!pEntry) {
8836 pData->uFirstChild = pItemList[ 0 ];
8837 pData->uLastChild = pItemList[uPos];
8838 } else {
8839 pEntry->uFirstChild = pItemList[ 0 ];
8840 pEntry->uLastChild = pItemList[uPos];
8841 }
8842
8843 uLast = 0;
8844 uItem = pItemList[0];
8845
8846 for(uNum = 0; uNum < uPos;) { // Kinder neu einhängen
8847 pEntry = pList[uItem];
8848 pEntry->uPrevItem = uLast;
8849
8850 uNum++;
8851 uLast = uItem;
8852 uItem = pItemList[uNum];
8853
8854 pEntry->uNextItem = uItem;
8855 }
8856
8857 pEntry = pList[uItem];
8858 pEntry->uPrevItem = uLast;
8859 pEntry->uNextItem = 0;
8860
8861 if(iMode != SORT_NOUPDATE) // Ausgabeliste neuerstellen
8862 if(uParent == 0 || (pParent->uShowPos && (pParent->uState & TVIS_EXPANDED))) {
8863 UpdateItems(pData, uParent);
8864
8865 if(pData->uStyle & TVS_SHOWSELALWAYS)
8866 if(pData->uSelectedItem) {
8867 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
8868 }
8869 }
8870
8871 if(uMax > 128)
8872 delete(pItemList);
8873
8874 return 1;
8875}
8876
8877//*****************************************************************************
8878//*
8879//* TreeListEndLabelEdit
8880//*
8881//*****************************************************************************
8882// Beendet das editiert eines Eintrages
8883// pData : Zeiger auf Fensterdaten
8884// iMode : Gibt an wie das Editieren beendet wurde
8885// 0 = Es gab es einen Abbruch mit ESC
8886// 1 = Eingabe ohne Enter
8887// 2 = Eingabe mit Enter
8888// Ergibt das Handle des Edit-Controlls oder NULL bei einem Fehler
8890 TCHAR cText[2052];
8891 NMTVDISPINFO sNotify;
8892 TV_ITEM sSet;
8893 LRESULT lRet;
8894 unsigned uSub;
8895 unsigned uItem;
8896 ExtraItem *pExtra;
8898 LPCTSTR *pList;
8899 LPCTSTR pText;
8900 LPTSTR pGetT;
8901 TCHAR cChar;
8902 int iAuto;
8903 int iIcon;
8904 int iLine;
8905 int iPos;
8906 int iLen;
8907 int iMax;
8908 int iSel;
8909 char cCb;
8910
8911 uItem = pData->uEditItem;
8912 uSub = pData->uEditSub;
8913 cCb = pData->cEditCb;
8914
8915 pData->uEditItem = 0;
8916 pData->uEditSub = 0;
8917 pData->cEditCb = 0;
8918
8919 if(uItem > pData->uTreeItemsMax || uSub >= pData->uColumnCount) {
8920 return 0;
8921 }
8922
8923 pEntry = pData->pTreeItems[uItem];
8924 if(!pEntry) {
8925 return 0;
8926 }
8927
8928 if(iMode) { // Eingabe
8929 GetWindowText(pData->hEdit, cText, sizeof(cText) / sizeof(cText[0]));
8930 cText[sizeof(cText) / sizeof(cText[0]) - 1] = 0;
8931 sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT | TVIF_SUBITEM;
8932 sNotify.item.cchTextMax = sizeof(cText) / sizeof(cText[0]) - 1;
8933 sNotify.item.pszText = cText;
8934
8935 if(pData->cColumnStart) { // Wurde ein Text eingegeben
8936 sNotify.item.mask |= TVIF_TEXTCHANGED;
8937 }
8938
8939 if(iMode == 2) { // Wurde der Text mit RETURN eingegeben
8940 sNotify.item.mask |= TVIF_RETURNEXIT;
8941 }
8942 } else { // Abbruch
8943 sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_CANCELED | TVIF_SUBITEM;
8944 sNotify.item.pszText = NULL;
8945 sNotify.item.cchTextMax = 0;
8946 }
8947
8948 sNotify.hdr.code = TVN_ENDLABELEDIT;
8949 sNotify.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
8950 sNotify.item.stateMask = 0xFFFFFFFF;
8951 sNotify.item.cChildren = uSub;
8952
8953 if(uSub) { // Wurde der Text in einer Sub-Spalte geändert
8954 pExtra = pData->pExtraItems[uSub - 1][uItem];
8955 if(!pExtra) {
8956 sNotify.item.state = 0;
8957 sNotify.item.lParam = 0;
8958 } else {
8959 sNotify.item.state = pEntry->uState & TVIS_BASEFLAGS;
8960 sNotify.item.state |= pExtra->uState;
8961 sNotify.item.lParam = pEntry->lParam;
8962 }
8963 } else {
8964 sNotify.item.state = pEntry->uState;
8965 sNotify.item.lParam = pEntry->lParam;
8966 }
8967
8968 UNLOCK(pData);
8969 ShowWindow(pData->hEdit, SW_HIDE);
8970 lRet = SendNotify(pData, &sNotify.hdr);
8971 LOCK(pData);
8972
8973 if(lRet || !iMode)
8974 return 0;
8975
8976 if(cCb) { // Callback aufrufen
8977 sNotify.hdr.code = TVN_SETDISPINFO;
8978 sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT | TVIF_SUBITEM;
8979 sNotify.item.stateMask = (UINT)~TVIS_BASEFLAGS;
8980 sNotify.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
8981 sNotify.item.cChildren = uSub;
8982
8983 UNLOCK(pData);
8984 SendNotify(pData, &sNotify.hdr);
8985 LOCK(pData);
8986 } else { // Neuen Text eingeben
8987 pGetT = sNotify.item.pszText;
8988 sSet.mask = TVIF_SUBITEM | TVIF_TEXT;
8989 sSet.cchTextMax = sNotify.item.cchTextMax;
8990 sSet.hItem = (HTREEITEM)(ULONG_PTR)uItem;
8991 sSet.pszText = pGetT;
8992 sSet.cChildren = uSub;
8993
8994 iIcon = pData->aColumn[uSub].iCbIcon;
8995 iAuto = pData->aColumn[uSub].bEdit;
8996
8997 if(iIcon >= 0 && iAuto != TVAX_NONE) { // Auch ein Icon zuweisen
8998 iPos = -1;
8999
9000 if((1 << iAuto) & ((1 << TVAX_CBLIST) | (1 << TVAX_COMBO))) {
9001 iPos = (int)SendMessage(pData->hEdit, CB_GETCURSEL, 0, 0);
9002 sSet.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
9003 sSet.iImage = iIcon + iPos;
9004 sSet.iSelectedImage = sSet.iImage;
9005 }
9006
9007 if(iPos <= -1) {
9008 iMax = pData->aColumn[uSub].bCbSize;
9009 if(iMax <= 0)
9010 iMax = 1024;
9011
9012 iSel = -1;
9013
9014 if(pData->aColumn[uSub].bFlags & TVAE_PTRLIST) { // Zeigerliste char *pTexte[]={"1","2",NULL};
9015 pList = (LPCTSTR *)pData->aColumn[uSub].pCbData;
9016
9017 for(iPos = 0; iPos < iMax; iPos++) {
9018 if(!pList[iPos])
9019 break;
9020 if(!str_cmp(pGetT, pList[iPos]))
9021 iSel = iPos;
9022 }
9023 } else { // Textliste char *pText="1|2|3";
9024 pText = (LPTSTR)pData->aColumn[uSub].pCbData;
9025 cChar = (TCHAR)pData->aColumn[uSub].bCbChar;
9026
9027 for(iPos = 0; iPos < iMax; iPos++) {
9028 for(iLen = 0; pText[iLen]; iLen++) {
9029 if(pText[iLen] == cChar)
9030 break;
9031 }
9032
9033 if(str_ncmp(pGetT, pText, iLen) == 0 && !pGetT[iLen]) {
9034 iSel = iPos;
9035 break;
9036 }
9037
9038 pText += iLen;
9039 if(pText[0] == cChar)
9040 pText++;
9041 if(pText[0] == 0)
9042 break;
9043 }
9044 }
9045
9046 sSet.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
9047 sSet.iImage = iIcon + iSel;
9048 sSet.iSelectedImage = sSet.iImage;
9049 }
9050 }
9051
9052 if(pData->aColumn[uSub].bFlags & TVAE_NEXTLINE && // In die nächste Zeile springen
9053 iMode == 2 && iAuto != TVAX_NONE && iAuto != TVAX_STEP) {
9054 if(!pData->cColumnStart) {
9055 if(uSub) { // Hat sich der Text verändert ?
9056 pExtra = pData->pExtraItems[uSub - 1][uItem];
9057 if(pExtra && pExtra->pText) {
9058 if(!_tcscmp(pGetT, pExtra->pText))
9059 return 1;
9060 } else {
9061 if(!*pGetT)
9062 return 1;
9063 }
9064 } else {
9065 pEntry = pData->pTreeItems[uItem];
9066 if(pEntry && pEntry->pText) {
9067 if(!_tcscmp(pGetT, pEntry->pText))
9068 return 1;
9069 } else {
9070 if(!*pGetT)
9071 return 1;
9072 }
9073 }
9074 }
9075
9076 TreeListSetItem(pData, &sSet);
9077
9078 iLine = pEntry->uShowPos;
9079 if(iLine < (int)pData->uItemPosCount) {
9080 uItem = pData->pItemPos[iLine];
9081 TreeListSelectItem(pData, uItem, pData->uSelectedSub, TVC_BYKEYBOARD | TVC_DESELECT);
9082 }
9083 } else {
9084 TreeListSetItem(pData, &sSet);
9085 }
9086 }
9087
9088 return 1;
9089}
9090
9091//*****************************************************************************
9092//*
9093//* TreeListEditLabel
9094//*
9095//*****************************************************************************
9096// Startet das editiert eines Eintrages
9097// pData : Zeiger auf Fensterdaten
9098// uItem : Item das editiert werden soll
9099// uSub : Spalte die editiert werden soll und andere Flags
9100// TVIR_EDITCOL(n) = Spalte angeben
9101// TVIR_SELAREA(a,b) = Einen Textbereich auswählen
9102// TVIR_SETCURSOR(n) = Den Cursor auf eine bestimmte Textstelle
9103// TVIR_SETAT(n) = Den Cursor auf eine bestimmte Pixelstelle
9104// TVIR_SELALL = Den gesammten Text wählen
9105// TVIR_EDITCOMBOLIST = Statt dem Edit-Fenster eine ComboBox nur mit Listenauswahl einblenden
9106// TVIR_EDITFULL = Das Edit-Fenster über die volle Breite einblenden
9107// TVIR_EDITCOMBOBOX = Statt dem Edit-Fenster eine ComboBox einblenden
9108// Ergibt das Handle des Edit-Controlls oder NULL bei einem Fehler
9109static HWND TreeListEditLabel(TreeListData *pData, unsigned uItem, unsigned uSub) {
9110
9111 HDC hDc;
9112 HWND hWnd;
9113 LRESULT lRet;
9114 WNDPROC pProc;
9115 char cTemp;
9116 LPARAM lParam;
9117 ExtraItem *pExtra;
9119 NMTVDISPINFO sNotify;
9120 LPCTSTR pText;
9121 RECT sRect;
9122 SIZE sSize;
9123 HFONT hFont;
9124 unsigned uCol;
9125 unsigned uSel;
9126 unsigned uNext;
9127 unsigned uBits;
9128 unsigned uSize;
9129 unsigned uStart;
9130 unsigned uState;
9131 unsigned uFlags;
9132 unsigned uHeight;
9133 int iPixels;
9134 int iWidth;
9135 int iTemp;
9136
9137 uBits = uSub >> 29;
9138 uSel = (uSub >> 8) & 0x0FFFFF;
9139 uSub &= 0xFF;
9140
9141 if(uSub >= pData->uColumnCount)
9142 return NULL;
9143 if(uItem > pData->uTreeItemsMax)
9144 return NULL;
9145 pEntry = pData->pTreeItems[uItem];
9146 if(!pEntry)
9147 return NULL;
9148
9149 if(uItem != pData->uSelectedItem || uSub != pData->uSelectedSub) {
9150 uCol = (pData->uStyleEx & TVS_EX_SUBSELECT) ? uSub : 0;
9151 iTemp = TreeListSelectItem(pData, uItem, uCol, TVC_UNKNOWN);
9152 }
9153
9154 TreeListEnsureVisible(pData, uItem, uSub);
9155
9156 if(pData->hEdit) { // Editfenster löschen
9157 DestroyWindow(pData->hEdit);
9158 pData->hEdit = 0;
9159 }
9160
9161 switch(uBits & 3) { // Editfenster neu erzeugen
9162 case 1:
9163 pData->hEdit = CreateWindow(_T("COMBOBOX"), NULL, WS_BORDER | WS_CHILD | CBS_AUTOHSCROLL | CBS_DROPDOWN | WS_VSCROLL, 0, 0, 0, 0, pData->hWnd, (HMENU)3, NULL, NULL);
9164 pData->uEditMode = 1;
9165 SendMessage(pData->hEdit, CB_LIMITTEXT, 2048, 0);
9166 break;
9167
9168 case 2:
9169 pData->hEdit = CreateWindow(_T("COMBOBOX"), NULL, WS_BORDER | WS_CHILD | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST | WS_VSCROLL, 0, 0, 0, 0, pData->hWnd, (HMENU)3, NULL, NULL);
9170 pData->uEditMode = 2;
9171 SendMessage(pData->hEdit, CB_LIMITTEXT, 2048, 0);
9172 break;
9173
9174 default
9175 :
9176 uFlags = ES_LEFT;
9177
9178 if(uBits & 4) {
9179 if(pData->aColumn[uSub].bAlign == DT_RIGHT)
9180 uFlags = ES_RIGHT;
9181 if(pData->aColumn[uSub].bAlign == DT_CENTER)
9182 uFlags = ES_CENTER;
9183 }
9184
9185 pData->hEdit = CreateWindow(_T("EDIT"), NULL, WS_BORDER | WS_CHILD | ES_AUTOHSCROLL | uFlags, 0, 0, 0, 0, pData->hWnd, (HMENU)3, NULL, NULL);
9186 pData->uEditMode = 0;
9187 SendMessage(pData->hEdit, EM_SETLIMITTEXT, 2048, 0);
9188 break;
9189 }
9190
9191 if(!pData->hEdit)
9192 return NULL;
9193
9194 if(pSetWindowTheme) { // Remove the Visual-Styles (XP+)
9195 pSetWindowTheme(pData->hEdit, L"", L"");
9196 }
9197
9198 pData->pProcId3 = (WNDPROC)GetWindowLongPtr(pData->hEdit, GWLP_WNDPROC);
9201
9202 hWnd = GetWindow(pData->hEdit, GW_CHILD);
9203
9204 while(hWnd) {
9209 }
9210
9211 pData->cEditCb = 0;
9212
9213 if(pData->uEditMode >= 1) { // ComboBox leeren
9214 SendMessage(pData->hEdit, CB_RESETCONTENT, 0, 0);
9215 }
9216
9217 if(uSub == 0) { // Haupteintrag bearbeiten
9219
9220 pText = pEntry->pText;
9221 uSize = pEntry->uTextSize;
9222 iPixels = pEntry->iTextPixels + 10;
9223 lParam = pEntry->lParam;
9224 uState = pEntry->uState;
9225 hFont = (uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
9226
9227 if(pEntry->bCallback & TVIF_TEXT) {
9228 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iTemp, &uSize, &pText);
9229 hDc = GetDC(pData->hWnd);
9230 SelectObject(hDc, hFont);
9232 ReleaseDC(pData->hWnd, hDc);
9233 iPixels = sRect.right - sRect.left + 10;
9234 pData->cEditCb = 1;
9235 }
9236
9237 if(uBits & 4) { // Volle Spaltenbreite
9238 if(pEntry->iImage != TV_NOIMAGE) {
9239 uNext = pData->aColumnPos[1];
9240 sRect.right = pData->aColumnXpos[uNext];
9241 sRect.right -= pData->uScrollX;
9242 }
9243
9244 iPixels = sRect.right - sRect.left - 2;
9245 } else {
9246 if(pData->uEditMode) {
9247 if(iPixels < 60)
9248 iPixels = 60;
9249 } else {
9250 if(iPixels < 48)
9251 iPixels = 48;
9252 }
9253
9254 if(pText && *pText) {
9255 iPixels += str_len(pText);
9256 }
9257
9258 if(pData->uEditMode) {
9259 iPixels += GetSystemMetrics(SM_CXHSCROLL);
9260 }
9261 }
9262 } else { // Extraeintrag bearbeiten
9263 if(uBits & 4) {
9264 TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_COLTOSUB(uSub), &sRect);
9265
9266 if(pData->aColumn[uSub].bEdit >= TVAX_CHECK) {
9267 sRect.left += pData->iChecksXsize;
9268 if(sRect.right < sRect.left)
9269 sRect.right = sRect.left + 1;
9270 }
9271 } else {
9273 }
9274
9275 pExtra = pData->pExtraItems[uSub - 1][uItem];
9276 if(!pExtra) {
9277 pData->cTempText1[0] = 0;
9278 pText = pData->cTempText1;
9279 uSize = sizeof(pData->cTempText1) / sizeof(pData->cTempText1[0]);
9280 iPixels = sRect.right - sRect.left + 10;
9281 hFont = pData->hFontN;
9282 uState = pEntry->uState & TVIS_BASEFLAGS;
9283 lParam = 0;
9284 } else {
9285 pText = pExtra->pText;
9286 uSize = pExtra->uTextSize;
9287 iPixels = pExtra->iTextPixels + 10;
9288 lParam = pEntry->lParam;
9289 uState = pExtra->uState;
9290 uState |= pEntry->uState & TVIS_BASEFLAGS;
9291 hFont = (uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
9292
9293 if(pExtra->bCallback & TVIF_TEXT) {
9294 CallbackExtra(pData, pEntry, pExtra, uItem, uSub, TVIF_TEXT, &iTemp, &uSize, &pText);
9295 hDc = GetDC(pData->hWnd);
9296 SelectObject(hDc, hFont);
9298 ReleaseDC(pData->hWnd, hDc);
9299 iPixels = sRect.right - sRect.left;
9300 pData->cEditCb = 1;
9301 }
9302 }
9303
9304 if(uBits & 4) { // Volle Spaltenbreite
9305 if(pExtra && pExtra->iImage != TV_NOIMAGE) {
9306 sRect.left += pData->iImagesXsize + 1;
9307 }
9308
9309 iPixels = sRect.right - sRect.left - 2;
9310 } else {
9311 if(pData->uEditMode) {
9312 if(iPixels < 60)
9313 iPixels = 60;
9314 } else {
9315 if(iPixels < 48)
9316 iPixels = 48;
9317 }
9318
9319 if(pText && *pText) {
9320 iPixels += str_len(pText);
9321 }
9322
9323 if(pData->uEditMode) {
9324 iPixels += GetSystemMetrics(SM_CXHSCROLL);
9325 }
9326
9327 switch(pData->aColumn[uSub].bAlign) {
9328 case DT_RIGHT:
9329 iWidth = sRect.right - sRect.left;
9330 sRect.left += iWidth - iPixels;
9331 break;
9332
9333 case DT_CENTER:
9334 iWidth = sRect.right - sRect.left;
9335 sRect.left += (iWidth - iPixels) / 2;
9336 break;
9337 }
9338 }
9339 }
9340
9341 UNLOCK(pData);
9342
9343 sNotify.hdr.code = TVN_BEGINLABELEDIT;
9344 sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT | TVIF_SUBITEM;
9345 sNotify.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
9346 sNotify.item.pszText = (LPTSTR)pText;
9347 sNotify.item.lParam = lParam;
9348 sNotify.item.state = uState;
9349 sNotify.item.cchTextMax = uSize;
9350 sNotify.item.stateMask = 0xFFFFFFFF;
9351 sNotify.item.cChildren = uSub;
9352
9353 lRet = SendNotify(pData, &sNotify.hdr);
9354
9355 LOCK(pData);
9356
9357 if(lRet) { // Das Editieren abbrechen
9359 return NULL;
9360 }
9361
9362 pEntry = pData->pTreeItems[uItem];
9363 if(!pEntry)
9364 return NULL;
9365
9366 if(pData->uToolTipItem) { // Ein offenes Tooltip verstecken
9367 UpdateToolTip(pData, 0, 0);
9368 }
9369
9370 UNLOCK(pData);
9371 SetFocus(pData->hEdit);
9372 LOCK(pData);
9373
9374 if(pData->uEditMode) {
9375 sRect.top--;
9376 uHeight = 260;
9377 } else {
9378 uHeight = pData->iFontHeight + 4;
9379 }
9380
9381 if(pData->uEditMode) {
9382 if(iPixels < 60)
9383 iPixels = 60;
9384 } else {
9385 if(iPixels < 48)
9386 iPixels = 48;
9387 }
9388
9389 cTemp = pData->cColumnStart;
9390 SetWindowPos(pData->hEdit, HWND_TOP, sRect.left + 2, sRect.top + 1, iPixels, uHeight, SWP_SHOWWINDOW);
9391 SendMessage(pData->hEdit, WM_SETFONT, (WPARAM)hFont, 0);
9392 SetWindowText(pData->hEdit, pText);
9393 pData->cColumnStart = cTemp;
9394
9395 switch(uSel >> 18) { // Welche Textauswahl
9396 case 3:
9397 uStart = (uSel) & 0x01FF; // Einen Textbereich markieren
9398 uSize = (uSel >> 9) & 0x01FF;
9399 break;
9400
9401 case 2:
9402 uStart = uSel & 0x3FFFF; // Cursor auf eine bestimmte Stelle
9403 uSize = uStart;
9404 break;
9405
9406 case 1:
9407 uSel &= 0x3FFFF;
9408 if(uSel > 4)
9409 uSel -= 4;
9410 hDc = GetDC(pData->hEdit);
9411 SelectObject(hDc, hFont);
9412 GetTextExtentExPoint(hDc, pText, uSize, uSel, &iWidth, NULL, &sSize);
9413
9414 if(uSize > 0 && iWidth < (int)uSize - 1) { // Halben Buchstaben addieren
9415 GetTextExtentExPoint(hDc, pText + iWidth, 1, uSel, NULL, NULL, &sSize);
9416 uSel += sSize.cx / 2;
9417 GetTextExtentExPoint(hDc, pText, uSize, uSel, &iWidth, NULL, &sSize);
9418 }
9419
9420 ReleaseDC(pData->hEdit, hDc);
9421
9422 if(sSize.cx <= (int)uSel) {
9423 uStart = 0;
9424 break;
9425 }
9426
9427 uStart = iWidth;
9428 uSize = iWidth;
9429 break;
9430
9431 default
9432 :
9433 uStart = 0; // Alles markieren
9434 break;
9435 }
9436
9437 switch(pData->uEditMode) {
9438 case 0:
9439 SendMessage(pData->hEdit, EM_SETSEL, uStart, uSize);
9440 break;
9441 case 1:
9442 SendMessage(pData->hEdit, CB_SETEDITSEL, 0, MAKELPARAM(uStart, uSize));
9443 break;
9444 default
9445 :
9446 uStart = 0;
9447 uSize = 0xFFFF;
9448 break;
9449 }
9450
9452
9453 pData->uLastSel = MAKELPARAM(uStart, uSize);
9454 pData->uEditItem = uItem;
9455 pData->uEditSub = uSub;
9456
9457 return pData->hEdit;
9458}
9459
9460
9461//*****************************************************************************
9462//*
9463//* TreeListStartAutoEdit
9464//*
9465//*****************************************************************************
9466// Startet die Editierung für einen Wert via Notyfy-Rückfrage.
9467// pData : Zeiger auf die Fensterdaten
9468// uItem : Ist der Eintrag der Editiert werden soll
9469// uSub : Ist die Nummer der Spalte
9470// wParam : Ist der W-Parameter des Tastendrucks
9471// VK_EDITCLK bei einem Clickauf das ausgewählte Feld
9472// VK_DBLCLK bei einem Doppelclick
9473// VK_RETURN bei einen Enter-Druck
9474// VK_ISACHAR bei WM_CHAR Nachrichten
9475// <char> bei einer Zeicheneingabe
9476// lParam : Ist der L-Parameter des Tastendrucks (bzw. die Koordinaten)
9477// Ergibt 1 das Editieren gestartet wurde, ansonsten 0
9478// 0 wenn der Eintrag nicht gewählt wurde
9479static int TreeListStartNotifyEdit(TreeListData *pData, unsigned uItem, unsigned uSub, WPARAM wParam, LPARAM lParam) {
9480
9481 TCHAR cText[1024];
9482 TV_STARTEDIT sNotify;
9483 ExtraItem *pExtra;
9485 unsigned uBits;
9486 unsigned uCnt;
9487 unsigned uMax;
9488 unsigned uLen;
9489 unsigned uNum;
9490 LPCTSTR pText;
9491 RECT sRect;
9492 TCHAR cChar;
9493 LRESULT lRet;
9494 MSG sMsg;
9495 HWND hWnd;
9496 INT iSel;
9497
9498 if(!(pData->uStyle & TVS_EDITLABELS))
9499 return 0;
9500 if(uItem == 0 || uItem > pData->uTreeItemsMax)
9501 return 0;
9502 if(uSub > 0 && uSub >= pData->uColumnCount)
9503 return 0;
9504
9505 pEntry = pData->pTreeItems[uItem];
9506 if(!pEntry)
9507 return 0;
9508
9509 if(wParam < ' ' && wParam != VK_RETURN) { // Falsche Taste
9510 return 0;
9511 }
9512
9513 if(wParam >= ' ' && wParam <= 0xFFFF) { // Shift und Cltr prüfen
9514 if(GetKeyState(VK_MENU) & 0x8000) {
9515 return 0;
9516 }
9517
9518 if(GetKeyState(VK_CONTROL) & 0x8000) {
9519 return 0;
9520 }
9521 }
9522
9523 sNotify.hdr.code = TVN_STARTEDIT;
9524 sNotify.uAction = (UINT)wParam;
9525 sNotify.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
9526 sNotify.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
9527 sNotify.item.stateMask = 0xFFFFFFFF;
9528 sNotify.item.lParam = pEntry->lParam;
9529 sNotify.item.cChildren = uSub;
9530 sNotify.uHeight = 0;
9531 sNotify.pTextEntries = 0;
9532 sNotify.pTextList = 0;
9533 sNotify.uMaxEntries = 255;
9534 sNotify.ptAction.x = LOWORD(lParam);
9535 sNotify.ptAction.y = HIWORD(lParam);
9536
9537 if(uSub) { // Spalte verwenden
9538 pExtra = pData->pExtraItems[uSub - 1][pData->uSelectedItem];
9539
9540 if(pExtra) {
9541 sNotify.item.state = pExtra->uState&~TVIS_BASEFLAGS;
9542 sNotify.item.pszText = pExtra->pText;
9543 sNotify.item.cchTextMax = pExtra->uTextSize;
9544 } else {
9545 sNotify.item.state = 0;
9546 sNotify.item.cchTextMax = 0;
9547 sNotify.item.pszText = _T("");
9548 }
9549
9550 sNotify.item.state |= pEntry->uState & TVIS_BASEFLAGS;
9551 } else { // Haupteintrag
9552 sNotify.item.state = pEntry->uState;
9553 sNotify.item.pszText = pEntry->pText;
9554 sNotify.item.cchTextMax = pEntry->uTextSize;
9555 }
9556
9557 UNLOCK(pData);
9558 lRet = SendNotify(pData, &sNotify.hdr);
9559 LOCK(pData);
9560
9561 if(!lRet)
9562 return 0;
9563
9564 if(wParam == VK_RETURN) {
9565 wParam = VK_DBLCLK;
9566 uBits = 0;
9567 } else
9568 if(wParam == VK_EDITCLK) {
9569 if(pData->uStyleEx & TVS_EX_NOCURSORSET) {
9570 uBits = 0;
9571 } else {
9573 uBits = TVIR_SETAT(LOWORD(lParam) - sRect.left);
9574 }
9575 } else {
9576 uBits = 0;
9577 }
9578
9579 cChar = (TCHAR)((lRet >> 8) & 0xFF);
9580 uBits |= U(lRet)&TVIR_EDITFULL;
9581
9582 if(U(lRet)&TVIR_EDITCOMBOBOX) { // Eine Combobox anzeigen
9583 uBits |= (U(lRet)&TVIR_EDITCOMBOLIST) ? 0x40000000 : 0x20000000;
9584 }
9585
9586 hWnd = TreeListEditLabel(pData, uItem, uSub | uBits);
9587 if(!hWnd)
9588 return 0;
9589
9590 if(lRet & TVIR_EDITCOMBOBOX) { // Die Combobox füllen
9591 uMax = sNotify.uMaxEntries;
9592 iSel = -1;
9593
9594 if(sNotify.pTextList) { // Texte über Listenfeld
9595 for(uCnt = 0; uCnt < uMax; uCnt++) {
9596 pText = sNotify.pTextList[uCnt];
9597 if(!pText)
9598 break;
9599
9601
9602 if(sNotify.item.pszText && !_tcscmp(pText, sNotify.item.pszText)) {
9603 iSel = uCnt;
9604 }
9605 }
9606 } else { // Text mit
9607 pText = sNotify.pTextEntries;
9608
9609 if(!pText)
9610 pText = _T("\0");
9611
9612 for(uCnt = 0; uCnt < uMax; uCnt++) {
9613 for(uLen = 0; pText[uLen]; uLen++) { // Subtextlänge holen
9614 if(pText[uLen] == cChar)
9615 break;
9616 }
9617
9618 if(!uLen && !pText[uLen])
9619 break;
9620
9621 uNum = uLen;
9622 if(uNum >= sizeof(cText) / sizeof(TCHAR)) {
9623 uNum = sizeof(cText) / sizeof(TCHAR) - 1;
9624 }
9625
9626 memcpy(cText, pText, uNum * sizeof(TCHAR));
9627 cText[uNum] = 0;
9628 SendMessage(hWnd, CB_ADDSTRING, 1, (LPARAM)cText);
9629
9630 if(sNotify.item.pszText && wParam >= 0x10000 && !_tcscmp(cText, sNotify.item.pszText)) {
9631 iSel = uCnt;
9632 }
9633
9634 pText += uLen;
9635 if(!cChar || *pText)
9636 pText++;
9637 }
9638
9639 if(lRet & TVIR_EDITCOMBODEL) { // Den Puffer löschen
9640 delete((TCHAR*)sNotify.pTextEntries);
9641 }
9642 }
9643
9644 if(iSel >= 0) { // Listeneintrag auswählen
9645 SendMessage(hWnd, CB_SETCURSEL, iSel, 0);
9646 }
9647
9648 if(sNotify.uHeight) { // Höhe der Dropdown-Liste einstellen
9650 }
9651
9652 if(lRet & TVIR_EDITCOMBODOWN) { // Dropdown-Liste einblenden
9654 }
9655
9656 if(!(lRet & TVIR_EDITCOMBOLIST)) { // Textauswahl wiederherstellen
9657 SetWindowText(hWnd, sNotify.item.pszText);
9658 SendMessage(hWnd, CB_SETEDITSEL, 0, pData->uLastSel);
9659 }
9660 }
9661
9662 if(wParam < 0x10000) { // Taste an Fenster senden
9663 pData->cColumnStart = 1;
9664 sMsg.hwnd = hWnd;
9665 sMsg.lParam = lParam;
9666 sMsg.wParam = wParam;
9667 sMsg.message = WM_KEYDOWN;
9668
9669 TranslateMessage(&sMsg);
9670 } else
9671 if(wParam & VK_ISACHAR) {
9672 SendMessage(hWnd, WM_CHAR, wParam & 0xFFFF, lParam);
9673 } else {
9674 pData->cColumnStart = 0;
9675 }
9676
9677 return 1;
9678}
9679
9680//*****************************************************************************
9681//*
9682//* TreeListStartAutoEdit
9683//*
9684//*****************************************************************************
9685// Startet die Autoeditierung für eine Spalte
9686// pData : Zeiger auf die Fensterdaten
9687// uColumn : Ist die Nummer der Spalte
9688// wParam : Ist der W-Parameter des Tastendrucks
9689// VK_EDITCLK bei einem Clickauf das ausgewählte Feld
9690// VK_ICONCLK bei einem Clickauf das Iion
9691// VK_DBLCLK bei einem Doppelclick
9692// lParam : Ist der L-Parameter des Tastendrucks (bzw. die Koordinaten)
9693// Ergibt 1 das Editieren gestartet wurde, ansonsten 0
9694// 0 wenn der Eintrag nicht gewählt wurde
9696
9697 TCHAR cBuffer[256];
9698 NMTREEVIEW sNotify;
9699 ExtraItem *pExtra;
9701 LPTSTR *pList;
9702 LPTSTR pText;
9703 TV_ITEM sItem;
9704 RECT sRect;
9705 TCHAR cChar;
9706 unsigned uMode;
9707 unsigned uBits;
9708 unsigned uFlag;
9709 unsigned uMax;
9710 unsigned uPos;
9711 unsigned uLen;
9712 unsigned uSub;
9713 HWND hWnd;
9714 int iSel;
9715 int iRet;
9716 int iIcon;
9717
9718 if(pData->uEditItem)
9719 return 0;
9720 if(pData->uColumnCount <= uColumn)
9721 return 0;
9722 if(!(pData->uStyle & TVS_EDITLABELS))
9723 return 0;
9724
9725 uBits = pData->aColumn[uColumn].bFlags;
9726 uMode = pData->aColumn[uColumn].bEdit;
9727
9728 if(uMode == 0)
9729 return 0;
9730
9731 if(uBits & TVAE_STATEENABLE) { // Kann das Editieren gesperrt werden
9732 if(uColumn) {
9733 pExtra = pData->pExtraItems[uColumn - 1][pData->uSelectedItem];
9734 if(pExtra && (pExtra->uState & TVIS_DISABLEBIT))
9735 return 0;
9736 } else {
9737 pEntry = pData->pTreeItems[pData->uSelectedItem];
9738 if(!pEntry || (pEntry->uState & TVIS_DISABLEBIT))
9739 return 0;
9740 }
9741 }
9742
9743 if(wParam != VK_RETURN && wParam < 0x10000) { // Zeicheneingabe
9744 if(!TVIS_EDIT(uMode))
9745 return 0;
9746 if(uBits & TVAE_ONLYRETURN)
9747 return 0;
9748 if(wParam <= ' ')
9749 return 0;
9750 pData->cColumnStart = 1;
9751 } else {
9752 pData->cColumnStart = 0;
9753 }
9754
9755 uMax = pData->aColumn[uColumn].bCbSize;
9756 if(!uMax)
9757 uMax = 1024;
9758
9759//******************** Weiterschalten mit Return ******************************
9760 if(uMode >= TVAX_STEP) {
9761 sItem.mask = TVIF_TEXT | TVIF_SUBITEM | TVIF_TEXTPTR | ((uMode < TVAX_CHECK) ? 0 : TVIF_STATE | TVIF_PARAM);
9762 sItem.stateMask = 0xFFFFFFFF;
9763 sItem.hItem = (HTREEITEM)(ULONG_PTR)pData->uSelectedItem;
9764 sItem.cChildren = uColumn;
9765
9766 if(!TreeListGetItem(pData, &sItem))
9767 return 0;
9768
9769 if((uMode & 1) && wParam != VK_ICONCLK) { // Ein Edit-Feld öffnen
9770 uMode = TVAX_EDIT;
9771 goto EditField;
9772 }
9773
9774 if(uMode >= TVAX_CHECK) { // State-Bits bei Checkboxen setzen
9775 if(uBits & TVAE_STATEENABLE)
9776 uFlag = sItem.state & (~TVIS_STATEIMAGEMASK | TVIS_DISABLEBIT);
9777 else
9778 uFlag = sItem.state & (~TVIS_STATEIMAGEMASK);
9779
9780 if(pData->uStyleEx & TVS_EX_BITCHECKBOX)
9781 sItem.state = (sItem.state ^ 0x1000);
9782 else
9783 sItem.state = (sItem.state & 0x1000) ? 0x2000 : 0x1000;
9784
9785 sItem.state |= uFlag;
9786 } else {
9787 sItem.mask &= ~TVIF_STATE;
9788 }
9789
9790 if(uBits & TVAE_PTRLIST) { // Zeigerliste char *pTexte[]={"1","2",NULL};
9791 pList = (LPTSTR *)pData->aColumn[uColumn].pCbData;
9792
9793 if(!pList) {
9794 if(uMode < TVAX_CHECK)
9795 return 0;
9796 sItem.mask &= ~TVIF_TEXT;
9797 pText = sItem.pszText;
9798 uPos = 0;
9799 goto NoTextChange;
9800 }
9801
9802 for(uPos = 0;; uPos++) {
9803 if(uPos >= uMax || !pList[uPos]){
9804 uPos = 0; break;
9805 }
9806 if(str_cmp(sItem.pszText, pList[uPos]))
9807 continue;
9808 uPos++;
9809 if(uPos >= uMax || !pList[uPos])
9810 uPos = 0;
9811 break;
9812 }
9813
9814 pText = pList[uPos];
9815 if(!pText) {
9816 if(uMode < TVAX_CHECK)
9817 return 0;
9818 sItem.mask &= ~TVIF_TEXT;
9819 pText = sItem.pszText;
9820 }
9821 } else { // Textliste char *pText="1|2|3";
9822 pText = (LPTSTR)pData->aColumn[uColumn].pCbData;
9823 cChar = (TCHAR)pData->aColumn[uColumn].bCbChar;
9824 sItem.cchTextMax--;
9825
9826 if(!pText) {
9827 if(uMode < TVAX_CHECK)
9828 return 0;
9829 sItem.mask &= ~TVIF_TEXT;
9830 pText = sItem.pszText;
9831 uPos = 0;
9832 goto NoTextChange;
9833 }
9834
9835 for(uPos = 0;; uPos++) {
9836 if(uPos >= uMax) {
9837 pText = (LPTSTR)pData->aColumn[uColumn].pCbData;
9838 uPos = 0;
9839 break;
9840 }
9841
9842 for(uLen = 0; pText[uLen]; uLen++) { // Subtextlänge bestimmen
9843 if(pText[uLen] == cChar)
9844 break;
9845 }
9846
9847 if(sItem.cchTextMax == (int)uLen) // Ist der Subtext der aktulle Text
9848 if(str_ncmp(sItem.pszText, pText, uLen) == 0) {
9849 uPos++;
9850
9851 if(uPos >= uMax) {
9852 pText = (LPTSTR)pData->aColumn[uColumn].pCbData;
9853 uPos = 0;
9854 break;
9855 }
9856
9857 pText += uLen;
9858 if(pText[0] == cChar)
9859 pText++;
9860 if(pText[0] == 0) {
9861 pText = (LPTSTR)pData->aColumn[uColumn].pCbData;
9862 uPos = 0;
9863 }
9864
9865 break;
9866 }
9867
9868 pText += uLen;
9869 if(pText[0] == cChar)
9870 pText++;
9871 if(pText[0] == 0) {
9872 pText = (LPTSTR)pData->aColumn[uColumn].pCbData;
9873 uPos = 0;
9874 break;
9875 }
9876
9877 }
9878
9879 for(uLen = 0; pText[uLen] && uLen < 256; uLen++) { // Ausgewählten Text kopiren
9880 if(pText[uLen] == cChar)
9881 break;
9882 cBuffer[uLen] = pText[uLen];
9883 }
9884
9885 cBuffer[uLen] = 0;
9886 pText = cBuffer;
9887 }
9888
9889NoTextChange:
9890
9891 sItem.mask &= ~TVIF_TEXTPTR;
9892 sItem.stateMask &= TVIS_STATEIMAGEMASK;
9893 sItem.hItem = (HTREEITEM)(ULONG_PTR)pData->uSelectedItem;
9894 sItem.pszText = pText;
9895 sItem.cchTextMax = 256;
9896 sItem.cChildren = uColumn;
9897 iIcon = pData->aColumn[uColumn].iCbIcon;
9898
9899 if(iIcon >= 0) { // Auch ein Icon zuweisen
9900 sItem.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
9901 sItem.iImage = iIcon + uPos;
9902 sItem.iSelectedImage = sItem.iImage;
9903 }
9904
9905 iRet = TreeListSetItem(pData, &sItem);
9906
9907 sNotify.hdr.code = (uMode < TVAX_CHECK) ? TVN_STEPSTATECHANGED : TVN_CBSTATECHANGED;
9908 sNotify.action = (UINT)wParam;
9909 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT | TVIF_SUBITEM;
9910 sNotify.itemNew.stateMask = 0xFFFFFFFF;
9911 sNotify.itemNew.hItem = sItem.hItem;
9912 sNotify.itemNew.state = sItem.state;
9913 sNotify.itemNew.lParam = sItem.lParam;
9914 sNotify.itemNew.pszText = sItem.pszText;
9915 sNotify.itemNew.cchTextMax = sItem.cchTextMax;
9916 sNotify.itemNew.cChildren = uColumn;
9917 sNotify.itemOld.mask = 0;
9918 sNotify.ptDrag.x = LOWORD(lParam);
9919 sNotify.ptDrag.y = HIWORD(lParam);
9920
9921 UNLOCK(pData);
9922 SendNotify(pData, &sNotify.hdr);
9923 LOCK(pData);
9924
9925 return iRet;
9926 }
9927
9928//******************** Edit oder Combobox *************************************
9929EditField:
9930
9931 uSub = (uMode - 1) << 29;
9932 uSub |= uColumn;
9933
9934 if(uBits & TVAE_FULLWIDTH) {
9935 uSub |= TVIR_EDITFULL;
9936 }
9937
9938 if(wParam == VK_EDITCLK) // Cursor auf Klickposition
9939 if(!(pData->uStyleEx & TVS_EX_NOCURSORSET)) {
9940 TreeListGetItemRect(pData, pData->uSelectedItem, TVIR_COLTOSUB(uColumn) | TVIR_GETCOLUMN | TVIR_TEXT, &sRect);
9941 uSub |= TVIR_SETAT(LOWORD(lParam) - sRect.left);
9942 }
9943
9944 hWnd = TreeListEditLabel(pData, pData->uSelectedItem, uSub);
9945 if(!hWnd)
9946 return 0;
9947
9948 if(uMode != TVAX_EDIT) {
9949 iSel = (uMode != TVAX_CBLIST) ? -1 : 0;
9950 sItem.mask = TVIF_TEXT | TVIF_SUBITEM | TVIF_TEXTPTR;
9951 sItem.hItem = (HTREEITEM)(ULONG_PTR)pData->uSelectedItem;
9952 sItem.cChildren = uColumn;
9953
9954 if(!TreeListGetItem(pData, &sItem))
9955 return 0;
9956
9957 if(uBits & TVAE_PTRLIST) { // Zeigerliste char *pTexte[]={"1","2",NULL};
9958 pList = (LPTSTR *)pData->aColumn[uColumn].pCbData;
9959
9960 for(uPos = 0; uPos < uMax; uPos++) {
9961 if(!pList[uPos])
9962 break;
9963 if(!str_cmp(sItem.pszText, pList[uPos]))
9964 iSel = uPos;
9966 }
9967 } else { // Textliste char *pText="1|2|3";
9968 pText = (LPTSTR)pData->aColumn[uColumn].pCbData;
9969 cChar = (TCHAR)pData->aColumn[uColumn].bCbChar;
9970 sItem.cchTextMax--;
9971
9972 for(uPos = 0; uPos < uMax; uPos++) {
9973 for(uLen = 0; pText[uLen]; uLen++) {
9974 if(pText[uLen] == cChar)
9975 break;
9976 }
9977
9978 if(sItem.cchTextMax == (int)uLen)
9979 if(str_ncmp(sItem.pszText, pText, uLen) == 0) {
9980 iSel = uPos;
9981 }
9982
9983 if(cChar) {
9984 if(uLen < 256){
9985 memcpy(cBuffer, pText, sizeof(TCHAR)*uLen);
9986 cBuffer[uLen] = 0;
9987 }
9988 else {
9989 memcpy(cBuffer, pText, sizeof(TCHAR) * 255);
9990 cBuffer[255 ] = 0;
9991 }
9992 SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)cBuffer);
9993 } else {
9995 }
9996
9997 pText += uLen;
9998 if(pText[0] == cChar)
9999 pText++;
10000 if(pText[0] == 0)
10001 break;
10002 }
10003 }
10004
10005 if(iSel >= 0) {
10006 SendMessage(hWnd, CB_SETCURSEL, iSel, 0);
10007 }
10008 }
10009
10010 if((uBits & TVAE_DROPDOWN) && (uMode&~1) == 2) { // Dropdownliste aufklappen
10012 }
10013
10014 // Ersten Buchstaben ans Fenster übergeben
10015 if(TVIS_EDIT(uMode) && pData->cColumnStart && wParam != VK_EDITCLK) {
10017 }
10018
10019 return 1;
10020}
10021
10022//*****************************************************************************
10023//*
10024//* TreeListProc
10025//*
10026//*****************************************************************************
10027// Ist die Fensterfunktion für das TreeList Fenster
10029
10031 MSG *pMsg;
10032 LPARAM lRet;
10033 TV_HITTESTINFO sInfo;
10034 POINT sPoint;
10035 SCROLLINFO sScroll;
10036 unsigned uChange;
10037 unsigned uDelta;
10038 unsigned uTime;
10039 unsigned uFlag;
10040 unsigned uMode;
10041 unsigned uVal;
10042 unsigned uOld;
10043 int iDif;
10044 int iPos;
10045 int iMax;
10046 HDC hDc;
10047
10048 switch(uMsg) {
10049 case WM_CREATE: // Das Fenster erzeugen
10050
10051 pData = new(TreeListData, 1);
10052 if(!pData)
10053 return -1;
10054
10055 memset(pData, 0, sizeof(TreeListData));
10056 pData->pToolTipText = new(TCHAR, 256);
10057 pData->uToolTipSize = 256;
10058
10059 if(!pData->pToolTipText) {
10060 delete(pData);
10061 return -1;
10062 }
10063
10064 pData->pTreeItems = new(BaseItem*, 1);
10065 if(!pData->pTreeItems) {
10066 delete(pData->pToolTipText);
10067 delete(pData);
10068 return -1;
10069 }
10070
10071 pData->pItemPos = new(unsigned, 1);
10072 if(!pData->pItemPos) {
10073 delete(pData->pToolTipText);
10074 delete(pData->pTreeItems);
10075 delete(pData);
10076 return -1;
10077 }
10078
10079 GlobalInit();
10080
10081 pData->pItemPos [0] = 0;
10082 pData->pTreeItems[0] = NULL;
10083
10085 pData->iIndent = DEFAULT_IDENT;
10086 pData->iShift = DEFAULT_SHIFT;
10087 pData->uStyle = GetWindowLong(hWnd, GWL_STYLE);
10088 pData->hSem = CreateSemaphore(0, 1, 0x70000000, 0);
10089 pData->hWnd = hWnd;
10090 pData->cIsEnabled = (char)IsWindowEnabled(hWnd);
10091 pData->iAutoAdd = 1;
10092 pData->aColumnPos[0] = 0;
10093 pData->aColumnPos[1] = 1;
10094
10095 if(!(pData->uStyle & (TVS_HASBUTTONS | TVS_HASLINES))) {
10096 pData->cHasRootRow = 0;
10097 } else {
10098 pData->cHasRootRow = (char)((pData->uStyle & TVS_LINESATROOT) ? 1 : 0);
10099 }
10100
10101 if(!(pData->uStyle & TVS_NOTOOLTIPS)) {
10103 }
10104
10109
10110 if(pOpenThemeData) // Soll ein Thema angezeigt werden
10111 pData->hTheme = pOpenThemeData(hWnd, L"TREEVIEW");
10112 else
10113 pData->hTheme = NULL;
10114
10115 pData->cGlyphOk = (char)((pData->hTheme) ? 1 : 0);
10116
10117 if(pData->uStyle & TVS_CHECKBOXES) {
10119 }
10120
10121 return 0;
10122
10123 case WM_DESTROY: // Das Fenster zerstören
10124
10125 pData = GetHandle(hWnd);
10126
10127 LOCK(pData);
10128
10130 if(pData->hStates == THEMEIMGLIST)
10131 pData->hStates = 0;
10132 if(pData->hChecks == THEMEIMGLIST)
10133 pData->hChecks = 0;
10134 if(pData->hEdit){
10135 DestroyWindow(pData->hEdit);
10136 pData->hEdit = 0;
10137 }
10138 if(pData->hHeader){
10139 DestroyWindow(pData->hHeader);
10140 pData->hHeader = 0;
10141 }
10142 if(pData->hToolTip){
10143 DestroyWindow(pData->hToolTip);
10144 pData->hToolTip = 0;
10145 }
10146 if(pData->hStates){
10147 ImageList_Destroy(pData->hStates);
10148 pData->hStates = 0;
10149 }
10150
10151 if(pData->uStyleEx & TVS_EX_SHAREIMAGELISTS) {
10152 if(pData->hStates && pData->iStatesMode) {
10153 ImageList_Destroy(pData->hStates);
10154 pData->hStates = 0;
10155 }
10156 if(pData->hChecks && pData->iChecksMode) {
10157 ImageList_Destroy(pData->hChecks);
10158 pData->hChecks = 0;
10159 }
10160 pData->hImages = 0;
10161 pData->hSubImg = 0;
10162 pData->hHeadImg = 0;
10163 } else {
10164 if(pData->hStates){
10165 ImageList_Destroy(pData->hStates);
10166 pData->hStates = 0;
10167 }
10168 if(pData->hChecks){
10169 ImageList_Destroy(pData->hChecks);
10170 pData->hChecks = 0;
10171 }
10172 if(pData->hImages){
10173 ImageList_Destroy(pData->hImages);
10174 pData->hImages = 0;
10175 }
10176 if(pData->hSubImg){
10177 ImageList_Destroy(pData->hSubImg);
10178 pData->hSubImg = 0;
10179 }
10180 if(pData->hHeadImg){
10181 if(pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST)
10182 ImageList_Destroy(pData->hHeadImg);
10183 pData->hHeadImg = 0;
10184 }
10185 }
10186
10187 if(pData->hThemeBt){
10188 pCloseThemeData(pData->hThemeBt);
10189 pData->hThemeBt = 0;
10190 }
10191 if(pData->hTheme){
10192 pCloseThemeData(pData->hTheme);
10193 pData->hTheme = 0;
10194 }
10195
10196 for(uVal = 1; uVal < pData->uColumnCount; uVal++) {
10197 delete(pData->pExtraItems[uVal - 1]);
10198 pData->pExtraItems[uVal - 1] = 0;
10199 }
10200
10201 if(pData->hFontB){
10202 DeleteObject(pData->hFontB);
10203 pData->hFontB = 0;
10204 }
10205
10206 pData->uColumnCount = 0;
10207
10208 UNLOCK(pData);
10209
10210 return 0;
10211
10212 case WM_NCDESTROY: // Das Fenster zerstören
10213
10214 pData = GetHandle(hWnd);
10215
10216 LOCK(pData);
10217
10218 delete(pData->pToolTipText);
10219 delete(pData->pTreeItems);
10220 delete(pData->pItemPos);
10221
10222 UNLOCK(pData);
10223
10224 SetWindowLongPtr(hWnd, 0, 0);
10225 CloseHandle(pData->hSem);
10226 memset(pData, 0, sizeof(TreeListData));
10227 delete(pData);
10228
10229 GlobalDeinit();
10230
10231 return 0;
10232
10233 case WM_SHOWWINDOW: // Fenster ein/ausblenden
10234
10235 if(wParam) {
10236 pData = GetHandle(hWnd);
10237
10238 sScroll.cbSize = sizeof(SCROLLINFO);
10239 sScroll.fMask = SIF_ALL;
10240 sScroll.nMin = 0;
10241 sScroll.nMax = 0;
10242 sScroll.nPage = 0;
10243 sScroll.nPos = 0;
10244 sScroll.nTrackPos = 0;
10245
10246 SetScrollInfo(pData->hWnd, SB_VERT, &sScroll, TRUE);
10247 SetScrollInfo(pData->hWnd, SB_HORZ, &sScroll, TRUE);
10248
10249 pData->uOldXCount = 0xFFFF;
10250 pData->uOldYCount = 0xFFFF;
10251
10254 }
10255
10256 return 0;
10257
10258 case WM_SIZE: // Die Fenstergröße wurde verändert
10259
10260 pData = GetHandle(hWnd);
10261 uFlag = 0;
10262
10263 LOCK(pData);
10264
10265 uVal = LOWORD(lParam);
10266 if(uVal && uVal != pData->uSizeX) {
10267 uOld = pData->uSizeX;
10268 pData->uSizeX = uVal;
10269
10270 if(pData->uColumnCountVar) { // Spalten mit variabler Breite nach führen
10271 RECT sRect;
10272 int iDelta;
10273 int iNum;
10274
10275 iDelta = uVal - uOld;
10276
10277 ChangeColSize(pData, iDelta);
10278
10279 iNum = UpdateColumns(pData);
10280 GetClientRect(hWnd, &sRect);
10281 sRect.left = iNum;
10282 sRect.left -= pData->uScrollX;
10283 sRect.top = pData->uStartPixel;
10284 InvalidateRect(hWnd, &sRect, FALSE);
10285 }
10286
10287 if(uVal > uOld) { // Hat sich die Breite vergrößert
10288 RECT sRect;
10289
10290 GetClientRect(hWnd, &sRect);
10291 sRect.right = uVal;
10292 sRect.left = uOld;
10293 InvalidateRect(hWnd, &sRect, FALSE);
10294 }
10295
10296 pData->aColumnXpos[pData->uColumnCount + 1] = uVal + 1;
10297
10298 MoveWindow(pData->hHeader, -(int)pData->uScrollX, 0, uVal + pData->uScrollX, pData->uStartPixel, uVal > uOld);
10300 }
10301
10302 uVal = HIWORD(lParam);
10303 if(uVal && uVal != pData->uSizeY) {
10304 if(uVal > pData->uSizeY) { // Hat sich die Höhe vergrößert
10305 RECT sRect;
10306
10307 GetClientRect(hWnd, &sRect);
10308 uFlag = 1;
10309 sRect.bottom = uVal;
10310 sRect.top = pData->uSizeY;
10311 InvalidateRect(hWnd, &sRect, FALSE);
10312 } else {
10313 uFlag = 0;
10314 }
10315
10316 pData->uSizeY = uVal;
10317 pData->uSizeYsub = (uVal <= pData->uStartPixel) ? 0 : uVal - pData->uStartPixel;
10318
10319 if(pData->uSizeY > pData->uStartPixel) {
10320 pData->uMaxEnties = pData->uSizeY;
10321 pData->uMaxEnties -= pData->uStartPixel;
10322 } else {
10323 pData->uMaxEnties = 0;
10324 }
10325
10326 pData->uPageEnties = pData->uMaxEnties;
10327 pData->uMaxEnties += pData->iRowHeight - 1;
10328 pData->uMaxEnties /= pData->iRowHeight;
10329 pData->uPageEnties /= pData->iRowHeight;
10330 // Wenn Höhe vergrößert dann Scroll-Position prüfen
10331 if(uFlag && pData->uPageEnties > 2 && pData->uScrollY > 0) {
10332 if(pData->uScrollY + pData->uPageEnties + 1 > pData->uItemPosCount) {
10333 iPos = pData->uItemPosCount - pData->uPageEnties + 1;
10334 if(iPos < 0)
10335 iPos = 0;
10336 if(U(iPos) != pData->uScrollY) {
10337 pData->uScrollY = iPos;
10339 }
10340 }
10341 }
10343 }
10344
10345 UNLOCK(pData);
10346
10347 if(uFlag) {
10349 }
10350
10351 return 0;
10352
10353 case WM_ENABLE: // Das Fenster feischalten oder sperren
10354
10355 pData = GetHandle(hWnd);
10356 if(pData->cIsEnabled != ((U(wParam)) ? 1 : 0)) {
10357 uVal = GetWindowLong(hWnd, GWL_STYLE);
10358 uVal &= (0xFFFF0000 & ~WS_DISABLED);
10359 uVal |= (0x0000FFFF | WS_DISABLED) & (pData->uStyle ^ WS_DISABLED);
10361 }
10362
10363 return 0;
10364
10365 case WM_SETFOCUS: // Das Fenster bekommt den Focus
10366
10367 pData = GetHandle(hWnd);
10368 if(!pData->cHasFocus) {
10369 NMHDR sNotify;
10370
10371 LOCK(pData);
10372 pData->cHasFocus = 1;
10373
10374 if(pData->uSelectedCount <= 1) {
10375 if(pData->uSelectedItem) {
10376 if(pData->uStyleEx & TVS_EX_FULLROWMARK)
10377 UpdateRow(pData, pData->uSelectedItem);
10378 else
10379 UpdateRect(pData, pData->uSelectedItem, pData->uSelectedSub);
10380 }
10381 } else {
10383 }
10384
10385 UNLOCK(pData);
10386
10387 sNotify.code = NM_SETFOCUS;
10388 SendNotify(pData, &sNotify);
10389 }
10390
10391 return 0;
10392
10393 case WM_KILLFOCUS: // Das Fenster bekommt den Focus
10394
10395 pData = GetHandle(hWnd);
10396 if(pData->cHasFocus) {
10397 NMHDR sNotify;
10398
10399 LOCK(pData);
10400 pData->cHasFocus = 0;
10401
10402 if(pData->uSelectedCount <= 1) {
10403 if(pData->uSelectedItem) {
10404 if(pData->uStyleEx & TVS_EX_FULLROWMARK)
10405 UpdateRow(pData, pData->uSelectedItem);
10406 else
10407 UpdateRect(pData, pData->uSelectedItem, pData->uSelectedSub);
10408 }
10409 } else {
10411 }
10412
10413 UNLOCK(pData);
10414
10415 sNotify.code = NM_KILLFOCUS;
10416 SendNotify(pData, &sNotify);
10417 }
10418
10419 return 0;
10420
10421 case WM_MOUSEMOVE: // Gab es eine Mausbewegung
10422
10423 pData = GetHandle(hWnd);
10424 sInfo.hItem = 0;
10425 sInfo.flags = 0;
10426
10427 if(!(pData->uStyle & TVS_NOTOOLTIPS)) {
10428 if(!pData->cIsEnabled) { // Ist das Fenster freigegeben
10429 return 0;
10430 }
10431
10432 LOCK(pData);
10433
10434 sInfo.pt.x = LOWORD(lParam);
10435 sInfo.pt.y = HIWORD(lParam);
10436 TreeListHitTest(pData, &sInfo);
10437 UpdateToolTip(pData, U(sInfo.hItem), sInfo.flags);
10438
10439 UNLOCK(pData);
10440 }
10441
10442 if(pData->uStyle & TVS_TRACKSELECT) {
10443 if(!pData->cIsEnabled) { // Ist das Fenster freigegeben
10444 return 0;
10445 }
10446
10447 LOCK(pData);
10448
10449 if(!sInfo.hItem) {
10450 sInfo.pt.x = LOWORD(lParam);
10451 sInfo.pt.y = HIWORD(lParam);
10452 TreeListHitTest(pData, &sInfo);
10453 }
10454
10455 if(sInfo.hItem && (sInfo.flags & (TVHT_ONSUBITEM | TVHT_ONSUBLABEL | TVHT_ONITEM))) {
10456 TreeListSetTrackItem(pData, U(sInfo.hItem), TVHT_SUBTOCOL(sInfo.flags));
10457 }
10458
10459 UNLOCK(pData);
10460 }
10461
10462 if(wParam & pData->uDragFlags) // Drag beginnen
10463 if(U(lParam) != pData->uLastMove) {
10464 NMTREEVIEW sNotify;
10466 int iDiffX;
10467 int iDiffY;
10468
10469 iDiffX = (short)(lParam) - (short)(pData->uLastMove);
10470 iDiffY = (short)(lParam >> 16) - (short)(pData->uLastMove >> 16);
10471
10472 if(iDiffX < 0)
10473 iDiffX = -iDiffX;
10474 if(iDiffY < 0)
10475 iDiffY = -iDiffY;
10476
10477 if(iDiffX <= 2 && iDiffY <= 2) { // Mehr als zwei Pixel-Verschub
10478 return 0;
10479 }
10480
10481 LOCK(pData);
10482
10483 if(pData->uDragItem > pData->uTreeItemsMax) {
10484 UNLOCK(pData);
10485 return 0;
10486 }
10487
10488 pEntry = pData->pTreeItems[pData->uDragItem];
10489 if(!pEntry) {
10490 UNLOCK(pData);
10491 return 0;
10492 }
10493
10494 sNotify.hdr.code = TVN_BEGINDRAG;
10495 sNotify.action = (pEntry->uState & TVIS_EXPANDED) ? TVE_COLLAPSE : TVE_EXPAND;
10496 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBNUMBER;
10497 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)pData->uDragItem;
10498 sNotify.itemNew.stateMask = 0xFFFFFFFF;
10499 sNotify.itemNew.state = pEntry->uState;
10500 sNotify.itemNew.lParam = pEntry->lParam;
10501 sNotify.itemNew.cChildren = pData->uDragSub;
10502 sNotify.itemNew.pszText = (LPTSTR) - 1;
10503 sNotify.itemNew.cchTextMax = -1;
10504 sNotify.itemOld.mask = 0;
10505 sNotify.ptDrag.x = LOWORD(lParam);
10506 sNotify.ptDrag.y = HIWORD(lParam);
10507 pData->uDragFlags = 0;
10508 pData->cClickFlag = 0;
10509 pData->cClickEdit = 0;
10510
10511 UNLOCK(pData);
10512
10513 SendNotify(pData, &sNotify.hdr);
10514 }
10515
10516 pData->uLastMove = U(lParam);
10517
10518 return 0;
10519
10520 case WM_LBUTTONUP: // Linken Mausklick aufheben
10521
10522 pData = GetHandle(hWnd);
10523 pData->uDragFlags &= ~MK_LBUTTON;
10524
10525 if(pData->cClickFlag || pData->cClickEdit) {
10527 pData->cClickFlag = 0;
10528 pData->cClickEdit = 0;
10529 } else {
10531 }
10532
10533 return 0;
10534
10535 case WM_RBUTTONUP: // Linken Mausklick aufheben
10536
10537 pData = GetHandle(hWnd);
10538 pData->uDragFlags &= ~MK_RBUTTON;
10539
10541
10542 break;
10543
10544 case WM_LBUTTONDOWN: // Mausklick
10545
10546 pData = GetHandle(hWnd);
10547
10548 LOCK(pData);
10549
10550 uTime = GetTickCount();
10551
10552 if(pData->cButtonFlag && pData->uToolTipItem) { // Doppelklick simulieren über ToolTip
10553 pData->cButtonFlag = 0;
10554 uDelta = uTime - pData->uButtonLast;
10555
10556 if(uDelta < 700) {
10557 iPos = abs(LOWORD(lParam) - LOWORD(pData->uButtonPos));
10558 iPos += abs(HIWORD(lParam) - HIWORD(pData->uButtonPos));
10559
10560 if(iPos <= 6) {
10562 return 0;
10563 }
10564 }
10565 }
10566
10567 pData->cButtonFlag = 1;
10568 pData->uButtonLast = uTime;
10569 pData->uButtonPos = U(lParam);
10570
10572
10573 return 0;
10574
10575 case WM_LBUTTONDBLCLK:
10576 case WM_RBUTTONDOWN:
10577 case WM_RBUTTONDBLCLK:
10578
10579 pData = GetHandle(hWnd);
10580
10581 LOCK(pData);
10582
10583 pData->cButtonFlag = 0;
10585
10586 return 0;
10587
10588 case WM_KEYDOWN: // Tastendruck
10589
10590 pData = GetHandle(hWnd);
10591 LOCK(pData);
10593
10594 return 0;
10595
10596 case WM_KEYUP: // Tastendruck
10597
10599 return 1;
10600
10601 case WM_CHAR: // Zeicheneingabe
10602
10603 pData = GetHandle(hWnd);
10604 iMax = lParam & 0xFFFF;
10605
10606 for(iPos = 0; iPos < iMax; iPos++) {
10608 }
10609
10610 return 0;
10611
10612 case WM_DRAWITEM: // Weietleiten von OwnerDraw des Headers
10613
10614 if(wParam == 1) {
10615 pData = GetHandle(hWnd);
10617 }
10618
10619 return 0;
10620
10621 case WM_MOUSEWHEEL: // Scrollen mit dem Mausrad
10622
10623 if(!(LOWORD(wParam) & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON))) {
10624 pData = GetHandle(hWnd);
10625
10626 if(pData->uEditItem)
10627 return 0;
10628
10629 iDif = (short)HIWORD(wParam) / (WHEEL_DELTA / 2);
10630
10631 if(wParam & MK_CONTROL) {
10632 iDif *= 9;
10633 } else
10634 if(wParam & MK_SHIFT) {
10635 iDif *= 3;
10636 }
10637
10638 iPos = pData->uScrollY - iDif;
10639 iMax = pData->uItemPosCount;
10640 iMax -= pData->uPageEnties - 1;
10641
10642 if(iPos >= iMax)
10643 iPos = iMax;
10644 if(iPos < 0)
10645 iPos = 0;
10646 if(iPos != (int)pData->uScrollY)
10647 if(!(pData->uStyle & TVS_NOSCROLL)) {
10648 pData->uScrollY = iPos;
10649 SetScrollPos(hWnd, SB_VERT, iPos, TRUE);
10651 }
10652
10653 return 1;
10654 }
10655
10656 return 0;
10657
10658 case WM_HSCROLL: // Vertikalles scrollen
10659
10660 pData = GetHandle(hWnd);
10661 iPos = pData->uScrollX;
10662
10663 if(pData->uEditItem)
10664 return 0;
10665
10666 switch(LOWORD(wParam)) {
10667 case SB_LINEDOWN:
10668 iPos += 16;
10669 break;
10670 case SB_LINEUP:
10671 iPos -= 16;
10672 break;
10673 case SB_PAGEDOWN:
10674 iPos += pData->uSizeX;
10675 break;
10676 case SB_PAGEUP:
10677 iPos -= pData->uSizeX;
10678 break;
10679 case SB_THUMBPOSITION:
10680 iPos = HIWORD(wParam);
10681 break;
10682 case SB_THUMBTRACK:
10683 iPos = HIWORD(wParam);
10684 break;
10685 }
10686
10687 uVal = pData->uColumnCount;
10688 if(uVal)
10689 iMax = pData->aColumnXpos[uVal] - pData->uSizeX / 2;
10690 else
10691 iMax = pData->iMaxSizeX;
10692 iMax -= pData->uSizeX / 2;
10693
10694 if(iPos >= iMax)
10695 iPos = iMax;
10696 if(iPos < 0)
10697 iPos = 0;
10698 if(iPos != (int)pData->uScrollX) {
10699 pData->uScrollX = iPos;
10700 SetScrollPos(hWnd, SB_HORZ, iPos, TRUE);
10702
10703 if(pData->hHeader) {
10704 MoveWindow(pData->hHeader, -iPos, 0, pData->uSizeX + iPos, pData->uStartPixel, TRUE);
10705 }
10706 }
10707
10708 return 0;
10709
10710 case WM_VSCROLL: // Vertikalles scrollen
10711
10712 pData = GetHandle(hWnd);
10713 iPos = pData->uScrollY;
10714
10715 if(pData->uEditItem)
10716 return 0;
10717
10718 switch(LOWORD(wParam)) {
10719 case SB_LINEDOWN:
10720 iPos++;
10721 break;
10722 case SB_LINEUP:
10723 iPos--;
10724 break;
10725 case SB_PAGEDOWN:
10726 iPos += (pData->uPageEnties > 1) ? pData->uPageEnties - 1 : 1;
10727 break;
10728 case SB_PAGEUP:
10729 iPos -= (pData->uPageEnties > 1) ? pData->uPageEnties - 1 : 1;
10730 break;
10731 case SB_THUMBPOSITION:
10732 case SB_THUMBTRACK:
10733 if(pData->uItemPosCount < 0x7F00) {
10734 iPos = HIWORD(wParam);
10735 } else {
10736 sScroll.cbSize = sizeof(SCROLLINFO);
10737 sScroll.fMask = SIF_TRACKPOS;
10738 GetScrollInfo(hWnd, SB_VERT, &sScroll);
10739 iPos = sScroll.nTrackPos;
10740 }
10741 }
10742
10743 iMax = pData->uItemPosCount;
10744 iMax -= pData->uPageEnties - 1;
10745
10746 if(iPos >= iMax)
10747 iPos = iMax;
10748 if(iPos < 0)
10749 iPos = 0;
10750 if(iPos != (int)pData->uScrollY) {
10751 pData->uScrollY = iPos;
10752 SetScrollPos(hWnd, SB_VERT, iPos, TRUE);
10754 }
10755
10756 return 0;
10757
10758 case WM_SYSCOLORCHANGE: // Wurden die Systemfarben verändert
10759
10760 pData = GetHandle(hWnd);
10761
10762 LOCK(pData);
10763
10764 if(pData->hTheme) {
10765 pCloseThemeData(pData->hTheme);
10766 pData->hTheme = NULL;
10767 }
10768
10769 if(pData->hThemeBt) {
10770 pCloseThemeData(pData->hThemeBt);
10771 pData->hThemeBt = NULL;
10772 }
10773
10774 if(pOpenThemeData) {
10775 pData->hTheme = pOpenThemeData(hWnd, L"TREEVIEW");
10776 pData->cGlyphOk = (char)((pData->hTheme) ? 1 : 0);
10777 }
10778
10779 if(pData->iStatesMode)
10781 if(pData->iChecksMode)
10783
10784 if(pData->hHeader)
10785 SendMessage(pData->hHeader, WM_SYSCOLORCHANGE, 0, 0);
10787 UNLOCK(pData);
10788
10789 return 0;
10790
10791 case WM_GETFONT: //tell what font we are using
10792 {
10793 HFONT hFont;
10794 pData = GetHandle(hWnd);
10795
10796 LOCK(pData);
10797 hFont = pData->hFontN;
10798 UNLOCK(pData);
10799 return (LRESULT)hFont;
10800 }
10801
10802 case WM_SETFONT: // Einen neuen Font zuweisen
10803
10804 pData = GetHandle(hWnd);
10805
10806 LOCK(pData);
10807
10809 if(UpdateFont(pData))
10811 }
10812
10813 UNLOCK(pData);
10814
10815 return 0;
10816
10817 case WM_STYLECHANGED: // Hat sich der Fenstersytle geändert
10818
10819 if(wParam == GWL_STYLE) {
10820 pData = GetHandle(hWnd);
10821 lParam = ((STYLESTRUCT *)lParam)->styleNew;
10822
10823 LOCK(pData);
10824 uChange = U(lParam) ^ pData->uStyle;
10825 pData->uStyle = U(lParam);
10826
10827 if(uChange & (TVS_CHECKBOXES | TVS_NONEVENHEIGHT)) {
10828 if(lParam & TVS_CHECKBOXES) {
10829 if(pData->hStates == NULL) {
10831 }
10832 } else {
10833 if(pData->iStatesMode && pData->hStates) {
10834 if(pData->hStates != THEMEIMGLIST) {
10835 ImageList_Destroy(pData->hStates);
10836 }
10837
10838 pData->hStates = NULL;
10839 pData->iStatesMode = 0;
10840 }
10841 }
10842
10845 }
10846
10848 if(!(pData->uStyle & (TVS_HASBUTTONS | TVS_HASLINES))) {
10849 pData->cHasRootRow = 0;
10850 } else {
10851 pData->cHasRootRow = (char)((pData->uStyle & TVS_LINESATROOT) ? 1 : 0);
10852 }
10853
10855 }
10856
10857 if(uChange & TVS_NOSCROLL) {
10858 pData->uOldYCount = 0xFFFF;
10859 pData->uOldXCount = 0xFFFF;
10860
10863 }
10864
10865 if(uChange & TVS_NOTOOLTIPS) {
10866 if(pData->uStyle & TVS_NOTOOLTIPS) {
10867 UpdateToolTip(pData, 0, 0);
10868 } else {
10870 }
10871 }
10872
10873 if(uChange & WS_DISABLED) {
10874 pData->cIsEnabled = (char)((pData->uStyle & WS_DISABLED) ? 0 : 1);
10876 if(!pData->cIsEnabled)
10877 UpdateToolTip(pData, 0, 0);
10878 }
10879
10880 UNLOCK(pData);
10881 }
10882
10883 return 0;
10884
10885 case WM_PAINT: // Das Fenster zeichnen
10886
10887 if(wParam) {
10889 } else {
10890 PAINTSTRUCT sPaint;
10891
10892 hDc = BeginPaint(hWnd, &sPaint);
10893
10895 RECT sRect;
10896 HDC hDcBuffer;
10897 HANDLE hBufferedPaint;
10898
10899 GetClientRect(hWnd, &sRect);
10900 hBufferedPaint = pBeginBufferedPt(hDc, &sRect, BPBF_COMPATIBLEBITMAP, NULL, &hDcBuffer);
10901
10902 if(hBufferedPaint) {
10903 TreeListDraw(hWnd, hDcBuffer, &sRect);
10904 pEndBufferedPt(hBufferedPaint, TRUE);
10905 } else {
10906 TreeListDraw(hWnd, hDc, &sRect);
10907 }
10908 } else {
10909 TreeListDraw(hWnd, hDc, &sPaint.rcPaint);
10910 }
10911
10912 EndPaint(hWnd, &sPaint);
10913 }
10914
10915 return 0;
10916
10917 case WM_TIMER: // Timer Funktion
10918
10919 if(wParam == ID_TOOLTIPCHECK) {
10920 pData = GetHandle(hWnd);
10921 if(pData->uToolTipItem) {
10922 if(pData->uToolTipShow) { // Verzögertes einblenden
10923 pData->uToolTipShow--;
10924 if(pData->uToolTipShow)
10925 return 0;
10926
10927 LOCK(pData);
10928
10929 GetCursorPos(&sPoint);
10930
10931 sInfo.pt.x = sPoint.x;
10932 sInfo.pt.y = sPoint.y;
10933
10934 ScreenToClient(hWnd, &sInfo.pt);
10935
10936 if(WindowFromPoint(sPoint) == hWnd) {
10937 TreeListHitTest(pData, &sInfo);
10938 } else {
10939 sInfo.hItem = 0;
10940 sInfo.flags = 0;
10941 }
10942
10943 if(sInfo.flags & TVHT_ONITEM)
10944 if(pData->uToolTipItem == U(sInfo.hItem) && pData->uToolTipSub == 0) {
10945 TOOLINFO sInfo;
10946
10947 UNLOCK(pData);
10948
10949 sInfo.cbSize = sizeof(sInfo);
10950 sInfo.hwnd = pData->hWnd;
10951 sInfo.uId = (UINT_PTR)pData->hWnd;
10952
10953 if(pData->uToolTipItem) {
10954 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
10955 }
10956
10957 SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y));
10958 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
10959
10960 return 0;
10961 }
10962
10963 if(sInfo.flags & TVHT_ONSUBITEM)
10964 if(pData->uToolTipItem == U(sInfo.hItem) && TVHT_SUBTOCOL(sInfo.flags) == pData->uToolTipSub) {
10965 TOOLINFO sInfo;
10966
10967 UNLOCK(pData);
10968
10969 sInfo.cbSize = sizeof(sInfo);
10970 sInfo.hwnd = pData->hWnd;
10971 sInfo.uId = (UINT_PTR)pData->hWnd;
10972
10973 if(pData->uToolTipItem) {
10974 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
10975 }
10976
10977 SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y));
10978 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
10979
10980 return 0;
10981 }
10982
10983 // ToolTip wieder entferenen
10984 UpdateToolTip(pData, U(sInfo.hItem), sInfo.flags);
10985 UNLOCK(pData);
10986 }
10987
10988 LOCK(pData);
10989
10990 GetCursorPos(&sInfo.pt);
10991 ScreenToClient(hWnd, &sInfo.pt);
10992 TreeListHitTest(pData, &sInfo);
10993 UpdateToolTip(pData, U(sInfo.hItem), sInfo.flags);
10994
10995 UNLOCK(pData);
10996 }
10997 }
10998
10999 return 0;
11000
11001 case WM_COMMAND: // Kommando Nachrichnten
11002
11004 pData = GetHandle(hWnd);
11005 if(pData->uEditItem) {
11006 LOCK(pData);
11008 UNLOCK(pData);
11009 if(pData->uEditMode)
11010 if(wParam != MAKELONG(3, EN_KILLFOCUS)) {
11011 SetFocus(pData->hWnd);
11012 }
11013 }
11014 } else
11015 if(wParam == MAKELONG(3, EN_ESCAPE)) { // ESC-Taste in Edit-Fenster
11016 pData = GetHandle(hWnd);
11017 if(pData->uEditItem) {
11018 LOCK(pData);
11020 UNLOCK(pData);
11021 if(pData->uEditMode)
11022 SetFocus(pData->hWnd);
11023 }
11024 } // Änderung in Edit-Fenster
11025 else
11027 pData = GetHandle(hWnd);
11028 pData->cColumnStart = 1;
11029 }
11030
11031 return 0;
11032
11033 case WM_NOTIFY: // Notify Nachrichnten
11034
11035 if(wParam == 1) { // Nachricht vom Header
11036 NMHEADER *pHdr = (NMHEADER *)lParam;
11037 HDITEM sItem;
11038 HDITEM sTemp;
11039 RECT sRect;
11040 int iDelta;
11041 int iCode;
11042 int iSize;
11043 int iNext;
11044 int iCol;
11045 int iSub;
11046
11047 iCode = pHdr->hdr.code;
11048 // Hat sich die Spaltenbreite verändert
11049 if(iCode == HDN_ITEMCHANGED && (pHdr->pitem->mask & HDI_WIDTH)) {
11050 pData = GetHandle(hWnd);
11051 iCol = pHdr->iItem;
11052
11053 if(pData->aColumn[iCol].sReal != pHdr->pitem->cxy) {
11054 iCode = HDN_TRACK;
11055 }
11056 }
11057
11058 if(iCode == HDN_BEGINDRAG) { // Drag&Drop im Header
11059 pData = GetHandle(hWnd);
11060
11061 if(!(pData->uStyleEx & TVS_EX_HEADERDRAGDROP) || pHdr->iItem == 0) {
11062 return 1;
11063 }
11064
11065 return 0;
11066 }
11067
11068 if(iCode == HDN_ENDDRAG) { // Drag&Drop im Header fertig
11069 if(pHdr->pitem->iOrder == 0 || pHdr->iItem == 0) {
11070 return 1;
11071 }
11072
11073 pData = GetHandle(hWnd);
11074
11075 if(!(pData->uStyleEx & TVS_EX_HEADERDRAGDROP)) {
11076 return 1;
11077 }
11078
11080
11081 return 0;
11082 }
11083
11084 if(iCode == HDN_BEGINTRACK) { // User will die Spaltenbreite ändern
11085 pData = GetHandle(hWnd);
11086
11087 if(!pData->cHasFocus) {
11088 SetFocus(pData->hWnd);
11089 }
11090
11091 if(pData->uStyleEx & TVS_EX_NOCOLUMNRESIZE) { // Darf der User die Spaltenbreite ändern
11092 return 1;
11093 }
11094
11095 if(pData->uStyleEx & TVS_EX_FIXEDCOLSIZE) { // Fixe gesammte Spaltenbreite
11096 iNext = pData->aColumn[pHdr->iItem].bIndex;
11097
11098 for(iNext++;; iNext++) { // Suche nächste veränerbare Spalte
11099 if(U(iNext) >= pData->uColumnCount) {
11100 return 1;
11101 }
11102
11103 iSub = pData->aColumnPos[iNext];
11104
11105 if(pData->aColumn[iSub].sFixed == 0) {
11106 break;
11107 }
11108 }
11109 }
11110
11111 if(U(pHdr->iItem) < pData->uColumnCount) // Darf die Spalte verändert werden
11112 if(pData->aColumn[pHdr->iItem].sFixed) {
11113 POINT sPoint;
11114 int iCol;
11115 int iSub;
11116
11117 if(pData->aColumn[pHdr->iItem].sReal || pHdr->iItem < 0) {
11118 return 1;
11119 }
11120
11121 GetCursorPos(&sPoint); // Die nächste veränderbare Spalte greifen
11122 ScreenToClient(pData->hHeader, &sPoint);
11123
11124 PostMessage(pData->hHeader, WM_LBUTTONUP, 0, MAKELONG(sPoint.x, sPoint.y));
11125
11126 iCol = pData->aColumn[pHdr->iItem].bIndex;
11127 iSub = pData->aColumnPos[iCol - 1];
11128
11129 PostMessage(pData->hHeader, WM_LBUTTONDOWN, 0, MAKELONG(pData->aColumnXpos[iSub + 1] - 2, sPoint.y));
11130
11131 return 1;
11132 }
11133 }
11134
11135 if(iCode == HDN_DIVIDERDBLCLICK) { // Doppelcklick auf Spaltentrenner
11136 pData = GetHandle(hWnd);
11137
11138 if(!pData->cHasFocus) {
11139 SetFocus(pData->hWnd);
11140 }
11141
11142 if(pData->uStyleEx & TVS_EX_NOCOLUMNRESIZE) { // Darf der User die Spaltenbreite ändern
11143 return 0;
11144 }
11145
11146 if(U(pHdr->iItem) < pData->uColumnCount) // Darf die Spalte verändert werden
11147 if(pData->aColumn[pHdr->iItem].sFixed) {
11148 return 0;
11149 }
11150
11151 LOCK(pData);
11152
11153 iSize = TreeListScanColumn(pData, pHdr->iItem);
11154 if(iSize) { // Spalte auf maximale Textbreite
11155 sItem.cxy = iSize;
11156 pHdr->pitem = &sItem;
11158
11159 if(pData->aColumn[pHdr->iItem].bMinEx) // Minimale Breite prüfen
11160 if(pData->aColumn[pHdr->iItem].sMin > sItem.cxy) {
11161 sItem.cxy = pData->aColumn[pHdr->iItem].sMin;
11162 }
11163 }
11164
11165 UNLOCK(pData);
11166 }
11167
11168 if(iCode == HDN_TRACK || iCode == HDN_ENDTRACK) { // Wurde die Spaltenbreite verändert
11169 pData = GetHandle(hWnd);
11170
11171 if(!pData->cHasFocus && iCode == HDN_ENDTRACK) {
11172 SetFocus(pData->hWnd);
11173 }
11174
11175 LOCK(pData);
11176
11177 iCol = pHdr->iItem;
11178 sItem.mask = HDI_WIDTH;
11179 sItem.cxy = pHdr->pitem->cxy;
11180
11181 if(pData->aColumn[iCol].bMinEx) // Minimale Breite prüfen
11182 if(pData->aColumn[iCol].sMin > sItem.cxy) {
11183 sItem.cxy = pData->aColumn[iCol].sMin;
11184 pHdr->pitem->cxy = sItem.cxy;
11185
11186 if(sItem.cxy == pData->aColumn[iCol].sSize) {
11187 UNLOCK(pData);
11188 return 0;
11189 }
11190 }
11191
11192 if(pData->uStyleEx & TVS_EX_FIXEDCOLSIZE) { // Fixe gesammte Spaltenbreite
11193 if(iCol == 0 && sItem.cxy <= 0) {
11194 sItem.cxy = 1;
11195 pHdr->pitem->cxy = 1;
11196
11197 if(sItem.cxy == pData->aColumn[iCol].sSize) {
11198 UNLOCK(pData);
11199 return 0;
11200 }
11201 }
11202
11203 iNext = pData->aColumn[iCol].bIndex;
11204
11205 for(iNext++;; iNext++) { // Überspringe fixierte Spalten
11206 if(U(iNext) >= pData->uColumnCount) {
11207 UNLOCK(pData);
11208 return 0;
11209 }
11210
11211 iSub = pData->aColumnPos[iNext];
11212
11213 if(pData->aColumn[iSub].sFixed == 0) {
11214 break;
11215 }
11216 }
11217
11218 iDelta = pData->aColumn[iCol].sReal - sItem.cxy;
11219 sTemp.cxy = pData->aColumn[iSub].sReal + iDelta;
11220
11221 if(iDelta < 0) { // Nächste Spalte wird zu klein
11222 if(sTemp.cxy < 0) {
11223 sTemp.cxy = 0;
11224 iDelta = -pData->aColumn[iSub].sReal;
11225 sItem.cxy = pData->aColumn[iCol].sReal - iDelta;
11226 }
11227
11228 if(pData->aColumn[iSub].bMinEx) // Minimale Breite prüfen
11229 if(pData->aColumn[iSub].sMin > sTemp.cxy) {
11230 iDelta += pData->aColumn[iSub].sMin - sTemp.cxy;
11231 sTemp.cxy = pData->aColumn[iSub].sMin;
11232 sItem.cxy = pData->aColumn[iCol].sReal - iDelta;
11233 }
11234
11235 pHdr->pitem->cxy = sItem.cxy;
11236
11237 if(iDelta >= 0) { // Keine Änderung
11238 UNLOCK(pData);
11239 return 0;
11240 }
11241 }
11242
11243 if(pData->aColumn[iSub].bWeight) { // Variable Spalte
11244 pData->iVarSize -= pData->aColumn[iSub].sSize;
11245 pData->iVarSize += sTemp.cxy;
11246 } else { // Fixe Spalte
11247 pData->iFixSize -= pData->aColumn[iSub].sSize;
11248 pData->iFixSize += sTemp.cxy;
11249 }
11250
11251 sTemp.mask = HDI_WIDTH;
11252
11253 iDif = pData->aColumn[iSub].sReal;
11254 pData->aColumn[iSub].sSize = (short)sTemp.cxy;
11255 pData->aColumn[iSub].sReal = (short)sTemp.cxy;
11256 Header_SetItem(pData->hHeader, iSub, &sTemp);
11257
11258 // Breite verändert
11259 if(iDif != sTemp.cxy && (pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY)) {
11260 TV_COLSIZE sNotify;
11261
11262 sNotify.hdr.code = TVN_COLUMNCHANGED;
11263 sNotify.uColumn = iSub;
11264 sNotify.uIndex = pData->aColumn[iSub].bIndex;
11265 sNotify.uPosX = pData->aColumnXpos[iSub];
11266 sNotify.iSize = sTemp.cxy;
11267
11268 UNLOCK(pData);
11269 SendNotify(pData, &sNotify.hdr);
11270 LOCK(pData);
11271 }
11272 }
11273
11274 if(pData->aColumn[iCol].bWeight) { // Ist es eine variable Spalte
11275 pData->iVarSize -= pData->aColumn[iCol].sSize;
11276 pData->iVarSize += sItem.cxy;
11277 } else { // Fixe Spalte
11278 pData->iFixSize -= pData->aColumn[iCol].sSize;
11279 pData->iFixSize += sItem.cxy;
11280 }
11281
11282 iDif = pData->aColumn[iCol].sReal;
11283 pData->aColumn[iCol].sSize = (short)sItem.cxy;
11284 pData->aColumn[iCol].sReal = (short)sItem.cxy;
11285 Header_SetItem(pData->hHeader, iCol, &sItem);
11286
11287 iSize = UpdateColumns(pData);
11288 if(iSize < 0x10000) { // Spalten neu zeichnen
11289 GetClientRect(hWnd, &sRect);
11290 sRect.left = iSize;
11291 sRect.left -= pData->uScrollX;
11292 InvalidateRect(hWnd, &sRect, FALSE);
11293 }
11294
11296 UNLOCK(pData);
11297
11298 // Breite verändert
11299 if(iDif != sItem.cxy && (pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY)) {
11300 TV_COLSIZE sNotify;
11301
11302 sNotify.hdr.code = TVN_COLUMNCHANGED;
11303 sNotify.uColumn = iCol;
11304 sNotify.uIndex = pData->aColumn[iCol].bIndex;
11305 sNotify.uPosX = pData->aColumnXpos[iCol];
11306 sNotify.iSize = sItem.cxy;
11307
11308 UNLOCK(pData);
11309 SendNotify(pData, &sNotify.hdr);
11310 LOCK(pData);
11311 }
11312 }
11313 // Weiterleiten an Elternfenster
11315 pData = GetHandle(hWnd);
11316
11317 if(!pData->cHasFocus) {
11318 SetFocus(pData->hWnd);
11319 }
11320
11321 SendNotify(pData, &pHdr->hdr);
11322 }
11323 } else {
11324 NMHDR *pHdr = (NMHDR *)lParam;
11325 NMTTDISPINFO *pInfo;
11326
11327 switch(pHdr->code) {
11328 case TTN_GETDISPINFO:
11329
11330 pData = GetHandle(hWnd);
11331 pInfo = (NMTTDISPINFO *)pHdr;
11332 pInfo->lpszText = pData->pToolTipText;
11333 SendMessage(pData->hToolTip, WM_SETFONT, (WPARAM)pData->hFontT, 0);
11334 break;
11335 }
11336 }
11337
11338 return 0;
11339
11340 case WM_GETDLGCODE: // Welche Tasten werden im Dialog benutzt
11341
11342 pMsg = (MSG *)lParam;
11343 if(pMsg && pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) {
11344 return DLGC_WANTALLKEYS;
11345 }
11346
11348
11349 case WM_PASTE: // Weiterleiten an Edit-Control
11350 case WM_CLEAR:
11351 case WM_COPY:
11352 case WM_CUT:
11353
11354 pData = GetHandle(hWnd);
11355
11356 if(pData->hEdit) {
11357 PostMessage(pData->hEdit, uMsg, 0, 0);
11358 return 0;
11359 }
11360
11361 break;
11362
11363 case TVM_SETIMAGELIST: // Die Image-Liste einstellen
11364
11365 pData = GetHandle(hWnd);
11366
11367 LOCK(pData);
11368#ifdef _DEBUG
11369 char dbg[255];
11370 sprintf(dbg, "TVM_SETIMAGELIST %d", (int)wParam);
11371 OutputDebugStringA(dbg);
11372#endif
11373 switch((int)wParam) {
11374 case TVSIL_NORMAL:
11375 lRet = (LPARAM)pData->hImages;
11376 if(lRet == lParam)
11377 break;
11378
11379 pData->hImages = (HIMAGELIST)lParam;
11380 if(!pData->hImages) {
11381 pData->iImagesXsize = 0;
11382 pData->iImagesYsize = 0;
11383 } else {
11384 IMAGEINFO sInfo;
11385 ImageList_GetImageInfo(pData->hImages, 0, &sInfo);
11386 pData->iImagesXsize = sInfo.rcImage.right - sInfo.rcImage.left;
11387 pData->iImagesYsize = sInfo.rcImage.bottom - sInfo.rcImage.top;
11388 if(pData->hHeader && ((pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST) == 0))
11389 SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hImages);
11390 }
11391
11392 if(!pData->iSubImgMode || pData->hSubImg == pData->hImages) {
11393 pData->iSubImgMode = 0;
11394 pData->hSubImg = pData->hImages;
11395 pData->iSubImgXsize = pData->iImagesXsize;
11396 pData->iSubImgYsize = pData->iImagesXsize;
11397 }
11398
11399 if(!pData->cFixedHeight) {
11400 pData->iRowHeight = 1;
11403 } else {
11405 }
11406
11407 break;
11408
11409 case TVSIL_HEADER:
11410 lRet = pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST;
11411 if(lRet == 0)
11412 break;
11413
11414 lRet = (LPARAM)pData->hHeadImg;
11415 if(lRet == lParam)
11416 break;
11417
11418 pData->hHeadImg = (HIMAGELIST)lParam;
11419
11420 if(pData->hHeader)
11421 SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hHeadImg);
11422
11423 if(!pData->cFixedHeight) {
11424 pData->iRowHeight = 1;
11427 } else {
11429 }
11430 break;
11431
11432 case TVSIL_STATE:
11433 lRet = (LPARAM)pData->hStates;
11434 if(lRet == lParam)
11435 break;
11436
11437 if(pData->iStatesMode) {
11438 if(pData->hStates != THEMEIMGLIST) {
11439 ImageList_Destroy(pData->hStates);
11440 }
11441
11442 pData->iStatesMode = 0;
11443 }
11444
11445 pData->hStates = (HIMAGELIST)lParam;
11446 if(!pData->hStates) {
11447 pData->iStatesXsize = 0;
11448 pData->iStatesYsize = 0;
11449
11450 if(pData->uStyle & TVS_CHECKBOXES) {
11452 }
11453 } else
11454 if(pData->hStates == THEMEIMGLIST) {
11455 pData->iStatesXsize = 16;
11456 pData->iStatesYsize = 16;
11457 pData->iStatesMode = 1;
11458 if(!pData->hThemeBt)
11460 } else {
11461 IMAGEINFO sInfo;
11462 ImageList_GetImageInfo(pData->hStates, 0, &sInfo);
11463 pData->iStatesXsize = sInfo.rcImage.right - sInfo.rcImage.left;
11464 pData->iStatesYsize = sInfo.rcImage.bottom - sInfo.rcImage.top;
11465 pData->iStatesMode = 0;
11466 }
11467
11468 if(!pData->cFixedHeight) {
11469 pData->iRowHeight = 1;
11472 } else {
11474 }
11475
11476 break;
11477
11478 case TVSIL_CHECK:
11479 lRet = (LPARAM)pData->hChecks;
11480 if(lRet == lParam)
11481 break;
11482
11483 if(pData->iChecksMode) {
11484 if(pData->hChecks != THEMEIMGLIST) {
11485 ImageList_Destroy(pData->hChecks);
11486 }
11487
11488 pData->iChecksMode = 0;
11489 }
11490
11491 pData->hChecks = (HIMAGELIST)lParam;
11492 if(!pData->hChecks) {
11493 pData->iChecksXsize = 0;
11494 pData->iChecksYsize = 0;
11495
11496 for(uVal = 0; uVal < pData->uColumnCount; uVal++) {
11497 if(pData->aColumn[uVal].bEdit < TVSIL_CHECK)
11498 continue;
11500 break;
11501 }
11502 } else
11503 if(pData->hChecks == THEMEIMGLIST) {
11504 pData->iChecksXsize = 16;
11505 pData->iChecksYsize = 16;
11506 pData->iChecksMode = 1;
11507 if(!pData->hThemeBt)
11509 } else {
11510 IMAGEINFO sInfo;
11511 ImageList_GetImageInfo(pData->hChecks, 0, &sInfo);
11512 pData->iChecksXsize = sInfo.rcImage.right - sInfo.rcImage.left;
11513 pData->iChecksYsize = sInfo.rcImage.bottom - sInfo.rcImage.top;
11514 pData->iChecksMode = 0;
11515 }
11516
11517 if(!pData->cFixedHeight) {
11518 pData->iRowHeight = 1;
11521 } else {
11523 }
11524
11525 break;
11526
11527 case TVSIL_SUBIMAGES:
11528 lRet = (LPARAM)pData->hSubImg;
11529 if(lRet == lParam)
11530 break;
11531
11532 if(pData->iSubImgMode) {
11533 ImageList_Destroy(pData->hSubImg);
11534 pData->iSubImgMode = 0;
11535 }
11536
11537 pData->hSubImg = (HIMAGELIST)lParam;
11538 if(!pData->hSubImg || pData->hSubImg == pData->hImages) {
11539 pData->iSubImgMode = 0;
11540 pData->hSubImg = pData->hImages;
11541 pData->iSubImgXsize = pData->iImagesXsize;
11542 pData->iSubImgYsize = pData->iImagesXsize;
11543 } else {
11544 IMAGEINFO sInfo;
11545 ImageList_GetImageInfo(pData->hSubImg, 0, &sInfo);
11546 pData->iSubImgXsize = sInfo.rcImage.right - sInfo.rcImage.left;
11547 pData->iSubImgYsize = sInfo.rcImage.bottom - sInfo.rcImage.top;
11548 pData->iSubImgMode = 1;
11549 }
11550
11551 if(!pData->cFixedHeight) {
11552 pData->iRowHeight = 1;
11555 } else {
11557 }
11558
11559 break;
11560
11561 default:
11562 lRet = 0;
11563 }
11564
11565 UNLOCK(pData);
11566
11567 return lRet;
11568
11569 case TVM_GETIMAGELIST: // Die Image-Liste abfragen
11570
11571 pData = GetHandle(hWnd);
11572 if(!pData)
11573 return 0;
11574
11575 switch((int)wParam) {
11576 case TVSIL_NORMAL:
11577 lRet = (LPARAM)pData->hImages;
11578 break;
11579 case TVSIL_STATE:
11580 lRet = (LPARAM)pData->hImages;
11581 break;
11582 case TVSIL_CHECK:
11583 lRet = (LPARAM)pData->hChecks;
11584 break;
11585 case TVSIL_HEADER:
11586 lRet = (LPARAM)pData->hHeadImg;
11587 break;
11588 default
11589 :
11590 lRet = 0;
11591 }
11592
11593 return lRet;
11594
11595 case TVM_GETSETOPTION: // Diverse Optionen einstellen
11596
11597 pData = GetHandle(hWnd);
11598 lRet = 0;
11599
11600 switch(U(wParam) & ~TVOP_WRITEOPTION) {
11601 case TVOP_AUTOEXPANDOFF: // Icon Offset für TVS_EX_AUTOEXPANDICON
11602
11603 lRet = pData->iAutoAdd;
11604
11605 if((wParam & TVOP_WRITEOPTION) && lParam != lRet) {
11606 LOCK(pData);
11607
11608 pData->iAutoAdd = (int)lParam;
11609 if(pData->uItemPosCount > 0) {
11611 }
11612
11613 UNLOCK(pData);
11614 }
11615
11616 break;
11617 }
11618
11619 return lRet;
11620
11621 case TVM_GETITEMSTATE: // Die Statusbits eines Eintrags abfragen
11622
11623 pData = GetHandle(hWnd);
11624 LOCK(pData);
11625
11626 if(U(wParam) <= pData->uTreeItemsMax) {
11628
11629 pEntry = pData->pTreeItems[U(wParam)];
11630 if(!pEntry)
11631 lRet = 0;
11632 {
11633 lRet = pEntry->uState;
11634 }
11635 } else {
11636 lRet = 0;
11637 }
11638
11639 UNLOCK(pData);
11640
11641 return lRet;
11642
11643 case TVM_GETITEM: // Einträge abfragen
11644
11645 pData = GetHandle(hWnd);
11646 LOCK(pData);
11647 lRet = TreeListGetItem(pData, (TV_ITEM *)lParam);
11648 UNLOCK(pData);
11649
11650 return lRet;
11651
11652 case TVM_SETITEM: // Einträge einfügen
11653
11654 pData = GetHandle(hWnd);
11655 LOCK(pData);
11656 lRet = TreeListSetItem(pData, (TV_ITEM *)lParam);
11657 UNLOCK(pData);
11658
11659 return lRet;
11660
11661 case TVM_INSERTITEM: // Einträge einfügen
11662
11663 pData = GetHandle(hWnd);
11664 LOCK(pData);
11666 UNLOCK(pData);
11667
11668 return lRet;
11669
11670 case TVM_DELETEITEM: // Einträge löschen
11671
11672 pData = GetHandle(hWnd);
11673 LOCK(pData);
11674 lRet = TreeListDeleteItem(pData, U(lParam), (U(wParam) == 0x88) ? 2 : 1);
11675 UNLOCK(pData);
11676
11677 return lRet;
11678
11679 case TVM_FINDITEM: // Einträge suchen
11680
11681 pData = GetHandle(hWnd);
11682 LOCK(pData);
11684 UNLOCK(pData);
11685
11686 return lRet;
11687
11688 case TVM_DELETECOLUMN: // Löschen einer Salte im Header
11689
11690 pData = GetHandle(hWnd);
11691 LOCK(pData);
11693 UNLOCK(pData);
11694
11695 return lRet;
11696
11697 case TVM_INSERTCOLUMN: // Einfügen einer Salte im Header
11698
11699 pData = GetHandle(hWnd);
11700 LOCK(pData);
11702 UNLOCK(pData);
11703
11704 return lRet;
11705
11706 case TVM_GETCOLUMNCOUNT: // Abfragen der Spaltenanzahl
11707
11708 pData = GetHandle(hWnd);
11709 return (LRESULT)pData->uColumnCount;
11710
11711 case TVM_GETHEADER: // Abfragen des Header-Fensters
11712
11713 pData = GetHandle(hWnd);
11714 return (LRESULT)pData->hHeader;
11715
11716 case TVM_GETEXTENDEDSTYLE: // Abfragen der erweiterten Style-Bits
11717
11718 pData = GetHandle(hWnd);
11719 return pData->uStyleEx;
11720
11721 case TVM_SETEXTENDEDSTYLE: // Einstellen der erweiterten Style-Bits
11722
11723 pData = GetHandle(hWnd);
11724 if(!wParam)
11725 wParam = 0xFFFFFFFF;
11726
11727 uVal = pData->uStyleEx & ~U(wParam);
11728 uVal |= U(lParam) & U(wParam);
11729
11730 if(pData->uStyleEx != uVal) { // Has it changed?
11731 LOCK(pData);
11732 uChange = pData->uStyleEx ^ uVal;
11733 pData->uStyleEx = uVal;
11734
11735 if(uChange & TVS_EX_AUTOHSCROLL) {
11737 }
11738
11739 if((uChange & TVS_EX_GRAYEDDISABLE) && !pData->cIsEnabled) {
11741 }
11742
11743 if(uChange & TVS_EX_ITEMLINES) {
11746 }
11747
11750 }
11751
11752 if((uChange&~U(lParam)) & TVS_EX_SUBSELECT) {
11753 TreeListSelectItem(pData, pData->uSelectedItem, 0, TVC_UNKNOWN);
11754 }
11755
11756 if(pData->hHeader){
11757 if((uChange & TVS_EX_HIDEHEADERS) || (uChange & TVS_EX_HEADEROWNIMGLIST)) {
11758 pData->uStartPixel = (pData->uStyleEx & TVS_EX_HIDEHEADERS) ? 0 : bDrawWithTheme ? GetSystemMetrics(SM_CYHSCROLL) : 17;
11759 MoveWindow(pData->hHeader, -(int)pData->uScrollX, 0, pData->uSizeX + pData->uScrollX, pData->uStartPixel, TRUE);
11760
11761 if(pData->uStyleEx & TVS_EX_HEADEROWNIMGLIST){
11762 SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hHeadImg);
11763 } else {
11764 SendMessage(pData->hHeader, HDM_SETIMAGELIST, 0, (LPARAM)pData->hImages);
11765 }
11766
11768 }
11769 }
11770
11771 UNLOCK(pData);
11772 }
11773
11774 return uVal;
11775
11776 case TVM_GETINSERTMARKCOLOR: // Farben abfragen
11778 goto ColGet;
11779 case TVM_GETLINECOLOR:
11780 wParam = TVC_LINE;
11781 goto ColGet;
11782 case TVM_GETTEXTCOLOR:
11783 wParam = TVC_TEXT;
11784 case TVM_GETBKCOLOR:
11785
11786ColGet:
11787 if(wParam < 0 || wParam >= MAX_COLORS)
11788 return 0xFFFFFFFF;
11789 pData = GetHandle(hWnd);
11790 return pData->uColors[U(wParam)];
11791
11792 case TVM_SETINSERTMARKCOLOR: // Farben einstellen
11794 goto ColSet;
11795 case TVM_SETLINECOLOR:
11796 wParam = TVC_LINE;
11797 goto ColSet;
11798 case TVM_SETTEXTCOLOR:
11799 wParam = TVC_TEXT;
11800 case TVM_SETBKCOLOR:
11801
11802ColSet:
11803 if(wParam < 0 || wParam >= MAX_COLORS)
11804 return 0xFFFFFFFF;
11805
11806 pData = GetHandle(hWnd);
11807
11808 LOCK(pData);
11809
11810 lRet = pData->uColors[U(wParam)];
11811
11812 if((COLORREF)lParam == TV_NOCOLOR) { // Standartfarbe einstellen
11813 if(pData->cColorChanged[U(wParam)]) {
11814 pData->cColorChanged[U(wParam)] = 0;
11817 }
11818 } else {
11819 pData->cColorChanged[U(wParam)] = 1;
11820 pData->uColors [U(wParam)] = (COLORREF)lParam;
11821
11822 if(lRet != lParam) {
11825 }
11826 }
11827
11828 UNLOCK(pData);
11829
11830 return lRet;
11831
11832 case TVM_HITTEST: // Abfragen von Koortinatenpositionen
11833
11834 pData = GetHandle(hWnd);
11835
11836 LOCK(pData);
11838 UNLOCK(pData);
11839
11840 return lRet;
11841
11842 case TVM_SELECTCHILDS: // Mehrere Einträge auswählen
11843
11844 pData = GetHandle(hWnd);
11845
11846 LOCK(pData);
11848 UNLOCK(pData);
11849
11850 return lRet;
11851
11852 case TVM_SELECTSUBITEM: // Einen (Sub)Eintrag auswählen
11853
11854 pData = GetHandle(hWnd);
11855
11856 LOCK(pData);
11857 if(!(pData->uStyleEx & TVS_EX_SUBSELECT))
11858 wParam = 0;
11860 if(lRet > 1)
11861 lRet = 1;
11862 UNLOCK(pData);
11863
11864 return lRet;
11865
11866 case TVM_SELECTDROP: // Den unterstrichenen Eintrags auswählen
11867
11868 pData = GetHandle(hWnd);
11869
11870 LOCK(pData);
11872 UNLOCK(pData);
11873
11874 return lRet;
11875
11876 case TVM_SELECTITEM: // Einen Eintrag auswählen
11877
11878 pData = GetHandle(hWnd);
11879
11880 LOCK(pData);
11881
11882 switch(wParam) {
11883 case TVGN_CARET:
11885 if(lRet > 1)
11886 lRet = 1;
11887 break;
11888 case TVGN_DROPHILITE:
11889 lRet = TreeListSetTrackItem(pData, U(lParam), 0);
11890 break;
11891
11892 case TVGN_FIRSTVISIBLE:
11894 lRet = (lRet < 0) ? 0 : 1;
11895 break;
11896
11897 default
11898 :
11899 lRet = 0;
11900 }
11901
11902 UNLOCK(pData);
11903
11904 return lRet;
11905
11906 case TVM_GETCOLUMNORDERARRAY: // Spaltensortierung abfragen
11907
11908 if(!lParam)
11909 return 0;
11910
11911 pData = GetHandle(hWnd);
11912
11913 if(!pData->hHeader)
11914 return 0;
11915
11916 return Header_GetOrderArray(pData->hHeader, U(wParam), lParam);
11917
11918 case TVM_SETCOLUMNORDERARRAY: // Spalten sortieren
11919
11920 pData = GetHandle(hWnd);
11921 LOCK(pData);
11922 lRet = TreeListSetOrderArray(pData, U(wParam), (unsigned *)lParam);
11923 UNLOCK(pData);
11924
11925 return lRet;
11926
11927 case TVM_GETCOUNT: // Anzahl der Einträge abfragen
11928
11929 pData = GetHandle(hWnd);
11930 return pData->uTreeItemsCount;
11931
11932 case TVM_GETINDENT: // Einrückung abfragen
11933
11934 pData = GetHandle(hWnd);
11935 return pData->iIndent;
11936
11937 case TVM_SETINDENT: // Einrückung einstellen
11938
11939 pData = GetHandle(hWnd);
11940 lRet = pData->iIndent;
11941 if(wParam < 5)
11942 wParam = 5;
11943 if(wParam > 64)
11944 wParam = 64;
11945 if(lRet != (LPARAM)wParam) {
11946 LOCK(pData);
11947 pData->iIndent = (int)wParam;
11949 UNLOCK(pData);
11950 }
11951
11952 return lRet;
11953
11954 case TVM_GETITEMHEIGHT: // Zeilenhöhe abfragen
11955
11956 pData = GetHandle(hWnd);
11957 return pData->iRowHeight;
11958
11959 case TVM_SETITEMHEIGHT: // Zeilenhöhe abfragen
11960
11961 pData = GetHandle(hWnd);
11962 lRet = pData->iRowHeight;
11963
11964 if(wParam == -1) {
11965 LOCK(pData);
11966 pData->cFixedHeight = 0;
11969 UNLOCK(pData);
11970 return lRet;
11971 }
11972
11973 if(wParam & 1)
11974 if(!(pData->uStyleEx & TVS_NONEVENHEIGHT))
11975 wParam--;
11976 if(wParam < 1)
11977 wParam = 1;
11978 if(wParam > 256)
11979 wParam = 256;
11980
11981 if(lRet != (LPARAM)wParam) {
11982 LOCK(pData);
11983 pData->cFixedHeight = 1;
11984 pData->iRowHeight = (int)wParam;
11986 UNLOCK(pData);
11987 }
11988
11989 return lRet;
11990
11991 case TVM_GETVISIBLECOUNT: // Abfragen der sichtbaren Zeilen
11992
11993 pData = GetHandle(hWnd);
11994 return pData->uPageEnties;
11995
11996 case TVM_ENSUREVISIBLE: // Einen Eintrag ins Sichtfenster legen
11997
11998 pData = GetHandle(hWnd);
11999 LOCK(pData);
12000 lRet = TreeListEnsureVisible(pData, U(lParam), (int)wParam);
12001 UNLOCK(pData);
12002
12003 return lRet;
12004
12005 case TVM_ISITEMVISIBLE: // Ist ein Eintrag sichtbar
12006
12007 pData = GetHandle(hWnd);
12008 LOCK(pData);
12009 lRet = TreeListIsVisible(pData, U(lParam), (int)wParam);
12010 UNLOCK(pData);
12011
12012 return lRet;
12013
12014 case TVM_GETNEXTITEM: // Einen Eintrag suchen
12015
12016 pData = GetHandle(hWnd);
12017 LOCK(pData);
12018 lRet = TreeListGetNextItem(pData, U(lParam), (int)wParam);
12019 UNLOCK(pData);
12020
12021 return lRet;
12022
12023 case TVM_GETITEMRECT: // Das Rechteck eines Eintrages abfragen
12024
12025 pData = GetHandle(hWnd);
12026 LOCK(pData);
12027 uVal = *(unsigned *)lParam;
12028 lRet = TreeListGetItemRect(pData, uVal, U(wParam), (RECT *)lParam);
12029 UNLOCK(pData);
12030
12031 return lRet;
12032
12033 case TVM_EXPAND: // Einen Eintrag umklappen
12034
12035 pData = GetHandle(hWnd);
12036 LOCK(pData);
12037 lRet = 0;
12038NextExp:
12039 if(U(lParam) <= pData->uTreeItemsMax) {
12041#ifndef __REACTOS__
12042 POINT sPoint;
12043#endif
12044
12045 pEntry = pData->pTreeItems[U(lParam)];
12046 if(pEntry) {
12047 sPoint.x = 0;
12048 sPoint.y = 0;
12049
12050 if(wParam & TVE_EXPANDNEXT) { // Bei erstem Eltereneintrag beginnen
12051 if(!pEntry->uParent) {
12052 UNLOCK(pData);
12053 return 1;
12054 }
12055
12056 lParam = pEntry->uParent;
12057 pEntry = pData->pTreeItems[U(lParam)];
12058 wParam &= ~TVE_EXPANDNEXT;
12059 }
12060
12061 switch(wParam & 0x0F) {
12062 case TVE_COLLAPSE:
12063 if(pEntry->uState & TVIS_EXPANDED) {
12064 lRet = (TreeListToggleItem(pData, U(lParam), 0)) ? 0 : 1;
12065 } else { // Nur Flag löschen
12066 pEntry->uState &= ~TVIS_EXPANDPARTIAL;
12067 lRet = 1;
12068 }
12069 // Kinder löschen
12071 pEntry->uState &= TVIS_EXPANDEDONCE;
12072
12073 while(pEntry->uLastChild) {
12074 if(!TreeListDeleteItem(pData, pEntry->uLastChild, 1))
12075 break;
12076 pEntry = pData->pTreeItems[U(lParam)];
12077 }
12078 }
12079 // Auch Eltern zuklappen
12080 if(!(wParam & TVE_EXPANDRECURSIVE)) {
12081 break;
12082 }
12083
12084 if(!pEntry->uParent) {
12085 break;
12086 }
12087
12088 lParam = pEntry->uParent;
12089 goto NextExp;
12090 break;
12091
12092 case TVE_EXPAND:
12093 if(!(pEntry->uState & TVIS_EXPANDED)) {
12095 lRet = (TreeListToggleItem(pData, U(lParam), uVal)) ? 0 : 1;
12096 } else { // Schon aufgeklappt
12097 lRet = 1;
12098
12100 if(!(wParam & TVE_EXPANDFORCE))
12103 }
12104 } else {
12105 if(pEntry->uState & TVIS_EXPANDPARTIAL) {
12106 lRet = (TreeListToggleItem(pData, U(lParam), TVE_EXPAND)) ? 0 : 1;
12107 }
12108 }
12109 }
12110 // Auch Eltern aufklappen
12111 if(!(wParam & TVE_EXPANDRECURSIVE)) {
12112 break;
12113 }
12114
12115 if(!pEntry->uParent) {
12116 break;
12117 }
12118
12119 lParam = pEntry->uParent;
12120 goto NextExp;
12121 break;
12122
12123 case TVE_TOGGLE:
12124 lRet = (TreeListToggleItem(pData, U(lParam), 0)) ? 0 : 1;
12125 break;
12126 }
12127
12128 // Aktion auch auf alle Kinder anwenden
12129 if((wParam & TVE_ALLCHILDS) && pEntry->uFirstChild) {
12130 lParam = pEntry->uFirstChild;
12132 sPoint.x = 0;
12133 sPoint.y = 0;
12134
12135 for(;;) {
12136 UNLOCK(pData);
12137
12138 TreeListProc(hWnd, uMsg, wParam, lParam);
12139
12140 LOCK(pData);
12141
12142 if(U(lParam) > pData->uTreeItemsMax) {
12143 break;
12144 }
12145
12146 pEntry = pData->pTreeItems[U(lParam)];
12147 if(!pEntry || !pEntry->uNextItem)
12148 break;
12149
12150 lParam = pEntry->uNextItem;
12151 }
12152 }
12153 }
12154 }
12155
12156 UNLOCK(pData);
12157
12158 return lRet;
12159
12160 case TVM_SETINSERTMARK: // Einfügemarke eintellen
12161
12162 pData = GetHandle(hWnd);
12163
12164 LOCK(pData);
12165 lRet = TreeListSetInsertMark(pData, U(lParam), (int)wParam);
12166 UNLOCK(pData);
12167
12168 return lRet;
12169
12170 case TVM_SETITEMBKCOLOR: // Hintergrundfarbe eines Eintrages ändern
12171
12172 pData = GetHandle(hWnd);
12173
12174 LOCK(pData);
12175 lRet = TreeListSetItemColor(pData, U(wParam & 0xFFFFFF), U(wParam) >> 24, (COLORREF)lParam, 0);
12176 UNLOCK(pData);
12177
12178 return lRet;
12179
12180 case TVM_SETITEMTEXTCOLOR: // Textfarbe eines Eintrages ändern
12181
12182 pData = GetHandle(hWnd);
12183
12184 LOCK(pData);
12185 lRet = TreeListSetItemColor(pData, U(wParam & 0xFFFFFF), U(wParam) >> 24, (COLORREF)lParam, 1);
12186 UNLOCK(pData);
12187
12188 return lRet;
12189
12190 case TVM_GETITEMBKCOLOR: // Hintergrundfarbe eines Eintrages abfragen
12191
12192 pData = GetHandle(hWnd);
12193
12194 LOCK(pData);
12195 lRet = TreeListGetItemColor(pData, U(wParam), U(lParam), 0);
12196 UNLOCK(pData);
12197
12198 return lRet;
12199
12200 case TVM_GETITEMTEXTCOLOR: // Textfarbe eines Eintrages abfragen
12201
12202 pData = GetHandle(hWnd);
12203
12204 LOCK(pData);
12205 lRet = TreeListGetItemColor(pData, U(wParam), U(lParam), 1);
12206 UNLOCK(pData);
12207
12208 return lRet;
12209
12210 case TVM_SORTCHILDRENEX: // Sortieren mit Funktion
12211
12212 pData = GetHandle(hWnd);
12213
12214 LOCK(pData);
12216 UNLOCK(pData);
12217
12218 return lRet;
12219
12220 case TVM_SORTCHILDRENCB: // Sortieren mit Funktion
12221
12222 pData = GetHandle(hWnd);
12223
12224 LOCK(pData);
12226 UNLOCK(pData);
12227
12228 return lRet;
12229
12230 case TVM_SORTCHILDREN: // Sortieren der Kindereinträge
12231
12232 pData = GetHandle(hWnd);
12233
12234 LOCK(pData);
12235 lRet = TreeListSortItems(pData, U(lParam), (int)wParam);
12236 UNLOCK(pData);
12237
12238 return lRet;
12239
12240 case TVM_GETITEMOFROW: // Hole den Eintrag von einer Reihe
12241
12242 pData = GetHandle(hWnd);
12243
12244 LOCK(pData);
12245 if(U(lParam) < pData->uItemPosCount)
12246 lRet = pData->pItemPos[U(lParam)];
12247 else
12248 lRet = 0;
12249 UNLOCK(pData);
12250
12251 return lRet;
12252
12253 case TVM_GETROWCOUNT: // Hole die Anzahl der sichtbaren Reihen
12254
12255 pData = GetHandle(hWnd);
12256
12257 return pData->uItemPosCount;
12258
12259 case TVM_GETCOUNTPERPAGE: // Hole die Anzahl der darstelbaren Reihen
12260
12261 pData = GetHandle(hWnd);
12262
12263 return pData->uMaxEnties;
12264
12265 case TVM_GETROWOFITEM: // Suche Reihe zu einem Eintrag
12266
12267 pData = GetHandle(hWnd);
12268
12269 LOCK(pData);
12270 if(U(lParam) <= pData->uTreeItemsMax) {
12272
12273 pEntry = pData->pTreeItems[U(lParam)];
12274 if(!pEntry)
12275 lRet = -1;
12276 else
12277 lRet = pEntry->uShowPos - 1;
12278 } else {
12279 lRet = -1;
12280 }
12281 UNLOCK(pData);
12282
12283 return lRet;
12284
12285 case TVM_EDITLABEL: // Einen Eintrag editieren
12286
12287 pData = GetHandle(hWnd);
12288 if(!(pData->uStyle & TVS_EDITLABELS))
12289 return 0;
12290
12291 LOCK(pData);
12292
12293 if((wParam & 0xFFFFFF00) == TVLE_DONOTIFY) { // Notify starten
12295 } else {
12296 pData->cColumnStart = 0;
12298 }
12299
12300 UNLOCK(pData);
12301
12302 return lRet;
12303
12304 case TVM_GETEDITCONTROL: // Das Handle des Edit-Fensters abfragen
12305
12306 pData = GetHandle(hWnd);
12307 return (LRESULT)pData->hEdit;
12308
12309 case TVM_GETTOOLTIPS: // Das Handle des ToolTip-Fensters abfragen
12310
12311 pData = GetHandle(hWnd);
12312 return (LRESULT)pData->hToolTip;
12313
12314 case TVM_SETTOOLTIPS: // Das Handle für das ToolTip-Fensters setzen
12315
12316 pData = GetHandle(hWnd);
12317 lRet = (LRESULT)pData->hToolTip;
12318 pData->hToolTip = (HWND)wParam;
12319 return lRet;
12320
12321 case TVM_SETUSERDATASIZE: // Einstellen der Größe der User-Daten
12322
12323 if(lParam < 0 || lParam > 0x1000000)
12324 return -1;
12325 pData = GetHandle(hWnd);
12326
12327 LOCK(pData);
12328
12329 if(pData->uTreeItemsCount > 0) {
12330 lRet = 0;
12331 } else {
12332 pData->uUserDataSize = U(lParam);
12333 lRet = lParam;
12334 }
12335
12336 UNLOCK(pData);
12337
12338 return lRet;
12339
12340 case TVM_GETUSERDATASIZE: // Abfragen der Größe der User-Daten
12341
12342 pData = GetHandle(hWnd);
12343 return pData->uUserDataSize;
12344
12345 case TVM_GETUSERDATA: // Einen Zeiger auf die User-Daten holen
12346
12347 pData = GetHandle(hWnd);
12348
12349 if(pData->uUserDataSize && U(lParam) <= pData->uTreeItemsMax) {
12351
12352 pEntry = pData->pTreeItems[U(lParam)];
12353 if(pEntry)
12354 return (LRESULT)(pEntry + 1);
12355 }
12356
12357 return 0;
12358
12359 case TVM_SETCOLUMN: // Einen Spalten-Header einstellen
12360
12361 pData = GetHandle(hWnd);
12362
12363 if(pData->hHeader && U(wParam) < pData->uColumnCount) {
12364 HDITEM sItem;
12365 unsigned uBit;
12366 unsigned uCol;
12367 TV_COLUMN *pCol;
12368
12369 pCol = (TV_COLUMN *)lParam;
12370 uCol = U(wParam);
12371
12372 uVal = pCol->cx;
12373 if(uVal == TVCF_LASTSIZE) { // Breite vor Fixierung benutzen
12374 if(pData->aColumn[uCol].sFixed > 0) {
12375 uVal = pData->aColumn[uCol].sFixed;
12376 } else {
12377 uVal = pData->aColumn[uCol].sReal;
12378 }
12379 }
12380
12381 if(pCol->mask & TVCF_FIXED) { // Die Spalte fixieren
12382 uBit = pCol->fmt & TVCFMT_FIXED;
12383
12384 if(uBit != 0 && pData->aColumn[uCol].sFixed == 0) {
12385 pData->aColumn[uCol].sFixed = pData->aColumn[uCol].sReal;
12386 if(!pData->aColumn[uCol].sFixed)
12387 pData->aColumn[uCol].sFixed = 100;
12388 }
12389
12390 if(uBit == 0 && pData->aColumn[uCol].sFixed != 0) {
12391 pData->aColumn[uCol].sFixed = 0;
12392 }
12393 }
12394
12395 sItem.mask = 0;
12396 if(pCol->mask & TVCF_FMT){
12397 sItem.mask |= HDI_FORMAT;
12398 sItem.fmt = pCol->fmt | HDF_STRING;
12399 }
12400 if(pCol->mask & TVCF_IMAGE){
12401 sItem.mask |= HDI_IMAGE;
12402 sItem.iImage = pCol->iImage;
12403 }
12404 if(pCol->mask & TVCF_WIDTH){
12405 sItem.mask |= HDI_WIDTH;
12406 sItem.cxy = uVal;
12407 pData->aColumn[uCol].sSize = (short)sItem.cxy;
12408 }
12409 if(pCol->mask & TVCF_TEXT){
12410 sItem.mask |= HDI_TEXT;
12411 sItem.pszText = pCol->pszText;
12412 sItem.cchTextMax = pCol->cchTextMax;
12413 }
12414
12415 if(sItem.mask) {
12416 lRet = SendMessage(pData->hHeader, HDM_SETITEM, uCol, (LPARAM)&sItem);
12417 } else {
12418 lRet = 1;
12419 }
12420
12421 if(lRet && (pCol->mask & TVCF_FMT)) { // Hat sich die Ausrichtung verändert
12422 BYTE bAlign;
12423
12424 switch(pCol->fmt) {
12425 case TVCFMT_CENTER: bAlign = DT_CENTER; break;
12426 case TVCFMT_RIGHT: bAlign = DT_RIGHT; break;
12427 default: bAlign = DT_LEFT; break;
12428 }
12429
12430 if(pData->aColumn[uCol].bAlign != bAlign) {
12431 pData->aColumn[uCol].bAlign = bAlign;
12432 UpdateColRect(pData, uCol);
12433 }
12434 }
12435
12436 if(lRet && (pCol->mask & TVCF_MARK)) { // Die Spalte markieren
12437 RECT sRect;
12438 unsigned uNext;
12439
12440 uVal = (pCol->fmt & TVCFMT_MARK) ? 1 : 0;
12441 if(uVal != pData->aColumn[uCol].bMark) {
12442 pData->aColumn[uCol].bMark = (BYTE)uVal;
12443 pData->uMarkedCols += uVal * 2 - 1;
12444
12445 uNext = pData->aColumn [uCol ].bNext;
12446 sRect.left = pData->aColumnXpos[uCol ];
12447 sRect.right = pData->aColumnXpos[uNext] + 1;
12448 sRect.bottom = pData->uScrollX;
12449 sRect.top = pData->uSizeY;
12450 InvalidateRect(pData->hWnd, &sRect, FALSE);
12451 }
12452 }
12453 } else {
12454 lRet = 0;
12455 }
12456
12457 return lRet;
12458
12459 case TVM_GETCOLUMN: // Einen Spalten-Header abfragen
12460
12461 pData = GetHandle(hWnd);
12462 if(pData->hHeader) {
12463 HDITEM sItem;
12464 TV_COLUMN *pCol = (TV_COLUMN *)lParam;
12465 int bWantMark;
12466 unsigned uCol;
12467
12468 uCol = U(wParam);
12469 sItem.mask = 0;
12470 if(pCol->mask & TVCF_FMT) {
12471 sItem.mask |= HDI_FORMAT;
12472 bWantMark = pCol->fmt & TVCFMT_MARK; //memorize if we want the marked state
12473 }
12474 if(pCol->mask & TVCF_IMAGE){
12475 sItem.mask |= HDI_IMAGE;
12476 }
12477 if(pCol->mask & TVCF_WIDTH){
12478 sItem.mask |= HDI_WIDTH;
12479 }
12480 if(pCol->mask & TVCF_TEXT){
12481 sItem.mask |= HDI_TEXT;
12482 sItem.pszText = pCol->pszText;
12483 sItem.cchTextMax = pCol->cchTextMax;
12484 }
12485
12486 lRet = SendMessage(pData->hHeader, HDM_GETITEM, wParam, (LPARAM)&sItem);
12487
12488 pCol->mask = 0;
12489
12490 if(sItem.mask & HDI_FORMAT) {
12491 pCol->mask |= TVCF_FMT;
12492 pCol->fmt = sItem.fmt;
12493
12494 if(bWantMark && pData->aColumn[uCol].bMark)
12495 pCol->fmt |= TVCFMT_MARK;
12496 if(!pData->aColumn[uCol].sReal && pData->aColumn[uCol].sFixed)
12497 pCol->fmt |= TVCFMT_FIXED;
12498 }
12499 if(sItem.mask & HDI_IMAGE){
12500 pCol->mask |= TVCF_IMAGE;
12501 pCol->iImage = sItem.iImage;
12502 }
12503 if(sItem.mask & HDI_WIDTH){
12504 pCol->mask |= TVCF_WIDTH;
12505 pCol->cx = sItem.cxy;
12506 }
12507 if(sItem.mask & HDI_TEXT){
12508 pCol->mask |= TVCF_TEXT;
12509 pCol->pszText = sItem.pszText;
12510 pCol->cchTextMax = sItem.cchTextMax;
12511 }
12512
12513 } else {
12514 lRet = 0;
12515 }
12516
12517 return lRet;
12518
12519 case TVM_SETFOCUSITEM: // Focus einstellen
12520
12521 pData = GetHandle(hWnd);
12522
12523 LOCK(pData);
12524 lRet = TreeListSetFocus(pData, U(lParam), U(wParam));
12525 UNLOCK(pData);
12526
12527 return lRet;
12528
12529 case TVM_SETCOLUMNWIDTH: // Die Spaltenbreite einstellen
12530
12531 pData = GetHandle(hWnd);
12532
12533 if(pData->hHeader && U(wParam) < pData->uColumnCount && (int)lParam >= 0) {
12534 HDITEM sItem;
12535
12536 sItem.mask = HDI_WIDTH;
12537 sItem.cxy = (int)lParam;
12538 lRet = SendMessage(pData->hHeader, HDM_SETITEM, wParam, (LPARAM)&sItem);
12539 } else {
12540 lRet = 0;
12541 }
12542
12543 return lRet;
12544
12545 case TVM_COLUMNAUTOEDIT: // AutoEdit für eine Spalte einstellen
12546
12547 pData = GetHandle(hWnd);
12548 uVal = (wParam >> 11) & 0x3F;
12549
12550 if(uVal >= pData->uColumnCount) {
12551 return 0;
12552 }
12553
12554 uMode = (U(wParam) >> TVAE_MODEPOS) & 7;
12555
12556 if(uMode == TVAX_NONE) {
12557 wParam = 0;
12558 } else
12559 if(uVal == 0 && uMode >= TVAX_CHECK) { // Checkboxes are not allowed in the first column
12560 return 0;
12561 }
12562
12563 LOCK(pData);
12564
12565 uChange = pData->aColumn[uVal].bEdit << TVAE_MODEPOS;
12566 uChange |= pData->aColumn[uVal].bFlags & TVAE_STATEENABLE;
12567
12568 pData->aColumn[uVal].bEdit = (BYTE)(uMode);
12569 pData->aColumn[uVal].bFlags = (BYTE)(wParam);
12570 pData->aColumn[uVal].bCbChar = (BYTE)(wParam >> 17);
12571 pData->aColumn[uVal].bCbSize = (BYTE)(wParam >> 25);
12572 pData->aColumn[uVal].pCbData = (void *)lParam;
12573 pData->aColumn[uVal].iCbIcon = -1;
12574
12575 if(uMode >= TVAX_CHECK) { // Sollen Checkboxen dargestetllt werden
12576 if(!pData->hChecks) {
12579 }
12580
12581 if((uChange ^ wParam) & ((TVAE_MODEMASK ^ TVAE_CHECK ^ TVAE_CHECKED) | TVAE_STATEENABLE)) {
12582 UpdateColRect(pData, uVal);
12583 }
12584 } else
12585 if((uChange & TVAE_MODEMASK) >= TVAE_CHECK) { // Waren Checkboxen dargestetllt
12586 if((uChange ^ wParam) & ((TVAE_MODEMASK ^ TVAE_CHECK ^ TVAE_CHECKED) | TVAE_STATEENABLE)) {
12587 UpdateColRect(pData, uVal);
12588 }
12589 }
12590
12591 UNLOCK(pData);
12592
12593 return 1;
12594
12595 case TVM_COLUMNAUTOICON: // Icons für AutoEdit einstellen
12596
12597 pData = GetHandle(hWnd);
12598 uVal = U(wParam);
12599
12600 if(uVal >= pData->uColumnCount || !pData->aColumn[uVal].bEdit) {
12601 return 0;
12602 }
12603
12604 LOCK(pData);
12605
12606 pData->aColumn[uVal].iCbIcon = (int)lParam;
12607
12608 UNLOCK(pData);
12609
12610 return 1;
12611
12612 case TVM_GETCOLUMNWIDTH: // Die Spaltenbreite abfragen
12613
12614 pData = GetHandle(hWnd);
12615 if(pData->hHeader) {
12616 HDITEM sItem;
12617
12618 sItem.mask = HDI_WIDTH;
12619 sItem.cxy = (int)lParam;
12620 SendMessage(pData->hHeader, HDM_GETITEM, wParam, (LPARAM)&sItem);
12621 lRet = sItem.cxy;
12622 } else {
12623 lRet = 0;
12624 }
12625
12626 return lRet;
12627
12628 case TVM_CREATEDRAGIMAGE: // Ein Drag-Image erzeugen
12629
12630 pData = GetHandle(hWnd);
12631 LOCK(pData);
12633 UNLOCK(pData);
12634 return lRet;
12635
12636 case TVM_ENDEDITLABELNOW: // Die aktuelle Eingabe abbrechen
12637
12638 pData = GetHandle(hWnd);
12639 LOCK(pData);
12640 lRet = (TreeListEndLabelEdit(pData, (wParam) ? 0 : 1)) ? 1 : 0;
12641 UNLOCK(pData);
12642 return 0;
12643
12644 case TVM_GETISEARCHSTRING: // Holt den aktuellen Suchtext
12645
12646 uDelta = GetTickCount() - uKeyLast;
12647
12648 if(!lParam) {
12649 return (uDelta <= 750) ? uKeyPos : 0;
12650 }
12651
12652 if(uDelta > 750) {
12653 ((TCHAR *)lParam)[0] = 0;
12654 return FALSE;
12655 }
12656
12657 memcpy((TCHAR *)lParam, cKeyData, uKeyPos * sizeof(TCHAR));
12658 ((TCHAR *)lParam)[uKeyPos] = 0;
12659 return TRUE;
12660
12661 case TVM_GETUNICODEFORMAT: // Wird gerade UNI-Code verwendet
12662
12663#if UNICODE
12664 return 1;
12665#else
12666 return 0;
12667#endif
12668
12669 }
12670
12671 return DefWindowProc(hWnd, uMsg, wParam, lParam);
12672}
12673
12674
12675//*****************************************************************************
12676//*
12677//* TreeListDraw
12678//*
12679//*****************************************************************************
12680// Zeichnet das Fenster
12681static void TreeListDraw(HWND hWnd, HDC hDc, RECT *pRect) {
12682
12683 COLORREF uEcColor;
12684 COLORREF uEvColor;
12685 COLORREF uBkColor;
12686 COLORREF uBtColor;
12687 COLORREF uOdColor;
12688 COLORREF uOcColor;
12689 COLORREF uFrColor;
12690 COLORREF uInColor;
12691 COLORREF uOldColor;
12692 COLORREF uOutColor;
12693 COLORREF uNextColor;
12694 COLORREF uTempColor;
12695 HRGN hRgnMain;
12696 HRGN aRgn[MAX_COLUMNS + 1];
12697 SIZE sSize;
12698 RECT sRect;
12699 RECT sArea;
12700 RECT sButton;
12702 BaseItem *pTemp;
12704 ExtraItem *pExtra;
12705 LPCTSTR pText;
12706 HIMAGELIST hImgList;
12707 unsigned uTextSize;
12708 unsigned uRgnCount;
12709 unsigned uAutoMask;
12710 unsigned uFirstPos;
12711 unsigned uStyleEx;
12712 unsigned uColMark;
12713 unsigned uColumn;
12714 unsigned uState;
12715 unsigned uStyle;
12716 unsigned uExtra;
12717 unsigned uNext;
12718 unsigned uMark;
12719 unsigned uItem;
12720 unsigned uBits;
12721 unsigned uPos;
12722 unsigned uMax;
12723 int *pOffsets;
12724 int iRnType[MAX_COLUMNS + 1];
12725 int iXscroll;
12726 int iHeight;
12727 int iIndent;
12728 int iDelta;
12729 int iImage;
12730 int iShift;
12731 int iStart;
12732 int iCount;
12733 int iLevel;
12734 int iLast;
12735 int iSize;
12736 int iXpos;
12737 int iYpos;
12738 int iMaxX;
12739 int iAdd;
12740 int i;
12741
12742 pData = GetHandle(hWnd);
12743
12744 LOCK(pData);
12745
12746 GetClientRect(hWnd, &sRect);
12747
12748 if(!pRect)
12749 pRect = &sRect;
12750
12751 iXscroll = -(int)pData->uScrollX;
12752 pOffsets = pData->aColumnXpos;
12753 hRgnMain = CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
12754
12755 uMax = pData->uColumnCount;
12756 if(!uMax) {
12757 aRgn [ 0 ] = CreateRectRgn(sRect.left, sRect.top, sRect.right, sRect.bottom);
12758 iRnType[ 0 ] = CombineRgn(aRgn[0], aRgn[0], hRgnMain, RGN_AND);
12759 uRgnCount = 1;
12760 } else {
12761 for(uPos = 0; uPos < uMax; uPos++) {
12762 uExtra = pData->aColumnPos[uPos ];
12763 uNext = pData->aColumnPos[uPos + 1];
12764 aRgn [uExtra] = CreateRectRgn(sRect.left + pOffsets[uExtra] + iXscroll, sRect.top, sRect.left + pOffsets[uNext] + iXscroll, sRect.bottom);
12765 iRnType[uExtra] = CombineRgn(aRgn[uExtra], aRgn[uExtra], hRgnMain, RGN_AND);
12766 }
12767
12768 aRgn [uPos] = CreateRectRgn(sRect.left + pOffsets[uPos] + iXscroll, sRect.top, sRect.right, sRect.bottom);
12769 iRnType[uPos] = CombineRgn(aRgn[uPos], aRgn[uPos], hRgnMain, RGN_AND);
12770
12771 uRgnCount = uMax + 1;
12772 }
12773
12774 iHeight = pData->iRowHeight;
12775 uStyleEx = pData->uStyleEx;
12776 uStyle = pData->uStyle;
12777 iIndent = pData->iIndent;
12778 iShift = pData->iShift;
12779 uPos = pData->uScrollY;
12780 uMax = pData->uMaxEnties + uPos;
12781 uNext = (pData->uColumnCount <= 1) ? 1 : pData->aColumn[1].bIndex;
12782 uFirstPos = pData->aColumnXpos[uNext];
12783
12784 if(iRnType[0] == NULLREGION)
12785 iMaxX = pData->iMaxSizeX;
12786 else
12787 iMaxX = uFirstPos - 1;
12788
12789 if(uStyleEx & TVS_EX_ITEMLINES) {
12790 iHeight--;
12791 }
12792
12793 if(uStyleEx & TVS_EX_AUTOEXPANDICON) {
12794 uAutoMask = TVIS_EXPANDED;
12795 } else {
12796 uAutoMask = 0;
12797 }
12798
12799 if(uMax > pData->uItemPosCount) {
12800 uMax = pData->uItemPosCount;
12801 }
12802
12803 uBkColor = pData->uColors[TVC_BK ];
12804 uFrColor = pData->uColors[TVC_FRAME];
12805
12806 if(pData->uStyleEx & TVS_EX_ALTERNATECOLOR) { // Abwechselnde Farben
12807 uOdColor = pData->uColors[TVC_ODD ];
12808 uEvColor = pData->uColors[TVC_EVEN ];
12809 uOcColor = pData->uColors[TVC_COLODD ];
12810 uEcColor = pData->uColors[TVC_COLEVEN];
12811 } else {
12812 uOdColor = uBkColor;
12813 uEvColor = uBkColor;
12814 uOcColor = pData->uColors[TVC_COLBK];
12815 uEcColor = pData->uColors[TVC_COLBK];
12816 }
12817
12818 if(!pData->cIsEnabled) // Wenn Fenster gessperrt grau zeichnen
12819 if(pData->uStyleEx & TVS_EX_GRAYEDDISABLE) {
12820 uBkColor = pData->uColors[TVC_GRAYED];
12821 uEvColor = uEcColor;
12822 uOdColor = uOcColor;
12823 }
12824
12825 uInColor = pData->uColors[TVC_LINE];
12826 uBtColor = pData->uColors[TVC_BOX ];
12827 iStart = 0;
12828 iLast = 0;
12829
12830 sArea.top = sRect.top + pData->uStartPixel;
12831 SelectObject(hDc, pData->hFontN);
12833 SetBkColor(hDc, uBkColor);
12834 SetBkMode(hDc, TRANSPARENT);
12835 SetTextAlign(hDc, TA_LEFT | TA_TOP);
12836 SetTextColor(hDc, pData->uColors[TVC_TEXT]);
12837
12838//******************** Einträge zeichnen **************************************
12839 for(; uPos < uMax; uPos++) { // Alle Einträge ausgeben
12840 uItem = pData->pItemPos[uPos];
12841
12842 pEntry = pData->pTreeItems[uItem];
12843 if(!pEntry)
12844 break;
12845
12846 if((pEntry->uState & TVIS_SELECTED) && (uStyleEx & TVS_EX_FULLROWMARK)) {
12847 if(uStyleEx & TVS_EX_ALTERNATECOLOR)
12848 uOutColor = (uPos & 1) ? pData->uColors[TVC_MARKODD] : pData->uColors[TVC_MARKEVEN];
12849 else
12850 uOutColor = pData->uColors[TVC_MARK];
12851
12852 uMark = (unsigned)~TVIS_BKCOLOR;
12853 uColMark = 0;
12854 } else
12855 if(uPos & 1) { // Farbe wechselweise ändern
12856 uColMark = pData->aColumn[0].bMark;
12857 uOutColor = (uColMark) ? uOcColor : uOdColor;
12858 uMark = 0xFFFFFFFF;
12859 } else {
12860 uColMark = pData->aColumn[0].bMark;
12861 uOutColor = (uColMark) ? uEcColor : uEvColor;
12862 uMark = 0xFFFFFFFF;
12863 }
12864
12865 sArea.bottom = sArea.top + pData->iRowHeight;
12866 sArea.left = iXscroll;
12867 iLevel = pEntry->uLevel;
12868
12869 if(iRnType[0] == NULLREGION) {
12870 goto ExtraDraw;
12871 }
12872
12873 uBits = pEntry->uState & 0xFFFF;
12874 uBits |= pEntry->bFlags << 16;
12875 uBits &= uMark;
12876 iImage = (uBits & LVIS_SELECTED) ? pEntry->iSelectedImage : pEntry->iImage;
12877 pText = pEntry->pText;
12878 uTextSize = pEntry->uTextSize;
12879
12880 if(pData->uSelectedSub && uItem == pData->uSelectedItem) {
12881 if(pData->uSelectedCount <= 1 || !(pData->uStyleEx & TVS_EX_SUBSELECT)) {
12882 uBits &= ~TVIS_SELECTED;
12883 }
12884 }
12885
12886 if(pEntry->bCallback) {
12887 CallbackEntry(pData, pEntry, uItem, pEntry->bCallback, &iImage, &uTextSize, &pText);
12888
12889 pEntry = pData->pTreeItems[uItem];
12890 if(!pEntry)
12891 break;
12892 }
12893
12894 SelectObject(hDc, aRgn[0]);
12895
12897 sButton.left = 0;
12898 sButton.right = iIndent * (iLevel + 1) + 2;
12899 sButton.bottom = sArea.bottom + 1;
12900 sButton.top = sArea.bottom - 2;
12901
12902 SetBkColor(hDc, uFrColor);
12903 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL);
12904 }
12905
12906 if(pData->aColumn[0].bMark) { // Ist die erste Spalte markiert
12907 uBkColor = pData->uColors[TVC_COLBK];
12908 }
12909
12910 SetBkColor(hDc, (uStyleEx & TVS_EX_FULLROWITEMS) ? uOutColor : uBkColor);
12911
12912 if(pData->cHasRootRow)
12913 iLevel++;
12914
12915 if(iLevel <= 0)
12916 goto NoRootLines;
12917
12918 if(uStyle & (TVS_HASBUTTONS | TVS_HASLINES)) {
12919 iLevel--;
12920 }
12921
12922 if(uStyleEx & TVS_EX_FULLROWITEMS) {
12923 sArea.bottom--;
12924 iAdd = 1;
12925 } else {
12926 iAdd = 0;
12927 }
12928
12929 if(uStyle & TVS_HASLINES) {
12930 pTemp = pData->pTreeItems[pEntry->uParent];
12931 sArea.right = sArea.left + 1; // Eine leerer Pixelreihe am Anfang
12932 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
12933 sArea.left += iIndent * iLevel + 1;
12934
12935 for(i = iLevel; i > 0; i--) { // Bereich vor Schaltflächen
12936 sArea.right = sArea.left;
12937 sArea.left -= iIndent;
12938
12939 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
12940
12941 iXpos = sArea.left + iShift;
12942
12943 if(pTemp) {
12944 if(pTemp->uNextItem) { // Zeichne vertikale Linien
12945 MoveToEx(hDc, iXpos, sArea.top | 1, NULL);
12946 LineTo(hDc, iXpos, sArea.bottom + iAdd);
12947 }
12948
12949 pTemp = pData->pTreeItems[pTemp->uParent];
12950 }
12951 }
12952
12953 sArea.left += iIndent * iLevel;
12954 } else { // Ohne Linien zeichnen
12955 if(iLevel > 0) {
12956 sArea.right = sArea.left + iIndent * iLevel;
12957 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
12958 sArea.left += sArea.right;
12959 }
12960 }
12961
12962 if(uStyle & TVS_HASBUTTONS) { // Fenster mit Schaltflächen ?
12963 sArea.right = sArea.left + iIndent;
12964 iXpos = sArea.left + iShift;
12965 iYpos = sArea.top + pData->iRowHeight / 2;
12966
12967 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
12968
12969 if(uStyle & TVS_HASLINES) { // Linien unter Schaltflächen
12970 MoveToEx(hDc, iXpos, sArea.top | 1, NULL);
12971
12972 if(pEntry->uNextItem)
12973 LineTo(hDc, iXpos, sArea.bottom + iAdd);
12974 else
12975 LineTo(hDc, iXpos, iYpos + 1);
12976
12977 MoveToEx(hDc, iXpos + 1 + (iYpos & 1), iYpos, NULL);
12978 LineTo(hDc, sArea.right , iYpos);
12979 }
12980
12981 if(pEntry->bFlags & TVIX_HASBUTTON) { // Schaltflächen zeichnen
12982 sButton.left = iXpos - 4;
12983 sButton.top = iYpos - 4;
12984 sButton.right = iXpos + 5;
12985 sButton.bottom = iYpos + 5;
12986
12987 if(pData->cGlyphOk) { // Thema benutzen
12989 pDrawThemeBackg(pData->hTheme, hDc, TVP_GLYPH, uState, &sButton, 0);
12990 } else {
12991 SetBkColor(hDc, uBtColor);
12992 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL);
12993
12994 sButton.left += 1;
12995 sButton.top += 1;
12996 sButton.right -= 1;
12997 sButton.bottom -= 1;
12998
12999 SetBkColor(hDc, pData->uColors[TVC_BOXBG]);
13000 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL);
13001
13002 sButton.left = iXpos - 2;
13003 sButton.top = iYpos ;
13004 sButton.right = iXpos + 3;
13005 sButton.bottom = iYpos + 1;
13006
13007 SetBkColor(hDc, uInColor);
13008 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL);
13009
13010 // '+' statt '-' Schaltfläsche zeichnenen
13011 if((uBits ^ TVIS_EXPANDED) & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) {
13012 sButton.left = iXpos ;
13013 sButton.top = iYpos - 2;
13014 sButton.right = iXpos + 1;
13015 sButton.bottom = iYpos + 3;
13016 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sButton, NULL, 0, NULL);
13017 }
13018 }
13019
13020 SetBkColor(hDc, uBkColor);
13021 }
13022
13023 sArea.left += iIndent;
13024 } else
13025 if(uStyle & TVS_HASLINES) { // Nur Linien zeichnen ohne Schaltflächen
13026 sArea.right = sArea.left + iIndent;
13027 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13028
13029 iYpos = sArea.top + pData->iRowHeight / 2;
13030 iXpos = sArea.left + iShift;
13031 MoveToEx(hDc, iXpos, sArea.top | 1, NULL);
13032
13033 if(pEntry->uNextItem)
13034 LineTo(hDc, iXpos, sArea.bottom);
13035 else
13036 LineTo(hDc, iXpos, iYpos + 1);
13037
13038 MoveToEx(hDc, iXpos + 1 + (iYpos & 1), iYpos, NULL);
13039 LineTo(hDc, sArea.right , iYpos);
13040
13041 sArea.left += iIndent;
13042 }
13043
13044 if(uStyleEx & TVS_EX_FULLROWITEMS)
13045 sArea.bottom++;
13046
13047NoRootLines:
13048
13049 if(uStyleEx & TVS_EX_ITEMLINES) { // Linien um den Eintrag zeichnen
13050 iAdd = 1;
13051 sArea.right = sArea.left + 1;
13052
13053 if(uStyleEx & TVS_EX_FULLROWITEMS) {
13054 iStart = sArea.left;
13055 iAdd = 0;
13056 } else
13057 if(iLevel >= 0) {
13058 SetBkColor(hDc, uFrColor);
13059 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13060
13061 sArea.left++;
13062 sArea.bottom--;
13063 iStart = sArea.left;
13064 } else {
13065 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13066
13067 sArea.left++;
13068 sArea.bottom--;
13069 iStart = sArea.left - 1;
13070 }
13071 } else {
13072 iAdd = 0;
13073 }
13074
13075 SetBkColor(hDc, (uBits & TVIS_BKCOLOR) ? pEntry->uColorBk : uOutColor);
13076 SelectObject(hDc, (uBits & TVIS_BOLD) ? pData->hFontB : pData->hFontN);
13077
13078 if(pData->hStates) { // State-Icons anzeigen
13079 sArea.right = sArea.left + pData->iStatesXsize;
13080 iYpos = sArea.top + (iHeight - pData->iStatesYsize) / 2;
13081 i = (uBits & LVIS_STATEIMAGEMASK) >> 12;
13082
13083 sArea.right += iAdd;
13084 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13085 sArea.left += iAdd;
13086
13087 if(pData->hStates == THEMEIMGLIST) { // Mit Thema zeichnen
13088 if(pData->uStyleEx & TVS_EX_BITCHECKBOX)
13089 i++;
13090
13091 if(i >= 1 && i <= 2) {
13092 uState = (i == 1) ? CBS_UNCHECKEDNORMAL : CBS_CHECKEDNORMAL;
13093 pDrawThemeBackg(pData->hThemeBt, hDc, BP_CHECKBOX, uState, &sArea, 0);
13094 }
13095 } else {
13096 ImageList_Draw(pData->hStates, i, hDc, sArea.left, iYpos, ILD_TRANSPARENT);
13097 }
13098
13099 sArea.left += pData->iStatesXsize;
13100 iAdd = 0;
13101 }
13102
13103 if(pData->hImages && iImage != TV_NOIMAGE) { // Icon zeichnen vom Haupteintrag
13104 if(iImage >= TV_SECONDICON) { // Sub-Image-Liste verwenden
13105 if(iImage & TV_NOAUTOEXPAND) {
13106 iImage &= ~TV_NOAUTOEXPAND; // Kein Auto-Expant bei diesem Icon
13107 } else
13108 if((pEntry->uState & uAutoMask) && pEntry->uFirstChild) {
13109 iImage += 1; // Auto-Expant aktivieren
13110 }
13111
13112 iImage -= TV_SECONDICON;
13113 sArea.right = sArea.left + pData->iSubImgXsize;
13114 iYpos = sArea.top + (iHeight - pData->iSubImgYsize) / 2;
13115 pEntry->bFlags |= TVIX_HASIMAGE;
13116
13117 sArea.right += iAdd;
13118 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13119 sArea.left += iAdd;
13120 ImageList_Draw(pData->hSubImg, iImage, hDc, sArea.left, iYpos, ILD_TRANSPARENT | (uBits & (TVIS_OVERLAYMASK | LVIS_CUT)));
13121
13122 sArea.left += pData->iSubImgXsize;
13123 iAdd = 0;
13124 } else { // Haup-Image-Liste verwenden
13125 if(iImage & TV_NOAUTOEXPAND) {
13126 iImage &= ~TV_NOAUTOEXPAND; // Kein Auto-Expant bei diesem Icon
13127 } else
13128 if((pEntry->uState & uAutoMask) && pEntry->uFirstChild) {
13129 iImage += pData->iAutoAdd; // Auto-Expant aktivieren
13130 }
13131
13132 sArea.right = sArea.left + pData->iImagesXsize;
13133 iYpos = sArea.top + (iHeight - pData->iImagesYsize) / 2;
13134 pEntry->bFlags |= TVIX_HASIMAGE;
13135
13136 sArea.right += iAdd;
13137 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13138 sArea.left += iAdd;
13139 ImageList_Draw(pData->hImages, iImage, hDc, sArea.left, iYpos, ILD_TRANSPARENT | (uBits & (TVIS_OVERLAYMASK | LVIS_CUT)));
13140
13141 sArea.left += pData->iImagesXsize;
13142 iAdd = 0;
13143 }
13144 } else {
13145 pEntry->bFlags &= ~TVIX_HASIMAGE;
13146 }
13147
13148 sArea.right = uFirstPos; // Text ausgeben vom Haupteintrag
13149 iYpos = sArea.top + (iHeight - pData->iFontHeight) / 2;
13150
13152 // Das Feld speziel zeichnen
13153 TCHAR *pPtr = (TCHAR *)new(TCHAR, uTextSize + 4);
13154 INT *pPos = (INT *)new(INT, uTextSize + 4);
13155
13156 ExtTextOut(hDc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, &sArea, NULL, 0, NULL);
13157
13158 sButton.top = iYpos;
13159 sButton.left = sArea.left + 4;
13160 sButton.right = sArea.right;
13161 sButton.bottom = iYpos + pData->iFontHeight + 2;
13162
13163 if(!uTextSize) { // Feld ohne Text ?
13164 sButton.right -= 2;
13165 sButton.bottom--;
13166 pEntry->iTextPixels = 0;
13167 } else {
13168 if(pData->uStyleEx & TVS_EX_FULLROWMARK)
13169 if(pData->cHasFocus == 0 || uItem != pData->uSelectedItem || pData->uSelectedSub)
13170 if((uBits & TVIS_SELECTED) && !(uBits & (TVIS_DROPHILITED | TVIS_FOCUSED))) {
13171 sButton.left -= 1;
13172 }
13173
13174 DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
13175 pEntry->iTextPixels = sButton.right - sButton.left;
13176 }
13177
13178 // Passt der Text in die Spalte
13179 if(sButton.left + pEntry->iTextPixels >= (int)(sArea.right - pData->uScrollX)) {
13180 iSize = sArea.right - pData->uScrollX - sButton.left - 2;
13181 iSize -= (uBits & TVIS_BOLD) ? pData->uTrippleB : pData->uTrippleN;
13182 if(iSize < 3) {
13183 iCount = 0;
13184 } else {
13185 GetTextExtentExPoint(hDc, pText, uTextSize, iSize, &iCount, pPos, &sSize);
13186 }
13187 // Temporären Text mit "..." erzeugen
13188 memcpy(pPtr , pText, iCount * sizeof(TCHAR));
13189 memcpy(pPtr + iCount, _T("..."), 4 * sizeof(TCHAR));
13190
13191 pText = pPtr;
13192 uTextSize = iCount + 3;
13193 sButton.right = sArea.right - 2;
13194 }
13195
13196 // Das Feld selektiert zeichnen
13197 if((uBits & TVIS_SELECTED) && pData->cHasFocus && uItem == pData->uSelectedItem && !pData->uSelectedSub) {
13198 uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT);
13200 Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1);
13201 } else {
13202 if(uBits & TVIS_DROPHILITED) {
13203 uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT);
13206 Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1);
13207 } else
13208 if(uBits & TVIS_SELECTED) { // Ist das Feld ohne Focus ausgewählt
13209 if(pData->cHasFocus) {
13210 uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT);
13213 } else {
13214 if(uBits & TVIS_TEXTCOLOR)
13215 uTempColor = pEntry->uColorText;
13216 else
13217 uTempColor = pData ->uColors[TVC_TEXT];
13218
13219 if(pData->uStyleEx & TVS_EX_FULLROWMARK)
13221 else
13223
13225 }
13226
13227 Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1);
13228 } else { // Das Feld normal zeichnen
13229 if(uBits & TVIS_TRACKED)
13230 uTempColor = pData ->uColors[TVC_TRACK];
13231 else
13232 if(uBits & TVIS_TEXTCOLOR)
13233 uTempColor = pEntry->uColorText;
13234 else
13235 uTempColor = pData ->uColors[TVC_TEXT ];
13236 sButton.right--;
13237 sButton.left --;
13238 }
13239
13241
13242 if(uBits & TVIS_FOCUSED) { // Einen punktierten Rahmen um den Text zeichnen
13244 Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1);
13245 }
13246 }
13247
13248 SetTextColor(hDc, uTempColor);
13249 sButton.left += pData->iFontOff;
13250 DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
13251
13252 if(uBits & (TVIS_UNDERLINE | TVIS_TRACKED)) // Text unterstreichen
13253 if(pText && *pText) {
13254 sButton.left -= pData->iFontOff;
13255 sButton.right -= pData->iFontOff + 1;
13256 sButton.top += pData->iFontLine;
13257 sButton.bottom = sButton.top + 1;
13258 uOldColor = SetBkColor(hDc, uTempColor);
13259 ExtTextOut(hDc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, &sButton, NULL, 0, NULL);
13260 SetBkColor(hDc, uOldColor);
13261 }
13262
13263 SetTextColor(hDc, pData->uColors[TVC_TEXT]);
13264
13265 delete(pPos);
13266 delete(pPtr);
13267 } else { // Das Feld normal ausgeben
13268 if(!pEntry->iTextPixels && uTextSize) {
13269 sButton.top = iYpos;
13270 sButton.left = sArea.left + 4;
13271 sButton.right = sArea.right;
13272 sButton.bottom = iYpos + pData->iFontHeight + 2;
13273 // Textbreite berechen
13274 DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
13275
13276 pEntry->iTextPixels = sButton.right - sButton.left;
13277 }
13278
13279 // Ist der Text größer als die Spalte
13280 if(sArea.left + pEntry->iTextPixels >= (int)(sArea.right - pData->uScrollX)) {
13281 INT *pPos = (INT *)new(INT, uTextSize);
13282
13283 iSize = sArea.right - sArea.left - pData->uScrollX;
13284 iSize -= (uBits & TVIS_BOLD) ? pData->uTrippleB : pData->uTrippleN;
13285 if(iSize < 3) {
13286 iCount = 0;
13287 } else {
13288 GetTextExtentExPoint(hDc, pText, uTextSize, iSize, &iCount, pPos, &sSize);
13289 }
13290
13291 if(iCount > 0) { // Passen noch Buchstaben vor "..."
13292 sButton.right = sArea.right;
13293 sArea.right = sArea.left + 2 + pPos[iCount - 1];
13294
13295 ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, iCount, NULL);
13296
13297 sArea.left = sArea.right;
13298 sArea.right = sButton.right;
13299
13300 ExtTextOut(hDc, sArea.left , iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, _T("..."), 3, NULL);
13301 } else {
13302 ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, _T("..."), 3, NULL);
13303 }
13304
13305 delete(pPos);
13306 } else {
13307 ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, uTextSize, NULL);
13308 }
13309 }
13310
13311 i = sArea.left - iXscroll;
13312 i += pEntry->iTextPixels + 5;
13313 if(i > iMaxX)
13314 iMaxX = i;
13315
13316 if(uStyleEx & TVS_EX_ITEMLINES) { // Linien um den Eintrag zeichnen
13317 SetBkColor(hDc, uFrColor);
13318
13319 if(iLast > iStart) { // Ist das Feld nach links eingerückt gegenüber dem oberen
13320 sArea.top--;
13321 sArea.bottom = sArea.top + 1;
13322 sArea.left = iStart - 1;
13323 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13324 sArea.top++;
13325 }
13326
13327 iLast = iStart; // Linie unter Feld zeichnen
13328 sArea.top += iHeight;
13329 sArea.left = iStart;
13330 sArea.bottom = sArea.top + 1;
13331
13332 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13333
13334 sArea.top -= iHeight;
13335 }
13336
13337 //************ Extraeinträge zeichnen *********************************
13338
13339ExtraDraw:
13340
13341 uNextColor = uOutColor; // Hintergrundfarbe für die nächste Spalte
13342
13343 if(pData->aColumn[0].bMark) { // Ist die erste Spalte markiert
13344 uBkColor = pData->uColors[TVC_BK];
13345 }
13346
13347 for(uColumn = 1; uColumn <= pData->uColumnCount; uColumn++) { // Extra Spalten zeichnen
13348 uExtra = pData->aColumnPos[uColumn ];
13349 uNext = pData->aColumnPos[uColumn + 1];
13350
13351 if(pData->aColumn[uExtra].sReal == 0) // Ist die Spalte sichtbar
13352 if(uColumn < pData->uColumnCount) {
13353 continue;
13354 }
13355
13356 if(uColMark != pData->aColumn[uExtra].bMark) // Ist die Spalte anderst markiert
13357 if(!(pEntry->uState & TVIS_SELECTED) || !(uStyleEx & TVS_EX_FULLROWMARK)) {
13358 if(uPos & 1) {
13359 uColMark = pData->aColumn[uExtra].bMark;
13360 uOutColor = (uColMark) ? uOcColor : uOdColor;
13361 } else {
13362 uColMark = pData->aColumn[uExtra].bMark;
13363 uOutColor = (uColMark) ? uEcColor : uEvColor;
13364 }
13365 }
13366
13367 GetRgnBox(aRgn[uExtra], &sButton);
13368
13369 if(iRnType[uExtra] == NULLREGION)
13370 continue;
13371
13372 SelectObject(hDc, aRgn[uExtra]);
13373
13374 sArea.left = pData->aColumnXpos[uExtra];
13375 sArea.left += iXscroll;
13376
13377 if(uStyleEx & TVS_EX_ITEMLINES) { // Linie um den Eintrag zeichnen
13378 SetBkColor(hDc, uFrColor);
13379 // Linke Linie
13380 sArea.right = sArea.left + 1;
13381 sArea.bottom += 1;
13382
13383 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13384
13385 sArea.left += 1; // Untere Linie
13386 sArea.top += iHeight;
13387 sArea.bottom = sArea.top + 1;
13388 sArea.right = pData->aColumnXpos[uNext];
13389 if(uColumn < pData->uColumnCount)
13390 sArea.right += iXscroll;
13391
13392 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13393
13394 sArea.top -= iHeight;
13395 sArea.bottom -= 1;
13396 iAdd = 1;
13397 }
13398
13399 if(sArea.left > (int)pData->uSizeX)
13400 break; // Noch im sichtbaren Bereich
13401
13402 sArea.right = pData->aColumnXpos[uNext];
13403
13404 if(uColumn < pData->uColumnCount) { // Ist es die letze Spalte ?
13405 sArea.right += iXscroll;
13406 pExtra = pData->pExtraItems[uExtra - 1][uItem];
13407 if(!pExtra)
13408 uNextColor = uOutColor;
13409 } else {
13410 pExtra = 0;
13411 }
13412
13413 if(!pExtra) { // Leeres Feld zeichnen
13414 SetBkColor(hDc, uNextColor);
13415 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13416 } else {
13417 iSize = pData->iSubImgXsize;
13418 hImgList = pData->hSubImg;
13419 iImage = pExtra->iImage;
13420 pText = pExtra->pText;
13421 uTextSize = pExtra->uTextSize;
13422 uBits = (pExtra->uState & 0xFFFF);
13423 uBits |= (pExtra->bFlags << 16);
13424 uBits |= pEntry->uState & TVIS_BASEFLAGS;
13425 uBits &= uMark;
13426
13427 if(uExtra != pData->uSelectedSub) {
13428 uBits &= ~TVIS_SELECTED;
13429 }
13430
13431 if(pExtra->bCallback) { // Text über Callback holen
13432 CallbackExtra(pData, pEntry, pExtra, uItem, uExtra, pExtra->bCallback, &iImage, &uTextSize, &pText);
13433 pExtra = pData->pExtraItems[uExtra - 1][uItem];
13434 if(!pExtra)
13435 break;
13436 }
13437
13438 uNextColor = (uBits & TVIS_BKCOLOR) ? pExtra->uColorBk : uOutColor;
13439 SetBkColor(hDc, uNextColor);
13440
13441 if(pData->aColumn[uExtra].bEdit >= TVAX_CHECK) { // Checkboxen statt Icons
13442 hImgList = pData->hChecks;
13443 iSize = pData->iChecksXsize;
13444 iImage = (pExtra->uState & TVIS_STATEIMAGEMASK) >> 12;
13445 uBits &= ~TVIS_OVERLAYMASK;
13446
13447 if(iImage & 8)
13448 if(pData->aColumn[uExtra].bFlags & TVAE_STATEENABLE) {
13449 iImage &= 7;
13450 }
13451 }
13452
13453 if(hImgList && iImage > TV_NOIMAGE) { // Icon zeichnen
13454 sArea.right = sArea.left + iSize + 2;
13455 iYpos = sArea.top + (iHeight - iSize) / 2;
13456 pExtra->bFlags |= TVIX_HASIMAGE;
13457
13458 SelectObject(hDc, (uBits & TVIS_BOLD) ? pData->hFontB : pData->hFontN);
13459 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sArea, NULL, 0, NULL);
13460
13461 if(hImgList == THEMEIMGLIST) { // Mit Thema zeichnen
13462 if(pData->uStyleEx & TVS_EX_BITCHECKBOX)
13463 iImage++;
13464
13465 if(iImage == 1 || iImage == 2) {
13466 uState = (iImage == 1) ? CBS_UNCHECKEDNORMAL : CBS_CHECKEDNORMAL;
13467 pDrawThemeBackg(pData->hThemeBt, hDc, BP_CHECKBOX, uState, &sArea, 0);
13468 }
13469 } else {
13470 ImageList_Draw(hImgList, iImage, hDc, sArea.left + 1, iYpos, ILD_TRANSPARENT | (uBits & (TVIS_OVERLAYMASK | LVIS_CUT)));
13471 }
13472
13473 sArea.left += iSize + 1;
13474 sArea.right = pData->aColumnXpos[uNext];
13475 sArea.right += iXscroll;
13476 } else {
13477 pExtra->bFlags &= ~TVIX_HASIMAGE;
13478 }
13479
13480 iYpos = sArea.top + (iHeight - pData->iFontHeight) / 2;
13481 SelectObject(hDc, (uBits & TVIS_BOLD) ? pData->hFontB : pData->hFontN);
13482
13484 // Text ausgeben in spezilem Format
13485 TCHAR *pPtr = (TCHAR *)new(TCHAR, uTextSize + 4);
13486 INT *pPos = (INT *)new(INT, uTextSize + 4);
13487
13488 ExtTextOut(hDc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, &sArea, NULL, 0, NULL);
13489
13490 sButton.top = iYpos;
13491 sButton.left = sArea.left + 4;
13492 sButton.right = sArea.right;
13493 sButton.bottom = iYpos + pData->iFontHeight + 2;
13494
13495 if(!uTextSize) {
13496 sButton.left--;
13497 sButton.right -= 2;
13498 sButton.bottom--;
13499 pExtra->iTextPixels = 0;
13500 } else {
13501 if(pData->uStyleEx & TVS_EX_FULLROWMARK)
13502 if(pData->cHasFocus == 0 || uItem != pData->uSelectedItem)
13503 if((uBits & TVIS_SELECTED) && !(uBits & (TVIS_DROPHILITED | TVIS_FOCUSED))) {
13504 sButton.left -= 2;
13505 }
13506
13507 DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
13508 pExtra->iTextPixels = sButton.right - sButton.left;
13509 }
13510
13511 // Passt der Text in die Spalte
13512 if(sButton.left + pExtra->iTextPixels >= sArea.right) {
13513 if(uTextSize > 253)
13514 uTextSize = 253;
13515
13516 iSize = sArea.right - sButton.left - 2;
13517 iSize -= (uBits & TVIS_BOLD) ? pData->uTrippleB : pData->uTrippleN;
13518 if(iSize < 3) {
13519 iCount = 0;
13520 } else {
13521 GetTextExtentExPoint(hDc, pText, uTextSize, iSize, &iCount, pPos, &sSize);
13522 }
13523
13524 memcpy(pPtr , pText, iCount * sizeof(TCHAR));
13525 memcpy(pPtr + iCount, _T("..."), 4 * sizeof(TCHAR));
13526
13527 pText = pPtr;
13528 uTextSize = iCount + 3;
13529 sButton.right = sArea.right - 2;
13530 }
13531
13532 switch(pData->aColumn[uExtra].bAlign) { // Textausrichtung ausgleichen
13533 case DT_CENTER:
13534 iDelta = sArea .right - sArea .left;
13535 iDelta -= sButton.right - sButton.left;
13536 iDelta -= 6;
13537 iDelta /= 2;
13538 sButton.right += iDelta;
13539 sButton.left += iDelta;
13540 break;
13541
13542 case DT_RIGHT:
13543 iDelta = sArea .right - sArea .left;
13544 iDelta -= sButton.right - sButton.left;
13545 iDelta -= 6;
13546 sButton.right += iDelta;
13547 sButton.left += iDelta;
13548 break;
13549
13550 }
13551 // Ist das Feld ohne Focus ausgewählt
13552 if((uBits & TVIS_SELECTED) && pData->cHasFocus && uItem == pData->uSelectedItem) {
13553 uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT);
13555 Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1);
13556 } else {
13557 if(uBits & TVIS_DROPHILITED) {
13558 uTempColor = GetSysColor(COLOR_HIGHLIGHTTEXT);
13561 Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1);
13562 } else
13563 if(uBits & TVIS_SELECTED && uItem == pData->uSelectedItem) {
13564 if(uBits & TVIS_TEXTCOLOR)
13565 uTempColor = pEntry->uColorText;
13566 else
13567 uTempColor = pData->uColors[TVC_TEXT];
13568
13569 if(pData->uStyleEx & TVS_EX_FULLROWMARK)
13571 else
13573
13575 Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1);
13576 } else {
13577 if(uBits & TVIS_TRACKED)
13578 uTempColor = pData ->uColors[TVC_TRACK];
13579 else
13580 if(uBits & TVIS_TEXTCOLOR)
13581 uTempColor = pExtra->uColorText;
13582 else
13583 uTempColor = pData ->uColors[TVC_TEXT ];
13584 sButton.right--;
13585 sButton.left --;
13586 }
13587
13589
13590 if(uBits & TVIS_FOCUSED) { // Punktierten Rahmen um Text zeichnen
13592 Rectangle(hDc, sButton.left - 2, sButton.top - 1, sButton.right + 2, sButton.bottom + 1);
13593 }
13594 }
13595
13596 SetTextColor(hDc, uTempColor);
13597 sButton.left += pData->iFontOff;
13598
13599 DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
13600
13601 if(uBits & (TVIS_UNDERLINE | TVIS_TRACKED)) // Text unterstreichen
13602 if(pText && *pText) {
13603 sButton.left -= pData->iFontOff;
13604 sButton.right -= pData->iFontOff + 1;
13605 sButton.top += pData->iFontLine;
13606 sButton.bottom = sButton.top + 1;
13607 uOldColor = SetBkColor(hDc, uTempColor);
13608 ExtTextOut(hDc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, &sButton, NULL, 0, NULL);
13609 SetBkColor(hDc, uOldColor);
13610 }
13611
13612 SetTextColor(hDc, pData->uColors[TVC_TEXT]);
13613
13614 delete(pPos);
13615 delete(pPtr);
13616 } else { // Den Text ganz normal ausgeben
13617 if(!pExtra->iTextPixels) {
13618 sButton.top = iYpos;
13619 sButton.left = sArea.left + 4;
13620 sButton.right = sArea.right;
13621 sButton.bottom = iYpos + pData->iFontHeight + 2;
13622
13623 if(uTextSize) { // Textbreite berechen
13624 DrawText(hDc, pText, uTextSize, &sButton, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
13625 pExtra->iTextPixels = sButton.right - sButton.left;
13626 } else {
13627 pExtra->iTextPixels = 0;
13628 }
13629 }
13630 // Ist der Text größer als die Spalte
13631 if(sArea.left + pExtra->iTextPixels >= sArea.right) {
13632 INT *pPos = (INT *)new(INT, uTextSize);
13633
13634 iSize = sArea.right - sArea.left;
13635 iSize -= (uBits & TVIS_BOLD) ? pData->uTrippleB : pData->uTrippleN;
13636 if(iSize < 3) {
13637 iCount = 0;
13638 } else {
13639 GetTextExtentExPoint(hDc, pText, uTextSize, iSize, &iCount, pPos, &sSize);
13640 }
13641
13642 if(iCount > 0) { // Passen noch Buchstaben vor "..."
13643 sButton.right = sArea.right;
13644 sArea.right = sArea.left + 2 + pPos[iCount - 1];
13645
13646 ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, iCount, NULL);
13647
13648 sArea.left = sArea.right;
13649 sArea.right = sButton.right;
13650
13651 ExtTextOut(hDc, sArea.left , iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, _T("..."), 3, NULL);
13652 } else {
13653 ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, _T("..."), 3, NULL);
13654 }
13655
13656 delete(pPos);
13657 } else {
13658 switch(pData->aColumn[uExtra].bAlign) { // Textausrichtung
13659 case DT_CENTER:
13661 ExtTextOut(hDc, (sArea.right + sArea.left) / 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, uTextSize, NULL);
13662 SetTextAlign(hDc, TA_LEFT | TA_TOP);
13663 break;
13664
13665 case DT_RIGHT:
13667 ExtTextOut(hDc, sArea.right - 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, uTextSize, NULL);
13668 SetTextAlign(hDc, TA_LEFT | TA_TOP);
13669 break;
13670
13671 default
13672 :
13673 ExtTextOut(hDc, sArea.left + 2, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sArea, pText, uTextSize, NULL);
13674 break;
13675 }
13676 }
13677 }
13678 }
13679 }
13680
13681 sArea.top += pData->iRowHeight;
13682 }
13683
13684 if(sArea.top < sRect.bottom) { // Untere Fläche ohne Einträge füllen
13685 SelectObject(hDc, hRgnMain);
13686
13687 // Gibt es markierte Spalten
13688 if(pData->uMarkedCols > 0 && (pData->cIsEnabled || !(pData->uStyleEx & TVS_EX_GRAYEDDISABLE))) {
13689 sRect.right = 0 - pData->uScrollX;
13690
13691 for(uColumn = 0; uColumn < pData->uColumnCount; uColumn++) {
13692 uExtra = pData->aColumnPos[uColumn ];
13693 uNext = pData->aColumnPos[uColumn + 1];
13694 uMark = pData->aColumn[uExtra].bMark;
13695 sRect.top = sArea.top;
13696 sRect.left = sRect.right;
13697 sRect.right = pData->aColumnXpos[uNext] + uMark;
13698 sRect.right -= pData->uScrollX;
13699 if(sRect.right == sRect.left + 1)
13700 uMark = 0;
13701 SetBkColor(hDc, (uMark) ? pData->uColors[TVC_COLBK] : uBkColor);
13702 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sRect, NULL, 0, NULL);
13703 }
13704
13705 sRect.top = sArea.top;
13706 sRect.left = sRect.right;
13707 sRect.right = pData->uSizeX;
13708 SetBkColor(hDc, uBkColor);
13709 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sRect, NULL, 0, NULL);
13710 } else { // Keine markierten Spalten
13711 sRect.top = sArea.top;
13712 SetBkColor(hDc, uBkColor);
13713 ExtTextOut(hDc, 0, 0, ETO_OPAQUE, &sRect, NULL, 0, NULL);
13714 }
13715 }
13716
13717 if(pData->iMaxSizeX != iMaxX) { // X-Scrollbar aktuallisieren
13718 pData->iMaxSizeX = iMaxX;
13719 if(pData->uColumnCount == 0)
13720 if(pData->iMaxSizeX != (int)pData->uOldXCount) {
13722 }
13723 }
13724
13725 UNLOCK(pData);
13726
13727 DeleteObject(hRgnMain);
13728
13729 for(uPos = 0; uPos < uRgnCount; uPos++) {
13730 DeleteObject(aRgn[uPos]);
13731 }
13732
13733}
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define VOID
Definition: acefi.h:82
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
HWND hWnd
Definition: settings.c:17
HFONT hFont
Definition: main.c:53
HINSTANCE hInstance
Definition: charmap.c:19
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT uFlags
Definition: api.c:59
BOOL WINAPI ImageList_Draw(HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
Definition: imagelist.c:1228
BOOL WINAPI ImageList_GetImageInfo(HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
Definition: imagelist.c:2088
BOOL WINAPI ImageList_Destroy(HIMAGELIST himl)
Definition: imagelist.c:928
INT WINAPI ImageList_AddMasked(HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
Definition: imagelist.c:563
HIMAGELIST WINAPI ImageList_Create(INT cx, INT cy, UINT flags, INT cInitial, INT cGrow)
Definition: imagelist.c:804
#define CloseHandle
Definition: compat.h:739
HANDLE HWND
Definition: compat.h:19
#define GetProcAddress(x, y)
Definition: compat.h:753
#define CALLBACK
Definition: compat.h:35
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
unsigned char
Definition: typeof.h:29
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
#define BI_RGB
Definition: precomp.h:47
#define RGB(r, g, b)
Definition: precomp.h:62
#define abs(i)
Definition: fconv.c:206
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
FxChildList * pList
FxObject * pParent
Definition: fxdpcapi.cpp:86
PLIST_ENTRY pEntry
Definition: fxioqueue.cpp:4484
pKey DeleteObject()
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
int iLine
Definition: hpp.c:35
void WINAPI SHIM_OBJ_NAME() OutputDebugStringA(LPCSTR lpOutputString)
Definition: ignoredbgout.c:18
#define _tcscmp
Definition: tchar.h:1424
#define TEXT(s)
Definition: k32.h:26
HWND hList
Definition: livecd.c:10
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define sprintf(buf, format,...)
Definition: sprintf.c:55
static LPSTR pName
Definition: security.c:75
static HBITMAP
Definition: button.c:44
static HDC
Definition: imagelist.c:92
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
static HRGN INT iCode
Definition: mapping.c:33
static unsigned(__cdecl *hash_bstr)(bstr_t s)
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
static int int const SCRIPT_CONTROL const SCRIPT_STATE SCRIPT_ITEM * pItems
Definition: usp10.c:62
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
unsigned int UINT
Definition: ndis.h:50
#define BOOL
Definition: nt_native.h:43
#define DWORD
Definition: nt_native.h:44
#define LPVOID
Definition: nt_native.h:45
_In_ UINT iPoint
Definition: ntgdi.h:2197
#define L(x)
Definition: ntvdm.h:50
#define LRESULT
Definition: ole.h:14
#define LOWORD(l)
Definition: pedump.c:82
#define WS_CHILD
Definition: pedump.c:617
#define WS_BORDER
Definition: pedump.c:625
#define WS_POPUP
Definition: pedump.c:616
#define WS_VSCROLL
Definition: pedump.c:627
#define ES_AUTOHSCROLL
Definition: pedump.c:672
#define WS_VISIBLE
Definition: pedump.c:620
long LONG
Definition: pedump.c:60
#define WS_DISABLED
Definition: pedump.c:621
#define ES_LEFT
Definition: pedump.c:664
#define ES_CENTER
Definition: pedump.c:665
#define ES_RIGHT
Definition: pedump.c:666
int(CALLBACK * PFNTVCOMPARE)(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
Definition: commctrl.h:3608
#define TVSIL_STATE
Definition: commctrl.h:3444
#define TVM_GETCOUNT
Definition: commctrl.h:3431
#define TVN_ITEMEXPANDED
Definition: commctrl.h:3739
#define I_IMAGECALLBACK
Definition: commctrl.h:2385
#define TVN_DELETEITEM
Definition: commctrl.h:3742
#define TVM_CREATEDRAGIMAGE
Definition: commctrl.h:3538
#define NM_RDBLCLK
Definition: commctrl.h:134
#define TVHT_TORIGHT
Definition: commctrl.h:3535
#define TVHT_NOWHERE
Definition: commctrl.h:3524
#define HDS_BUTTONS
Definition: commctrl.h:629
#define TVN_SELCHANGED
Definition: commctrl.h:3735
#define TVE_COLLAPSERESET
Definition: commctrl.h:3426
#define TVHT_BELOW
Definition: commctrl.h:3534
#define TVS_TRACKSELECT
Definition: commctrl.h:3256
#define TVN_BEGINDRAG
Definition: commctrl.h:3740
#define TVN_KEYDOWN
Definition: commctrl.h:3713
#define NMTTDISPINFO
Definition: commctrl.h:1914
#define TVGN_PARENT
Definition: commctrl.h:3455
#define WC_HEADER
Definition: commctrl.h:626
#define LPTV_HITTESTINFO
Definition: commctrl.h:3515
#define TVM_GETTOOLTIPS
Definition: commctrl.h:3560
#define TVS_LINESATROOT
Definition: commctrl.h:3249
#define TVI_LAST
Definition: commctrl.h:3370
#define HDM_SETITEM
Definition: commctrl.h:756
#define TVHT_ABOVE
Definition: commctrl.h:3533
#define HDN_ENDTRACK
Definition: commctrl.h:872
#define TVM_SORTCHILDRENCB
Definition: commctrl.h:3547
#define HDI_TEXT
Definition: commctrl.h:704
#define TVIF_TEXT
Definition: commctrl.h:3266
#define HDN_DIVIDERDBLCLICK
Definition: commctrl.h:870
#define HDN_BEGINTRACK
Definition: commctrl.h:871
#define TVHT_ONITEM
Definition: commctrl.h:3527
#define TVGN_FIRSTVISIBLE
Definition: commctrl.h:3457
#define NM_DBLCLK
Definition: commctrl.h:131
#define HDF_CENTER
Definition: commctrl.h:715
#define TVN_BEGINLABELEDIT
Definition: commctrl.h:3743
#define NMTVDISPINFO
Definition: commctrl.h:3675
#define ILC_COLORDDB
Definition: commctrl.h:353
#define TVM_ENDEDITLABELNOW
Definition: commctrl.h:3550
#define Header_SetItem(hwndHD, i, phdi)
Definition: commctrl.h:758
#define TVGN_PREVIOUSVISIBLE
Definition: commctrl.h:3459
#define TVM_GETISEARCHSTRING
Definition: commctrl.h:3556
#define HDF_RIGHT
Definition: commctrl.h:714
#define TVIF_IMAGE
Definition: commctrl.h:3267
#define TV_SORTCB
Definition: commctrl.h:3611
#define TVE_EXPANDPARTIAL
Definition: commctrl.h:3425
#define TVM_GETITEMRECT
Definition: commctrl.h:3428
#define TVIS_EXPANDEDONCE
Definition: commctrl.h:3285
#define TVGN_LASTVISIBLE
Definition: commctrl.h:3462
#define Header_GetOrderArray(hwnd, iCount, lpi)
Definition: commctrl.h:807
#define TVM_SETTEXTCOLOR
Definition: commctrl.h:3577
#define TVHT_ONITEMINDENT
Definition: commctrl.h:3528
#define TVSIL_NORMAL
Definition: commctrl.h:3443
#define TVM_GETUNICODEFORMAT
Definition: commctrl.h:3568
#define TVIS_BOLD
Definition: commctrl.h:3283
struct _IMAGELIST * HIMAGELIST
Definition: commctrl.h:324
#define Header_SetOrderArray(hwnd, iCount, lpi)
Definition: commctrl.h:810
#define TVM_GETITEMHEIGHT
Definition: commctrl.h:3573
#define TVC_BYMOUSE
Definition: commctrl.h:3651
#define Header_InsertItem(hwndHD, i, phdi)
Definition: commctrl.h:741
#define TVHT_ONITEMBUTTON
Definition: commctrl.h:3529
#define TVI_FIRST
Definition: commctrl.h:3369
#define HDN_BEGINDRAG
Definition: commctrl.h:855
#define TVS_SHOWSELALWAYS
Definition: commctrl.h:3252
#define TV_HITTESTINFO
Definition: commctrl.h:3516
#define HDI_WIDTH
Definition: commctrl.h:702
#define TVIS_SELECTED
Definition: commctrl.h:3280
#define TVS_FULLROWSELECT
Definition: commctrl.h:3259
#define TVN_SETDISPINFO
Definition: commctrl.h:3737
#define HDN_TRACK
Definition: commctrl.h:873
struct _TREEITEM * HTREEITEM
Definition: commctrl.h:3264
#define TTN_GETDISPINFO
Definition: commctrl.h:1878
#define TVHT_ONITEMLABEL
Definition: commctrl.h:3526
#define NM_CLICK
Definition: commctrl.h:130
#define Header_DeleteItem(hwndHD, i)
Definition: commctrl.h:744
#define TVN_ENDLABELEDIT
Definition: commctrl.h:3744
#define NM_KILLFOCUS
Definition: commctrl.h:136
#define TVS_HASLINES
Definition: commctrl.h:3248
#define LPSTR_TEXTCALLBACK
Definition: commctrl.h:2383
#define TVE_EXPAND
Definition: commctrl.h:3423
#define HDS_DRAGDROP
Definition: commctrl.h:632
#define TVGN_PREVIOUS
Definition: commctrl.h:3454
#define TVM_SETINSERTMARKCOLOR
Definition: commctrl.h:3587
#define TV_INSERTSTRUCT
Definition: commctrl.h:3377
#define TVI_ROOT
Definition: commctrl.h:3368
#define INFOTIPSIZE
Definition: commctrl.h:124
#define TVIS_CUT
Definition: commctrl.h:3281
#define TVHT_ONITEMSTATEICON
Definition: commctrl.h:3531
#define TOOLTIPS_CLASS
Definition: commctrl.h:1710
#define TVS_NONEVENHEIGHT
Definition: commctrl.h:3261
#define TVM_GETEDITCONTROL
Definition: commctrl.h:3506
#define TVS_CHECKBOXES
Definition: commctrl.h:3255
#define TVE_TOGGLE
Definition: commctrl.h:3424
#define TVS_NOSCROLL
Definition: commctrl.h:3260
#define TVM_GETTEXTCOLOR
Definition: commctrl.h:3581
#define TVM_DELETEITEM
Definition: commctrl.h:3414
#define TVHT_ONITEMRIGHT
Definition: commctrl.h:3530
#define HDN_ENDDRAG
Definition: commctrl.h:856
#define TVM_SORTCHILDREN
Definition: commctrl.h:3541
#define TTM_TRACKPOSITION
Definition: commctrl.h:1813
#define TTF_IDISHWND
Definition: commctrl.h:1764
#define ILD_TRANSPARENT
Definition: commctrl.h:418
#define HDM_SETIMAGELIST
Definition: commctrl.h:794
#define NMTREEVIEW
Definition: commctrl.h:3642
#define HDN_ITEMCLICK
Definition: commctrl.h:868
#define TVGN_DROPHILITE
Definition: commctrl.h:3460
#define TVM_SETBKCOLOR
Definition: commctrl.h:3575
#define TVM_SETINSERTMARK
Definition: commctrl.h:3564
#define TVIS_DROPHILITED
Definition: commctrl.h:3282
#define LVIS_SELECTED
Definition: commctrl.h:2319
#define I_CHILDRENCALLBACK
Definition: commctrl.h:3293
#define TVC_UNKNOWN
Definition: commctrl.h:3650
#define TV_ITEM
Definition: commctrl.h:3300
#define NM_RETURN
Definition: commctrl.h:132
#define TVM_GETVISIBLECOUNT
Definition: commctrl.h:3509
#define HDF_STRING
Definition: commctrl.h:720
#define TVM_SELECTITEM
Definition: commctrl.h:3478
#define TVM_INSERTITEM
Definition: commctrl.h:3410
#define TVM_EDITLABEL
Definition: commctrl.h:3502
#define TVIS_STATEIMAGEMASK
Definition: commctrl.h:3288
#define HDI_FORMAT
Definition: commctrl.h:705
#define TVM_SETITEM
Definition: commctrl.h:3495
#define TVIF_HANDLE
Definition: commctrl.h:3270
#define TVGN_ROOT
Definition: commctrl.h:3452
#define NMHEADER
Definition: commctrl.h:894
#define TVE_COLLAPSE
Definition: commctrl.h:3422
#define TVGN_NEXTVISIBLE
Definition: commctrl.h:3458
#define HDS_HORZ
Definition: commctrl.h:628
#define TVGN_CHILD
Definition: commctrl.h:3456
#define TVIS_EXPANDED
Definition: commctrl.h:3284
#define TVIS_EXPANDPARTIAL
Definition: commctrl.h:3286
#define TVN_SELCHANGING
Definition: commctrl.h:3734
#define TVN_GETINFOTIP
Definition: commctrl.h:3771
#define TVC_BYKEYBOARD
Definition: commctrl.h:3652
#define TVM_ENSUREVISIBLE
Definition: commctrl.h:3544
#define TVM_SETIMAGELIST
Definition: commctrl.h:3446
#define TVM_SETINDENT
Definition: commctrl.h:3437
#define TTF_ABSOLUTE
Definition: commctrl.h:1769
#define NM_RCLICK
Definition: commctrl.h:133
#define NM_SETFOCUS
Definition: commctrl.h:135
#define TVIS_OVERLAYMASK
Definition: commctrl.h:3287
#define TVN_ITEMEXPANDING
Definition: commctrl.h:3738
#define TVGN_CARET
Definition: commctrl.h:3461
#define TVS_HASBUTTONS
Definition: commctrl.h:3247
#define ILC_MASK
Definition: commctrl.h:351
#define TVM_HITTEST
Definition: commctrl.h:3512
#define TVS_NOTOOLTIPS
Definition: commctrl.h:3254
#define TVM_GETIMAGELIST
Definition: commctrl.h:3440
#define TVS_DISABLEDRAGDROP
Definition: commctrl.h:3251
#define TVM_GETINSERTMARKCOLOR
Definition: commctrl.h:3589
#define TVM_GETBKCOLOR
Definition: commctrl.h:3579
#define TVI_SORT
Definition: commctrl.h:3371
#define TVHT_ONITEMICON
Definition: commctrl.h:3525
#define TVS_SINGLEEXPAND
Definition: commctrl.h:3257
#define HDN_ITEMCHANGED
Definition: commctrl.h:867
#define TVIF_PARAM
Definition: commctrl.h:3268
#define TVS_EDITLABELS
Definition: commctrl.h:3250
#define HDI_IMAGE
Definition: commctrl.h:708
#define TVIF_CHILDREN
Definition: commctrl.h:3272
#define TTM_ADDTOOL
Definition: commctrl.h:1839
#define TTF_TRACK
Definition: commctrl.h:1768
#define TOOLINFO
Definition: commctrl.h:1718
#define LVIS_STATEIMAGEMASK
Definition: commctrl.h:2326
#define TVS_RTLREADING
Definition: commctrl.h:3253
#define HDITEM
Definition: commctrl.h:697
#define TVN_GETDISPINFO
Definition: commctrl.h:3736
#define NMTVGETINFOTIP
Definition: commctrl.h:3772
#define TVM_GETINDENT
Definition: commctrl.h:3434
#define HDN_ITEMDBLCLICK
Definition: commctrl.h:869
#define TTM_TRACKACTIVATE
Definition: commctrl.h:1812
#define HDM_GETITEM
Definition: commctrl.h:749
#define TVIF_SELECTEDIMAGE
Definition: commctrl.h:3271
#define TVHT_TOLEFT
Definition: commctrl.h:3536
#define TVS_INFOTIP
Definition: commctrl.h:3258
#define TVM_EXPAND
Definition: commctrl.h:3419
#define TVIF_STATE
Definition: commctrl.h:3269
#define TVM_SETTOOLTIPS
Definition: commctrl.h:3558
#define HDF_JUSTIFYMASK
Definition: commctrl.h:716
#define TVN_SINGLEEXPAND
Definition: commctrl.h:3716
#define TVGN_NEXT
Definition: commctrl.h:3453
#define TVM_GETITEM
Definition: commctrl.h:3488
#define TTM_SETMAXTIPWIDTH
Definition: commctrl.h:1819
#define TVM_GETNEXTITEM
Definition: commctrl.h:3449
#define TVM_SETITEMHEIGHT
Definition: commctrl.h:3571
#define LVIS_CUT
Definition: commctrl.h:2320
#define WM_NOTIFY
Definition: richedit.h:61
#define DefWindowProc
Definition: ros2win.h:31
#define memset(x, y, z)
Definition: compat.h:39
static void Exit(void)
Definition: sock.c:1330
unsigned uLevel
Definition: treelist.c:184
unsigned uNextItem
Definition: treelist.c:182
UINT uState
Definition: treelist.c:175
BYTE bCallback
Definition: treelist.c:187
unsigned uShowPos
Definition: treelist.c:178
unsigned uPrevItem
Definition: treelist.c:181
unsigned uFirstChild
Definition: treelist.c:179
int iSelectedImage
Definition: treelist.c:177
int iTextPixels
Definition: treelist.c:185
unsigned uLastChild
Definition: treelist.c:180
LPTSTR pText
Definition: treelist.c:174
WORD uTextSize
Definition: treelist.c:186
LPARAM lParam
Definition: treelist.c:173
unsigned uParent
Definition: treelist.c:183
COLORREF uColorText
Definition: treelist.c:189
BYTE bFlags
Definition: treelist.c:188
COLORREF uColorBk
Definition: treelist.c:190
int iImage
Definition: treelist.c:176
BYTE bIndex
Definition: treelist.c:215
BYTE bWeight
Definition: treelist.c:213
BYTE bMinEx
Definition: treelist.c:212
BYTE bCbChar
Definition: treelist.c:221
void * pCbData
Definition: treelist.c:206
short sSize
Definition: treelist.c:208
short sFixed
Definition: treelist.c:211
BYTE bNext
Definition: treelist.c:214
BYTE bFlags
Definition: treelist.c:218
BYTE bMark
Definition: treelist.c:222
short sReal
Definition: treelist.c:209
BYTE bCbSize
Definition: treelist.c:220
BYTE bAlign
Definition: treelist.c:216
BYTE bEnable
Definition: treelist.c:219
BYTE bEdit
Definition: treelist.c:217
short sMin
Definition: treelist.c:210
INT iCbIcon
Definition: treelist.c:207
COLORREF uColorBk
Definition: treelist.c:202
int iTextPixels
Definition: treelist.c:197
int iImage
Definition: treelist.c:196
BYTE bFlags
Definition: treelist.c:200
UINT uState
Definition: treelist.c:195
WORD uTextSize
Definition: treelist.c:198
LPTSTR pText
Definition: treelist.c:194
BYTE bCallback
Definition: treelist.c:199
COLORREF uColorText
Definition: treelist.c:201
LONG lfWeight
Definition: dimm.idl:46
unsigned uInsertMark
Definition: treelist.c:312
unsigned uEditMode
Definition: treelist.c:301
char cEditCb
Definition: treelist.c:340
unsigned uButtonPos
Definition: treelist.c:319
HWND hToolTip
Definition: treelist.c:243
char cHasRootRow
Definition: treelist.c:332
char cGlyphOk
Definition: treelist.c:339
char cClickEdit
Definition: treelist.c:335
unsigned uLastChild
Definition: treelist.c:277
unsigned uToolTipShow
Definition: treelist.c:298
HWND hEdit
Definition: treelist.c:241
int iStatesXsize
Definition: treelist.c:250
unsigned uPageEnties
Definition: treelist.c:288
int iSubImgYsize
Definition: treelist.c:259
unsigned uSizeY
Definition: treelist.c:282
unsigned uDragFlags
Definition: treelist.c:314
unsigned uSelectedCount
Definition: treelist.c:291
int iStatesMode
Definition: treelist.c:249
WNDPROC pProcId3
Definition: treelist.c:231
int iImagesXsize
Definition: treelist.c:255
unsigned uSizeYsub
Definition: treelist.c:283
char cIsEnabled
Definition: treelist.c:336
unsigned uLastSel
Definition: treelist.c:317
unsigned uDragItem
Definition: treelist.c:315
unsigned uStyle
Definition: treelist.c:284
int iImagesYsize
Definition: treelist.c:256
unsigned uItemPosCount
Definition: treelist.c:268
POINT sToolTipPos
Definition: treelist.c:300
unsigned uLastMove
Definition: treelist.c:318
int iFontHeight
Definition: treelist.c:246
unsigned uTreeItemsMax
Definition: treelist.c:272
LPVOID hThemeBt
Definition: treelist.c:230
char cButtonFlag
Definition: treelist.c:341
int iSubImgXsize
Definition: treelist.c:258
HIMAGELIST hStates
Definition: treelist.c:232
HFONT hFontL
Definition: treelist.c:239
unsigned * pItemPos
Definition: treelist.c:269
unsigned uSizeX
Definition: treelist.c:281
unsigned uTrackedSub
Definition: treelist.c:311
HIMAGELIST hImages
Definition: treelist.c:233
char cLockChanges
Definition: treelist.c:331
HFONT hFontN
Definition: treelist.c:237
char cReSelect
Definition: treelist.c:338
unsigned uOldYCount
Definition: treelist.c:307
WNDPROC pToolProc
Definition: treelist.c:244
unsigned uMarkedCols
Definition: treelist.c:313
HIMAGELIST hHeadImg
Definition: treelist.c:236
unsigned uEditSub
Definition: treelist.c:303
int iChecksYsize
Definition: treelist.c:254
int iAllWeight
Definition: treelist.c:261
unsigned uButtonLast
Definition: treelist.c:320
char cClickFlag
Definition: treelist.c:334
unsigned uMaxEnties
Definition: treelist.c:287
unsigned uScrollX
Definition: treelist.c:279
unsigned uNextSeachPos
Definition: treelist.c:274
char cFixedHeight
Definition: treelist.c:330
int iFixSize
Definition: treelist.c:263
unsigned uOldYPage
Definition: treelist.c:306
LPVOID hTheme
Definition: treelist.c:229
int iStatesYsize
Definition: treelist.c:251
int iChecksXsize
Definition: treelist.c:253
HFONT hFontT
Definition: treelist.c:240
int iAutoAdd
Definition: treelist.c:266
unsigned uSingleSel
Definition: treelist.c:278
unsigned uToolTipSize
Definition: treelist.c:321
unsigned uTrackedItem
Definition: treelist.c:310
char cHasFocus
Definition: treelist.c:337
unsigned uStyleEx
Definition: treelist.c:285
char cKeyIgnore
Definition: treelist.c:333
unsigned uFocusItem
Definition: treelist.c:295
unsigned uUserDataSize
Definition: treelist.c:275
unsigned uDragSub
Definition: treelist.c:316
unsigned uFocusSub
Definition: treelist.c:296
HANDLE hSem
Definition: treelist.c:228
unsigned uSelectedSub
Definition: treelist.c:294
unsigned uOldXPage
Definition: treelist.c:304
LPTSTR pToolTipText
Definition: treelist.c:322
unsigned uToolTipSub
Definition: treelist.c:299
unsigned uTrippleB
Definition: treelist.c:308
int iRowHeight
Definition: treelist.c:260
unsigned uStartPixel
Definition: treelist.c:286
unsigned uTreeItemsCount
Definition: treelist.c:273
unsigned uFirstChild
Definition: treelist.c:276
HIMAGELIST hChecks
Definition: treelist.c:234
unsigned uColumnCount
Definition: treelist.c:289
HWND hHeader
Definition: treelist.c:242
unsigned uOldXCount
Definition: treelist.c:305
int iVarSize
Definition: treelist.c:262
int iMaxSizeX
Definition: treelist.c:267
unsigned uTrippleN
Definition: treelist.c:309
int iChecksMode
Definition: treelist.c:252
int iSubImgMode
Definition: treelist.c:257
unsigned uSelectedItem
Definition: treelist.c:293
HFONT hFontB
Definition: treelist.c:238
int iFontLine
Definition: treelist.c:247
BaseItem ** pTreeItems
Definition: treelist.c:270
unsigned uEditItem
Definition: treelist.c:302
unsigned uSelectedBase
Definition: treelist.c:292
char cColumnStart
Definition: treelist.c:329
unsigned uColumnCountVar
Definition: treelist.c:290
unsigned uToolTipItem
Definition: treelist.c:297
int iFontOff
Definition: treelist.c:248
unsigned uScrollY
Definition: treelist.c:280
HIMAGELIST hSubImg
Definition: treelist.c:235
LONG cx
Definition: kdterminal.h:27
LPARAM lParam
Definition: treelist.h:50
LPCTSTR pText
Definition: treelist.h:51
UINT uState
Definition: treelist.h:48
UINT uFlags
Definition: treelist.h:46
UINT uColumn
Definition: treelist.h:47
UINT uStateMask
Definition: treelist.h:49
PFNTVCOMPAREEX lpfnCompare
Definition: treelist.h:41
HTREEITEM hParent
Definition: treelist.h:40
LPARAM lParam
Definition: treelist.h:42
NMHDR hdr
Definition: treelist.h:73
UINT uPosX
Definition: treelist.h:76
INT iSize
Definition: treelist.h:77
UINT uColumn
Definition: treelist.h:74
UINT uIndex
Definition: treelist.h:75
UINT uHeight
Definition: treelist.h:65
POINT ptAction
Definition: treelist.h:69
TVITEM item
Definition: treelist.h:63
UINT uMaxEntries
Definition: treelist.h:66
UINT uAction
Definition: treelist.h:64
LPCTSTR pTextEntries
Definition: treelist.h:67
NMHDR hdr
Definition: treelist.h:62
LPCTSTR * pTextList
Definition: treelist.h:68
int cbClsExtra
Definition: winuser.h:3204
HINSTANCE hInstance
Definition: winuser.h:3206
HCURSOR hCursor
Definition: winuser.h:3208
LPCSTR lpszMenuName
Definition: winuser.h:3210
HICON hIconSm
Definition: winuser.h:3212
UINT style
Definition: winuser.h:3202
int cbWndExtra
Definition: winuser.h:3205
UINT cbSize
Definition: winuser.h:3201
WNDPROC lpfnWndProc
Definition: winuser.h:3203
LPCSTR lpszClassName
Definition: winuser.h:3211
HICON hIcon
Definition: winuser.h:3207
HBRUSH hbrBackground
Definition: winuser.h:3209
ULONG biClrImportant
Definition: precomp.h:43
USHORT biBitCount
Definition: precomp.h:37
LONG biYPelsPerMeter
Definition: precomp.h:41
ULONG biCompression
Definition: precomp.h:38
LONG biXPelsPerMeter
Definition: precomp.h:40
BITMAPINFOHEADER bmiHeader
Definition: wingdi.h:1476
UINT lbStyle
Definition: wingdi.h:1747
ULONG_PTR lbHatch
Definition: wingdi.h:1749
COLORREF lbColor
Definition: wingdi.h:1748
UINT_PTR idFrom
Definition: winuser.h:3158
UINT code
Definition: winuser.h:3159
HWND hwndFrom
Definition: winuser.h:3157
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
LONG right
Definition: windef.h:308
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
BYTE tmPitchAndFamily
Definition: wingdi.h:2379
LONG tmAscent
Definition: wingdi.h:2362
LONG tmHeight
Definition: wingdi.h:2361
static int TreeListSetItem(TreeListData *pData, const TV_ITEM *pItem)
Definition: treelist.c:4628
#define FIRST_LINE
Definition: treelist.c:111
static int TreeListDeleteColumn(TreeListData *pData, unsigned uCol)
Definition: treelist.c:5119
#define CBS_UNCHECKEDNORMAL
Definition: treelist.c:148
static BeginBufferedPnT pBeginBufferedPt
Definition: treelist.c:359
#define TVIX_VARBUTTON
Definition: treelist.c:164
static int UpdateFont(TreeListData *pData)
Definition: treelist.c:2150
static TCHAR cKeyData[16]
Definition: treelist.c:375
static void GlobalInit()
Definition: treelist.c:438
static void GlobalDeinit()
Definition: treelist.c:491
static int TreeListIsVisible(TreeListData *pData, unsigned uItem, unsigned uSub)
Definition: treelist.c:2990
static void CreateStateImageList(TreeListData *pData, int iMode)
Definition: treelist.c:1080
static int TreeListXorSelectItem(TreeListData *pData, unsigned uItem, int iMode)
Definition: treelist.c:3317
LPVOID(WINAPI * OpenThemeDataT)(HWND hwnd, LPCWSTR pszClassList)
Definition: treelist.c:349
static int TreeListSetTrackItem(TreeListData *pData, unsigned uItem, unsigned uSub)
Definition: treelist.c:6140
static void UpdateColorsList(TreeListData *pData)
Definition: treelist.c:1350
#define GetHandle(h)
Definition: treelist.c:116
static int UpdateHeight(TreeListData *pData)
Definition: treelist.c:1470
#define SORT_NOUPDATE
Definition: treelist.c:109
static unsigned TreeListHitTest(TreeListData *pData, TV_HITTESTINFO *pInfo)
Definition: treelist.c:5726
static HFONT hDefaultFontB
Definition: treelist.c:370
static unsigned TreeListGetNextItem(TreeListData *pData, unsigned uItem, unsigned uFlags)
Definition: treelist.c:6223
static HPEN hPatternPen
Definition: treelist.c:368
#define TVIX_BKCOLOR
Definition: treelist.c:169
static LRESULT CALLBACK TreeListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: treelist.c:10028
#define WHEEL_DELTA
Definition: treelist.c:99
static HWND TreeListEditLabel(TreeListData *pData, unsigned uItem, unsigned uSub)
Definition: treelist.c:9109
static IsAppThemedT pIsAppThemed
Definition: treelist.c:366
#define MAX_COLUMNS
Definition: treelist.c:102
static int TreeListSortItemsCb(TreeListData *pData, TV_SORTCB *pSortData, int iMode)
Definition: treelist.c:8358
static void UpdateScrollX(TreeListData *pData)
Definition: treelist.c:1658
static void CreateToolTip(TreeListData *pData)
Definition: treelist.c:1047
static int TreeListToggleItem(TreeListData *pData, unsigned uItem, unsigned uAddFlags)
Definition: treelist.c:2593
static GetThemeBackgRcT pGetThemeBackgRc
Definition: treelist.c:365
#define TVIS_TRACKED
Definition: treelist.c:122
#define CBS_CHECKEDNORMAL
Definition: treelist.c:151
#define EN_SETTEXT
Definition: treelist.c:105
#define TVIS_EDIT(m)
Definition: treelist.c:120
#define EN_RETURN
Definition: treelist.c:106
#define GetWindowLongPtr
Definition: treelist.c:73
#define EN_ESCAPE
Definition: treelist.c:107
#define str_ncpy
Definition: treelist.c:91
#define TVIX_FOCUSED
Definition: treelist.c:170
static IsThemeActiveT pIsThemeActive
Definition: treelist.c:367
#define SetWindowLongPtr
Definition: treelist.c:70
static HIMAGELIST CreateDragImage(TreeListData *pData, unsigned uItem, unsigned uSub)
Definition: treelist.c:1204
static LRESULT SendNotify(TreeListData *pData, NMHDR *pNotify)
Definition: treelist.c:530
#define str_ncmp
Definition: treelist.c:92
#define TVC_ONLYFOCUS
Definition: treelist.c:127
#define TVAX_EDIT
Definition: treelist.c:156
static LONG lWindowCount
Definition: treelist.c:371
#define TVIS_FOCUSED
Definition: treelist.c:125
static int UpdateRow(TreeListData *pData, unsigned uItem)
Definition: treelist.c:1604
static int TreeListSortItems(TreeListData *pData, unsigned uParent, int iMode)
Definition: treelist.c:8614
static LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: treelist.c:687
#define GWLP_WNDPROC
Definition: treelist.c:66
static int TreeListStartNotifyEdit(TreeListData *pData, unsigned uItem, unsigned uSub, WPARAM wParam, LPARAM lParam)
Definition: treelist.c:9479
static void TreeListChangeCheckbox(TreeListData *pData, UINT uItem, int iPosX, int iPosY)
Definition: treelist.c:6798
static HFONT hDefaultFontN
Definition: treelist.c:369
#define str_cmp
Definition: treelist.c:90
static unsigned TreeListFindItem(TreeListData *pData, unsigned uItem, TVFIND *pFind)
Definition: treelist.c:6539
static int TreeListSelectChilds(TreeListData *pData, unsigned uItem, int iMode)
Definition: treelist.c:3945
#define LOCK(d)
Definition: treelist.c:119
static int TreeListSortItemsEx(TreeListData *pData, TV_SORTEX *pSortData, int iMode)
Definition: treelist.c:8096
static LRESULT CALLBACK ToolProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: treelist.c:826
static LRESULT TreeListGetItemColor(TreeListData *pData, unsigned uItem, unsigned uSub, int iMode)
Definition: treelist.c:5995
static void CallbackExtra(TreeListData *pData, BaseItem *pEntry, ExtraItem *pExtra, unsigned uItem, unsigned uSub, unsigned uFlags, int *iImage, unsigned *uTextSize, LPCTSTR *pText)
Definition: treelist.c:639
#define TVIX_TRACKED
Definition: treelist.c:167
#define GWLP_USERDATA
Definition: treelist.c:63
#define VK_ISACHAR
Definition: treelist.c:110
int TreeListRegister(HINSTANCE hInstance)
Definition: treelist.c:394
BOOL(WINAPI * IsAppThemedT)()
Definition: treelist.c:353
#define str_icmp
Definition: treelist.c:93
#define THEMEIMGLIST
Definition: treelist.c:115
static void TreeListDraw(HWND hWnd, HDC hDc, RECT *pRect)
Definition: treelist.c:12681
#define TVC_UNSELECT
Definition: treelist.c:128
static int TreeListScanColumn(TreeListData *pData, unsigned uSub)
Definition: treelist.c:5643
#define FROM_HEADER
Definition: treelist.c:112
static int TreeListInsertColumn(TreeListData *pData, unsigned uCol, TV_COLUMN *pColumn)
Definition: treelist.c:5319
static void UpdateScrollY(TreeListData *pData)
Definition: treelist.c:1724
static void UpdateView(TreeListData *pData)
Definition: treelist.c:1636
static BufferedPtInitT pBufferedPtExit
Definition: treelist.c:361
static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT *pRect)
Definition: treelist.c:2755
static void TreeListMouseNotify(TreeListData *pData, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: treelist.c:6883
#define WM_MOUSEWHEEL
Definition: treelist.c:96
#define XCHANGE_MEM(a, b)
#define TVIX_TEXTCOLOR
Definition: treelist.c:168
#define str_len
Definition: treelist.c:89
#define BP_CHECKBOX
Definition: treelist.c:145
static int UpdateRect(TreeListData *pData, unsigned uItem, unsigned uSub)
Definition: treelist.c:1529
static int CreateFontset(TreeListData *pData, HFONT hFont)
Definition: treelist.c:2121
static unsigned uKeyPos
Definition: treelist.c:377
static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int iMode)
Definition: treelist.c:3587
static CloseThemeDataT pCloseThemeData
Definition: treelist.c:363
#define ID_TOOLTIPCHECK
Definition: treelist.c:108
static unsigned TreeListSetInsertMark(TreeListData *pData, unsigned uItem, int iMode)
Definition: treelist.c:5923
static unsigned uKeyLast
Definition: treelist.c:376
#define TVIX_HASIMAGE
Definition: treelist.c:166
HRESULT(WINAPI * EndBufferedPtT)(HANDLE, BOOL)
Definition: treelist.c:345
HRESULT(WINAPI * SetWindowThemeT)(HWND, LPCWSTR, LPCWSTR)
Definition: treelist.c:344
HRESULT(WINAPI * BufferedPtInitT)(VOID)
Definition: treelist.c:347
static unsigned TreeListNextUnselUntil(TreeListData *pData, unsigned uItem, unsigned uStop)
Definition: treelist.c:6727
#define GLPS_OPENED
Definition: treelist.c:142
static void TreeListKeyDown(TreeListData *pData, WPARAM wParam, LPARAM lParam)
Definition: treelist.c:7635
static void UpdateToolTip(TreeListData *pData, unsigned uItem, unsigned uFlags)
Definition: treelist.c:1771
#define TVP_GLYPH
Definition: treelist.c:136
#define I_CCB
Definition: treelist.c:113
static void TreeListRemoveFocus(TreeListData *pData)
Definition: treelist.c:3418
static HMODULE hUxThemeDll
Definition: treelist.c:356
static void CallbackEntry(TreeListData *pData, BaseItem *pEntry, unsigned uItem, unsigned uFlags, int *iImage, unsigned *uTextSize, LPCTSTR *pText)
Definition: treelist.c:550
static int TreeListDeleteItem(TreeListData *pData, unsigned uItem, int iMode)
Definition: treelist.c:3072
static int TreeListSetOrderArray(TreeListData *pData, unsigned uItems, unsigned *pArray)
Definition: treelist.c:2493
static RECT sToolRect
Definition: treelist.c:373
#define TVAX_NONE
Definition: treelist.c:155
#define DEFAULT_SHIFT
Definition: treelist.c:131
HRESULT(WINAPI * CloseThemeDataT)(LPVOID)
Definition: treelist.c:350
static void UpdateItems(TreeListData *pData, unsigned uItem)
Definition: treelist.c:2249
HRESULT(WINAPI * GetThemeBackgRcT)(LPVOID, HDC, int, int, LPCRECT, LPRECT)
Definition: treelist.c:352
#define DEFAULT_IDENT
Definition: treelist.c:130
static int TreeListSetFocus(TreeListData *pData, unsigned uItem, unsigned uSub)
Definition: treelist.c:3459
static void ChangeColSize(TreeListData *pData, int iDelta)
Definition: treelist.c:862
static unsigned TreeListInsertItem(TreeListData *pData, TV_INSERTSTRUCT *pInsert)
Definition: treelist.c:4008
static int UpdateColRect(TreeListData *pData, unsigned uColumn)
Definition: treelist.c:1567
static unsigned TreeListGetItem(TreeListData *pData, TV_ITEM *pItem)
Definition: treelist.c:4966
static BOOL bDrawWithTheme
Definition: treelist.c:385
BOOL(WINAPI * IsThemeActiveT)()
Definition: treelist.c:354
#define TVAX_STEP
Definition: treelist.c:159
#define U(h)
Definition: treelist.c:114
#define BPBF_COMPATIBLEBITMAP
Definition: treelist.c:133
#define TVC_DESELECT
Definition: treelist.c:129
static int TreeListStartAutoEdit(TreeListData *pData, unsigned uColumn, WPARAM wParam, LPARAM lParam)
Definition: treelist.c:9695
#define TVAX_CHECK
Definition: treelist.c:161
#define TVIX_HASBUTTON
Definition: treelist.c:165
static BufferedPtInitT pBufferedPtInit
Definition: treelist.c:360
HRESULT(WINAPI * DrawThemeBackgT)(LPVOID, HDC, int, int, const RECT *, const RECT *)
Definition: treelist.c:351
#define TVAX_COMBO
Definition: treelist.c:157
static void TreeListMouseClick(TreeListData *pData, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: treelist.c:6931
static DrawThemeBackgT pDrawThemeBackg
Definition: treelist.c:364
#define UNLOCK(d)
Definition: treelist.c:118
static int TreeListEndLabelEdit(TreeListData *pData, int iMode)
Definition: treelist.c:8889
#define TVIS_BKCOLOR
Definition: treelist.c:123
HANDLE(WINAPI * BeginBufferedPnT)(HDC, RECT *, DWORD, LPVOID, HDC *)
Definition: treelist.c:346
static SetWindowThemeT pSetWindowTheme
Definition: treelist.c:357
static COLORREF TreeListSetItemColor(TreeListData *pData, unsigned uItem, unsigned uSub, COLORREF uColor, int iMode)
Definition: treelist.c:6042
static int TreeListEnsureVisible(TreeListData *pData, unsigned uItem, unsigned uSub)
Definition: treelist.c:2861
static unsigned TreeListNextSelUntil(TreeListData *pData, unsigned uItem, unsigned uStop)
Definition: treelist.c:6655
static OpenThemeDataT pOpenThemeData
Definition: treelist.c:362
static void TreeListChar(TreeListData *pData, UINT nChar, LPARAM lParam)
Definition: treelist.c:7491
#define TVAX_CBLIST
Definition: treelist.c:158
static int UpdateColumns(TreeListData *pData)
Definition: treelist.c:2391
#define GLPS_CLOSED
Definition: treelist.c:139
#define MAX_COLORS
Definition: treelist.c:104
#define TVIS_BASEFLAGS
Definition: treelist.c:121
BOOL TreeListUnregister(HINSTANCE hInstance)
Definition: treelist.c:429
static EndBufferedPtT pEndBufferedPt
Definition: treelist.c:358
#define TVIS_TEXTCOLOR
Definition: treelist.c:126
#define TVN_LBUTTONUP
Definition: treelist.h:298
#define TVS_EX_EDITCLICK
Definition: treelist.h:283
#define TVS_EX_NOCHARSELCET
Definition: treelist.h:275
#define TVIR_EDITFULL
Definition: treelist.h:248
#define TVGN_NEXTSELECTED
Definition: treelist.h:160
#define TVS_EX_SINGLECHECKBOX
Definition: treelist.h:266
#define TVCFMT_CENTER
Definition: treelist.h:184
#define TVI_BEFORE
Definition: treelist.h:116
#define TVGN_FOCUS
Definition: treelist.h:162
#define TVS_EX_SHAREIMAGELISTS
Definition: treelist.h:282
#define TVIR_SETAT(a)
Definition: treelist.h:255
#define TVI_AFTER
Definition: treelist.h:117
#define TVIF_CHILD
Definition: treelist.h:99
#define TVC_FRAME
Definition: treelist.h:140
#define TVM_SELECTSUBITEM
Definition: treelist.h:308
#define TVN_RBUTTONUP
Definition: treelist.h:299
#define TVM_GETLINECOLOR
Definition: treelist.h:345
#define TVNRET_SKIPNEW
Definition: treelist.h:359
#define TVIF_TOOLTIPTIME
Definition: treelist.h:94
#define TVHT_ONRIGHTSPACE
Definition: treelist.h:220
#define TVIF_CANCELED
Definition: treelist.h:100
#define TVGN_DROPHILITESUB
Definition: treelist.h:157
#define TVC_MARK
Definition: treelist.h:145
#define TVM_SETFOCUSITEM
Definition: treelist.h:332
#define TVI_SORTEX
Definition: treelist.h:115
#define TVM_SETLINECOLOR
Definition: treelist.h:348
#define TVGN_NEXTSELCHILD
Definition: treelist.h:164
#define TVE_ONLYCHILDS
Definition: treelist.h:114
#define TVIR_GETCOLUMN
Definition: treelist.h:229
#define TVM_GETCOLUMNORDERARRAY
Definition: treelist.h:333
#define TVAE_FULLWIDTH
Definition: treelist.h:203
#define TVM_SORTCHILDRENEX
Definition: treelist.h:324
#define TV_SECONDICON
Definition: treelist.h:91
#define TVM_SELECTCHILDS
Definition: treelist.h:329
#define TVM_SETCOLUMN
Definition: treelist.h:317
#define TVS_EX_SUBSELECT
Definition: treelist.h:271
#define TVS_EX_HIDEHEADERS
Definition: treelist.h:277
#define TVCF_LASTSIZE
Definition: treelist.h:178
#define TVM_GETHEADER
Definition: treelist.h:304
#define TVNRET_SKIPOLD
Definition: treelist.h:356
#define TVSIL_HEADER
Definition: treelist.h:107
#define TVIF_TEXTPTR
Definition: treelist.h:93
#define TVS_EX_HOMEENDSELECT
Definition: treelist.h:281
#define TVC_ODD
Definition: treelist.h:138
#define TVIR_EDITCOMBODOWN
Definition: treelist.h:245
#define TVS_EX_HEADERCHGNOTIFY
Definition: treelist.h:264
#define TVCF_WIDTH
Definition: treelist.h:173
#define TVIR_COLTOSUB(u)
Definition: treelist.h:228
#define TVM_COLUMNAUTOICON
Definition: treelist.h:326
#define TVCFMT_RIGHT
Definition: treelist.h:187
#define TVC_TRACK
Definition: treelist.h:144
#define TVM_GETCOLUMN
Definition: treelist.h:318
#define VK_EDITCLK
Definition: treelist.h:126
#define TVAE_PTRLIST
Definition: treelist.h:204
#define TVM_GETROWCOUNT
Definition: treelist.h:315
#define TVAE_CHECK
Definition: treelist.h:199
#define TVC_COLEVEN
Definition: treelist.h:152
#define TVHT_ONSUBLABEL
Definition: treelist.h:221
#define TVHT_ONSUBITEM
Definition: treelist.h:224
#define TVIF_CASE
Definition: treelist.h:97
#define TVE_EXPANDFORCE
Definition: treelist.h:111
#define TVS_EX_STEPOUT
Definition: treelist.h:267
#define TVIR_EDITCOMBOBOX
Definition: treelist.h:246
#define TVE_EXPANDRECURSIVE
Definition: treelist.h:110
#define TVIF_NEXT
Definition: treelist.h:98
#define TVM_SETUSERDATASIZE
Definition: treelist.h:321
#define TVC_BK
Definition: treelist.h:137
#define TVGN_LASTCHILD
Definition: treelist.h:165
#define TVAE_CHECKED
Definition: treelist.h:200
#define TVM_FINDITEM
Definition: treelist.h:328
#define TVM_GETEXTENDEDSTYLE
Definition: treelist.h:339
#define TVM_GETUSERDATASIZE
Definition: treelist.h:322
#define TVC_LINE
Definition: treelist.h:142
#define TVCFMT_FIXED
Definition: treelist.h:188
#define TVS_EX_ITEMLINES
Definition: treelist.h:269
#define TVM_ISITEMVISIBLE
Definition: treelist.h:331
#define TVHT_ONSUBICON
Definition: treelist.h:222
#define TVM_GETUSERDATA
Definition: treelist.h:323
#define TVE_EXPANDNEXT
Definition: treelist.h:112
#define TVCF_VWIDTH
Definition: treelist.h:174
#define VK_ICONCLK
Definition: treelist.h:123
#define TVIR_EDITCOL(u)
Definition: treelist.h:250
#define TVCF_MARK
Definition: treelist.h:176
#define TV_NOIMAGE
Definition: treelist.h:88
#define TV_FIND
Definition: treelist.h:87
#define TVAE_MODEMASK
Definition: treelist.h:212
#define TVS_EX_ALTERNATECOLOR
Definition: treelist.h:270
#define TVN_STARTEDIT
Definition: treelist.h:297
#define TVC_CLASSNAME
Definition: treelist.h:134
#define TVIF_RETURNEXIT
Definition: treelist.h:96
#define TVIS_UNDERLINE
Definition: treelist.h:104
#define TVM_GETCOLUMNCOUNT
Definition: treelist.h:305
#define TVM_SETITEMTEXTCOLOR
Definition: treelist.h:312
#define TVN_COLUMNCHANGED
Definition: treelist.h:300
#define TVS_EX_NOCOLUMNRESIZE
Definition: treelist.h:276
#define TVC_MARKODD
Definition: treelist.h:146
#define TVAE_STATEENABLE
Definition: treelist.h:206
#define TVM_GETROWOFITEM
Definition: treelist.h:316
#define TVCF_FMT
Definition: treelist.h:170
#define TVS_EX_BITCHECKBOX
Definition: treelist.h:268
#define TVAE_ONLYRETURN
Definition: treelist.h:205
#define TVAE_NEXTLINE
Definition: treelist.h:201
#define TVHT_ONSUBRIGHT
Definition: treelist.h:223
#define TVS_EX_NOCURSORSET
Definition: treelist.h:284
#define TVC_BOX
Definition: treelist.h:143
#define TVN_CBSTATECHANGED
Definition: treelist.h:295
#define TVM_GETCOLUMNWIDTH
Definition: treelist.h:320
#define TVM_GETITEMTEXTCOLOR
Definition: treelist.h:313
#define TVM_SETCOLUMNWIDTH
Definition: treelist.h:319
#define TVIS_WITHCHILDS
Definition: treelist.h:234
#define TVIF_TEXTCHANGED
Definition: treelist.h:95
#define TVN_ITEMTOOLTIP
Definition: treelist.h:294
#define VK_DBLCLK
Definition: treelist.h:120
#define TVCF_IMAGE
Definition: treelist.h:171
int(CALLBACK * PFNTVCOMPAREEX)(HWND hWnd, HTREEITEM hItem1, HTREEITEM hItem2, LPARAM lParam1, LPARAM lParam2, LPARAM lParam)
Definition: treelist.h:36
#define TVC_COLBK
Definition: treelist.h:150
#define TVCFMT_MARK
Definition: treelist.h:189
#define TVIF_SUBNUMBER
Definition: treelist.h:103
#define TVM_SELECTDROP
Definition: treelist.h:309
#define TVCF_MIN
Definition: treelist.h:175
#define TVOP_WRITEOPTION
Definition: treelist.h:239
#define TVC_MARKEVEN
Definition: treelist.h:147
#define TVS_EX_HEADEROWNIMGLIST
Definition: treelist.h:263
#define TVM_GETITEMBKCOLOR
Definition: treelist.h:311
#define TVHT_SUBTOCOL(u)
Definition: treelist.h:218
#define TV_NOCOLOR
Definition: treelist.h:89
#define TVS_EX_FULLROWMARK
Definition: treelist.h:272
#define TVIR_EDITCOMBOLIST
Definition: treelist.h:247
#define TV_COLUMN
Definition: treelist.h:86
#define TV_NOAUTOEXPAND
Definition: treelist.h:90
#define TVM_COLUMNAUTOEDIT
Definition: treelist.h:325
#define TVGN_CARETSUB
Definition: treelist.h:158
#define TVS_EX_GRAYEDDISABLE
Definition: treelist.h:278
#define TVM_DELETECOLUMN
Definition: treelist.h:306
#define TVS_EX_HEADERDRAGDROP
Definition: treelist.h:265
#define TVC_COLODD
Definition: treelist.h:151
#define TVGN_NEXTITEM
Definition: treelist.h:166
#define TVS_EX_TOOLTIPNOTIFY
Definition: treelist.h:273
#define TVIF_SUBITEM
Definition: treelist.h:102
#define TVC_EVEN
Definition: treelist.h:139
#define TVS_EX_MULTISELECT
Definition: treelist.h:286
#define TVM_INSERTCOLUMN
Definition: treelist.h:307
#define TVS_EX_FIXEDCOLSIZE
Definition: treelist.h:280
#define TVAE_DBLCLICK
Definition: treelist.h:202
#define TVE_ALLCHILDS
Definition: treelist.h:113
#define TVAE_DROPDOWN
Definition: treelist.h:208
#define TVAE_MODEPOS
Definition: treelist.h:213
#define TVSIL_SUBIMAGES
Definition: treelist.h:106
#define TVS_EX_AUTOHSCROLL
Definition: treelist.h:289
#define TVM_GETITEMOFROW
Definition: treelist.h:314
#define TVC_BOXBG
Definition: treelist.h:149
#define TVIS_DESELECT
Definition: treelist.h:235
#define TVS_EX_FULLROWITEMS
Definition: treelist.h:279
#define TVS_EX_AUTOEXPANDICON
Definition: treelist.h:274
#define TVN_STEPSTATECHANGED
Definition: treelist.h:296
#define TVOP_AUTOEXPANDOFF
Definition: treelist.h:238
#define TVAE_ICONCLICK
Definition: treelist.h:207
#define TVM_GETITEMSTATE
Definition: treelist.h:336
#define TVM_GETSETOPTION
Definition: treelist.h:330
#define TVM_SETCOLUMNORDERARRAY
Definition: treelist.h:334
#define TVM_SETEXTENDEDSTYLE
Definition: treelist.h:342
#define TVCF_TEXT
Definition: treelist.h:172
#define TVGN_FOCUSSUB
Definition: treelist.h:163
#define TVC_INSERT
Definition: treelist.h:148
#define TVC_GRAYED
Definition: treelist.h:153
#define TVC_TEXT
Definition: treelist.h:141
#define TVM_GETCOUNTPERPAGE
Definition: treelist.h:327
#define TVIS_DISABLEBIT
Definition: treelist.h:214
#define TVIR_TEXT
Definition: treelist.h:230
#define TVSIL_CHECK
Definition: treelist.h:105
#define TVIR_EDITCOMBODEL
Definition: treelist.h:244
#define TVCF_FIXED
Definition: treelist.h:177
#define TVM_SETITEMBKCOLOR
Definition: treelist.h:310
#define TVLE_DONOTIFY
Definition: treelist.h:92
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
LPCSTR pText
Definition: txtscale.cpp:79
PVOID HANDLE
Definition: typedefs.h:73
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define MAKELONG(a, b)
Definition: typedefs.h:249
#define HIWORD(l)
Definition: typedefs.h:247
#define _T(x)
Definition: vfdio.h:22
#define LPCRECT
Definition: precomp.h:29
#define LPRECT
Definition: precomp.h:28
#define LoadLibrary
Definition: winbase.h:3797
#define CreateSemaphore
Definition: winbase.h:3695
#define OutputDebugString
Definition: winbase.h:3825
_In_ ULONG iMode
Definition: winddi.h:3520
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
DWORD COLORREF
Definition: windef.h:300
#define HRESULT
Definition: msvc.h:7
#define WINAPI
Definition: msvc.h:6
#define GetTextExtentExPoint
Definition: wingdi.h:4471
#define DIB_RGB_COLORS
Definition: wingdi.h:367
HGDIOBJ WINAPI GetStockObject(_In_ int)
int WINAPI GetDeviceCaps(_In_opt_ HDC, _In_ int)
#define PS_ALTERNATE
Definition: wingdi.h:585
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:999
HRGN WINAPI CreateRectRgn(_In_ int, _In_ int, _In_ int, _In_ int)
HPEN WINAPI ExtCreatePen(_In_ DWORD iPenStyle, _In_ DWORD cWidth, _In_ const LOGBRUSH *plbrush, _In_ DWORD cStyle, _In_reads_opt_(cStyle) const DWORD *pstyle)
int WINAPI GetDIBits(_In_ HDC hdc, _In_ HBITMAP hbm, _In_ UINT start, _In_ UINT cLines, _Out_opt_ LPVOID lpvBits, _At_((LPBITMAPINFOHEADER) lpbmi, _Inout_) LPBITMAPINFO lpbmi, _In_ UINT usage)
#define FW_BOLD
Definition: wingdi.h:378
#define PS_DOT
Definition: wingdi.h:588
#define NULLREGION
Definition: wingdi.h:361
UINT WINAPI SetTextAlign(_In_ HDC, _In_ UINT)
Definition: text.c:883
int WINAPI SetDIBits(_In_opt_ HDC, _In_ HBITMAP, _In_ UINT, _In_ UINT, _In_ CONST VOID *, _In_ CONST BITMAPINFO *, _In_ UINT)
#define PS_COSMETIC
Definition: wingdi.h:584
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1539
#define TA_RIGHT
Definition: wingdi.h:933
BOOL WINAPI MoveToEx(_In_ HDC, _In_ int, _In_ int, _Out_opt_ LPPOINT)
#define TA_LEFT
Definition: wingdi.h:932
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
int WINAPI CombineRgn(_In_opt_ HRGN hrgnDest, _In_opt_ HRGN hrgnSrc1, _In_opt_ HRGN hrgnSrc2, _In_ int fnCombineMode)
#define DIB_PAL_COLORS
Definition: wingdi.h:366
#define TRANSPARENT
Definition: wingdi.h:950
#define RGN_AND
Definition: wingdi.h:356
#define TMPF_FIXED_PITCH
Definition: wingdi.h:1311
#define ETO_CLIPPED
Definition: wingdi.h:648
#define ExtTextOut
Definition: wingdi.h:4454
#define NULL_BRUSH
Definition: wingdi.h:901
#define ETO_OPAQUE
Definition: wingdi.h:647
#define OPAQUE
Definition: wingdi.h:949
#define NULL_PEN
Definition: wingdi.h:904
HBITMAP WINAPI CreateCompatibleBitmap(_In_ HDC hdc, _In_ INT cx, _In_ INT cy)
#define TA_TOP
Definition: wingdi.h:930
#define FW_NORMAL
Definition: wingdi.h:373
#define BITSPIXEL
Definition: wingdi.h:720
BOOL WINAPI Rectangle(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int)
int WINAPI SetBkMode(_In_ HDC, _In_ int)
Definition: dc.c:1056
COLORREF WINAPI SetTextColor(_In_ HDC, _In_ COLORREF)
Definition: text.c:918
_In_ UINT iStart
Definition: wingdi.h:3620
#define TA_CENTER
Definition: wingdi.h:931
#define GetObject
Definition: wingdi.h:4468
BOOL WINAPI DeleteDC(_In_ HDC)
HPEN WINAPI CreatePen(_In_ int, _In_ int, _In_ COLORREF)
#define GetTextMetrics
Definition: wingdi.h:4474
#define CreateFontIndirect
Definition: wingdi.h:4444
BOOL WINAPI LineTo(_In_ HDC, _In_ int, _In_ int)
#define PS_SOLID
Definition: wingdi.h:586
int WINAPI GetRgnBox(_In_ HRGN, _Out_ LPRECT)
#define WM_PAINT
Definition: winuser.h:1620
HWND WINAPI GetFocus(void)
Definition: window.c:1893
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
#define MK_RBUTTON
Definition: winuser.h:2368
DWORD WINAPI GetSysColor(_In_ int)
#define SetWindowLong
Definition: winuser.h:5853
#define MK_SHIFT
Definition: winuser.h:2369
#define SW_HIDE
Definition: winuser.h:768
#define CB_SETDROPPEDWIDTH
Definition: winuser.h:1962
#define DT_NOPREFIX
Definition: winuser.h:537
BOOL WINAPI RedrawWindow(_In_opt_ HWND, _In_opt_ LPCRECT, _In_opt_ HRGN, _In_ UINT)
#define SB_THUMBTRACK
Definition: winuser.h:573
#define COLOR_INFOBK
Definition: winuser.h:942
#define WM_ENABLE
Definition: winuser.h:1615
#define WM_MOUSEFIRST
Definition: winuser.h:1774
#define SB_LINEUP
Definition: winuser.h:564
#define WM_HSCROLL
Definition: winuser.h:1743
#define WM_PASTE
Definition: winuser.h:1863
BOOL WINAPI TranslateMessage(_In_ const MSG *)
#define MAKELPARAM(l, h)
Definition: winuser.h:4008
#define WM_KEYUP
Definition: winuser.h:1716
#define EN_KILLFOCUS
Definition: winuser.h:2025
#define COLOR_WINDOW
Definition: winuser.h:918
BOOL WINAPI ShowWindow(_In_ HWND, _In_ int)
#define WM_MOUSELAST
Definition: winuser.h:1801
#define COLOR_SCROLLBAR
Definition: winuser.h:912
#define DT_CENTER
Definition: winuser.h:527
#define CBS_AUTOHSCROLL
Definition: winuser.h:281
#define CBS_DROPDOWNLIST
Definition: winuser.h:284
#define CallWindowProc
Definition: winuser.h:5735
#define COLOR_WINDOWTEXT
Definition: winuser.h:921
struct tagSCROLLINFO SCROLLINFO
#define WM_VSCROLL
Definition: winuser.h:1744
#define WM_CREATE
Definition: winuser.h:1608
#define DLGC_WANTCHARS
Definition: winuser.h:2618
#define GWL_ID
Definition: winuser.h:859
#define CB_SETTOPINDEX
Definition: winuser.h:1969
#define CB_SHOWDROPDOWN
Definition: winuser.h:1970
BOOL WINAPI DrawFrameControl(_In_ HDC, _Inout_ LPRECT, _In_ UINT, _In_ UINT)
#define EM_GETSEL
Definition: winuser.h:1997
BOOL WINAPI SetWindowPos(_In_ HWND, _In_opt_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ UINT)
#define DFCS_FLAT
Definition: winuser.h:510
#define VK_SPACE
Definition: winuser.h:2219
#define WM_SIZE
Definition: winuser.h:1611
#define COLOR_HIGHLIGHT
Definition: winuser.h:926
HBRUSH WINAPI GetSysColorBrush(_In_ int)
#define SB_VERT
Definition: winuser.h:553
#define DT_SINGLELINE
Definition: winuser.h:540
#define DLGC_WANTALLKEYS
Definition: winuser.h:2612
#define WM_LBUTTONDBLCLK
Definition: winuser.h:1778
#define WM_COMMAND
Definition: winuser.h:1740
#define DFCS_BUTTONCHECK
Definition: winuser.h:496
#define IDC_ARROW
Definition: winuser.h:687
#define CB_SETCURSEL
Definition: winuser.h:1961
#define VK_CONTROL
Definition: winuser.h:2203
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2670
#define DFC_BUTTON
Definition: winuser.h:476
#define WM_RBUTTONUP
Definition: winuser.h:1780
#define VK_UP
Definition: winuser.h:2225
#define WM_RBUTTONDBLCLK
Definition: winuser.h:1781
#define UnregisterClass
Definition: winuser.h:5861
#define WM_SETFOCUS
Definition: winuser.h:1613
#define WM_MOUSEMOVE
Definition: winuser.h:1775
#define RDW_UPDATENOW
Definition: winuser.h:1220
#define RDW_ERASE
Definition: winuser.h:1211
#define WM_CUT
Definition: winuser.h:1861
#define CB_RESETCONTENT
Definition: winuser.h:1959
#define CS_DBLCLKS
Definition: winuser.h:651
#define SPI_GETICONTITLELOGFONT
Definition: winuser.h:1380
#define WM_LBUTTONDOWN
Definition: winuser.h:1776
#define WM_SYSCOLORCHANGE
Definition: winuser.h:1626
#define SIF_TRACKPOS
Definition: winuser.h:1237
#define WM_GETFONT
Definition: winuser.h:1651
int WINAPI SetScrollPos(_In_ HWND, _In_ int, _In_ int, _In_ BOOL)
BOOL WINAPI ClientToScreen(_In_ HWND, _Inout_ LPPOINT)
#define SM_CYHSCROLL
Definition: winuser.h:962
#define WM_DRAWITEM
Definition: winuser.h:1645
#define GW_HWNDNEXT
Definition: winuser.h:761
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define VK_NEXT
Definition: winuser.h:2221
#define CBN_SELCHANGE
Definition: winuser.h:1979
#define DrawText
Definition: winuser.h:5771
#define CreateWindow
Definition: winuser.h:5754
#define WM_SHOWWINDOW
Definition: winuser.h:1628
#define WM_RBUTTONDOWN
Definition: winuser.h:1779
#define WM_SETTEXT
Definition: winuser.h:1617
#define EM_LINELENGTH
Definition: winuser.h:2003
#define DT_LEFT
Definition: winuser.h:534
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
#define RegisterClassEx
Definition: winuser.h:5837
#define MK_MBUTTON
Definition: winuser.h:2371
#define VK_RETURN
Definition: winuser.h:2201
#define HWND_TOP
Definition: winuser.h:1207
HWND WINAPI SetFocus(_In_opt_ HWND)
#define MK_CONTROL
Definition: winuser.h:2370
#define EM_SETLIMITTEXT
Definition: winuser.h:2011
#define WM_SETFONT
Definition: winuser.h:1650
#define WM_TIMER
Definition: winuser.h:1742
#define VK_END
Definition: winuser.h:2222
#define VK_HOME
Definition: winuser.h:2223
BOOL WINAPI EndPaint(_In_ HWND, _In_ const PAINTSTRUCT *)
#define DLGC_WANTARROWS
Definition: winuser.h:2610
#define CB_ADDSTRING
Definition: winuser.h:1936
#define SB_PAGEDOWN
Definition: winuser.h:569
#define SIF_ALL
Definition: winuser.h:1232
#define SWP_SHOWWINDOW
Definition: winuser.h:1248
#define SendMessage
Definition: winuser.h:5843
#define CBN_KILLFOCUS
Definition: winuser.h:1978
#define LoadCursor
Definition: winuser.h:5812
#define VK_BACK
Definition: winuser.h:2198
#define COLOR_HIGHLIGHTTEXT
Definition: winuser.h:927
HDC WINAPI GetDC(_In_opt_ HWND)
#define SB_LINEDOWN
Definition: winuser.h:565
#define EM_SETSEL
Definition: winuser.h:2018
#define CBS_DROPDOWN
Definition: winuser.h:283
#define GetWindowLong
Definition: winuser.h:5796
#define COLOR_BTNSHADOW
Definition: winuser.h:930
#define CB_SETEDITSEL
Definition: winuser.h:1963
#define CB_GETDROPPEDSTATE
Definition: winuser.h:1945
#define WM_LBUTTONUP
Definition: winuser.h:1777
#define WM_CHAR
Definition: winuser.h:1717
#define GetWindowText
Definition: winuser.h:5798
BOOL WINAPI IsWindowEnabled(_In_ HWND)
#define DT_VCENTER
Definition: winuser.h:543
#define PostMessage
Definition: winuser.h:5832
#define GetNextWindow(h, c)
Definition: winuser.h:4727
#define SM_CXHSCROLL
Definition: winuser.h:982
#define CW_USEDEFAULT
Definition: winuser.h:225
HWND WINAPI GetParent(_In_ HWND)
#define CS_GLOBALCLASS
Definition: winuser.h:652
#define VK_LEFT
Definition: winuser.h:2224
HWND WINAPI GetWindow(_In_ HWND, _In_ UINT)
#define WM_NCDESTROY
Definition: winuser.h:1684
#define VK_RIGHT
Definition: winuser.h:2226
#define VK_DOWN
Definition: winuser.h:2227
HWND WINAPI WindowFromPoint(_In_ POINT)
#define WM_COPY
Definition: winuser.h:1862
#define CB_GETTOPINDEX
Definition: winuser.h:1955
#define CB_LIMITTEXT
Definition: winuser.h:1958
#define MK_LBUTTON
Definition: winuser.h:2367
#define VK_SHIFT
Definition: winuser.h:2202
#define VK_PRIOR
Definition: winuser.h:2220
int WINAPI SetScrollInfo(_In_ HWND, _In_ int, _In_ LPCSCROLLINFO, _In_ BOOL)
#define WM_DESTROY
Definition: winuser.h:1609
#define SetWindowText
Definition: winuser.h:5857
#define DFCS_CHECKED
Definition: winuser.h:504
#define WM_CLEAR
Definition: winuser.h:1864
SHORT WINAPI GetAsyncKeyState(_In_ int)
#define WM_KEYDOWN
Definition: winuser.h:1715
#define DT_RIGHT
Definition: winuser.h:538
#define GW_CHILD
Definition: winuser.h:763
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
LRESULT(CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM)
Definition: winuser.h:2906
#define DT_CALCRECT
Definition: winuser.h:526
HDC WINAPI BeginPaint(_In_ HWND, _Out_ LPPAINTSTRUCT)
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
#define SystemParametersInfo
Definition: winuser.h:5858
#define CB_GETCURSEL
Definition: winuser.h:1943
#define GWL_STYLE
Definition: winuser.h:852
BOOL WINAPI GetScrollInfo(_In_ HWND, _In_ int, _Inout_ LPSCROLLINFO)
#define VK_ESCAPE
Definition: winuser.h:2214
BOOL WINAPI DestroyWindow(_In_ HWND)
#define WM_KILLFOCUS
Definition: winuser.h:1614
int WINAPI GetSystemMetrics(_In_ int)
#define SB_PAGEUP
Definition: winuser.h:568
BOOL WINAPI MoveWindow(_In_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ BOOL)
#define RDW_INVALIDATE
Definition: winuser.h:1214
#define WM_GETDLGCODE
Definition: winuser.h:1689
#define SB_HORZ
Definition: winuser.h:552
SHORT WINAPI GetKeyState(_In_ int)
#define VK_MENU
Definition: winuser.h:2204
#define CBN_EDITCHANGE
Definition: winuser.h:1975
#define EN_CHANGE
Definition: winuser.h:2022
#define COLOR_3DFACE
Definition: winuser.h:929
#define SB_THUMBPOSITION
Definition: winuser.h:572
BOOL WINAPI ScreenToClient(_In_ HWND, _Inout_ LPPOINT)
char TCHAR
Definition: xmlstorage.h:189
const CHAR * LPCTSTR
Definition: xmlstorage.h:193
CHAR * LPTSTR
Definition: xmlstorage.h:192
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
unsigned char BYTE
Definition: xxhash.c:193