ReactOS 0.4.16-dev-338-g34e76ad
treelist.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS GUI first stage setup application
3 * LICENSE: GPL-3.0-or-later (https://spdx.org/licenses/GPL-3.0-or-later)
4 * PURPOSE: Implements a TreeList control: a tree window with columns.
5 * COPYRIGHT: Copyright (C) Anton Zechner (az_software@inode.at) 2007
6 * Copyright (C) Sébastien Kirche (sebastien.kirche@free.fr) 2014
7 *
8 * NOTE: Taken from the TreeList code found at https://github.com/sebkirche/treelist
9 */
10
11//*****************************************************************************
12//*
13//*
14//* TreeListWnd.cpp
15//*
16//*
17//*****************************************************************************
18//
19// This code creates a tree window with a list
20//
21//
22// Copyright (C) Anton Zechner (az_software@inode.at) 2007
23// Copyright (C) Sébastien Kirche (sebastien.kirche@free.fr) 2014
24//
25// TreeListWnd is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
26// Sourcecode which use TreeListWnd must be published. Commercial users
27// must published their code too, or make an licence agreement with me.
28//
29//
30// TreeListWnd wird unter GNU GENERAL PUBLIC LICENSE (GPL) vertreiben.
31// Sourcecode welcher TreeListWnd verwendet muss veröffendlicht werden.
32// Komerzielle Nutzer müssen ihren Code ebenfalls veröffentlichen, oder
33// eine Nutzungsvereinbarung mit mir treffen.
34//
35//
36// Version: 2.04
37//
38#ifdef UNICODE
39#ifndef _UNICODE
40#define _UNICODE
41#endif
42#endif
43
44#if 0
45 #include <stdio.h>
46 #include <windows.h>
47 #include <string.h>
48 #include <malloc.h>
49 #include <tchar.h>
50#else
51 #include "reactos.h"
52#endif
53
54#define new(TYPE, numElems) \
55 HeapAlloc(GetProcessHeap(), 0, (numElems) * sizeof(TYPE))
56#define delete(ptr) \
57 HeapFree(GetProcessHeap(), 0, (ptr))
58
59
60#include "treelist.h"
61
62#ifndef GWLP_USERDATA
63#define GWLP_USERDATA GWL_USERDATA
64#endif
65#ifndef GWLP_WNDPROC
66#define GWLP_WNDPROC GWL_WNDPROC
67#endif
68#ifndef _WIN64
69#ifndef SetWindowLongPtr
70#define SetWindowLongPtr SetWindowLong
71#endif
72#ifndef GetWindowLongPtr
73#define GetWindowLongPtr GetWindowLong
74#endif
75#ifndef DWORD_PTR
76#define DWORD_PTR DWORD
77#endif
78#ifndef LONG_PTR
79#define LONG_PTR LONG
80#endif
81#endif
82#ifdef UNICODE
83#define str_len (unsigned)wcslen
84#define str_cmp wcscmp
85#define str_ncpy wcsncpy
86#define str_ncmp wcsncmp
87#define str_icmp _wcsicmp
88#else
89#define str_len (unsigned)strlen
90#define str_cmp strcmp
91#define str_ncpy strncpy
92#define str_ncmp strncmp
93#define str_icmp _stricmp
94#endif
95#ifndef WM_MOUSEWHEEL
96#define WM_MOUSEWHEEL 0x020A
97#endif
98#ifndef WHEEL_DELTA
99#define WHEEL_DELTA 120
100#endif
101#ifndef MAX_COLUMNS
102#define MAX_COLUMNS 32
103#endif
104#define MAX_COLORS 16
105#define EN_SETTEXT 0x1000
106#define EN_RETURN 0x1578
107#define EN_ESCAPE 0x1579
108#define ID_TOOLTIPCHECK 0x3912
109#define SORT_NOUPDATE 1234567
110#define VK_ISACHAR 0x01000000
111#define FIRST_LINE 0xFFFFFFFE
112#define FROM_HEADER 0x88776655
113#define I_CCB I_CHILDRENCALLBACK
114#define U(h) ((unsigned)(ULONG_PTR)(h))
115#define THEMEIMGLIST ((HIMAGELIST)1)
116#define GetHandle(h) ((TreeListData*)GetWindowLongPtr(h,0))
117#define TVIF_ALL (TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT)
118#define UNLOCK(d) ReleaseSemaphore(d->hSem,1,NULL)
119#define LOCK(d) WaitForSingleObject(d->hSem,INFINITE)
120#define TVIS_EDIT(m) ((1<<m)&((1<<TVAX_EDIT)|(1<<TVAX_COMBO)|(1<<TVAX_STEPED)|(1<<TVAX_CHECKED)))
121#define TVIS_BASEFLAGS (TVIS_EXPANDED|TVIS_EXPANDEDONCE|TVIS_EXPANDPARTIAL|TVIS_SELECTED)
122#define TVIS_TRACKED (TVIX_TRACKED<<16)
123#define TVIS_BKCOLOR (TVIX_BKCOLOR<<16)
124#undef TVIS_FOCUSED
125#define TVIS_FOCUSED (TVIX_FOCUSED<<16)
126#define TVIS_TEXTCOLOR (TVIX_TEXTCOLOR<<16)
127#define TVC_ONLYFOCUS TVIF_ONLYFOCUS
128#define TVC_UNSELECT 0x4000
129#define TVC_DESELECT 0x8000
130#define DEFAULT_IDENT 19
131#define DEFAULT_SHIFT 7
132#ifndef BPBF_COMPATIBLEBITMAP
133#define BPBF_COMPATIBLEBITMAP 0
134#endif
135#ifndef TVP_GLYPH
136#define TVP_GLYPH 2
137#endif
138#ifndef GLPS_CLOSED
139#define GLPS_CLOSED 1
140#endif
141#ifndef GLPS_OPENED
142#define GLPS_OPENED 2
143#endif
144#ifndef BP_CHECKBOX
145#define BP_CHECKBOX 3
146#endif
147#ifndef CBS_UNCHECKEDNORMAL
148#define CBS_UNCHECKEDNORMAL 1
149#endif
150#ifndef CBS_CHECKEDNORMAL
151#define CBS_CHECKEDNORMAL 5
152#endif
153
154
155#define TVAX_NONE (TVAE_NONE >>TVAE_MODEPOS)// No automatic edit
156#define TVAX_EDIT (TVAE_EDIT >>TVAE_MODEPOS)// automatic edit with edit
157#define TVAX_COMBO (TVAE_COMBO >>TVAE_MODEPOS)// automatic edit with ComboBox
158#define TVAX_CBLIST (TVAE_CBLIST >>TVAE_MODEPOS)// automatic edit with ComboListBox
159#define TVAX_STEP (TVAE_STEP >>TVAE_MODEPOS)// Einzelnes Weiterschalten mit Enter
160#define TVAX_STEPED (TVAE_STEPED >>TVAE_MODEPOS)// Einzelnes Weiterschalten mit Enter und Edit
161#define TVAX_CHECK (TVAE_CHECK >>TVAE_MODEPOS)// automatic edit with CheckBox
162#define TVAX_CHECKED (TVAE_CHECKED>>TVAE_MODEPOS)// automatic edit with CheckBox and Edit
163
164#define TVIX_VARBUTTON 0x01 // buttons are not permanent
165#define TVIX_HASBUTTON 0x02 // entry has button
166#define TVIX_HASIMAGE 0x04 // entry has icon
167#define TVIX_TRACKED 0x08 // entry under the cursor
168#define TVIX_TEXTCOLOR 0x10 // entry has its own text color
169#define TVIX_BKCOLOR 0x20 // entry has its own backround color
170#define TVIX_FOCUSED 0x40 // entry has the focus
171
172typedef struct {
173 LPARAM lParam; // LPARAM argument for the item
174 LPTSTR pText; // pointer to the item text
175 UINT uState; // item state
176 int iImage; // item image index
177 int iSelectedImage; // item selected image index
178 unsigned uShowPos; // Ist die Position in der Sichtbarliste (0=unsichtbar)
179 unsigned uFirstChild; // Ist die Nummer des ersten Kind-Eintrages (0=keines)
180 unsigned uLastChild; // Ist die Nummer des letzten Kind-Eintrages (0=keines)
181 unsigned uPrevItem; // Ist die Nummer des vorherigen Eintrages (0=keines)
182 unsigned uNextItem; // Ist die Nummer des nächsten Eintrages (0=keines)
183 unsigned uParent; // Ist die Nummer des Elterneintrages (0=Root)
184 unsigned uLevel; // Ist die Ebene des Eintrages (0=Root)
185 int iTextPixels; // Ist die Breites des Textes in Pixel
186 WORD uTextSize; // Länge des Textes in Zeichen
187 BYTE bCallback; // Sind Bits für Callbacks
188 BYTE bFlags; // Diverse Flags
189 COLORREF uColorText; // Spezielle Textfarbe
190 COLORREF uColorBk; // Spezielle Hintergrundfarbe
191} BaseItem;
192
193typedef struct {
194 LPTSTR pText; // Zeiger auf Tree-Text
195 UINT uState; // Zustand des Eintrages
196 int iImage; // Ist die Nummer des an zu zeigenden Icons
197 int iTextPixels; // Ist die Breites des Textes in Pixel
198 WORD uTextSize; // Länge des Textes in Zeichen
199 BYTE bCallback; // Sind Bits für Callbacks
200 BYTE bFlags; // Diverse Flags
201 COLORREF uColorText; // Spezielle Textfarbe
202 COLORREF uColorBk; // Spezielle Hintergrundfarbe
203} ExtraItem;
204
205typedef struct {
206 void *pCbData; // Data for autoedit
207 INT iCbIcon; // Starting offset for in icon list for autoedit
208 short sSize; // width of the column
209 short sReal; // real width of the column
210 short sMin; // minimum width
211 short sFixed; // fixed width
212 BYTE bMinEx; // the width cannot be less than min width
213 BYTE bWeight; // weight for variable columns
214 BYTE bNext; // Ist die Spalte die nach der eigenen sichtbar ist (gespeicherte Reihenfolge)
215 BYTE bIndex; // Ist die Spalte in der diese Reihe sichtbar ist (sichtbarer Index)
216 BYTE bAlign; // Text alignment
217 BYTE bEdit; // Automaisches Editiern einer Spalte (siehe TVAE_???>>7)
218 BYTE bFlags; // Automaisches Editiern einer Spalte (siehe TVAE_???)
219 BYTE bEnable; // Automaisches einer mit Statebits aktivieren
220 BYTE bCbSize; // Maximum number of entries in the data list
221 BYTE bCbChar; // separator for the data list
222 BYTE bMark; // is column marked ?
223 BYTE bDummy[32 - 23 - sizeof(void *)]; // padding bytes - 32 bytes alignment
224} ColumnData;
225
226typedef struct {
227 HWND hWnd; // handle of the control
228 HANDLE hSem; // access semaphore
229 LPVOID hTheme; // Handle für benutztes Thema (TREELIST)
230 LPVOID hThemeBt; // Handle für benutztes Thema (BUTTON)
231 WNDPROC pProcId3; // Fenster Funktion für ID3 Fenster
232 HIMAGELIST hStates; // Handle der Icon-Liste für States und Overlay
233 HIMAGELIST hImages; // Handle der Icon-Liste
234 HIMAGELIST hChecks; // Handle der Icon-Liste für die Checkboxen in den Spalten
235 HIMAGELIST hSubImg; // Handle der Icon-Liste für die Spalten
236 HIMAGELIST hHeadImg; // Handle for header images
237 HFONT hFontN; // Normal font
238 HFONT hFontB; // Bold fonts
239 HFONT hFontL; // Last used font
240 HFONT hFontT; // Tooltip font
241 HWND hEdit; // Handle des Edit-Fensters
242 HWND hHeader; // Handle des Header Fensters
243 HWND hToolTip; // Handle des Tooltip-Fensters
244 WNDPROC pToolProc; // Alte Fensterfunktion des Tooltips
245 COLORREF uColors[MAX_COLORS]; // 0=Hintergrundfarbe 1=Abwechselnte Farbe 2=Farbe für Trennlinien 3=Textfarbe
246 int iFontHeight; // Ist die Höhe des Fonts
247 int iFontLine; // Ist die Position der Linie beim unterstreichen
248 int iFontOff; // Ist die Position um der ein Text horizontal verschoben wird
249 int iStatesMode; // Die hStates Image-Liste wurde für die Checkboxen erzeugt
250 int iStatesXsize; // Breite der States und Overlay Icons
251 int iStatesYsize; // Höhe der States und Overlay Icons
252 int iChecksMode; // Die hChecks Image-Liste wurde für die Checkboxen erzeugt
253 int iChecksXsize; // Breite der States und Overlay Icons
254 int iChecksYsize; // Höhe der States und Overlay Icons
255 int iImagesXsize; // Breite der Icons
256 int iImagesYsize; // Höhe der Icons
257 int iSubImgMode; // Die SubImg Image-Liste ist nicht die hImages Liste
258 int iSubImgXsize; // Breite der Icons
259 int iSubImgYsize; // Höhe der Icons
260 int iRowHeight; // Ist die Höhe einer Zeile
261 int iAllWeight; // Das Gewicht aller variablen Spalten
262 int iVarSize; // Ist die Breite aller variablen Spalten
263 int iFixSize; // Ist die Breite aller fixen Spalten
264 int iIndent; // Einrückung der Kindereintäge
265 int iShift; // Einrückung der vertikalen Linien
266 int iAutoAdd; // Offset zum Open-Icon für TVS_EX_AUTOEXPANDICON
267 int iMaxSizeX; // Die Größe des breitesten sichtbaren Eintrages
268 unsigned uItemPosCount; // Anzahl der sichtbaren Einträge
269 unsigned *pItemPos; // Liste mit den Offsets der sichtbaren Einträge
270 BaseItem **pTreeItems; // Zeiger auf Item Zeiger
271 ExtraItem **pExtraItems[MAX_COLUMNS - 1]; // Zeiger auf die Spalteneinträge
272 unsigned uTreeItemsMax; // Größe der Liste mit den vorhanden Einträge (alociert um 1 größer)
273 unsigned uTreeItemsCount; // Anzahl der vorhanden Einträge
274 unsigned uNextSeachPos; // Nächste Position zum suchen von freien Einträgen
275 unsigned uUserDataSize; // Ist die Größe der Userdaten in einem Eintrag
276 unsigned uFirstChild; // Ist die Nummer des ersten Kind-Eintrages (0=keines)
277 unsigned uLastChild; // Ist die Nummer des letzten Kind-Eintrages (0=keines)
278 unsigned uSingleSel; // Ist die Nummer des gewählten Eintrages (bei Checkboxen)
279 unsigned uScrollX; // Aktuelle X-Scroll-Position
280 unsigned uScrollY; // Aktuelle Y-Scroll-Position
281 unsigned uSizeX; // Aktuelle X-Fenster-Größe
282 unsigned uSizeY; // Aktuelle Y-Fenster-Größe
283 unsigned uSizeYsub; // Aktuelle Y-Fenster-Größe ohne Header
284 unsigned uStyle; // Ist der aktuele Style des Fensters
285 unsigned uStyleEx; // Erweiterte Sytle-Flags (siehe TVS_EX_???)
286 unsigned uStartPixel; // Ist die Y-Koordinate bei der der erste Eintrag beginnt
287 unsigned uMaxEnties; // Anzahl der sichtbaren Einträge (inkl. halbsichtbare)
288 unsigned uPageEnties; // Anzahl der sichtbaren Einträge (ohne halbsichtbare)
289 unsigned uColumnCount; // Anzahl der Spalten
290 unsigned uColumnCountVar; // Anzahl der variabeln Spalten
291 unsigned uSelectedCount; // Anzahl der ausgewählten Einträge
292 unsigned uSelectedBase; // Ist der Eintrag ab dem gewählt wurde
293 unsigned uSelectedItem; // Ist der Eintrag der gerade gewählt ist
294 unsigned uSelectedSub; // Ist die Spalte die gerade gewählt ist
295 unsigned uFocusItem; // Ist der Eintrag der einen leeren Focus hat
296 unsigned uFocusSub; // Ist die Spalte die einen leeren Focus hat
297 unsigned uToolTipItem; // Ist der ToolTip-Eintrag der gerade gewählt ist
298 unsigned uToolTipShow; // Ist die Zeitverzögerung in 500 ms Schritten für das Tooltip
299 unsigned uToolTipSub; // Ist die ToolTip-Spalte die gerade gewählt ist
300 POINT sToolTipPos; // Ist die globale Koordinate des ToolTips
301 unsigned uEditMode; // Ist der Modus des Editfensters (0=Edit 1=ComboBox 2=ComboBox fix)
302 unsigned uEditItem; // Ist der Eintrag der gerade editiert wird
303 unsigned uEditSub; // Ist die Spalte die gerade editiert wird
304 unsigned uOldXPage; // Alte Werte für X-Scroll-Bar
305 unsigned uOldXCount; // *
306 unsigned uOldYPage; // Alte Werte für Y-Scroll-Bar
307 unsigned uOldYCount; // *
308 unsigned uTrippleB; // Bereite des "..." Strings für den fetten Fonts
309 unsigned uTrippleN; // Bereite des "..." Strings für den normalen Fonts
310 unsigned uTrackedItem; // Ist der Eintrag der unterstrichen werden soll
311 unsigned uTrackedSub; // Ist die Spalte des Eintrages der unterstrichen werden soll
312 unsigned uInsertMark; // Ist der Eintrag mit der Einfügemarke
313 unsigned uMarkedCols; // Anzahl der markierten Spalten
314 unsigned uDragFlags; // Welche Maustasten sind an
315 unsigned uDragItem; // Eintrag für Dragoperation
316 unsigned uDragSub; // Untereintrag für Dragoperation
317 unsigned uLastSel; // Letzte Textauswahl beim Editieren
318 unsigned uLastMove; // Letzte Cursorposition bei WM_MOUSEMOVE
319 unsigned uButtonPos; // Wo wurde eine Maustaste wurde zuletzt gedrückt
320 unsigned uButtonLast; // Wann wurde eine Maustaste wurde zuletzt gedrückt
321 unsigned uToolTipSize; // Textspeichergröße für Tooltip
322 LPTSTR pToolTipText; // Textspeicher für Tooltip
323 TCHAR cTempText1 [260]; // Erster Textpuffer für Callbacks
324 TCHAR cTempText2 [260]; // Zeiter Textpuffer für Callbacks
325 ColumnData aColumn [MAX_COLUMNS]; // Daten der Spalten
326 int aColumnXpos [MAX_COLUMNS + 2]; // Array mit den Positionen der Spalten
327 BYTE aColumnPos [MAX_COLUMNS + 2]; // Array mit Anzeigepositionen der Spalten
328 char cColorChanged[MAX_COLORS ]; // Welche Farbe wurden verändert
329 char cColumnStart; // Wurde das Autoeditiren mit einer WM_CHAR Eingabe gestartet
330 char cFixedHeight; // Ist eine fixe Höhe eingestellt
331 char cLockChanges; // Sperren von Fensteränderungen
332 char cHasRootRow; // Wird gesetzt wenn eine Root-Spalte eingefügt wird
333 char cKeyIgnore; // Die nächste Taste nicht für Sucher verwenden
334 char cClickFlag; // Merker für LBUTTON-DOWN bei Multiselect
335 char cClickEdit; // Merker für LBUTTON-DOWN bei Edit-Click
336 char cIsEnabled; // Ist das Fenster freigegeben
337 char cHasFocus; // Hat das Fenster den Focus
338 char cReSelect; // Soll die Auswahl neu selektiert werden
339 char cGlyphOk; // Die Schaltfäche über Themen zeichnen
340 char cEditCb; // Muss das Edit-Fenster einen Callback aufrufen
341 char cButtonFlag; // Welche Maustaste wurde zuletzt gedrückt
343
349typedef LPVOID (WINAPI *OpenThemeDataT)(HWND hwnd, LPCWSTR pszClassList);
351typedef HRESULT(WINAPI *DrawThemeBackgT)(LPVOID, HDC, int, int, const RECT *, const RECT *);
355
368static HPEN hPatternPen = NULL;
371static LONG lWindowCount = -1;
372#ifndef __REACTOS__
373static RECT sToolRect = { -2, 0, 2, 64};
374#endif
375static TCHAR cKeyData[16];
376static unsigned uKeyLast;
377static unsigned uKeyPos;
378static void TreeListDraw(HWND hWnd, HDC hDc, RECT *pRect);
380static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int iMode);
381static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT *pRect);
382static int TreeListStartNotifyEdit(TreeListData *pData, unsigned uItem, unsigned uSub, WPARAM wParam, LPARAM lParam);
383static int TreeListStartAutoEdit(TreeListData *pData, unsigned uColumn, WPARAM wParam, LPARAM lParam);
386
387//*****************************************************************************
388//*
389//* TreeListRegister
390//*
391//*****************************************************************************
392// Registiert das TreeList Fenster.
393// Ergibt 1 wenn das Fenster erfolgreich registiert wurde.
395
396 static int iIsRegistered = FALSE;
397 WNDCLASSEX sClass;
398
399 OutputDebugString(TEXT("TreeListRegister() - before checking\n"));
400
401 if(iIsRegistered)
402 return TRUE;
403
404 OutputDebugString(TEXT("TreeListRegister() - before registration\n"));
405
406 memset(&sClass, 0, sizeof(sClass));
407 sClass.cbSize = sizeof(sClass);
409 sClass.lpfnWndProc = TreeListProc;
410 sClass.cbClsExtra = 0;
411 sClass.cbWndExtra = sizeof(TreeListData *);
412 sClass.hInstance = hInstance;
413 sClass.hIcon = NULL;
414 sClass.hCursor = LoadCursor(NULL, IDC_ARROW);
415 sClass.hbrBackground = NULL;
416 sClass.lpszMenuName = NULL;
417 sClass.hIconSm = NULL;
419
420 if(!RegisterClassEx(&sClass))
421 return 0;
422
423 OutputDebugString(TEXT("TreeListRegister() - registration done\n"));
424 iIsRegistered = TRUE;
425
426 return TRUE;
427}
428
431}
432
433//*****************************************************************************
434//*
435//* GlobalInit
436//*
437//*****************************************************************************
438static void GlobalInit() {
439
440 LOGBRUSH sLog;
441 long lCount;
442
443
444
446 if(lCount > 0)
447 return;
448
450 sLog.lbStyle = PS_SOLID;
451 sLog.lbHatch = 0;
453
454 if(!hPatternPen) {
455 hPatternPen = CreatePen(PS_DOT, 1, RGB(0, 0, 0));
456 }
457
458
459 if(!hUxThemeDll) {
460 hUxThemeDll = LoadLibrary(_T("UxTheme.dll"));
461 if(hUxThemeDll) {
470 pGetThemeBackgRc = (GetThemeBackgRcT)GetProcAddress(hUxThemeDll, "GetThemeBackgroundContentRect");
473
476 }
477 }
478
479 if(pBufferedPtInit) {
481 }
482
483}
484
485
486//*****************************************************************************
487//*
488//* GlobalDeinit
489//*
490//*****************************************************************************
491static void GlobalDeinit() {
492
493 int lCount;
494
496 if(lCount >= 0)
497 return;
498
499 if(hDefaultFontN) {
502 }
503
504 if(hDefaultFontB) {
507 }
508
509 if(hPatternPen) {
512 }
513
514 if(pBufferedPtExit) {
516 }
517
518}
519
520
521//*****************************************************************************
522//*
523//* SendNotify
524//*
525//*****************************************************************************
526// Sendet eine WM_NOTIFY Nachricht and das Elternfenster
527// pData : Zeiger auf die Fensterdaten
528// pNotify : Zeiger auf die Notify-Daten
529// Ergibt den Rückgabewert der WM_NOTIFY Nachrich
531
532 pNotify->hwndFrom = pData->hWnd;
533 pNotify->idFrom = GetWindowLong(pNotify->hwndFrom, GWL_ID);
534
535 return SendMessage(GetParent(pNotify->hwndFrom), WM_NOTIFY, pNotify->idFrom, (LPARAM)pNotify);
536}
537
538
539//*****************************************************************************
540//*
541//* CallbackEntry
542//*
543//*****************************************************************************
544// Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen
545// pData : Zeiger auf die Fensterdaten
546// pEntry : Zeiger auf den Eintrag
547// uItem : Nummer des Eintrages
548// uFlags : Welche Daten sollen abgefragt werden
549// Ergibt den Rückgabewert der WM_NOTIFY Nachrich
550static void CallbackEntry(TreeListData *pData, BaseItem *pEntry, unsigned uItem, unsigned uFlags, int *iImage, unsigned *uTextSize, LPCTSTR *pText) {
551
552 NMTVDISPINFO sInfo;
553
554 sInfo.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | uFlags;
555 sInfo.item.lParam = pEntry->lParam;
556 sInfo.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
557 sInfo.item.state = pEntry->uState;
558 sInfo.item.stateMask = 0xFFFFFFFF;
559 sInfo.item.iImage = I_IMAGECALLBACK;
560 sInfo.item.iSelectedImage = I_IMAGECALLBACK;
561 sInfo.item.cChildren = I_CHILDRENCALLBACK;
562
563 if(uFlags & TVIF_TEXT) {
564 if(*uTextSize) {
565 pData->cTempText2[sizeof(pData->cTempText2) / sizeof(TCHAR) - 1] = 0;
566 pData->cTempText2[0] = 0;
567 sInfo.item.pszText = pData->cTempText2;
568 sInfo.item.cchTextMax = sizeof(pData->cTempText2) / sizeof(TCHAR) - 1;
569 } else {
570 pData->cTempText1[sizeof(pData->cTempText1) / sizeof(TCHAR) - 1] = 0;
571 pData->cTempText1[0] = 0;
572 sInfo.item.pszText = pData->cTempText1;
573 sInfo.item.cchTextMax = sizeof(pData->cTempText1) / sizeof(TCHAR) - 1;
574 }
575 } else {
576 sInfo.item.pszText = 0;
577 sInfo.item.cchTextMax = 0;
578 }
579
580 sInfo.hdr.hwndFrom = pData->hWnd;
581 sInfo.hdr.idFrom = GetWindowLong(pData->hWnd, GWL_ID);
582 sInfo.hdr.code = TVN_GETDISPINFO;
583
584 UNLOCK(pData);
585 SendMessage(GetParent(sInfo.hdr.hwndFrom), WM_NOTIFY, sInfo.hdr.idFrom, (LPARAM)&sInfo);
586 LOCK(pData);
587
588 if(uFlags & TVIF_IMAGE) {
589 if(!(pEntry->uState & TVIS_SELECTED))
590 *iImage = sInfo.item.iImage;
591 } else
593 if(pEntry->uState & TVIS_SELECTED)
594 *iImage = sInfo.item.iSelectedImage;
595 }
596
597 if(uFlags & TVIF_CHILDREN) {
598 switch(sInfo.item.cChildren) {
599 case 0:
600 pEntry->bFlags &= ~TVIX_HASBUTTON;
601 pEntry->bFlags |= TVIX_VARBUTTON;
602 break;
603
604 case 1:
605 pEntry->bFlags &= ~TVIX_VARBUTTON;
606 pEntry->bFlags |= TVIX_HASBUTTON;
607 break;
608
609 default
610 :
611 pEntry->bFlags |= TVIX_VARBUTTON;
612
613 if(pEntry->uFirstChild)
614 pEntry->bFlags |= TVIX_HASBUTTON;
615 else
616 pEntry->bFlags &= ~TVIX_HASBUTTON;
617 }
618 }
619
620 if(uFlags & TVIF_TEXT) {
621 *pText = sInfo.item.pszText;
622 *uTextSize = str_len(sInfo.item.pszText);
623 pEntry->iTextPixels = 0;
624 }
625
626}
627
628//*****************************************************************************
629//*
630//* CallbackExtra
631//*
632//*****************************************************************************
633// Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen
634// pData : Zeiger auf die Fensterdaten
635// pEntry : Zeiger auf den Eintrag
636// uItem : Nummer des Eintrages
637// uFlags : Welche Daten sollen abgefragt werden
638// Ergibt den Rückgabewert der WM_NOTIFY Nachrich
639static void CallbackExtra(TreeListData *pData, BaseItem *pEntry, ExtraItem *pExtra, unsigned uItem, unsigned uSub, unsigned uFlags, int *iImage, unsigned *uTextSize, LPCTSTR *pText) {
640
641 NMTVDISPINFO sInfo;
642
643 sInfo.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | uFlags;
644 sInfo.item.lParam = pEntry->lParam;
645 sInfo.item.hItem = (HTREEITEM)(ULONG_PTR)uItem;
646 sInfo.item.state = pExtra->uState;
647 sInfo.item.state |= (pEntry->uState & TVIS_BASEFLAGS);
648 sInfo.item.stateMask = 0xFFFFFFFF;
649 sInfo.item.iImage = I_IMAGECALLBACK;
650 sInfo.item.iSelectedImage = I_IMAGECALLBACK;
651 sInfo.item.cChildren = uSub;
652
653 if(uFlags & TVIF_TEXT) {
654 pData->cTempText1[sizeof(pData->cTempText1) / sizeof(TCHAR) - 1] = 0;
655 pData->cTempText1[0] = 0;
656 sInfo.item.pszText = pData->cTempText1;
657 sInfo.item.cchTextMax = sizeof(pData->cTempText1) / sizeof(TCHAR) - 1;
658 } else {
659 sInfo.item.pszText = 0;
660 sInfo.item.cchTextMax = 0;
661 }
662
663 sInfo.hdr.hwndFrom = pData->hWnd;
664 sInfo.hdr.idFrom = GetWindowLong(pData->hWnd, GWL_ID);
665 sInfo.hdr.code = TVN_GETDISPINFO;
666
667 UNLOCK(pData);
668 SendMessage(GetParent(sInfo.hdr.hwndFrom), WM_NOTIFY, sInfo.hdr.idFrom, (LPARAM)&sInfo);
669 LOCK(pData);
670
671
672 if(uFlags & TVIF_IMAGE)
673 *iImage = sInfo.item.iImage;
674 if(uFlags & TVIF_TEXT) {
675 *pText = sInfo.item.pszText;
676 *uTextSize = str_len(sInfo.item.pszText);
677 }
678
679}
680
681//*****************************************************************************
682//*
683//* EditProc
684//*
685//*****************************************************************************
686// Ist die Fensterfunktion für das Edit Fenster
688
690 WNDPROC pProc;
691 DWORD dwStop;
692 DWORD dwStart;
693 DWORD dwCount;
694 LRESULT lResult;
695 HWND hParent;
696 HWND hCombo;
697 int iDelta;
698 int iState;
699 int iPos;
700 int iId;
701
702
703 hParent = GetParent(hWnd);
704 iId = GetWindowLong(hWnd, GWL_ID);
705
706 if(iId == 3) {
707 hCombo = hWnd;
708 pData = GetHandle(hParent);
709 pProc = pData->pProcId3;
710 } else {
711 hCombo = hParent;
712 hParent = GetParent(hParent);
713 pData = GetHandle(hParent);
715 }
716
717 if(uMsg == WM_KEYDOWN) {
718 if(wParam == VK_RETURN) {
720 return 0;
721 }
722
723 if(wParam == VK_ESCAPE) {
725 return 0;
726 }
727
728 if((pData->uStyleEx & TVS_EX_STEPOUT) && !(GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
729 switch(wParam) { // Aus Fenster springen
730
731 case VK_UP:
732 if(pData->uEditMode)
733 break;
735 PostMessage(hParent, WM_KEYDOWN, VK_UP , 0x00500001);
736 PostMessage(hParent, WM_KEYUP , VK_UP , 0x00500001);
737 return 0;
738
739 case VK_DOWN:
740 if(pData->uEditMode)
741 break;
743 PostMessage(hParent, WM_KEYDOWN, VK_DOWN, 0x00500001);
744 PostMessage(hParent, WM_KEYUP , VK_DOWN, 0x00500001);
745 return 0;
746
747 case VK_LEFT:
748 if(pData->uEditMode && iId == 3)
749 break;
750 SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwStop);
751 if(dwStart || dwStop)
752 break;
754 PostMessage(hParent, WM_KEYDOWN, VK_LEFT, 0x00500001);
755 PostMessage(hParent, WM_KEYUP , VK_LEFT, 0x00500001);
756 return 0;
757
758 case VK_RIGHT:
759 if(pData->uEditMode && iId == 3)
760 break;
761 SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwStop);
762 dwCount = (DWORD)SendMessage(hWnd, EM_LINELENGTH, 0, 0);
763 if(dwCount > dwStart)
764 break;
765 if(dwCount > dwStop)
766 break;
767
769 PostMessage(hParent, WM_KEYDOWN, VK_RIGHT, 0x00500001);
770 PostMessage(hParent, WM_KEYUP , VK_RIGHT, 0x00500001);
771 return 0;
772 }
773 }
774
775 if(wParam == VK_DOWN && pData->uEditMode) {
776 if(!SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0)) {
777 SendMessage(hCombo, CB_SHOWDROPDOWN, 1, 0);
778 return 0;
779 }
780 }
781 } else
782 if(uMsg == WM_CHAR) {
783 if(wParam == VK_RETURN) {
784 return 0;
785 }
786
787 if(wParam == VK_ESCAPE) {
788 return 0;
789 }
790 } else
791 if(uMsg == WM_COMMAND) {
792 if(wParam == MAKELONG(3, EN_ESCAPE) || wParam == MAKELONG(3, EN_RETURN)) {
794 return 0;
795 }
796 } else
797 if(uMsg == WM_MOUSEWHEEL) {
798 iState = (int)CallWindowProc(pProc, hWnd, CB_GETDROPPEDSTATE, 0, 0);
799 if(iState) {
800 iDelta = (short)HIWORD(wParam);
801 iDelta /= WHEEL_DELTA;
802 iPos = (int)CallWindowProc(pProc, hWnd, CB_GETTOPINDEX, 0, 0);
803 iPos -= iDelta;
804 CallWindowProc(pProc, hWnd, CB_SETTOPINDEX, iPos, 0);
805 return 0;
806 }
807 } else
808 if(uMsg == WM_GETDLGCODE) { // Welche Tasten werden im Dialog benutzt
809 return DLGC_WANTALLKEYS;
810 } else
811 if(uMsg == WM_SETTEXT) {
812 lResult = CallWindowProc(pProc, hWnd, uMsg, wParam, lParam);;
814 return lResult;
815 }
816
817 return CallWindowProc(pProc, hWnd, uMsg, wParam, lParam);
818}
819
820//*****************************************************************************
821//*
822//* ToolProc
823//*
824//*****************************************************************************
825// Ist die Fensterfunktion für das ToolTip Fenster
827
829 POINT sPoint;
830 UINT uPos;
831
832 if(uMsg == WM_SETFOCUS) {
834 return 0;
835 }
836
838
839 if(uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) { // Mausklicks auf Tooltip zum Elternfenster
840 sPoint.x = LOWORD(lParam);
841 sPoint.y = HIWORD(lParam);
842
843 ClientToScreen(hWnd , &sPoint);
844 ScreenToClient(pData->hWnd, &sPoint);
845
846 uPos = MAKELONG(sPoint.x, sPoint.y);
847
848 return TreeListProc(pData->hWnd, uMsg, wParam, uPos);
849 }
850
851 return CallWindowProc(pData->pToolProc, hWnd, uMsg, wParam, lParam);
852}
853
854//*****************************************************************************
855//*
856//* ChangeColSize
857//*
858//*****************************************************************************
859// Ändert die Größe der variablen Spalten
860// pData : Zeiger auf die Fensterdaten
861// iDelta : Ist die Größenänderung in Pixel
862static void ChangeColSize(TreeListData *pData, int iDelta) {
863
864 unsigned uPos;
865 HDITEM sItem;
866 RECT sRect;
867 TV_COLSIZE sNotify;
868 int iWeight;
869 int iValue;
870 int iPoint;
871 int iStart;
872 int iSize;
873 int iRest;
874 int iOff;
875 int iNum;
876 int iCnt;
877 int iAll;
878 int iVar;
879 int iFix;
880
881 sItem.mask = HDI_WIDTH;
882 iAll = pData->iAllWeight;
883 iCnt = pData->uColumnCountVar;
884
885 if(iCnt <= 1) { // Nur eine variable Spalte
886 for(uPos = 0; uPos < pData->uColumnCount; uPos++) {
887 iWeight = pData->aColumn[uPos].bWeight;
888 if(!iWeight)
889 continue;
890
891 iValue = pData->aColumn[uPos].sSize;
892 iValue += iDelta;
893 sItem.cxy = iValue;
894
895 pData->aColumn[uPos].sSize = (short)iValue;
896 pData->iVarSize = iValue;
897
898 if(sItem.cxy < pData->aColumn[uPos].sMin) {
899 sItem.cxy = pData->aColumn[uPos].sMin;
900 }
901
902 if(pData->aColumn[uPos].sReal != sItem.cxy) { // Ändert sich die Breite
903 pData->aColumn[uPos].sReal = (short)sItem.cxy;
904 Header_SetItem(pData->hHeader, uPos, &sItem);
905
906 if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) {
907 sNotify.hdr.code = TVN_COLUMNCHANGED;
908 sNotify.uColumn = uPos;
909 sNotify.uIndex = pData->aColumn[uPos].bIndex;
910 sNotify.uPosX = pData->aColumnXpos[uPos];
911 sNotify.iSize = sItem.cxy;
912
913 UNLOCK(pData);
914 SendNotify(pData, &sNotify.hdr);
915 LOCK(pData);
916 }
917 }
918
919 break;
920 }
921
922 return;
923 }
924
925 if(iDelta > 0)
926 iStart = (pData->uSizeX) % iAll;
927 else
928 iStart = (pData->uSizeX - iDelta) % iAll;
929
930 iOff = 0;
931
932 for(uPos = 0;; uPos++) { // Suchen die Anfangsspalte
933 iWeight = pData->aColumn[uPos].bWeight;
934 if(!iWeight)
935 continue;
936
937 iOff += iWeight;
938 if(iOff > iStart)
939 break;
940 }
941
942
943 iPoint = 0;
944 iSize = iDelta / iAll;
945 iRest = iDelta % iAll;
946 iNum = iRest;
947 iOff -= iStart;
948
949 iWeight = iOff;
950 iValue = pData->aColumn[uPos].sSize;
951 iValue += iSize * iWeight;
952 iPoint += iRest * iWeight;
953 iValue += iPoint / iAll;
954 iNum -= iPoint / iAll;
955 iPoint %= iAll;
956
957 pData->aColumn[uPos].sSize = (short)iValue;
958
959
960 if(iWeight >= pData->aColumn[uPos].bWeight) { // Wurde die ganze Spalte berechnet
961 iCnt--;
962 iOff = 0;
963 }
964
965 while(iCnt > 0) {
966 uPos++;
967
968 if(uPos >= pData->uColumnCount)
969 uPos = 0;
970 iWeight = pData->aColumn[uPos].bWeight;
971 if(!iWeight)
972 continue;
973
974 iValue = pData->aColumn[uPos].sSize;
975
976 iCnt--;
977 if(iCnt) {
978 iValue += iSize * iWeight;
979 iPoint += iRest * iWeight;
980 iValue += iPoint / iAll;
981 iNum -= iPoint / iAll;
982 iPoint %= iAll;
983 } else {
984 iWeight -= iOff;
985 iValue += iSize * iWeight;
986 iValue += iNum;
987 }
988
989 pData->aColumn[uPos].sSize = (short)iValue;
990 }
991
992 iVar = 0;
993 iFix = 0;
994 iCnt = pData->uColumnCountVar;
995
996 for(uPos = 0; iCnt > 0; uPos++) { // Ausgeben der neuen Breiten
997 iWeight = pData->aColumn[uPos].bWeight;
998 if(!iWeight) {
999 iFix += pData->aColumn[uPos].sSize;
1000 continue;
1001 }
1002
1003 iVar += pData->aColumn[uPos].sSize;
1004 sItem.cxy = pData->aColumn[uPos].sSize;
1005
1006 if(sItem.cxy < pData->aColumn[uPos].sMin) {
1007 sItem.cxy = pData->aColumn[uPos].sMin;
1008 }
1009
1010 if(pData->aColumn[uPos].sReal != sItem.cxy) { // Ändert sich die Breite
1011 pData->aColumn[uPos].sReal = (short)sItem.cxy;
1012 Header_SetItem(pData->hHeader, uPos, &sItem);
1013
1014 if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) {
1015 sNotify.hdr.code = TVN_COLUMNCHANGED;
1016 sNotify.uColumn = uPos;
1017 sNotify.uIndex = pData->aColumn[uPos].bIndex;
1018 sNotify.uPosX = pData->aColumnXpos[uPos];
1019 sNotify.iSize = sItem.cxy;
1020
1021 UNLOCK(pData);
1022 SendNotify(pData, &sNotify.hdr);
1023 LOCK(pData);
1024 }
1025 }
1026
1027 iCnt--;
1028 }
1029
1030 pData->iFixSize = iFix;
1031 pData->iVarSize = iVar;
1032
1033 if(iDelta > 0) {
1034 GetClientRect(pData->hHeader, &sRect);
1035 InvalidateRect(pData->hHeader, NULL, FALSE);
1036 }
1037
1038}
1039
1040//*****************************************************************************
1041//*
1042//* CreateToolTip
1043//*
1044//*****************************************************************************
1045// Erzeugt ein ToolTip Fenster
1046// pData : Zeiger auf die Fensterdaten
1048
1049 TOOLINFO sInfo;
1050
1051 if(pData->hToolTip)
1052 return;
1053
1055 pData->pToolProc = (WNDPROC)GetWindowLongPtr(pData->hToolTip, GWLP_WNDPROC);
1056
1057 sInfo.cbSize = sizeof(TOOLINFO);
1058 sInfo.uFlags = TTF_ABSOLUTE | TTF_TRACK | TTF_IDISHWND;
1059 sInfo.hwnd = pData->hWnd;
1060 sInfo.hinst = NULL;
1061 sInfo.uId = (LPARAM)(pData->hWnd);
1062 sInfo.lpszText = LPSTR_TEXTCALLBACK;
1063
1064 GetClientRect(pData->hWnd, &sInfo.rect);
1065 SendMessage(pData->hToolTip, TTM_ADDTOOL, 0, (LPARAM)&sInfo);
1066 SendMessage(pData->hToolTip, TTM_SETMAXTIPWIDTH, 0, 10000);
1067 SetWindowLong(pData->hToolTip, GWL_ID, 2);
1070}
1071
1072//*****************************************************************************
1073//*
1074//* CreateStateImageList
1075//*
1076//*****************************************************************************
1077// Erzeugt eine Image-Liste mit zwei Checkboxen
1078// pData : Zeiger auf die Fensterdaten
1079// iMode : Welche Imageliste soll erzeugt werden (0=hStates 1=hChecks)
1081
1082 BITMAPINFO sInfo;
1083 BYTE aMem[0x1000];
1084 HDC hDcSrc;
1085 HDC hDc;
1086 HBITMAP hBmp;
1087 HBITMAP hBmpNew;
1088 RECT sRect;
1089 int iBits;
1090
1091 if(pOpenThemeData) { // Über Thema zeichnen
1092 if(!pData->hThemeBt) {
1093 pData->hThemeBt = pOpenThemeData(pData->hWnd, L"BUTTON");
1094 }
1095
1096 if(pData->hThemeBt) {
1097 if(iMode) {
1098 if(pData->hChecks && pData->hChecks != THEMEIMGLIST) {
1099 ImageList_Destroy(pData->hChecks);
1100 }
1101
1102 pData->hChecks = THEMEIMGLIST;
1103 pData->iChecksXsize = 16;
1104 pData->iChecksYsize = 16;
1105 pData->iChecksMode = 1;
1106 } else {
1107 if(pData->hStates && pData->hStates != THEMEIMGLIST) {
1108 ImageList_Destroy(pData->hStates);
1109 }
1110
1111 pData->hStates = THEMEIMGLIST;
1112 pData->iStatesXsize = 16;
1113 pData->iStatesYsize = 16;
1114 pData->iStatesMode = 1;
1115 }
1116
1117 return;
1118 }
1119 }
1120
1121 if(iMode) {
1122 if(pData->hChecks && pData->hChecks != THEMEIMGLIST)
1123 return;
1124 } else {
1125 if(pData->hStates && pData->hStates != THEMEIMGLIST)
1126 return;
1127 }
1128
1129 hDcSrc = GetDC(NULL);
1130 hDc = CreateCompatibleDC(NULL);
1131 hBmp = CreateCompatibleBitmap(hDcSrc, 16 * 3, 16);
1132
1133 SelectObject(hDc, hBmp);
1135 SetBkMode(hDc, OPAQUE);
1138 Rectangle(hDc, -1, -1, 16 * 3 + 2, 16 + 2);
1139
1140 sRect.top = 8 - 6;
1141 sRect.bottom = 8 + 7;
1142 sRect.left = 16 * 1 + 8 - 7;
1143 sRect.right = 16 * 1 + 8 + 6;
1144
1146
1147 sRect.left = 16 * 2 + 8 - 7;
1148 sRect.right = 16 * 2 + 8 + 6;
1149
1151
1152 iBits = GetDeviceCaps(hDc, BITSPIXEL);
1153
1154 sInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1155 sInfo.bmiHeader.biWidth = 16 * 3;
1156 sInfo.bmiHeader.biHeight = 16;
1157 sInfo.bmiHeader.biPlanes = 1;
1158 sInfo.bmiHeader.biBitCount = (WORD)iBits;
1160 sInfo.bmiHeader.biSizeImage = 0;
1161 sInfo.bmiHeader.biXPelsPerMeter = 0;
1162 sInfo.bmiHeader.biYPelsPerMeter = 0;
1163 sInfo.bmiHeader.biClrUsed = (iBits > 8) ? 0 : 1 << iBits;;
1164 sInfo.bmiHeader.biClrImportant = (iBits > 8) ? 0 : 1 << iBits;;
1165
1166 GetDIBits(hDc, hBmp, 0, 0 , NULL, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1167 GetDIBits(hDc, hBmp, 0, 16, aMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1168
1169 hBmpNew = CreateCompatibleBitmap(hDc, 16 * 3, 16);
1170
1171 SetDIBits(hDc, hBmpNew, 0, 16, aMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1172
1173 if(iMode == 0) {
1174 pData->hStates = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 3, 14);
1175 pData->iStatesXsize = 16;
1176 pData->iStatesYsize = 16;
1177 pData->iStatesMode = 1;
1178
1180 } else {
1181 pData->hChecks = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 3, 14);
1182 pData->iChecksXsize = 16;
1183 pData->iChecksYsize = 16;
1184 pData->iChecksMode = 1;
1185
1187 }
1188
1189 DeleteObject(hBmpNew);
1190 DeleteObject(hBmp);
1191 DeleteDC(hDc);
1192 ReleaseDC(NULL, hDcSrc);
1193}
1194
1195//*****************************************************************************
1196//*
1197//* CreateDragImage
1198//*
1199//*****************************************************************************
1200// Erzeugt eine Image-Liste mit zwei Checkboxen
1201// pData : Zeiger auf die Fensterdaten
1202// uSub : Ist die Spalte für die das Drag-Image erzeugt werden soll
1203// Ergibt ein Handle mit der Imageliste oder NULL bei einem Fehler
1204static HIMAGELIST CreateDragImage(TreeListData *pData, unsigned uItem, unsigned uSub) {
1205
1206 ExtraItem *pExtra;
1209 BITMAPINFO sInfo;
1210 BYTE *pMem;
1211 HDC hDcSrc;
1212 HDC hDc;
1213 HBITMAP hBmp;
1214 HBITMAP hBmpNew;
1215 RECT sRect;
1216 unsigned uTSize;
1217 int iAdd;
1218 int iBits;
1219 int iWidth;
1220 int iHeigh;
1221 int iImage;
1222 int iYpos;
1223 LPCTSTR pText;
1224
1225 if(uItem > pData->uTreeItemsMax)
1226 return NULL;
1227
1228 pEntry = pData->pTreeItems[uItem];
1229 if(!pEntry)
1230 return 0;
1231
1232 iHeigh = pData->iFontHeight;
1233
1234 if(uSub) { // Image für Extraeintrag erzeugen
1235 if(uSub >= pData->uColumnCount)
1236 return 0;
1237
1238 pExtra = pData->pExtraItems[uSub - 1][uItem];
1239 if(!pExtra) {
1240 pText = _T("????");
1241 uTSize = 4;
1242 iImage = -1;
1243 iWidth = pData->iFontHeight * 4;
1244 } else {
1245 pText = pExtra->pText;
1246 uTSize = pExtra->uTextSize;
1247 iImage = pExtra->iImage;
1248 iWidth = pExtra->iTextPixels;
1249
1250 if(pExtra->bCallback & (TVIF_IMAGE | TVIF_TEXT)) {
1251 CallbackExtra(pData, pEntry, pExtra, uItem, uSub, pExtra->bCallback, &iImage, &uTSize, &pText);
1252 }
1253 }
1254 } else { // Image für Haupteintrag erzeugen
1255 pText = pEntry->pText;
1256 uTSize = pEntry->uTextSize;
1257 iImage = pEntry->iImage;
1258 iWidth = pEntry->iTextPixels;
1259
1260 if(pEntry->bCallback & (TVIF_IMAGE | TVIF_TEXT)) {
1261 CallbackEntry(pData, pEntry, uItem, pEntry->bCallback, &iImage, &uTSize, &pText);
1262 }
1263 }
1264
1265 if(pData->hImages && iImage >= 0) { // Größen für Images anpassen
1266 if(iHeigh < pData->iImagesYsize)
1267 iHeigh = pData->iImagesYsize;
1268 iAdd = pData->iImagesXsize + 2;
1269 iWidth += iAdd;
1270 } else {
1271 iAdd = 0;
1272 iImage = 1;
1273 }
1274
1275 if(iWidth > 240)
1276 iWidth = 240;
1277 if(iHeigh > 32)
1278 iHeigh = 32;
1279
1280 pMem = new(BYTE, iHeigh * (iWidth + 4) * 4 + 1024);
1281 if(!pMem)
1282 return NULL;
1283
1284 hDcSrc = GetDC(NULL);
1285 hDc = CreateCompatibleDC(NULL);
1286 hBmp = CreateCompatibleBitmap(hDcSrc, iWidth, iHeigh);
1287
1288 SelectObject(hDc, hBmp);
1290 SelectObject(hDc, (pEntry->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN);
1291 SetTextColor(hDc, pData->uColors[TVC_TEXT]);
1292 SetBkColor(hDc, RGB(123, 77, 91));
1293
1294 sRect.top = 0;
1295 sRect.bottom = iHeigh;
1296 sRect.left = 0;
1297 sRect.right = iWidth;
1298 iYpos = (iHeigh - pData->iFontHeight) / 2;
1299
1300 ExtTextOut(hDc, iAdd, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sRect, pText, uTSize, NULL);
1301
1302 if(iImage >= 0) {
1304 ImageList_Draw(pData->hImages, iImage, hDc, 0, 0, ILD_TRANSPARENT);
1305 }
1306
1307 iBits = GetDeviceCaps(hDc, BITSPIXEL);
1308
1309 sInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1310 sInfo.bmiHeader.biWidth = iWidth;
1311 sInfo.bmiHeader.biHeight = iHeigh;
1312 sInfo.bmiHeader.biPlanes = 1;
1313 sInfo.bmiHeader.biBitCount = (WORD)iBits;
1315 sInfo.bmiHeader.biSizeImage = 0;
1316 sInfo.bmiHeader.biXPelsPerMeter = 0;
1317 sInfo.bmiHeader.biYPelsPerMeter = 0;
1318 sInfo.bmiHeader.biClrUsed = (iBits > 8) ? 0 : 1 << iBits;;
1319 sInfo.bmiHeader.biClrImportant = (iBits > 8) ? 0 : 1 << iBits;;
1320
1321 GetDIBits(hDc, hBmp, 0, 0 , NULL, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1322 GetDIBits(hDc, hBmp, 0, iHeigh, pMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1323
1324 hBmpNew = CreateCompatibleBitmap(hDc, iWidth, iHeigh);
1325
1326 SetDIBits(hDc, hBmpNew, 0, iHeigh, pMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS : DIB_PAL_COLORS);
1327
1328 hList = ImageList_Create(iWidth, iHeigh, ILC_COLORDDB | ILC_MASK, 1, 0);
1329
1330 ImageList_AddMasked(hList, hBmpNew, RGB(123, 77, 91));
1331
1332 DeleteObject(hBmpNew);
1333 DeleteObject(hBmp);
1334 DeleteDC(hDc);
1335 ReleaseDC(NULL, hDcSrc);
1336
1337 delete(pMem);
1338
1339 return hList;
1340}
1341
1342
1343//*****************************************************************************
1344//*
1345//* UpdateColorsList
1346//*
1347//*****************************************************************************
1348// Aktualisiert alle Farben
1349// pData : Zeiger auf die Fensterdaten
1351
1352 unsigned uColOdd;
1353 unsigned uColor;
1354 int iDiff;
1355 int iSum;
1356
1357 if(!pData->cColorChanged[TVC_BK ])
1358 pData->uColors[TVC_BK ] = GetSysColor(COLOR_WINDOW);
1359 if(!pData->cColorChanged[TVC_BOX ])
1361 if(!pData->cColorChanged[TVC_EVEN ])
1362 pData->uColors[TVC_EVEN ] = GetSysColor(COLOR_WINDOW);
1363 if(!pData->cColorChanged[TVC_TEXT ])
1365 if(!pData->cColorChanged[TVC_LINE ])
1367 if(!pData->cColorChanged[TVC_FRAME ])
1369 if(!pData->cColorChanged[TVC_TRACK ])
1370 pData->uColors[TVC_TRACK ] = GetSysColor(COLOR_WINDOWTEXT) ^ RGB(0, 0, 255);
1371 if(!pData->cColorChanged[TVC_INSERT ])
1373 if(!pData->cColorChanged[TVC_ODD ])
1374 pData->uColors[TVC_ODD ] = GetSysColor(COLOR_INFOBK);
1375 if(!pData->cColorChanged[TVC_BOXBG ])
1377 if(!pData->cColorChanged[TVC_COLBK ])
1379 if(!pData->cColorChanged[TVC_COLODD ])
1381 if(!pData->cColorChanged[TVC_COLEVEN])
1383 if(!pData->cColorChanged[TVC_GRAYED ])
1385
1386
1387 if(pData->hTheme && !pData->cColorChanged[TVC_BOXBG] && !pData->cColorChanged[TVC_BOX] && !pData->cColorChanged[TVC_LINE]) {
1388 pData->cGlyphOk = 1;
1389 } else {
1390 pData->cGlyphOk = 0;
1391 }
1392
1393
1394 if(!pData->cColorChanged[TVC_GRAYED]) {
1395 pData->uColors[TVC_GRAYED] = (GetSysColor(COLOR_SCROLLBAR) & 0x00FEFEFE) >> 1;
1396 pData->uColors[TVC_GRAYED] += (GetSysColor(COLOR_WINDOW) & 0x00FEFEFE) >> 1;
1397 }
1398
1399 if(!pData->cColorChanged[TVC_ODD]) {
1400 uColOdd = pData->uColors[TVC_ODD];
1401 iDiff = ((uColOdd) & 0xFF) - ((pData->uColors[TVC_EVEN]) & 0xFF);
1402 iSum = iDiff * iDiff;
1403 iDiff = ((uColOdd >> 8) & 0xFF) - ((pData->uColors[TVC_EVEN] >> 8) & 0xFF);
1404 iSum += iDiff * iDiff;
1405 iDiff = ((uColOdd >> 16) & 0xFF) - ((pData->uColors[TVC_EVEN] >> 16) & 0xFF);
1406 iSum += iDiff * iDiff;
1407
1408 if(iSum < 64) { // Ist die alternierente Farbe fast gleich ?
1409 uColOdd = pData->uColors[TVC_EVEN] & 0x0000FFFF;
1410 uColOdd |= ((pData->uColors[TVC_EVEN] & 0x00FF0000) - 0x00080000) & 0x00FF0000;
1411 }
1412
1413 pData->uColors[TVC_ODD] = uColOdd;
1414 }
1415
1416 if(!pData->cColorChanged[TVC_COLBK]) {
1417 uColor = GetSysColor(COLOR_WINDOW);
1418 if(uColor & 0x00F00000)
1419 uColor -= 0x00100000;
1420 if(uColor & 0x0000F000)
1421 uColor -= 0x00001000;
1422 if(uColor & 0x000000F0)
1423 uColor -= 0x00000010;
1424
1425 pData->uColors[TVC_COLBK] = uColor;
1426 }
1427
1428 if(!pData->cColorChanged[TVC_COLODD]) {
1429 uColor = pData->uColors[TVC_ODD];
1430 if(uColor & 0x00F00000)
1431 uColor -= 0x00100000;
1432 if(uColor & 0x0000F000)
1433 uColor -= 0x00001000;
1434 if(uColor & 0x000000F0)
1435 uColor -= 0x00000010;
1436
1437 pData->uColors[TVC_COLODD] = uColor;
1438 }
1439
1440 if(!pData->cColorChanged[TVC_COLEVEN]) {
1441 uColor = GetSysColor(COLOR_WINDOW);
1442 if(uColor & 0x00F00000)
1443 uColor -= 0x00100000;
1444 if(uColor & 0x0000F000)
1445 uColor -= 0x00001000;
1446 if(uColor & 0x000000F0)
1447 uColor -= 0x00000010;
1448
1449 pData->uColors[TVC_COLEVEN] = uColor;
1450 }
1451
1452 if(!pData->cColorChanged[TVC_MARKODD ])
1453 pData->uColors[TVC_MARKODD ] = ((pData->uColors[TVC_ODD ] >> 3) & 0x1F1F1F) * 7;
1454 if(!pData->cColorChanged[TVC_MARKODD ])
1455 pData->uColors[TVC_MARKODD ] += ((GetSysColor(COLOR_HIGHLIGHT) >> 3) & 0x1F1F1F) * 1;
1456 if(!pData->cColorChanged[TVC_MARKEVEN])
1457 pData->uColors[TVC_MARKEVEN] = ((pData->uColors[TVC_EVEN ] >> 3) & 0x1F1F1F) * 7;
1458 if(!pData->cColorChanged[TVC_MARKEVEN])
1459 pData->uColors[TVC_MARKEVEN] += ((GetSysColor(COLOR_HIGHLIGHT) >> 3) & 0x1F1F1F) * 1;
1460}
1461
1462//*****************************************************************************
1463//*
1464//* UpdateHeight
1465//*
1466//*****************************************************************************
1467// Checks if the row height has changed
1468// pData : pointer to the window data
1469// Returns 1 if changed or 0 else.
1471
1472 int iHeight;
1473 RECT sRect;
1474
1475 if(pData->cFixedHeight)
1476 return 0;
1477
1478 iHeight = 10;
1479
1480 if(pData->hChecks)
1481 if(iHeight < pData->iChecksYsize + 2)
1482 iHeight = pData->iChecksYsize + 2;
1483 if(pData->hStates)
1484 if(iHeight < pData->iStatesYsize + 2)
1485 iHeight = pData->iStatesYsize + 2;
1486 if(iHeight < pData->iSubImgYsize + 2)
1487 iHeight = pData->iSubImgYsize + 2;
1488 if(iHeight < pData->iImagesYsize + 2)
1489 iHeight = pData->iImagesYsize + 2;
1490 if(iHeight < pData->iFontHeight + 2)
1491 iHeight = pData->iFontHeight + 2;
1492 if(pData->uStyleEx & TVS_EX_ITEMLINES)
1493 iHeight++;
1494 if(pData->uStyle & TVS_NONEVENHEIGHT && (iHeight & 1))
1495 iHeight++;
1496 if(pData->iRowHeight == iHeight)
1497 return 0;
1498
1499 pData->iRowHeight = iHeight;
1500
1501 if(pData->uSizeY > pData->uStartPixel) {
1502 pData->uMaxEnties = pData->uSizeY;
1503 pData->uMaxEnties -= pData->uStartPixel;
1504 } else {
1505 pData->uMaxEnties = 0;
1506 }
1507
1508 pData->uPageEnties = pData->uMaxEnties;
1509 pData->uMaxEnties += pData->iRowHeight - 1;
1510 pData->uMaxEnties /= pData->iRowHeight;
1511 pData->uPageEnties /= pData->iRowHeight;
1512
1513 GetClientRect(pData->hWnd, &sRect);
1514 InvalidateRect(pData->hWnd, &sRect, FALSE);
1515
1516 return 1;
1517}
1518
1519//*****************************************************************************
1520//*
1521//* UpdateRect
1522//*
1523//*****************************************************************************
1524// Zeichnet einen Eintrag neu
1525// pData : Zeiger auf die Fensterdaten
1526// uItem : Ist die Nummer des Eintrages
1527// uSub : Ist die Spaltennummer
1528// Ergibt 1 wenn der Eintrag sichtbar war
1529static int UpdateRect(TreeListData *pData, unsigned uItem, unsigned uSub) {
1530
1532 RECT sRect;
1533 UINT uNext;
1534 UINT uPos;
1535
1536 pEntry = pData->pTreeItems[uItem];
1537 if(!pEntry || !pEntry->uShowPos)
1538 return 0; // Ist der Eintrag aufgeklappt
1539
1540 uPos = pEntry->uShowPos - pData->uScrollY - 1;
1541 if(uPos >= pData->uMaxEnties)
1542 return 0; // Eintrag im Fenster sichtbar
1543
1544 uNext = pData->aColumn[uSub].bNext;
1545 sRect.left = pData->aColumnXpos[uSub ];
1546 sRect.left -= pData->uScrollX;
1547 sRect.right = pData->aColumnXpos[uNext];
1548 sRect.right -= pData->uScrollX;
1549 sRect.top = pData->uStartPixel;
1550 sRect.top += pData->iRowHeight * uPos;
1551 sRect.bottom = pData->iRowHeight + sRect.top;
1552
1553 InvalidateRect(pData->hWnd, &sRect, FALSE);
1554
1555 return 1;
1556}
1557
1558//*****************************************************************************
1559//*
1560//* UpdateColRect
1561//*
1562//*****************************************************************************
1563// Zeichnet einen ganze Spalte neu
1564// pData : Zeiger auf die Fensterdaten
1565// uColumn : Die nummer der Spalte
1566// Ergibt 1 wenn der Eintrag sichtbar war
1567static int UpdateColRect(TreeListData *pData, unsigned uColumn) {
1568
1569 RECT sRect;
1570 UINT uNext;
1571
1572 if(uColumn >= pData->uColumnCount)
1573 return 0;
1574
1575 sRect.left = pData->aColumnXpos[uColumn];
1576 sRect.left -= pData->uScrollX;
1577 if(sRect.left > (int)pData->uSizeX)
1578 return 0;
1579
1580 uNext = pData->aColumn[uColumn].bNext;
1581
1582 sRect.right = pData->aColumnXpos[uNext];
1583 sRect.right -= pData->uScrollX;
1584 if(sRect.right < 0)
1585 return 0;
1586
1587 sRect.top = 0;
1588 sRect.bottom = pData->uSizeY;
1589
1590 InvalidateRect(pData->hWnd, &sRect, FALSE);
1591
1592 return 1;
1593}
1594
1595//*****************************************************************************
1596//*
1597//* UpdateRow
1598//*
1599//*****************************************************************************
1600// Zeichnet einen Eintrag über die ganze Zeile neu
1601// pData : Zeiger auf die Fensterdaten
1602// uItem : Ist die Nummer des Eintrages
1603// Ergibt 1 wenn der Eintrag sichtbar war
1604static int UpdateRow(TreeListData *pData, unsigned uItem) {
1605
1607 RECT sRect;
1608 unsigned uPos;
1609
1610 pEntry = pData->pTreeItems[uItem];
1611 if(!pEntry || !pEntry->uShowPos)
1612 return 0; // Ist der Eintrag aufgeklappt
1613
1614 uPos = pEntry->uShowPos - pData->uScrollY - 1;
1615 if(uPos >= pData->uMaxEnties)
1616 return 0; // Eintrag im Fenster sichtbar
1617
1618 sRect.left = 0;
1619 sRect.right = pData->uSizeX;
1620 sRect.top = pData->uStartPixel;
1621 sRect.top += pData->iRowHeight * uPos;
1622 sRect.bottom = pData->iRowHeight + sRect.top;
1623 InvalidateRect(pData->hWnd, &sRect, FALSE);
1624
1625 return 1;
1626}
1627
1628//*****************************************************************************
1629//*
1630//* UpdateView
1631//*
1632//*****************************************************************************
1633// Redraw the whole window
1634// pData : Zeiger auf die Fensterdaten
1635// Ergibt 1 wenn der Eintrag sichtbar war
1637
1638 RECT sRect;
1639
1640 GetClientRect(pData->hWnd, &sRect);
1641 sRect.top = pData->uStartPixel;
1642 InvalidateRect(pData->hWnd, &sRect, FALSE);
1643
1644 if(pData->hHeader && ((pData->uStyleEx & TVS_EX_HIDEHEADERS) == 0)){
1645 GetClientRect(pData->hHeader, &sRect);
1646 InvalidateRect(pData->hHeader, &sRect, FALSE);
1647 }
1648}
1649
1650//*****************************************************************************
1651//*
1652//* UpdateScrollX
1653//*
1654//*****************************************************************************
1655// Aktualisiert die X-Scroolbar
1656// pData : Zeiger auf die Fensterdaten
1657// Ergibt 1 wenn der sich Einstellungen verändert haben
1659
1660 SCROLLINFO sInfo;
1661 unsigned uSize;
1662 unsigned uCols;
1663
1664 uCols = pData->uColumnCount;
1665 if(uCols)
1666 uSize = pData->aColumnXpos[uCols] - 1;
1667 else
1668 uSize = pData->iMaxSizeX - 1;
1669
1670
1671 if(pData->uOldXCount == uSize)
1672 if(pData->uOldXPage == pData->uSizeX) {
1673 return;
1674 }
1675
1676 pData->uOldXPage = pData->uSizeX;
1677 pData->uOldXCount = uSize;
1678
1679 UNLOCK(pData);
1680
1681 sInfo.cbSize = sizeof(SCROLLINFO);
1682 sInfo.fMask = SIF_ALL;
1683 sInfo.nMin = 0;
1684 sInfo.nMax = uSize;
1685 sInfo.nPage = pData->uSizeX;
1686 sInfo.nPos = pData->uScrollX;
1687 sInfo.nTrackPos = 0;
1688
1689 if(pData->uStyle & TVS_NOSCROLL) {
1690 sInfo.nMax = 0;
1691 } else
1692 if(pData->uStyleEx & TVS_EX_AUTOHSCROLL) {
1693 sInfo.nMax = 0;
1694 } else
1695 if(sInfo.nMax > 0) {
1696 sInfo.nMax--;
1697 }
1698
1699
1700 if((int)sInfo.nPage >= sInfo.nMax && pData->uScrollX > 0) {
1701 sInfo.nPos = 0;
1702 pData->uScrollX = 0;
1703
1705
1706 if(pData->hHeader) {
1707 MoveWindow(pData->hHeader, 0, 0, pData->uSizeX, pData->uStartPixel, TRUE);
1708 }
1709 }
1710
1711 SetScrollInfo(pData->hWnd, SB_HORZ, &sInfo, TRUE);
1712
1713 LOCK(pData);
1714}
1715
1716//*****************************************************************************
1717//*
1718//* UpdateScrollY
1719//*
1720//*****************************************************************************
1721// Aktualisiert die Y-Scroolbar
1722// pData : Zeiger auf die Fensterdaten
1723// Ergibt 1 wenn der sich Einstellungen verändert haben
1725
1726 SCROLLINFO sInfo;
1727
1728 if(pData->uOldYCount == pData->uItemPosCount)
1729 if(pData->uOldYPage == pData->uPageEnties) {
1730 return;
1731 }
1732
1733 pData->uOldYPage = pData->uPageEnties;
1734 pData->uOldYCount = pData->uItemPosCount;
1735
1736 UNLOCK(pData);
1737
1738 sInfo.cbSize = sizeof(SCROLLINFO);
1739 sInfo.fMask = SIF_ALL;
1740 sInfo.nMin = 0;
1741 sInfo.nMax = pData->uItemPosCount;
1742 sInfo.nPage = pData->uPageEnties;
1743 sInfo.nPos = pData->uScrollY;
1744 sInfo.nTrackPos = 0;
1745
1746 if(pData->uStyle & TVS_NOSCROLL) {
1747 sInfo.nMax = 0;
1748 }
1749
1750 if((int)sInfo.nPage >= sInfo.nMax && pData->uScrollY > 0) {
1751 sInfo.nPos = 0;
1752 pData->uScrollY = 0;
1753
1755 }
1756
1757 SetScrollInfo(pData->hWnd, SB_VERT, &sInfo, TRUE);
1758
1759 LOCK(pData);
1760}
1761
1762//*****************************************************************************
1763//*
1764//* UpdateToolTip
1765//*
1766//*****************************************************************************
1767// Aktualisiert den Text für das Tootip
1768// pData : Zeiger auf Fensterdaten
1769// uItem : Item auf den der Mauszeiger zeigt
1770// uFlags : Flags vom HitTest
1771static void UpdateToolTip(TreeListData *pData, unsigned uItem, unsigned uFlags) {
1772
1773 TCHAR cTemp[INFOTIPSIZE];
1774#ifndef __REACTOS__
1775 HWND hToolTip;
1776#endif
1777 NMTVGETINFOTIP sToolNv;
1778 NMTREEVIEW sNotify;
1779 TOOLINFO sInfo;
1780 ExtraItem *pExtra;
1782 LPCTSTR pText;
1783 RECT sRect;
1784 unsigned uSize;
1785 unsigned uCol;
1786 unsigned uLen;
1787 LRESULT lRet;
1788 int iTemp;
1789 // Tooltip ausbelnden
1790 if(!uItem || (uItem == pData->uEditItem && TVHT_SUBTOCOL(uFlags) == pData->uEditSub)) {
1791 if(pData->uToolTipItem)
1792 goto ExitTip;
1793 return;
1794 }
1795
1796 pEntry = pData->pTreeItems[uItem];
1797
1798 if(uFlags & TVHT_ONITEM) {
1799 if(pData->uToolTipItem != uItem || pData->uToolTipSub != 0) {
1800 if(!pData->pTreeItems[uItem]) { // Existiert der Eintag noch ?
1801 goto ExitTip;
1802 }
1803
1805
1806 if(sRect.right > (int)pData->uSizeX) {
1807 sRect.right = pData->uSizeX;
1808 }
1809
1810 lRet = 0;
1811
1812 if(pData->uStyleEx & TVS_EX_TOOLTIPNOTIFY) { // Tooltip-Daten via speziellem Notify holen
1813 sNotify.hdr.code = TVN_ITEMTOOLTIP;
1814 sNotify.action = 0;
1815 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
1816 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
1817 sNotify.itemNew.stateMask = 0xFFFFFFFF;
1818 sNotify.itemNew.state = pEntry->uState;
1819 sNotify.itemNew.lParam = pEntry->lParam;
1820 sNotify.itemNew.pszText = pEntry->pText;
1821 sNotify.itemNew.cchTextMax = pEntry->uTextSize;
1822 sNotify.itemNew.cChildren = 0;
1823 sNotify.itemOld.mask = 0;
1824 sNotify.ptDrag.x = sRect.left;
1825 sNotify.ptDrag.y = sRect.top;
1826
1827 UNLOCK(pData);
1828 lRet = SendNotify(pData, &sNotify.hdr);
1829 LOCK(pData);
1830
1831 if(lRet)
1832 goto UserTip;
1833 } else
1834 if(pData->uStyle & TVS_INFOTIP) { // Tooltip-Daten via normalem Notify holen
1835 sToolNv.hdr.code = TVN_GETINFOTIP;
1836 sToolNv.cchTextMax = INFOTIPSIZE;
1837 sToolNv.hItem = (HTREEITEM)(ULONG_PTR)uItem;
1838 sToolNv.lParam = pEntry->lParam;
1839 sToolNv.pszText = cTemp;
1840
1841 str_ncpy(cTemp, pEntry->pText, INFOTIPSIZE);
1842 cTemp[INFOTIPSIZE - 1] = 0;
1843
1844 UNLOCK(pData);
1845 lRet = SendNotify(pData, &sNotify.hdr);
1846 LOCK(pData);
1847
1848 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
1849 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
1850 sNotify.itemNew.pszText = sToolNv.pszText;
1851 sNotify.itemNew.cchTextMax = str_len(sToolNv.pszText);
1852 sNotify.itemNew.cChildren = 0;
1853 sNotify.itemNew.stateMask = 0xFFFFFFFF;
1854 sNotify.itemNew.state = pEntry->uState;
1855 sNotify.itemNew.lParam = pEntry->lParam;
1856 sNotify.ptDrag.x = sRect.left;
1857 sNotify.ptDrag.y = sRect.top;
1858
1859 goto UserTip;
1860 }
1861 // Passt der Text in die Spalte
1862 if(sRect.right - sRect.left <= pEntry->iTextPixels + 4) {
1863 pText = pEntry->pText;
1864 uSize = pEntry->uTextSize;
1865
1866 if(pEntry->bCallback & TVIF_TEXT) {
1867 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iTemp, &uSize, &pText);
1868 }
1869
1870 if(!pText || *pText == 0)
1871 goto ExitTip;
1872
1873 uLen = str_len(pText) + 1;
1874 if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergrößern
1875 delete(pData->pToolTipText);
1876 pData->uToolTipSize = (uLen + 255)&~0xFF;
1877 pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4);
1878 }
1879
1880 memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR));
1881 pData->hFontT = (pEntry->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
1882
1883#ifndef __REACTOS__
1884 hToolTip = pData->hToolTip;
1885#endif
1886 pData->sToolTipPos.x = sRect.left;
1887 pData->sToolTipPos.y = sRect.top;
1888
1889 ClientToScreen(pData->hWnd, &pData->sToolTipPos);
1890
1891 UNLOCK(pData);
1892
1893 sInfo.cbSize = sizeof(sInfo);
1894 sInfo.hwnd = pData->hWnd;
1895 sInfo.uId = (UINT_PTR)pData->hWnd;
1896
1897 if(pData->uToolTipItem) {
1898 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
1899 pData->uToolTipItem = 0;
1900 }
1901
1902 SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y));
1903 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
1904
1905 LOCK(pData);
1906
1907 pData->uToolTipItem = uItem;
1908 pData->uToolTipShow = 0;
1909 pData->uToolTipSub = 0;
1910
1911 SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);
1912 } else {
1913 if(pData->uToolTipItem)
1914 goto ExitTip;
1915 }
1916 }
1917
1918 return;
1919 }
1920
1922 if(pData->uToolTipItem != uItem || TVHT_SUBTOCOL(uFlags) != pData->uToolTipSub) {
1923 lRet = 0;
1924 uCol = TVHT_SUBTOCOL(uFlags);
1925 pExtra = pData->pExtraItems[uCol - 1][uItem];
1926
1927 if(pData->uStyleEx & TVS_EX_TOOLTIPNOTIFY) { // Tooltip-Daten via Notify holen
1929
1930 if(sRect.right > (int)pData->uSizeX) {
1931 sRect.right = pData->uSizeX;
1932 }
1933
1934 if(pExtra) {
1935 sNotify.itemNew.state = pExtra->uState;
1936 sNotify.itemNew.pszText = pExtra->pText;
1937 sNotify.itemNew.cchTextMax = pExtra->uTextSize;
1938 } else {
1939 sNotify.itemNew.state = 0;
1940 sNotify.itemNew.cchTextMax = 0;
1941 sNotify.itemNew.pszText = _T("");
1942 }
1943
1944 sNotify.hdr.code = TVN_ITEMTOOLTIP;
1945 sNotify.action = 0;
1946 sNotify.itemNew.lParam = pEntry->lParam;
1947 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
1948 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
1949 sNotify.itemNew.stateMask = 0xFFFFFFFF;
1950 sNotify.itemNew.cChildren = uCol;
1951 sNotify.itemOld.mask = 0;
1952 sNotify.ptDrag.x = sRect.left;
1953 sNotify.ptDrag.y = sRect.top;
1954
1955 UNLOCK(pData);
1956 lRet = SendNotify(pData, &sNotify.hdr);
1957 LOCK(pData);
1958
1959 if(lRet)
1960 goto UserTip;
1961 }
1962
1963 if(pExtra) { // Tooltip auf Unterspalte ?
1965
1966 if(sRect.right > (int)pData->uSizeX) {
1967 sRect.right = pData->uSizeX;
1968 }
1969
1970 if(sRect.right - sRect.left <= pExtra->iTextPixels + 4) {
1971 pText = pExtra->pText;
1972 uSize = pExtra->uTextSize;
1973
1974 if(pExtra->bCallback & TVIF_TEXT) {
1975 CallbackExtra(pData, pEntry, pExtra, uItem, uCol, TVIF_TEXT, &iTemp, &uSize, &pText);
1976 }
1977
1978 if(!pText || *pText == 0)
1979 goto ExitTip;
1980
1981 uLen = str_len(pText) + 1;
1982 if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergrößern
1983 delete(pData->pToolTipText);
1984 pData->uToolTipSize = (uLen + 255)&~0xFF;
1985 pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4);
1986 }
1987
1988 memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR));
1989 pData->hFontT = (pExtra->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
1990
1991 pData->sToolTipPos.x = sRect.left;
1992 pData->sToolTipPos.y = sRect.top;
1993#ifndef __REACTOS__
1994 hToolTip = pData->hToolTip;
1995#endif
1996
1997 ClientToScreen(pData->hWnd, &pData->sToolTipPos);
1998
1999 UNLOCK(pData);
2000
2001 sInfo.cbSize = sizeof(sInfo);
2002 sInfo.hwnd = pData->hWnd;
2003 sInfo.uId = (UINT_PTR)pData->hWnd;
2004
2005 if(pData->uToolTipItem) {
2006 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
2007 pData->uToolTipItem = 0;
2008 }
2009
2010 SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y));
2011 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
2012
2013 LOCK(pData);
2014
2015 pData->uToolTipItem = uItem;
2016 pData->uToolTipSub = uCol;
2017 pData->uToolTipShow = 0;
2018
2019 SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);
2020 } else {
2021 if(pData->uToolTipItem)
2022 goto ExitTip;
2023 }
2024 } else {
2025 if(pData->uToolTipItem)
2026 goto ExitTip;
2027 }
2028 }
2029
2030 return;
2031 }
2032
2033ExitTip:
2034
2035 if(pData->uToolTipItem) { // Tooltip ausblenden
2036 UNLOCK(pData);
2037
2038 sInfo.cbSize = sizeof(sInfo);
2039 sInfo.hwnd = pData->hWnd;
2040 sInfo.uId = (UINT_PTR)pData->hWnd;
2041
2042 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
2043
2044 LOCK(pData);
2045
2046 pData->uToolTipItem = 0;
2047 pData->uToolTipSub = 0;
2048 pData->uToolTipShow = 0;
2049
2051 }
2052
2053 return;
2054
2055UserTip:
2056
2057 pText = sNotify.itemNew.pszText; // Soll ein User-Tooltip angezeigt werden
2058 uSize = sNotify.itemNew.cchTextMax;
2059 sRect.left = sNotify.ptDrag.x;
2060 sRect.top = sNotify.ptDrag.y;
2061
2062 if(!pText || *pText == 0)
2063 goto ExitTip;
2064
2065 uLen = str_len(pText) + 1;
2066 if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergrößern
2067
2068 delete(pData->pToolTipText);
2069 pData->uToolTipSize = (uLen + 255)&~0xFF;
2070 pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4);
2071 }
2072
2073 memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR));
2074 pData->hFontT = (pEntry->uState & TVIS_BOLD) ? pData->hFontB : pData->hFontN;
2075
2076 ClientToScreen(pData->hWnd, &sNotify.ptDrag);
2077 pData->sToolTipPos = sNotify.ptDrag;
2078#ifndef __REACTOS__
2079 hToolTip = pData->hToolTip;
2080#endif
2081 // Tooltip verzögert anzeigen
2082 if((sNotify.itemNew.mask & TVIF_TOOLTIPTIME) && sNotify.itemNew.lParam > 0) {
2083 pData->uToolTipShow = (unsigned)(sNotify.itemNew.lParam + 499) / 500;
2084 pData->uToolTipSub = sNotify.itemNew.cChildren;
2085 pData->uToolTipItem = uItem;
2086
2087 SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 500, NULL);
2088
2089 return;
2090 }
2091
2092 UNLOCK(pData);
2093
2094 sInfo.cbSize = sizeof(sInfo);
2095 sInfo.hwnd = pData->hWnd;
2096 sInfo.uId = (UINT_PTR)pData->hWnd;
2097
2098 if(pData->uToolTipItem) { // Tooltip Fenster aktivieren
2099 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
2100 pData->uToolTipItem = 0;
2101 }
2102
2103 SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(sNotify.ptDrag.x, sNotify.ptDrag.y));
2104 SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
2105
2106 LOCK(pData);
2107
2108 pData->uToolTipShow = 0;
2109 pData->uToolTipItem = uItem;
2110 pData->uToolTipSub = sNotify.itemNew.cChildren;
2111
2112 SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);
2113}
2114
2115//*****************************************************************************
2116//*
2117//* CreateFontset
2118//*
2119//*****************************************************************************
2120// Create the font set (normal, bold, etc...) from the given HFONT
2122 LOGFONT sLog;
2123 HFONT hBold;
2124 int iRet = 0;
2125
2126 if(GetObject(hFont, sizeof(sLog), &sLog)){
2127 sLog.lfWeight = FW_BOLD;
2128 if((hBold = CreateFontIndirect(&sLog))){
2129 pData->hFontN = hFont; //store the given font
2130 if(pData->hFontB != hDefaultFontB){
2131 //if the current bold is not the default bold, free it
2132 DeleteObject(pData->hFontB);
2133 }
2134 pData->hFontB = hBold; //store the created bold
2135 iRet = 1;
2136 }
2137 }
2138 return iRet;
2139}
2140
2141//*****************************************************************************
2142//*
2143//* UpdateFont
2144//*
2145//*****************************************************************************
2146// Erzeugt einen den fetten Font für das Fenster
2147// pData : Zeiger auf die Fensterdaten
2148// iRedraw : Soll das Fenster neugezeichnet werden
2149// Ergibt 1 wenn der Font verändert wurde
2151
2152 int iPos;
2153 int iRet;
2154 HDC hDc;
2155 LOGFONT sLog;
2156 SIZE sSize;
2157 TEXTMETRIC sMetrics;
2159 BaseItem **pList;
2160 ExtraItem *pExtra;
2161 ExtraItem **pItems;
2162 unsigned uSub;
2163
2164 if(!hDefaultFontN) { // Den Standard-Font erzeugen
2165 SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(sLog), &sLog, 0);
2166 sLog.lfWeight = FW_NORMAL;
2168 sLog.lfWeight = FW_BOLD;
2170 }
2171
2172
2173 if(!pData->hFontN)
2174 pData->hFontN = hDefaultFontN;
2175 if(!pData->hFontB)
2176 pData->hFontB = hDefaultFontB;
2177
2178/*
2179 if(pData->hFontN == hDefaultFontN) { // Ist der Standard-Font eingestellt
2180 pData->hFontB = hDefaultFontB;
2181 } else {
2182 pData->hFontB = pData->hFontN;
2183 }
2184*/
2185
2186 if(pData->hFontN != pData->hFontL) {
2187 pData->hFontL = pData->hFontN;
2188
2189 hDc = GetDC(NULL);
2190 SelectObject(hDc, pData->hFontN);
2191 GetTextMetrics(hDc, &sMetrics);
2192 pData->iFontHeight = sMetrics.tmHeight;
2193 pData->iFontLine = sMetrics.tmAscent + 1;
2194 pData->iFontOff = (sMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH) ? 0 : -1;
2195 ReleaseDC(NULL, hDc);
2196
2197 pList = pData->pTreeItems;
2198 iPos = pData->uTreeItemsMax;
2199
2200 for(; iPos >= 0; iPos--) { // Alle Textbreiten zurücksetzen
2201 pEntry = pList[iPos];
2202 if(!pEntry)
2203 continue;
2204
2205 pEntry->iTextPixels = 0;
2206 }
2207
2208
2209 for(uSub = 1; uSub < pData->uColumnCount; uSub++) {
2210 iPos = pData->uTreeItemsMax;
2211 pItems = pData->pExtraItems[uSub - 1];
2212
2213 for(; iPos >= 0; iPos--) {
2214 pExtra = pItems[iPos];
2215 if(!pExtra)
2216 continue;
2217
2218 pExtra->iTextPixels = 0;
2219 }
2220 }
2221
2222 iRet = 1;
2223 } else {
2224 iRet = 0;
2225 }
2226
2227 // compute Width of "..." text
2228 hDc = GetDC(NULL);
2229 SelectObject(hDc, pData->hFontN);
2230 GetTextExtentExPoint(hDc, _T("..."), 3, 256, NULL, NULL, &sSize);
2231 pData->uTrippleN = sSize.cx;
2232 SelectObject(hDc, pData->hFontB);
2233 GetTextExtentExPoint(hDc, _T("..."), 3, 256, NULL, NULL, &sSize);
2234 pData->uTrippleB = sSize.cx;
2235 ReleaseDC(NULL, hDc);
2236
2237 return iRet;
2238}
2239
2240
2241//*****************************************************************************
2242//*
2243//* UpdateItems
2244//*
2245//*****************************************************************************
2246// Berechnet die Positionen der Zeilen für die sichtbaren Einträge
2247// pData : Zeiger auf die Fensterdaten
2248// uItem : Ist der Eintrag ab dem begonnen wird
2249static void UpdateItems(TreeListData *pData, unsigned uItem) {
2250
2251 unsigned uPos;
2252 unsigned uOld;
2253 unsigned uNum;
2254 unsigned uTemp;
2255 unsigned uStart;
2256 unsigned *pLines;
2257 BaseItem **pItems;
2259 BaseItem *pTemp;
2260 RECT sRect;
2261
2262 uOld = pData->uItemPosCount;
2263 pLines = pData->pItemPos;
2264 pItems = pData->pTreeItems;
2265
2266 if(!uItem) { // Am Anfang beginnen
2267 uItem = pData->uFirstChild;
2268 if(!uItem) { // Leere Liste
2269 if(!uOld)
2270 return;
2271
2272 for(uNum = 0; uNum < uOld; uNum++) { // Die alten Einträge zurücksetzen
2273 uTemp = pLines[uNum];
2274 if(!uTemp)
2275 continue;
2276 pLines[uNum] = 0;
2277 pTemp = pItems[uTemp];
2278 if(!pTemp)
2279 continue;
2280 pTemp->uShowPos = 0;
2281 }
2282
2283 pData->uItemPosCount = 0;
2284
2285 GetClientRect(pData->hWnd, &sRect);
2286 InvalidateRect(pData->hWnd, &sRect, TRUE);
2287
2288 memset(pLines, 0, sizeof(unsigned)*uOld);
2289 return;
2290 }
2291
2292 for(uNum = 0; uNum < uOld; uNum++) { // Die alten Einträge zurücksetzen
2293 uTemp = pLines[uNum];
2294 if(!uTemp)
2295 continue;
2296 pLines[uNum] = 0;
2297 pTemp = pItems[uTemp];
2298 if(!pTemp)
2299 continue;
2300 pTemp->uShowPos = 0;
2301 }
2302
2303 pEntry = pItems[uItem];
2304 pEntry->uShowPos = 1;
2305 pLines[0] = uItem;
2306 uPos = 1;
2307 uStart = 0;
2308 } else { // Bei einem Eintrag beginnen
2309 pEntry = pItems[uItem];
2310 uPos = pEntry->uShowPos;
2311 if(uPos)
2312 uStart = uPos - 1;
2313 else
2314 uStart = 0;
2315
2316 for(uNum = uPos; uNum < uOld; uNum++) { // Die alten Einträge zurücksetzen
2317 uTemp = pLines[uNum];
2318 if(!uTemp)
2319 continue;
2320 pLines[uNum] = 0;
2321 pTemp = pItems[uTemp];
2322 if(!pTemp)
2323 continue;
2324 pTemp->uShowPos = 0;
2325 }
2326 }
2327
2328 for(;;) { // Die Zeilen neu zuordnen
2329 if(pEntry->uFirstChild && (pEntry->uState & TVIS_EXPANDED)) {
2330 uItem = pEntry->uFirstChild;
2331 } else
2332 if(pEntry->uNextItem) {
2333 uItem = pEntry->uNextItem;
2334 } else {
2335 for(;;) {
2336 uItem = pEntry->uParent;
2337 if(!uItem)
2338 break;
2339
2340 pEntry = pItems[uItem];
2341 if(pEntry->uNextItem) { // Gibt es etwas in der gleichen Ebene
2342 uItem = pEntry->uNextItem;
2343 break;
2344 }
2345 }
2346
2347 if(!uItem)
2348 break;
2349 }
2350
2351 pEntry = pItems[uItem];
2352
2353 if(pLines[uPos] != uItem) {
2354 pLines[uPos] = uItem;
2355 } else {
2356 if(uStart == uPos)
2357 uStart++;
2358 }
2359
2360 uPos++;
2361 pEntry->uShowPos = uPos;
2362 }
2363
2364 pData->uItemPosCount = uPos;
2365
2366 if(uStart > pData->uScrollY) // Neu zu zeichnenten Bereich bestimmen
2367 uStart -= pData->uScrollY;
2368 else
2369 uStart = 0;
2370
2371 GetClientRect(pData->hWnd, &sRect);
2372
2373 sRect.top = pData->uStartPixel + pData->iRowHeight * uStart;
2374
2375 if(sRect.top <= sRect.bottom) {
2376 InvalidateRect(pData->hWnd, &sRect, FALSE);
2377 }
2378
2379 if(uOld != uPos)
2381}
2382
2383//*****************************************************************************
2384//*
2385//* UpdateColumns
2386//*
2387//*****************************************************************************
2388// Prüft ob es Veränderungen in Spaltenbreiten gab
2389// pData : Zeiger auf die Fensterdaten
2390// Ergibt die Breite ab der die Spalten verändert wurden oder 0x10000
2392#ifndef __REACTOS__
2393 HWND hHeader;
2394#endif
2395 UINT uNext;
2396 UINT uCol;
2397 UINT uSub;
2398 int iSize;
2399 int iNum;
2400 int iNow;
2401 int iOld;
2402 int iRet;
2403
2404#ifndef __REACTOS__
2405 hHeader = pData->hHeader;
2406#endif
2407 pData->aColumnXpos[0] = 0;
2408
2409 iRet = 0x10000;
2410 iOld = 0;
2411 iNow = 0;
2412
2413 for(uCol = 0; uCol < pData->uColumnCount;) { // Suche die erste geänderte Spalte
2414 uSub = pData->aColumnPos[uCol];
2415 iSize = pData->aColumn[uSub].sReal;
2416 uSub = pData->aColumn[uSub].bNext;
2417 iOld = iNow;
2418 iNow += iSize;
2419 uCol += 1;
2420
2421 if(uCol == 1)
2422 iNow -= 1;
2423 if(iNow < iOld)
2424 iNow = iOld;
2425 if(uSub == pData->uColumnCount)
2426 if(iNow >= (int)pData->uSizeX - 1) {
2427 iNow++;
2428 }
2429
2430 iNum = pData->aColumnXpos[uSub];
2431
2432 if(iNum == iNow)
2433 continue;
2434 if(iNum == 0)
2435 iNum = iOld;
2436 if(iNum >= iNow) {
2437 iRet = iOld;
2438 } else {
2439 iRet = iOld;
2440
2441 if(pData->uSelectedItem) { // Problem bei ausgewählten leeren Einträgen
2442 uNext = pData->aColumn[pData->uSelectedSub].bNext;
2443 if(uNext == uSub) {
2444 UpdateRect(pData, pData->uSelectedItem, pData->uSelectedSub);
2445 }
2446 }
2447
2448 if(pData->uTrackedItem) {
2449 uNext = pData->aColumn[pData->uTrackedSub].bNext;
2450 if(uNext == uSub) {
2451 UpdateRect(pData, pData->uTrackedItem, pData->uTrackedSub);
2452 }
2453 }
2454 }
2455
2456 pData->aColumnXpos[uSub] = iNow;
2457 break;
2458 }
2459
2460 while(uCol < pData->uColumnCount) { // Restliche Spalten berechen
2461 iOld = iNow;
2462 uSub = pData->aColumnPos[uCol];
2463 iNow += pData->aColumn[uSub].sReal;
2464 uSub = pData->aColumn[uSub].bNext;
2465 uCol += 1;
2466
2467 if(uCol == pData->uColumnCount)
2468 if(iNow >= (int)pData->uSizeX - 1) {
2469 iNow++;
2470 }
2471
2472 pData->aColumnXpos[uSub] = iNow;
2473 }
2474
2475 pData->aColumnXpos[pData->uColumnCount + 1] = pData->uSizeX + 1;
2476
2477 return iRet;
2478}
2479
2480//*****************************************************************************
2481//*
2482//* TreeListSetOrderArray
2483//*
2484//*****************************************************************************
2485// Stellt die anzeige Reihenfolge der Spalten ein
2486// pData : Zeiger auf die Fensterdaten
2487// uItems : Ist die Nummer des Eintrages
2488// pArray : Zeiger auf die Einträge. Null steht für die Standartreihenfolge.
2489// z.B. {0,2,1} meint die sichtbare Reihenfolge Col0,Col2,Col1
2490// Der erste Eintrag muss 0 immer sein.
2491// Ergibt 1 = Ok
2492// 0 = Fehler
2493static int TreeListSetOrderArray(TreeListData *pData, unsigned uItems, unsigned *pArray) {
2494
2495 BYTE aFlags[MAX_COLUMNS + 1];
2496 UINT aArray[MAX_COLUMNS + 1];
2497 TV_COLSIZE sNotify;
2498 UINT uDiff;
2499 UINT uCol;
2500 UINT uSub;
2501
2502 if(!pArray) { // Spezialreihenfolge setzen
2503 if(uItems == FROM_HEADER) { // Array aus Header holen
2504 if(!Header_GetOrderArray(pData->hHeader, pData->uColumnCount, aArray)) {
2505 return 0;
2506 }
2507
2508 if(aArray[0] != 0) {
2509 return 0;
2510 }
2511 } else {
2512 for(uCol = pData->uColumnCount; uCol > 0; uCol++) { // Standartreihenfolge
2513 uCol--;
2514 aArray[uCol] = uCol;
2515 }
2516 }
2517
2518 uItems = pData->uColumnCount;
2519 pArray = aArray;
2520 } else { // Prüfe Array
2521 if(pData->uColumnCount != uItems || uItems == 0 || *pArray) {
2522 return 0;
2523 }
2524 }
2525
2526 memset(aFlags, 0, sizeof(aFlags) - 1);
2527
2528 for(uCol = 0, uDiff = 0; uCol < uItems; uCol++) { // Die Einträge prüfen
2529 uSub = pArray[uCol];
2530 if(uSub >= uItems)
2531 return 0;
2532 if(aFlags[uSub])
2533 return 0;
2534
2535 aFlags[uSub] = (BYTE)uCol;
2536
2537 uDiff |= uCol ^ pData->aColumnPos[uSub];
2538 }
2539
2540 if(uDiff == 0) { // Alles blieb gleich
2541 return 1;
2542 }
2543
2544 aFlags[0 ] = 0;
2545 aFlags[uItems] = (BYTE)uItems;
2546
2547 for(uCol = 1; uCol < uItems; uCol++) { // Die Einträge anpassen
2548 pData->aColumnPos[uCol] = (BYTE)pArray[uCol];
2549 }
2550
2551 for(uCol = 0; uCol < uItems; uCol++) {
2552 uSub = aFlags[uCol];
2553 pData->aColumn[uCol].bIndex = (BYTE)uSub;
2554 pData->aColumn[uCol].bNext = pData->aColumnPos[uSub + 1];
2555 }
2556
2557 Header_SetOrderArray(pData->hHeader, uItems, pArray);
2560
2561 if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) { // Alle Spalten haben sich verändert
2562 UNLOCK(pData);
2563
2564 for(uCol = 0; uCol < uItems; uCol++) {
2565 sNotify.hdr.code = TVN_COLUMNCHANGED;
2566 sNotify.uColumn = uCol;
2567 sNotify.uIndex = pData->aColumn[uCol].bIndex;
2568 sNotify.uPosX = pData->aColumnXpos[uCol];
2569 sNotify.iSize = pData->aColumn[uCol].sReal;
2570
2571 SendNotify(pData, &sNotify.hdr);
2572 }
2573
2574 LOCK(pData);
2575 }
2576
2577 return 1;
2578}
2579
2580//*****************************************************************************
2581//*
2582//* TreeListToggleItem
2583//*
2584//*****************************************************************************
2585// Klappt bei einem Eintrag die Kinder um, und schickt alle Notify-Nachrichten.
2586// pData : Zeiger auf die Fensterdaten
2587// uItem : Ist die Nummer des Eintrages
2588// uAddFlags : Sind die State-Flags die hinzugefügt werden sollen
2589// Bits 0..3 entahlen das Kommando, bei automatisch ermitteln
2590// Ergibt -1 = Fehler
2591// 0 = Ausgeführt
2592// 1 = Abbruch
2593static int TreeListToggleItem(TreeListData *pData, unsigned uItem, unsigned uAddFlags) {
2594
2595 NMTREEVIEW sNotify;
2596 BaseItem **pList;
2598 BaseItem *pTemp;
2599 unsigned uAction;
2600 unsigned uLevel;
2601 unsigned uNext;
2602 LRESULT lRet;
2603 BOOL bDo;
2604
2605 if(uItem > pData->uTreeItemsMax)
2606 return 0;
2607
2608 pList = pData->pTreeItems;
2609 pEntry = pList[uItem];
2610 if(!pEntry)
2611 return -1;
2612
2613 uAction = uAddFlags & 0x0F;
2614 if(!uAction) {
2616 }
2617
2618 sNotify.action = uAction;
2619 sNotify.hdr.code = TVN_ITEMEXPANDING;
2620 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
2621 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
2622 sNotify.itemNew.stateMask = 0xFFFFFFFF;
2623 sNotify.itemNew.state = pEntry->uState;
2624 sNotify.itemNew.lParam = pEntry->lParam;
2625 sNotify.itemNew.pszText = (LPTSTR) - 1;
2626 sNotify.itemNew.cchTextMax = -1;
2627 sNotify.itemOld.mask = 0;
2628 sNotify.ptDrag.x = 0;
2629 sNotify.ptDrag.y = 0;
2630
2631 UNLOCK(pData);
2632
2633 lRet = SendNotify(pData, &sNotify.hdr);
2634
2635 LOCK(pData);
2636
2637 pList = pData->pTreeItems;
2638 pEntry = pList[uItem];
2639
2640 if(pEntry == 0)
2641 return -1; // Eintrag inzischen gelöscht ?
2642 if(lRet != 0)
2643 return 1; // User-Abbruch ?
2644
2645 if(uAction == TVE_EXPAND) { // Aufklappen
2646 if(pEntry->uState & TVIS_EXPANDED) {
2647 bDo = FALSE; // Nur von + auf -
2648 } else {
2649 pEntry->uState |= TVIS_EXPANDED; // Kinder Aufklappen
2650 bDo = TRUE;
2651 }
2652 } else { // Zuklappen
2653 pEntry->uState &= ~TVIS_EXPANDED;
2654 bDo = TRUE;
2655 }
2656
2657 pEntry->uState &= ~TVIS_EXPANDPARTIAL;
2658 pEntry->uState |= uAddFlags&~0x0F;
2659
2660 if(pEntry->uShowPos && bDo) {
2661 if(pEntry->uState & TVIS_EXPANDED) { // Kinderfenster aktuallisieren
2662 uLevel = 0;
2663 uNext = pEntry->uFirstChild;
2664
2665 while(uNext) {
2666 pTemp = pList[uNext];
2667 pTemp->uShowPos = 0;
2668
2669 if(pTemp->uFirstChild) {
2670 uNext = pTemp->uFirstChild;
2671 uLevel++;
2672 continue;
2673 }
2674
2675 if(pTemp->uNextItem) {
2676 uNext = pTemp->uNextItem;
2677 continue;
2678 }
2679
2680 if(uLevel == 0)
2681 break;
2682
2683 uNext = pList[pTemp->uParent]->uNextItem;
2684 uLevel--;
2685 }
2686 }
2687
2688 UpdateItems(pData, uItem);
2689 }
2690
2691 sNotify.action = uAction;
2692 sNotify.hdr.code = TVN_ITEMEXPANDED;
2693 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
2694 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
2695 sNotify.itemNew.stateMask = 0xFFFFFFFF;
2696 sNotify.itemNew.state = pEntry->uState;
2697 sNotify.itemNew.lParam = pEntry->lParam;
2698 sNotify.itemNew.pszText = (LPTSTR) - 1;
2699 sNotify.itemNew.cchTextMax = -1;
2700 sNotify.itemOld.mask = 0;
2701 sNotify.ptDrag.x = 0;
2702 sNotify.ptDrag.y = 0;
2703
2704 UNLOCK(pData);
2705
2706 SendNotify(pData, &sNotify.hdr);
2707
2708 LOCK(pData);
2709
2710 pList = pData->pTreeItems;
2711 pEntry = pData->pTreeItems[uItem];
2712
2713 if(!pEntry)
2714 return -1; // Eintrag inzischen gelöscht ?
2715
2716 if(uAction == TVE_EXPAND) { // ONCE setzen nach Expandieren
2717 pEntry->uState |= TVIS_EXPANDEDONCE;
2718 }
2719
2720 if(pData->uSelectedItem && bDo) { // Ist der ausgewählten Eintrag sichtbar ?
2721 pEntry = pList[pData->uSelectedItem];
2722 if(!pEntry) {
2723 pData->uSelectedItem = 0;
2724 pData->uSelectedSub = 0;
2725 } else
2726 if(!pEntry->uShowPos) {
2727 while(!pEntry->uShowPos) {
2728 uItem = pEntry->uParent;
2729 pEntry = pList[uItem];
2730 }
2731
2732 TreeListSelectItem(pData, uItem, pData->uSelectedSub, TVC_UNKNOWN);
2733 }
2734 }
2735
2736 if(bDo == FALSE) { // Nur von + auf -
2737 UpdateRect(pData, uItem, 0);
2738 }
2739
2740 return 0;
2741}
2742
2743//*****************************************************************************
2744//*
2745//* TreeListGetItemRect
2746//*
2747//*****************************************************************************
2748// Holt das Rechteck eines Eintrages
2749// pData : Zeiger auf die Fensterdaten
2750// uItem : Ist die Nummer des Eintrages
2751// uFlags : Bit 0 : 0=volle Zeile 1=nur Text
2752// Bit 7 : 1=nur Spalte
2753// Bit 24.. : Spaltennummer
2754// Ergibt 1 wenn der Eintrag sichtbar war
2755static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT *pRect) {
2756
2757 ExtraItem *pExtra;
2759 unsigned uNext;
2760 unsigned uPos;
2761 unsigned uSub;
2762
2763 if(uItem > pData->uTreeItemsMax) {
2764 memset(pRect, 0, sizeof(RECT));
2765 return 0;
2766 }
2767
2768 pEntry = pData->pTreeItems[uItem];
2769 if(!pEntry->uShowPos) { // Ist der Eintrag aufgeklappt
2770 memset(pRect, 0, sizeof(RECT));
2771 return 0;
2772 }
2773
2774 uPos = pEntry->uShowPos - pData->uScrollY - 1;
2775 if(uPos >= pData->uMaxEnties) { // Eintrag im Fenster sichtbar
2776 memset(pRect, 0, sizeof(RECT));
2777 return 0;
2778 }
2779
2780 pRect->top = pData->uStartPixel;
2781 pRect->top += pData->iRowHeight * uPos;
2782 pRect->bottom = pData->iRowHeight + pRect->top;
2783
2784 if((uFlags & 0xFC) == TVIR_GETCOLUMN) { // Nur Spalten
2785 uSub = uFlags >> 24;
2786 if(uSub >= pData->uColumnCount)
2787 uSub = 0;
2788
2789 uNext = pData->aColumn[uSub].bNext;
2790 pRect->left = pData->aColumnXpos[uSub];
2791 pRect->left -= pData->uScrollX;
2792 pRect->right = pData->aColumnXpos[uNext];
2793 pRect->right -= pData->uScrollX;
2794 } else {
2795 uSub = 0;
2796 pRect->left = 0;
2797 pRect->left -= pData->uScrollX;
2798 pRect->right = pData->uSizeX;
2799 }
2800
2801 if(uFlags & TVIR_TEXT) { // Nur Text ausgeben
2802 if(uSub > 0) {
2803 pExtra = pData ->pExtraItems[uSub - 1][uItem];
2804
2805 if(pData->aColumn[uSub].bEdit == TVAX_CHECK) {
2806 pRect->left += pData->iChecksXsize;
2807 if(pRect->left > pRect->right)
2808 pRect->left = pRect->right;
2809 } else
2810 if(pExtra && pExtra->bFlags & TVIX_HASIMAGE) {
2811 pRect->left += pData->iImagesXsize;
2812 if(pRect->left > pRect->right)
2813 pRect->left = pRect->right;
2814 }
2815 } else {
2816 if(pData->cHasRootRow) { // Root-Linien ausgleichen
2817 pRect->left += pData->iIndent;
2818 }
2819
2820 pRect->left += pData->iIndent * pEntry->uLevel;
2821
2822 if(pData->hStates) {
2823 pRect->left += pData->iStatesXsize;
2824 }
2825
2826 if(!(pData->uStyle & TVS_HASLINES)) {
2827 pRect->left -= 1;
2828 }
2829
2830 if(pData->uStyleEx & TVS_EX_ITEMLINES) {
2831 pRect->left += 1;
2832 if(pEntry->bFlags & TVIX_HASIMAGE)
2833 pRect->left++;
2834 }
2835
2836 if(pEntry->bFlags & TVIX_HASIMAGE) {
2837 pRect->left += pData->iImagesXsize;
2838 }
2839
2840 if(pRect->left > pRect->right) {
2841 pRect->left = pRect->right;
2842 }
2843 }
2844 }
2845
2846 return 1;
2847}
2848
2849//*****************************************************************************
2850//*
2851//* TreeListEnsureVisible
2852//*
2853//*****************************************************************************
2854// Macht einen Eintrag sichtbar
2855// pData : Zeiger auf die Fensterdaten
2856// uItem : Ist die Nummer des Eintrages
2857// uSub : Untereintrag der sichtbar sein soll
2858// 0xFFFFFFFF nur Zeile
2859// FIRST_LINE als oberster Eintrag
2860// Ergibt 1 wenn nur zum Eintrag gescrollt wurde bzw. 0 wenn aufgeklapt wurde
2861static int TreeListEnsureVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
2862
2864 BaseItem *pTemp;
2865 unsigned uTemp;
2866 unsigned uNext;
2867 unsigned uPos;
2868 int iNum;
2869 int iAnf;
2870 int iOff;
2871 int iEnd;
2872 int iMax;
2873 int iRet;
2874
2875 if(uItem > pData->uTreeItemsMax)
2876 return -1;
2877
2878 pEntry = pData->pTreeItems[uItem];
2879 if(!pEntry)
2880 return -1;
2881
2882 uPos = pEntry->uShowPos;
2883 if(!uPos) { // Zweige aufklappen wenn Eintrag zugeklappt
2884
2885 iRet = 0;
2886
2887 for(pTemp = pEntry;;) {
2888 uTemp = pTemp->uParent;
2889 pTemp = pData->pTreeItems[uTemp];
2890 if(!pTemp)
2891 break;
2892 if((pTemp->uState & TVIS_EXPANDED) == 0) {
2893 if(TreeListToggleItem(pData, uTemp, 0))
2894 return 0;
2895 }
2896 }
2897
2898 pEntry = pData->pTreeItems[uItem];
2899 if(!pEntry)
2900 return 0;
2901
2902 uPos = pEntry->uShowPos;
2903 if(!uPos)
2904 return 0;
2905 } else { // Nur Scrollen
2906 iRet = 1;
2907 }
2908
2909 uPos--;
2910 if(uPos < pData->uScrollY) { // Vor erster Zeile
2911 pData->uScrollY = uPos;
2912 SetScrollPos(pData->hWnd, SB_VERT, uPos, TRUE);
2914 } else
2915 if(uSub == FIRST_LINE) { // Als ersten Eintrag
2916 if(uPos != pData->uScrollY) {
2917 pData->uScrollY = uPos;
2918 SetScrollPos(pData->hWnd, SB_VERT, uPos, TRUE);
2920 }
2921
2922 return iRet;
2923 } else
2924 if(uPos >= pData->uScrollY + pData->uPageEnties) { // Nach letzter Zeile
2925 iOff = uPos - (pData->uPageEnties - 1);
2926 iMax = pData->uItemPosCount;
2927 iMax -= pData->uPageEnties - 1;
2928
2929 if(iOff >= iMax)
2930 iOff = iMax;
2931 if(iOff < 0)
2932 iOff = 0;
2933 if(iOff != (int)pData->uScrollY) {
2934 pData->uScrollY = iOff;
2935 SetScrollPos(pData->hWnd, SB_VERT, iOff, TRUE);
2937 }
2938 }
2939
2940 if(uSub < pData->uColumnCount) { // Horizontal einrichten
2941 uNext = pData->aColumn[uSub].bNext;
2942 iNum = pData->uSizeX;
2943 iOff = pData->uScrollX;
2944 iAnf = pData->aColumnXpos[uSub ];
2945 iEnd = pData->aColumnXpos[uNext];
2946
2947 if(iOff + iNum < iAnf)
2948 iOff = iAnf;
2949 if(iOff >= iEnd)
2950 iOff = iAnf;
2951 if(iOff + iNum < iEnd)
2952 iOff = iEnd - iNum;
2953 if(iOff > iAnf)
2954 iOff = iAnf;
2955
2956 iMax = pData->aColumnXpos[pData->uColumnCount];
2957 iMax -= pData->uSizeX / 2;
2958
2959 if(iOff > iMax)
2960 iOff = iMax;
2961 if(iOff < 0)
2962 iOff = 0;
2963 if(iOff != (int)pData->uScrollX) {
2964 pData->uScrollX = iOff;
2965 SetScrollPos(pData->hWnd, SB_HORZ, iOff, TRUE);
2967 MoveWindow(pData->hHeader, -iOff, 0, iNum + iOff, pData->uStartPixel, TRUE);
2968 }
2969 }
2970 return iRet;
2971}
2972
2973//*****************************************************************************
2974//*
2975//* TreeListIsVisible
2976//*
2977//*****************************************************************************
2978// Prüft ob ein Eintrag sichtbar ist
2979// pData : Zeiger auf die Fensterdaten
2980// uItem : Ist die Nummer des Eintrages
2981// uSub : Untereintrag der geprüft werden soll
2982// 0xFFFFFFFF nur Zeile prüfen
2983// Ergibt den Zustand des Eintrages:
2984// -1 = Unbekannter Eintrag
2985// 0 = Eintrag ist zugeklappt
2986// 1 = Eintrag ist aufgeklappt aber nicht sichtbar
2987// 2 = Eintrag ist aufgeklappt und teilweise sichtbar
2988// 3 = Eintrag ist aufgeklappt und Spalte ist nur teilweise sichtbar
2989// 4 = Eintrag ist aufgeklappt und ganz sichtbar
2990static int TreeListIsVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
2991
2993 unsigned uNext;
2994 unsigned uPos;
2995 int iNum;
2996 int iAnf;
2997 int iOff;
2998 int iEnd;
2999
3000 if(uItem > pData->uTreeItemsMax)
3001 return -1;
3002
3003 pEntry = pData->pTreeItems[uItem];
3004 if(!pEntry)
3005 return -1;
3006
3007 uPos = pEntry->uShowPos;
3008 if(!uPos) { // Ist der Eintrag zugeklappt
3009 return 0;
3010 }
3011
3012 uPos--;
3013 if(uPos < pData->uScrollY) { // Vor erster Zeile
3014
3015 return 1;
3016 }
3017
3018 if(uPos >= pData->uScrollY + pData->uMaxEnties) { // Nach letzter Zeile
3019 return 1;
3020 }
3021
3022 if(uPos == pData->uScrollY + pData->uPageEnties) { // Auf halbsichtbarer Zeile
3023 if(uSub < pData->uColumnCount) {
3024 uNext = pData->aColumn[uSub].bNext;
3025 iNum = pData->uSizeX;
3026 iOff = pData->uScrollX;
3027 iAnf = pData->aColumnXpos[uSub ];
3028 iEnd = pData->aColumnXpos[uNext];
3029
3030 if(iOff + iNum < iAnf)
3031 return 1;
3032 if(iOff >= iEnd)
3033 return 1;
3034 }
3035
3036 return 2;
3037 }
3038
3039 if(uSub < pData->uColumnCount) { // Spalte prüfen
3040 uNext = pData->aColumn[uSub].bNext;
3041 iNum = pData->uSizeX;
3042 iOff = pData->uScrollX;
3043 iAnf = pData->aColumnXpos[uSub ];
3044 iEnd = pData->aColumnXpos[uNext];
3045
3046 if(iOff + iNum < iAnf)
3047 return 1;
3048 if(iOff >= iEnd)
3049 return 1;
3050 if(iOff + iNum < iEnd)
3051 return 3;
3052 if(iOff > iAnf)
3053 return 3;
3054 }
3055
3056 return 4;
3057}
3058
3059//*****************************************************************************
3060//*
3061//* TreeListDeleteItem
3062//*
3063//*****************************************************************************
3064// Löscht einen Eintrag aus dem Fenster
3065// pData : Zeiger auf die Fensterdaten
3066// uItem : Ist die Nummer des Eintrages der gelöscht werden soll
3067// iMode : Wie soll der Eintrag gelöscht werden
3068// 0 = Eintrag löschen und nicht neu zeichnen
3069// 1 = Eintrag löschen und neu zeichnen
3070// 2 = Nur Kindereinträge löschen und neu zeichnen
3071// Ergibt 1 wenn der Eintrag gelöscht wurde.
3072static int TreeListDeleteItem(TreeListData *pData, unsigned uItem, int iMode) {
3073
3074 NMTREEVIEW sNotify;
3075 ExtraItem **pList;
3076 ExtraItem *pExtra;
3078 BaseItem *pTemp;
3079 unsigned uPos;
3080 int iOff;
3081 int iMax;
3082
3083 if(pData->cLockChanges)
3084 return 0;
3085
3086 if(uItem > pData->uTreeItemsMax) { // Prüfe den Eintrag
3087 if(uItem != U(TVI_ROOT))
3088 return 0; // Alles löschen
3089 if(pData->uLastChild == 0)
3090 return 0;
3091
3092 while(pData->uLastChild) {
3093 TreeListDeleteItem(pData, pData->uLastChild, 0);
3094 }
3095
3096 pData->uItemPosCount = 0;
3097
3100
3101 return 1;
3102 }
3103
3104 pEntry = pData->pTreeItems[uItem];
3105 if(!pEntry) { // Prüfe den Eintrag
3106 if(uItem != 0)
3107 return 0; // Alles löschen
3108 if(pData->uLastChild == 0)
3109 return 0;
3110
3111 while(pData->uLastChild) {
3112 TreeListDeleteItem(pData, pData->uLastChild, 0);
3113 }
3114
3115 pData->uItemPosCount = 0;
3116
3119
3120 return 1;
3121 }
3122
3123 if(iMode == 2) { // Nur Kindereinträge löschen
3124 if(!pEntry->uFirstChild) {
3125 return 0;
3126 }
3127
3128 while(pEntry->uLastChild) { // Alle Kinder löschen
3129 TreeListDeleteItem(pData, pEntry->uLastChild, 0);
3130 }
3131
3132 uPos = pEntry->uShowPos;
3133 if(uPos) {
3134 UpdateItems(pData, uItem);
3135 }
3136
3137 return 1;
3138 }
3139
3140 while(pEntry->uLastChild) { // Alle Kinder löschen
3141 TreeListDeleteItem(pData, pEntry->uLastChild, 0);
3142 }
3143
3144 if(uItem == pData->uSelectedItem) { // Einen ausgewählten Eintrag löschen
3145 sNotify.hdr.code = TVN_SELCHANGED;
3146 sNotify.action = TVC_UNKNOWN;
3147 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3148 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3149 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3150 sNotify.itemOld.state = pEntry->uState&~TVIS_SELECTED;
3151 sNotify.itemOld.lParam = pEntry->lParam;
3152 sNotify.itemOld.cChildren = 0;
3153 sNotify.itemOld.pszText = (LPTSTR) - 1;
3154 sNotify.itemOld.cchTextMax = -1;
3155 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3156 sNotify.itemNew.hItem = NULL;
3157 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3158 sNotify.itemNew.state = 0;
3159 sNotify.itemNew.lParam = 0;
3160 sNotify.itemNew.cChildren = 0;
3161 sNotify.itemNew.pszText = (LPTSTR) - 1;
3162 sNotify.itemNew.cchTextMax = -1;
3163 sNotify.ptDrag.x = 0;
3164 sNotify.ptDrag.y = 0;
3165
3166 UNLOCK(pData);
3167 SendNotify(pData, &sNotify.hdr); // Bekant geben das der Eintrag nicht mehr ausgewählt ist
3168 LOCK(pData);
3169
3170 pData->uSelectedItem = 0;
3171 pData->uSelectedSub = 0;
3172 }
3173
3174 sNotify.hdr.code = TVN_DELETEITEM;
3175 sNotify.itemNew.mask = 0;
3176 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
3177 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3178 sNotify.itemOld.lParam = pEntry->lParam;
3179 sNotify.itemOld.pszText = (LPTSTR) - 1;
3180 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3181 sNotify.itemNew.state = pEntry->uState;
3182 sNotify.itemOld.cchTextMax = -1;
3183 sNotify.ptDrag.x = 0;
3184 sNotify.ptDrag.y = 0;
3185
3186 UNLOCK(pData);
3187 SendNotify(pData, &sNotify.hdr);
3188 LOCK(pData);
3189
3190 pEntry = pData->pTreeItems[uItem]; // Prüfen ob der Eintrag noch existiert
3191 if(!pEntry)
3192 return 0;
3193
3194 if(uItem == pData->uTrackedItem) { // Einen unterstrichenen Eintrag löschen
3195 pData->uTrackedItem = 0;
3196 pData->uTrackedSub = 0;
3197 }
3198
3199 if(pData->uInsertMark == uItem) {
3200 pData->uInsertMark = 0;
3201 }
3202
3203 if(pData->uSingleSel == uItem) {
3204 pData->uSingleSel = 0;
3205 }
3206
3207 if(pEntry->uPrevItem) { // Gibt es einen vorherigen Eintrag
3208 pTemp = pData->pTreeItems[pEntry->uPrevItem];
3209 pTemp->uNextItem = pEntry->uNextItem;
3210 } else {
3211 if(pEntry->uParent) { // Neues erstes Kind in Elterneintrag
3212 pTemp = pData->pTreeItems[pEntry->uParent];
3213 pTemp->uFirstChild = pEntry->uNextItem;
3214 } else {
3215 pData->uFirstChild = pEntry->uNextItem;
3216 }
3217 }
3218
3219 if(pEntry->uNextItem) { // Gibt es einen vorherigen Eintrag
3220 pTemp = pData->pTreeItems[pEntry->uNextItem];
3221 pTemp->uPrevItem = pEntry->uPrevItem;
3222 } else {
3223 if(pEntry->uParent) { // Neues letztes Kind in Elterneintrag
3224 pTemp = pData->pTreeItems[pEntry->uParent];
3225 pTemp->uLastChild = pEntry->uPrevItem;
3226
3227 if(pTemp->uFirstChild == 0 && pTemp->uLastChild == 0) {
3228 pTemp->bFlags &= ~TVIX_HASBUTTON;
3229 }
3230 } else {
3231 pData->uLastChild = pEntry->uPrevItem;
3232 }
3233 }
3234
3235 for(uPos = 1; uPos < pData->uColumnCount; uPos++) { // Alle Extraeinträge löschen
3236 pList = pData->pExtraItems[uPos - 1];
3237
3238 pExtra = pList[uItem];
3239 if(!pExtra)
3240 continue;
3241
3242 pList[uItem] = NULL;
3243
3244 if(pExtra->pText) {
3245 pExtra->uTextSize = 0;
3246 delete(pExtra->pText);
3247 }
3248
3249 delete(pExtra);
3250 }
3251
3252
3253 pData->pTreeItems[uItem] = NULL; // Den Eintrag löschen
3254
3255 if(pEntry->pText) {
3256 pEntry->uTextSize = 0;
3257 delete(pEntry->pText);
3258 }
3259
3260 if(iMode) { // Den Eintrag neuzeichnen
3261 uItem = pEntry->uPrevItem;
3262 if(!uItem && !pEntry->uNextItem) {
3263 uItem = pEntry->uParent;
3264 if(!uItem)
3265 uPos = 1;
3266 else
3267 uPos = pData->pTreeItems[uItem]->uShowPos;
3268 } else {
3269 uPos = pEntry->uShowPos;
3270 }
3271
3272 if(uPos) {
3273 UpdateItems(pData, uItem);
3274 }
3275 }
3276
3277 if(pEntry->uState & TVIS_SELECTED) // Ausgewählte Einträge runterzählen
3278 if(pData->uSelectedCount > 0) {
3279 pData->uSelectedCount--;
3280 }
3281
3282 delete(pEntry);
3283
3284 pData->uTreeItemsCount--;
3285
3286 iOff = pData->uScrollY; // Prüfe die Scrollposition
3287 iMax = pData->uItemPosCount;
3288 iMax -= pData->uPageEnties - 1;
3289
3290 if(iOff >= iMax)
3291 iOff = iMax;
3292 if(iOff < 0)
3293 iOff = 0;
3294 if(iOff != (int)pData->uScrollY) {
3295 pData->uScrollY = iOff;
3296 SetScrollPos(pData->hWnd, SB_VERT, iOff, TRUE);
3298 }
3299
3300 return 1;
3301}
3302
3303//*****************************************************************************
3304//*
3305//* TreeListXorSelectItem
3306//*
3307//*****************************************************************************
3308// Wählt einen Eintrag ab bzw. an
3309// pData : Zeiger auf die Fensterdaten
3310// uItem : Ist die Nummer des Eintrages der ausgewählt werden soll
3311// iMode : Ist der Grund für die Änderung
3312// TVC_BYKEYBOARD
3313// TVC_BYMOUSE
3314// TVC_UNKNOWN
3315// Ergibt 1 wenn der Eintrag ab/angewählt wurde
3316// 0 wenn der Eintrag nicht verändert wurde
3317static int TreeListXorSelectItem(TreeListData *pData, unsigned uItem, int iMode) {
3318
3319 NMTREEVIEW sNotify;
3321 unsigned uOld;
3322 unsigned uRet;
3323
3324 pEntry = pData->pTreeItems[uItem];
3325 if(!pEntry)
3326 return 0;
3327 if(uItem == pData->uSelectedItem)
3328 return 0;
3329
3330 uOld = pEntry->uState;
3331
3332 sNotify.hdr.code = TVN_SELCHANGING;
3333 sNotify.action = iMode;
3334 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3335 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3336 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3337 sNotify.itemNew.state = pEntry->uState;
3338 sNotify.itemNew.lParam = pEntry->lParam;
3339 sNotify.itemNew.cChildren = 0;
3340 sNotify.itemNew.pszText = (LPTSTR) - 1;
3341 sNotify.itemNew.cchTextMax = -1;
3342 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3343 sNotify.itemOld.hItem = NULL;
3344 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3345 sNotify.itemOld.state = 0;
3346 sNotify.itemOld.lParam = 0;
3347 sNotify.itemOld.cChildren = 0;
3348 sNotify.itemOld.pszText = (LPTSTR) - 1;
3349 sNotify.itemOld.cchTextMax = -1;
3350 sNotify.ptDrag.x = 0;
3351 sNotify.ptDrag.y = 0;
3352
3353 UNLOCK(pData);
3354 uRet = U(SendNotify(pData, &sNotify.hdr));
3355 LOCK(pData);
3356
3357 if(uRet)
3358 return 0;
3359
3360 pEntry = pData->pTreeItems[uItem];
3361 if(!pEntry)
3362 return 0;
3363 pEntry->uState ^= TVIS_SELECTED;
3364
3365 sNotify.hdr.code = TVN_SELCHANGED;
3366 sNotify.action = iMode;
3367 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3368 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3369 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3370 sNotify.itemNew.state = pEntry->uState;
3371 sNotify.itemNew.lParam = pEntry->lParam;
3372 sNotify.itemNew.cChildren = 0;
3373 sNotify.itemNew.pszText = (LPTSTR) - 1;
3374 sNotify.itemNew.cchTextMax = -1;
3375 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3376 sNotify.itemOld.hItem = NULL;
3377 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3378 sNotify.itemOld.state = 0;
3379 sNotify.itemOld.lParam = 0;
3380 sNotify.itemOld.cChildren = 0;
3381 sNotify.itemOld.pszText = (LPTSTR) - 1;
3382 sNotify.itemOld.cchTextMax = -1;
3383 sNotify.ptDrag.x = 0;
3384 sNotify.ptDrag.y = 0;
3385
3386 UNLOCK(pData);
3387 SendNotify(pData, &sNotify.hdr);
3388 LOCK(pData);
3389
3390 pEntry = pData->pTreeItems[uItem];
3391 if(!pEntry)
3392 return 0;
3393 if(pEntry->uShowPos) {
3394 if(pData->uStyleEx & TVS_EX_FULLROWMARK)
3395 UpdateRow(pData, uItem);
3396 else
3397 UpdateRect(pData, uItem, 0);
3398 }
3399
3400 if((uOld ^ pEntry->uState)&TVIS_SELECTED) {
3401 if(pEntry->uState & TVIS_SELECTED)
3402 pData->uSelectedCount++;
3403 else
3404 pData->uSelectedCount--;
3405 }
3406
3407 return 1;
3408}
3409
3410
3411//*****************************************************************************
3412//*
3413//* TreeListRemoveFocus
3414//*
3415//*****************************************************************************
3416// Wählt den Focus ab
3417// pData : Zeiger auf die Fensterdaten
3419
3420 ExtraItem *pExtra;
3422 unsigned uItem;
3423 unsigned uSub;
3424
3425 if(!pData->uFocusItem)
3426 return;
3427
3428 uItem = pData->uFocusItem;
3429 pEntry = pData->pTreeItems[uItem];
3430
3431 if(pEntry) {
3432 pEntry->bFlags &= ~TVIX_FOCUSED;
3433
3434 uSub = pData->uFocusSub;
3435
3436 if(uSub) {
3437 pExtra = pData->pExtraItems[uSub - 1][uItem];
3438 if(pExtra)
3439 pExtra->bFlags &= ~TVIX_FOCUSED;
3440 }
3441
3442 UpdateRect(pData, uItem, uSub);
3443 }
3444
3445 pData->uFocusItem = 0;
3446 pData->uFocusSub = 0;
3447}
3448
3449//*****************************************************************************
3450//*
3451//* TreeListSetFocus
3452//*
3453//*****************************************************************************
3454// Wählt den Focus-Eintrag
3455// pData : Zeiger auf die Fensterdaten
3456// uItem : Eintrag für den Focus (0xFFFFFFFF=keine Änderung)
3457// uSub : Spalte für den Focus (0xFFFFFFFF=keine Änderung)
3458// Ergibt 1 wenn der Focus gesetzt wurde, bzw 0 bei einem Fehler
3459static int TreeListSetFocus(TreeListData *pData, unsigned uItem, unsigned uSub) {
3460
3461 ExtraItem *pExtra;
3463 BaseItem *pTemp;
3464 unsigned uTemp;
3465 unsigned uCol;
3466
3467 if(pData->uFocusItem) {
3468 if(uSub == 0xFFFFFFFF)
3469 uSub = pData->uFocusSub;
3470 if(uItem == 0xFFFFFFFF)
3471 uItem = pData->uFocusItem;
3472 } else {
3473 if(uSub == 0xFFFFFFFF)
3474 uSub = pData->uSelectedSub;
3475 if(uItem == 0xFFFFFFFF)
3476 uItem = pData->uSelectedItem;
3477 }
3478
3479 if(pData->uFocusItem == uItem)
3480 if(pData->uFocusSub == uSub)
3481 return 1;
3482
3483 if(!uItem) { // Focus abwählen
3485 return 1;
3486 }
3487
3488
3489 if(uItem > pData->uTreeItemsMax) { // Den Eintrag prüfen
3490 return 0;
3491 }
3492
3493 pEntry = pData->pTreeItems[uItem];
3494 if(!pEntry) {
3495 return 0;
3496 }
3497
3498 if(!(pData->uStyleEx & TVS_EX_SUBSELECT))
3499 uSub = 0;
3500
3501 if(!(pData->uStyleEx & TVS_EX_MULTISELECT)) { // Einzel auswahl
3502 return TreeListSelectItem(pData, uItem, uSub, TVC_UNKNOWN);
3503 }
3504
3505 uTemp = pData->uFocusItem;
3506 pTemp = pData->pTreeItems[uTemp];
3507
3508 if(pTemp) { // Den alten Eintrag abwählen
3509 pTemp->bFlags &= ~TVIX_FOCUSED;
3510 uCol = pData->uFocusSub;
3511
3512 if(uCol) {
3513 pExtra = pData->pExtraItems[uCol - 1][uTemp];
3514 if(pExtra)
3515 pExtra->bFlags &= ~TVIX_FOCUSED;
3516 }
3517
3518 UpdateRect(pData, uItem, uSub);
3519 }
3520
3521
3522 if(uSub) { // Neuen Eintrag wählen
3523 pExtra = pData->pExtraItems[uSub - 1][uItem];
3524 if(pExtra)
3525 pExtra->bFlags |= TVIX_FOCUSED;
3526 } else {
3527 pEntry->bFlags |= TVIX_FOCUSED;
3528 }
3529
3530 pData->uFocusItem = uItem;
3531 pData->uFocusSub = uSub;
3532
3533 if(pEntry->uState & TVIS_SELECTED) { // Auch die Auswahl nachziehen
3534 if(pData->uSelectedItem != uItem) {
3535 uTemp = pData->uSelectedItem;
3536 uCol = pData->uSelectedSub;
3537 } else {
3538 uTemp = 0;
3539 uCol = pData->uSelectedSub;
3540 }
3541
3542 pData->uSelectedItem = uItem;
3543 pData->uSelectedSub = uSub;
3544
3545 if(pData->uStyleEx & TVS_EX_FULLROWMARK) {
3546 uCol = uSub + 1;
3547 }
3548
3549 if(uTemp) {
3550 if(uCol != uSub)
3551 UpdateRow(pData, uTemp);
3552 else
3553 UpdateRect(pData, uTemp, uCol);
3554 }
3555
3556
3557 if(uCol != uSub)
3558 UpdateRow(pData, uItem);
3559 else
3560 UpdateRect(pData, uItem, uCol);
3561 } else {
3562 UpdateRect(pData, uItem, uSub);
3563 }
3564
3565 return 1;
3566}
3567
3568//*****************************************************************************
3569//*
3570//* TreeListSelectItem
3571//*
3572//*****************************************************************************
3573// Wählt einen Eintrag aus
3574// pData : Zeiger auf die Fensterdaten
3575// uItem : Ist die Nummer des Eintrages der ausgewählt werden soll
3576// uSubItem : Ist die Spalte die gewählt werden soll
3577// iMode : Ist der Grund für die Änderung
3578// TVC_BYKEYBOARD
3579// TVC_BYMOUSE
3580// TVC_UNKNOWN
3581// TVC_ONLYFOCUS (nur der Focus hat sich verändert)
3582// TVC_DESELECT (dieses Flag löscht die alte Auswahl)
3583// TVC_UNSELECT (dieses Flag löscht Auswahl bei MultiSel)
3584// Ergibt 2 wenn der Eintrag gewählt und umgeklapt wurde
3585// 1 wenn der Eintrag gewählt wurde
3586// 0 wenn der Eintrag nicht gewählt wurde
3587static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int iMode) {
3588
3589 NMTREEVIEW sNotify;
3590 ExtraItem *pExtra;
3592 BaseItem *pTemp;
3593 LPARAM lParam;
3594 LPARAM lPaOld;
3595 unsigned uState;
3596 unsigned uStOld;
3597 unsigned uNext;
3598 unsigned uPos;
3599 unsigned uOld;
3600 unsigned uSub;
3601 unsigned uRet;
3602 int iDel;
3603 int iSel;
3604
3605 uOld = pData->uSelectedItem;
3606 uSub = pData->uSelectedSub;
3607
3608 if(uSubItem >= pData->uColumnCount && uSubItem > 0)
3609 return 0;
3610 if(uItem > pData->uTreeItemsMax)
3611 return 0;
3612 if(uItem == uOld)
3613 if(uSubItem == uSub)
3614 if(pData->uSelectedCount <= 1 || !(pData->uStyleEx & TVS_EX_MULTISELECT)) {
3615 return 1;
3616 }
3617
3618 if(pData->uStyleEx & TVS_EX_MULTISELECT) { // Ist die Mehrfachauswahl möglich
3619 iSel = iMode & TVC_UNSELECT;
3620 iDel = iMode & TVC_DESELECT;
3621 if(!iDel) {
3622 if(pData->uStyleEx & (TVS_EX_FULLROWMARK | TVS_EX_SUBSELECT))
3623 UpdateRow(pData, uOld);
3624 else
3625 UpdateRect(pData, uOld, uSub);
3626
3627 uOld = 0;
3628 uSub = 0;
3629 } else { // Alle gewählten Einträge abwählen
3630 if(pData->uSelectedCount > 1 && pData->uTreeItemsMax) {
3631 for(uPos = pData->uTreeItemsMax; uPos; uPos--) {
3632 pEntry = pData->pTreeItems[uPos];
3633 if(!pEntry || !(pEntry->uState & TVIS_SELECTED))
3634 continue;
3636 if(!pData->uSelectedCount)
3637 break; // Wurden alle Einträge abgewählt
3638 }
3639 }
3640 }
3641 } else { // Altes Select löschen
3642 iMode &= ~TVC_ONLYFOCUS;
3643 iDel = 1;
3644 iSel = 0;
3645 }
3646
3648
3649 pEntry = pData->pTreeItems[uItem];
3650 if(!pEntry) { // Neuen Statatus holen
3651 if(uItem)
3652 return 0;
3653 uState = 0;
3654 lParam = 0;
3655 } else {
3656 uState = pEntry->uState;
3657 lParam = pEntry->lParam;
3658
3659 if(uSubItem) {
3660 uState &= TVIS_BASEFLAGS;
3661 pExtra = pData->pExtraItems[uSubItem - 1][uItem];
3662 if(pExtra)
3663 uState |= pExtra->uState;
3664 }
3665 }
3666
3667 pTemp = pData->pTreeItems[uOld];
3668 if(!pTemp) { // Alten Status holen
3669 uStOld = 0;
3670 lPaOld = 0;
3671 } else {
3672 uStOld = pTemp->uState;
3673 lPaOld = pTemp->lParam;
3674
3675 if(uSub) {
3676 uStOld &= TVIS_BASEFLAGS;
3677 pExtra = pData->pExtraItems[uSub - 1][uOld];
3678 if(pExtra)
3679 uStOld |= pExtra->uState;
3680 }
3681 }
3682
3683 sNotify.hdr.code = TVN_SELCHANGING;
3684 sNotify.action = iMode;
3685 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3686 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3687 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3688 sNotify.itemNew.state = uState;
3689 sNotify.itemNew.lParam = lParam;
3690 sNotify.itemNew.cChildren = uSubItem;
3691 sNotify.itemNew.pszText = (LPTSTR) - 1;
3692 sNotify.itemNew.cchTextMax = -1;
3693 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3694 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uOld;
3695 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3696 sNotify.itemOld.state = uStOld;
3697 sNotify.itemNew.lParam = lPaOld;
3698 sNotify.itemOld.cChildren = uSub;
3699 sNotify.itemOld.pszText = (LPTSTR) - 1;
3700 sNotify.itemOld.cchTextMax = -1;
3701 sNotify.ptDrag.x = 0;
3702 sNotify.ptDrag.y = 0;
3703
3704
3705 UNLOCK(pData);
3706
3707 if(SendNotify(pData, &sNotify.hdr)) { // Abfragen ob der Eintrag gewählt werden darf
3708 LOCK(pData);
3709 return 0;
3710 }
3711
3712 LOCK(pData);
3713
3714 if(uItem) { // Prüfen ob der Eintrag noch existiert
3715 pEntry = pData->pTreeItems[uItem];
3716 if(!pEntry)
3717 return 0;
3718 }
3719
3720 if(iDel) {
3721 uOld = pData->uSelectedItem;
3722 pTemp = pData->pTreeItems[uOld];
3723 }
3724
3725
3726 if(pTemp) { // Den alten Eintrag abwählen
3727 if(pTemp->uShowPos) { // Den Eintrag neu zeichnen
3728 if((pData->uStyleEx & TVS_EX_FULLROWMARK) || pData->uSelectedSub)
3729 UpdateRow(pData, uOld);
3730 else
3731 UpdateRect(pData, uOld, uSub);
3732 }
3733
3734 if(pTemp->uState & TVIS_SELECTED) {
3735 uStOld &= ~TVIS_SELECTED;
3736 pTemp->uState &= ~TVIS_SELECTED;
3737
3738 if(pData->uSelectedCount > 0) {
3739 pData->uSelectedCount -= 1;
3740 }
3741 }
3742
3743 pData->uSelectedSub = 0;
3744 pData->uSelectedItem = 0;
3745 } else {
3746 uOld = 0;
3747 }
3748
3749
3750 if(uItem) { // Den neuen Eintrag wählen
3751 if(iSel) {
3752 if(pEntry->uState & TVIS_SELECTED) {
3753 uState &= ~TVIS_SELECTED;
3754 pEntry->uState &= ~TVIS_SELECTED;
3755 if(pData->uSelectedCount)
3756 pData->uSelectedCount--;
3757 }
3758 } else {
3759 if(!(pEntry->uState & TVIS_SELECTED)) {
3760 uState |= TVIS_SELECTED;
3761 pEntry->uState |= TVIS_SELECTED;
3762 pData->uSelectedCount += 1;
3763 }
3764 }
3765
3766 if(uSubItem && uSubItem < pData->uColumnCount) {
3767 pExtra = pData->pExtraItems[uSubItem - 1][uItem];
3768 if(!pExtra) {
3769 pExtra = new(ExtraItem, 1);
3770 memset(pExtra, 0, sizeof(ExtraItem));
3771 pExtra->iImage = TV_NOIMAGE;
3772 pExtra->uState = pEntry->uState & (TVIS_BOLD | TVIS_UNDERLINE);
3773 pData->pExtraItems[uSubItem - 1][uItem] = pExtra;
3774 }
3775
3776 uState = pExtra->uState;
3777 uState |= pEntry->uState & TVIS_BASEFLAGS;
3778 } else {
3779 uState = pEntry->uState;
3780 }
3781
3782 if(pEntry->uShowPos) { // Den Eintrag neu zeichnen
3783 if(pData->uStyleEx & (TVS_EX_FULLROWMARK | TVS_EX_SUBSELECT))
3784 UpdateRow(pData, uItem);
3785 else
3786 UpdateRect(pData, uItem, uSubItem);
3787 }
3788
3789 pData->uSelectedSub = uSubItem;
3790 pData->uSelectedItem = uItem;
3791 } else {
3792 pData->uSelectedItem = 0;
3793 pData->uSelectedSub = 0;
3794 uState = 0;
3795 }
3796
3797 sNotify.hdr.code = TVN_SELCHANGED;
3798 sNotify.action = iMode;
3799 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3800 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3801 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3802 sNotify.itemNew.state = uState;
3803 sNotify.itemNew.lParam = lParam;
3804 sNotify.itemNew.cChildren = uSubItem;
3805 sNotify.itemNew.pszText = (LPTSTR) - 1;
3806 sNotify.itemNew.cchTextMax = -1;
3807 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | TVIF_PARAM;
3808 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uOld;
3809 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3810 sNotify.itemOld.state = uStOld;
3811 sNotify.itemOld.lParam = lPaOld;
3812 sNotify.itemOld.cChildren = uSub;
3813 sNotify.itemOld.pszText = (LPTSTR) - 1;
3814 sNotify.itemOld.cchTextMax = -1;
3815 sNotify.ptDrag.x = 0;
3816 sNotify.ptDrag.y = 0;
3817
3818 UNLOCK(pData);
3819 SendNotify(pData, &sNotify.hdr);
3820 LOCK(pData);
3821
3822 if(!(pData->uStyle & TVS_SINGLEEXPAND)) { // Einzelmodus aktiv
3823 if(pData->uStyle & TVS_SHOWSELALWAYS)
3824 if(pData->uSelectedItem) {
3825 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
3826 }
3827
3828 return 1;
3829 }
3830
3831
3832 //*****************************************************************************
3833
3834
3835 sNotify.hdr.code = TVN_SINGLEEXPAND;
3836 sNotify.action = iMode;
3837 sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
3838 sNotify.itemNew.hItem = (HTREEITEM)(ULONG_PTR)uItem;
3839 sNotify.itemNew.stateMask = 0xFFFFFFFF;
3840 sNotify.itemNew.state = (pEntry) ? pEntry->uState : 0;
3841 sNotify.itemNew.cChildren = 0;
3842 sNotify.itemNew.pszText = (LPTSTR) - 1;
3843 sNotify.itemNew.cchTextMax = -1;
3844 sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
3845 sNotify.itemOld.hItem = (HTREEITEM)(ULONG_PTR)uOld;
3846 sNotify.itemOld.stateMask = 0xFFFFFFFF;
3847 sNotify.itemOld.state = (pTemp) ? pTemp->uState : 0;
3848 sNotify.itemOld.cChildren = 0;
3849 sNotify.itemOld.pszText = (LPTSTR) - 1;
3850 sNotify.itemOld.cchTextMax = -1;
3851 sNotify.ptDrag.x = 0;
3852 sNotify.ptDrag.y = 0;
3853
3854 UNLOCK(pData);
3855 uRet = U(SendNotify(pData, &sNotify.hdr)); // Anfragen ob die Zweige umgeklappt werden dürfen
3856 LOCK(pData);
3857
3858
3859 pTemp = pData->pTreeItems[uOld ]; // Zeiger neu holen falls es Änderungen gab
3860 pEntry = pData->pTreeItems[uItem];
3861
3862 while(pTemp && pEntry) { // Beide Zweige sysnchronisieren
3863 if(pEntry->uLevel > pTemp->uLevel) {
3864 uNext = pEntry->uParent;
3865
3866 if(!(uRet & TVNRET_SKIPNEW))
3867 if(!(pEntry->uState & TVIS_EXPANDED)) {
3868 TreeListToggleItem(pData, uItem, 0);
3869 }
3870
3871 pEntry = pData->pTreeItems[uNext];
3872 uItem = uNext;
3873
3874 if(!uItem)
3875 break;
3876
3877 continue;
3878 }
3879
3880 if(uItem == uOld)
3881 goto EndSel; // Bis zum gleichen Knoten
3882
3883 uNext = pTemp->uParent;
3884
3885 if(!(uRet & TVNRET_SKIPOLD))
3886 if(pTemp->uState & TVIS_EXPANDED) {
3887 TreeListToggleItem(pData, uOld, 0);
3888 }
3889
3890 pTemp = pData->pTreeItems[uNext];
3891 uOld = uNext;
3892 }
3893
3894 if(!uItem) {
3895 if(!(uRet & TVNRET_SKIPOLD))
3896 while(pTemp) { // Alten Zweig zuklappen
3897 uNext = pTemp->uParent;
3898
3899 if(pTemp->uState & TVIS_EXPANDED) {
3900 TreeListToggleItem(pData, uOld, 0);
3901 }
3902
3903 pTemp = pData->pTreeItems[uNext];
3904 uOld = uNext;
3905 }
3906
3907 goto EndSel;
3908 }
3909
3910 if(!uOld) {
3911 if(!(uRet & TVNRET_SKIPNEW))
3912 while(pEntry) { // Neuen Zweig aufklappen
3913 uNext = pEntry->uParent;
3914
3915 if(!(pEntry->uState & TVIS_EXPANDED)) {
3916 TreeListToggleItem(pData, uItem, 0);
3917 }
3918
3919 pEntry = pData->pTreeItems[uNext];
3920 uItem = uNext;
3921 }
3922 }
3923
3924EndSel:
3925
3926 if(pData->uStyle & TVS_SHOWSELALWAYS)
3927 if(pData->uSelectedItem) {
3928 TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
3929 }
3930
3931 return 2;
3932}
3933
3934//*****************************************************************************
3935//*
3936//* TreeListSelectChilds
3937//*
3938//*****************************************************************************
3939// Wählt einen Eintrag aus
3940// pData : Zeiger auf die Fensterdaten
3941// uItem : Ist die Nummer des Eintrages der ausgewählt werden soll
3942// iMode : Bit 0 = Untereintäge auch ändern
3943// Bit 1 = Einträge abwählen
3944// Ergibt 1 wenn die Auswahl funktioniert hat, bzw. 0 bei einem Fehler
3945static int TreeListSelectChilds(TreeListData *pData, unsigned uItem, int iMode) {
3946
3948 unsigned uLevel;
3949 unsigned uXor;
3950
3951 if(!(pData->uStyleEx & TVS_EX_MULTISELECT))
3952 return 0;
3953
3954 uLevel = 0;
3955
3956 if(uItem == U(TVI_ROOT)) {
3957 uItem = pData->uFirstChild;
3958 } else {
3959 if(uItem > pData->uTreeItemsMax)
3960 return 0;
3961 }
3962
3963 if(!pData->pTreeItems[uItem]) {
3964 return 0;
3965 }
3966
3967
3968 uXor = (iMode & TVIS_DESELECT) ? 0 : TVIS_SELECTED;
3970
3971 for(;;) {
3972 pEntry = pData->pTreeItems[uItem];
3973
3974 if((pEntry->uState ^ uXor)&TVIS_SELECTED) {
3976 }
3977
3978 if(iMode && pEntry->uFirstChild) { // Auch Kinder ändern
3979 uItem = pEntry->uFirstChild;
3980 uLevel++;
3981 continue;
3982 }
3983
3984 for(;;) { // Eine Ebene höher
3985 uItem = pEntry->uNextItem;
3986 if(uItem != 0)
3987 break;
3988 if(uLevel == 0)
3989 return 1;
3990
3991 uLevel--;
3992
3993 uItem = pEntry->uParent;
3994 pEntry = pData->pTreeItems[uItem];
3995 }
3996 }
3997}
3998
3999//*****************************************************************************
4000//*
4001//* TreeListInsertItem
4002//*
4003//*****************************************************************************
4004// Fügt einen Eintrag ins Fenster ein
4005// pData : Zeiger auf die Fensterdaten
4006// pInsert : Zeiger auf die ein zu fügenden Daten
4007// Ergibt die Einfügeposition des neuen Eintrages oder 0 bei einem Fehler
4009
4010 char *pTemp;
4011 BYTE bFlag;
4012 LPCTSTR pText;
4013 LPCTSTR pTextTemp;
4014 PFNTVSORTEX pCompare;
4015 ExtraItem **pExOld[MAX_COLUMNS];
4016 ExtraItem **pExNew[MAX_COLUMNS];
4017 BaseItem *pNew;
4018 BaseItem **pOld;
4019 BaseItem **pItems;
4022 unsigned *pPosNew;
4023 unsigned *pPosOld;
4024 unsigned *pFirst;
4025 unsigned *pLast;
4026 unsigned uBefore;
4027 unsigned uParent;
4028 unsigned uAfter;
4029 unsigned uFirst;
4030 unsigned uSize;
4031 unsigned uBits;
4032 unsigned uItem;
4033 unsigned uNext;
4034 unsigned uMax;
4035 unsigned uPos;
4036 unsigned uNum;
4037 int iCmp;
4038 int iNone;
4039 int iCount;
4040 int iShift;
4041
4042 if(pData->cLockChanges)
4043 return 0;
4044
4045 uParent = U(pInsert->hParent);
4046 if(uParent > pData->uTreeItemsMax) { // Prüfe das Elternelement
4047 if(pInsert->hParent != TVI_ROOT) {
4048 return 0;
4049 }
4050
4051 pParent = NULL;
4052 } else {
4053 pParent = pData->pTreeItems[uParent];
4054 if(!pParent) {
4055 if(uParent)
4056 return 0;
4057 pParent = NULL;
4058 }
4059 }
4060
4061 if(pData->uTreeItemsCount + 1 > pData->uTreeItemsMax) { // Größe der Liste erhöhen
4062 pPosOld = pData->pItemPos;
4063 pOld = pData->pTreeItems;
4064 uMax = pData->uTreeItemsMax;
4065 uMax += pData->uTreeItemsMax / 2;
4066 uMax += 64;
4067 pItems = new(BaseItem*, uMax + 1);
4068
4069 if(!pItems) {
4070 return 0;
4071 }
4072
4073 pPosNew = new(unsigned, uMax);
4074 if(!pPosNew) {
4075 delete(pItems);
4076 return 0;
4077 }
4078
4079 for(uPos = 1; uPos < pData->uColumnCount; uPos++) {
4080 pExOld[uPos] = pData->pExtraItems[uPos - 1];
4081 pExNew[uPos] = new(ExtraItem*, uMax + 1);
4082
4083 if(!pExNew[uPos]) {
4084 for(uPos--; uPos > 0; uPos--)
4085 delete(pExNew[uPos]);
4086 delete(pPosNew);
4087 delete(pItems);
4088 return 0;
4089 }
4090 }
4091
4092 memcpy(pItems , pData->pTreeItems , sizeof(BaseItem *) * (pData->uTreeItemsMax + 1));
4093 memset(pItems + pData->uTreeItemsMax + 1, 0, sizeof(BaseItem *) * (uMax - pData->uTreeItemsMax));
4094 memcpy(pPosNew, pData->pItemPos , sizeof(unsigned) * (pData->uTreeItemsCount));
4095 memset(pPosNew + pData->uTreeItemsCount, 0, sizeof(unsigned) * (uMax - pData->uTreeItemsCount));
4096
4097 for(uPos = 1; uPos < pData->uColumnCount; uPos++) {
4098 memcpy(pExNew[uPos], pExOld[uPos] , sizeof(ExtraItem *) * (pData->uTreeItemsMax + 1));
4099 memset(pExNew[uPos] + pData->uTreeItemsMax + 1, 0, sizeof(ExtraItem *) * (uMax - pData->uTreeItemsMax));
4100 pData->pExtraItems[uPos - 1] = pExNew[uPos];
4101 delete(pExOld[uPos]);
4102 }
4103
4104 pData->uTreeItemsMax = uMax;
4105 pData->pTreeItems = pItems;
4106 pData->pItemPos = pPosNew;
4107 delete(pPosOld);
4108 delete(pOld);
4109 }
4110
4111 //******************** Den neuen Eintrag erzeugen *****************************
4112 pItems = pData->pTreeItems;
4113 uPos = pData->uNextSeachPos + 1;
4114 pTemp = new(char, sizeof(BaseItem) + pData->uUserDataSize);
4115 pNew = (BaseItem *)pTemp;
4116
4117 if(!pNew) { // Konnte der Speicher reserviert werden
4118 return 0;
4119 }
4120
4121 if(pData->uUserDataSize) { // Die Userdaten auf 0 setzen
4122 memset(pTemp + sizeof(BaseItem), 0, pData->uUserDataSize);
4123 }
4124
4125 for(;; uPos++) { // Suche freie Position
4126 if(uPos > pData->uTreeItemsMax)
4127 uPos = 1;
4128 if(pItems[uPos] == NULL)
4129 break;
4130 }
4131
4132 pData->uNextSeachPos = uPos;
4133
4134 memset(pNew, 0, sizeof(BaseItem)); // Erstelle den neuen Eintrag
4135 pNew->iImage = TV_NOIMAGE;
4136 pNew->iSelectedImage = TV_NOIMAGE;
4137
4138 uBits = pInsert->item.mask;
4139
4140 if(uBits & TVIF_STATE) {
4141 pNew->uState = pInsert->item.state & pInsert->item.stateMask;
4142 } else {
4143 if(pData->uStyle & TVS_CHECKBOXES)
4144 if(!(pData->uStyleEx & TVS_EX_BITCHECKBOX)) {
4145 pNew->uState = 0x1000;
4146 }
4147 }
4148
4149 if(uBits & TVIF_PARAM) {
4150 pNew->lParam = pInsert->item.lParam;
4151 }
4152
4153 if(uBits & TVIF_IMAGE) {
4154 pNew->iImage = pInsert->item.iImage;
4155 if(pNew->iImage == I_IMAGECALLBACK)
4156 pNew->bCallback |= TVIF_IMAGE;
4157 }
4158
4159 if(uBits & TVIF_SELECTEDIMAGE) {
4160 pNew->iSelectedImage = pInsert->item.iSelectedImage;
4161 if(pNew->iSelectedImage == I_IMAGECALLBACK)
4163 }
4164
4165 if(uBits & TVIF_CHILDREN) { // Art der Schaltflächen
4166 switch(pInsert->item.cChildren) {
4167 case 0:
4168 break;
4169 case 1:
4170 pNew->bFlags |= TVIX_HASBUTTON;
4171 break;
4172 case I_CCB:
4173 pNew->bCallback |= TVIF_CHILDREN;
4174 break;
4175 default
4176 :
4177 pNew->bFlags |= TVIX_VARBUTTON;
4178 break;
4179 }
4180 } else {
4181 pNew->bFlags |= TVIX_VARBUTTON;
4182 }
4183
4184 if(pData->uStyle & TVS_SINGLEEXPAND) { // Nicht aufklappen bei Einzelmodus
4185 pNew->uState &= ~TVIS_EXPANDED;
4186 }
4187
4188 if(uBits & TVIF_TEXT) { // Text einfügen
4189 if(pInsert->item.pszText == LPSTR_TEXTCALLBACK) {
4190 pNew->bCallback |= TVIF_TEXT;
4191 pNew->uTextSize = 0;
4192 pNew->pText = 0;
4193 } else {
4194 pNew->uTextSize = (WORD)str_len(pInsert->item.pszText);
4195 pNew->pText = new(TCHAR, pNew->uTextSize + 1);
4196 memcpy(pNew->pText, pInsert->item.pszText, sizeof(TCHAR) * (pNew->uTextSize + 1));
4197 }
4198 } else {
4199 pNew->pText = new(TCHAR, 1);
4200 pNew->pText[0] = 0;
4201 pNew->uTextSize = 0;
4202 }
4203
4204 if(!pParent) { // Einen Root-Eintrag einfügen
4205 pNew->uParent = 0;
4206 uParent = 0;
4207 bFlag = 0;
4208 uFirst = 0xFFFFFFFF;
4209 pFirst = &pData->uFirstChild;
4210 pLast = &pData->uLastChild;
4211 } else { // Einen Tree-Eintrag einfügen
4212 pNew->uParent = uParent;
4213 pNew->uLevel = pParent->uLevel + 1;
4214 uFirst = pParent->uFirstChild;
4215 pFirst = &pParent->uFirstChild;
4216 pLast = &pParent->uLastChild;
4217 bFlag = pParent->bFlags;
4218
4219 if(pParent->bFlags & TVIX_VARBUTTON) {
4220 pParent->bFlags |= TVIX_HASBUTTON;
4221 }
4222 }
4223
4224 //******************** Eintrage einfügen **************************************
4225 uAfter = U(pInsert->hInsertAfter);
4226
4227 switch(uAfter) {
4228 case U(TVI_BEFORE): // Nach einem Eintrag einfügen
4229 if(pParent) { // Einen Root-Eintrag einfügen
4230 pEntry = pParent;
4231 pParent ->bFlags = bFlag;
4232 uParent = pParent->uParent;
4233 pParent = pItems [uParent];
4234
4235 if(!pParent) {
4236 pNew->uParent = 0;
4237 pNew->uLevel = 0;
4238 uParent = 0;
4239 uFirst = 0xFFFFFFFF;
4240 pFirst = &pData->uFirstChild;
4241 pLast = &pData->uLastChild;
4242 } else { // Einen Tree-Eintrag einfügen
4243 pNew->uParent = uParent;
4244 pNew->uLevel = pParent->uLevel + 1;
4245 uFirst = pParent->uFirstChild;
4246 pFirst = &pParent->uFirstChild;
4247 pLast = &pParent->uLastChild;
4248
4249 if(pParent->bFlags & TVIX_VARBUTTON) {
4250 pParent->bFlags |= TVIX_HASBUTTON;
4251 }
4252 }
4253
4254 if(pEntry->uPrevItem) {
4255 uAfter = pEntry->uPrevItem;
4256 goto DoInsert;
4257 }
4258 }
4259
4260 case U(TVI_FIRST): // Am Anfang einfügen
4261 if(pFirst[0]) { // Gibt es schon Einträge
4262 pEntry = pItems[pFirst[0]];
4263 pEntry->uPrevItem = uPos;
4264 } else {
4265 pFirst[0] = uPos;
4266 pLast [0] = uPos;
4267 break;
4268 }
4269
4270 pNew ->uNextItem = pFirst[0]; // Eintrag einfügen
4271 pFirst[0] = uPos;
4272 break;
4273
4274 case U(TVI_ROOT): // Als Root-Eintrag einfügen
4275 pNew->uParent = 0;
4276 uParent = 0;
4277 pFirst = &pData->uFirstChild;
4278 pLast = &pData->uLastChild;
4279
4280 case U(TVI_LAST): // Am Ende einfügen
4281 if(pLast[0]) { // Gibt es schon Einträge
4282 pEntry = pItems[pLast[0]];
4283 pEntry->uNextItem = uPos;
4284 } else {
4285 pFirst[0] = uPos;
4286 pLast [0] = uPos;
4287 break;
4288 }
4289
4290 pNew ->uPrevItem = pLast[0]; // Eintrag einfügen
4291 pLast[0] = uPos;
4292 break;
4293
4294
4295 case U(TVI_SORTEX): // Einfügen mittels Funktion
4296 uItem = pFirst[0];
4297 if(!uItem) { // Gibt es keine Kindeinträge
4298 pFirst[0] = uPos;
4299 pLast [0] = uPos;
4300 break;
4301 }
4302
4303 if(pNew->bCallback & TVIF_TEXT) { // Text über Callback holen
4304 uSize = 1;
4305 LOCK(pData);
4306 CallbackEntry(pData, pNew, uPos, TVIF_TEXT, &iNone, &uSize, &pText);
4307 UNLOCK(pData);
4308 } else {
4309 pText = pNew->pText;
4310 }
4311
4312 pData->cLockChanges = 1;
4313
4314 pCompare = (PFNTVSORTEX)(pInsert->item.hItem);
4315 if(!pCompare)
4316 break;
4317 uNext = uItem;
4318 iCount = 0;
4319 uBefore = 0;
4320
4321 while(uNext) { // Zähle die Einträge
4322 iCount++;
4323 uNext = pItems[uNext]->uNextItem;
4324 }
4325
4326 while(iCount > 0) { // Binary-Seach Algorithnus
4327 iShift = iCount / 2;
4328 uNext = uItem;
4329
4330 while(iShift > 0) {
4331 uNext = pItems[uNext]->uNextItem;
4332 iShift--;
4333 }
4334
4335 pEntry = pItems[uNext];
4336 if(pEntry->bCallback & TVIF_TEXT) { // Text über Callback holen
4337 uSize = 0;
4338 LOCK(pData);
4339 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pTextTemp);
4340 UNLOCK(pData);
4341 } else {
4342 pTextTemp = pEntry->pText;
4343 }
4344
4345 iCmp = pCompare(pData->hWnd, (HTREEITEM)(ULONG_PTR)uNext, pTextTemp, pText, pEntry->lParam, pInsert->item.lParam);
4346 if(iCmp < 0) {
4347 iCount -= (iCount + 1) / 2;
4348 continue;
4349 }
4350
4351 if(iCmp > 0) {
4352 iCount -= iCount / 2 + 1;
4353 uBefore = uNext;
4354 uItem = pItems[uNext]->uNextItem;
4355 continue;
4356 }
4357
4358 uBefore = pEntry->uPrevItem;
4359 uItem = uNext;
4360 break;
4361 }
4362
4363 pData->cLockChanges = 0;
4364
4365 pNew->uNextItem = uItem;
4366 pNew->uPrevItem = uBefore;
4367
4368 if(uBefore) { // Vorherigen Eintrag anpassen
4369 pEntry = pItems[uBefore];
4370 pEntry->uNextItem = uPos;
4371 } else { // Am Anfang einfügen
4372 pFirst[0] = uPos;
4373 }
4374
4375 if(uItem) { // Nächsten Eintrag anpassen
4376 pEntry = pItems[uItem];
4377 pEntry->uPrevItem = uPos;
4378 } else { // Am Ende anhängen
4379 pLast[0] = uPos;
4380 }
4381 break;
4382
4383 case U(TVI_SORT): // Alphapetisch einfügen
4384 uItem = pFirst[0];
4385 if(!uItem) { // Gibt es keine Kindeinträge
4386 pFirst[0] = uPos;
4387 pLast [0] = uPos;
4388 break;
4389 }
4390
4391 if(pNew->bCallback & TVIF_TEXT) { // Text über Callback holen
4392 uSize = 1;
4393 LOCK(pData);
4394 CallbackEntry(pData, pNew, uPos, TVIF_TEXT, &iNone, &uSize, &pText);
4395 UNLOCK(pData);
4396 } else {
4397 pText = pNew->pText;
4398 }
4399
4400 pData->cLockChanges = 1;
4401
4402 uNext = uItem;
4403 iCount = 0;
4404 uBefore = 0;
4405
4406 while(uNext) { // Zähle die Einträge
4407 iCount++;
4408 uNext = pItems[uNext]->uNextItem;
4409 }
4410
4411 while(iCount > 0) { // Binary-Seach Algorithnus
4412 iShift = iCount / 2;
4413 uNext = uItem;
4414
4415 while(iShift > 0) {
4416 uNext = pItems[uNext]->uNextItem;
4417 iShift--;
4418 }
4419
4420
4421 pEntry = pItems[uNext];
4422 if(pEntry->bCallback & TVIF_TEXT) { // Text über Callback holen
4423 uSize = 0;
4424 LOCK(pData);
4425 CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize, &pTextTemp);
4426 UNLOCK(pData);
4427 } else {
4428 pTextTemp = pEntry->pText;
4429 }
4430
4431 iCmp = str_icmp(pText, pTextTemp);
4432
4433 if(iCmp < 0) {
4434 iCount -= (iCount + 1) / 2;
4435 continue;
4436 }
4437
4438 if(iCmp > 0) {
4439 iCount -= iCount / 2 + 1;
4440 uBefore = uNext;
4441 uItem = pItems[uNext]->uNextItem;
4442 continue;
4443 }
4444
4445 uBefore = pEntry->uPrevItem;
4446 uItem = uNext;
4447 break;
4448 }
4449
4450
4451 pData->cLockChanges = 0;
4452
4453 pNew->uNextItem = uItem;
4454 pNew->uPrevItem = uBefore;
4455
4456 if(uBefore) { // Vorherigen Eintrag anpassen
4457 pEntry = pItems[uBefore];
4458 pEntry->uNextItem = uPos;
4459 } else { // Am Anfang einfügen
4460 pFirst[0] = uPos;
4461 }
4462
4463 if(uItem) { // Nächsten Eintrag anpassen
4464 pEntry = pItems[uItem];
4465 pEntry->uPrevItem = uPos;
4466 } else { // Am Ende anhängen
4467 pLast[0] = uPos;
4468 }
4469 break;
4470
4471 case U(TVI_AFTER): // Nach einem Eintrag einfügen
4472 uAfter = uParent;
4473
4474 if(pParent) { // Einen Root-Eintrag einfügen
4475 pParent ->bFlags = bFlag;
4476 uParent = pParent->uParent;
4477 pParent = pItems [uParent];
4478
4479 if(!pParent) {
4480 pNew->uParent = 0;
4481 pNew->uLevel = 0;
4482 uParent = 0;
4483 uFirst = 0xFFFFFFFF;
4484 pFirst = &pData->uFirstChild;
4485 pLast = &pData->uLastChild;
4486 } else { // Einen Tree-Eintrag einfügen
4487 pNew->uParent = uParent;
4488 pNew->uLevel = pParent->uLevel + 1;
4489 uFirst = pParent->uFirstChild;
4490 pFirst = &pParent->uFirstChild;
4491 pLast = &pParent->uLastChild;
4492
4493 if(pParent->bFlags & TVIX_VARBUTTON) {
4494 pParent->bFlags |= TVIX_HASBUTTON;
4495 }
4496 }
4497 }
4498
4499 default
4500 : // Hinter einen Eintrag einfügen
4501DoInsert:
4502 uItem = pFirst[0];
4503 if(!uItem) { // Gibt es keine Kindeinträge
4504 pFirst[0] = uPos;
4505 pLast [0] = uPos;
4506 break;
4507 }
4508
4509 if(uAfter > pData->uTreeItemsMax) {
4510 if((uAfter & 0xFFF00000) == 0xFFE00000) { // In einer genauen Reihe nach Patent einfügen
4511 uAfter &= 0xFFFFF;
4512
4513 uItem = pFirst[0];
4514 if(!uItem) { // Gibt es keine Kindeinträge
4515 pFirst[0] = uPos;
4516 pLast [0] = uPos;
4517 break;
4518 }
4519
4520 if(uAfter == 0) { // In die erste Reihe einfügen
452