[SNDVOL32] Advanced controls dialog: Remove the TBS_AUTOTICKS style from the trackbar...
[reactos.git] / base / setup / reactos / treelist.c
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)(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
172 typedef 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
193 typedef 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
205 typedef 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
226 typedef 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
342 } TreeListData;
343
344 typedef HRESULT(WINAPI *SetWindowThemeT)(HWND, LPCWSTR, LPCWSTR);
345 typedef HRESULT(WINAPI *EndBufferedPtT)(HANDLE, BOOL);
346 typedef HANDLE(WINAPI *BeginBufferedPnT)(HDC, RECT *, DWORD, LPVOID, HDC *);
347 typedef HRESULT(WINAPI *BufferedPtInitT)(VOID);
348 typedef HRESULT(WINAPI *BufferedPtInitT)(VOID);
349 typedef LPVOID (WINAPI *OpenThemeDataT)(HWND hwnd, LPCWSTR pszClassList);
350 typedef HRESULT(WINAPI *CloseThemeDataT)(LPVOID);
351 typedef HRESULT(WINAPI *DrawThemeBackgT)(LPVOID, HDC, int, int, const RECT *, const RECT *);
352 typedef HRESULT(WINAPI *GetThemeBackgRcT)(LPVOID, HDC, int, int, LPCRECT, LPRECT);
353 typedef BOOL (WINAPI *IsAppThemedT)();
354 typedef BOOL (WINAPI *IsThemeActiveT)();
355
356 static HMODULE hUxThemeDll = NULL;
357 static SetWindowThemeT pSetWindowTheme = NULL;
358 static EndBufferedPtT pEndBufferedPt = NULL;
359 static BeginBufferedPnT pBeginBufferedPt = NULL;
360 static BufferedPtInitT pBufferedPtInit = NULL;
361 static BufferedPtInitT pBufferedPtExit = NULL;
362 static OpenThemeDataT pOpenThemeData = NULL;
363 static CloseThemeDataT pCloseThemeData = NULL;
364 static DrawThemeBackgT pDrawThemeBackg = NULL;
365 static GetThemeBackgRcT pGetThemeBackgRc = NULL;
366 static IsAppThemedT pIsAppThemed = NULL;
367 static IsThemeActiveT pIsThemeActive = NULL;
368 static HPEN hPatternPen = NULL;
369 static HFONT hDefaultFontN = NULL;
370 static HFONT hDefaultFontB = NULL;
371 static LONG lWindowCount = -1;
372 #ifndef __REACTOS__
373 static RECT sToolRect = { -2, 0, 2, 64};
374 #endif
375 static TCHAR cKeyData[16];
376 static unsigned uKeyLast;
377 static unsigned uKeyPos;
378 static void TreeListDraw(HWND hWnd, HDC hDc, RECT *pRect);
379 static LRESULT CALLBACK TreeListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
380 static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int iMode);
381 static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT *pRect);
382 static int TreeListStartNotifyEdit(TreeListData *pData, unsigned uItem, unsigned uSub, WPARAM wParam, LPARAM lParam);
383 static int TreeListStartAutoEdit(TreeListData *pData, unsigned uColumn, WPARAM wParam, LPARAM lParam);
384 static int TreeListEndLabelEdit(TreeListData *pData, int iMode);
385 static BOOL bDrawWithTheme = FALSE;
386
387 //*****************************************************************************
388 //*
389 //* TreeListRegister
390 //*
391 //*****************************************************************************
392 // Registiert das TreeList Fenster.
393 // Ergibt 1 wenn das Fenster erfolgreich registiert wurde.
394 int TreeListRegister(HINSTANCE hInstance) {
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);
408 sClass.style = CS_DBLCLKS | CS_GLOBALCLASS;
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;
418 sClass.lpszClassName = _T(TVC_CLASSNAME);
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
429 BOOL TreeListUnregister(HINSTANCE hInstance){
430 return UnregisterClass(_T(TVC_CLASSNAME),hInstance);
431 }
432
433 //*****************************************************************************
434 //*
435 //* GlobalInit
436 //*
437 //*****************************************************************************
438 static void GlobalInit() {
439
440 LOGBRUSH sLog;
441 long lCount;
442
443
444
445 lCount = InterlockedIncrement(&lWindowCount);
446 if(lCount > 0)
447 return;
448
449 sLog.lbColor = GetSysColor(COLOR_BTNSHADOW);
450 sLog.lbStyle = PS_SOLID;
451 sLog.lbHatch = 0;
452 hPatternPen = ExtCreatePen(PS_COSMETIC | PS_ALTERNATE, 1, &sLog, 0, NULL);
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) {
462 pSetWindowTheme = (SetWindowThemeT)GetProcAddress(hUxThemeDll, "SetWindowTheme");
463 pEndBufferedPt = (EndBufferedPtT)GetProcAddress(hUxThemeDll, "EndBufferedPaint");
464 pBeginBufferedPt = (BeginBufferedPnT)GetProcAddress(hUxThemeDll, "BeginBufferedPaint");
465 pBufferedPtInit = (BufferedPtInitT)GetProcAddress(hUxThemeDll, "BufferedPaintInit");
466 pBufferedPtExit = (BufferedPtInitT)GetProcAddress(hUxThemeDll, "BufferedPaintUnInit");
467 pOpenThemeData = (OpenThemeDataT)GetProcAddress(hUxThemeDll, "OpenThemeData");
468 pCloseThemeData = (CloseThemeDataT)GetProcAddress(hUxThemeDll, "CloseThemeData");
469 pDrawThemeBackg = (DrawThemeBackgT)GetProcAddress(hUxThemeDll, "DrawThemeBackground");
470 pGetThemeBackgRc = (GetThemeBackgRcT)GetProcAddress(hUxThemeDll, "GetThemeBackgroundContentRect");
471 pIsAppThemed = (IsAppThemedT)GetProcAddress(hUxThemeDll, "IsAppThemed");
472 pIsThemeActive = (IsThemeActiveT)GetProcAddress(hUxThemeDll, "IsThemeActive");
473
474 if(pIsAppThemed && pIsThemeActive)
475 bDrawWithTheme = pIsAppThemed() && pIsThemeActive();
476 }
477 }
478
479 if(pBufferedPtInit) {
480 pBufferedPtInit();
481 }
482
483 }
484
485
486 //*****************************************************************************
487 //*
488 //* GlobalDeinit
489 //*
490 //*****************************************************************************
491 static void GlobalDeinit() {
492
493 int lCount;
494
495 lCount = InterlockedDecrement(&lWindowCount);
496 if(lCount >= 0)
497 return;
498
499 if(hDefaultFontN) {
500 DeleteObject(hDefaultFontN);
501 hDefaultFontN = NULL;
502 }
503
504 if(hDefaultFontB) {
505 DeleteObject(hDefaultFontB);
506 hDefaultFontB = NULL;
507 }
508
509 if(hPatternPen) {
510 DeleteObject(hPatternPen);
511 hPatternPen = NULL;
512 }
513
514 if(pBufferedPtExit) {
515 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
530 static LRESULT SendNotify(TreeListData *pData, NMHDR *pNotify) {
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
550 static 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)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
592 if(uFlags & TVIF_SELECTEDIMAGE) {
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
639 static 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)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
687 static LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
688
689 TreeListData *pData;
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);
714 pProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_USERDATA);
715 }
716
717 if(uMsg == WM_KEYDOWN) {
718 if(wParam == VK_RETURN) {
719 SendMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
720 return 0;
721 }
722
723 if(wParam == VK_ESCAPE) {
724 SendMessage(hParent, WM_COMMAND, MAKELONG(3, EN_ESCAPE), (LPARAM)hWnd);
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;
734 PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
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;
742 PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
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;
753 PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
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
768 PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
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)) {
793 SendMessage(hParent, WM_COMMAND, wParam, (LPARAM)hWnd);
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);;
813 SendMessage(hParent, WM_COMMAND, MAKELONG(3, EN_SETTEXT), (LPARAM)hWnd);
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
826 static LRESULT CALLBACK ToolProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
827
828 TreeListData *pData;
829 POINT sPoint;
830 UINT uPos;
831
832 if(uMsg == WM_SETFOCUS) {
833 SetFocus((HWND)lParam);
834 return 0;
835 }
836
837 pData = (TreeListData *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
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
862 static 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
1047 static void CreateToolTip(TreeListData *pData) {
1048
1049 TOOLINFO sInfo;
1050
1051 if(pData->hToolTip)
1052 return;
1053
1054 pData->hToolTip = CreateWindow(TOOLTIPS_CLASS, NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, pData->hWnd, NULL, NULL, NULL);
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);
1068 SetWindowLongPtr(pData->hToolTip, GWLP_USERDATA, (LPARAM)pData);
1069 SetWindowLongPtr(pData->hToolTip, GWLP_WNDPROC , (LPARAM)ToolProc);
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)
1080 static void CreateStateImageList(TreeListData *pData, int iMode) {
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);
1134 SelectObject(hDc, GetStockObject(NULL_PEN));
1135 SetBkMode(hDc, OPAQUE);
1136 SetBkColor(hDc, GetSysColor(COLOR_WINDOW));
1137 SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT));
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
1145 DrawFrameControl(hDc, &sRect, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT);
1146
1147 sRect.left = 16 * 2 + 8 - 7;
1148 sRect.right = 16 * 2 + 8 + 6;
1149
1150 DrawFrameControl(hDc, &sRect, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_FLAT);
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;
1159 sInfo.bmiHeader.biCompression = BI_RGB;
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
1179 ImageList_AddMasked(pData->hStates, hBmpNew, GetSysColor(COLOR_HIGHLIGHT));
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
1186 ImageList_AddMasked(pData->hChecks, hBmpNew, GetSysColor(COLOR_HIGHLIGHT));
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
1204 static HIMAGELIST CreateDragImage(TreeListData *pData, unsigned uItem, unsigned uSub) {
1205
1206 ExtraItem *pExtra;
1207 BaseItem *pEntry;
1208 HIMAGELIST hList;
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);
1289 SelectObject(hDc, GetStockObject(NULL_PEN));
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) {
1303 SetBkColor(hDc, GetSysColor(COLOR_WINDOW));
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;
1314 sInfo.bmiHeader.biCompression = BI_RGB;
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
1350 static void UpdateColorsList(TreeListData *pData) {
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 ])
1360 pData->uColors[TVC_BOX ] = GetSysColor(COLOR_BTNSHADOW);
1361 if(!pData->cColorChanged[TVC_EVEN ])
1362 pData->uColors[TVC_EVEN ] = GetSysColor(COLOR_WINDOW);
1363 if(!pData->cColorChanged[TVC_TEXT ])
1364 pData->uColors[TVC_TEXT ] = GetSysColor(COLOR_WINDOWTEXT);
1365 if(!pData->cColorChanged[TVC_LINE ])
1366 pData->uColors[TVC_LINE ] = GetSysColor(COLOR_WINDOWTEXT);
1367 if(!pData->cColorChanged[TVC_FRAME ])
1368 pData->uColors[TVC_FRAME ] = GetSysColor(COLOR_3DFACE);
1369 if(!pData->cColorChanged[TVC_TRACK ])
1370 pData->uColors[TVC_TRACK ] = GetSysColor(COLOR_WINDOWTEXT) ^ RGB(0, 0, 255);
1371 if(!pData->cColorChanged[TVC_INSERT ])
1372 pData->uColors[TVC_INSERT ] = GetSysColor(COLOR_INFOBK);
1373 if(!pData->cColorChanged[TVC_ODD ])
1374 pData->uColors[TVC_ODD ] = GetSysColor(COLOR_INFOBK);
1375 if(!pData->cColorChanged[TVC_BOXBG ])
1376 pData->uColors[TVC_BOXBG ] = GetSysColor(COLOR_WINDOW);
1377 if(!pData->cColorChanged[TVC_COLBK ])
1378 pData->uColors[TVC_COLBK ] = GetSysColor(COLOR_WINDOW);
1379 if(!pData->cColorChanged[TVC_COLODD ])
1380 pData->uColors[TVC_COLODD ] = GetSysColor(COLOR_BTNSHADOW);
1381 if(!pData->cColorChanged[TVC_COLEVEN])
1382 pData->uColors[TVC_COLEVEN] = GetSysColor(COLOR_WINDOW);
1383 if(!pData->cColorChanged[TVC_GRAYED ])
1384 pData->uColors[TVC_GRAYED ] = GetSysColor(COLOR_SCROLLBAR);
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.
1470 static int UpdateHeight(TreeListData *pData) {
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
1529 static int UpdateRect(TreeListData *pData, unsigned uItem, unsigned uSub) {
1530
1531 BaseItem *pEntry;
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
1567 static 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
1604 static int UpdateRow(TreeListData *pData, unsigned uItem) {
1605
1606 BaseItem *pEntry;
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
1636 static void UpdateView(TreeListData *pData) {
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
1658 static void UpdateScrollX(TreeListData *pData) {
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
1704 UpdateView(pData);
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
1724 static void UpdateScrollY(TreeListData *pData) {
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
1754 UpdateView(pData);
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
1771 static 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;
1781 BaseItem *pEntry;
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
1804 TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT, &sRect);
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)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)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)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
1921 if(uFlags & (TVHT_ONSUBICON | TVHT_ONSUBLABEL)) {
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
1928 TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT | TVIR_COLTOSUB(uCol), &sRect);
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)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 ?
1964 TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT | TVIR_COLTOSUB(uCol), &sRect);
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
2033 ExitTip:
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
2050 KillTimer(pData->hWnd, ID_TOOLTIPCHECK);
2051 }
2052
2053 return;
2054
2055 UserTip:
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
2121 static int CreateFontset(TreeListData *pData, HFONT 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
2150 static int UpdateFont(TreeListData *pData) {
2151
2152 int iPos;
2153 int iRet;
2154 HDC hDc;
2155 LOGFONT sLog;
2156 SIZE sSize;
2157 TEXTMETRIC sMetrics;
2158 BaseItem *pEntry;
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;
2167 hDefaultFontN = CreateFontIndirect(&sLog);
2168 sLog.lfWeight = FW_BOLD;
2169 hDefaultFontB = CreateFontIndirect(&sLog);
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
2249 static 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;
2258 BaseItem *pEntry;
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)
2380 UpdateScrollY(pData);
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
2391 static int UpdateColumns(TreeListData *pData) {
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
2493 static 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);
2558 UpdateColumns(pData);
2559 UpdateView(pData);
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
2593 static int TreeListToggleItem(TreeListData *pData, unsigned uItem, unsigned uAddFlags) {
2594
2595 NMTREEVIEW sNotify;
2596 BaseItem **pList;
2597 BaseItem *pEntry;
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) {
2615 uAction = ((pEntry->uState ^ TVIS_EXPANDED) & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) ? TVE_EXPAND : TVE_COLLAPSE;
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)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)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
2755 static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT *pRect) {
2756
2757 ExtraItem *pExtra;
2758 BaseItem *pEntry;
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
2861 static int TreeListEnsureVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
2862
2863 BaseItem *pEntry;
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);
2913 UpdateView(pData);
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);
2919 UpdateView(pData);
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);
2936 UpdateView(pData);
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);
2966 UpdateView(pData);
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
2990 static int TreeListIsVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
2991
2992 BaseItem *pEntry;
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.
3072 static int TreeListDeleteItem(TreeListData *pData, unsigned uItem, int iMode) {
3073
3074 NMTREEVIEW sNotify;
3075 ExtraItem **pList;
3076 ExtraItem *pExtra;
3077 BaseItem *pEntry;
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
3098 UpdateScrollY(pData);
3099 UpdateView(pData);
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
3117 UpdateScrollY(pData);
3118 UpdateView(pData);
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)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)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);
3297 UpdateView(pData);
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
3317 static int TreeListXorSelectItem(TreeListData *pData, unsigned uItem, int iMode) {
3318
3319 NMTREEVIEW sNotify;
3320 BaseItem *pEntry;
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)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)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
3418 static void TreeListRemoveFocus(TreeListData *pData) {
3419
3420 ExtraItem *pExtra;
3421 BaseItem *pEntry;
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
3459 static int TreeListSetFocus(TreeListData *pData, unsigned uItem, unsigned uSub) {
3460
3461 ExtraItem *pExtra;
3462 BaseItem *pEntry;
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
3484 TreeListRemoveFocus(pData);
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
3587 static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int iMode) {
3588
3589 NMTREEVIEW sNotify;
3590 ExtraItem *pExtra;
3591 BaseItem *pEntry;
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;
3635 if(TreeListXorSelectItem(pData, uPos, iMode))
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
3647 iMode &= ~(TVC_DESELECT | TVC_UNSELECT);
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)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)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)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)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)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)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
3924 EndSel:
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
3945 static int TreeListSelectChilds(TreeListData *pData, unsigned uItem, int iMode) {
3946
3947 BaseItem *pEntry;
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;
3969 iMode &= TVIS_WITHCHILDS;
3970
3971 for(;;) {
3972 pEntry = pData->pTreeItems[uItem];
3973
3974 if((pEntry->uState ^ uXor)&TVIS_SELECTED) {
3975 TreeListXorSelectItem(pData, uItem, TVC_UNKNOWN);
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
4008 static unsigned TreeListInsertItem(TreeListData *pData, TV_INSERTSTRUCT *pInsert) {
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;
4020 BaseItem *pEntry;
4021 BaseItem *pParent;
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)
4162 pNew->bCallback |= TVIF_SELECTEDIMAGE;
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)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
4501 DoInsert:
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
4613 TreeListSelectItem(pData, uPos, 0, TVC_UNKNOWN);
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
4628 static int TreeListSetItem(TreeListData *pData, const TV_ITEM *pItem) {
4629
4630 BYTE bCall;
4631 BYTE bFlags;
4632 ExtraItem **pList;
4633 ExtraItem *pExtra;
4634 BaseItem *pEntry;
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) {
4744 TreeListSelectItem(pData, 0 , 0, TVC_UNKNOWN);
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) {
4915 TreeListSelectItem(pData, 0 , 0, TVC_UNKNOWN);
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
4931 uMask &= TVIS_EXPANDPARTIAL | TVIS_EXPANDPARTIAL;
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
4966 static unsigned TreeListGetItem(TreeListData *pData, TV_ITEM *pItem) {
4967
4968 ExtraItem **pList;
4969 ExtraItem *pExtra;
4970 BaseItem *pEntry;
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
5119 static 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;
5149 TreeListEndLabelEdit(pData, 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;
5291 UpdateHeight(pData);
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
5303 UpdateScrollX(pData);
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.
5319 static 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;
5361 UpdateHeight(pData);
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 }
5369 SendMessage(pData->hHeader, WM_SETFONT, (WPARAM)hDefaultFontN, 0);
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
5600 UpdateScrollX(pData);
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)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
5643 static int TreeListScanColumn(TreeListData *pData, unsigned uSub) {
5644
5645 BaseItem **pList;
5646 BaseItem *pEntry;
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
5726 static unsigned TreeListHitTest(TreeListData *pData, TV_HITTESTINFO *pInfo) {
5727
5728 BaseItem *pEntry;
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)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
5923 static unsigned TreeListSetInsertMark(TreeListData *pData, unsigned uItem, int iMode) {
5924
5925 TV_INSERTSTRUCT sInsert;
5926 ExtraItem *pExtra;
5927 BaseItem *pEntry;
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)pEntry->uParent;
5954 sInsert.hInsertAfter = (HTREEITEM)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)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
5995 static LRESULT TreeListGetItemColor(TreeListData *pData, unsigned uItem, unsigned uSub, int iMode) {
5996
5997 COLORREF uColor;
5998 ExtraItem *pExtra;
5999 BaseItem *pEntry;
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
6042 static COLORREF TreeListSetItemColor(TreeListData *pData, unsigned uItem, unsigned uSub, COLORREF uColor, int iMode) {
6043
6044 TV_ITEM sSet;
6045 COLORREF uOld;
6046 ExtraItem *pExtra;
6047 BaseItem *pEntry;
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)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
6140 static int TreeListSetTrackItem(TreeListData *pData, unsigned uItem, unsigned uSub) {
6141
6142 ExtraItem *pExtra;
6143 BaseItem *pEntry;
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
6223 static unsigned TreeListGetNextItem(TreeListData *pData, unsigned uItem, unsigned uFlags) {
6224 BaseItem *pEntry;
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
6483 case TVGN_PREVIOUSVISIBLE:
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
6539 static unsigned TreeListFindItem(TreeListData *pData, unsigned uItem, TVFIND *pFind) {
6540 int iImage;
6541 BaseItem *pEntry;
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
6655 static unsigned TreeListNextSelUntil(TreeListData *pData, unsigned uItem, unsigned uStop) {
6656
6657 BaseItem *pEntry;
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
6727 static unsigned TreeListNextUnselUntil(TreeListData *pData, unsigned uItem, unsigned uStop) {
6728
6729 BaseItem *pEntry;
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 :
6798 static void TreeListChangeCheckbox(TreeListData *pData, UINT uItem, int iPosX, int iPosY) {
6799
6800 BaseItem *pTemp;
6801 BaseItem *pEntry;
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)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)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)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)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
6883 static void TreeListMouseNotify(TreeListData *pData, UINT uMsg, WPARAM wParam, LPARAM lParam) {
6884
6885 TV_HITTESTINFO sInfo;
6886 NMTREEVIEW sNotify;
6887 BaseItem *pEntry;
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)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
6931 static void TreeListMouseClick(TreeListData *pData, UINT uMsg, WPARAM wParam, LPARAM lParam) {
6932 ExtraItem *pExtra;
6933 BaseItem *pEntry;
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) {
6984 uMaskItem = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON | TVHT_ONITEMRIGHT;
6985 uMaskSub = TVHT_ONSUBICON | TVHT_ONSUBLABEL | TVHT_ONSUBRIGHT;
6986 } else {
6987 uMaskItem = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON;
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];
6994 if(pEntry && (pEntry->uState & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) == (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) {
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) {
7077 TreeListSelectItem(pData, uItem, 0, TVC_BYMOUSE | TVC_DESELECT);
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)) {
7092 TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD);
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;
7106 TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD);
7107 }
7108 }
7109
7110 pData->cReSelect = 0;
7111 goto End;
7112 }
7113
7114 TreeListSelectItem(pData, uItem, 0, TVC_BYMOUSE);
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) {
7144 TreeListXorSelectItem(pData, uTemp, TVC_BYMOUSE);
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;
7156 TreeListXorSelectItem(pData, uNum, TVC_BYMOUSE);
7157 }
7158 } else {
7159 for(uNum = uTemp;;) { // Kinder abwählen
7160 uNum = TreeListNextSelUntil(pData, uNum, uTemp);
7161 if(!uNum)
7162 break;
7163 TreeListXorSelectItem(pData, uNum, TVC_BYMOUSE);
7164 }
7165 }
7166 }
7167
7168 if(uPos == uStop)
7169 break;
7170 }
7171
7172 TreeListRemoveFocus(pData);
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
7192 TreeListSelectItem(pData, uItem, 0, TVC_BYMOUSE);
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
7209 TreeListSelectItem(pData, 0, 0, TVC_BYMOUSE);
7210
7211 if(TreeListXorSelectItem(pData, uItem, TVC_BYMOUSE)) {
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;
7219 TreeListXorSelectItem(pData, uTemp, TVC_BYMOUSE);
7220 }
7221 }
7222
7223 uTemp = pData->uFocusItem;
7224 if(uTemp) { // Ist ein Focus definiert
7225 TreeListRemoveFocus(pData);
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
7251 iMode = TVC_BYMOUSE;
7252 } else {
7253 iMode = TVC_BYMOUSE | TVC_DESELECT;
7254 }
7255
7256 uOldSub = pData->uSelectedSub;
7257 uOldItem = pData->uSelectedItem;
7258
7259 TreeListRemoveFocus(pData);
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) {
7267 TreeListStartAutoEdit(pData, 0, VK_DBLCLK, lParam);
7268 } else
7269 if(TreeListStartNotifyEdit(pData, pData->uSelectedItem, 0, VK_DBLCLK, lParam)) {
7270
7271 } else
7272 if(pEntry && (pEntry->uState & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) == (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) {
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) {
7299 TreeListStartAutoEdit(pData, 0, VK_EDITCLK, lParam);
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
7334 TreeListSelectItem(pData, 0, 0, TVC_BYMOUSE);
7335
7336 if(TreeListXorSelectItem(pData, uItem, TVC_BYMOUSE)) {
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;
7344 TreeListXorSelectItem(pData, uTemp, TVC_BYMOUSE);
7345 }
7346 }
7347
7348 TreeListRemoveFocus(pData);
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
7368 iMode = TVC_BYMOUSE;
7369 } else {
7370 iMode = TVC_BYMOUSE | TVC_DESELECT;
7371 }
7372
7373 uOldSub = pData->uSelectedSub;
7374 uOldItem = pData->uSelectedItem;
7375
7376 TreeListRemoveFocus(pData);
7377 TreeListSelectItem(pData, uItem, uSub, (wParam & MK_CONTROL) ? TVC_BYMOUSE : TVC_BYMOUSE | TVC_DESELECT);
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)))) {
7385 TreeListStartAutoEdit(pData, uSub, (sInfo.flags & TVHT_ONSUBICON) ? VK_ICONCLK : VK_DBLCLK, lParam);
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) {
7397 TreeListStartAutoEdit(pData, uSub, VK_ICONCLK, lParam);
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) {
7412 TreeListStartAutoEdit(pData, uSub, VK_EDITCLK, lParam);
7413 } else {
7414 TreeListStartNotifyEdit(pData, uItem, uSub, VK_EDITCLK, lParam);
7415 }
7416 }
7417 }
7418 }
7419 } else {
7420 pEntry = NULL;
7421 uSub = 0;
7422 }
7423
7424 End:
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)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
7491 static void TreeListChar(TreeListData *pData, UINT nChar, LPARAM lParam) {
7492
7493 LPTSTR pName;
7494 ExtraItem *pExtra;
7495 BaseItem *pEntry;
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
7635 static void TreeListKeyDown(TreeListData *pData, WPARAM wParam, LPARAM lParam) {
7636
7637 BaseItem *pTemp;
7638 BaseItem *pEntry;
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) {
7692 wParam = VK_ICONCLK;
7693 lParam = 0;
7694 }
7695
7696 TreeListStartAutoEdit(pData, iSub, wParam, lParam);
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;
7778 SetScrollPos(pData->hWnd, SB_VERT, iLine, TRUE);
7779 UpdateView(pData);
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);
7799 UpdateView(pData);
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 {
7834 TreeListRemoveFocus(pData);
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) {
7964 TreeListRemoveFocus(pData);
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)) {
7999 TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD);
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;
8014 TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD);
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) {
8042 if(!TreeListXorSelectItem(pData, uItem, TVC_BYKEYBOARD))
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;
8057 TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD);
8058 }
8059 } else {
8060 for(uTemp = uItem;;) {
8061 uTemp = TreeListNextUnselUntil(pData, uTemp, uItem);
8062 if(!uTemp)
8063 break;
8064 TreeListXorSelectItem(pData, uTemp, TVC_BYKEYBOARD);
8065 }
8066 }
8067 }
8068 }
8069 }
8070 }
8071 }
8072
8073 Exit:
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
8096 static int TreeListSortItemsEx(TreeListData *pData, TV_SORTEX *pSortData, int iMode) {
8097
8098 TV_SORTEX sSort;
8099 unsigned uNum;
8100 unsigned uItem;
8101 unsigned uLast;
8102 unsigned uFirst;
8103 unsigned uParent;
8104 BaseItem *pParent;
8105 BaseItem *pEntry;
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)uFirst;
8144 sSort.lParam = pSortData->lParam;
8145 sSort.lpfnCompare = pSortData->lpfnCompare;
8146 TreeListSortItemsEx(pData, &sSort, iMode);
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)uFirst;
8167 sSort.lParam = pSortData->lParam;
8168 sSort.lpfnCompare = pSortData->lpfnCompare;
8169 TreeListSortItemsEx(pData, &sSort, iMode);
8170 return 1;
8171 }
8172 }
8173
8174 if(iMode) { // Sortiere die Untereinträge
8175 pNext = pList[uFirst];
8176 sSort.hParent = (HTREEITEM)uFirst;
8177 sSort.lParam = pSortData->lParam;
8178 sSort.lpfnCompare = pSortData->lpfnCompare;
8179
8180 while(pNext) {
8181 if(pNext->uFirstChild) {
8182 TreeListSortItemsEx(pData, &sSort, SORT_NOUPDATE);
8183 }
8184
8185 sSort.hParent = (HTREEITEM)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)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)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)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
8358 static int TreeListSortItemsCb(TreeListData *pData, TV_SORTCB *pSortData, int iMode) {
8359
8360 TV_SORTCB sSort;
8361 unsigned uNum;
8362 unsigned uItem;
8363 unsigned uLast;
8364 unsigned uFirst;
8365 unsigned uParent;
8366 BaseItem *pParent;
8367 BaseItem *pEntry;
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)uFirst;
8403 sSort.lParam = pSortData->lParam;
8404 sSort.lpfnCompare = pSortData->lpfnCompare;
8405 TreeListSortItemsCb(pData, &sSort, iMode);
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)uFirst;
8426 sSort.lParam = pSortData->lParam;
8427 sSort.lpfnCompare = pSortData->lpfnCompare;
8428 TreeListSortItemsCb(pData, &sSort, iMode);
8429 return 1;
8430 }
8431 }
8432
8433 if(iMode) { // Sortiere die Untereinträge
8434 pNext = pList[uFirst];
8435 sSort.hParent = (HTREEITEM)uFirst;
8436 sSort.lParam = pSortData->lParam;
8437 sSort.lpfnCompare = pSortData->lpfnCompare;
8438
8439 while(pNext) {
8440 if(pNext->uFirstChild) {
8441 TreeListSortItemsCb(pData, &sSort, SORT_NOUPDATE);
8442 }
8443
8444 sSort.hParent = (HTREEITEM)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
8614 static int TreeListSortItems(TreeListData *pData, unsigned uParent, int iMode) {
8615
8616 unsigned uNum;
8617 unsigned uItem;
8618 unsigned uLast;
8619 unsigned uFirst;
8620 BaseItem *pParent;
8621 BaseItem *pEntry;
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) {
8688 TreeListSortItems(pData, uItem, SORT_NOUPDATE);
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
8889 static int TreeListEndLabelEdit(TreeListData *pData, int iMode) {
8890 TCHAR cText[2052];
8891 NMTVDISPINFO sNotify;
8892 TV_ITEM sSet;
8893 LRESULT lRet;
8894 unsigned uSub;
8895 unsigned uItem;
8896 ExtraItem *pExtra;
8897 BaseItem *pEntry;
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)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)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)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
9109 static 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;
9118 BaseItem *pEntry;
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);
9199 SetWindowLongPtr(pData->hEdit, GWLP_USERDATA, (LPARAM)pData);
9200 SetWindowLongPtr(pData->hEdit, GWLP_WNDPROC , (LPARAM)EditProc);
9201
9202 hWnd = GetWindow(pData->hEdit, GW_CHILD);
9203
9204 while(hWnd) {
9205 pProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
9206 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)pProc);
9207 SetWindowLongPtr(hWnd, GWLP_WNDPROC , (LPARAM)EditProc);
9208 hWnd = GetNextWindow(hWnd, GW_HWNDNEXT);
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
9218 TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT, &sRect);
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);
9231 DrawText(hDc, pText, uSize, &sRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
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 {
9272 TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT | TVIR_COLTOSUB(uSub), &sRect);
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);
9297 DrawText(hDc, pText, uSize, &sRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
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)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
9358 TreeListEndLabelEdit(pData, 0);
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
9451 RedrawWindow(pData->hEdit, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
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
9479 static int TreeListStartNotifyEdit(TreeListData *pData, unsigned uItem, unsigned uSub, WPARAM wParam, LPARAM lParam) {
9480
9481 TCHAR cText[1024];
9482 TV_STARTEDIT sNotify;
9483 ExtraItem *pExtra;
9484 BaseItem *pEntry;
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)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 {
9572 TreeListGetItemRect(pData, uItem, TVIR_COLTOSUB(uSub) | TVIR_GETCOLUMN | TVIR_TEXT, &sRect);
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
9600 SendMessage(hWnd, CB_ADDSTRING, 1, (LPARAM)pText);
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
9649 SendMessage(hWnd, CB_SETDROPPEDWIDTH, sNotify.uHeight, 0);
9650 }
9651
9652 if(lRet & TVIR_EDITCOMBODOWN) { // Dropdown-Liste einblenden
9653 SendMessage(hWnd, CB_SHOWDROPDOWN, 1, 0);
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
9695 static int TreeListStartAutoEdit(TreeListData *pData, unsigned uColumn, WPARAM wParam, LPARAM lParam) {
9696
9697 TCHAR cBuffer[256];
9698 NMTREEVIEW sNotify;
9699 ExtraItem *pExtra;
9700 BaseItem *pEntry;
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)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
9889 NoTextChange:
9890
9891 sItem.mask &= ~TVIF_TEXTPTR;
9892 sItem.stateMask &= TVIS_STATEIMAGEMASK;
9893 sItem.hItem = (HTREEITEM)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 *************************************
9929 EditField:
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)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;
9965 SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)pList[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 {
9994 SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)pText);
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
10011 SendMessage(hWnd, CB_SHOWDROPDOWN, 1, 0);
10012 }
10013
10014 // Ersten Buchstaben ans Fenster übergeben
10015 if(TVIS_EDIT(uMode) && pData->cColumnStart && wParam != VK_EDITCLK) {
10016 SendMessage(hWnd, WM_CHAR, wParam, 0);
10017 }
10018
10019 return 1;
10020 }
10021
10022 //*****************************************************************************
10023 //*
10024 //* TreeListProc
10025 //*
10026 //*****************************************************************************
10027 // Ist die Fensterfunktion für das TreeList Fenster
10028 static LRESULT CALLBACK TreeListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
10029
10030 TreeListData *pData;
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
10084 SetWindowLongPtr(hWnd, 0, (LONG_PTR)pData);
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)) {
10102 CreateToolTip(pData);
10103 }
10104
10105 UpdateFont(pData);
10106 UpdateHeight(pData);
10107 UpdateColorsList(pData);
10108 UpdateScrollY(pData);
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) {
10118 CreateStateImageList(pData, 0);
10119 }
10120
10121 return 0;
10122
10123 case WM_DESTROY: // Das Fenster zerstören
10124
10125 pData = GetHandle(hWnd);
10126
10127 LOCK(pData);
10128
10129 TreeListDeleteItem(pData, U(TVI_ROOT), 0);
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
10252 UpdateScrollY(pData);
10253 UpdateScrollX(pData);
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);
10299 UpdateScrollX(pData);
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;
10338 UpdateView(pData);
10339 }
10340 }
10341 }
10342 UpdateScrollY(pData);
10343 }
10344
10345 UNLOCK(pData);
10346
10347 if(uFlag) {
10348 RedrawWindow(pData->hHeader, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
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);
10360 SetWindowLong(hWnd, GWL_STYLE, uVal);
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 {
10382 UpdateView(pData);
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 {
10410 UpdateView(pData);
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;
10465 BaseItem *pEntry;
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)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) {
10526 TreeListMouseClick(pData, uMsg, wParam, lParam);
10527 pData->cClickFlag = 0;
10528 pData->cClickEdit = 0;
10529 } else {
10530 TreeListMouseNotify(pData, TVN_LBUTTONUP, wParam, lParam);
10531 }
10532
10533 return 0;
10534
10535 case WM_RBUTTONUP: // Linken Mausklick aufheben
10536
10537 pData = GetHandle(hWnd);
10538 pData->uDragFlags &= ~MK_RBUTTON;
10539
10540 TreeListMouseNotify(pData, TVN_RBUTTONUP, wParam, lParam);
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) {
10561 TreeListMouseClick(pData, WM_LBUTTONDBLCLK, wParam, lParam);
10562 return 0;
10563 }
10564 }
10565 }
10566
10567 pData->cButtonFlag = 1;
10568 pData->uButtonLast = uTime;
10569 pData->uButtonPos = U(lParam);
10570
10571 TreeListMouseClick(pData, uMsg, wParam, lParam);
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;
10584 TreeListMouseClick(pData, uMsg, wParam, lParam);
10585
10586 return 0;
10587
10588 case WM_KEYDOWN: // Tastendruck
10589
10590 pData = GetHandle(hWnd);
10591 LOCK(pData);
10592 TreeListKeyDown(pData, wParam, lParam);
10593
10594 return 0;
10595
10596 case WM_KEYUP: // Tastendruck
10597
10598 DefWindowProc(hWnd, uMsg, wParam, lParam);
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++) {
10607 TreeListChar(pData, (UINT)wParam, lParam);
10608 }
10609
10610 return 0;
10611
10612 case WM_DRAWITEM: // Weietleiten von OwnerDraw des Headers
10613
10614 if(wParam == 1) {
10615 pData = GetHandle(hWnd);
10616 return SendMessage(GetParent(hWnd), uMsg, GetWindowLong(hWnd, GWL_ID), lParam);
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);
10650 UpdateView(pData);
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);
10701 UpdateView(pData);
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);
10753 UpdateView(pData);
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)
10780 CreateStateImageList(pData, 0);
10781 if(pData->iChecksMode)
10782 CreateStateImageList(pData, 1);
10783
10784 if(pData->hHeader)
10785 SendMessage(pData->hHeader, WM_SYSCOLORCHANGE, 0, 0);
10786 UpdateColorsList(pData);
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
10808 if(CreateFontset(pData, (HFONT)wParam)){
10809 if(UpdateFont(pData))
10810 UpdateView(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) {
10830 CreateStateImageList(pData, 0);
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
10843 UpdateHeight(pData);
10844 UpdateScrollY(pData);
10845 }
10846
10847 if(uChange & (TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_RTLREADING | TVS_CHECKBOXES | TVS_TRACKSELECT)) {
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
10854 UpdateView(pData);
10855 }
10856
10857 if(uChange & TVS_NOSCROLL) {
10858 pData->uOldYCount = 0xFFFF;
10859 pData->uOldXCount = 0xFFFF;
10860
10861 UpdateScrollX(pData);
10862 UpdateScrollY(pData);
10863 }
10864
10865 if(uChange & TVS_NOTOOLTIPS) {
10866 if(pData->uStyle & TVS_NOTOOLTIPS) {
10867 UpdateToolTip(pData, 0, 0);
10868 } else {
10869 CreateToolTip(pData);
10870 }
10871 }
10872
10873 if(uChange & WS_DISABLED) {
10874 pData->cIsEnabled = (char)((pData->uStyle & WS_DISABLED) ? 0 : 1);
10875 UpdateView(pData);
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) {
10888 TreeListDraw(hWnd, (HDC)wParam, NULL);
10889 } else {
10890 PAINTSTRUCT sPaint;
10891
10892 hDc = BeginPaint(hWnd, &sPaint);
10893
10894 if(pBeginBufferedPt && pEndBufferedPt) {
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
11003 if(wParam == MAKELONG(3, EN_KILLFOCUS) || wParam == MAKELONG(3, EN_RETURN) || wParam == MAKELONG(3, CBN_KILLFOCUS)) {
11004 pData = GetHandle(hWnd);
11005 if(pData->uEditItem) {
11006 LOCK(pData);
11007 TreeListEndLabelEdit(pData, (wParam == MAKELONG(3, EN_RETURN)) ? 2 : 1);
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);
11019 TreeListEndLabelEdit(pData, 0);
11020 UNLOCK(pData);
11021 if(pData->uEditMode)
11022 SetFocus(pData->hWnd);
11023 }
11024 } // Änderung in Edit-Fenster
11025 else
11026 if(wParam == MAKELONG(3, EN_CHANGE) || wParam == MAKELONG(3, CBN_EDITCHANGE) || wParam == MAKELONG(3, CBN_SELCHANGE) || wParam == MAKELONG(3, EN_SETTEXT)) {
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
11079 PostMessage(hWnd, TVM_SETCOLUMNORDERARRAY, FROM_HEADER, 0);
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;
11157 iCode = HDN_ENDTRACK;
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
11295 UpdateScrollX(pData);
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
11314 if(iCode == HDN_ITEMCLICK || iCode == HDN_ITEMDBLCLICK) {
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
11347 return DLGC_WANTCHARS | DLGC_WANTARROWS;
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;
11401 UpdateHeight(pData);
11402 UpdateScrollY(pData);
11403 } else {
11404 UpdateView(pData);
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;
11425 UpdateHeight(pData);
11426 UpdateScrollY(pData);
11427 } else {
11428 UpdateView(pData);
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) {
11451 CreateStateImageList(pData, 0);
11452 }
11453 } else
11454 if(pData->hStates == THEMEIMGLIST) {
11455 pData->iStatesXsize = 16;
11456 pData->iStatesYsize = 16;
11457 pData->iStatesMode = 1;
11458 if(!pData->hThemeBt)
11459 CreateStateImageList(pData, 0);
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;
11470 UpdateHeight(pData);
11471 UpdateScrollY(pData);
11472 } else {
11473 UpdateView(pData);
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;
11499 CreateStateImageList(pData, 1);
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)
11508 CreateStateImageList(pData, 1);
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;
11519 UpdateHeight(pData);
11520 UpdateScrollY(pData);
11521 } else {
11522 UpdateView(pData);
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;
11553 UpdateHeight(pData);
11554 UpdateScrollY(pData);
11555 } else {
11556 UpdateView(pData);
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) {
11610 UpdateView(pData);
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) {
11627 BaseItem *pEntry;
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);
11665 lRet = TreeListInsertItem(pData, (TV_INSERTSTRUCT *)lParam);
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);
11683 lRet = TreeListFindItem(pData, U(wParam), (TV_FIND *)lParam);
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);
11692 lRet = TreeListDeleteColumn(pData, U(wParam));
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);
11701 lRet = TreeListInsertColumn(pData, (int)wParam, (TV_COLUMN *)lParam);
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) {
11736 UpdateScrollX(pData);
11737 }
11738
11739 if((uChange & TVS_EX_GRAYEDDISABLE) && !pData->cIsEnabled) {
11740 UpdateView(pData);
11741 }
11742
11743 if(uChange & TVS_EX_ITEMLINES) {
11744 UpdateHeight(pData);
11745 UpdateScrollY(pData);
11746 }
11747
11748 if(uChange & (TVS_EX_ALTERNATECOLOR | TVS_EX_SUBSELECT | TVS_EX_MULTISELECT | TVS_EX_FULLROWMARK | TVS_EX_FULLROWITEMS)) {
11749 UpdateView(pData);
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
11767 UpdateView(pData);
11768 }
11769 }
11770
11771 UNLOCK(pData);
11772 }
11773
11774 return uVal;
11775
11776 case TVM_GETINSERTMARKCOLOR: // Farben abfragen
11777 wParam = TVC_INSERT;
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
11786 ColGet:
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
11793 wParam = TVC_INSERT;
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
11802 ColSet:
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;
11815 UpdateColorsList(pData);
11816 UpdateView(pData);
11817 }
11818 } else {
11819 pData->cColorChanged[U(wParam)] = 1;
11820 pData->uColors [U(wParam)] = (COLORREF)lParam;
11821
11822 if(lRet != lParam) {
11823 UpdateColorsList(pData);
11824 UpdateView(pData);
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);
11837 lRet = TreeListHitTest(pData, (LPTV_HITTESTINFO)lParam);
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);
11847 lRet = TreeListSelectChilds(pData, U(lParam), U(wParam));
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;
11859 lRet = TreeListSelectItem(pData, U(lParam), U(wParam), TVC_UNKNOWN);
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);
11871 lRet = TreeListSetTrackItem(pData, U(lParam), U(wParam));
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:
11884 lRet = TreeListSelectItem(pData, U(lParam), 0, TVC_UNKNOWN);
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:
11893 lRet = TreeListEnsureVisible(pData, U(lParam), FIRST_LINE);
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;
11948 UpdateView(pData);
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;
11967 UpdateHeight(pData);
11968 UpdateScrollY(pData);
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;
11985 UpdateView(pData);
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;
12038 NextExp:
12039 if(U(lParam) <= pData->uTreeItemsMax) {
12040 BaseItem *pEntry;
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
12070 if(wParam & TVE_COLLAPSERESET) {
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)) {
12094 uVal = (wParam & TVE_EXPANDPARTIAL) ? TVIS_EXPANDPARTIAL : 0;
12095 lRet = (TreeListToggleItem(pData, U(lParam), uVal)) ? 0 : 1;
12096 } else { // Schon aufgeklappt
12097 lRet = 1;
12098
12099 if(wParam & TVE_EXPANDPARTIAL) {
12100 if(!(wParam & TVE_EXPANDFORCE))
12101 if((pEntry->uState & (TVIS_EXPANDPARTIAL | TVIS_EXPANDEDONCE)) != (TVIS_EXPANDPARTIAL | TVIS_EXPANDEDONCE)) {
12102 lRet = (TreeListToggleItem(pData, U(lParam), TVE_EXPAND | TVIS_EXPANDPARTIAL)) ? 0 : 1;
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;
12131 wParam &= ~(TVE_EXPANDRECURSIVE | TVE_EXPANDNEXT | TVE_ONLYCHILDS);
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);
12215 lRet = TreeListSortItemsEx(pData, (TV_SORTEX *)lParam, (int)wParam);
12216 UNLOCK(pData);
12217
12218 return lRet;
12219
12220 case TVM_SORTCHILDRENCB: // Sortieren mit Funktion
12221
12222 pData = GetHandle(hWnd);
12223
12224 LOCK(pData);
12225 lRet = TreeListSortItemsCb(pData, (TV_SORTCB *)lParam, (int)wParam);
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) {
12271 BaseItem *pEntry;
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
12294 lRet = TreeListStartNotifyEdit(pData, U(lParam), TVIR_EDITCOL(wParam), VK_RETURN, 0);
12295 } else {
12296 pData->cColumnStart = 0;
12297 lRet = (LRESULT)TreeListEditLabel(pData, U(lParam), U(wParam));
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) {
12350 BaseItem *pEntry;
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) {
12577 CreateStateImageList(pData, 1);
12578 UpdateHeight(pData);
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);
12632 lRet = (LRESULT)CreateDragImage(pData, U(lParam), U(wParam));
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
12681 static 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;
12701 TreeListData *pData;
12702 BaseItem *pTemp;
12703 BaseItem *pEntry;
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);
12832 SelectObject(hDc, hPatternPen);
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
12896 if((uStyleEx & (TVS_EX_ITEMLINES | TVS_EX_FULLROWITEMS)) == (TVS_EX_ITEMLINES | TVS_EX_FULLROWITEMS)) {
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
12988 uState = ((uBits ^ TVIS_EXPANDED) & (TVIS_EXPANDED | TVIS_EXPANDPARTIAL)) ? GLPS_CLOSED : GLPS_OPENED;
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
13047 NoRootLines:
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
13151 if(uBits & (TVIS_SELECTED | TVIS_DROPHILITED | TVIS_UNDERLINE | TVIS_TRACKED | TVIS_TEXTCOLOR | TVIS_FOCUSED)) {
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);
13199 SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT));
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);
13204 SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT));
13205 SelectObject(hDc, GetStockObject(NULL_PEN));
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);
13211 SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT));
13212 SelectObject(hDc, GetStockObject(NULL_PEN));
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)
13220 SelectObject(hDc, GetStockObject(NULL_BRUSH));
13221 else
13222 SelectObject(hDc, GetSysColorBrush(COLOR_3DFACE));
13223
13224 SelectObject(hDc, GetStockObject(NULL_PEN));
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
13240 SelectObject(hDc, hPatternPen);
13241
13242 if(uBits & TVIS_FOCUSED) { // Einen punktierten Rahmen um den Text zeichnen
13243 SelectObject(hDc, GetStockObject(NULL_BRUSH));
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
13339 ExtraDraw:
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
13483 if(uBits & (TVIS_SELECTED | TVIS_DROPHILITED | TVIS_UNDERLINE | TVIS_TRACKED | TVIS_TEXTCOLOR | TVIS_FOCUSED)) {
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);
13554 SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT));
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);
13559 SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT));
13560 SelectObject(hDc, GetStockObject(NULL_PEN));
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)
13570 SelectObject(hDc, GetStockObject(NULL_BRUSH));
13571 else
13572 SelectObject(hDc, GetSysColorBrush(COLOR_3DFACE));
13573
13574 SelectObject(hDc, GetStockObject(NULL_PEN));
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
13588 SelectObject(hDc, hPatternPen);
13589
13590 if(uBits & TVIS_FOCUSED) { // Punktierten Rahmen um Text zeichnen
13591 SelectObject(hDc, GetStockObject(NULL_BRUSH));
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:
13660 SetTextAlign(hDc, TA_CENTER | TA_TOP);
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:
13666 SetTextAlign(hDc, TA_RIGHT | TA_TOP);
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) {
13721 UpdateScrollX(pData);
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 }