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
8 * NOTE: Taken from the TreeList code found at https://github.com/sebkirche/treelist
11 //*****************************************************************************
17 //*****************************************************************************
19 // This code creates a tree window with a list
22 // Copyright (C) Anton Zechner (az_software@inode.at) 2007
23 // Copyright (C) Sébastien Kirche (sebastien.kirche@free.fr) 2014
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.
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.
54 #define new(TYPE, numElems) \
55 HeapAlloc(GetProcessHeap(), 0, (numElems) * sizeof(TYPE))
57 HeapFree(GetProcessHeap(), 0, (ptr))
63 #define GWLP_USERDATA GWL_USERDATA
66 #define GWLP_WNDPROC GWL_WNDPROC
69 #ifndef SetWindowLongPtr
70 #define SetWindowLongPtr SetWindowLong
72 #ifndef GetWindowLongPtr
73 #define GetWindowLongPtr GetWindowLong
76 #define DWORD_PTR DWORD
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
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
96 #define WM_MOUSEWHEEL 0x020A
99 #define WHEEL_DELTA 120
102 #define MAX_COLUMNS 32
104 #define MAX_COLORS 16
105 #define EN_SETTEXT 0x1000
106 #define EN_RETURN 0x1578
107 #define EN_ESCAPE 0x1579
108 #define ID_TOOLTIPCHECK 0x3912
109 #define SORT_NOUPDATE 1234567
110 #define VK_ISACHAR 0x01000000
111 #define FIRST_LINE 0xFFFFFFFE
112 #define FROM_HEADER 0x88776655
113 #define I_CCB I_CHILDRENCALLBACK
114 #define U(h) ((unsigned)(h))
115 #define THEMEIMGLIST ((HIMAGELIST)1)
116 #define GetHandle(h) ((TreeListData*)GetWindowLongPtr(h,0))
117 #define TVIF_ALL (TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT)
118 #define UNLOCK(d) ReleaseSemaphore(d->hSem,1,NULL)
119 #define LOCK(d) WaitForSingleObject(d->hSem,INFINITE)
120 #define TVIS_EDIT(m) ((1<<m)&((1<<TVAX_EDIT)|(1<<TVAX_COMBO)|(1<<TVAX_STEPED)|(1<<TVAX_CHECKED)))
121 #define TVIS_BASEFLAGS (TVIS_EXPANDED|TVIS_EXPANDEDONCE|TVIS_EXPANDPARTIAL|TVIS_SELECTED)
122 #define TVIS_TRACKED (TVIX_TRACKED<<16)
123 #define TVIS_BKCOLOR (TVIX_BKCOLOR<<16)
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
139 #define GLPS_CLOSED 1
142 #define GLPS_OPENED 2
145 #define BP_CHECKBOX 3
147 #ifndef CBS_UNCHECKEDNORMAL
148 #define CBS_UNCHECKEDNORMAL 1
150 #ifndef CBS_CHECKEDNORMAL
151 #define CBS_CHECKEDNORMAL 5
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
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
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
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
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
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
344 typedef HRESULT(WINAPI
*SetWindowThemeT
)(HWND
, LPCWSTR
, LPCWSTR
);
345 typedef HRESULT(WINAPI
*EndBufferedPtT
)(HANDLE
, BOOL
);
346 typedef HANDLE(WINAPI
*BeginBufferedPnT
)(HDC
, RECT
*, DWORD
, LPVOID
, HDC
*);
347 typedef HRESULT(WINAPI
*BufferedPtInitT
)(VOID
);
348 typedef HRESULT(WINAPI
*BufferedPtInitT
)(VOID
);
349 typedef LPVOID (WINAPI
*OpenThemeDataT
)(HWND hwnd
, LPCWSTR pszClassList
);
350 typedef HRESULT(WINAPI
*CloseThemeDataT
)(LPVOID
);
351 typedef HRESULT(WINAPI
*DrawThemeBackgT
)(LPVOID
, HDC
, int, int, const RECT
*, const RECT
*);
352 typedef HRESULT(WINAPI
*GetThemeBackgRcT
)(LPVOID
, HDC
, int, int, LPCRECT
, LPRECT
);
353 typedef BOOL (WINAPI
*IsAppThemedT
)();
354 typedef BOOL (WINAPI
*IsThemeActiveT
)();
356 static HMODULE hUxThemeDll
= NULL
;
357 static SetWindowThemeT pSetWindowTheme
= NULL
;
358 static EndBufferedPtT pEndBufferedPt
= NULL
;
359 static BeginBufferedPnT pBeginBufferedPt
= NULL
;
360 static BufferedPtInitT pBufferedPtInit
= NULL
;
361 static BufferedPtInitT pBufferedPtExit
= NULL
;
362 static OpenThemeDataT pOpenThemeData
= NULL
;
363 static CloseThemeDataT pCloseThemeData
= NULL
;
364 static DrawThemeBackgT pDrawThemeBackg
= NULL
;
365 static GetThemeBackgRcT pGetThemeBackgRc
= NULL
;
366 static IsAppThemedT pIsAppThemed
= NULL
;
367 static IsThemeActiveT pIsThemeActive
= NULL
;
368 static HPEN hPatternPen
= NULL
;
369 static HFONT hDefaultFontN
= NULL
;
370 static HFONT hDefaultFontB
= NULL
;
371 static LONG lWindowCount
= -1;
373 static RECT sToolRect
= { -2, 0, 2, 64};
375 static TCHAR cKeyData
[16];
376 static unsigned uKeyLast
;
377 static unsigned uKeyPos
;
378 static void TreeListDraw(HWND hWnd
, HDC hDc
, RECT
*pRect
);
379 static LRESULT CALLBACK
TreeListProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
380 static int TreeListSelectItem(TreeListData
*pData
, unsigned uItem
, unsigned uSubItem
, int iMode
);
381 static int TreeListGetItemRect(TreeListData
*pData
, unsigned uItem
, unsigned uFlags
, RECT
*pRect
);
382 static int TreeListStartNotifyEdit(TreeListData
*pData
, unsigned uItem
, unsigned uSub
, WPARAM wParam
, LPARAM lParam
);
383 static int TreeListStartAutoEdit(TreeListData
*pData
, unsigned uColumn
, WPARAM wParam
, LPARAM lParam
);
384 static int TreeListEndLabelEdit(TreeListData
*pData
, int iMode
);
385 static BOOL bDrawWithTheme
= FALSE
;
387 //*****************************************************************************
391 //*****************************************************************************
392 // Registiert das TreeList Fenster.
393 // Ergibt 1 wenn das Fenster erfolgreich registiert wurde.
394 int TreeListRegister(HINSTANCE hInstance
) {
396 static int iIsRegistered
= FALSE
;
399 OutputDebugString(TEXT("TreeListRegister() - before checking\n"));
404 OutputDebugString(TEXT("TreeListRegister() - before registration\n"));
406 memset(&sClass
, 0, sizeof(sClass
));
407 sClass
.cbSize
= sizeof(sClass
);
408 sClass
.style
= CS_DBLCLKS
| CS_GLOBALCLASS
;
409 sClass
.lpfnWndProc
= TreeListProc
;
410 sClass
.cbClsExtra
= 0;
411 sClass
.cbWndExtra
= sizeof(TreeListData
*);
412 sClass
.hInstance
= hInstance
;
414 sClass
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
415 sClass
.hbrBackground
= NULL
;
416 sClass
.lpszMenuName
= NULL
;
417 sClass
.hIconSm
= NULL
;
418 sClass
.lpszClassName
= _T(TVC_CLASSNAME
);
420 if(!RegisterClassEx(&sClass
))
423 OutputDebugString(TEXT("TreeListRegister() - registration done\n"));
424 iIsRegistered
= TRUE
;
429 BOOL
TreeListUnregister(HINSTANCE hInstance
){
430 return UnregisterClass(_T(TVC_CLASSNAME
),hInstance
);
433 //*****************************************************************************
437 //*****************************************************************************
438 static void GlobalInit() {
445 lCount
= InterlockedIncrement(&lWindowCount
);
449 sLog
.lbColor
= GetSysColor(COLOR_BTNSHADOW
);
450 sLog
.lbStyle
= PS_SOLID
;
452 hPatternPen
= ExtCreatePen(PS_COSMETIC
| PS_ALTERNATE
, 1, &sLog
, 0, NULL
);
455 hPatternPen
= CreatePen(PS_DOT
, 1, RGB(0, 0, 0));
460 hUxThemeDll
= LoadLibrary(_T("UxTheme.dll"));
462 pSetWindowTheme
= (SetWindowThemeT
)GetProcAddress(hUxThemeDll
, "SetWindowTheme");
463 pEndBufferedPt
= (EndBufferedPtT
)GetProcAddress(hUxThemeDll
, "EndBufferedPaint");
464 pBeginBufferedPt
= (BeginBufferedPnT
)GetProcAddress(hUxThemeDll
, "BeginBufferedPaint");
465 pBufferedPtInit
= (BufferedPtInitT
)GetProcAddress(hUxThemeDll
, "BufferedPaintInit");
466 pBufferedPtExit
= (BufferedPtInitT
)GetProcAddress(hUxThemeDll
, "BufferedPaintUnInit");
467 pOpenThemeData
= (OpenThemeDataT
)GetProcAddress(hUxThemeDll
, "OpenThemeData");
468 pCloseThemeData
= (CloseThemeDataT
)GetProcAddress(hUxThemeDll
, "CloseThemeData");
469 pDrawThemeBackg
= (DrawThemeBackgT
)GetProcAddress(hUxThemeDll
, "DrawThemeBackground");
470 pGetThemeBackgRc
= (GetThemeBackgRcT
)GetProcAddress(hUxThemeDll
, "GetThemeBackgroundContentRect");
471 pIsAppThemed
= (IsAppThemedT
)GetProcAddress(hUxThemeDll
, "IsAppThemed");
472 pIsThemeActive
= (IsThemeActiveT
)GetProcAddress(hUxThemeDll
, "IsThemeActive");
474 if(pIsAppThemed
&& pIsThemeActive
)
475 bDrawWithTheme
= pIsAppThemed() && pIsThemeActive();
479 if(pBufferedPtInit
) {
486 //*****************************************************************************
490 //*****************************************************************************
491 static void GlobalDeinit() {
495 lCount
= InterlockedDecrement(&lWindowCount
);
500 DeleteObject(hDefaultFontN
);
501 hDefaultFontN
= NULL
;
505 DeleteObject(hDefaultFontB
);
506 hDefaultFontB
= NULL
;
510 DeleteObject(hPatternPen
);
514 if(pBufferedPtExit
) {
521 //*****************************************************************************
525 //*****************************************************************************
526 // Sendet eine WM_NOTIFY Nachricht and das Elternfenster
527 // pData : Zeiger auf die Fensterdaten
528 // pNotify : Zeiger auf die Notify-Daten
529 // Ergibt den Rückgabewert der WM_NOTIFY Nachrich
530 static LRESULT
SendNotify(TreeListData
*pData
, NMHDR
*pNotify
) {
532 pNotify
->hwndFrom
= pData
->hWnd
;
533 pNotify
->idFrom
= GetWindowLong(pNotify
->hwndFrom
, GWL_ID
);
535 return SendMessage(GetParent(pNotify
->hwndFrom
), WM_NOTIFY
, pNotify
->idFrom
, (LPARAM
)pNotify
);
539 //*****************************************************************************
543 //*****************************************************************************
544 // Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen
545 // pData : Zeiger auf die Fensterdaten
546 // pEntry : Zeiger auf den Eintrag
547 // uItem : Nummer des Eintrages
548 // uFlags : Welche Daten sollen abgefragt werden
549 // Ergibt den Rückgabewert der WM_NOTIFY Nachrich
550 static void CallbackEntry(TreeListData
*pData
, BaseItem
*pEntry
, unsigned uItem
, unsigned uFlags
, int *iImage
, unsigned *uTextSize
, LPCTSTR
*pText
) {
554 sInfo
.item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| uFlags
;
555 sInfo
.item
.lParam
= pEntry
->lParam
;
556 sInfo
.item
.hItem
= (HTREEITEM
)uItem
;
557 sInfo
.item
.state
= pEntry
->uState
;
558 sInfo
.item
.stateMask
= 0xFFFFFFFF;
559 sInfo
.item
.iImage
= I_IMAGECALLBACK
;
560 sInfo
.item
.iSelectedImage
= I_IMAGECALLBACK
;
561 sInfo
.item
.cChildren
= I_CHILDRENCALLBACK
;
563 if(uFlags
& TVIF_TEXT
) {
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;
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;
576 sInfo
.item
.pszText
= 0;
577 sInfo
.item
.cchTextMax
= 0;
580 sInfo
.hdr
.hwndFrom
= pData
->hWnd
;
581 sInfo
.hdr
.idFrom
= GetWindowLong(pData
->hWnd
, GWL_ID
);
582 sInfo
.hdr
.code
= TVN_GETDISPINFO
;
585 SendMessage(GetParent(sInfo
.hdr
.hwndFrom
), WM_NOTIFY
, sInfo
.hdr
.idFrom
, (LPARAM
)&sInfo
);
588 if(uFlags
& TVIF_IMAGE
) {
589 if(!(pEntry
->uState
& TVIS_SELECTED
))
590 *iImage
= sInfo
.item
.iImage
;
592 if(uFlags
& TVIF_SELECTEDIMAGE
) {
593 if(pEntry
->uState
& TVIS_SELECTED
)
594 *iImage
= sInfo
.item
.iSelectedImage
;
597 if(uFlags
& TVIF_CHILDREN
) {
598 switch(sInfo
.item
.cChildren
) {
600 pEntry
->bFlags
&= ~TVIX_HASBUTTON
;
601 pEntry
->bFlags
|= TVIX_VARBUTTON
;
605 pEntry
->bFlags
&= ~TVIX_VARBUTTON
;
606 pEntry
->bFlags
|= TVIX_HASBUTTON
;
611 pEntry
->bFlags
|= TVIX_VARBUTTON
;
613 if(pEntry
->uFirstChild
)
614 pEntry
->bFlags
|= TVIX_HASBUTTON
;
616 pEntry
->bFlags
&= ~TVIX_HASBUTTON
;
620 if(uFlags
& TVIF_TEXT
) {
621 *pText
= sInfo
.item
.pszText
;
622 *uTextSize
= str_len(sInfo
.item
.pszText
);
623 pEntry
->iTextPixels
= 0;
628 //*****************************************************************************
632 //*****************************************************************************
633 // Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen
634 // pData : Zeiger auf die Fensterdaten
635 // pEntry : Zeiger auf den Eintrag
636 // uItem : Nummer des Eintrages
637 // uFlags : Welche Daten sollen abgefragt werden
638 // Ergibt den Rückgabewert der WM_NOTIFY Nachrich
639 static void CallbackExtra(TreeListData
*pData
, BaseItem
*pEntry
, ExtraItem
*pExtra
, unsigned uItem
, unsigned uSub
, unsigned uFlags
, int *iImage
, unsigned *uTextSize
, LPCTSTR
*pText
) {
643 sInfo
.item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| uFlags
;
644 sInfo
.item
.lParam
= pEntry
->lParam
;
645 sInfo
.item
.hItem
= (HTREEITEM
)uItem
;
646 sInfo
.item
.state
= pExtra
->uState
;
647 sInfo
.item
.state
|= (pEntry
->uState
& TVIS_BASEFLAGS
);
648 sInfo
.item
.stateMask
= 0xFFFFFFFF;
649 sInfo
.item
.iImage
= I_IMAGECALLBACK
;
650 sInfo
.item
.iSelectedImage
= I_IMAGECALLBACK
;
651 sInfo
.item
.cChildren
= uSub
;
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;
659 sInfo
.item
.pszText
= 0;
660 sInfo
.item
.cchTextMax
= 0;
663 sInfo
.hdr
.hwndFrom
= pData
->hWnd
;
664 sInfo
.hdr
.idFrom
= GetWindowLong(pData
->hWnd
, GWL_ID
);
665 sInfo
.hdr
.code
= TVN_GETDISPINFO
;
668 SendMessage(GetParent(sInfo
.hdr
.hwndFrom
), WM_NOTIFY
, sInfo
.hdr
.idFrom
, (LPARAM
)&sInfo
);
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
);
681 //*****************************************************************************
685 //*****************************************************************************
686 // Ist die Fensterfunktion für das Edit Fenster
687 static LRESULT CALLBACK
EditProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
703 hParent
= GetParent(hWnd
);
704 iId
= GetWindowLong(hWnd
, GWL_ID
);
708 pData
= GetHandle(hParent
);
709 pProc
= pData
->pProcId3
;
712 hParent
= GetParent(hParent
);
713 pData
= GetHandle(hParent
);
714 pProc
= (WNDPROC
)GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
717 if(uMsg
== WM_KEYDOWN
) {
718 if(wParam
== VK_RETURN
) {
719 SendMessage(hParent
, WM_COMMAND
, MAKELONG(3, EN_RETURN
), (LPARAM
)hWnd
);
723 if(wParam
== VK_ESCAPE
) {
724 SendMessage(hParent
, WM_COMMAND
, MAKELONG(3, EN_ESCAPE
), (LPARAM
)hWnd
);
728 if((pData
->uStyleEx
& TVS_EX_STEPOUT
) && !(GetAsyncKeyState(VK_SHIFT
) & 0x8000)) {
729 switch(wParam
) { // Aus Fenster springen
734 PostMessage(hParent
, WM_COMMAND
, MAKELONG(3, EN_RETURN
), (LPARAM
)hWnd
);
735 PostMessage(hParent
, WM_KEYDOWN
, VK_UP
, 0x00500001);
736 PostMessage(hParent
, WM_KEYUP
, VK_UP
, 0x00500001);
742 PostMessage(hParent
, WM_COMMAND
, MAKELONG(3, EN_RETURN
), (LPARAM
)hWnd
);
743 PostMessage(hParent
, WM_KEYDOWN
, VK_DOWN
, 0x00500001);
744 PostMessage(hParent
, WM_KEYUP
, VK_DOWN
, 0x00500001);
748 if(pData
->uEditMode
&& iId
== 3)
750 SendMessage(hWnd
, EM_GETSEL
, (WPARAM
)&dwStart
, (LPARAM
)&dwStop
);
751 if(dwStart
|| dwStop
)
753 PostMessage(hParent
, WM_COMMAND
, MAKELONG(3, EN_RETURN
), (LPARAM
)hWnd
);
754 PostMessage(hParent
, WM_KEYDOWN
, VK_LEFT
, 0x00500001);
755 PostMessage(hParent
, WM_KEYUP
, VK_LEFT
, 0x00500001);
759 if(pData
->uEditMode
&& iId
== 3)
761 SendMessage(hWnd
, EM_GETSEL
, (WPARAM
)&dwStart
, (LPARAM
)&dwStop
);
762 dwCount
= (DWORD
)SendMessage(hWnd
, EM_LINELENGTH
, 0, 0);
763 if(dwCount
> dwStart
)
768 PostMessage(hParent
, WM_COMMAND
, MAKELONG(3, EN_RETURN
), (LPARAM
)hWnd
);
769 PostMessage(hParent
, WM_KEYDOWN
, VK_RIGHT
, 0x00500001);
770 PostMessage(hParent
, WM_KEYUP
, VK_RIGHT
, 0x00500001);
775 if(wParam
== VK_DOWN
&& pData
->uEditMode
) {
776 if(!SendMessage(hCombo
, CB_GETDROPPEDSTATE
, 0, 0)) {
777 SendMessage(hCombo
, CB_SHOWDROPDOWN
, 1, 0);
782 if(uMsg
== WM_CHAR
) {
783 if(wParam
== VK_RETURN
) {
787 if(wParam
== VK_ESCAPE
) {
791 if(uMsg
== WM_COMMAND
) {
792 if(wParam
== MAKELONG(3, EN_ESCAPE
) || wParam
== MAKELONG(3, EN_RETURN
)) {
793 SendMessage(hParent
, WM_COMMAND
, wParam
, (LPARAM
)hWnd
);
797 if(uMsg
== WM_MOUSEWHEEL
) {
798 iState
= (int)CallWindowProc(pProc
, hWnd
, CB_GETDROPPEDSTATE
, 0, 0);
800 iDelta
= (short)HIWORD(wParam
);
801 iDelta
/= WHEEL_DELTA
;
802 iPos
= (int)CallWindowProc(pProc
, hWnd
, CB_GETTOPINDEX
, 0, 0);
804 CallWindowProc(pProc
, hWnd
, CB_SETTOPINDEX
, iPos
, 0);
808 if(uMsg
== WM_GETDLGCODE
) { // Welche Tasten werden im Dialog benutzt
809 return DLGC_WANTALLKEYS
;
811 if(uMsg
== WM_SETTEXT
) {
812 lResult
= CallWindowProc(pProc
, hWnd
, uMsg
, wParam
, lParam
);;
813 SendMessage(hParent
, WM_COMMAND
, MAKELONG(3, EN_SETTEXT
), (LPARAM
)hWnd
);
817 return CallWindowProc(pProc
, hWnd
, uMsg
, wParam
, lParam
);
820 //*****************************************************************************
824 //*****************************************************************************
825 // Ist die Fensterfunktion für das ToolTip Fenster
826 static LRESULT CALLBACK
ToolProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
832 if(uMsg
== WM_SETFOCUS
) {
833 SetFocus((HWND
)lParam
);
837 pData
= (TreeListData
*)GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
839 if(uMsg
>= WM_MOUSEFIRST
&& uMsg
<= WM_MOUSELAST
) { // Mausklicks auf Tooltip zum Elternfenster
840 sPoint
.x
= LOWORD(lParam
);
841 sPoint
.y
= HIWORD(lParam
);
843 ClientToScreen(hWnd
, &sPoint
);
844 ScreenToClient(pData
->hWnd
, &sPoint
);
846 uPos
= MAKELONG(sPoint
.x
, sPoint
.y
);
848 return TreeListProc(pData
->hWnd
, uMsg
, wParam
, uPos
);
851 return CallWindowProc(pData
->pToolProc
, hWnd
, uMsg
, wParam
, lParam
);
854 //*****************************************************************************
858 //*****************************************************************************
859 // Ändert die Größe der variablen Spalten
860 // pData : Zeiger auf die Fensterdaten
861 // iDelta : Ist die Größenänderung in Pixel
862 static void ChangeColSize(TreeListData
*pData
, int iDelta
) {
881 sItem
.mask
= HDI_WIDTH
;
882 iAll
= pData
->iAllWeight
;
883 iCnt
= pData
->uColumnCountVar
;
885 if(iCnt
<= 1) { // Nur eine variable Spalte
886 for(uPos
= 0; uPos
< pData
->uColumnCount
; uPos
++) {
887 iWeight
= pData
->aColumn
[uPos
].bWeight
;
891 iValue
= pData
->aColumn
[uPos
].sSize
;
895 pData
->aColumn
[uPos
].sSize
= (short)iValue
;
896 pData
->iVarSize
= iValue
;
898 if(sItem
.cxy
< pData
->aColumn
[uPos
].sMin
) {
899 sItem
.cxy
= pData
->aColumn
[uPos
].sMin
;
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
);
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
;
914 SendNotify(pData
, &sNotify
.hdr
);
926 iStart
= (pData
->uSizeX
) % iAll
;
928 iStart
= (pData
->uSizeX
- iDelta
) % iAll
;
932 for(uPos
= 0;; uPos
++) { // Suchen die Anfangsspalte
933 iWeight
= pData
->aColumn
[uPos
].bWeight
;
944 iSize
= iDelta
/ iAll
;
945 iRest
= iDelta
% iAll
;
950 iValue
= pData
->aColumn
[uPos
].sSize
;
951 iValue
+= iSize
* iWeight
;
952 iPoint
+= iRest
* iWeight
;
953 iValue
+= iPoint
/ iAll
;
954 iNum
-= iPoint
/ iAll
;
957 pData
->aColumn
[uPos
].sSize
= (short)iValue
;
960 if(iWeight
>= pData
->aColumn
[uPos
].bWeight
) { // Wurde die ganze Spalte berechnet
968 if(uPos
>= pData
->uColumnCount
)
970 iWeight
= pData
->aColumn
[uPos
].bWeight
;
974 iValue
= pData
->aColumn
[uPos
].sSize
;
978 iValue
+= iSize
* iWeight
;
979 iPoint
+= iRest
* iWeight
;
980 iValue
+= iPoint
/ iAll
;
981 iNum
-= iPoint
/ iAll
;
985 iValue
+= iSize
* iWeight
;
989 pData
->aColumn
[uPos
].sSize
= (short)iValue
;
994 iCnt
= pData
->uColumnCountVar
;
996 for(uPos
= 0; iCnt
> 0; uPos
++) { // Ausgeben der neuen Breiten
997 iWeight
= pData
->aColumn
[uPos
].bWeight
;
999 iFix
+= pData
->aColumn
[uPos
].sSize
;
1003 iVar
+= pData
->aColumn
[uPos
].sSize
;
1004 sItem
.cxy
= pData
->aColumn
[uPos
].sSize
;
1006 if(sItem
.cxy
< pData
->aColumn
[uPos
].sMin
) {
1007 sItem
.cxy
= pData
->aColumn
[uPos
].sMin
;
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
);
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
;
1022 SendNotify(pData
, &sNotify
.hdr
);
1030 pData
->iFixSize
= iFix
;
1031 pData
->iVarSize
= iVar
;
1034 GetClientRect(pData
->hHeader
, &sRect
);
1035 InvalidateRect(pData
->hHeader
, NULL
, FALSE
);
1040 //*****************************************************************************
1044 //*****************************************************************************
1045 // Erzeugt ein ToolTip Fenster
1046 // pData : Zeiger auf die Fensterdaten
1047 static void CreateToolTip(TreeListData
*pData
) {
1054 pData
->hToolTip
= CreateWindow(TOOLTIPS_CLASS
, NULL
, WS_POPUP
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, pData
->hWnd
, NULL
, NULL
, NULL
);
1055 pData
->pToolProc
= (WNDPROC
)GetWindowLongPtr(pData
->hToolTip
, GWLP_WNDPROC
);
1057 sInfo
.cbSize
= sizeof(TOOLINFO
);
1058 sInfo
.uFlags
= TTF_ABSOLUTE
| TTF_TRACK
| TTF_IDISHWND
;
1059 sInfo
.hwnd
= pData
->hWnd
;
1061 sInfo
.uId
= (LPARAM
)(pData
->hWnd
);
1062 sInfo
.lpszText
= LPSTR_TEXTCALLBACK
;
1064 GetClientRect(pData
->hWnd
, &sInfo
.rect
);
1065 SendMessage(pData
->hToolTip
, TTM_ADDTOOL
, 0, (LPARAM
)&sInfo
);
1066 SendMessage(pData
->hToolTip
, TTM_SETMAXTIPWIDTH
, 0, 10000);
1067 SetWindowLong(pData
->hToolTip
, GWL_ID
, 2);
1068 SetWindowLongPtr(pData
->hToolTip
, GWLP_USERDATA
, (LPARAM
)pData
);
1069 SetWindowLongPtr(pData
->hToolTip
, GWLP_WNDPROC
, (LPARAM
)ToolProc
);
1072 //*****************************************************************************
1074 //* CreateStateImageList
1076 //*****************************************************************************
1077 // Erzeugt eine Image-Liste mit zwei Checkboxen
1078 // pData : Zeiger auf die Fensterdaten
1079 // iMode : Welche Imageliste soll erzeugt werden (0=hStates 1=hChecks)
1080 static void CreateStateImageList(TreeListData
*pData
, int iMode
) {
1091 if(pOpenThemeData
) { // Über Thema zeichnen
1092 if(!pData
->hThemeBt
) {
1093 pData
->hThemeBt
= pOpenThemeData(pData
->hWnd
, L
"BUTTON");
1096 if(pData
->hThemeBt
) {
1098 if(pData
->hChecks
&& pData
->hChecks
!= THEMEIMGLIST
) {
1099 ImageList_Destroy(pData
->hChecks
);
1102 pData
->hChecks
= THEMEIMGLIST
;
1103 pData
->iChecksXsize
= 16;
1104 pData
->iChecksYsize
= 16;
1105 pData
->iChecksMode
= 1;
1107 if(pData
->hStates
&& pData
->hStates
!= THEMEIMGLIST
) {
1108 ImageList_Destroy(pData
->hStates
);
1111 pData
->hStates
= THEMEIMGLIST
;
1112 pData
->iStatesXsize
= 16;
1113 pData
->iStatesYsize
= 16;
1114 pData
->iStatesMode
= 1;
1122 if(pData
->hChecks
&& pData
->hChecks
!= THEMEIMGLIST
)
1125 if(pData
->hStates
&& pData
->hStates
!= THEMEIMGLIST
)
1129 hDcSrc
= GetDC(NULL
);
1130 hDc
= CreateCompatibleDC(NULL
);
1131 hBmp
= CreateCompatibleBitmap(hDcSrc
, 16 * 3, 16);
1133 SelectObject(hDc
, hBmp
);
1134 SelectObject(hDc
, GetStockObject(NULL_PEN
));
1135 SetBkMode(hDc
, OPAQUE
);
1136 SetBkColor(hDc
, GetSysColor(COLOR_WINDOW
));
1137 SelectObject(hDc
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1138 Rectangle(hDc
, -1, -1, 16 * 3 + 2, 16 + 2);
1141 sRect
.bottom
= 8 + 7;
1142 sRect
.left
= 16 * 1 + 8 - 7;
1143 sRect
.right
= 16 * 1 + 8 + 6;
1145 DrawFrameControl(hDc
, &sRect
, DFC_BUTTON
, DFCS_BUTTONCHECK
| DFCS_FLAT
);
1147 sRect
.left
= 16 * 2 + 8 - 7;
1148 sRect
.right
= 16 * 2 + 8 + 6;
1150 DrawFrameControl(hDc
, &sRect
, DFC_BUTTON
, DFCS_BUTTONCHECK
| DFCS_CHECKED
| DFCS_FLAT
);
1152 iBits
= GetDeviceCaps(hDc
, BITSPIXEL
);
1154 sInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1155 sInfo
.bmiHeader
.biWidth
= 16 * 3;
1156 sInfo
.bmiHeader
.biHeight
= 16;
1157 sInfo
.bmiHeader
.biPlanes
= 1;
1158 sInfo
.bmiHeader
.biBitCount
= (WORD
)iBits
;
1159 sInfo
.bmiHeader
.biCompression
= BI_RGB
;
1160 sInfo
.bmiHeader
.biSizeImage
= 0;
1161 sInfo
.bmiHeader
.biXPelsPerMeter
= 0;
1162 sInfo
.bmiHeader
.biYPelsPerMeter
= 0;
1163 sInfo
.bmiHeader
.biClrUsed
= (iBits
> 8) ? 0 : 1 << iBits
;;
1164 sInfo
.bmiHeader
.biClrImportant
= (iBits
> 8) ? 0 : 1 << iBits
;;
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
);
1169 hBmpNew
= CreateCompatibleBitmap(hDc
, 16 * 3, 16);
1171 SetDIBits(hDc
, hBmpNew
, 0, 16, aMem
, &sInfo
, (iBits
> 8) ? DIB_RGB_COLORS
: DIB_PAL_COLORS
);
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;
1179 ImageList_AddMasked(pData
->hStates
, hBmpNew
, GetSysColor(COLOR_HIGHLIGHT
));
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;
1186 ImageList_AddMasked(pData
->hChecks
, hBmpNew
, GetSysColor(COLOR_HIGHLIGHT
));
1189 DeleteObject(hBmpNew
);
1192 ReleaseDC(NULL
, hDcSrc
);
1195 //*****************************************************************************
1199 //*****************************************************************************
1200 // Erzeugt eine Image-Liste mit zwei Checkboxen
1201 // pData : Zeiger auf die Fensterdaten
1202 // uSub : Ist die Spalte für die das Drag-Image erzeugt werden soll
1203 // Ergibt ein Handle mit der Imageliste oder NULL bei einem Fehler
1204 static HIMAGELIST
CreateDragImage(TreeListData
*pData
, unsigned uItem
, unsigned uSub
) {
1225 if(uItem
> pData
->uTreeItemsMax
)
1228 pEntry
= pData
->pTreeItems
[uItem
];
1232 iHeigh
= pData
->iFontHeight
;
1234 if(uSub
) { // Image für Extraeintrag erzeugen
1235 if(uSub
>= pData
->uColumnCount
)
1238 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
1243 iWidth
= pData
->iFontHeight
* 4;
1245 pText
= pExtra
->pText
;
1246 uTSize
= pExtra
->uTextSize
;
1247 iImage
= pExtra
->iImage
;
1248 iWidth
= pExtra
->iTextPixels
;
1250 if(pExtra
->bCallback
& (TVIF_IMAGE
| TVIF_TEXT
)) {
1251 CallbackExtra(pData
, pEntry
, pExtra
, uItem
, uSub
, pExtra
->bCallback
, &iImage
, &uTSize
, &pText
);
1254 } else { // Image für Haupteintrag erzeugen
1255 pText
= pEntry
->pText
;
1256 uTSize
= pEntry
->uTextSize
;
1257 iImage
= pEntry
->iImage
;
1258 iWidth
= pEntry
->iTextPixels
;
1260 if(pEntry
->bCallback
& (TVIF_IMAGE
| TVIF_TEXT
)) {
1261 CallbackEntry(pData
, pEntry
, uItem
, pEntry
->bCallback
, &iImage
, &uTSize
, &pText
);
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;
1280 pMem
= new(BYTE
, iHeigh
* (iWidth
+ 4) * 4 + 1024);
1284 hDcSrc
= GetDC(NULL
);
1285 hDc
= CreateCompatibleDC(NULL
);
1286 hBmp
= CreateCompatibleBitmap(hDcSrc
, iWidth
, iHeigh
);
1288 SelectObject(hDc
, hBmp
);
1289 SelectObject(hDc
, GetStockObject(NULL_PEN
));
1290 SelectObject(hDc
, (pEntry
->uState
& TVIS_BOLD
) ? pData
->hFontB
: pData
->hFontN
);
1291 SetTextColor(hDc
, pData
->uColors
[TVC_TEXT
]);
1292 SetBkColor(hDc
, RGB(123, 77, 91));
1295 sRect
.bottom
= iHeigh
;
1297 sRect
.right
= iWidth
;
1298 iYpos
= (iHeigh
- pData
->iFontHeight
) / 2;
1300 ExtTextOut(hDc
, iAdd
, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sRect
, pText
, uTSize
, NULL
);
1303 SetBkColor(hDc
, GetSysColor(COLOR_WINDOW
));
1304 ImageList_Draw(pData
->hImages
, iImage
, hDc
, 0, 0, ILD_TRANSPARENT
);
1307 iBits
= GetDeviceCaps(hDc
, BITSPIXEL
);
1309 sInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1310 sInfo
.bmiHeader
.biWidth
= iWidth
;
1311 sInfo
.bmiHeader
.biHeight
= iHeigh
;
1312 sInfo
.bmiHeader
.biPlanes
= 1;
1313 sInfo
.bmiHeader
.biBitCount
= (WORD
)iBits
;
1314 sInfo
.bmiHeader
.biCompression
= BI_RGB
;
1315 sInfo
.bmiHeader
.biSizeImage
= 0;
1316 sInfo
.bmiHeader
.biXPelsPerMeter
= 0;
1317 sInfo
.bmiHeader
.biYPelsPerMeter
= 0;
1318 sInfo
.bmiHeader
.biClrUsed
= (iBits
> 8) ? 0 : 1 << iBits
;;
1319 sInfo
.bmiHeader
.biClrImportant
= (iBits
> 8) ? 0 : 1 << iBits
;;
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
);
1324 hBmpNew
= CreateCompatibleBitmap(hDc
, iWidth
, iHeigh
);
1326 SetDIBits(hDc
, hBmpNew
, 0, iHeigh
, pMem
, &sInfo
, (iBits
> 8) ? DIB_RGB_COLORS
: DIB_PAL_COLORS
);
1328 hList
= ImageList_Create(iWidth
, iHeigh
, ILC_COLORDDB
| ILC_MASK
, 1, 0);
1330 ImageList_AddMasked(hList
, hBmpNew
, RGB(123, 77, 91));
1332 DeleteObject(hBmpNew
);
1335 ReleaseDC(NULL
, hDcSrc
);
1343 //*****************************************************************************
1345 //* UpdateColorsList
1347 //*****************************************************************************
1348 // Aktualisiert alle Farben
1349 // pData : Zeiger auf die Fensterdaten
1350 static void UpdateColorsList(TreeListData
*pData
) {
1357 if(!pData
->cColorChanged
[TVC_BK
])
1358 pData
->uColors
[TVC_BK
] = GetSysColor(COLOR_WINDOW
);
1359 if(!pData
->cColorChanged
[TVC_BOX
])
1360 pData
->uColors
[TVC_BOX
] = GetSysColor(COLOR_BTNSHADOW
);
1361 if(!pData
->cColorChanged
[TVC_EVEN
])
1362 pData
->uColors
[TVC_EVEN
] = GetSysColor(COLOR_WINDOW
);
1363 if(!pData
->cColorChanged
[TVC_TEXT
])
1364 pData
->uColors
[TVC_TEXT
] = GetSysColor(COLOR_WINDOWTEXT
);
1365 if(!pData
->cColorChanged
[TVC_LINE
])
1366 pData
->uColors
[TVC_LINE
] = GetSysColor(COLOR_WINDOWTEXT
);
1367 if(!pData
->cColorChanged
[TVC_FRAME
])
1368 pData
->uColors
[TVC_FRAME
] = GetSysColor(COLOR_3DFACE
);
1369 if(!pData
->cColorChanged
[TVC_TRACK
])
1370 pData
->uColors
[TVC_TRACK
] = GetSysColor(COLOR_WINDOWTEXT
) ^ RGB(0, 0, 255);
1371 if(!pData
->cColorChanged
[TVC_INSERT
])
1372 pData
->uColors
[TVC_INSERT
] = GetSysColor(COLOR_INFOBK
);
1373 if(!pData
->cColorChanged
[TVC_ODD
])
1374 pData
->uColors
[TVC_ODD
] = GetSysColor(COLOR_INFOBK
);
1375 if(!pData
->cColorChanged
[TVC_BOXBG
])
1376 pData
->uColors
[TVC_BOXBG
] = GetSysColor(COLOR_WINDOW
);
1377 if(!pData
->cColorChanged
[TVC_COLBK
])
1378 pData
->uColors
[TVC_COLBK
] = GetSysColor(COLOR_WINDOW
);
1379 if(!pData
->cColorChanged
[TVC_COLODD
])
1380 pData
->uColors
[TVC_COLODD
] = GetSysColor(COLOR_BTNSHADOW
);
1381 if(!pData
->cColorChanged
[TVC_COLEVEN
])
1382 pData
->uColors
[TVC_COLEVEN
] = GetSysColor(COLOR_WINDOW
);
1383 if(!pData
->cColorChanged
[TVC_GRAYED
])
1384 pData
->uColors
[TVC_GRAYED
] = GetSysColor(COLOR_SCROLLBAR
);
1387 if(pData
->hTheme
&& !pData
->cColorChanged
[TVC_BOXBG
] && !pData
->cColorChanged
[TVC_BOX
] && !pData
->cColorChanged
[TVC_LINE
]) {
1388 pData
->cGlyphOk
= 1;
1390 pData
->cGlyphOk
= 0;
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;
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
;
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;
1413 pData
->uColors
[TVC_ODD
] = uColOdd
;
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;
1425 pData
->uColors
[TVC_COLBK
] = uColor
;
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;
1437 pData
->uColors
[TVC_COLODD
] = uColor
;
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;
1449 pData
->uColors
[TVC_COLEVEN
] = uColor
;
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;
1462 //*****************************************************************************
1466 //*****************************************************************************
1467 // Checks if the row height has changed
1468 // pData : pointer to the window data
1469 // Returns 1 if changed or 0 else.
1470 static int UpdateHeight(TreeListData
*pData
) {
1475 if(pData
->cFixedHeight
)
1481 if(iHeight
< pData
->iChecksYsize
+ 2)
1482 iHeight
= pData
->iChecksYsize
+ 2;
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
)
1494 if(pData
->uStyle
& TVS_NONEVENHEIGHT
&& (iHeight
& 1))
1496 if(pData
->iRowHeight
== iHeight
)
1499 pData
->iRowHeight
= iHeight
;
1501 if(pData
->uSizeY
> pData
->uStartPixel
) {
1502 pData
->uMaxEnties
= pData
->uSizeY
;
1503 pData
->uMaxEnties
-= pData
->uStartPixel
;
1505 pData
->uMaxEnties
= 0;
1508 pData
->uPageEnties
= pData
->uMaxEnties
;
1509 pData
->uMaxEnties
+= pData
->iRowHeight
- 1;
1510 pData
->uMaxEnties
/= pData
->iRowHeight
;
1511 pData
->uPageEnties
/= pData
->iRowHeight
;
1513 GetClientRect(pData
->hWnd
, &sRect
);
1514 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
1519 //*****************************************************************************
1523 //*****************************************************************************
1524 // Zeichnet einen Eintrag neu
1525 // pData : Zeiger auf die Fensterdaten
1526 // uItem : Ist die Nummer des Eintrages
1527 // uSub : Ist die Spaltennummer
1528 // Ergibt 1 wenn der Eintrag sichtbar war
1529 static int UpdateRect(TreeListData
*pData
, unsigned uItem
, unsigned uSub
) {
1536 pEntry
= pData
->pTreeItems
[uItem
];
1537 if(!pEntry
|| !pEntry
->uShowPos
)
1538 return 0; // Ist der Eintrag aufgeklappt
1540 uPos
= pEntry
->uShowPos
- pData
->uScrollY
- 1;
1541 if(uPos
>= pData
->uMaxEnties
)
1542 return 0; // Eintrag im Fenster sichtbar
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
;
1553 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
1558 //*****************************************************************************
1562 //*****************************************************************************
1563 // Zeichnet einen ganze Spalte neu
1564 // pData : Zeiger auf die Fensterdaten
1565 // uColumn : Die nummer der Spalte
1566 // Ergibt 1 wenn der Eintrag sichtbar war
1567 static int UpdateColRect(TreeListData
*pData
, unsigned uColumn
) {
1572 if(uColumn
>= pData
->uColumnCount
)
1575 sRect
.left
= pData
->aColumnXpos
[uColumn
];
1576 sRect
.left
-= pData
->uScrollX
;
1577 if(sRect
.left
> (int)pData
->uSizeX
)
1580 uNext
= pData
->aColumn
[uColumn
].bNext
;
1582 sRect
.right
= pData
->aColumnXpos
[uNext
];
1583 sRect
.right
-= pData
->uScrollX
;
1588 sRect
.bottom
= pData
->uSizeY
;
1590 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
1595 //*****************************************************************************
1599 //*****************************************************************************
1600 // Zeichnet einen Eintrag über die ganze Zeile neu
1601 // pData : Zeiger auf die Fensterdaten
1602 // uItem : Ist die Nummer des Eintrages
1603 // Ergibt 1 wenn der Eintrag sichtbar war
1604 static int UpdateRow(TreeListData
*pData
, unsigned uItem
) {
1610 pEntry
= pData
->pTreeItems
[uItem
];
1611 if(!pEntry
|| !pEntry
->uShowPos
)
1612 return 0; // Ist der Eintrag aufgeklappt
1614 uPos
= pEntry
->uShowPos
- pData
->uScrollY
- 1;
1615 if(uPos
>= pData
->uMaxEnties
)
1616 return 0; // Eintrag im Fenster sichtbar
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
);
1628 //*****************************************************************************
1632 //*****************************************************************************
1633 // Redraw the whole window
1634 // pData : Zeiger auf die Fensterdaten
1635 // Ergibt 1 wenn der Eintrag sichtbar war
1636 static void UpdateView(TreeListData
*pData
) {
1640 GetClientRect(pData
->hWnd
, &sRect
);
1641 sRect
.top
= pData
->uStartPixel
;
1642 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
1644 if(pData
->hHeader
&& ((pData
->uStyleEx
& TVS_EX_HIDEHEADERS
) == 0)){
1645 GetClientRect(pData
->hHeader
, &sRect
);
1646 InvalidateRect(pData
->hHeader
, &sRect
, FALSE
);
1650 //*****************************************************************************
1654 //*****************************************************************************
1655 // Aktualisiert die X-Scroolbar
1656 // pData : Zeiger auf die Fensterdaten
1657 // Ergibt 1 wenn der sich Einstellungen verändert haben
1658 static void UpdateScrollX(TreeListData
*pData
) {
1664 uCols
= pData
->uColumnCount
;
1666 uSize
= pData
->aColumnXpos
[uCols
] - 1;
1668 uSize
= pData
->iMaxSizeX
- 1;
1671 if(pData
->uOldXCount
== uSize
)
1672 if(pData
->uOldXPage
== pData
->uSizeX
) {
1676 pData
->uOldXPage
= pData
->uSizeX
;
1677 pData
->uOldXCount
= uSize
;
1681 sInfo
.cbSize
= sizeof(SCROLLINFO
);
1682 sInfo
.fMask
= SIF_ALL
;
1685 sInfo
.nPage
= pData
->uSizeX
;
1686 sInfo
.nPos
= pData
->uScrollX
;
1687 sInfo
.nTrackPos
= 0;
1689 if(pData
->uStyle
& TVS_NOSCROLL
) {
1692 if(pData
->uStyleEx
& TVS_EX_AUTOHSCROLL
) {
1695 if(sInfo
.nMax
> 0) {
1700 if((int)sInfo
.nPage
>= sInfo
.nMax
&& pData
->uScrollX
> 0) {
1702 pData
->uScrollX
= 0;
1706 if(pData
->hHeader
) {
1707 MoveWindow(pData
->hHeader
, 0, 0, pData
->uSizeX
, pData
->uStartPixel
, TRUE
);
1711 SetScrollInfo(pData
->hWnd
, SB_HORZ
, &sInfo
, TRUE
);
1716 //*****************************************************************************
1720 //*****************************************************************************
1721 // Aktualisiert die Y-Scroolbar
1722 // pData : Zeiger auf die Fensterdaten
1723 // Ergibt 1 wenn der sich Einstellungen verändert haben
1724 static void UpdateScrollY(TreeListData
*pData
) {
1728 if(pData
->uOldYCount
== pData
->uItemPosCount
)
1729 if(pData
->uOldYPage
== pData
->uPageEnties
) {
1733 pData
->uOldYPage
= pData
->uPageEnties
;
1734 pData
->uOldYCount
= pData
->uItemPosCount
;
1738 sInfo
.cbSize
= sizeof(SCROLLINFO
);
1739 sInfo
.fMask
= SIF_ALL
;
1741 sInfo
.nMax
= pData
->uItemPosCount
;
1742 sInfo
.nPage
= pData
->uPageEnties
;
1743 sInfo
.nPos
= pData
->uScrollY
;
1744 sInfo
.nTrackPos
= 0;
1746 if(pData
->uStyle
& TVS_NOSCROLL
) {
1750 if((int)sInfo
.nPage
>= sInfo
.nMax
&& pData
->uScrollY
> 0) {
1752 pData
->uScrollY
= 0;
1757 SetScrollInfo(pData
->hWnd
, SB_VERT
, &sInfo
, TRUE
);
1762 //*****************************************************************************
1766 //*****************************************************************************
1767 // Aktualisiert den Text für das Tootip
1768 // pData : Zeiger auf Fensterdaten
1769 // uItem : Item auf den der Mauszeiger zeigt
1770 // uFlags : Flags vom HitTest
1771 static void UpdateToolTip(TreeListData
*pData
, unsigned uItem
, unsigned uFlags
) {
1773 TCHAR cTemp
[INFOTIPSIZE
];
1777 NMTVGETINFOTIP sToolNv
;
1789 // Tooltip ausbelnden
1790 if(!uItem
|| (uItem
== pData
->uEditItem
&& TVHT_SUBTOCOL(uFlags
) == pData
->uEditSub
)) {
1791 if(pData
->uToolTipItem
)
1796 pEntry
= pData
->pTreeItems
[uItem
];
1798 if(uFlags
& TVHT_ONITEM
) {
1799 if(pData
->uToolTipItem
!= uItem
|| pData
->uToolTipSub
!= 0) {
1800 if(!pData
->pTreeItems
[uItem
]) { // Existiert der Eintag noch ?
1804 TreeListGetItemRect(pData
, uItem
, TVIR_GETCOLUMN
| TVIR_TEXT
, &sRect
);
1806 if(sRect
.right
> (int)pData
->uSizeX
) {
1807 sRect
.right
= pData
->uSizeX
;
1812 if(pData
->uStyleEx
& TVS_EX_TOOLTIPNOTIFY
) { // Tooltip-Daten via speziellem Notify holen
1813 sNotify
.hdr
.code
= TVN_ITEMTOOLTIP
;
1815 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
;
1816 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
1817 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
1818 sNotify
.itemNew
.state
= pEntry
->uState
;
1819 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
1820 sNotify
.itemNew
.pszText
= pEntry
->pText
;
1821 sNotify
.itemNew
.cchTextMax
= pEntry
->uTextSize
;
1822 sNotify
.itemNew
.cChildren
= 0;
1823 sNotify
.itemOld
.mask
= 0;
1824 sNotify
.ptDrag
.x
= sRect
.left
;
1825 sNotify
.ptDrag
.y
= sRect
.top
;
1828 lRet
= SendNotify(pData
, &sNotify
.hdr
);
1834 if(pData
->uStyle
& TVS_INFOTIP
) { // Tooltip-Daten via normalem Notify holen
1835 sToolNv
.hdr
.code
= TVN_GETINFOTIP
;
1836 sToolNv
.cchTextMax
= INFOTIPSIZE
;
1837 sToolNv
.hItem
= (HTREEITEM
)uItem
;
1838 sToolNv
.lParam
= pEntry
->lParam
;
1839 sToolNv
.pszText
= cTemp
;
1841 str_ncpy(cTemp
, pEntry
->pText
, INFOTIPSIZE
);
1842 cTemp
[INFOTIPSIZE
- 1] = 0;
1845 lRet
= SendNotify(pData
, &sNotify
.hdr
);
1848 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
;
1849 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
1850 sNotify
.itemNew
.pszText
= sToolNv
.pszText
;
1851 sNotify
.itemNew
.cchTextMax
= str_len(sToolNv
.pszText
);
1852 sNotify
.itemNew
.cChildren
= 0;
1853 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
1854 sNotify
.itemNew
.state
= pEntry
->uState
;
1855 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
1856 sNotify
.ptDrag
.x
= sRect
.left
;
1857 sNotify
.ptDrag
.y
= sRect
.top
;
1861 // Passt der Text in die Spalte
1862 if(sRect
.right
- sRect
.left
<= pEntry
->iTextPixels
+ 4) {
1863 pText
= pEntry
->pText
;
1864 uSize
= pEntry
->uTextSize
;
1866 if(pEntry
->bCallback
& TVIF_TEXT
) {
1867 CallbackEntry(pData
, pEntry
, uItem
, TVIF_TEXT
, &iTemp
, &uSize
, &pText
);
1870 if(!pText
|| *pText
== 0)
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);
1880 memcpy(pData
->pToolTipText
, pText
, uLen
* sizeof(TCHAR
));
1881 pData
->hFontT
= (pEntry
->uState
& TVIS_BOLD
) ? pData
->hFontB
: pData
->hFontN
;
1884 hToolTip
= pData
->hToolTip
;
1886 pData
->sToolTipPos
.x
= sRect
.left
;
1887 pData
->sToolTipPos
.y
= sRect
.top
;
1889 ClientToScreen(pData
->hWnd
, &pData
->sToolTipPos
);
1893 sInfo
.cbSize
= sizeof(sInfo
);
1894 sInfo
.hwnd
= pData
->hWnd
;
1895 sInfo
.uId
= (UINT_PTR
)pData
->hWnd
;
1897 if(pData
->uToolTipItem
) {
1898 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 0, (LPARAM
)&sInfo
);
1899 pData
->uToolTipItem
= 0;
1902 SendMessage(pData
->hToolTip
, TTM_TRACKPOSITION
, 0, MAKELONG(pData
->sToolTipPos
.x
, pData
->sToolTipPos
.y
));
1903 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 1, (LPARAM
)&sInfo
);
1907 pData
->uToolTipItem
= uItem
;
1908 pData
->uToolTipShow
= 0;
1909 pData
->uToolTipSub
= 0;
1911 SetTimer(pData
->hWnd
, ID_TOOLTIPCHECK
, 1500, NULL
);
1913 if(pData
->uToolTipItem
)
1921 if(uFlags
& (TVHT_ONSUBICON
| TVHT_ONSUBLABEL
)) {
1922 if(pData
->uToolTipItem
!= uItem
|| TVHT_SUBTOCOL(uFlags
) != pData
->uToolTipSub
) {
1924 uCol
= TVHT_SUBTOCOL(uFlags
);
1925 pExtra
= pData
->pExtraItems
[uCol
- 1][uItem
];
1927 if(pData
->uStyleEx
& TVS_EX_TOOLTIPNOTIFY
) { // Tooltip-Daten via Notify holen
1928 TreeListGetItemRect(pData
, uItem
, TVIR_GETCOLUMN
| TVIR_TEXT
| TVIR_COLTOSUB(uCol
), &sRect
);
1930 if(sRect
.right
> (int)pData
->uSizeX
) {
1931 sRect
.right
= pData
->uSizeX
;
1935 sNotify
.itemNew
.state
= pExtra
->uState
;
1936 sNotify
.itemNew
.pszText
= pExtra
->pText
;
1937 sNotify
.itemNew
.cchTextMax
= pExtra
->uTextSize
;
1939 sNotify
.itemNew
.state
= 0;
1940 sNotify
.itemNew
.cchTextMax
= 0;
1941 sNotify
.itemNew
.pszText
= _T("");
1944 sNotify
.hdr
.code
= TVN_ITEMTOOLTIP
;
1946 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
1947 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
;
1948 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
1949 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
1950 sNotify
.itemNew
.cChildren
= uCol
;
1951 sNotify
.itemOld
.mask
= 0;
1952 sNotify
.ptDrag
.x
= sRect
.left
;
1953 sNotify
.ptDrag
.y
= sRect
.top
;
1956 lRet
= SendNotify(pData
, &sNotify
.hdr
);
1963 if(pExtra
) { // Tooltip auf Unterspalte ?
1964 TreeListGetItemRect(pData
, uItem
, TVIR_GETCOLUMN
| TVIR_TEXT
| TVIR_COLTOSUB(uCol
), &sRect
);
1966 if(sRect
.right
> (int)pData
->uSizeX
) {
1967 sRect
.right
= pData
->uSizeX
;
1970 if(sRect
.right
- sRect
.left
<= pExtra
->iTextPixels
+ 4) {
1971 pText
= pExtra
->pText
;
1972 uSize
= pExtra
->uTextSize
;
1974 if(pExtra
->bCallback
& TVIF_TEXT
) {
1975 CallbackExtra(pData
, pEntry
, pExtra
, uItem
, uCol
, TVIF_TEXT
, &iTemp
, &uSize
, &pText
);
1978 if(!pText
|| *pText
== 0)
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);
1988 memcpy(pData
->pToolTipText
, pText
, uLen
* sizeof(TCHAR
));
1989 pData
->hFontT
= (pExtra
->uState
& TVIS_BOLD
) ? pData
->hFontB
: pData
->hFontN
;
1991 pData
->sToolTipPos
.x
= sRect
.left
;
1992 pData
->sToolTipPos
.y
= sRect
.top
;
1994 hToolTip
= pData
->hToolTip
;
1997 ClientToScreen(pData
->hWnd
, &pData
->sToolTipPos
);
2001 sInfo
.cbSize
= sizeof(sInfo
);
2002 sInfo
.hwnd
= pData
->hWnd
;
2003 sInfo
.uId
= (UINT_PTR
)pData
->hWnd
;
2005 if(pData
->uToolTipItem
) {
2006 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 0, (LPARAM
)&sInfo
);
2007 pData
->uToolTipItem
= 0;
2010 SendMessage(pData
->hToolTip
, TTM_TRACKPOSITION
, 0, MAKELONG(pData
->sToolTipPos
.x
, pData
->sToolTipPos
.y
));
2011 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 1, (LPARAM
)&sInfo
);
2015 pData
->uToolTipItem
= uItem
;
2016 pData
->uToolTipSub
= uCol
;
2017 pData
->uToolTipShow
= 0;
2019 SetTimer(pData
->hWnd
, ID_TOOLTIPCHECK
, 1500, NULL
);
2021 if(pData
->uToolTipItem
)
2025 if(pData
->uToolTipItem
)
2035 if(pData
->uToolTipItem
) { // Tooltip ausblenden
2038 sInfo
.cbSize
= sizeof(sInfo
);
2039 sInfo
.hwnd
= pData
->hWnd
;
2040 sInfo
.uId
= (UINT_PTR
)pData
->hWnd
;
2042 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 0, (LPARAM
)&sInfo
);
2046 pData
->uToolTipItem
= 0;
2047 pData
->uToolTipSub
= 0;
2048 pData
->uToolTipShow
= 0;
2050 KillTimer(pData
->hWnd
, ID_TOOLTIPCHECK
);
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
;
2062 if(!pText
|| *pText
== 0)
2065 uLen
= str_len(pText
) + 1;
2066 if(uLen
>= pData
->uToolTipSize
) { // Tooltipspeicher vergrößern
2068 delete(pData
->pToolTipText
);
2069 pData
->uToolTipSize
= (uLen
+ 255)&~0xFF;
2070 pData
->pToolTipText
= new(TCHAR
, pData
->uToolTipSize
+ 4);
2073 memcpy(pData
->pToolTipText
, pText
, uLen
* sizeof(TCHAR
));
2074 pData
->hFontT
= (pEntry
->uState
& TVIS_BOLD
) ? pData
->hFontB
: pData
->hFontN
;
2076 ClientToScreen(pData
->hWnd
, &sNotify
.ptDrag
);
2077 pData
->sToolTipPos
= sNotify
.ptDrag
;
2079 hToolTip
= pData
->hToolTip
;
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
;
2087 SetTimer(pData
->hWnd
, ID_TOOLTIPCHECK
, 500, NULL
);
2094 sInfo
.cbSize
= sizeof(sInfo
);
2095 sInfo
.hwnd
= pData
->hWnd
;
2096 sInfo
.uId
= (UINT_PTR
)pData
->hWnd
;
2098 if(pData
->uToolTipItem
) { // Tooltip Fenster aktivieren
2099 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 0, (LPARAM
)&sInfo
);
2100 pData
->uToolTipItem
= 0;
2103 SendMessage(pData
->hToolTip
, TTM_TRACKPOSITION
, 0, MAKELONG(sNotify
.ptDrag
.x
, sNotify
.ptDrag
.y
));
2104 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 1, (LPARAM
)&sInfo
);
2108 pData
->uToolTipShow
= 0;
2109 pData
->uToolTipItem
= uItem
;
2110 pData
->uToolTipSub
= sNotify
.itemNew
.cChildren
;
2112 SetTimer(pData
->hWnd
, ID_TOOLTIPCHECK
, 1500, NULL
);
2115 //*****************************************************************************
2119 //*****************************************************************************
2120 // Create the font set (normal, bold, etc...) from the given HFONT
2121 static int CreateFontset(TreeListData
*pData
, HFONT hFont
){
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
);
2134 pData
->hFontB
= hBold
; //store the created bold
2141 //*****************************************************************************
2145 //*****************************************************************************
2146 // Erzeugt einen den fetten Font für das Fenster
2147 // pData : Zeiger auf die Fensterdaten
2148 // iRedraw : Soll das Fenster neugezeichnet werden
2149 // Ergibt 1 wenn der Font verändert wurde
2150 static int UpdateFont(TreeListData
*pData
) {
2157 TEXTMETRIC sMetrics
;
2164 if(!hDefaultFontN
) { // Den Standard-Font erzeugen
2165 SystemParametersInfo(SPI_GETICONTITLELOGFONT
, sizeof(sLog
), &sLog
, 0);
2166 sLog
.lfWeight
= FW_NORMAL
;
2167 hDefaultFontN
= CreateFontIndirect(&sLog
);
2168 sLog
.lfWeight
= FW_BOLD
;
2169 hDefaultFontB
= CreateFontIndirect(&sLog
);
2174 pData
->hFontN
= hDefaultFontN
;
2176 pData
->hFontB
= hDefaultFontB
;
2179 if(pData->hFontN == hDefaultFontN) { // Ist der Standard-Font eingestellt
2180 pData->hFontB = hDefaultFontB;
2182 pData->hFontB = pData->hFontN;
2186 if(pData
->hFontN
!= pData
->hFontL
) {
2187 pData
->hFontL
= pData
->hFontN
;
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
);
2197 pList
= pData
->pTreeItems
;
2198 iPos
= pData
->uTreeItemsMax
;
2200 for(; iPos
>= 0; iPos
--) { // Alle Textbreiten zurücksetzen
2201 pEntry
= pList
[iPos
];
2205 pEntry
->iTextPixels
= 0;
2209 for(uSub
= 1; uSub
< pData
->uColumnCount
; uSub
++) {
2210 iPos
= pData
->uTreeItemsMax
;
2211 pItems
= pData
->pExtraItems
[uSub
- 1];
2213 for(; iPos
>= 0; iPos
--) {
2214 pExtra
= pItems
[iPos
];
2218 pExtra
->iTextPixels
= 0;
2227 // compute Width of "..." text
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
);
2241 //*****************************************************************************
2245 //*****************************************************************************
2246 // Berechnet die Positionen der Zeilen für die sichtbaren Einträge
2247 // pData : Zeiger auf die Fensterdaten
2248 // uItem : Ist der Eintrag ab dem begonnen wird
2249 static void UpdateItems(TreeListData
*pData
, unsigned uItem
) {
2262 uOld
= pData
->uItemPosCount
;
2263 pLines
= pData
->pItemPos
;
2264 pItems
= pData
->pTreeItems
;
2266 if(!uItem
) { // Am Anfang beginnen
2267 uItem
= pData
->uFirstChild
;
2268 if(!uItem
) { // Leere Liste
2272 for(uNum
= 0; uNum
< uOld
; uNum
++) { // Die alten Einträge zurücksetzen
2273 uTemp
= pLines
[uNum
];
2277 pTemp
= pItems
[uTemp
];
2280 pTemp
->uShowPos
= 0;
2283 pData
->uItemPosCount
= 0;
2285 GetClientRect(pData
->hWnd
, &sRect
);
2286 InvalidateRect(pData
->hWnd
, &sRect
, TRUE
);
2288 memset(pLines
, 0, sizeof(unsigned)*uOld
);
2292 for(uNum
= 0; uNum
< uOld
; uNum
++) { // Die alten Einträge zurücksetzen
2293 uTemp
= pLines
[uNum
];
2297 pTemp
= pItems
[uTemp
];
2300 pTemp
->uShowPos
= 0;
2303 pEntry
= pItems
[uItem
];
2304 pEntry
->uShowPos
= 1;
2308 } else { // Bei einem Eintrag beginnen
2309 pEntry
= pItems
[uItem
];
2310 uPos
= pEntry
->uShowPos
;
2316 for(uNum
= uPos
; uNum
< uOld
; uNum
++) { // Die alten Einträge zurücksetzen
2317 uTemp
= pLines
[uNum
];
2321 pTemp
= pItems
[uTemp
];
2324 pTemp
->uShowPos
= 0;
2328 for(;;) { // Die Zeilen neu zuordnen
2329 if(pEntry
->uFirstChild
&& (pEntry
->uState
& TVIS_EXPANDED
)) {
2330 uItem
= pEntry
->uFirstChild
;
2332 if(pEntry
->uNextItem
) {
2333 uItem
= pEntry
->uNextItem
;
2336 uItem
= pEntry
->uParent
;
2340 pEntry
= pItems
[uItem
];
2341 if(pEntry
->uNextItem
) { // Gibt es etwas in der gleichen Ebene
2342 uItem
= pEntry
->uNextItem
;
2351 pEntry
= pItems
[uItem
];
2353 if(pLines
[uPos
] != uItem
) {
2354 pLines
[uPos
] = uItem
;
2361 pEntry
->uShowPos
= uPos
;
2364 pData
->uItemPosCount
= uPos
;
2366 if(uStart
> pData
->uScrollY
) // Neu zu zeichnenten Bereich bestimmen
2367 uStart
-= pData
->uScrollY
;
2371 GetClientRect(pData
->hWnd
, &sRect
);
2373 sRect
.top
= pData
->uStartPixel
+ pData
->iRowHeight
* uStart
;
2375 if(sRect
.top
<= sRect
.bottom
) {
2376 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
2380 UpdateScrollY(pData
);
2383 //*****************************************************************************
2387 //*****************************************************************************
2388 // Prüft ob es Veränderungen in Spaltenbreiten gab
2389 // pData : Zeiger auf die Fensterdaten
2390 // Ergibt die Breite ab der die Spalten verändert wurden oder 0x10000
2391 static int UpdateColumns(TreeListData
*pData
) {
2405 hHeader
= pData
->hHeader
;
2407 pData
->aColumnXpos
[0] = 0;
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
;
2425 if(uSub
== pData
->uColumnCount
)
2426 if(iNow
>= (int)pData
->uSizeX
- 1) {
2430 iNum
= pData
->aColumnXpos
[uSub
];
2441 if(pData
->uSelectedItem
) { // Problem bei ausgewählten leeren Einträgen
2442 uNext
= pData
->aColumn
[pData
->uSelectedSub
].bNext
;
2444 UpdateRect(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
2448 if(pData
->uTrackedItem
) {
2449 uNext
= pData
->aColumn
[pData
->uTrackedSub
].bNext
;
2451 UpdateRect(pData
, pData
->uTrackedItem
, pData
->uTrackedSub
);
2456 pData
->aColumnXpos
[uSub
] = iNow
;
2460 while(uCol
< pData
->uColumnCount
) { // Restliche Spalten berechen
2462 uSub
= pData
->aColumnPos
[uCol
];
2463 iNow
+= pData
->aColumn
[uSub
].sReal
;
2464 uSub
= pData
->aColumn
[uSub
].bNext
;
2467 if(uCol
== pData
->uColumnCount
)
2468 if(iNow
>= (int)pData
->uSizeX
- 1) {
2472 pData
->aColumnXpos
[uSub
] = iNow
;
2475 pData
->aColumnXpos
[pData
->uColumnCount
+ 1] = pData
->uSizeX
+ 1;
2480 //*****************************************************************************
2482 //* TreeListSetOrderArray
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.
2493 static int TreeListSetOrderArray(TreeListData
*pData
, unsigned uItems
, unsigned *pArray
) {
2495 BYTE aFlags
[MAX_COLUMNS
+ 1];
2496 UINT aArray
[MAX_COLUMNS
+ 1];
2502 if(!pArray
) { // Spezialreihenfolge setzen
2503 if(uItems
== FROM_HEADER
) { // Array aus Header holen
2504 if(!Header_GetOrderArray(pData
->hHeader
, pData
->uColumnCount
, aArray
)) {
2508 if(aArray
[0] != 0) {
2512 for(uCol
= pData
->uColumnCount
; uCol
> 0; uCol
++) { // Standartreihenfolge
2514 aArray
[uCol
] = uCol
;
2518 uItems
= pData
->uColumnCount
;
2520 } else { // Prüfe Array
2521 if(pData
->uColumnCount
!= uItems
|| uItems
== 0 || *pArray
) {
2526 memset(aFlags
, 0, sizeof(aFlags
) - 1);
2528 for(uCol
= 0, uDiff
= 0; uCol
< uItems
; uCol
++) { // Die Einträge prüfen
2529 uSub
= pArray
[uCol
];
2535 aFlags
[uSub
] = (BYTE
)uCol
;
2537 uDiff
|= uCol
^ pData
->aColumnPos
[uSub
];
2540 if(uDiff
== 0) { // Alles blieb gleich
2545 aFlags
[uItems
] = (BYTE
)uItems
;
2547 for(uCol
= 1; uCol
< uItems
; uCol
++) { // Die Einträge anpassen
2548 pData
->aColumnPos
[uCol
] = (BYTE
)pArray
[uCol
];
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];
2557 Header_SetOrderArray(pData
->hHeader
, uItems
, pArray
);
2558 UpdateColumns(pData
);
2561 if(pData
->uStyleEx
& TVS_EX_HEADERCHGNOTIFY
) { // Alle Spalten haben sich verändert
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
;
2571 SendNotify(pData
, &sNotify
.hdr
);
2580 //*****************************************************************************
2582 //* TreeListToggleItem
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
2593 static int TreeListToggleItem(TreeListData
*pData
, unsigned uItem
, unsigned uAddFlags
) {
2605 if(uItem
> pData
->uTreeItemsMax
)
2608 pList
= pData
->pTreeItems
;
2609 pEntry
= pList
[uItem
];
2613 uAction
= uAddFlags
& 0x0F;
2615 uAction
= ((pEntry
->uState
^ TVIS_EXPANDED
) & (TVIS_EXPANDED
| TVIS_EXPANDPARTIAL
)) ? TVE_EXPAND
: TVE_COLLAPSE
;
2618 sNotify
.action
= uAction
;
2619 sNotify
.hdr
.code
= TVN_ITEMEXPANDING
;
2620 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
;
2621 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
2622 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
2623 sNotify
.itemNew
.state
= pEntry
->uState
;
2624 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
2625 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
2626 sNotify
.itemNew
.cchTextMax
= -1;
2627 sNotify
.itemOld
.mask
= 0;
2628 sNotify
.ptDrag
.x
= 0;
2629 sNotify
.ptDrag
.y
= 0;
2633 lRet
= SendNotify(pData
, &sNotify
.hdr
);
2637 pList
= pData
->pTreeItems
;
2638 pEntry
= pList
[uItem
];
2641 return -1; // Eintrag inzischen gelöscht ?
2643 return 1; // User-Abbruch ?
2645 if(uAction
== TVE_EXPAND
) { // Aufklappen
2646 if(pEntry
->uState
& TVIS_EXPANDED
) {
2647 bDo
= FALSE
; // Nur von + auf -
2649 pEntry
->uState
|= TVIS_EXPANDED
; // Kinder Aufklappen
2652 } else { // Zuklappen
2653 pEntry
->uState
&= ~TVIS_EXPANDED
;
2657 pEntry
->uState
&= ~TVIS_EXPANDPARTIAL
;
2658 pEntry
->uState
|= uAddFlags
&~0x0F;
2660 if(pEntry
->uShowPos
&& bDo
) {
2661 if(pEntry
->uState
& TVIS_EXPANDED
) { // Kinderfenster aktuallisieren
2663 uNext
= pEntry
->uFirstChild
;
2666 pTemp
= pList
[uNext
];
2667 pTemp
->uShowPos
= 0;
2669 if(pTemp
->uFirstChild
) {
2670 uNext
= pTemp
->uFirstChild
;
2675 if(pTemp
->uNextItem
) {
2676 uNext
= pTemp
->uNextItem
;
2683 uNext
= pList
[pTemp
->uParent
]->uNextItem
;
2688 UpdateItems(pData
, uItem
);
2691 sNotify
.action
= uAction
;
2692 sNotify
.hdr
.code
= TVN_ITEMEXPANDED
;
2693 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
;
2694 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
2695 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
2696 sNotify
.itemNew
.state
= pEntry
->uState
;
2697 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
2698 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
2699 sNotify
.itemNew
.cchTextMax
= -1;
2700 sNotify
.itemOld
.mask
= 0;
2701 sNotify
.ptDrag
.x
= 0;
2702 sNotify
.ptDrag
.y
= 0;
2706 SendNotify(pData
, &sNotify
.hdr
);
2710 pList
= pData
->pTreeItems
;
2711 pEntry
= pData
->pTreeItems
[uItem
];
2714 return -1; // Eintrag inzischen gelöscht ?
2716 if(uAction
== TVE_EXPAND
) { // ONCE setzen nach Expandieren
2717 pEntry
->uState
|= TVIS_EXPANDEDONCE
;
2720 if(pData
->uSelectedItem
&& bDo
) { // Ist der ausgewählten Eintrag sichtbar ?
2721 pEntry
= pList
[pData
->uSelectedItem
];
2723 pData
->uSelectedItem
= 0;
2724 pData
->uSelectedSub
= 0;
2726 if(!pEntry
->uShowPos
) {
2727 while(!pEntry
->uShowPos
) {
2728 uItem
= pEntry
->uParent
;
2729 pEntry
= pList
[uItem
];
2732 TreeListSelectItem(pData
, uItem
, pData
->uSelectedSub
, TVC_UNKNOWN
);
2736 if(bDo
== FALSE
) { // Nur von + auf -
2737 UpdateRect(pData
, uItem
, 0);
2743 //*****************************************************************************
2745 //* TreeListGetItemRect
2747 //*****************************************************************************
2748 // Holt das Rechteck eines Eintrages
2749 // pData : Zeiger auf die Fensterdaten
2750 // uItem : Ist die Nummer des Eintrages
2751 // uFlags : Bit 0 : 0=volle Zeile 1=nur Text
2752 // Bit 7 : 1=nur Spalte
2753 // Bit 24.. : Spaltennummer
2754 // Ergibt 1 wenn der Eintrag sichtbar war
2755 static int TreeListGetItemRect(TreeListData
*pData
, unsigned uItem
, unsigned uFlags
, RECT
*pRect
) {
2763 if(uItem
> pData
->uTreeItemsMax
) {
2764 memset(pRect
, 0, sizeof(RECT
));
2768 pEntry
= pData
->pTreeItems
[uItem
];
2769 if(!pEntry
->uShowPos
) { // Ist der Eintrag aufgeklappt
2770 memset(pRect
, 0, sizeof(RECT
));
2774 uPos
= pEntry
->uShowPos
- pData
->uScrollY
- 1;
2775 if(uPos
>= pData
->uMaxEnties
) { // Eintrag im Fenster sichtbar
2776 memset(pRect
, 0, sizeof(RECT
));
2780 pRect
->top
= pData
->uStartPixel
;
2781 pRect
->top
+= pData
->iRowHeight
* uPos
;
2782 pRect
->bottom
= pData
->iRowHeight
+ pRect
->top
;
2784 if((uFlags
& 0xFC) == TVIR_GETCOLUMN
) { // Nur Spalten
2785 uSub
= uFlags
>> 24;
2786 if(uSub
>= pData
->uColumnCount
)
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
;
2797 pRect
->left
-= pData
->uScrollX
;
2798 pRect
->right
= pData
->uSizeX
;
2801 if(uFlags
& TVIR_TEXT
) { // Nur Text ausgeben
2803 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
2805 if(pData
->aColumn
[uSub
].bEdit
== TVAX_CHECK
) {
2806 pRect
->left
+= pData
->iChecksXsize
;
2807 if(pRect
->left
> pRect
->right
)
2808 pRect
->left
= pRect
->right
;
2810 if(pExtra
&& pExtra
->bFlags
& TVIX_HASIMAGE
) {
2811 pRect
->left
+= pData
->iImagesXsize
;
2812 if(pRect
->left
> pRect
->right
)
2813 pRect
->left
= pRect
->right
;
2816 if(pData
->cHasRootRow
) { // Root-Linien ausgleichen
2817 pRect
->left
+= pData
->iIndent
;
2820 pRect
->left
+= pData
->iIndent
* pEntry
->uLevel
;
2822 if(pData
->hStates
) {
2823 pRect
->left
+= pData
->iStatesXsize
;
2826 if(!(pData
->uStyle
& TVS_HASLINES
)) {
2830 if(pData
->uStyleEx
& TVS_EX_ITEMLINES
) {
2832 if(pEntry
->bFlags
& TVIX_HASIMAGE
)
2836 if(pEntry
->bFlags
& TVIX_HASIMAGE
) {
2837 pRect
->left
+= pData
->iImagesXsize
;
2840 if(pRect
->left
> pRect
->right
) {
2841 pRect
->left
= pRect
->right
;
2849 //*****************************************************************************
2851 //* TreeListEnsureVisible
2853 //*****************************************************************************
2854 // Macht einen Eintrag sichtbar
2855 // pData : Zeiger auf die Fensterdaten
2856 // uItem : Ist die Nummer des Eintrages
2857 // uSub : Untereintrag der sichtbar sein soll
2858 // 0xFFFFFFFF nur Zeile
2859 // FIRST_LINE als oberster Eintrag
2860 // Ergibt 1 wenn nur zum Eintrag gescrollt wurde bzw. 0 wenn aufgeklapt wurde
2861 static int TreeListEnsureVisible(TreeListData
*pData
, unsigned uItem
, unsigned uSub
) {
2875 if(uItem
> pData
->uTreeItemsMax
)
2878 pEntry
= pData
->pTreeItems
[uItem
];
2882 uPos
= pEntry
->uShowPos
;
2883 if(!uPos
) { // Zweige aufklappen wenn Eintrag zugeklappt
2887 for(pTemp
= pEntry
;;) {
2888 uTemp
= pTemp
->uParent
;
2889 pTemp
= pData
->pTreeItems
[uTemp
];
2892 if((pTemp
->uState
& TVIS_EXPANDED
) == 0) {
2893 if(TreeListToggleItem(pData
, uTemp
, 0))
2898 pEntry
= pData
->pTreeItems
[uItem
];
2902 uPos
= pEntry
->uShowPos
;
2905 } else { // Nur Scrollen
2910 if(uPos
< pData
->uScrollY
) { // Vor erster Zeile
2911 pData
->uScrollY
= uPos
;
2912 SetScrollPos(pData
->hWnd
, SB_VERT
, uPos
, TRUE
);
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
);
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;
2933 if(iOff
!= (int)pData
->uScrollY
) {
2934 pData
->uScrollY
= iOff
;
2935 SetScrollPos(pData
->hWnd
, SB_VERT
, iOff
, TRUE
);
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
];
2947 if(iOff
+ iNum
< iAnf
)
2951 if(iOff
+ iNum
< iEnd
)
2956 iMax
= pData
->aColumnXpos
[pData
->uColumnCount
];
2957 iMax
-= pData
->uSizeX
/ 2;
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
);
2973 //*****************************************************************************
2975 //* TreeListIsVisible
2977 //*****************************************************************************
2978 // Prüft ob ein Eintrag sichtbar ist
2979 // pData : Zeiger auf die Fensterdaten
2980 // uItem : Ist die Nummer des Eintrages
2981 // uSub : Untereintrag der geprüft werden soll
2982 // 0xFFFFFFFF nur Zeile prüfen
2983 // Ergibt den Zustand des Eintrages:
2984 // -1 = Unbekannter Eintrag
2985 // 0 = Eintrag ist zugeklappt
2986 // 1 = Eintrag ist aufgeklappt aber nicht sichtbar
2987 // 2 = Eintrag ist aufgeklappt und teilweise sichtbar
2988 // 3 = Eintrag ist aufgeklappt und Spalte ist nur teilweise sichtbar
2989 // 4 = Eintrag ist aufgeklappt und ganz sichtbar
2990 static int TreeListIsVisible(TreeListData
*pData
, unsigned uItem
, unsigned uSub
) {
3000 if(uItem
> pData
->uTreeItemsMax
)
3003 pEntry
= pData
->pTreeItems
[uItem
];
3007 uPos
= pEntry
->uShowPos
;
3008 if(!uPos
) { // Ist der Eintrag zugeklappt
3013 if(uPos
< pData
->uScrollY
) { // Vor erster Zeile
3018 if(uPos
>= pData
->uScrollY
+ pData
->uMaxEnties
) { // Nach letzter Zeile
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
];
3030 if(iOff
+ iNum
< iAnf
)
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
];
3046 if(iOff
+ iNum
< iAnf
)
3050 if(iOff
+ iNum
< iEnd
)
3059 //*****************************************************************************
3061 //* TreeListDeleteItem
3063 //*****************************************************************************
3064 // Löscht einen Eintrag aus dem Fenster
3065 // pData : Zeiger auf die Fensterdaten
3066 // uItem : Ist die Nummer des Eintrages der gelöscht werden soll
3067 // iMode : Wie soll der Eintrag gelöscht werden
3068 // 0 = Eintrag löschen und nicht neu zeichnen
3069 // 1 = Eintrag löschen und neu zeichnen
3070 // 2 = Nur Kindereinträge löschen und neu zeichnen
3071 // Ergibt 1 wenn der Eintrag gelöscht wurde.
3072 static int TreeListDeleteItem(TreeListData
*pData
, unsigned uItem
, int iMode
) {
3083 if(pData
->cLockChanges
)
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)
3092 while(pData
->uLastChild
) {
3093 TreeListDeleteItem(pData
, pData
->uLastChild
, 0);
3096 pData
->uItemPosCount
= 0;
3098 UpdateScrollY(pData
);
3104 pEntry
= pData
->pTreeItems
[uItem
];
3105 if(!pEntry
) { // Prüfe den Eintrag
3107 return 0; // Alles löschen
3108 if(pData
->uLastChild
== 0)
3111 while(pData
->uLastChild
) {
3112 TreeListDeleteItem(pData
, pData
->uLastChild
, 0);
3115 pData
->uItemPosCount
= 0;
3117 UpdateScrollY(pData
);
3123 if(iMode
== 2) { // Nur Kindereinträge löschen
3124 if(!pEntry
->uFirstChild
) {
3128 while(pEntry
->uLastChild
) { // Alle Kinder löschen
3129 TreeListDeleteItem(pData
, pEntry
->uLastChild
, 0);
3132 uPos
= pEntry
->uShowPos
;
3134 UpdateItems(pData
, uItem
);
3140 while(pEntry
->uLastChild
) { // Alle Kinder löschen
3141 TreeListDeleteItem(pData
, pEntry
->uLastChild
, 0);
3144 if(uItem
== pData
->uSelectedItem
) { // Einen ausgewählten Eintrag löschen
3145 sNotify
.hdr
.code
= TVN_SELCHANGED
;
3146 sNotify
.action
= TVC_UNKNOWN
;
3147 sNotify
.itemOld
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3148 sNotify
.itemOld
.hItem
= (HTREEITEM
)uItem
;
3149 sNotify
.itemOld
.stateMask
= 0xFFFFFFFF;
3150 sNotify
.itemOld
.state
= pEntry
->uState
&~TVIS_SELECTED
;
3151 sNotify
.itemOld
.lParam
= pEntry
->lParam
;
3152 sNotify
.itemOld
.cChildren
= 0;
3153 sNotify
.itemOld
.pszText
= (LPTSTR
) - 1;
3154 sNotify
.itemOld
.cchTextMax
= -1;
3155 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3156 sNotify
.itemNew
.hItem
= NULL
;
3157 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
3158 sNotify
.itemNew
.state
= 0;
3159 sNotify
.itemNew
.lParam
= 0;
3160 sNotify
.itemNew
.cChildren
= 0;
3161 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
3162 sNotify
.itemNew
.cchTextMax
= -1;
3163 sNotify
.ptDrag
.x
= 0;
3164 sNotify
.ptDrag
.y
= 0;
3167 SendNotify(pData
, &sNotify
.hdr
); // Bekant geben das der Eintrag nicht mehr ausgewählt ist
3170 pData
->uSelectedItem
= 0;
3171 pData
->uSelectedSub
= 0;
3174 sNotify
.hdr
.code
= TVN_DELETEITEM
;
3175 sNotify
.itemNew
.mask
= 0;
3176 sNotify
.itemOld
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
;
3177 sNotify
.itemOld
.hItem
= (HTREEITEM
)uItem
;
3178 sNotify
.itemOld
.lParam
= pEntry
->lParam
;
3179 sNotify
.itemOld
.pszText
= (LPTSTR
) - 1;
3180 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
3181 sNotify
.itemNew
.state
= pEntry
->uState
;
3182 sNotify
.itemOld
.cchTextMax
= -1;
3183 sNotify
.ptDrag
.x
= 0;
3184 sNotify
.ptDrag
.y
= 0;
3187 SendNotify(pData
, &sNotify
.hdr
);
3190 pEntry
= pData
->pTreeItems
[uItem
]; // Prüfen ob der Eintrag noch existiert
3194 if(uItem
== pData
->uTrackedItem
) { // Einen unterstrichenen Eintrag löschen
3195 pData
->uTrackedItem
= 0;
3196 pData
->uTrackedSub
= 0;
3199 if(pData
->uInsertMark
== uItem
) {
3200 pData
->uInsertMark
= 0;
3203 if(pData
->uSingleSel
== uItem
) {
3204 pData
->uSingleSel
= 0;
3207 if(pEntry
->uPrevItem
) { // Gibt es einen vorherigen Eintrag
3208 pTemp
= pData
->pTreeItems
[pEntry
->uPrevItem
];
3209 pTemp
->uNextItem
= pEntry
->uNextItem
;
3211 if(pEntry
->uParent
) { // Neues erstes Kind in Elterneintrag
3212 pTemp
= pData
->pTreeItems
[pEntry
->uParent
];
3213 pTemp
->uFirstChild
= pEntry
->uNextItem
;
3215 pData
->uFirstChild
= pEntry
->uNextItem
;
3219 if(pEntry
->uNextItem
) { // Gibt es einen vorherigen Eintrag
3220 pTemp
= pData
->pTreeItems
[pEntry
->uNextItem
];
3221 pTemp
->uPrevItem
= pEntry
->uPrevItem
;
3223 if(pEntry
->uParent
) { // Neues letztes Kind in Elterneintrag
3224 pTemp
= pData
->pTreeItems
[pEntry
->uParent
];
3225 pTemp
->uLastChild
= pEntry
->uPrevItem
;
3227 if(pTemp
->uFirstChild
== 0 && pTemp
->uLastChild
== 0) {
3228 pTemp
->bFlags
&= ~TVIX_HASBUTTON
;
3231 pData
->uLastChild
= pEntry
->uPrevItem
;
3235 for(uPos
= 1; uPos
< pData
->uColumnCount
; uPos
++) { // Alle Extraeinträge löschen
3236 pList
= pData
->pExtraItems
[uPos
- 1];
3238 pExtra
= pList
[uItem
];
3242 pList
[uItem
] = NULL
;
3245 pExtra
->uTextSize
= 0;
3246 delete(pExtra
->pText
);
3253 pData
->pTreeItems
[uItem
] = NULL
; // Den Eintrag löschen
3256 pEntry
->uTextSize
= 0;
3257 delete(pEntry
->pText
);
3260 if(iMode
) { // Den Eintrag neuzeichnen
3261 uItem
= pEntry
->uPrevItem
;
3262 if(!uItem
&& !pEntry
->uNextItem
) {
3263 uItem
= pEntry
->uParent
;
3267 uPos
= pData
->pTreeItems
[uItem
]->uShowPos
;
3269 uPos
= pEntry
->uShowPos
;
3273 UpdateItems(pData
, uItem
);
3277 if(pEntry
->uState
& TVIS_SELECTED
) // Ausgewählte Einträge runterzählen
3278 if(pData
->uSelectedCount
> 0) {
3279 pData
->uSelectedCount
--;
3284 pData
->uTreeItemsCount
--;
3286 iOff
= pData
->uScrollY
; // Prüfe die Scrollposition
3287 iMax
= pData
->uItemPosCount
;
3288 iMax
-= pData
->uPageEnties
- 1;
3294 if(iOff
!= (int)pData
->uScrollY
) {
3295 pData
->uScrollY
= iOff
;
3296 SetScrollPos(pData
->hWnd
, SB_VERT
, iOff
, TRUE
);
3303 //*****************************************************************************
3305 //* TreeListXorSelectItem
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
3315 // Ergibt 1 wenn der Eintrag ab/angewählt wurde
3316 // 0 wenn der Eintrag nicht verändert wurde
3317 static int TreeListXorSelectItem(TreeListData
*pData
, unsigned uItem
, int iMode
) {
3324 pEntry
= pData
->pTreeItems
[uItem
];
3327 if(uItem
== pData
->uSelectedItem
)
3330 uOld
= pEntry
->uState
;
3332 sNotify
.hdr
.code
= TVN_SELCHANGING
;
3333 sNotify
.action
= iMode
;
3334 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3335 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
3336 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
3337 sNotify
.itemNew
.state
= pEntry
->uState
;
3338 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
3339 sNotify
.itemNew
.cChildren
= 0;
3340 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
3341 sNotify
.itemNew
.cchTextMax
= -1;
3342 sNotify
.itemOld
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3343 sNotify
.itemOld
.hItem
= NULL
;
3344 sNotify
.itemOld
.stateMask
= 0xFFFFFFFF;
3345 sNotify
.itemOld
.state
= 0;
3346 sNotify
.itemOld
.lParam
= 0;
3347 sNotify
.itemOld
.cChildren
= 0;
3348 sNotify
.itemOld
.pszText
= (LPTSTR
) - 1;
3349 sNotify
.itemOld
.cchTextMax
= -1;
3350 sNotify
.ptDrag
.x
= 0;
3351 sNotify
.ptDrag
.y
= 0;
3354 uRet
= U(SendNotify(pData
, &sNotify
.hdr
));
3360 pEntry
= pData
->pTreeItems
[uItem
];
3363 pEntry
->uState
^= TVIS_SELECTED
;
3365 sNotify
.hdr
.code
= TVN_SELCHANGED
;
3366 sNotify
.action
= iMode
;
3367 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3368 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
3369 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
3370 sNotify
.itemNew
.state
= pEntry
->uState
;
3371 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
3372 sNotify
.itemNew
.cChildren
= 0;
3373 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
3374 sNotify
.itemNew
.cchTextMax
= -1;
3375 sNotify
.itemOld
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3376 sNotify
.itemOld
.hItem
= NULL
;
3377 sNotify
.itemOld
.stateMask
= 0xFFFFFFFF;
3378 sNotify
.itemOld
.state
= 0;
3379 sNotify
.itemOld
.lParam
= 0;
3380 sNotify
.itemOld
.cChildren
= 0;
3381 sNotify
.itemOld
.pszText
= (LPTSTR
) - 1;
3382 sNotify
.itemOld
.cchTextMax
= -1;
3383 sNotify
.ptDrag
.x
= 0;
3384 sNotify
.ptDrag
.y
= 0;
3387 SendNotify(pData
, &sNotify
.hdr
);
3390 pEntry
= pData
->pTreeItems
[uItem
];
3393 if(pEntry
->uShowPos
) {
3394 if(pData
->uStyleEx
& TVS_EX_FULLROWMARK
)
3395 UpdateRow(pData
, uItem
);
3397 UpdateRect(pData
, uItem
, 0);
3400 if((uOld
^ pEntry
->uState
)&TVIS_SELECTED
) {
3401 if(pEntry
->uState
& TVIS_SELECTED
)
3402 pData
->uSelectedCount
++;
3404 pData
->uSelectedCount
--;
3411 //*****************************************************************************
3413 //* TreeListRemoveFocus
3415 //*****************************************************************************
3416 // Wählt den Focus ab
3417 // pData : Zeiger auf die Fensterdaten
3418 static void TreeListRemoveFocus(TreeListData
*pData
) {
3425 if(!pData
->uFocusItem
)
3428 uItem
= pData
->uFocusItem
;
3429 pEntry
= pData
->pTreeItems
[uItem
];
3432 pEntry
->bFlags
&= ~TVIX_FOCUSED
;
3434 uSub
= pData
->uFocusSub
;
3437 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
3439 pExtra
->bFlags
&= ~TVIX_FOCUSED
;
3442 UpdateRect(pData
, uItem
, uSub
);
3445 pData
->uFocusItem
= 0;
3446 pData
->uFocusSub
= 0;
3449 //*****************************************************************************
3451 //* TreeListSetFocus
3453 //*****************************************************************************
3454 // Wählt den Focus-Eintrag
3455 // pData : Zeiger auf die Fensterdaten
3456 // uItem : Eintrag für den Focus (0xFFFFFFFF=keine Änderung)
3457 // uSub : Spalte für den Focus (0xFFFFFFFF=keine Änderung)
3458 // Ergibt 1 wenn der Focus gesetzt wurde, bzw 0 bei einem Fehler
3459 static int TreeListSetFocus(TreeListData
*pData
, unsigned uItem
, unsigned uSub
) {
3467 if(pData
->uFocusItem
) {
3468 if(uSub
== 0xFFFFFFFF)
3469 uSub
= pData
->uFocusSub
;
3470 if(uItem
== 0xFFFFFFFF)
3471 uItem
= pData
->uFocusItem
;
3473 if(uSub
== 0xFFFFFFFF)
3474 uSub
= pData
->uSelectedSub
;
3475 if(uItem
== 0xFFFFFFFF)
3476 uItem
= pData
->uSelectedItem
;
3479 if(pData
->uFocusItem
== uItem
)
3480 if(pData
->uFocusSub
== uSub
)
3483 if(!uItem
) { // Focus abwählen
3484 TreeListRemoveFocus(pData
);
3489 if(uItem
> pData
->uTreeItemsMax
) { // Den Eintrag prüfen
3493 pEntry
= pData
->pTreeItems
[uItem
];
3498 if(!(pData
->uStyleEx
& TVS_EX_SUBSELECT
))
3501 if(!(pData
->uStyleEx
& TVS_EX_MULTISELECT
)) { // Einzel auswahl
3502 return TreeListSelectItem(pData
, uItem
, uSub
, TVC_UNKNOWN
);
3505 uTemp
= pData
->uFocusItem
;
3506 pTemp
= pData
->pTreeItems
[uTemp
];
3508 if(pTemp
) { // Den alten Eintrag abwählen
3509 pTemp
->bFlags
&= ~TVIX_FOCUSED
;
3510 uCol
= pData
->uFocusSub
;
3513 pExtra
= pData
->pExtraItems
[uCol
- 1][uTemp
];
3515 pExtra
->bFlags
&= ~TVIX_FOCUSED
;
3518 UpdateRect(pData
, uItem
, uSub
);
3522 if(uSub
) { // Neuen Eintrag wählen
3523 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
3525 pExtra
->bFlags
|= TVIX_FOCUSED
;
3527 pEntry
->bFlags
|= TVIX_FOCUSED
;
3530 pData
->uFocusItem
= uItem
;
3531 pData
->uFocusSub
= uSub
;
3533 if(pEntry
->uState
& TVIS_SELECTED
) { // Auch die Auswahl nachziehen
3534 if(pData
->uSelectedItem
!= uItem
) {
3535 uTemp
= pData
->uSelectedItem
;
3536 uCol
= pData
->uSelectedSub
;
3539 uCol
= pData
->uSelectedSub
;
3542 pData
->uSelectedItem
= uItem
;
3543 pData
->uSelectedSub
= uSub
;
3545 if(pData
->uStyleEx
& TVS_EX_FULLROWMARK
) {
3551 UpdateRow(pData
, uTemp
);
3553 UpdateRect(pData
, uTemp
, uCol
);
3558 UpdateRow(pData
, uItem
);
3560 UpdateRect(pData
, uItem
, uCol
);
3562 UpdateRect(pData
, uItem
, uSub
);
3568 //*****************************************************************************
3570 //* TreeListSelectItem
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
3581 // TVC_ONLYFOCUS (nur der Focus hat sich verändert)
3582 // TVC_DESELECT (dieses Flag löscht die alte Auswahl)
3583 // TVC_UNSELECT (dieses Flag löscht Auswahl bei MultiSel)
3584 // Ergibt 2 wenn der Eintrag gewählt und umgeklapt wurde
3585 // 1 wenn der Eintrag gewählt wurde
3586 // 0 wenn der Eintrag nicht gewählt wurde
3587 static int TreeListSelectItem(TreeListData
*pData
, unsigned uItem
, unsigned uSubItem
, int iMode
) {
3605 uOld
= pData
->uSelectedItem
;
3606 uSub
= pData
->uSelectedSub
;
3608 if(uSubItem
>= pData
->uColumnCount
&& uSubItem
> 0)
3610 if(uItem
> pData
->uTreeItemsMax
)
3613 if(uSubItem
== uSub
)
3614 if(pData
->uSelectedCount
<= 1 || !(pData
->uStyleEx
& TVS_EX_MULTISELECT
)) {
3618 if(pData
->uStyleEx
& TVS_EX_MULTISELECT
) { // Ist die Mehrfachauswahl möglich
3619 iSel
= iMode
& TVC_UNSELECT
;
3620 iDel
= iMode
& TVC_DESELECT
;
3622 if(pData
->uStyleEx
& (TVS_EX_FULLROWMARK
| TVS_EX_SUBSELECT
))
3623 UpdateRow(pData
, uOld
);
3625 UpdateRect(pData
, uOld
, uSub
);
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
))
3635 if(TreeListXorSelectItem(pData
, uPos
, iMode
))
3636 if(!pData
->uSelectedCount
)
3637 break; // Wurden alle Einträge abgewählt
3641 } else { // Altes Select löschen
3642 iMode
&= ~TVC_ONLYFOCUS
;
3647 iMode
&= ~(TVC_DESELECT
| TVC_UNSELECT
);
3649 pEntry
= pData
->pTreeItems
[uItem
];
3650 if(!pEntry
) { // Neuen Statatus holen
3656 uState
= pEntry
->uState
;
3657 lParam
= pEntry
->lParam
;
3660 uState
&= TVIS_BASEFLAGS
;
3661 pExtra
= pData
->pExtraItems
[uSubItem
- 1][uItem
];
3663 uState
|= pExtra
->uState
;
3667 pTemp
= pData
->pTreeItems
[uOld
];
3668 if(!pTemp
) { // Alten Status holen
3672 uStOld
= pTemp
->uState
;
3673 lPaOld
= pTemp
->lParam
;
3676 uStOld
&= TVIS_BASEFLAGS
;
3677 pExtra
= pData
->pExtraItems
[uSub
- 1][uOld
];
3679 uStOld
|= pExtra
->uState
;
3683 sNotify
.hdr
.code
= TVN_SELCHANGING
;
3684 sNotify
.action
= iMode
;
3685 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3686 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
3687 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
3688 sNotify
.itemNew
.state
= uState
;
3689 sNotify
.itemNew
.lParam
= lParam
;
3690 sNotify
.itemNew
.cChildren
= uSubItem
;
3691 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
3692 sNotify
.itemNew
.cchTextMax
= -1;
3693 sNotify
.itemOld
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3694 sNotify
.itemOld
.hItem
= (HTREEITEM
)uOld
;
3695 sNotify
.itemOld
.stateMask
= 0xFFFFFFFF;
3696 sNotify
.itemOld
.state
= uStOld
;
3697 sNotify
.itemNew
.lParam
= lPaOld
;
3698 sNotify
.itemOld
.cChildren
= uSub
;
3699 sNotify
.itemOld
.pszText
= (LPTSTR
) - 1;
3700 sNotify
.itemOld
.cchTextMax
= -1;
3701 sNotify
.ptDrag
.x
= 0;
3702 sNotify
.ptDrag
.y
= 0;
3707 if(SendNotify(pData
, &sNotify
.hdr
)) { // Abfragen ob der Eintrag gewählt werden darf
3714 if(uItem
) { // Prüfen ob der Eintrag noch existiert
3715 pEntry
= pData
->pTreeItems
[uItem
];
3721 uOld
= pData
->uSelectedItem
;
3722 pTemp
= pData
->pTreeItems
[uOld
];
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
);
3731 UpdateRect(pData
, uOld
, uSub
);
3734 if(pTemp
->uState
& TVIS_SELECTED
) {
3735 uStOld
&= ~TVIS_SELECTED
;
3736 pTemp
->uState
&= ~TVIS_SELECTED
;
3738 if(pData
->uSelectedCount
> 0) {
3739 pData
->uSelectedCount
-= 1;
3743 pData
->uSelectedSub
= 0;
3744 pData
->uSelectedItem
= 0;
3750 if(uItem
) { // Den neuen Eintrag wählen
3752 if(pEntry
->uState
& TVIS_SELECTED
) {
3753 uState
&= ~TVIS_SELECTED
;
3754 pEntry
->uState
&= ~TVIS_SELECTED
;
3755 if(pData
->uSelectedCount
)
3756 pData
->uSelectedCount
--;
3759 if(!(pEntry
->uState
& TVIS_SELECTED
)) {
3760 uState
|= TVIS_SELECTED
;
3761 pEntry
->uState
|= TVIS_SELECTED
;
3762 pData
->uSelectedCount
+= 1;
3766 if(uSubItem
&& uSubItem
< pData
->uColumnCount
) {
3767 pExtra
= pData
->pExtraItems
[uSubItem
- 1][uItem
];
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
;
3776 uState
= pExtra
->uState
;
3777 uState
|= pEntry
->uState
& TVIS_BASEFLAGS
;
3779 uState
= pEntry
->uState
;
3782 if(pEntry
->uShowPos
) { // Den Eintrag neu zeichnen
3783 if(pData
->uStyleEx
& (TVS_EX_FULLROWMARK
| TVS_EX_SUBSELECT
))
3784 UpdateRow(pData
, uItem
);
3786 UpdateRect(pData
, uItem
, uSubItem
);
3789 pData
->uSelectedSub
= uSubItem
;
3790 pData
->uSelectedItem
= uItem
;
3792 pData
->uSelectedItem
= 0;
3793 pData
->uSelectedSub
= 0;
3797 sNotify
.hdr
.code
= TVN_SELCHANGED
;
3798 sNotify
.action
= iMode
;
3799 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3800 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
3801 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
3802 sNotify
.itemNew
.state
= uState
;
3803 sNotify
.itemNew
.lParam
= lParam
;
3804 sNotify
.itemNew
.cChildren
= uSubItem
;
3805 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
3806 sNotify
.itemNew
.cchTextMax
= -1;
3807 sNotify
.itemOld
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
| TVIF_PARAM
;
3808 sNotify
.itemOld
.hItem
= (HTREEITEM
)uOld
;
3809 sNotify
.itemOld
.stateMask
= 0xFFFFFFFF;
3810 sNotify
.itemOld
.state
= uStOld
;
3811 sNotify
.itemOld
.lParam
= lPaOld
;
3812 sNotify
.itemOld
.cChildren
= uSub
;
3813 sNotify
.itemOld
.pszText
= (LPTSTR
) - 1;
3814 sNotify
.itemOld
.cchTextMax
= -1;
3815 sNotify
.ptDrag
.x
= 0;
3816 sNotify
.ptDrag
.y
= 0;
3819 SendNotify(pData
, &sNotify
.hdr
);
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
);
3832 //*****************************************************************************
3835 sNotify
.hdr
.code
= TVN_SINGLEEXPAND
;
3836 sNotify
.action
= iMode
;
3837 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
;
3838 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
3839 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
3840 sNotify
.itemNew
.state
= (pEntry
) ? pEntry
->uState
: 0;
3841 sNotify
.itemNew
.cChildren
= 0;
3842 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
3843 sNotify
.itemNew
.cchTextMax
= -1;
3844 sNotify
.itemOld
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
;
3845 sNotify
.itemOld
.hItem
= (HTREEITEM
)uOld
;
3846 sNotify
.itemOld
.stateMask
= 0xFFFFFFFF;
3847 sNotify
.itemOld
.state
= (pTemp
) ? pTemp
->uState
: 0;
3848 sNotify
.itemOld
.cChildren
= 0;
3849 sNotify
.itemOld
.pszText
= (LPTSTR
) - 1;
3850 sNotify
.itemOld
.cchTextMax
= -1;
3851 sNotify
.ptDrag
.x
= 0;
3852 sNotify
.ptDrag
.y
= 0;
3855 uRet
= U(SendNotify(pData
, &sNotify
.hdr
)); // Anfragen ob die Zweige umgeklappt werden dürfen
3859 pTemp
= pData
->pTreeItems
[uOld
]; // Zeiger neu holen falls es Änderungen gab
3860 pEntry
= pData
->pTreeItems
[uItem
];
3862 while(pTemp
&& pEntry
) { // Beide Zweige sysnchronisieren
3863 if(pEntry
->uLevel
> pTemp
->uLevel
) {
3864 uNext
= pEntry
->uParent
;
3866 if(!(uRet
& TVNRET_SKIPNEW
))
3867 if(!(pEntry
->uState
& TVIS_EXPANDED
)) {
3868 TreeListToggleItem(pData
, uItem
, 0);
3871 pEntry
= pData
->pTreeItems
[uNext
];
3881 goto EndSel
; // Bis zum gleichen Knoten
3883 uNext
= pTemp
->uParent
;
3885 if(!(uRet
& TVNRET_SKIPOLD
))
3886 if(pTemp
->uState
& TVIS_EXPANDED
) {
3887 TreeListToggleItem(pData
, uOld
, 0);
3890 pTemp
= pData
->pTreeItems
[uNext
];
3895 if(!(uRet
& TVNRET_SKIPOLD
))
3896 while(pTemp
) { // Alten Zweig zuklappen
3897 uNext
= pTemp
->uParent
;
3899 if(pTemp
->uState
& TVIS_EXPANDED
) {
3900 TreeListToggleItem(pData
, uOld
, 0);
3903 pTemp
= pData
->pTreeItems
[uNext
];
3911 if(!(uRet
& TVNRET_SKIPNEW
))
3912 while(pEntry
) { // Neuen Zweig aufklappen
3913 uNext
= pEntry
->uParent
;
3915 if(!(pEntry
->uState
& TVIS_EXPANDED
)) {
3916 TreeListToggleItem(pData
, uItem
, 0);
3919 pEntry
= pData
->pTreeItems
[uNext
];
3926 if(pData
->uStyle
& TVS_SHOWSELALWAYS
)
3927 if(pData
->uSelectedItem
) {
3928 TreeListEnsureVisible(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
3934 //*****************************************************************************
3936 //* TreeListSelectChilds
3938 //*****************************************************************************
3939 // Wählt einen Eintrag aus
3940 // pData : Zeiger auf die Fensterdaten
3941 // uItem : Ist die Nummer des Eintrages der ausgewählt werden soll
3942 // iMode : Bit 0 = Untereintäge auch ändern
3943 // Bit 1 = Einträge abwählen
3944 // Ergibt 1 wenn die Auswahl funktioniert hat, bzw. 0 bei einem Fehler
3945 static int TreeListSelectChilds(TreeListData
*pData
, unsigned uItem
, int iMode
) {
3951 if(!(pData
->uStyleEx
& TVS_EX_MULTISELECT
))
3956 if(uItem
== U(TVI_ROOT
)) {
3957 uItem
= pData
->uFirstChild
;
3959 if(uItem
> pData
->uTreeItemsMax
)
3963 if(!pData
->pTreeItems
[uItem
]) {
3968 uXor
= (iMode
& TVIS_DESELECT
) ? 0 : TVIS_SELECTED
;
3969 iMode
&= TVIS_WITHCHILDS
;
3972 pEntry
= pData
->pTreeItems
[uItem
];
3974 if((pEntry
->uState
^ uXor
)&TVIS_SELECTED
) {
3975 TreeListXorSelectItem(pData
, uItem
, TVC_UNKNOWN
);
3978 if(iMode
&& pEntry
->uFirstChild
) { // Auch Kinder ändern
3979 uItem
= pEntry
->uFirstChild
;
3984 for(;;) { // Eine Ebene höher
3985 uItem
= pEntry
->uNextItem
;
3993 uItem
= pEntry
->uParent
;
3994 pEntry
= pData
->pTreeItems
[uItem
];
3999 //*****************************************************************************
4001 //* TreeListInsertItem
4003 //*****************************************************************************
4004 // Fügt einen Eintrag ins Fenster ein
4005 // pData : Zeiger auf die Fensterdaten
4006 // pInsert : Zeiger auf die ein zu fügenden Daten
4007 // Ergibt die Einfügeposition des neuen Eintrages oder 0 bei einem Fehler
4008 static unsigned TreeListInsertItem(TreeListData
*pData
, TV_INSERTSTRUCT
*pInsert
) {
4014 PFNTVSORTEX pCompare
;
4015 ExtraItem
**pExOld
[MAX_COLUMNS
];
4016 ExtraItem
**pExNew
[MAX_COLUMNS
];
4042 if(pData
->cLockChanges
)
4045 uParent
= U(pInsert
->hParent
);
4046 if(uParent
> pData
->uTreeItemsMax
) { // Prüfe das Elternelement
4047 if(pInsert
->hParent
!= TVI_ROOT
) {
4053 pParent
= pData
->pTreeItems
[uParent
];
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;
4067 pItems
= new(BaseItem
*, uMax
+ 1);
4073 pPosNew
= new(unsigned, uMax
);
4079 for(uPos
= 1; uPos
< pData
->uColumnCount
; uPos
++) {
4080 pExOld
[uPos
] = pData
->pExtraItems
[uPos
- 1];
4081 pExNew
[uPos
] = new(ExtraItem
*, uMax
+ 1);
4084 for(uPos
--; uPos
> 0; uPos
--)
4085 delete(pExNew
[uPos
]);
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
));
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
]);
4104 pData
->uTreeItemsMax
= uMax
;
4105 pData
->pTreeItems
= pItems
;
4106 pData
->pItemPos
= pPosNew
;
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
;
4117 if(!pNew
) { // Konnte der Speicher reserviert werden
4121 if(pData
->uUserDataSize
) { // Die Userdaten auf 0 setzen
4122 memset(pTemp
+ sizeof(BaseItem
), 0, pData
->uUserDataSize
);
4125 for(;; uPos
++) { // Suche freie Position
4126 if(uPos
> pData
->uTreeItemsMax
)
4128 if(pItems
[uPos
] == NULL
)
4132 pData
->uNextSeachPos
= uPos
;
4134 memset(pNew
, 0, sizeof(BaseItem
)); // Erstelle den neuen Eintrag
4135 pNew
->iImage
= TV_NOIMAGE
;
4136 pNew
->iSelectedImage
= TV_NOIMAGE
;
4138 uBits
= pInsert
->item
.mask
;
4140 if(uBits
& TVIF_STATE
) {
4141 pNew
->uState
= pInsert
->item
.state
& pInsert
->item
.stateMask
;
4143 if(pData
->uStyle
& TVS_CHECKBOXES
)
4144 if(!(pData
->uStyleEx
& TVS_EX_BITCHECKBOX
)) {
4145 pNew
->uState
= 0x1000;
4149 if(uBits
& TVIF_PARAM
) {
4150 pNew
->lParam
= pInsert
->item
.lParam
;
4153 if(uBits
& TVIF_IMAGE
) {
4154 pNew
->iImage
= pInsert
->item
.iImage
;
4155 if(pNew
->iImage
== I_IMAGECALLBACK
)
4156 pNew
->bCallback
|= TVIF_IMAGE
;
4159 if(uBits
& TVIF_SELECTEDIMAGE
) {
4160 pNew
->iSelectedImage
= pInsert
->item
.iSelectedImage
;
4161 if(pNew
->iSelectedImage
== I_IMAGECALLBACK
)
4162 pNew
->bCallback
|= TVIF_SELECTEDIMAGE
;
4165 if(uBits
& TVIF_CHILDREN
) { // Art der Schaltflächen
4166 switch(pInsert
->item
.cChildren
) {
4170 pNew
->bFlags
|= TVIX_HASBUTTON
;
4173 pNew
->bCallback
|= TVIF_CHILDREN
;
4177 pNew
->bFlags
|= TVIX_VARBUTTON
;
4181 pNew
->bFlags
|= TVIX_VARBUTTON
;
4184 if(pData
->uStyle
& TVS_SINGLEEXPAND
) { // Nicht aufklappen bei Einzelmodus
4185 pNew
->uState
&= ~TVIS_EXPANDED
;
4188 if(uBits
& TVIF_TEXT
) { // Text einfügen
4189 if(pInsert
->item
.pszText
== LPSTR_TEXTCALLBACK
) {
4190 pNew
->bCallback
|= TVIF_TEXT
;
4191 pNew
->uTextSize
= 0;
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));
4199 pNew
->pText
= new(TCHAR
, 1);
4201 pNew
->uTextSize
= 0;
4204 if(!pParent
) { // Einen Root-Eintrag einfügen
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
;
4219 if(pParent
->bFlags
& TVIX_VARBUTTON
) {
4220 pParent
->bFlags
|= TVIX_HASBUTTON
;
4224 //******************** Eintrage einfügen **************************************
4225 uAfter
= U(pInsert
->hInsertAfter
);
4228 case U(TVI_BEFORE
): // Nach einem Eintrag einfügen
4229 if(pParent
) { // Einen Root-Eintrag einfügen
4231 pParent
->bFlags
= bFlag
;
4232 uParent
= pParent
->uParent
;
4233 pParent
= pItems
[uParent
];
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
;
4249 if(pParent
->bFlags
& TVIX_VARBUTTON
) {
4250 pParent
->bFlags
|= TVIX_HASBUTTON
;
4254 if(pEntry
->uPrevItem
) {
4255 uAfter
= pEntry
->uPrevItem
;
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
;
4270 pNew
->uNextItem
= pFirst
[0]; // Eintrag einfügen
4274 case U(TVI_ROOT
): // Als Root-Eintrag einfügen
4277 pFirst
= &pData
->uFirstChild
;
4278 pLast
= &pData
->uLastChild
;
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
;
4290 pNew
->uPrevItem
= pLast
[0]; // Eintrag einfügen
4295 case U(TVI_SORTEX
): // Einfügen mittels Funktion
4297 if(!uItem
) { // Gibt es keine Kindeinträge
4303 if(pNew
->bCallback
& TVIF_TEXT
) { // Text über Callback holen
4306 CallbackEntry(pData
, pNew
, uPos
, TVIF_TEXT
, &iNone
, &uSize
, &pText
);
4309 pText
= pNew
->pText
;
4312 pData
->cLockChanges
= 1;
4314 pCompare
= (PFNTVSORTEX
)(pInsert
->item
.hItem
);
4321 while(uNext
) { // Zähle die Einträge
4323 uNext
= pItems
[uNext
]->uNextItem
;
4326 while(iCount
> 0) { // Binary-Seach Algorithnus
4327 iShift
= iCount
/ 2;
4331 uNext
= pItems
[uNext
]->uNextItem
;
4335 pEntry
= pItems
[uNext
];
4336 if(pEntry
->bCallback
& TVIF_TEXT
) { // Text über Callback holen
4339 CallbackEntry(pData
, pEntry
, uItem
, TVIF_TEXT
, &iNone
, &uSize
, &pTextTemp
);
4342 pTextTemp
= pEntry
->pText
;
4345 iCmp
= pCompare(pData
->hWnd
, (HTREEITEM
)uNext
, pTextTemp
, pText
, pEntry
->lParam
, pInsert
->item
.lParam
);
4347 iCount
-= (iCount
+ 1) / 2;
4352 iCount
-= iCount
/ 2 + 1;
4354 uItem
= pItems
[uNext
]->uNextItem
;
4358 uBefore
= pEntry
->uPrevItem
;
4363 pData
->cLockChanges
= 0;
4365 pNew
->uNextItem
= uItem
;
4366 pNew
->uPrevItem
= uBefore
;
4368 if(uBefore
) { // Vorherigen Eintrag anpassen
4369 pEntry
= pItems
[uBefore
];
4370 pEntry
->uNextItem
= uPos
;
4371 } else { // Am Anfang einfügen
4375 if(uItem
) { // Nächsten Eintrag anpassen
4376 pEntry
= pItems
[uItem
];
4377 pEntry
->uPrevItem
= uPos
;
4378 } else { // Am Ende anhängen
4383 case U(TVI_SORT
): // Alphapetisch einfügen
4385 if(!uItem
) { // Gibt es keine Kindeinträge
4391 if(pNew
->bCallback
& TVIF_TEXT
) { // Text über Callback holen
4394 CallbackEntry(pData
, pNew
, uPos
, TVIF_TEXT
, &iNone
, &uSize
, &pText
);
4397 pText
= pNew
->pText
;
4400 pData
->cLockChanges
= 1;
4406 while(uNext
) { // Zähle die Einträge
4408 uNext
= pItems
[uNext
]->uNextItem
;
4411 while(iCount
> 0) { // Binary-Seach Algorithnus
4412 iShift
= iCount
/ 2;
4416 uNext
= pItems
[uNext
]->uNextItem
;
4421 pEntry
= pItems
[uNext
];
4422 if(pEntry
->bCallback
& TVIF_TEXT
) { // Text über Callback holen
4425 CallbackEntry(pData
, pEntry
, uItem
, TVIF_TEXT
, &iNone
, &uSize
, &pTextTemp
);
4428 pTextTemp
= pEntry
->pText
;
4431 iCmp
= str_icmp(pText
, pTextTemp
);
4434 iCount
-= (iCount
+ 1) / 2;
4439 iCount
-= iCount
/ 2 + 1;
4441 uItem
= pItems
[uNext
]->uNextItem
;
4445 uBefore
= pEntry
->uPrevItem
;
4451 pData
->cLockChanges
= 0;
4453 pNew
->uNextItem
= uItem
;
4454 pNew
->uPrevItem
= uBefore
;
4456 if(uBefore
) { // Vorherigen Eintrag anpassen
4457 pEntry
= pItems
[uBefore
];
4458 pEntry
->uNextItem
= uPos
;
4459 } else { // Am Anfang einfügen
4463 if(uItem
) { // Nächsten Eintrag anpassen
4464 pEntry
= pItems
[uItem
];
4465 pEntry
->uPrevItem
= uPos
;
4466 } else { // Am Ende anhängen
4471 case U(TVI_AFTER
): // Nach einem Eintrag einfügen
4474 if(pParent
) { // Einen Root-Eintrag einfügen
4475 pParent
->bFlags
= bFlag
;
4476 uParent
= pParent
->uParent
;
4477 pParent
= pItems
[uParent
];
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
;
4493 if(pParent
->bFlags
& TVIX_VARBUTTON
) {
4494 pParent
->bFlags
|= TVIX_HASBUTTON
;
4500 : // Hinter einen Eintrag einfügen
4503 if(!uItem
) { // Gibt es keine Kindeinträge
4509 if(uAfter
> pData
->uTreeItemsMax
) {
4510 if((uAfter
& 0xFFF00000) == 0xFFE00000) { // In einer genauen Reihe nach Patent einfügen
4514 if(!uItem
) { // Gibt es keine Kindeinträge
4520 if(uAfter
== 0) { // In die erste Reihe einfügen
4521 pEntry
= pItems
[uItem
];
4522 pEntry
->uPrevItem
= uPos
;
4523 pNew
->uNextItem
= uItem
;
4530 // Suche Einfügereihe
4531 for(; uItem
; uItem
= pItems
[uItem
]->uNextItem
) {
4534 if(uNum
== uAfter
) {
4535 uItem
= pItems
[uItem
]->uNextItem
;
4542 pNew
->uNextItem
= uItem
;
4543 pNew
->uPrevItem
= uBefore
;
4545 if(uBefore
) { // Vorherigen Eintrag anpassen
4546 pEntry
= pItems
[uBefore
];
4547 pEntry
->uNextItem
= uPos
;
4548 } else { // Am Anfang einfügen
4552 if(uItem
) { // Nächsten Eintrag anpassen
4553 pEntry
= pItems
[uItem
];
4554 pEntry
->uPrevItem
= uPos
;
4555 } else { // Am Ende anhängen
4564 pEntry
= pItems
[uAfter
];
4567 if(pEntry
&& uParent
== pEntry
->uParent
) { // Stimmt der Elterneintrag ?
4568 uItem
= pEntry
->uNextItem
;
4573 pEntry
= pItems
[uBefore
];
4576 pNew
->uNextItem
= uItem
;
4577 pNew
->uPrevItem
= uBefore
;
4579 if(uBefore
) { // Vorherigen Eintrag anpassen
4580 pEntry
->uNextItem
= uPos
;
4581 } else { // Am Anfang einfügen
4585 if(uItem
) { // Nächsten Eintrag anpassen
4586 pEntry
= pItems
[uItem
];
4587 pEntry
->uPrevItem
= uPos
;
4588 } else { // Am Ende anhängen
4595 pItems
[uPos
] = pNew
;
4596 pData
->uTreeItemsCount
++;
4597 // Die Anzeigezeilen akualisieren
4598 if(!pParent
|| !uFirst
|| (pParent
->uState
& TVIS_EXPANDED
)) {
4599 uItem
= pNew
->uPrevItem
;
4604 UpdateItems(pData
, 0);
4606 pEntry
= pItems
[uItem
];
4607 if(pEntry
&& pEntry
->uShowPos
)
4608 UpdateItems(pData
, uItem
);
4612 if(pNew
->uState
& TVIS_SELECTED
) { // Den ausgewählten Eintrag auswählen
4613 TreeListSelectItem(pData
, uPos
, 0, TVC_UNKNOWN
);
4619 //*****************************************************************************
4623 //*****************************************************************************
4624 // Ändert einen Eintrag im Fenster
4625 // pData : Zeiger auf die Fensterdaten
4626 // pItem : Zeiger auf die ein zu ändernden Daten
4627 // Ergibt 1 wenn ok oder 0 bei einem Fehler
4628 static int TreeListSetItem(TreeListData
*pData
, const TV_ITEM
*pItem
) {
4646 uItem
= U(pItem
->hItem
);
4647 if(uItem
> pData
->uTreeItemsMax
)
4650 pEntry
= pData
->pTreeItems
[uItem
];
4654 uBits
= pItem
->mask
;
4656 if(uBits
& TVIF_SUBITEM
) { // Einen Extraeintrag ändern
4657 uSub
= pItem
->cChildren
;
4659 if(uSub
>= pData
->uColumnCount
)
4661 pList
= pData
->pExtraItems
[uSub
- 1];
4662 pExtra
= pList
[uItem
];
4664 if(!pExtra
) { // Einen neuen Eintrag erzeugen
4665 pExtra
= new(ExtraItem
, 1);
4666 memset(pExtra
, 0, sizeof(ExtraItem
));
4667 pExtra
->iImage
= TV_NOIMAGE
;
4668 pExtra
->uState
= pEntry
->uState
& (TVIS_BOLD
| TVIS_UNDERLINE
);
4669 pList
[uItem
] = pExtra
;
4672 if(uBits
& TVIF_PARAM
) {
4673 pEntry
->lParam
= pItem
->lParam
;
4676 if((uBits
& TVIF_IMAGE
) && pExtra
->iImage
!= pItem
->iImage
) {
4679 pExtra
->iImage
= pItem
->iImage
;
4680 if(pExtra
->iImage
== I_IMAGECALLBACK
)
4681 pExtra
->bCallback
|= TVIF_IMAGE
;
4683 pExtra
->bCallback
&= TVIF_IMAGE
;
4686 if(uBits
& TVIF_TEXT
) { // Einen neuen Text einstellen
4687 if(pItem
->pszText
== LPSTR_TEXTCALLBACK
) {
4689 delete(pExtra
->pText
);
4690 pExtra
->bCallback
|= TVIF_TEXT
;
4691 pExtra
->uTextSize
= 0;
4695 uLen
= str_len(pItem
->pszText
);
4697 if(uLen
> pExtra
->uTextSize
|| !pExtra
->pText
) {
4699 delete(pExtra
->pText
);
4700 pExtra
->pText
= new(TCHAR
, uLen
+ 1);
4703 memcpy(pExtra
->pText
, pItem
->pszText
, (uLen
+ 1)*sizeof(TCHAR
));
4704 pExtra
->bCallback
&= ~TVIF_TEXT
;
4705 pExtra
->uTextSize
= (WORD
)uLen
;
4706 pExtra
->iTextPixels
= 0;
4711 if(uBits
& TVIF_STATE
) { // Den Status ändern
4712 uMask
= pItem
->stateMask
&~TVIS_BASEFLAGS
;
4713 uBits
= uMask
& (pExtra
->uState
^ pItem
->state
);
4714 uBits
|= (pItem
->stateMask
& TVIS_BASEFLAGS
) & (pEntry
->uState
^ pItem
->state
);
4715 pExtra
->uState
&= ~uMask
;
4716 pExtra
->uState
|= uMask
& pItem
->state
;
4718 if((uBits
& (TVIS_OVERLAYMASK
| TVIS_CUT
)) && (pData
->hImages
|| pData
->aColumn
[uSub
].bEdit
>= TVAX_CHECK
)) {
4719 uChange
= 1; // Ein Icon hats sich verändert
4722 if(uBits
& (TVIS_BOLD
| TVIS_DROPHILITED
)) {
4723 pExtra
->iTextPixels
= 0;
4727 if((uBits
& TVIS_EXPANDED
) && pEntry
->uFirstChild
) {
4728 iVal
= TreeListToggleItem(pData
, uItem
, 0);
4732 pEntry
= pData
->pTreeItems
[uItem
];
4737 if(uBits
& TVIS_SELECTED
) { // Hat sich die Auswahl geändert
4738 iVal
= (pData
->uStyleEx
& TVS_EX_SUBSELECT
) ? uSub
: 0;
4740 if(pItem
->state
& TVIS_SELECTED
) {
4741 iRet
= TreeListSelectItem(pData
, uItem
, iVal
, TVC_UNKNOWN
);
4743 if(pData
->uStyleEx
& TVS_EX_MULTISELECT
) {
4744 TreeListSelectItem(pData
, 0 , 0, TVC_UNKNOWN
);
4745 iRet
= TreeListXorSelectItem(pData
, uItem
, TVC_UNKNOWN
);
4747 iRet
= TreeListSelectItem(pData
, 0, 0, TVC_UNKNOWN
);
4750 pEntry
= pData
->pTreeItems
[uItem
];
4755 pList
= pData
->pExtraItems
[uSub
- 1];
4756 pExtra
= pList
[uItem
];
4766 if(!uChange
|| !pEntry
->uShowPos
)
4767 return 1; // Neuzeichnen des Eintrages
4769 UpdateRect(pData
, uItem
, uSub
);
4774 uBits
&= ~TVIF_CHILDREN
;
4777 //******************** Einen Basis Eintrag ändern *****************************
4778 if(uBits
& TVIF_PARAM
) {
4779 pEntry
->lParam
= pItem
->lParam
;
4782 if((uBits
& TVIF_IMAGE
) && pEntry
->iImage
!= pItem
->iImage
) {
4783 pEntry
->iImage
= pItem
->iImage
;
4784 if(!(pEntry
->uState
& TVIS_SELECTED
) && pData
->hImages
)
4786 if(pEntry
->iImage
== I_IMAGECALLBACK
)
4787 pEntry
->bCallback
|= TVIF_IMAGE
;
4789 pEntry
->bCallback
&= TVIF_IMAGE
;
4792 if((uBits
& TVIF_SELECTEDIMAGE
) && pEntry
->iSelectedImage
!= pItem
->iSelectedImage
) {
4793 pEntry
->iSelectedImage
= pItem
->iSelectedImage
;
4794 if((pEntry
->uState
& TVIS_SELECTED
) && pData
->hImages
)
4796 if(pEntry
->iSelectedImage
== I_IMAGECALLBACK
)
4797 pEntry
->bCallback
|= TVIF_SELECTEDIMAGE
;
4799 pEntry
->bCallback
&= TVIF_SELECTEDIMAGE
;
4802 if(uBits
& TVIF_CHILDREN
) {
4803 bCall
= pEntry
->bCallback
;
4804 bFlags
= pEntry
->bFlags
;
4806 switch(pItem
->cChildren
) {
4808 pEntry
->bCallback
&= ~TVIF_CHILDREN
;
4809 pEntry
->bFlags
&= ~TVIX_HASBUTTON
;
4810 pEntry
->bFlags
|= TVIX_VARBUTTON
;
4814 pEntry
->bCallback
&= ~TVIF_CHILDREN
;
4815 pEntry
->bFlags
&= TVIX_VARBUTTON
;
4816 pEntry
->bFlags
|= TVIX_HASBUTTON
;
4820 pEntry
->bCallback
|= TVIF_CHILDREN
;
4821 pEntry
->bFlags
&= ~TVIX_VARBUTTON
;
4826 pEntry
->bCallback
&= ~TVIF_CHILDREN
;
4827 pEntry
->bFlags
|= TVIX_VARBUTTON
;
4829 if(pEntry
->uFirstChild
)
4830 pEntry
->bFlags
|= TVIX_HASBUTTON
;
4832 pEntry
->bFlags
&= ~TVIX_HASBUTTON
;
4835 if(bCall
!= pEntry
->bCallback
|| bFlags
!= pEntry
->bFlags
) {
4840 if(uBits
& TVIF_TEXT
) { // Einen neuen Text einstellen
4841 if(pItem
->pszText
== LPSTR_TEXTCALLBACK
) {
4843 delete(pEntry
->pText
);
4844 pEntry
->bCallback
|= TVIF_TEXT
;
4845 pEntry
->uTextSize
= 0;
4849 uLen
= str_len(pItem
->pszText
);
4851 if(uLen
> pEntry
->uTextSize
) {
4853 delete(pEntry
->pText
);
4854 pEntry
->pText
= new(TCHAR
, uLen
+ 1);
4857 memcpy(pEntry
->pText
, pItem
->pszText
, (uLen
+ 1)*sizeof(TCHAR
));
4858 pEntry
->bCallback
&= ~TVIF_TEXT
;
4859 pEntry
->uTextSize
= (WORD
)uLen
;
4860 pEntry
->iTextPixels
= 0;
4865 if(uBits
& TVIF_STATE
) {
4866 uMask
= pItem
->stateMask
;
4868 if(pData
->uStyle
& TVS_SINGLEEXPAND
) { // Nicht aufklappen bei Einzelmodus
4869 uMask
&= ~TVIS_EXPANDED
;
4872 uBits
= uMask
& (pEntry
->uState
^ pItem
->state
);
4873 pEntry
->uState
&= ~uMask
;
4874 pEntry
->uState
|= uMask
& pItem
->state
;
4877 if((uBits
& (TVIS_OVERLAYMASK
| TVIS_CUT
)) && pData
->hImages
) {
4881 if(uBits
& TVIS_STATEIMAGEMASK
) { // Haben sich die State-Bits verändert
4882 if(pData
->hStates
) {
4886 if(pData
->uStyleEx
& TVS_EX_BITCHECKBOX
) {
4887 if(pEntry
->uState
& 0x1000) {
4888 pData
->uSingleSel
= uItem
;
4890 if(pData
->uSingleSel
== uItem
) {
4891 pData
->uSingleSel
= 0;
4894 if((pEntry
->uState
& TVIS_STATEIMAGEMASK
) == 0x2000) {
4895 pData
->uSingleSel
= uItem
;
4897 if(pData
->uSingleSel
== uItem
) {
4898 pData
->uSingleSel
= 0;
4903 if(uBits
& (TVIS_BOLD
| TVIS_DROPHILITED
)) {
4904 pEntry
->iTextPixels
= 0;
4908 if(uBits
& TVIS_SELECTED
) { // Hat sich die Auswahl geändert
4909 pEntry
->uState
^= TVIS_SELECTED
;
4911 if(pItem
->state
& TVIS_SELECTED
) {
4912 iRet
= TreeListSelectItem(pData
, uItem
, 0, TVC_UNKNOWN
);
4914 if(pData
->uStyleEx
& TVS_EX_MULTISELECT
) {
4915 TreeListSelectItem(pData
, 0 , 0, TVC_UNKNOWN
);
4916 iRet
= TreeListXorSelectItem(pData
, uItem
, TVC_UNKNOWN
);
4918 iRet
= TreeListSelectItem(pData
, 0, 0, TVC_UNKNOWN
);
4921 pEntry
= pData
->pTreeItems
[uItem
];
4930 if((uBits
& TVIS_EXPANDED
) && pEntry
->uFirstChild
) { // Sollen Teile auf/zugeklappt werden
4931 uMask
&= TVIS_EXPANDPARTIAL
| TVIS_EXPANDPARTIAL
;
4932 pEntry
->uState
^= TVIS_EXPANDED
;
4933 pEntry
->uState
^= uBits
& uMask
;
4934 iVal
= uMask
& pItem
->state
;
4936 iRet
= TreeListToggleItem(pData
, uItem
, iVal
);
4937 if(iRet
) { // Abbruch oder Fehler beim Auf/Zuklappen
4938 if(uChange
&& pEntry
->uShowPos
) { // Neuzeichnen des Eintrages
4939 UpdateRect(pData
, uItem
, 0);
4945 pEntry
->uState
&= ~uMask
;
4946 pEntry
->uState
|= iVal
;
4950 if(uChange
&& pEntry
->uShowPos
) { // Neuzeichnen des Eintrages
4951 UpdateRect(pData
, uItem
, 0);
4957 //*****************************************************************************
4961 //*****************************************************************************
4962 // Daten vone einem Eintrag abfragen
4963 // pData : Zeiger auf die Fensterdaten
4964 // pItem : Zeiger auf die den Datenspeicher
4965 // Ergibt 1 wenn ok oder 0 bei einem Fehler
4966 static unsigned TreeListGetItem(TreeListData
*pData
, TV_ITEM
*pItem
) {
4976 uItem
= U(pItem
->hItem
);
4977 if(uItem
> pData
->uTreeItemsMax
)
4980 pEntry
= pData
->pTreeItems
[uItem
];
4984 uBits
= pItem
->mask
;
4986 if(uBits
& TVIF_SUBITEM
) { // Einen Extraeintrag abfragen
4987 uSub
= pItem
->cChildren
;
4989 if(uSub
>= pData
->uColumnCount
)
4991 pList
= pData
->pExtraItems
[uSub
- 1];
4992 pExtra
= pList
[uItem
];
4994 if(!pExtra
) { // Einen neuen Eintrag erzeugen
4995 pExtra
= new(ExtraItem
, 1);
4996 memset(pExtra
, 0, sizeof(ExtraItem
));
4997 pExtra
->iImage
= TV_NOIMAGE
;
4998 pExtra
->uState
= pEntry
->uState
& (TVIS_BOLD
| TVIS_UNDERLINE
);
4999 pList
[uItem
] = pExtra
;
5002 if(uBits
& TVIF_PARAM
) {
5003 pItem
->lParam
= pEntry
->lParam
;
5006 if(uBits
& TVIF_IMAGE
) {
5007 pItem
->iImage
= pExtra
->iImage
;
5010 if(uBits
& TVIF_TEXT
) { // Einen neuen Text einstellen
5011 if(pExtra
->pText
== LPSTR_TEXTCALLBACK
) {
5012 pItem
->pszText
= LPSTR_TEXTCALLBACK
;
5014 if(uBits
& TVIF_TEXTPTR
) {
5015 if(!pExtra
->pText
) {
5016 pItem
->pszText
= _T("");
5017 pItem
->cchTextMax
= 0;
5019 pItem
->pszText
= pExtra
->pText
;
5020 pItem
->cchTextMax
= pExtra
->uTextSize
+ 1;
5024 uLen
= pExtra
->uTextSize
+ 1;
5025 if(pItem
->cchTextMax
< (int)uLen
) {
5026 if(pItem
->cchTextMax
<= 0) {
5029 uLen
= pItem
->cchTextMax
- 1;
5030 pItem
->pszText
[uLen
] = 0;
5034 memcpy(pItem
->pszText
, pExtra
->pText
, uLen
* sizeof(TCHAR
));
5036 if(pItem
->cchTextMax
> 0) {
5037 pItem
->pszText
[0] = 0;
5043 if(uBits
& TVIF_STATE
) {
5044 pItem
->state
= pExtra
->uState
&~TVIS_BASEFLAGS
;
5045 pItem
->state
&= pItem
->stateMask
;
5051 if(pEntry
->bCallback
& TVIF_CHILDREN
)
5052 pItem
->cChildren
= I_CHILDRENCALLBACK
;
5054 pItem
->cChildren
= (pEntry
->uFirstChild
) ? 1 : 0;
5056 uBits
&= ~TVIF_CHILDREN
;
5060 //******************** Einen Basis Eintrag ändern *****************************
5061 if(uBits
& TVIF_PARAM
) {
5062 pItem
->lParam
= pEntry
->lParam
;
5065 if(uBits
& TVIF_IMAGE
) {
5066 pItem
->iImage
= pEntry
->iImage
;
5069 if(uBits
& TVIF_SELECTEDIMAGE
) {
5070 pItem
->iSelectedImage
= pEntry
->iSelectedImage
;
5073 if(uBits
& TVIF_CHILDREN
) {
5074 if(pEntry
->bCallback
& TVIF_CHILDREN
)
5075 pItem
->cChildren
= I_CHILDRENCALLBACK
;
5077 pItem
->cChildren
= (pEntry
->uFirstChild
) ? 1 : 0;
5080 if(uBits
& TVIF_TEXT
) { // Einen neuen Text einstellen
5081 if(pEntry
->pText
== LPSTR_TEXTCALLBACK
) {
5082 pItem
->pszText
= LPSTR_TEXTCALLBACK
;
5084 if(uBits
& TVIF_TEXTPTR
) {
5085 pItem
->pszText
= pEntry
->pText
;
5086 pItem
->cchTextMax
= pEntry
->uTextSize
+ 1;
5088 uLen
= pEntry
->uTextSize
+ 1;
5089 if(pItem
->cchTextMax
< (int)uLen
) {
5090 if(pItem
->cchTextMax
<= 0) {
5093 uLen
= pItem
->cchTextMax
- 1;
5094 pItem
->pszText
[uLen
] = 0;
5098 memcpy(pItem
->pszText
, pEntry
->pText
, uLen
* sizeof(TCHAR
));
5102 if(uBits
& TVIF_STATE
) {
5103 pItem
->state
= pEntry
->uState
;
5104 pItem
->state
&= pItem
->stateMask
;
5110 //*****************************************************************************
5112 //* TreeListDeleteColumn
5114 //*****************************************************************************
5115 // Löscht eine Spalte aus dem Header
5116 // pData : Zeiger auf die Fensterdaten
5117 // uCol : Ist die Nummer der Spalte die gelöscht werden soll
5118 // Ergibt 1 wenn die Spalte gelöscht wurde
5119 static int TreeListDeleteColumn(TreeListData
*pData
, unsigned uCol
) {
5139 if(uCol
>= pData
->uColumnCount
)
5142 if(uCol
&& uCol
== pData
->uSelectedSub
) { // Ist die Auswahl in der Spalte
5143 TreeListSelectItem(pData
, pData
->uSelectedItem
, 0, TVC_UNKNOWN
);
5146 if(uCol
&& uCol
== pData
->uEditSub
) {
5147 pData
->uEditSub
= 0;
5148 pData
->uEditItem
= 0;
5149 TreeListEndLabelEdit(pData
, 0);
5152 if(uCol
&& uCol
== pData
->uFocusSub
) {
5153 pData
->uFocusSub
= 0;
5154 pData
->uFocusItem
= 0;
5157 if(uCol
== pData
->uTrackedSub
) {
5158 pData
->uTrackedSub
= 0;
5159 pData
->uTrackedItem
= 0;
5162 GetClientRect(pData
->hWnd
, &sRect
);
5164 iDelta
= pData
->aColumn
[uCol
].sSize
;
5165 iSub
= pData
->aColumn
[uCol
].bWeight
;
5171 for(uPos
= 0; uPos
< pData
->uColumnCount
; uPos
++) { // Zählern der variablen Spalten
5174 if(pData
->aColumn
[uPos
].bWeight
== 0) {
5175 iFix
+= pData
->aColumn
[uPos
].sSize
;
5179 iVar
+= pData
->aColumn
[uPos
].sSize
;
5180 iAll
+= pData
->aColumn
[uPos
].bWeight
;
5184 Header_DeleteItem(pData
->hHeader
, uCol
);
5185 pData
->uColumnCount
--;
5187 if(pData
->uColumnCount
> 0) { // Liste mit Extraeinträgen löschen
5192 pList
= pData
->pExtraItems
[iNum
];
5194 for(uItem
= 0; uItem
<= pData
->uTreeItemsMax
; uItem
++) { // Alle Einträge aus der Liste löschen
5195 pExtra
= pList
[uItem
];
5200 pExtra
->uTextSize
= 0;
5201 delete(pExtra
->pText
);
5207 memmove(pData
->pExtraItems
+ iNum
, pData
->pExtraItems
+ iNum
+ 1, sizeof(pList
) * (MAX_COLUMNS
- 1 - iNum
));
5208 pData
->pExtraItems
[pData
->uColumnCount
] = NULL
;
5215 if(pData
->aColumn
[uCol
].bWeight
) {
5216 pData
->uColumnCountVar
--;
5219 if(pData
->aColumn
[uCol
].bMark
) {
5220 pData
->uMarkedCols
--;
5223 uSub
= pData
->aColumnPos
[uCol
];
5225 memmove(pData
->aColumn
+ uCol
, pData
->aColumn
+ uCol
+ 1, (MAX_COLUMNS
- 1 - uCol
)*sizeof(ColumnData
));
5227 for(uIndex
= 0; uIndex
< uSub
; uIndex
++) { // Zuordnungs-Array anpassen
5228 bItem
= pData
->aColumnPos
[uIndex
- 1];
5233 pData
->aColumnPos
[uIndex
] = bItem
;
5236 for(; uIndex
<= pData
->uColumnCount
; uIndex
++) { // Spaltenpositionen verschieben
5237 bItem
= pData
->aColumnPos
[uIndex
+ 1];
5243 pData
->aColumnPos
[uIndex
] = bItem
;
5246 for(uIndex
= pData
->uColumnCount
; uIndex
> 0;) {
5248 bByte
= pData
->aColumn
[uIndex
].bIndex
;
5252 pData
->aColumn
[uIndex
].bIndex
= bByte
;
5255 pData
->aColumn
[uIndex
].bNext
= pData
->aColumnPos
[bByte
+ 1];
5258 pData
->iFixSize
= iFix
;
5259 pData
->iAllWeight
= iAll
;
5260 pData
->aColumn
[pData
->uColumnCount
].bWeight
= 0;
5262 if(iCnt
&& iDelta
) { // Variable Breiten anpassen
5263 ChangeColSize(pData
, iDelta
);
5266 pData
->iVarSize
= 0;
5270 if(pData
->uSelectedSub
> uCol
) { // Ist die Auswahl vor der Spalte
5271 pData
->uSelectedSub
--;
5274 if(pData
->uEditSub
> uCol
) {
5278 if(pData
->uFocusSub
> uCol
) {
5282 if(pData
->uTrackedSub
> uCol
) {
5283 pData
->uTrackedSub
--;
5286 if(!pData
->uColumnCount
) { // Den Header löschen
5287 DestroyWindow(pData
->hHeader
);
5288 pData
->hHeader
= NULL
;
5289 pData
->uStartPixel
= 0;
5290 pData
->iRowHeight
= 1;
5291 UpdateHeight(pData
);
5292 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
5295 iXoff
= UpdateColumns(pData
); // Hat sich die Spaltenbreiten verändert
5296 if(iXoff
< 0x10000) {
5298 sRect
.left
-= pData
->uScrollX
;
5299 sRect
.top
= pData
->uStartPixel
;
5300 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
5303 UpdateScrollX(pData
);
5309 //*****************************************************************************
5311 //* TreeListInsertColumn
5313 //*****************************************************************************
5314 // Adds a new column in the header
5315 // pData : Zeiger auf die Fensterdaten
5316 // uCol : Ist die Nummer der Spalte die eingefügt wird
5317 // pInsert : Zeiger auf die ein zu fügenden Daten
5318 // Returns the positio of the new column or -1 if an error occurs.
5319 static int TreeListInsertColumn(TreeListData
*pData
, unsigned uCol
, TV_COLUMN
*pColumn
) {
5345 GetClientRect(pData
->hWnd
, &sRect
);
5347 if(!pData
->hHeader
) { // Create a new header
5348 iStart
= bDrawWithTheme
? GetSystemMetrics(SM_CYHSCROLL
) : 17; //SM_CYHSCROLL is not enough tall with themes disabled apps;
5349 iYoff
= sRect
.top
+ iStart
;
5351 if(pData
->uStyleEx
& TVS_EX_HIDEHEADERS
) {
5355 pData
->hHeader
= CreateWindow(WC_HEADER
, NULL
, WS_VISIBLE
| WS_CHILD
| HDS_HORZ
| HDS_BUTTONS
| HDS_DRAGDROP
, sRect
.left
, sRect
.top
, sRect
.right
, iYoff
, pData
->hWnd
, (HMENU
)1, NULL
, NULL
);
5359 pData
->uStartPixel
= (pData
->uStyleEx
& TVS_EX_HIDEHEADERS
) ? 0 : iStart
;
5360 pData
->iRowHeight
= 1;
5361 UpdateHeight(pData
);
5363 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
5364 if(pData
->uStyleEx
& TVS_EX_HEADEROWNIMGLIST
){
5365 SendMessage(pData
->hHeader
, HDM_SETIMAGELIST
, 0, (LPARAM
)pData
->hHeadImg
);
5367 SendMessage(pData
->hHeader
, HDM_SETIMAGELIST
, 0, (LPARAM
)pData
->hImages
);
5369 SendMessage(pData
->hHeader
, WM_SETFONT
, (WPARAM
)hDefaultFontN
, 0);
5371 if(pData
->uSizeX
<= pData
->uStartPixel
)
5372 pData
->uSizeYsub
= 0;
5374 pData
->uSizeYsub
= pData
->uSizeX
- pData
->uStartPixel
;
5377 if(pData
->uColumnCount
>= MAX_COLUMNS
) { // Prüfe die Anzahl der Spalten
5381 memset(&sItem
, 0, sizeof(sItem
)); // Die Spaltendaten zusammenstellen
5383 if(uCol
>= pData
->uColumnCount
) {
5384 uCol
= pData
->uColumnCount
;
5387 if(pColumn
->mask
& TVCF_FMT
) { // text alignment
5388 sItem
.mask
|= HDI_FORMAT
;
5389 sItem
.fmt
= pColumn
->fmt
;
5391 switch(sItem
.fmt
& HDF_JUSTIFYMASK
) {
5406 if(pColumn
->mask
& TVCF_IMAGE
) { // Hat die Spalte auch ein Icon
5407 sItem
.mask
|= HDI_IMAGE
;
5408 sItem
.iImage
= pColumn
->iImage
;
5411 if(pColumn
->mask
& TVCF_TEXT
) { // Auch einen Text übergeben
5412 sItem
.mask
|= HDI_TEXT
;
5413 sItem
.pszText
= pColumn
->pszText
;
5416 if(pColumn
->mask
& TVCF_MIN
) { // Auch einen Min-Wert übergeben
5417 iMin
= pColumn
->iOrder
;
5429 if(pColumn
->mask
& TVCF_WIDTH
) { // Fixe Breite für die Spalte
5431 sItem
.mask
|= HDI_WIDTH
;
5432 sItem
.cxy
= pColumn
->cx
;
5433 iSize
= pColumn
->cx
;
5434 iDelta
= -pColumn
->cx
;
5436 } else { // Variable vordefinierte Breite
5437 if(pColumn
->mask
& TVCF_VWIDTH
)
5438 iWeight
= pColumn
->cx
;
5442 iVar
= pData
->iVarSize
;
5443 iFix
= pData
->iFixSize
;
5444 iAll
= pData
->iAllWeight
;
5445 iSize
= pData
->uSizeX
- iVar
- iFix
;
5452 if(pData
->uColumnCountVar
) { // Gibt es schon variable Spalten
5453 iSize
= (iVar
* iWeight
) / (iAll
+ iWeight
);
5459 sItem
.mask
|= HDI_WIDTH
;
5463 if(sItem
.cxy
< iMin
)
5467 uCol
= Header_InsertItem(pData
->hHeader
, uCol
, &sItem
);
5468 if(uCol
& 0x80000000)
5471 if(pData
->uColumnCount
> 0) { // Liste mit Extraeinträgen erzeugen
5472 pList
= new(ExtraItem
*, pData
->uTreeItemsMax
+ 1);
5474 Header_DeleteItem(pData
->hHeader
, uCol
);
5478 memset(pList
, 0, sizeof(ExtraItem
*) * (pData
->uTreeItemsMax
+ 1));
5484 memmove(pData
->pExtraItems
+ iNum
+ 1, pData
->pExtraItems
+ iNum
, sizeof(pList
) * (MAX_COLUMNS
- 2 - iNum
));
5485 pData
->pExtraItems
[iNum
] = pList
;
5488 memmove(pData
->aColumn
+ uCol
+ 1, pData
->aColumn
+ uCol
, (MAX_COLUMNS
- 1 - uCol
)*sizeof(ColumnData
));
5490 for(uIndex
= pData
->uColumnCount
+ 2; uIndex
> uCol
; uIndex
--) { // Zuordnungs-Array anpassen
5491 bItem
= pData
->aColumnPos
[uIndex
- 1];
5495 pData
->aColumnPos
[uIndex
] = bItem
;
5498 pData
->aColumnPos
[uCol
] = (BYTE
)uCol
;
5503 bItem
= pData
->aColumnPos
[uIndex
];
5508 pData
->aColumnPos
[uIndex
] = bItem
;
5511 for(uIndex
= pData
->uColumnCount
;;) { // Folgende Spalten verschieben
5512 bByte
= pData
->aColumn
[uIndex
].bIndex
;
5516 pData
->aColumn
[uIndex
].bIndex
= bByte
;
5527 if(pColumn
->mask
& TVCF_MARK
) // Ist die Spalte markiert
5528 if(pColumn
->fmt
& TVCFMT_MARK
) {
5532 if(pColumn
->mask
& TVCF_FIXED
) // Ist die Spalte fixiert
5533 if(pColumn
->fmt
& TVCFMT_FIXED
) {
5534 sFixed
= (short)((sItem
.cxy
> 0) ? sItem
.cxy
: 100);
5537 pData
->aColumn
[uCol
].bWeight
= (BYTE
)iWeight
;
5538 pData
->aColumn
[uCol
].sReal
= (short)sItem
.cxy
;
5539 pData
->aColumn
[uCol
].sSize
= (short)iSize
;
5540 pData
->aColumn
[uCol
].sMin
= (short)iMin
;
5541 pData
->aColumn
[uCol
].bIndex
= (BYTE
)uCol
;
5542 pData
->aColumn
[uCol
].bMinEx
= bMinEx
;
5543 pData
->aColumn
[uCol
].bAlign
= bAlign
;
5544 pData
->aColumn
[uCol
].bMark
= bMark
;
5545 pData
->aColumn
[uCol
].sFixed
= sFixed
;
5546 pData
->uMarkedCols
+= bMark
;
5549 for(uIndex
= pData
->uColumnCount
;;) { // Nächste sichtbare Spalten aktualisieren
5550 bByte
= pData
->aColumn
[uIndex
].bIndex
;
5551 pData
->aColumn
[uIndex
].bNext
= pData
->aColumnPos
[bByte
+ 1];
5557 if(pData
->uColumnCountVar
) { // Variable Breiten anpassen
5559 ChangeColSize(pData
, iDelta
);
5560 pData
->iVarSize
-= iDelta
;
5563 pData
->iFixSize
+= iSize
;
5567 pData
->iVarSize
= iSize
;
5569 pData
->iFixSize
+= iSize
;
5572 pData
->iAllWeight
+= iWeight
;
5573 pData
->uColumnCountVar
+= iAdd
;
5574 pData
->uColumnCount
+= 1;
5576 if(pData
->uSelectedSub
> 0 && pData
->uSelectedSub
>= uCol
) {
5577 pData
->uSelectedSub
++;
5580 if(pData
->uTrackedSub
> 0 && pData
->uTrackedSub
>= uCol
) {
5581 pData
->uTrackedSub
++;
5584 if(pData
->uFocusSub
> 0 && pData
->uFocusSub
>= uCol
) {
5588 if(pData
->uEditSub
> 0 && pData
->uEditSub
>= uCol
) {
5592 iXoff
= UpdateColumns(pData
); // Hat sich die Spaltenbreiten verändert
5593 if(iXoff
< 0x10000) {
5595 sRect
.left
-= pData
->uScrollX
;
5596 sRect
.top
= pData
->uStartPixel
;
5597 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
5600 UpdateScrollX(pData
);
5602 if(pData
->uInsertMark
) { // Fehlende Infomarken einfügen
5606 sSet
.mask
= TVIF_SUBITEM
;
5607 sSet
.hItem
= (HTREEITEM
)pData
->uInsertMark
;
5608 sSet
.cChildren
= uCol
;
5610 TreeListSetItem(pData
, &sSet
);
5612 pExtra
= pData
->pExtraItems
[uCol
- 1][pData
->uInsertMark
];
5614 pExtra
->uColorBk
= pData
->uColors
[TVC_INSERT
];
5615 pExtra
->bFlags
|= TVIX_BKCOLOR
;
5619 if(pData
->uStyleEx
& TVS_EX_HEADERCHGNOTIFY
) { // Geänderte Spalten melden
5620 sNotify
.hdr
.code
= TVN_COLUMNCHANGED
;
5621 sNotify
.uColumn
= uCol
;
5622 sNotify
.uIndex
= pData
->aColumn
[uCol
].bIndex
;
5623 sNotify
.uPosX
= pData
->aColumnXpos
[uCol
];
5624 sNotify
.iSize
= pData
->aColumn
[uCol
].sReal
;
5627 SendNotify(pData
, &sNotify
.hdr
);
5634 //*****************************************************************************
5636 //* TreeListScanColumn
5638 //*****************************************************************************
5639 // Berechnet die Breite der sichtbaren Einträge einer Spalte
5640 // pData : Zeiger auf die Fensterdaten
5641 // uSub : Ist die Spalte
5642 // Ergibt sie gescannte Breite
5643 static int TreeListScanColumn(TreeListData
*pData
, unsigned uSub
) {
5654 if(uSub
>= pData
->uColumnCount
)
5657 if(uSub
> 0) { // Extraspalte
5658 pItems
= pData
->pExtraItems
[uSub
- 1];
5659 pPList
= pData
->pItemPos
;
5662 for(uPos
= 0; uPos
< pData
->uItemPosCount
; uPos
++) {
5663 pExtra
= pItems
[pPList
[uPos
]];
5670 if(pData
->hSubImg
&& (pExtra
->bFlags
& TVIX_HASIMAGE
))
5671 iPos
= pData
->iSubImgXsize
;
5675 iPos
+= pExtra
->iTextPixels
+ 8;
5683 pList
= pData
->pTreeItems
;
5684 pPList
= pData
->pItemPos
;
5687 for(uPos
= 0; uPos
< pData
->uItemPosCount
; uPos
++) { // Erste Spalte
5688 pEntry
= pList
[pPList
[uPos
]];
5690 if(pEntry
->bFlags
& TVIX_HASIMAGE
)
5691 iPos
= pData
->iImagesXsize
;
5695 iPos
+= pEntry
->uLevel
* pData
->iIndent
;
5696 iPos
+= pEntry
->iTextPixels
+ 8;
5701 if(pData
->uStyleEx
& TVS_EX_ITEMLINES
) {
5705 if(pData
->cHasRootRow
) {
5706 iMax
+= pData
->iIndent
;
5709 if(pData
->hStates
) {
5710 iMax
+= pData
->iStatesXsize
;
5717 //*****************************************************************************
5721 //*****************************************************************************
5722 // Prüft wo eine Koordinate im Fenster ist
5723 // pData : Zeiger auf die Fensterdaten
5724 // pInfo : Zeiger auf die ein zu fügenden Daten
5725 // Ergibt das Item auf dem die Koordinate zeigt
5726 static unsigned TreeListHitTest(TreeListData
*pData
, TV_HITTESTINFO
*pInfo
) {
5740 iXpos
= pInfo
->pt
.x
;
5741 iYpos
= pInfo
->pt
.y
;
5743 if((unsigned)iXpos
>= pData
->uSizeX
) {
5744 pInfo
->hItem
= NULL
;
5745 pInfo
->flags
= (iXpos
< 0) ? TVHT_TOLEFT
: TVHT_TORIGHT
;
5749 iYpos
-= pData
->uStartPixel
;
5751 if((unsigned)iYpos
>= pData
->uSizeY
) {
5752 pInfo
->hItem
= NULL
;
5753 pInfo
->flags
= (iYpos
< 0) ? TVHT_ABOVE
: TVHT_BELOW
;
5757 iZpos
= iYpos
/ pData
->iRowHeight
;
5758 iZpos
+= pData
->uScrollY
;
5760 if((unsigned)iZpos
>= pData
->uItemPosCount
) {
5761 pInfo
->hItem
= NULL
;
5762 pInfo
->flags
= TVHT_NOWHERE
;
5766 iXpos
+= pData
->uScrollX
;
5767 uItem
= pData
->pItemPos
[iZpos
];
5768 pEntry
= pData
->pTreeItems
[uItem
];
5769 pInfo
->hItem
= (HTREEITEM
)uItem
;
5774 uSub
= pData
->aColumnPos
[1];
5776 if(iXpos
>= pData
->aColumnXpos
[uSub
]) { // Auf Extraeintrag
5777 for(uCol
= 1; uCol
< pData
->uColumnCount
; uCol
++) {
5778 uSub
= pData
->aColumnPos
[uCol
];
5779 uNext
= pData
->aColumnPos
[uCol
+ 1];
5781 if(iXpos
>= pData
->aColumnXpos
[uNext
])
5783 iXpos
-= pData
->aColumnXpos
[uSub
];
5785 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
5788 if(pData
->aColumn
[uSub
].bEdit
>= TVAX_CHECK
) { // Hat der Extraeintrag ein Icon
5789 iIcon
= pData
->iChecksXsize
;
5791 if(pExtra
&& (pExtra
->bFlags
& TVIX_HASIMAGE
)) {
5792 iIcon
= pData
->iImagesXsize
;
5797 pInfo
->flags
= uSub
<< 24;
5799 if(iXpos
< iIcon
) { // Auf Icon
5800 pInfo
->flags
|= TVHT_ONSUBICON
;
5804 if(!pExtra
|| !pExtra
->uTextSize
) { // Auf Text wenn leerer Eintrag
5805 pInfo
->flags
|= TVHT_ONSUBLABEL
;
5809 switch(pData
->aColumn
[uSub
].bAlign
) { // Textausrichtung
5812 if(iXpos
- iIcon
< pExtra
->iTextPixels
+ 5) {
5813 pInfo
->flags
|= TVHT_ONSUBLABEL
;
5819 iWidth
= pData
->aColumnXpos
[uNext
];
5820 iWidth
-= pData
->aColumnXpos
[uSub
];
5822 if(iXpos
>= iWidth
- pExtra
->iTextPixels
- 5) {
5823 pInfo
->flags
|= TVHT_ONSUBLABEL
;
5829 iWidth
= pData
->aColumnXpos
[uNext
];
5830 iWidth
-= pData
->aColumnXpos
[uSub
];
5834 if(iXpos
>= iWidth
- pExtra
->iTextPixels
/ 2 - 3)
5835 if(iXpos
<= iWidth
+ pExtra
->iTextPixels
/ 2 + 3) {
5836 pInfo
->flags
|= TVHT_ONSUBLABEL
;
5842 pInfo
->flags
|= TVHT_ONSUBRIGHT
;
5847 pInfo
->flags
= TVHT_ONRIGHTSPACE
;
5852 if(!pData
->cHasRootRow
) { // Root-Linien ausgleichen
5853 iXpos
+= pData
->iIndent
;
5856 iXpos
-= pData
->iIndent
* pEntry
->uLevel
;
5858 if(iXpos
< pData
->iIndent
) { // Auf eingerücktem Bereich
5859 if(pData
->uStyle
& TVS_HASBUTTONS
)
5860 if(pEntry
->bFlags
& TVIX_HASBUTTON
) {
5861 if(iXpos
>= pData
->iShift
- 6)
5862 if(iXpos
<= pData
->iShift
+ 7) {
5863 iYpos
%= pData
->iRowHeight
;
5864 iYpos
-= pData
->iRowHeight
/ 2;
5866 if(iYpos
>= -6 && iYpos
<= 7) {
5867 pInfo
->flags
= TVHT_ONITEMBUTTON
;
5873 pInfo
->flags
= TVHT_ONITEMINDENT
;
5877 iXpos
-= pData
->iIndent
;
5879 if(pData
->uStyleEx
& TVS_EX_ITEMLINES
) {
5883 if(pData
->hStates
) { // Auf der Auswahl-Box
5884 iXpos
-= pData
->iStatesXsize
;
5887 pInfo
->flags
= TVHT_ONITEMSTATEICON
;
5892 if(pEntry
->bFlags
& TVIX_HASIMAGE
) { // Auf dem Icon
5893 iXpos
-= pData
->iImagesXsize
;
5895 if(pData
->uStyleEx
& TVS_EX_ITEMLINES
)
5899 pInfo
->flags
= TVHT_ONITEMICON
;
5904 if(iXpos
< pEntry
->iTextPixels
+ 5 || !pEntry
->pText
|| !pEntry
->pText
[0]) {
5905 pInfo
->flags
= TVHT_ONITEMLABEL
;
5907 pInfo
->flags
= TVHT_ONITEMRIGHT
;
5913 //*****************************************************************************
5915 //* TreeListSetTrackItem
5917 //*****************************************************************************
5918 // Setzt das den Einfügeeintrag
5919 // pData : Zeiger auf die Fensterdaten
5920 // uItem : Ist die Nummer des Eintrages bei dem eingefügt werden soll
5921 // iMode : 0=davor einfügen 1=nachher einfügen
5922 // Ergibt 1 wenn der Eintrag eingefügt wurde
5923 static unsigned TreeListSetInsertMark(TreeListData
*pData
, unsigned uItem
, int iMode
) {
5925 TV_INSERTSTRUCT sInsert
;
5931 if(pData
->uInsertMark
) {
5932 iRet
= TreeListDeleteItem(pData
, pData
->uInsertMark
, 1);
5933 pData
->uInsertMark
= 0;
5940 if(uItem
> pData
->uTreeItemsMax
)
5943 pEntry
= pData
->pTreeItems
[uItem
];
5948 uItem
= pEntry
->uPrevItem
;
5950 uItem
= U(TVI_FIRST
);
5953 sInsert
.hParent
= (HTREEITEM
)pEntry
->uParent
;
5954 sInsert
.hInsertAfter
= (HTREEITEM
)uItem
;
5955 sInsert
.item
.mask
= TVIF_SELECTEDIMAGE
| TVIF_IMAGE
;
5956 sInsert
.item
.iImage
= TV_NOIMAGE
;
5957 sInsert
.item
.iSelectedImage
= TV_NOIMAGE
;
5959 uItem
= TreeListInsertItem(pData
, &sInsert
);
5963 pEntry
= pData
->pTreeItems
[uItem
];
5964 pEntry
->uColorBk
= pData
->uColors
[TVC_INSERT
];
5965 pEntry
->bFlags
|= TVIX_BKCOLOR
;
5966 sInsert
.item
.mask
|= TVIF_SUBITEM
;
5967 sInsert
.item
.hItem
= (HTREEITEM
)uItem
;
5969 for(uSub
= 1; uSub
< pData
->uColumnCount
; uSub
++) {
5970 sInsert
.item
.cChildren
= uSub
;
5972 TreeListSetItem(pData
, &sInsert
.item
);
5974 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
5975 pExtra
->uColorBk
= pData
->uColors
[TVC_INSERT
];
5976 pExtra
->bFlags
|= TVIX_BKCOLOR
;
5979 pData
->uInsertMark
= uItem
;
5984 //*****************************************************************************
5986 //* TreeListGetItemColor
5988 //*****************************************************************************
5989 // Holt die Farbe eins Feldes
5990 // pData : Zeiger auf die Fensterdaten
5991 // uItem : Ist die Nummer des Eintrages
5992 // uSub : Ist die Spalte
5993 // iMode : 0=Hintergrundfarbe 1=Textfarbe abfragen
5994 // Ergibt die alte Farbe oder TV_NOCOLOR wenn keine Farbe eingestellt war
5995 static LRESULT
TreeListGetItemColor(TreeListData
*pData
, unsigned uItem
, unsigned uSub
, int iMode
) {
6001 if(uItem
> pData
->uTreeItemsMax
)
6004 pEntry
= pData
->pTreeItems
[uItem
];
6008 if(uSub
) { // Extra-Eintrag abfragen
6009 if(uSub
>= pData
->uColumnCount
)
6012 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
6017 uColor
= (pExtra
->bFlags
& TVIX_TEXTCOLOR
) ? pExtra
->uColorText
: TV_NOCOLOR
;
6019 uColor
= (pExtra
->bFlags
& TVIX_BKCOLOR
) ? pExtra
->uColorBk
: TV_NOCOLOR
;
6022 uColor
= (pEntry
->bFlags
& TVIX_TEXTCOLOR
) ? pEntry
->uColorText
: TV_NOCOLOR
;
6024 uColor
= (pEntry
->bFlags
& TVIX_BKCOLOR
) ? pEntry
->uColorBk
: TV_NOCOLOR
;
6027 return (LRESULT
)uColor
;
6030 //*****************************************************************************
6032 //* TreeListSetItemColor
6034 //*****************************************************************************
6035 // Setzt die Farbe eines Feldes
6036 // pData : Zeiger auf die Fensterdaten
6037 // uItem : Ist die Nummer des Eintrages
6038 // uSub : Ist die Spalte
6039 // uColor : Ist die neue Farbe
6040 // iMode : 0=Hintergrundfarbe 1=Textfarbe einstellen
6041 // Ergibt die alte Farbe oder TV_NOCOLOR wenn keine Farbe eingestellt war
6042 static COLORREF
TreeListSetItemColor(TreeListData
*pData
, unsigned uItem
, unsigned uSub
, COLORREF uColor
, int iMode
) {
6049 if(uItem
> pData
->uTreeItemsMax
)
6052 pEntry
= pData
->pTreeItems
[uItem
];
6056 if(uSub
>= 255) { // Die Ganze Zeile ändern
6057 if(pData
->uColumnCount
) {
6058 for(uSub
= pData
->uColumnCount
; uSub
> 0; uSub
--) {
6059 TreeListSetItemColor(pData
, uItem
, uSub
, uColor
, iMode
);
6066 if(uSub
) { // Extra-Eintrag verändern
6067 if(uSub
>= pData
->uColumnCount
)
6070 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
6071 if(!pExtra
) { // Extra-Eintrag erzeugen
6072 sSet
.mask
= TVIF_SUBITEM
;
6073 sSet
.hItem
= (HTREEITEM
)uItem
;
6074 sSet
.cChildren
= uSub
;
6076 if(!TreeListSetItem(pData
, &sSet
))
6079 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
6082 if(iMode
) { // Textfarbe
6083 uOld
= (pExtra
->bFlags
& TVIX_TEXTCOLOR
) ? pExtra
->uColorText
: TV_NOCOLOR
;
6085 if(uColor
== TV_NOCOLOR
) {
6086 pExtra
->bFlags
&= ~TVIX_TEXTCOLOR
;
6088 pExtra
->bFlags
|= TVIX_TEXTCOLOR
;
6089 pExtra
->uColorText
= uColor
;
6091 } else { // Hintergrund
6092 uOld
= (pExtra
->bFlags
& TVIX_BKCOLOR
) ? pExtra
->uColorBk
: TV_NOCOLOR
;
6094 if(uColor
== TV_NOCOLOR
) {
6095 pExtra
->bFlags
&= ~TVIX_BKCOLOR
;
6097 pExtra
->bFlags
|= TVIX_BKCOLOR
;
6098 pExtra
->uColorBk
= uColor
;
6102 if(iMode
) { // Textfarbe
6103 uOld
= (pEntry
->bFlags
& TVIX_TEXTCOLOR
) ? pEntry
->uColorText
: TV_NOCOLOR
;
6105 if(uColor
== TV_NOCOLOR
) {
6106 pEntry
->bFlags
&= ~TVIX_TEXTCOLOR
;
6108 pEntry
->bFlags
|= TVIX_TEXTCOLOR
;
6109 pEntry
->uColorText
= uColor
;
6111 } else { // Hintergrund
6112 uOld
= (pEntry
->bFlags
& TVIX_BKCOLOR
) ? pEntry
->uColorBk
: TV_NOCOLOR
;
6114 if(uColor
== TV_NOCOLOR
) {
6115 pEntry
->bFlags
&= ~TVIX_BKCOLOR
;
6117 pEntry
->bFlags
|= TVIX_BKCOLOR
;
6118 pEntry
->uColorBk
= uColor
;
6123 if(uColor
!= uOld
) { // Neu zeichnen
6124 UpdateRect(pData
, uItem
, uSub
);
6130 //*****************************************************************************
6132 //* TreeListSetTrackItem
6134 //*****************************************************************************
6135 // Setzt das unterstrichene Item
6136 // pData : Zeiger auf die Fensterdaten
6137 // uItem : Ist die Nummer des Eintrages
6138 // uSub : Ist die Spalte
6139 // Ergibt 1 wenn der Eintrag unterstrichen wurde
6140 static int TreeListSetTrackItem(TreeListData
*pData
, unsigned uItem
, unsigned uSub
) {
6146 if(!(pData
->uStyleEx
& TVS_EX_SUBSELECT
)) {
6149 if(uSub
>= pData
->uColumnCount
) {
6156 if(uItem
> pData
->uTreeItemsMax
) {
6161 if(uItem
== pData
->uTrackedItem
)
6162 if(uSub
== pData
->uTrackedSub
) {
6167 if(pData
->uTrackedItem
) { // Den alten Eintrag zurücksetzen
6168 if(pData
->uTrackedSub
) {
6169 pExtra
= pData
->pExtraItems
[pData
->uTrackedSub
- 1][pData
->uTrackedItem
];
6171 pExtra
->bFlags
&= ~TVIX_TRACKED
;
6172 UpdateRect(pData
, pData
->uTrackedItem
, pData
->uTrackedSub
);
6175 pEntry
= pData
->pTreeItems
[pData
->uTrackedItem
];
6177 pEntry
->bFlags
&= ~TVIX_TRACKED
;
6178 UpdateRect(pData
, pData
->uTrackedItem
, 0);
6183 if(uItem
) { // Den neuen Eintrag setzen
6185 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
6187 pData
->uTrackedSub
= uSub
;
6188 pData
->uTrackedItem
= uItem
;
6189 pExtra
->bFlags
|= TVIX_TRACKED
;
6190 UpdateRect(pData
, uItem
, uSub
);
6195 pEntry
= pData
->pTreeItems
[uItem
];
6197 pData
->uTrackedSub
= 0;
6198 pData
->uTrackedItem
= uItem
;
6199 pEntry
->bFlags
|= TVIX_TRACKED
;
6200 UpdateRect(pData
, uItem
, 0);
6205 } else { // Keine Untersteichung
6206 pData
->uTrackedSub
= 0;
6207 pData
->uTrackedItem
= 0;
6213 //*****************************************************************************
6215 //* TreeListGetNextItem
6217 //*****************************************************************************
6218 // Sucht den nächsten Eintrag
6219 // pData : Zeiger auf die Fensterdaten
6220 // uItem : Ist die Nummer des Eintrages
6221 // uFlags : Bestimmt nach welchem Eintrag gesucht werden soll
6222 // Ergibt 1 wenn der Eintrag unterstrichen wurde
6223 static unsigned TreeListGetNextItem(TreeListData
*pData
, unsigned uItem
, unsigned uFlags
) {
6230 return pData
->uFirstChild
;
6233 if(uItem
> pData
->uTreeItemsMax
) {
6237 pEntry
= pData
->pTreeItems
[uItem
];
6241 return pEntry
->uNextItem
;
6244 if(uItem
> pData
->uTreeItemsMax
) {
6248 pEntry
= pData
->pTreeItems
[uItem
];
6252 return pEntry
->uPrevItem
;
6255 if(uItem
> pData
->uTreeItemsMax
) {
6259 pEntry
= pData
->pTreeItems
[uItem
];
6263 return pEntry
->uParent
;
6266 if(uItem
> pData
->uTreeItemsMax
) {
6267 if(uItem
== U(TVI_ROOT
))
6268 return pData
->uFirstChild
;
6272 pEntry
= pData
->pTreeItems
[uItem
];
6276 return pEntry
->uFirstChild
;
6278 case TVGN_LASTCHILD
:
6279 if(uItem
> pData
->uTreeItemsMax
) {
6280 if(uItem
== U(TVI_ROOT
))
6281 return pData
->uLastChild
;
6285 pEntry
= pData
->pTreeItems
[uItem
];
6289 return pEntry
->uLastChild
;
6291 case TVGN_FIRSTVISIBLE
:
6292 if(pData
->uItemPosCount
<= 0)
6294 if(pData
->uItemPosCount
<= pData
->uScrollY
)
6297 uItem
= pData
->pItemPos
[pData
->uScrollY
];
6299 if(uItem
> pData
->uTreeItemsMax
|| !pData
->pTreeItems
[uItem
]) {
6305 case TVGN_NEXTVISIBLE
:
6306 if(uItem
> pData
->uTreeItemsMax
) {
6307 if(uItem
!= U(TVI_ROOT
))
6309 if(pData
->uFirstChild
== 0)
6312 pEntry
= pData
->pTreeItems
[pData
->uFirstChild
];
6314 uPos
= pEntry
->uShowPos
;
6315 if(uPos
<= pData
->uScrollY
)
6318 return pData
->uFirstChild
;
6321 pEntry
= pData
->pTreeItems
[uItem
];
6325 uPos
= pEntry
->uShowPos
;
6326 if(uPos
<= pData
->uScrollY
)
6328 if(uPos
> pData
->uScrollY
+ pData
->uPageEnties
)
6331 uItem
= pData
->pItemPos
[uPos
];
6333 if(uItem
> pData
->uTreeItemsMax
|| !pData
->pTreeItems
[uItem
]) {
6339 case TVGN_NEXTSELECTED
:
6340 if(uItem
> pData
->uTreeItemsMax
) {
6341 if(uItem
!= U(TVI_ROOT
))
6344 uItem
= pData
->uFirstChild
;
6346 pEntry
= pData
->pTreeItems
[uItem
];
6349 if(pEntry
->uState
& TVIS_SELECTED
)
6353 pEntry
= pData
->pTreeItems
[uItem
];
6358 if(pEntry
->uFirstChild
) {
6359 uItem
= pEntry
->uFirstChild
;
6361 if(pEntry
->uNextItem
) {
6362 uItem
= pEntry
->uNextItem
;
6365 uItem
= pEntry
->uParent
;
6366 pEntry
= pData
->pTreeItems
[uItem
];
6369 if(pEntry
->uNextItem
) {
6370 uItem
= pEntry
->uNextItem
;
6376 pEntry
= pData
->pTreeItems
[uItem
];
6379 if(pEntry
->uState
& TVIS_SELECTED
)
6385 case TVGN_NEXTSELCHILD
:
6386 if(uItem
> pData
->uTreeItemsMax
) {
6387 if(uItem
!= U(TVI_ROOT
))
6390 uItem
= pData
->uFirstChild
;
6392 pEntry
= pData
->pTreeItems
[uItem
];
6395 if(pEntry
->uState
& TVIS_SELECTED
)
6400 pEntry
= pData
->pTreeItems
[uItem
];
6401 if(!pEntry
|| !pEntry
->uFirstChild
)
6408 if(pEntry
->uFirstChild
) {
6409 uItem
= pEntry
->uFirstChild
;
6411 if(pEntry
->uNextItem
) {
6412 uItem
= pEntry
->uNextItem
;
6415 uItem
= pEntry
->uParent
;
6418 pEntry
= pData
->pTreeItems
[uItem
];
6421 if(pEntry
->uNextItem
) {
6422 uItem
= pEntry
->uNextItem
;
6428 pEntry
= pData
->pTreeItems
[uItem
];
6431 if(pEntry
->uState
& TVIS_SELECTED
)
6438 if(uItem
> pData
->uTreeItemsMax
) {
6439 if(uItem
!= U(TVI_ROOT
))
6442 uItem
= pData
->uFirstChild
;
6444 pEntry
= pData
->pTreeItems
[uItem
];
6451 pEntry
= pData
->pTreeItems
[uItem
];
6456 if(pEntry
->uFirstChild
) {
6457 uItem
= pEntry
->uFirstChild
;
6459 if(pEntry
->uNextItem
) {
6460 uItem
= pEntry
->uNextItem
;
6463 uItem
= pEntry
->uParent
;
6464 pEntry
= pData
->pTreeItems
[uItem
];
6467 if(pEntry
->uNextItem
) {
6468 uItem
= pEntry
->uNextItem
;
6474 pEntry
= pData
->pTreeItems
[uItem
];
6483 case TVGN_PREVIOUSVISIBLE
:
6484 if(uItem
> pData
->uTreeItemsMax
) {
6488 pEntry
= pData
->pTreeItems
[uItem
];
6492 uPos
= pEntry
->uShowPos
- 1;
6493 if(uPos
<= pData
->uScrollY
)
6495 if(uPos
> pData
->uScrollY
+ pData
->uPageEnties
)
6498 return pData
->pItemPos
[uPos
- 1];
6500 case TVGN_LASTVISIBLE
:
6501 uPos
= pData
->uItemPosCount
;
6504 return pData
->pItemPos
[uPos
- 1];
6506 case TVGN_DROPHILITE
:
6507 return pData
->uTrackedItem
;
6509 case TVGN_DROPHILITESUB
:
6510 return pData
->uTrackedSub
;
6513 return pData
->uSelectedItem
;
6516 return pData
->uSelectedSub
;
6519 return (pData
->uFocusItem
) ? pData
->uFocusItem
: pData
->uSelectedItem
;
6522 return (pData
->uFocusItem
) ? pData
->uFocusSub
: pData
->uSelectedSub
;
6529 //*****************************************************************************
6531 //* TreeListFindItem
6533 //*****************************************************************************
6534 // Sucht einen Kindeintrag mit einem bestimmten Text
6535 // pData : Zeiger auf die Fensterdaten
6536 // uItem : Ist die Nummer des Elterneintrages
6537 // pFind : Die Struktur mit den Suchparametern
6538 // Ergibt die Nummer des Eintrages bzw. 0 wenn nicht gefunden wurde
6539 static unsigned TreeListFindItem(TreeListData
*pData
, unsigned uItem
, TVFIND
*pFind
) {
6552 if(pFind
->uFlags
& TVIF_CHILD
) { // In den Kindern suchen
6553 if(uItem
> pData
->uTreeItemsMax
) {
6554 if(uItem
!= U(TVI_ROOT
))
6556 uItem
= pData
->uFirstChild
;
6558 pEntry
= pData
->pTreeItems
[uItem
];
6562 uItem
= pEntry
->uFirstChild
;
6565 if(uItem
> pData
->uTreeItemsMax
) { // Ist der Eintrag gültig
6569 if(pFind
->uFlags
& TVIF_NEXT
) { // Beim nächsten Eintrag weitersuchen
6570 pEntry
= pData
->pTreeItems
[uItem
];
6574 uItem
= pEntry
->uNextItem
;
6578 uChkParam
= pFind
->uFlags
& TVIF_PARAM
;
6579 uChkState
= pFind
->uFlags
& TVIF_STATE
;
6580 uChkText
= pFind
->uFlags
& TVIF_TEXT
;
6581 uChkCase
= pFind
->uFlags
& TVIF_CASE
;
6582 uSub
= pFind
->uColumn
;
6586 uTextLen
= str_len(pFind
->pText
);
6589 for(; uItem
; uItem
= pEntry
->uNextItem
) { // Durchlaufe alle Kinder
6590 pEntry
= pData
->pTreeItems
[uItem
];
6594 if(uChkParam
&& pFind
->lParam
!= pEntry
->lParam
) { // Vergleiche lParam
6597 // Vergleiche die State-Bits
6598 if(uChkState
&& ((pEntry
->uState
^ pFind
->uState
)&pFind
->uStateMask
)) {
6605 if(uSub
) { // Text von Spalten
6606 if(uSub
>= pData
->uColumnCount
)
6609 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
6614 pCmpText
= pExtra
->pText
;
6617 uTextSize
= pExtra
->uTextSize
;
6619 } else { // Text vom Haupteintrag
6620 if(pEntry
->bCallback
& TVIF_TEXT
) {
6621 CallbackEntry(pData
, pEntry
, uItem
, pEntry
->bCallback
, &iImage
, &uTextSize
, &pCmpText
);
6623 pCmpText
= pEntry
->pText
;
6626 uTextSize
= pEntry
->uTextSize
;
6630 if(uTextLen
!= uTextSize
)
6633 if(uChkCase
) { // Zwischen Groß/Kleinbuchstaben unterscheiden
6634 if(!str_icmp(pCmpText
, pFind
->pText
))
6637 if(!memcmp(pCmpText
, pFind
->pText
, uTextSize
* sizeof(TCHAR
)))
6645 //*****************************************************************************
6647 //* TreeListNextSelUntil
6649 //*****************************************************************************
6650 // Sucht rekursiv ausgewählte Einträge
6651 // pData : Zeiger auf die Fensterdaten
6652 // uItem : Ist die Nummer des Eintrages nach dem mit der Suche begonnen werden soll
6653 // uStop : Bestimmt bei welchem Eintrag abgebrochen werden soll werden soll
6654 // Ergibt die Nummer des Eintrages oder 0 wenn keiner gefunden wurde
6655 static unsigned TreeListNextSelUntil(TreeListData
*pData
, unsigned uItem
, unsigned uStop
) {
6659 if(uItem
> pData
->uTreeItemsMax
) {
6660 if(uItem
!= U(TVI_ROOT
))
6663 uItem
= pData
->uFirstChild
;
6665 pEntry
= pData
->pTreeItems
[uItem
];
6668 if(pEntry
->uState
& TVIS_SELECTED
)
6673 pEntry
= pData
->pTreeItems
[uItem
];
6676 if(!pEntry
->uFirstChild
&& uItem
== uStop
)
6681 if(pEntry
->uFirstChild
) {
6682 uItem
= pEntry
->uFirstChild
;
6686 if(pEntry
->uNextItem
) {
6687 uItem
= pEntry
->uNextItem
;
6692 uItem
= pEntry
->uParent
;
6695 pEntry
= pData
->pTreeItems
[uItem
];
6698 if(pEntry
->uNextItem
) {
6699 uItem
= pEntry
->uNextItem
;
6707 pEntry
= pData
->pTreeItems
[uItem
];
6710 if(pEntry
->uState
& TVIS_SELECTED
)
6717 //*****************************************************************************
6719 //* TreeListNextUnselUntil
6721 //*****************************************************************************
6722 // Sucht rekursiv nicht ausgewählte Einträge
6723 // pData : Zeiger auf die Fensterdaten
6724 // uItem : Ist die Nummer des Eintrages nach dem mit der Suche begonnen werden soll
6725 // uStop : Bestimmt bei welchem Eintrag abgebrochen werden soll werden soll
6726 // Ergibt die Nummer des Eintrages oder 0 wenn keiner gefunden wurde
6727 static unsigned TreeListNextUnselUntil(TreeListData
*pData
, unsigned uItem
, unsigned uStop
) {
6731 if(uItem
> pData
->uTreeItemsMax
) {
6732 if(uItem
!= U(TVI_ROOT
))
6735 uItem
= pData
->uFirstChild
;
6737 pEntry
= pData
->pTreeItems
[uItem
];
6740 if((pEntry
->uState
& TVIS_SELECTED
) == 0)
6745 pEntry
= pData
->pTreeItems
[uItem
];
6748 if(!pEntry
->uFirstChild
&& uItem
== uStop
)
6753 if(pEntry
->uFirstChild
) {
6754 uItem
= pEntry
->uFirstChild
;
6758 if(pEntry
->uNextItem
) {
6759 uItem
= pEntry
->uNextItem
;
6764 uItem
= pEntry
->uParent
;
6767 pEntry
= pData
->pTreeItems
[uItem
];
6770 if(pEntry
->uNextItem
) {
6771 uItem
= pEntry
->uNextItem
;
6779 pEntry
= pData
->pTreeItems
[uItem
];
6782 if((pEntry
->uState
& TVIS_SELECTED
) == 0)
6789 //*****************************************************************************
6791 //* TreeListChangeCheckbox
6793 //*****************************************************************************
6794 // Schaltet eine Checkboc um
6795 // pData : Zeiger auf die Fensterdaten
6796 // uItem : Ist der Eintrag der geändert werden soll
6798 static void TreeListChangeCheckbox(TreeListData
*pData
, UINT uItem
, int iPosX
, int iPosY
) {
6806 sNotify
.itemOld
.mask
= 0;
6807 sNotify
.itemOld
.hItem
= 0;
6809 pEntry
= pData
->pTreeItems
[uItem
];
6810 uBits
= pEntry
->uState
& TVIS_STATEIMAGEMASK
;
6812 if(pData
->uStyleEx
& TVS_EX_SINGLECHECKBOX
) { // Einzelauswahl
6813 pTemp
= pData
->pTreeItems
[pData
->uSingleSel
];
6815 if(pData
->uSingleSel
== uItem
) {
6816 if(pData
->uStyleEx
& TVS_EX_BITCHECKBOX
) {
6824 if(pData
->uSingleSel
&& pTemp
) { // Anderer Eintrag gewählt
6825 sItem
.hItem
= (HTREEITEM
)pData
->uSingleSel
;
6826 sItem
.mask
= TVIF_STATE
;
6827 sItem
.stateMask
= TVIS_STATEIMAGEMASK
;
6828 sItem
.state
= (pData
->uStyleEx
& TVS_EX_BITCHECKBOX
) ? 0x0000 : 0x1000;
6830 TreeListSetItem(pData
, &sItem
);
6832 sNotify
.itemOld
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_TEXT
;
6833 sNotify
.itemOld
.hItem
= (HTREEITEM
)pData
->uSingleSel
;
6834 sNotify
.itemOld
.stateMask
= 0xFFFFFFFF;
6835 sNotify
.itemOld
.state
= pTemp
->uState
;
6836 sNotify
.itemOld
.lParam
= pTemp
->lParam
;
6837 sNotify
.itemOld
.pszText
= pTemp
->pText
;
6838 sNotify
.itemOld
.cchTextMax
= pTemp
->uTextSize
;
6839 sNotify
.itemOld
.cChildren
= 0;
6843 sItem
.hItem
= (HTREEITEM
)uItem
;
6844 sItem
.mask
= TVIF_STATE
;
6845 sItem
.stateMask
= TVIS_STATEIMAGEMASK
;
6847 if(pData
->uStyleEx
& TVS_EX_BITCHECKBOX
)
6848 sItem
.state
= (uBits
^ 0x1000);
6850 sItem
.state
= (uBits
& 0x1000) ? 0x2000 : 0x1000;
6852 TreeListSetItem(pData
, &sItem
);
6853 pData
->uSingleSel
= uItem
;
6855 sNotify
.hdr
.code
= TVN_CBSTATECHANGED
;
6856 sNotify
.action
= VK_DBLCLK
;
6857 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_TEXT
;
6858 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
6859 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
6860 sNotify
.itemNew
.state
= pEntry
->uState
;
6861 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
6862 sNotify
.itemNew
.pszText
= pEntry
->pText
;
6863 sNotify
.itemNew
.cchTextMax
= pEntry
->uTextSize
;
6864 sNotify
.itemNew
.cChildren
= 0;
6865 sNotify
.ptDrag
.x
= iPosX
;
6866 sNotify
.ptDrag
.y
= iPosY
;
6869 SendNotify(pData
, &sNotify
.hdr
);
6873 //*****************************************************************************
6875 //* TreeListMouseNotify
6877 //*****************************************************************************
6878 // Soll für einen Mausklick eine
6879 // pData : Zeiger auf die Fensterdaten
6880 // uMsg : Message des Mausklicks
6881 // wParam : WPARAM des Mausklicks
6882 // lParam : LPARAM des Mausklicks
6883 static void TreeListMouseNotify(TreeListData
*pData
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
6885 TV_HITTESTINFO sInfo
;
6890 sInfo
.flags
= (UINT
) wParam
;
6891 sInfo
.pt
.x
= LOWORD(lParam
);
6892 sInfo
.pt
.y
= HIWORD(lParam
);
6893 uItem
= TreeListHitTest(pData
, &sInfo
);
6896 pEntry
= pData
->pTreeItems
[uItem
];
6897 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
6898 sNotify
.itemNew
.state
= pEntry
->uState
;
6899 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
6900 sNotify
.itemNew
.cChildren
= TVHT_SUBTOCOL(sInfo
.flags
);
6902 sNotify
.itemNew
.stateMask
= 0;
6903 sNotify
.itemNew
.state
= 0;
6904 sNotify
.itemNew
.lParam
= 0;
6908 sNotify
.hdr
.code
= uMsg
;
6909 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBNUMBER
;
6910 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
6911 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
6912 sNotify
.itemNew
.cchTextMax
= -1;
6913 sNotify
.itemOld
.mask
= 0;
6914 sNotify
.ptDrag
.x
= LOWORD(lParam
);
6915 sNotify
.ptDrag
.y
= HIWORD(lParam
);
6917 SendNotify(pData
, &sNotify
.hdr
);
6921 //*****************************************************************************
6923 //* TreeListMouseClick
6925 //*****************************************************************************
6926 // Soll ein Mausklick ausgeführt werden. ACHTUNG UNLOCK wird ausgeführt
6927 // pData : Zeiger auf die Fensterdaten
6928 // uMsg : Message des Mausklicks
6929 // wParam : WPARAM des Mausklicks
6930 // lParam : LPARAM des Mausklicks
6931 static void TreeListMouseClick(TreeListData
*pData
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
6935 TV_HITTESTINFO sInfo
;
6954 if(!pData
->cIsEnabled
) { // Ist das Fenster freigegeben
6958 if(!pData
->cHasFocus
) { // Hat das Fenster den Focus
6959 if(GetFocus() != pData
->hWnd
) {
6961 SetFocus(pData
->hWnd
);
6964 if(GetFocus() != pData
->hWnd
) {
6969 pData
->cHasFocus
= 1;
6973 sInfo
.flags
= (UINT
) wParam
;
6974 sInfo
.pt
.x
= LOWORD(lParam
);
6975 sInfo
.pt
.y
= HIWORD(lParam
);
6976 uItem
= TreeListHitTest(pData
, &sInfo
);
6980 if(uItem
) { // Wurde auf einen Eintrag getrückt
6981 pEntry
= pData
->pTreeItems
[uItem
];
6983 if(pData
->uStyle
& TVS_FULLROWSELECT
) {
6984 uMaskItem
= TVHT_ONITEMICON
| TVHT_ONITEMLABEL
| TVHT_ONITEMSTATEICON
| TVHT_ONITEMRIGHT
;
6985 uMaskSub
= TVHT_ONSUBICON
| TVHT_ONSUBLABEL
| TVHT_ONSUBRIGHT
;
6987 uMaskItem
= TVHT_ONITEMICON
| TVHT_ONITEMLABEL
| TVHT_ONITEMSTATEICON
;
6988 uMaskSub
= TVHT_ONSUBICON
| TVHT_ONSUBLABEL
;
6991 if(sInfo
.flags
& TVHT_ONITEMBUTTON
) { // Eintrag aufklappen
6992 if(uMsg
== WM_LBUTTONDOWN
|| uMsg
== WM_LBUTTONDBLCLK
) {
6993 pEntry
= pData
->pTreeItems
[uItem
];
6994 if(pEntry
&& (pEntry
->uState
& (TVIS_EXPANDED
| TVIS_EXPANDPARTIAL
)) == (TVIS_EXPANDED
| TVIS_EXPANDPARTIAL
)) {
6995 TreeListToggleItem(pData
, uItem
, 0); // Von + auf - umschalten
6997 uToggle
= 1; // Eintrag auflappen
7001 if(sInfo
.flags
& TVHT_ONITEMSTATEICON
) { // Checkbox umschalten
7002 if(pData
->uStyle
& TVS_CHECKBOXES
)
7003 if(uMsg
== WM_LBUTTONDOWN
|| uMsg
== WM_LBUTTONDBLCLK
) {
7004 TreeListChangeCheckbox(pData
, uItem
, sInfo
.pt
.x
, sInfo
.pt
.y
);
7007 if(sInfo
.flags
& uMaskItem
) { // Eintrag auswählen
7008 if(!(pData
->uStyle
& TVS_DISABLEDRAGDROP
)) {
7009 if(uMsg
== WM_LBUTTONDOWN
) {
7010 pData
->uDragFlags
= MK_LBUTTON
;
7011 pData
->uDragItem
= uItem
;
7012 pData
->uDragSub
= 0;
7015 if(uMsg
== WM_RBUTTONDOWN
) {
7016 pData
->uDragFlags
= MK_RBUTTON
;
7017 pData
->uDragItem
= uItem
;
7018 pData
->uDragSub
= 0;
7022 if(pData
->uStyleEx
& TVS_EX_MULTISELECT
) { // Mehrfachauswahl erlaubt
7023 if(uMsg
== WM_RBUTTONDOWN
) // Keine Abwahl wenn mehrer Einträge aus gewählt
7024 if(pData
->uSelectedCount
> 1) {
7025 pEntry
= pData
->pTreeItems
[uItem
];
7026 if(pEntry
->uState
& TVIS_SELECTED
) {
7031 if(uMsg
== WM_LBUTTONDOWN
) // Spezialsteuerung für Multiselect bei Darg
7032 if(!(wParam
& (MK_CONTROL
| MK_SHIFT
)))
7033 if(pData
->uSelectedCount
> 0) {
7034 pEntry
= pData
->pTreeItems
[uItem
];
7035 if(pEntry
&& (pEntry
->uState
& TVIS_SELECTED
)) {
7036 pData
->cClickFlag
= 1;
7037 pData
->cClickEdit
= 0;
7042 if(uMsg
== WM_LBUTTONUP
&& pData
->cClickFlag
) {
7043 wParam
&= ~(MK_CONTROL
| MK_SHIFT
);
7044 uMsg
= WM_LBUTTONDOWN
;
7047 if(wParam
& MK_SHIFT
) { // Bis zum angeklicken Auswählen
7048 if(uMsg
!= WM_LBUTTONDOWN
)
7049 if(uMsg
!= WM_LBUTTONDBLCLK
)
7052 pData
->cClickEdit
= 0;
7054 uTemp
= pData
->uSelectedItem
;
7056 uTemp
= pData
->uFocusItem
;
7057 if(!uTemp
|| !pData
->cReSelect
)
7061 pEntry
= pData
->pTreeItems
[uTemp
];
7062 uLine
= pEntry
->uShowPos
;
7066 pEntry
= pData
->pTreeItems
[uItem
];
7067 uStop
= pEntry
->uShowPos
;
7071 if(pData
->uSelectedCount
<= 1) {
7072 pData
->uSelectedBase
= uTemp
;
7075 // Shift-Select neu auswählen
7076 if(pData
->cReSelect
&& pData
->uSelectedBase
) {
7077 TreeListSelectItem(pData
, uItem
, 0, TVC_BYMOUSE
| TVC_DESELECT
);
7078 TreeListEnsureVisible(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
7080 uTemp
= pData
->uSelectedBase
;
7081 pTemp
= pData
->pTreeItems
[uTemp
];
7084 while(pTemp
&& pTemp
->uShowPos
== 0) {
7085 pTemp
= pData
->pTreeItems
[pTemp
->uParent
];
7091 if(!(pTemp
->uState
& TVIS_SELECTED
)) {
7092 TreeListXorSelectItem(pData
, uTemp
, TVC_BYKEYBOARD
);
7095 if(pTemp
->uShowPos
< pEntry
->uShowPos
) {
7103 uTemp
= TreeListNextUnselUntil(pData
, uTemp
, uStop
);
7106 TreeListXorSelectItem(pData
, uTemp
, TVC_BYKEYBOARD
);
7110 pData
->cReSelect
= 0;
7114 TreeListSelectItem(pData
, uItem
, 0, TVC_BYMOUSE
);
7116 iAdd
= (uLine
> uStop
) ? -1 : 1;
7120 pEntry
= pData
->pTreeItems
[pData
->uSelectedBase
];
7122 while(pEntry
&& pEntry
->uShowPos
== 0) {
7123 pEntry
= pData
->pTreeItems
[pEntry
->uParent
];
7128 if(pEntry
->uShowPos
> uPos
&& uPos
> uStop
)
7132 if(pEntry
->uShowPos
< uPos
&& uPos
< uStop
)
7138 for(;; uPos
+= iAdd
) { // Einträge wählen
7139 uTemp
= pData
->pItemPos
[uPos
- 1];
7140 pEntry
= pData
->pTreeItems
[uTemp
];
7141 uSel
= pEntry
->uState
& TVIS_SELECTED
;
7143 if(uTemp
!= pData
->uSelectedBase
|| !uSel
) {
7144 TreeListXorSelectItem(pData
, uTemp
, TVC_BYMOUSE
);
7145 uSel
= pEntry
->uState
& TVIS_SELECTED
;
7148 // Auch unsichtbare Kinder wählen
7149 pTemp
= pData
->pTreeItems
[pEntry
->uFirstChild
];
7150 if(pTemp
&& !pTemp
->uShowPos
) {
7152 for(uNum
= uTemp
;;) { // Kinder auswählen
7153 uNum
= TreeListNextUnselUntil(pData
, uNum
, uTemp
);
7156 TreeListXorSelectItem(pData
, uNum
, TVC_BYMOUSE
);
7159 for(uNum
= uTemp
;;) { // Kinder abwählen
7160 uNum
= TreeListNextSelUntil(pData
, uNum
, uTemp
);
7163 TreeListXorSelectItem(pData
, uNum
, TVC_BYMOUSE
);
7172 TreeListRemoveFocus(pData
);
7174 pEntry
= pData
->pTreeItems
[uItem
];
7175 uSub
= TVHT_SUBTOCOL(sInfo
.flags
);
7176 if(!(pData
->uStyleEx
& TVS_EX_SUBSELECT
))
7179 pData
->uFocusSub
= uSub
;
7180 pData
->uFocusItem
= uItem
;
7183 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
7185 pExtra
->bFlags
|= TVIX_FOCUSED
;
7187 pEntry
->bFlags
|= TVIX_FOCUSED
;
7190 UpdateRect(pData
, uItem
, uSub
);
7192 TreeListSelectItem(pData
, uItem
, 0, TVC_BYMOUSE
);
7193 TreeListEnsureVisible(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
7198 if(wParam
& MK_CONTROL
) { // Einzelen Eintrag umschalten
7199 pData
->uSelectedBase
= uItem
;
7200 pData
->cReSelect
= 1;
7201 pData
->cClickEdit
= 0;
7203 pEntry
= pData
->pTreeItems
[uItem
];
7204 if(pEntry
&& (pEntry
->uState
& TVIS_SELECTED
)) {
7205 if(uMsg
!= WM_LBUTTONDOWN
)
7206 if(uMsg
!= WM_LBUTTONDBLCLK
)
7209 TreeListSelectItem(pData
, 0, 0, TVC_BYMOUSE
);
7211 if(TreeListXorSelectItem(pData
, uItem
, TVC_BYMOUSE
)) {
7212 // Auch unsichtbare Kinder abwählen
7213 pTemp
= pData
->pTreeItems
[pEntry
->uFirstChild
];
7214 if(pTemp
&& !pTemp
->uShowPos
)
7215 for(uTemp
= uItem
;;) {
7216 uTemp
= TreeListNextSelUntil(pData
, uTemp
, uItem
);
7219 TreeListXorSelectItem(pData
, uTemp
, TVC_BYMOUSE
);
7223 uTemp
= pData
->uFocusItem
;
7224 if(uTemp
) { // Ist ein Focus definiert
7225 TreeListRemoveFocus(pData
);
7228 uSub
= TVHT_SUBTOCOL(sInfo
.flags
);
7229 if(!(pData
->uStyleEx
& TVS_EX_SUBSELECT
))
7232 pData
->uFocusItem
= uItem
;
7233 pData
->uFocusSub
= uSub
;
7236 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
7238 pExtra
->bFlags
|= TVIX_FOCUSED
;
7240 pEntry
->bFlags
|= TVIX_FOCUSED
;
7243 UpdateRect(pData
, uItem
, uSub
);
7250 if(wParam
& MK_CONTROL
) { // Ist die Ctrl-Taste gedrückt
7251 iMode
= TVC_BYMOUSE
;
7253 iMode
= TVC_BYMOUSE
| TVC_DESELECT
;
7256 uOldSub
= pData
->uSelectedSub
;
7257 uOldItem
= pData
->uSelectedItem
;
7259 TreeListRemoveFocus(pData
);
7260 TreeListSelectItem(pData
, uItem
, 0, iMode
);
7261 TreeListEnsureVisible(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
7262 pEntry
= pData
->pTreeItems
[uItem
];
7264 if(uMsg
== WM_LBUTTONDBLCLK
) {
7265 // Auto-Edit mit Doppelklick
7266 if(pData
->aColumn
[0].bFlags
& TVAE_DBLCLICK
&& pData
->aColumn
[0].bEdit
) {
7267 TreeListStartAutoEdit(pData
, 0, VK_DBLCLK
, lParam
);
7269 if(TreeListStartNotifyEdit(pData
, pData
->uSelectedItem
, 0, VK_DBLCLK
, lParam
)) {
7272 if(pEntry
&& (pEntry
->uState
& (TVIS_EXPANDED
| TVIS_EXPANDPARTIAL
)) == (TVIS_EXPANDED
| TVIS_EXPANDPARTIAL
)) {
7273 TreeListToggleItem(pData
, uItem
, 0); // Von + auf - umschalten
7275 uToggle
= 1; // Eintrag auflappen
7278 if(uMsgOld
== WM_LBUTTONDOWN
) {
7279 if(pData
->uStyleEx
& TVS_EX_EDITCLICK
)
7280 if(!(wParam
& (MK_CONTROL
| MK_SHIFT
)))
7281 if(sInfo
.flags
& uMaskItem
&~TVHT_ONITEMICON
)
7282 if(uOldSub
== pData
->uSelectedSub
&& uOldItem
== pData
->uSelectedItem
) {
7283 pData
->cClickEdit
= 1;
7286 if(uMsgOld
== WM_LBUTTONUP
) {
7287 if(pData
->uStyleEx
& TVS_EX_EDITCLICK
)
7288 if(pData
->cClickFlag
&& !pData
->cClickEdit
)
7289 if(!(wParam
& (MK_CONTROL
| MK_SHIFT
)))
7290 if(sInfo
.flags
& uMaskItem
&~TVHT_ONITEMICON
)
7291 if(uOldSub
== pData
->uSelectedSub
&& uOldItem
== pData
->uSelectedItem
) {
7292 pData
->cClickEdit
= 1;
7295 if(pData
->cClickEdit
) {
7296 pData
->cClickEdit
= 0;
7298 if(pData
->aColumn
[0].bEdit
) {
7299 TreeListStartAutoEdit(pData
, 0, VK_EDITCLK
, lParam
);
7301 TreeListStartNotifyEdit(pData
, pData
->uSelectedItem
, 0, VK_EDITCLK
, lParam
);
7306 if(sInfo
.flags
& uMaskSub
) { // Extra-Eintrag auswählen
7307 if(pData
->uStyleEx
& TVS_EX_SUBSELECT
)
7308 uSub
= TVHT_SUBTOCOL(sInfo
.flags
);
7312 if(!(pData
->uStyle
& TVS_DISABLEDRAGDROP
)) {
7313 if(uMsg
== WM_LBUTTONDOWN
) {
7314 pData
->uDragFlags
= MK_LBUTTON
;
7315 pData
->uDragItem
= uItem
;
7316 pData
->uDragSub
= uSub
;
7319 if(uMsg
== WM_RBUTTONDOWN
) {
7320 pData
->uDragFlags
= MK_RBUTTON
;
7321 pData
->uDragItem
= uItem
;
7322 pData
->uDragSub
= uSub
;
7326 if(wParam
& MK_CONTROL
) {
7327 if(pData
->uStyleEx
& TVS_EX_MULTISELECT
) { // Auswahl umschalten
7328 pEntry
= pData
->pTreeItems
[uItem
];
7329 if(pEntry
&& (pEntry
->uState
& TVIS_SELECTED
)) {
7330 if(uMsg
!= WM_LBUTTONDOWN
)
7331 if(uMsg
!= WM_LBUTTONDBLCLK
)
7334 TreeListSelectItem(pData
, 0, 0, TVC_BYMOUSE
);
7336 if(TreeListXorSelectItem(pData
, uItem
, TVC_BYMOUSE
)) {
7337 // Auch unsichtbare Kinder abwählen
7338 pTemp
= pData
->pTreeItems
[pEntry
->uFirstChild
];
7339 if(pTemp
&& !pTemp
->uShowPos
)
7340 for(uTemp
= uItem
;;) {
7341 uTemp
= TreeListNextSelUntil(pData
, uTemp
, uItem
);
7344 TreeListXorSelectItem(pData
, uTemp
, TVC_BYMOUSE
);
7348 TreeListRemoveFocus(pData
);
7350 pData
->cClickEdit
= 0;
7351 pData
->uFocusItem
= uItem
;
7352 pData
->uFocusSub
= uSub
;
7355 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
7357 pExtra
->bFlags
|= TVIX_FOCUSED
;
7359 pEntry
->bFlags
|= TVIX_FOCUSED
;
7362 UpdateRect(pData
, uItem
, uSub
);
7368 iMode
= TVC_BYMOUSE
;
7370 iMode
= TVC_BYMOUSE
| TVC_DESELECT
;
7373 uOldSub
= pData
->uSelectedSub
;
7374 uOldItem
= pData
->uSelectedItem
;
7376 TreeListRemoveFocus(pData
);
7377 TreeListSelectItem(pData
, uItem
, uSub
, (wParam
& MK_CONTROL
) ? TVC_BYMOUSE
: TVC_BYMOUSE
| TVC_DESELECT
);
7378 TreeListEnsureVisible(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
7379 pEntry
= pData
->pTreeItems
[uItem
];
7381 if(uMsg
== WM_LBUTTONDBLCLK
) {
7382 if(pData
->aColumn
[uSub
].bEdit
&& // Auto-Edit mit Doppelklick
7383 ((pData
->aColumn
[uSub
].bFlags
& TVAE_DBLCLICK
) ||
7384 ((pData
->aColumn
[uSub
].bFlags
& TVAE_ICONCLICK
) && (sInfo
.flags
& TVHT_ONSUBICON
)))) {
7385 TreeListStartAutoEdit(pData
, uSub
, (sInfo
.flags
& TVHT_ONSUBICON
) ? VK_ICONCLK
: VK_DBLCLK
, lParam
);
7387 if(TreeListStartNotifyEdit(pData
, uItem
, uSub
, VK_DBLCLK
, lParam
)) {
7390 uToggle
= 1; // Eintrag auflappen
7393 if(uMsg
== WM_LBUTTONDOWN
) {
7394 if(pData
->aColumn
[uSub
].bEdit
) // Auto-Edit mit Klick auf Icon
7395 if(pData
->aColumn
[uSub
].bFlags
& TVAE_ICONCLICK
)
7396 if(sInfo
.flags
& TVHT_ONSUBICON
) {
7397 TreeListStartAutoEdit(pData
, uSub
, VK_ICONCLK
, lParam
);
7400 if(pData
->uStyleEx
& TVS_EX_EDITCLICK
)
7401 if(uSub
&& !(wParam
& (MK_CONTROL
| MK_SHIFT
)))
7402 if(sInfo
.flags
& uMaskSub
&~TVHT_ONSUBICON
)
7403 if(uOldSub
== pData
->uSelectedSub
&& uOldItem
== pData
->uSelectedItem
) {
7404 pData
->cClickEdit
= 1;
7407 if(uMsg
== WM_LBUTTONUP
) {
7408 if(pData
->cClickEdit
) {
7409 pData
->cClickEdit
= 0;
7411 if(pData
->aColumn
[uSub
].bEdit
) {
7412 TreeListStartAutoEdit(pData
, uSub
, VK_EDITCLK
, lParam
);
7414 TreeListStartNotifyEdit(pData
, uItem
, uSub
, VK_EDITCLK
, lParam
);
7428 sNotify
.hdr
.code
= TVN_LBUTTONUP
;
7430 case WM_LBUTTONDOWN
:
7431 sNotify
.hdr
.code
= NM_CLICK
;
7433 case WM_LBUTTONDBLCLK
:
7434 sNotify
.hdr
.code
= NM_DBLCLK
;
7437 sNotify
.hdr
.code
= TVN_RBUTTONUP
;
7439 case WM_RBUTTONDOWN
:
7440 sNotify
.hdr
.code
= NM_RCLICK
;
7442 case WM_RBUTTONDBLCLK
:
7443 sNotify
.hdr
.code
= NM_RDBLCLK
;
7452 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
7453 sNotify
.itemNew
.state
= pEntry
->uState
;
7454 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
7455 sNotify
.itemNew
.cChildren
= TVHT_SUBTOCOL(sInfo
.flags
);
7457 sNotify
.itemNew
.stateMask
= 0;
7458 sNotify
.itemNew
.state
= 0;
7459 sNotify
.itemNew
.lParam
= 0;
7463 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBNUMBER
;
7464 sNotify
.itemNew
.hItem
= (HTREEITEM
)uItem
;
7465 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
7466 sNotify
.itemNew
.cchTextMax
= -1;
7467 sNotify
.itemOld
.mask
= 0;
7468 sNotify
.ptDrag
.x
= LOWORD(lParam
);
7469 sNotify
.ptDrag
.y
= HIWORD(lParam
);
7473 if(!SendNotify(pData
, &sNotify
.hdr
)) {
7474 if(uToggle
) { // Aufklappen nur wenn Notify nicht abgefangen
7476 TreeListToggleItem(pData
, uItem
, 0);
7483 //*****************************************************************************
7487 //*****************************************************************************
7488 // Eingabe von Buchstaben über die WM_CHAR Nachricht
7489 // pData : Zeiger auf die Fensterdaten
7490 // nChar : Ist das Zeichen das eingegeben wurde
7491 static void TreeListChar(TreeListData
*pData
, UINT nChar
, LPARAM lParam
) {
7507 if(pData
->cKeyIgnore
)
7508 return; // Taste soll ignoriert werden
7510 iMax
= pData
->uItemPosCount
;
7511 uSub
= pData
->uSelectedSub
;
7514 if(TVIS_EDIT(pData
->aColumn
[uSub
].bEdit
)) // Bei AutoEdit keine Auswahl
7515 if(!(pData
->aColumn
[uSub
].bFlags
& TVAE_ONLYRETURN
)) {
7516 TreeListStartAutoEdit(pData
, uSub
, nChar
, 0);
7520 if(TreeListStartNotifyEdit(pData
, pData
->uSelectedItem
, uSub
, nChar
| VK_ISACHAR
, lParam
)) {
7527 iNum
= pData
->uSelectedItem
; // Hole die Startzeile
7529 iNum
= pData
->pTreeItems
[iNum
]->uShowPos
- 1;
7534 if((nChar
>= 'a' && nChar
<= 'z') || // In Grosbuchstaben umwandeln
7535 (nChar
>= 224 && nChar
<= 254)) {
7539 if(!(pData
->uStyleEx
& TVS_EX_NOCHARSELCET
))
7540 for(;;) { // Suche Anfangsbuchstaben
7541 uTick
= GetTickCount();
7542 uDelta
= (uKeyPos
> 0) ? 750 : 500;
7546 if(uTick
- uKeyLast
> uDelta
)
7550 if(uKeyPos
== 1 && cKeyData
[0] == (TCHAR
)nChar
) {
7554 cKeyData
[uKeyPos
] = (TCHAR
)nChar
;
7567 for(i
= iNum
+ 1; i
!= iNum
; i
++) { // Suche Übereinstimmung
7568 if(i
>= iMax
) {i
= -1; continue;}
7569 uItem
= pData
->pItemPos
[i
];
7573 pExtra
= pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
7575 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
7577 pName
= (pExtra
&& pExtra
->pText
) ? pExtra
->pText
: _T("");
7579 pEntry
= pData
->pTreeItems
[uItem
];
7580 pName
= (pEntry
&& pEntry
->pText
) ? pEntry
->pText
: _T("");
7583 for(uPos
= 0; uPos
< uKeyPos
; uPos
++) { // Vergleiche die Texte
7587 uVal
= ((unsigned char *)pName
)[uPos
];
7590 if((uVal
>= 'a' && uVal
<= 'z') || // In Grosbuchstaben umwandeln
7591 (uVal
>= 224 && uVal
<= 254)) {
7595 if(cKeyData
[uPos
] != (TCHAR
)uVal
) {
7603 if(TreeListSelectItem(pData
, uItem
, uSub
, TVC_UNKNOWN
| TVC_DESELECT
)) {
7604 TreeListEnsureVisible(pData
, uItem
, uSub
);
7625 //*****************************************************************************
7629 //*****************************************************************************
7630 // Soll ein Tastentruck ausgeführt werden. ACHTUNG UNLOCK wird ausgeführt
7631 // pData : Zeiger auf die Fensterdaten
7632 // wParam : WPARAM des Mausklicks
7633 // lParam : LPARAM des Mausklicks
7634 // Ergibt 0 wenn die Taste verarbeitet wurde
7635 static void TreeListKeyDown(TreeListData
*pData
, WPARAM wParam
, LPARAM lParam
) {
7639 TV_KEYDOWN_EX sNotify
;
7660 if(!pData
->cIsEnabled
) { // Ist das Fenster freigegeben
7664 if(!pData
->cHasFocus
) { // Hat das Fenster den Focus
7665 if(GetFocus() != pData
->hWnd
) {
7667 SetFocus(pData
->hWnd
);
7670 if(GetFocus() != pData
->hWnd
) {
7674 pData
->cHasFocus
= 1;
7678 if(wParam
== VK_RETURN
) { // Wurde Enter gedrückt
7681 sNotify
.hdr
.code
= NM_RETURN
;
7682 sNotify
.wVKey
= (WORD
)(wParam
);
7683 sNotify
.wScan
= (WORD
)(wParam
>> 16);
7684 sNotify
.flags
= (UINT
)(lParam
);
7686 SendNotify(pData
, &sNotify
.hdr
);
7688 iSub
= pData
->uSelectedSub
;
7690 if(pData
->aColumn
[iSub
].bEdit
) { // Auto-Edit starten
7691 if(GetAsyncKeyState(VK_CONTROL
) & 0x8000) {
7692 wParam
= VK_ICONCLK
;
7696 TreeListStartAutoEdit(pData
, iSub
, wParam
, lParam
);
7698 TreeListStartNotifyEdit(pData
, pData
->uSelectedItem
, iSub
, wParam
, lParam
);
7704 pEntry
= pData
->pTreeItems
[pData
->uSelectedItem
];
7705 iDel
= (GetAsyncKeyState(VK_SHIFT
) & 0x8000) ? 0 : TVC_DESELECT
;
7706 iScr
= GetAsyncKeyState(VK_CONTROL
) & 0x8000;
7708 if(iDel
&& iScr
) // Ende oder Anfang wählen
7709 if(wParam
== VK_HOME
|| wParam
== VK_END
)
7710 if(pData
->uStyleEx
& TVS_EX_HOMEENDSELECT
) {
7711 iDel
= TVC_DESELECT
;
7715 if(iDel
&& iScr
) { // Das Fenster scrollen
7716 iLine
= pData
->uScrollY
;
7717 iSub
= pData
->uScrollX
;
7721 iLine
= pData
->uTreeItemsCount
; // Ans Ende scrollen
7722 iLine
-= pData
->uPageEnties
;
7726 iLine
= 0; // Zum Anfang scrollen
7730 iSub
-= 16; // Links scrollen
7734 iSub
+= 16; // Rechts scrollen
7738 iLine
--; // Nach oben scrollen
7742 iLine
++; // Nach unten scrollen
7746 iLine
-= pData
->uSizeX
; // Eine Seite nach oben
7750 iLine
+= pData
->uSizeX
; // Eine Seite nach unten
7755 break; // Expantieren und schließen
7756 if(pEntry
->bFlags
& TVIX_HASBUTTON
) {
7757 TreeListToggleItem(pData
, pData
->uSelectedItem
, 0);
7767 if(iLine
!= (int)pData
->uScrollY
) {
7768 iMax
= pData
->uItemPosCount
;
7769 iMax
-= pData
->uPageEnties
- 1;
7775 if(iLine
!= (int)pData
->uScrollY
)
7776 if(!(pData
->uStyle
& TVS_NOSCROLL
)) {
7777 pData
->uScrollY
= iLine
;
7778 SetScrollPos(pData
->hWnd
, SB_VERT
, iLine
, TRUE
);
7783 if(iSub
!= (int)pData
->uScrollX
) {
7784 uVal
= pData
->uColumnCount
;
7786 iMax
= pData
->aColumnXpos
[uVal
] - pData
->uSizeX
/ 2;
7788 iMax
= pData
->iMaxSizeX
;
7789 iMax
-= pData
->uSizeX
- pData
->uSizeX
/ 2;
7795 if(iSub
!= (int)pData
->uScrollX
)
7796 if(!(pData
->uStyle
& TVS_NOSCROLL
)) {
7797 pData
->uScrollX
= iSub
;
7798 SetScrollPos(pData
->hWnd
, SB_HORZ
, iSub
, TRUE
);
7801 if(pData
->hHeader
) {
7802 MoveWindow(pData
->hHeader
, -iSub
, 0, pData
->uSizeX
+ iSub
, pData
->uStartPixel
, TRUE
);
7806 } else { // Einen anderen Eintrag auswählen
7807 iSub
= pData
->uSelectedSub
;
7808 iCol
= pData
->aColumn
[iSub
].bIndex
;
7816 uTemp
= pData
->uFocusItem
;
7817 if(uTemp
) { // Ist ein Focus definiert
7818 pTemp
= pData
->pTreeItems
[uTemp
];
7820 while(pTemp
&& !pTemp
->uShowPos
) {
7821 pTemp
= pData
->pTreeItems
[pTemp
->uParent
];
7825 iLine
= pTemp
->uShowPos
- 1;
7826 iSub
= pData
->uFocusSub
;
7827 iCol
= pData
->aColumn
[iSub
].bIndex
;
7830 if(pData
->uSelectedCount
> 1) {
7834 TreeListRemoveFocus(pData
);
7838 iLine
= pEntry
->uShowPos
- 1;
7842 uTemp
= pData
->uSelectedItem
;
7849 iLine
= pData
->uItemPosCount
- 1;
7855 if(pData
->uColumnCount
> 1 && (pData
->uStyleEx
& TVS_EX_SUBSELECT
)) {
7858 iSub
= pData
->aColumnPos
[iCol
];
7859 if(pData
->aColumn
[iSub
].sReal
> 0)
7865 if(!(pEntry
->uState
& TVIS_EXPANDED
) || !pEntry
->uFirstChild
) {
7866 pTemp
= pData
->pTreeItems
[pEntry
->uParent
];
7868 iLine
= pTemp
->uShowPos
- 1;
7872 if(pEntry
->bFlags
& TVIX_HASBUTTON
) {
7873 TreeListToggleItem(pData
, pData
->uSelectedItem
, 0);
7880 if(pData
->uColumnCount
> 1 && (pData
->uStyleEx
& TVS_EX_SUBSELECT
)) {
7881 while(iCol
+ 1 < (int)pData
->uColumnCount
) {
7883 iSub
= pData
->aColumnPos
[iCol
];
7884 if(pData
->aColumn
[iSub
].sReal
> 0)
7890 if(pEntry
->uState
& TVIS_EXPANDED
) {
7895 if(pEntry
->bFlags
& TVIX_HASBUTTON
) {
7896 TreeListToggleItem(pData
, pData
->uSelectedItem
, 0);
7910 iAdd
= pData
->uPageEnties
- 1; // Eine Seite nach oben
7917 iAdd
= pData
->uPageEnties
- 1; // Eine Seite nach unten
7923 case VK_BACK
: // Eine Ebene höher
7925 uItem
= pEntry
->uParent
;
7929 iLine
= pData
->pTreeItems
[uItem
]->uShowPos
- 1;
7938 if(pEntry
&& iCol
== 0 && (pData
->uStyle
& TVS_CHECKBOXES
)) {
7939 TreeListChangeCheckbox(pData
, pData
->uSelectedItem
, 0, 0);
7949 if(iCol
>= (int)pData
->uColumnCount
)
7950 iCol
= pData
->uColumnCount
- 1;
7953 if(iLine
>= (int)pData
->uItemPosCount
)
7954 iLine
= pData
->uItemPosCount
- 1;
7958 if(!(pData
->uStyleEx
& TVS_EX_SUBSELECT
))
7961 if(pData
->uItemPosCount
> 0)
7962 if(iLine
!= iOldLine
|| iCol
!= iOldCol
) { // Wurde ein anderer Eintrag ausgewählt
7963 if(pData
->uSelectedCount
> 1) {
7964 TreeListRemoveFocus(pData
);
7966 pData
->uSelectedBase
= uTemp
;
7971 if(pData
->cReSelect
) { // Die Shift-Auswahl neu erstellen
7972 iDel
= TVC_DESELECT
;
7975 uItem
= pData
->pItemPos
[iLine
];
7976 pTemp
= pData
->pTreeItems
[uItem
];
7977 iSub
= pData
->aColumnPos
[iCol
];
7978 iFocus
= (pTemp
&& (pTemp
->uState
& TVIS_SELECTED
)) ? TVC_ONLYFOCUS
: 0;
7980 TreeListSelectItem(pData
, uItem
, iSub
, TVC_BYKEYBOARD
| iDel
| iFocus
);
7982 if(!(pData
->uStyle
& TVS_NOSCROLL
)) {
7983 TreeListEnsureVisible(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
7986 if(pData
->cReSelect
&& pData
->uSelectedBase
) { // Shift-Select neu auswählen
7987 uTemp
= pData
->uSelectedBase
;
7988 pTemp
= pData
->pTreeItems
[uTemp
];
7991 while(pTemp
&& pTemp
->uShowPos
== 0) {
7992 pTemp
= pData
->pTreeItems
[pTemp
->uParent
];
7997 if(pTemp
&& !iShift
) {
7998 if(!(pTemp
->uState
& TVIS_SELECTED
)) {
7999 TreeListXorSelectItem(pData
, uTemp
, TVC_BYKEYBOARD
);
8002 iLineCmp
= pTemp
->uShowPos
- 1;
8003 if(iLineCmp
< iLine
) {
8011 uTemp
= TreeListNextUnselUntil(pData
, uTemp
, uStop
);
8014 TreeListXorSelectItem(pData
, uTemp
, TVC_BYKEYBOARD
);
8018 pData
->cReSelect
= 0;
8021 if((pData
->uStyleEx
& TVS_EX_MULTISELECT
) && !iDel
) {
8022 uVal
= pData
->uSelectedBase
;
8023 pTemp
= pData
->pTreeItems
[uVal
];
8024 iBase
= (pTemp
) ? pTemp
->uShowPos
- 1 : -1;
8026 if(iLine
> iOldLine
) { // Nach oben oder nach unten
8027 iMax
= (iOldLine
> iBase
) ? iOldLine
+ 1 : iOldLine
;
8033 iPos
= (iOldLine
< iBase
) ? iOldLine
- 1 : iOldLine
;
8038 for(; iPos
>= iMax
; iPos
--) { // Übersprungene Einträge mit aus/abwählen
8039 uItem
= pData
->pItemPos
[iPos
];
8041 if(iPos
!= iLine
&& iPos
!= iBase
) {
8042 if(!TreeListXorSelectItem(pData
, uItem
, TVC_BYKEYBOARD
))
8046 pTemp
= pData
->pTreeItems
[uItem
]; // Auch unsichtbare Kinder abwählen
8048 iSel
= pTemp
->uState
& TVIS_SELECTED
;
8049 pTemp
= pData
->pTreeItems
[pTemp
->uFirstChild
];
8050 if(!pTemp
|| pTemp
->uShowPos
)
8053 for(uTemp
= uItem
;;) {
8054 uTemp
= TreeListNextSelUntil(pData
, uTemp
, uItem
);
8057 TreeListXorSelectItem(pData
, uTemp
, TVC_BYKEYBOARD
);
8060 for(uTemp
= uItem
;;) {
8061 uTemp
= TreeListNextUnselUntil(pData
, uTemp
, uItem
);
8064 TreeListXorSelectItem(pData
, uTemp
, TVC_BYKEYBOARD
);
8075 sNotify
.hdr
.code
= TVN_KEYDOWN
;
8076 sNotify
.wVKey
= (WORD
)(wParam
);
8077 sNotify
.wScan
= (WORD
)(wParam
>> 16);
8078 sNotify
.flags
= (UINT
)(lParam
);
8082 pData
->cKeyIgnore
= (char)SendNotify(pData
, &sNotify
.hdr
);
8086 //*****************************************************************************
8088 //* TreeListSortItemsEx
8090 //*****************************************************************************
8091 // Sortiert die Kindereinträge eines Eintrages mitteles einer Funktion
8092 // pData : Zeiger auf die Fensterdaten
8093 // pSortData : Ist ein Zeiger auf die Sortiertaten
8094 // iMode : 1=Rekursiv sortieren
8095 // Ergibt 1 wenn ok sonst 0
8096 static int TreeListSortItemsEx(TreeListData
*pData
, TV_SORTEX
*pSortData
, int iMode
) {
8109 unsigned *pItemList
;
8111 unsigned uEnties
[128];
8115 PFNTVCOMPAREEX pCompare
;
8116 HTREEITEM hItemTemp
;
8120 int iLower
, iUpper
, iMiddle
, iCmp
;
8121 int uMemL
[30], uMemU
[30];
8127 pList
= pData
->pTreeItems
;
8129 uParent
= U(pSortData
->hParent
);
8130 if(uParent
> pData
->uTreeItemsMax
) { // Root-Eintrag sortieren
8131 if(uParent
!= U(TVI_ROOT
))
8134 uLast
= pData
->uLastChild
;
8135 uFirst
= pData
->uFirstChild
;
8138 if(uFirst
== uLast
) { // Einzelner Eintrag
8139 pNext
= pList
[uFirst
];
8140 if(!pNext
->uFirstChild
)
8143 sSort
.hParent
= (HTREEITEM
)uFirst
;
8144 sSort
.lParam
= pSortData
->lParam
;
8145 sSort
.lpfnCompare
= pSortData
->lpfnCompare
;
8146 TreeListSortItemsEx(pData
, &sSort
, iMode
);
8152 } else { // Untereintrag sortieren
8153 pParent
= pList
[uParent
];
8157 uLast
= pParent
->uLastChild
;
8158 uFirst
= pParent
->uFirstChild
;
8161 if(uFirst
== uLast
) { // Einzelner Eintrag
8162 pNext
= pList
[uFirst
];
8163 if(!pNext
->uFirstChild
)
8166 sSort
.hParent
= (HTREEITEM
)uFirst
;
8167 sSort
.lParam
= pSortData
->lParam
;
8168 sSort
.lpfnCompare
= pSortData
->lpfnCompare
;
8169 TreeListSortItemsEx(pData
, &sSort
, iMode
);
8174 if(iMode
) { // Sortiere die Untereinträge
8175 pNext
= pList
[uFirst
];
8176 sSort
.hParent
= (HTREEITEM
)uFirst
;
8177 sSort
.lParam
= pSortData
->lParam
;
8178 sSort
.lpfnCompare
= pSortData
->lpfnCompare
;
8181 if(pNext
->uFirstChild
) {
8182 TreeListSortItemsEx(pData
, &sSort
, SORT_NOUPDATE
);
8185 sSort
.hParent
= (HTREEITEM
)pNext
->uNextItem
;
8186 pNext
= pList
[pNext
->uNextItem
];
8193 //******************** Erzeuge Eintragsliste **********************************
8195 pItemList
= uEnties
;
8199 do { // Alle Kindeinträge suchen
8202 pItemNew
= new(unsigned, uMax
);
8203 memcpy(pItemNew
, pItemList
, uPos
* sizeof(pItemList
[0]));
8206 pItemList
= pItemNew
;
8209 pItemList
[uPos
] = uItem
;
8210 pNext
= pList
[uItem
];
8211 uItem
= pNext
->uNextItem
;
8216 //************************* Qsort-Algorithmus *********************************
8217 #define XCHANGE_MEM(a,b) uTemp=pItemList[a];pItemList[a]=pItemList[b];pItemList[b]=uTemp;
8219 pData
->cLockChanges
= 1;
8222 hTreeWnd
= pData
->hWnd
;
8223 pCompare
= pSortData
->lpfnCompare
;
8224 lParamSort
= pSortData
->lParam
;
8231 iMiddle
= (iStart
+ iLast
) >> 1; // Mitte bereichnen
8234 XCHANGE_MEM(iMiddle
, iLower
);
8236 uItem
= pItemList
[iStart
];
8237 hItemTemp
= (HTREEITEM
)uItem
;
8238 lParamTemp
= pList
[uItem
]->lParam
;
8245 uItem
= pItemList
[iLower
];
8246 iCmp
= pCompare(hTreeWnd
, (HTREEITEM
)uItem
, hItemTemp
, pList
[uItem
]->lParam
, lParamTemp
, lParamSort
);
8251 if(iUpper
<= iStart
)
8253 uItem
= pItemList
[iUpper
];
8254 iCmp
= pCompare(hTreeWnd
, (HTREEITEM
)uItem
, hItemTemp
, pList
[uItem
]->lParam
, lParamTemp
, lParamSort
);
8260 XCHANGE_MEM(iUpper
, iLower
);
8263 XCHANGE_MEM(iStart
, iUpper
);
8265 if(iUpper
- 1 - iStart
>= iLast
- iLower
) {
8266 if(iStart
+ 1 < iUpper
) {
8267 uMemL
[iLevel
] = iStart
;
8268 uMemU
[iLevel
] = iUpper
- 1;
8271 if(iLower
< iLast
) {
8276 if(iLower
< iLast
) {
8277 uMemL
[iLevel
] = iLower
;
8278 uMemU
[iLevel
] = iLast
;
8282 if(iStart
+ 1 < iUpper
) {
8287 // Eine Ebene absteigen
8290 if(iLevel
>= 0) { // Noch Ebenen vorhanden
8291 iStart
= uMemL
[iLevel
];
8292 iLast
= uMemU
[iLevel
];
8300 pData
->cLockChanges
= 0;
8302 //******************** Einträge neu einsortirenen *****************************
8305 pEntry
= pList
[uParent
];
8307 pData
->uFirstChild
= pItemList
[ 0 ];
8308 pData
->uLastChild
= pItemList
[uPos
];
8310 pEntry
->uFirstChild
= pItemList
[ 0 ];
8311 pEntry
->uLastChild
= pItemList
[uPos
];
8315 uItem
= pItemList
[0];
8317 for(uNum
= 0; uNum
< uPos
;) { // Kinder neu einhängen
8318 pEntry
= pList
[uItem
];
8319 pEntry
->uPrevItem
= uLast
;
8323 uItem
= pItemList
[uNum
];
8325 pEntry
->uNextItem
= uItem
;
8328 pEntry
= pList
[uItem
];
8329 pEntry
->uPrevItem
= uLast
;
8330 pEntry
->uNextItem
= 0;
8332 if(iMode
!= SORT_NOUPDATE
) // Ausgabeliste neuerstellen
8333 if(uParent
== 0 || (pParent
->uShowPos
&& (pParent
->uState
& TVIS_EXPANDED
))) {
8334 UpdateItems(pData
, uParent
);
8336 if(pData
->uStyle
& TVS_SHOWSELALWAYS
)
8337 if(pData
->uSelectedItem
) {
8338 TreeListEnsureVisible(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
8348 //*****************************************************************************
8350 //* TreeListSortItemsCb
8352 //*****************************************************************************
8353 // Sortiert die Kindereinträge eines Eintrages mitteles einer Funktion
8354 // pData : Zeiger auf die Fensterdaten
8355 // pSortData : Ist ein Zeiger auf die Sortiertaten
8356 // iMode : 1=Rekursiv sortieren
8357 // Ergibt 1 wenn ok sonst 0
8358 static int TreeListSortItemsCb(TreeListData
*pData
, TV_SORTCB
*pSortData
, int iMode
) {
8371 unsigned *pItemList
;
8373 unsigned uEnties
[128];
8377 PFNTVCOMPARE pCompare
;
8380 int iLower
, iUpper
, iMiddle
, iCmp
;
8381 int uMemL
[30], uMemU
[30];
8386 pList
= pData
->pTreeItems
;
8388 uParent
= U(pSortData
->hParent
);
8389 if(uParent
> pData
->uTreeItemsMax
) { // Root-Eintrag sortieren
8390 if(uParent
!= U(TVI_ROOT
))
8393 uLast
= pData
->uLastChild
;
8394 uFirst
= pData
->uFirstChild
;
8397 if(uFirst
== uLast
) { // Einzelner Eintrag
8398 pNext
= pList
[uFirst
];
8399 if(!pNext
->uFirstChild
)
8402 sSort
.hParent
= (HTREEITEM
)uFirst
;
8403 sSort
.lParam
= pSortData
->lParam
;
8404 sSort
.lpfnCompare
= pSortData
->lpfnCompare
;
8405 TreeListSortItemsCb(pData
, &sSort
, iMode
);
8411 } else { // Untereintrag sortieren
8412 pParent
= pList
[uParent
];
8416 uLast
= pData
->uLastChild
;
8417 uFirst
= pParent
->uFirstChild
;
8420 if(uFirst
== uLast
) { // Einzelner Eintrag
8421 pNext
= pList
[uFirst
];
8422 if(!pNext
->uFirstChild
)
8425 sSort
.hParent
= (HTREEITEM
)uFirst
;
8426 sSort
.lParam
= pSortData
->lParam
;
8427 sSort
.lpfnCompare
= pSortData
->lpfnCompare
;
8428 TreeListSortItemsCb(pData
, &sSort
, iMode
);
8433 if(iMode
) { // Sortiere die Untereinträge
8434 pNext
= pList
[uFirst
];
8435 sSort
.hParent
= (HTREEITEM
)uFirst
;
8436 sSort
.lParam
= pSortData
->lParam
;
8437 sSort
.lpfnCompare
= pSortData
->lpfnCompare
;
8440 if(pNext
->uFirstChild
) {
8441 TreeListSortItemsCb(pData
, &sSort
, SORT_NOUPDATE
);
8444 sSort
.hParent
= (HTREEITEM
)pNext
->uNextItem
;
8445 pNext
= pList
[pNext
->uNextItem
];
8452 //******************** Erzeuge Eintragsliste **********************************
8454 pItemList
= uEnties
;
8458 do { // Alle Kindeinträge suchen
8461 pItemNew
= new(unsigned, uMax
);
8462 memcpy(pItemNew
, pItemList
, uPos
* sizeof(pItemList
[0]));
8465 pItemList
= pItemNew
;
8468 pItemList
[uPos
] = uItem
;
8469 pNext
= pList
[uItem
];
8470 uItem
= pNext
->uNextItem
;
8474 //************************* Qsort-Algorithmus *********************************
8475 #define XCHANGE_MEM(a,b) uTemp=pItemList[a];pItemList[a]=pItemList[b];pItemList[b]=uTemp;
8477 pData
->cLockChanges
= 1;
8480 pCompare
= pSortData
->lpfnCompare
;
8481 lParamSort
= pSortData
->lParam
;
8488 iMiddle
= (iStart
+ iLast
) >> 1; // Mitte bereichnen
8491 XCHANGE_MEM(iMiddle
, iLower
);
8493 uItem
= pItemList
[iStart
];
8494 lParamTemp
= pList
[uItem
]->lParam
;
8501 uItem
= pItemList
[iLower
];
8502 iCmp
= pCompare(pList
[uItem
]->lParam
, lParamTemp
, lParamSort
);
8507 if(iUpper
<= iStart
)
8509 uItem
= pItemList
[iUpper
];
8510 iCmp
= pCompare(pList
[uItem
]->lParam
, lParamTemp
, lParamSort
);
8516 XCHANGE_MEM(iUpper
, iLower
);
8519 XCHANGE_MEM(iStart
, iUpper
);
8521 if(iUpper
- 1 - iStart
>= iLast
- iLower
) {
8522 if(iStart
+ 1 < iUpper
) {
8523 uMemL
[iLevel
] = iStart
;
8524 uMemU
[iLevel
] = iUpper
- 1;
8527 if(iLower
< iLast
) {
8532 if(iLower
< iLast
) {
8533 uMemL
[iLevel
] = iLower
;
8534 uMemU
[iLevel
] = iLast
;
8538 if(iStart
+ 1 < iUpper
) {
8543 // Eine Ebene absteigen
8546 if(iLevel
>= 0) { // Noch Ebenen vorhanden
8547 iStart
= uMemL
[iLevel
];
8548 iLast
= uMemU
[iLevel
];
8556 pData
->cLockChanges
= 0;
8558 //******************** Einträge neu einsortirenen *****************************
8561 pEntry
= pList
[uParent
];
8563 pData
->uFirstChild
= pItemList
[ 0 ];
8564 pData
->uLastChild
= pItemList
[uPos
];
8566 pEntry
->uFirstChild
= pItemList
[ 0 ];
8567 pEntry
->uLastChild
= pItemList
[uPos
];
8571 uItem
= pItemList
[0];
8573 for(uNum
= 0; uNum
< uPos
;) { // Kinder neu einhängen
8574 pEntry
= pList
[uItem
];
8575 pEntry
->uPrevItem
= uLast
;
8579 uItem
= pItemList
[uNum
];
8581 pEntry
->uNextItem
= uItem
;
8584 pEntry
= pList
[uItem
];
8585 pEntry
->uPrevItem
= uLast
;
8586 pEntry
->uNextItem
= 0;
8588 if(iMode
!= SORT_NOUPDATE
) // Ausgabeliste neuerstellen
8589 if(uParent
== 0 || (pParent
->uShowPos
&& (pParent
->uState
& TVIS_EXPANDED
))) {
8590 UpdateItems(pData
, uParent
);
8592 if(pData
->uStyle
& TVS_SHOWSELALWAYS
)
8593 if(pData
->uSelectedItem
) {
8594 TreeListEnsureVisible(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
8604 //*****************************************************************************
8606 //* TreeListSortItems
8608 //*****************************************************************************
8609 // Sortiert die Kindereinträge eines Eintrages via Text
8610 // pData : Zeiger auf die Fensterdaten
8611 // pSortData : Ist ein Zeiger auf die Sortiertaten
8612 // iMode : 1=Rekursiv sortieren
8613 // Ergibt 1 wenn ok sonst 0
8614 static int TreeListSortItems(TreeListData
*pData
, unsigned uParent
, int iMode
) {
8625 unsigned *pItemList
;
8627 unsigned uEnties
[128];
8633 int iLower
, iUpper
, iMiddle
, iCmp
;
8634 int uMemL
[30], uMemU
[30];
8641 pList
= pData
->pTreeItems
;
8643 if(uParent
> pData
->uTreeItemsMax
) { // Root-Eintrag sortieren
8644 if(uParent
!= U(TVI_ROOT
))
8647 uLast
= pData
->uLastChild
;
8648 uFirst
= pData
->uFirstChild
;
8651 if(uFirst
== pData
->uLastChild
) { // Einzelner Eintrag
8652 pNext
= pList
[uFirst
];
8653 if(!pNext
->uFirstChild
)
8656 TreeListSortItems(pData
, uFirst
, iMode
);
8660 pList
= pData
->pTreeItems
;
8663 } else { // Untereintrag sortieren
8664 pParent
= pList
[uParent
];
8668 uLast
= pParent
->uLastChild
;
8669 uFirst
= pParent
->uFirstChild
;
8672 if(uFirst
== pParent
->uLastChild
) { // Einzelner Eintrag
8673 pNext
= pList
[uFirst
];
8674 if(!pNext
->uFirstChild
)
8677 TreeListSortItems(pData
, uFirst
, iMode
);
8682 if(iMode
) { // Sortiere die Untereinträge
8686 pNext
= pList
[uItem
];
8687 if(pNext
->uFirstChild
) {
8688 TreeListSortItems(pData
, uItem
, SORT_NOUPDATE
);
8691 uItem
= pNext
->uNextItem
;
8698 //******************** Erzeuge Eintragsliste **********************************
8700 pItemList
= uEnties
;
8704 do { // Alle Kindeinträge suchen
8707 pItemNew
= new(unsigned, uMax
);
8708 memcpy(pItemNew
, pItemList
, uPos
* sizeof(pItemList
[0]));
8711 pItemList
= pItemNew
;
8714 pItemList
[uPos
] = uItem
;
8715 pNext
= pList
[uItem
];
8716 uItem
= pNext
->uNextItem
;
8720 //************************* Qsort-Algorithmus *********************************
8721 #define XCHANGE_MEM(a,b) uTemp=pItemList[a];pItemList[a]=pItemList[b];pItemList[b]=uTemp;
8723 pData
->cLockChanges
= 1;
8732 iMiddle
= (iStart
+ iLast
) >> 1; // Mitte bereichnen
8735 XCHANGE_MEM(iMiddle
, iLower
);
8737 uItem
= pItemList
[iStart
];
8738 pEntry
= pList
[uItem
];
8739 if(pEntry
->bCallback
& TVIF_TEXT
) {
8742 CallbackEntry(pData
, pEntry
, uItem
, TVIF_TEXT
, &iNone
, &uSize
, &pTextTemp
);
8745 pTextTemp
= pEntry
->pText
;
8754 uItem
= pItemList
[iLower
];
8755 pEntry
= pList
[uItem
];
8756 if(pEntry
->bCallback
& TVIF_TEXT
) {
8759 CallbackEntry(pData
, pEntry
, uItem
, TVIF_TEXT
, &iNone
, &uSize
, &pText
);
8762 pText
= pEntry
->pText
;
8765 iCmp
= str_icmp(pText
, pTextTemp
);
8771 if(iUpper
<= iStart
)
8773 uItem
= pItemList
[iUpper
];
8774 pEntry
= pList
[uItem
];
8775 if(pEntry
->bCallback
& TVIF_TEXT
) {
8777 CallbackEntry(pData
, pEntry
, uItem
, TVIF_TEXT
, &iNone
, &uSize
, &pText
);
8780 pText
= pEntry
->pText
;
8783 iCmp
= str_icmp(pText
, pTextTemp
);
8789 XCHANGE_MEM(iUpper
, iLower
);
8792 XCHANGE_MEM(iStart
, iUpper
);
8794 if(iUpper
- 1 - iStart
>= iLast
- iLower
) {
8795 if(iStart
+ 1 < iUpper
) {
8796 uMemL
[iLevel
] = iStart
;
8797 uMemU
[iLevel
] = iUpper
- 1;
8800 if(iLower
< iLast
) {
8805 if(iLower
< iLast
) {
8806 uMemL
[iLevel
] = iLower
;
8807 uMemU
[iLevel
] = iLast
;
8811 if(iStart
+ 1 < iUpper
) {
8816 // Eine Ebene absteigen
8819 if(iLevel
>= 0) { // Noch Ebenen vorhanden
8820 iStart
= uMemL
[iLevel
];
8821 iLast
= uMemU
[iLevel
];
8829 pData
->cLockChanges
= 0;
8831 //******************** Einträge neu einsortirenen *****************************
8834 pEntry
= pList
[uParent
];
8836 pData
->uFirstChild
= pItemList
[ 0 ];
8837 pData
->uLastChild
= pItemList
[uPos
];
8839 pEntry
->uFirstChild
= pItemList
[ 0 ];
8840 pEntry
->uLastChild
= pItemList
[uPos
];
8844 uItem
= pItemList
[0];
8846 for(uNum
= 0; uNum
< uPos
;) { // Kinder neu einhängen
8847 pEntry
= pList
[uItem
];
8848 pEntry
->uPrevItem
= uLast
;
8852 uItem
= pItemList
[uNum
];
8854 pEntry
->uNextItem
= uItem
;
8857 pEntry
= pList
[uItem
];
8858 pEntry
->uPrevItem
= uLast
;
8859 pEntry
->uNextItem
= 0;
8861 if(iMode
!= SORT_NOUPDATE
) // Ausgabeliste neuerstellen
8862 if(uParent
== 0 || (pParent
->uShowPos
&& (pParent
->uState
& TVIS_EXPANDED
))) {
8863 UpdateItems(pData
, uParent
);
8865 if(pData
->uStyle
& TVS_SHOWSELALWAYS
)
8866 if(pData
->uSelectedItem
) {
8867 TreeListEnsureVisible(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
8877 //*****************************************************************************
8879 //* TreeListEndLabelEdit
8881 //*****************************************************************************
8882 // Beendet das editiert eines Eintrages
8883 // pData : Zeiger auf Fensterdaten
8884 // iMode : Gibt an wie das Editieren beendet wurde
8885 // 0 = Es gab es einen Abbruch mit ESC
8886 // 1 = Eingabe ohne Enter
8887 // 2 = Eingabe mit Enter
8888 // Ergibt das Handle des Edit-Controlls oder NULL bei einem Fehler
8889 static int TreeListEndLabelEdit(TreeListData
*pData
, int iMode
) {
8891 NMTVDISPINFO sNotify
;
8911 uItem
= pData
->uEditItem
;
8912 uSub
= pData
->uEditSub
;
8913 cCb
= pData
->cEditCb
;
8915 pData
->uEditItem
= 0;
8916 pData
->uEditSub
= 0;
8919 if(uItem
> pData
->uTreeItemsMax
|| uSub
>= pData
->uColumnCount
) {
8923 pEntry
= pData
->pTreeItems
[uItem
];
8928 if(iMode
) { // Eingabe
8929 GetWindowText(pData
->hEdit
, cText
, sizeof(cText
) / sizeof(cText
[0]));
8930 cText
[sizeof(cText
) / sizeof(cText
[0]) - 1] = 0;
8931 sNotify
.item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_TEXT
| TVIF_SUBITEM
;
8932 sNotify
.item
.cchTextMax
= sizeof(cText
) / sizeof(cText
[0]) - 1;
8933 sNotify
.item
.pszText
= cText
;
8935 if(pData
->cColumnStart
) { // Wurde ein Text eingegeben
8936 sNotify
.item
.mask
|= TVIF_TEXTCHANGED
;
8939 if(iMode
== 2) { // Wurde der Text mit RETURN eingegeben
8940 sNotify
.item
.mask
|= TVIF_RETURNEXIT
;
8943 sNotify
.item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_CANCELED
| TVIF_SUBITEM
;
8944 sNotify
.item
.pszText
= NULL
;
8945 sNotify
.item
.cchTextMax
= 0;
8948 sNotify
.hdr
.code
= TVN_ENDLABELEDIT
;
8949 sNotify
.item
.hItem
= (HTREEITEM
)uItem
;
8950 sNotify
.item
.stateMask
= 0xFFFFFFFF;
8951 sNotify
.item
.cChildren
= uSub
;
8953 if(uSub
) { // Wurde der Text in einer Sub-Spalte geändert
8954 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
8956 sNotify
.item
.state
= 0;
8957 sNotify
.item
.lParam
= 0;
8959 sNotify
.item
.state
= pEntry
->uState
& TVIS_BASEFLAGS
;
8960 sNotify
.item
.state
|= pExtra
->uState
;
8961 sNotify
.item
.lParam
= pEntry
->lParam
;
8964 sNotify
.item
.state
= pEntry
->uState
;
8965 sNotify
.item
.lParam
= pEntry
->lParam
;
8969 ShowWindow(pData
->hEdit
, SW_HIDE
);
8970 lRet
= SendNotify(pData
, &sNotify
.hdr
);
8976 if(cCb
) { // Callback aufrufen
8977 sNotify
.hdr
.code
= TVN_SETDISPINFO
;
8978 sNotify
.item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_TEXT
| TVIF_SUBITEM
;
8979 sNotify
.item
.stateMask
= (UINT
)~TVIS_BASEFLAGS
;
8980 sNotify
.item
.hItem
= (HTREEITEM
)uItem
;
8981 sNotify
.item
.cChildren
= uSub
;
8984 SendNotify(pData
, &sNotify
.hdr
);
8986 } else { // Neuen Text eingeben
8987 pGetT
= sNotify
.item
.pszText
;
8988 sSet
.mask
= TVIF_SUBITEM
| TVIF_TEXT
;
8989 sSet
.cchTextMax
= sNotify
.item
.cchTextMax
;
8990 sSet
.hItem
= (HTREEITEM
)uItem
;
8991 sSet
.pszText
= pGetT
;
8992 sSet
.cChildren
= uSub
;
8994 iIcon
= pData
->aColumn
[uSub
].iCbIcon
;
8995 iAuto
= pData
->aColumn
[uSub
].bEdit
;
8997 if(iIcon
>= 0 && iAuto
!= TVAX_NONE
) { // Auch ein Icon zuweisen
9000 if((1 << iAuto
) & ((1 << TVAX_CBLIST
) | (1 << TVAX_COMBO
))) {
9001 iPos
= (int)SendMessage(pData
->hEdit
, CB_GETCURSEL
, 0, 0);
9002 sSet
.mask
|= TVIF_IMAGE
| TVIF_SELECTEDIMAGE
;
9003 sSet
.iImage
= iIcon
+ iPos
;
9004 sSet
.iSelectedImage
= sSet
.iImage
;
9008 iMax
= pData
->aColumn
[uSub
].bCbSize
;
9014 if(pData
->aColumn
[uSub
].bFlags
& TVAE_PTRLIST
) { // Zeigerliste char *pTexte[]={"1","2",NULL};
9015 pList
= (LPCTSTR
*)pData
->aColumn
[uSub
].pCbData
;
9017 for(iPos
= 0; iPos
< iMax
; iPos
++) {
9020 if(!str_cmp(pGetT
, pList
[iPos
]))
9023 } else { // Textliste char *pText="1|2|3";
9024 pText
= (LPTSTR
)pData
->aColumn
[uSub
].pCbData
;
9025 cChar
= (TCHAR
)pData
->aColumn
[uSub
].bCbChar
;
9027 for(iPos
= 0; iPos
< iMax
; iPos
++) {
9028 for(iLen
= 0; pText
[iLen
]; iLen
++) {
9029 if(pText
[iLen
] == cChar
)
9033 if(str_ncmp(pGetT
, pText
, iLen
) == 0 && !pGetT
[iLen
]) {
9039 if(pText
[0] == cChar
)
9046 sSet
.mask
|= TVIF_IMAGE
| TVIF_SELECTEDIMAGE
;
9047 sSet
.iImage
= iIcon
+ iSel
;
9048 sSet
.iSelectedImage
= sSet
.iImage
;
9052 if(pData
->aColumn
[uSub
].bFlags
& TVAE_NEXTLINE
&& // In die nächste Zeile springen
9053 iMode
== 2 && iAuto
!= TVAX_NONE
&& iAuto
!= TVAX_STEP
) {
9054 if(!pData
->cColumnStart
) {
9055 if(uSub
) { // Hat sich der Text verändert ?
9056 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
9057 if(pExtra
&& pExtra
->pText
) {
9058 if(!_tcscmp(pGetT
, pExtra
->pText
))
9065 pEntry
= pData
->pTreeItems
[uItem
];
9066 if(pEntry
&& pEntry
->pText
) {
9067 if(!_tcscmp(pGetT
, pEntry
->pText
))
9076 TreeListSetItem(pData
, &sSet
);
9078 iLine
= pEntry
->uShowPos
;
9079 if(iLine
< (int)pData
->uItemPosCount
) {
9080 uItem
= pData
->pItemPos
[iLine
];
9081 TreeListSelectItem(pData
, uItem
, pData
->uSelectedSub
, TVC_BYKEYBOARD
| TVC_DESELECT
);
9084 TreeListSetItem(pData
, &sSet
);
9091 //*****************************************************************************
9093 //* TreeListEditLabel
9095 //*****************************************************************************
9096 // Startet das editiert eines Eintrages
9097 // pData : Zeiger auf Fensterdaten
9098 // uItem : Item das editiert werden soll
9099 // uSub : Spalte die editiert werden soll und andere Flags
9100 // TVIR_EDITCOL(n) = Spalte angeben
9101 // TVIR_SELAREA(a,b) = Einen Textbereich auswählen
9102 // TVIR_SETCURSOR(n) = Den Cursor auf eine bestimmte Textstelle
9103 // TVIR_SETAT(n) = Den Cursor auf eine bestimmte Pixelstelle
9104 // TVIR_SELALL = Den gesammten Text wählen
9105 // TVIR_EDITCOMBOLIST = Statt dem Edit-Fenster eine ComboBox nur mit Listenauswahl einblenden
9106 // TVIR_EDITFULL = Das Edit-Fenster über die volle Breite einblenden
9107 // TVIR_EDITCOMBOBOX = Statt dem Edit-Fenster eine ComboBox einblenden
9108 // Ergibt das Handle des Edit-Controlls oder NULL bei einem Fehler
9109 static HWND
TreeListEditLabel(TreeListData
*pData
, unsigned uItem
, unsigned uSub
) {
9119 NMTVDISPINFO sNotify
;
9138 uSel
= (uSub
>> 8) & 0x0FFFFF;
9141 if(uSub
>= pData
->uColumnCount
)
9143 if(uItem
> pData
->uTreeItemsMax
)
9145 pEntry
= pData
->pTreeItems
[uItem
];
9149 if(uItem
!= pData
->uSelectedItem
|| uSub
!= pData
->uSelectedSub
) {
9150 uCol
= (pData
->uStyleEx
& TVS_EX_SUBSELECT
) ? uSub
: 0;
9151 iTemp
= TreeListSelectItem(pData
, uItem
, uCol
, TVC_UNKNOWN
);
9154 TreeListEnsureVisible(pData
, uItem
, uSub
);
9156 if(pData
->hEdit
) { // Editfenster löschen
9157 DestroyWindow(pData
->hEdit
);
9161 switch(uBits
& 3) { // Editfenster neu erzeugen
9163 pData
->hEdit
= CreateWindow(_T("COMBOBOX"), NULL
, WS_BORDER
| WS_CHILD
| CBS_AUTOHSCROLL
| CBS_DROPDOWN
| WS_VSCROLL
, 0, 0, 0, 0, pData
->hWnd
, (HMENU
)3, NULL
, NULL
);
9164 pData
->uEditMode
= 1;
9165 SendMessage(pData
->hEdit
, CB_LIMITTEXT
, 2048, 0);
9169 pData
->hEdit
= CreateWindow(_T("COMBOBOX"), NULL
, WS_BORDER
| WS_CHILD
| CBS_AUTOHSCROLL
| CBS_DROPDOWNLIST
| WS_VSCROLL
, 0, 0, 0, 0, pData
->hWnd
, (HMENU
)3, NULL
, NULL
);
9170 pData
->uEditMode
= 2;
9171 SendMessage(pData
->hEdit
, CB_LIMITTEXT
, 2048, 0);
9179 if(pData
->aColumn
[uSub
].bAlign
== DT_RIGHT
)
9181 if(pData
->aColumn
[uSub
].bAlign
== DT_CENTER
)
9185 pData
->hEdit
= CreateWindow(_T("EDIT"), NULL
, WS_BORDER
| WS_CHILD
| ES_AUTOHSCROLL
| uFlags
, 0, 0, 0, 0, pData
->hWnd
, (HMENU
)3, NULL
, NULL
);
9186 pData
->uEditMode
= 0;
9187 SendMessage(pData
->hEdit
, EM_SETLIMITTEXT
, 2048, 0);
9194 if(pSetWindowTheme
) { // Remove the Visual-Styles (XP+)
9195 pSetWindowTheme(pData
->hEdit
, L
"", L
"");
9198 pData
->pProcId3
= (WNDPROC
)GetWindowLongPtr(pData
->hEdit
, GWLP_WNDPROC
);
9199 SetWindowLongPtr(pData
->hEdit
, GWLP_USERDATA
, (LPARAM
)pData
);
9200 SetWindowLongPtr(pData
->hEdit
, GWLP_WNDPROC
, (LPARAM
)EditProc
);
9202 hWnd
= GetWindow(pData
->hEdit
, GW_CHILD
);
9205 pProc
= (WNDPROC
)GetWindowLongPtr(hWnd
, GWLP_WNDPROC
);
9206 SetWindowLongPtr(hWnd
, GWLP_USERDATA
, (LPARAM
)pProc
);
9207 SetWindowLongPtr(hWnd
, GWLP_WNDPROC
, (LPARAM
)EditProc
);
9208 hWnd
= GetNextWindow(hWnd
, GW_HWNDNEXT
);
9213 if(pData
->uEditMode
>= 1) { // ComboBox leeren
9214 SendMessage(pData
->hEdit
, CB_RESETCONTENT
, 0, 0);
9217 if(uSub
== 0) { // Haupteintrag bearbeiten
9218 TreeListGetItemRect(pData
, uItem
, TVIR_GETCOLUMN
| TVIR_TEXT
, &sRect
);
9220 pText
= pEntry
->pText
;
9221 uSize
= pEntry
->uTextSize
;
9222 iPixels
= pEntry
->iTextPixels
+ 10;
9223 lParam
= pEntry
->lParam
;
9224 uState
= pEntry
->uState
;
9225 hFont
= (uState
& TVIS_BOLD
) ? pData
->hFontB
: pData
->hFontN
;
9227 if(pEntry
->bCallback
& TVIF_TEXT
) {
9228 CallbackEntry(pData
, pEntry
, uItem
, TVIF_TEXT
, &iTemp
, &uSize
, &pText
);
9229 hDc
= GetDC(pData
->hWnd
);
9230 SelectObject(hDc
, hFont
);
9231 DrawText(hDc
, pText
, uSize
, &sRect
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
| DT_CALCRECT
);
9232 ReleaseDC(pData
->hWnd
, hDc
);
9233 iPixels
= sRect
.right
- sRect
.left
+ 10;
9237 if(uBits
& 4) { // Volle Spaltenbreite
9238 if(pEntry
->iImage
!= TV_NOIMAGE
) {
9239 uNext
= pData
->aColumnPos
[1];
9240 sRect
.right
= pData
->aColumnXpos
[uNext
];
9241 sRect
.right
-= pData
->uScrollX
;
9244 iPixels
= sRect
.right
- sRect
.left
- 2;
9246 if(pData
->uEditMode
) {
9254 if(pText
&& *pText
) {
9255 iPixels
+= str_len(pText
);
9258 if(pData
->uEditMode
) {
9259 iPixels
+= GetSystemMetrics(SM_CXHSCROLL
);
9262 } else { // Extraeintrag bearbeiten
9264 TreeListGetItemRect(pData
, uItem
, TVIR_GETCOLUMN
| TVIR_COLTOSUB(uSub
), &sRect
);
9266 if(pData
->aColumn
[uSub
].bEdit
>= TVAX_CHECK
) {
9267 sRect
.left
+= pData
->iChecksXsize
;
9268 if(sRect
.right
< sRect
.left
)
9269 sRect
.right
= sRect
.left
+ 1;
9272 TreeListGetItemRect(pData
, uItem
, TVIR_GETCOLUMN
| TVIR_TEXT
| TVIR_COLTOSUB(uSub
), &sRect
);
9275 pExtra
= pData
->pExtraItems
[uSub
- 1][uItem
];
9277 pData
->cTempText1
[0] = 0;
9278 pText
= pData
->cTempText1
;
9279 uSize
= sizeof(pData
->cTempText1
) / sizeof(pData
->cTempText1
[0]);
9280 iPixels
= sRect
.right
- sRect
.left
+ 10;
9281 hFont
= pData
->hFontN
;
9282 uState
= pEntry
->uState
& TVIS_BASEFLAGS
;
9285 pText
= pExtra
->pText
;
9286 uSize
= pExtra
->uTextSize
;
9287 iPixels
= pExtra
->iTextPixels
+ 10;
9288 lParam
= pEntry
->lParam
;
9289 uState
= pExtra
->uState
;
9290 uState
|= pEntry
->uState
& TVIS_BASEFLAGS
;
9291 hFont
= (uState
& TVIS_BOLD
) ? pData
->hFontB
: pData
->hFontN
;
9293 if(pExtra
->bCallback
& TVIF_TEXT
) {
9294 CallbackExtra(pData
, pEntry
, pExtra
, uItem
, uSub
, TVIF_TEXT
, &iTemp
, &uSize
, &pText
);
9295 hDc
= GetDC(pData
->hWnd
);
9296 SelectObject(hDc
, hFont
);
9297 DrawText(hDc
, pText
, uSize
, &sRect
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
| DT_CALCRECT
);
9298 ReleaseDC(pData
->hWnd
, hDc
);
9299 iPixels
= sRect
.right
- sRect
.left
;
9304 if(uBits
& 4) { // Volle Spaltenbreite
9305 if(pExtra
&& pExtra
->iImage
!= TV_NOIMAGE
) {
9306 sRect
.left
+= pData
->iImagesXsize
+ 1;
9309 iPixels
= sRect
.right
- sRect
.left
- 2;
9311 if(pData
->uEditMode
) {
9319 if(pText
&& *pText
) {
9320 iPixels
+= str_len(pText
);
9323 if(pData
->uEditMode
) {
9324 iPixels
+= GetSystemMetrics(SM_CXHSCROLL
);
9327 switch(pData
->aColumn
[uSub
].bAlign
) {
9329 iWidth
= sRect
.right
- sRect
.left
;
9330 sRect
.left
+= iWidth
- iPixels
;
9334 iWidth
= sRect
.right
- sRect
.left
;
9335 sRect
.left
+= (iWidth
- iPixels
) / 2;
9343 sNotify
.hdr
.code
= TVN_BEGINLABELEDIT
;
9344 sNotify
.item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_TEXT
| TVIF_SUBITEM
;
9345 sNotify
.item
.hItem
= (HTREEITEM
)uItem
;
9346 sNotify
.item
.pszText
= (LPTSTR
)pText
;
9347 sNotify
.item
.lParam
= lParam
;
9348 sNotify
.item
.state
= uState
;
9349 sNotify
.item
.cchTextMax
= uSize
;
9350 sNotify
.item
.stateMask
= 0xFFFFFFFF;
9351 sNotify
.item
.cChildren
= uSub
;
9353 lRet
= SendNotify(pData
, &sNotify
.hdr
);
9357 if(lRet
) { // Das Editieren abbrechen
9358 TreeListEndLabelEdit(pData
, 0);
9362 pEntry
= pData
->pTreeItems
[uItem
];
9366 if(pData
->uToolTipItem
) { // Ein offenes Tooltip verstecken
9367 UpdateToolTip(pData
, 0, 0);
9371 SetFocus(pData
->hEdit
);
9374 if(pData
->uEditMode
) {
9378 uHeight
= pData
->iFontHeight
+ 4;
9381 if(pData
->uEditMode
) {
9389 cTemp
= pData
->cColumnStart
;
9390 SetWindowPos(pData
->hEdit
, HWND_TOP
, sRect
.left
+ 2, sRect
.top
+ 1, iPixels
, uHeight
, SWP_SHOWWINDOW
);
9391 SendMessage(pData
->hEdit
, WM_SETFONT
, (WPARAM
)hFont
, 0);
9392 SetWindowText(pData
->hEdit
, pText
);
9393 pData
->cColumnStart
= cTemp
;
9395 switch(uSel
>> 18) { // Welche Textauswahl
9397 uStart
= (uSel
) & 0x01FF; // Einen Textbereich markieren
9398 uSize
= (uSel
>> 9) & 0x01FF;
9402 uStart
= uSel
& 0x3FFFF; // Cursor auf eine bestimmte Stelle
9410 hDc
= GetDC(pData
->hEdit
);
9411 SelectObject(hDc
, hFont
);
9412 GetTextExtentExPoint(hDc
, pText
, uSize
, uSel
, &iWidth
, NULL
, &sSize
);
9414 if(uSize
> 0 && iWidth
< (int)uSize
- 1) { // Halben Buchstaben addieren
9415 GetTextExtentExPoint(hDc
, pText
+ iWidth
, 1, uSel
, NULL
, NULL
, &sSize
);
9416 uSel
+= sSize
.cx
/ 2;
9417 GetTextExtentExPoint(hDc
, pText
, uSize
, uSel
, &iWidth
, NULL
, &sSize
);
9420 ReleaseDC(pData
->hEdit
, hDc
);
9422 if(sSize
.cx
<= (int)uSel
) {
9433 uStart
= 0; // Alles markieren
9437 switch(pData
->uEditMode
) {
9439 SendMessage(pData
->hEdit
, EM_SETSEL
, uStart
, uSize
);
9442 SendMessage(pData
->hEdit
, CB_SETEDITSEL
, 0, MAKELPARAM(uStart
, uSize
));
9451 RedrawWindow(pData
->hEdit
, NULL
, NULL
, RDW_INVALIDATE
| RDW_UPDATENOW
| RDW_ERASE
);
9453 pData
->uLastSel
= MAKELPARAM(uStart
, uSize
);
9454 pData
->uEditItem
= uItem
;
9455 pData
->uEditSub
= uSub
;
9457 return pData
->hEdit
;
9461 //*****************************************************************************
9463 //* TreeListStartAutoEdit
9465 //*****************************************************************************
9466 // Startet die Editierung für einen Wert via Notyfy-Rückfrage.
9467 // pData : Zeiger auf die Fensterdaten
9468 // uItem : Ist der Eintrag der Editiert werden soll
9469 // uSub : Ist die Nummer der Spalte
9470 // wParam : Ist der W-Parameter des Tastendrucks
9471 // VK_EDITCLK bei einem Clickauf das ausgewählte Feld
9472 // VK_DBLCLK bei einem Doppelclick
9473 // VK_RETURN bei einen Enter-Druck
9474 // VK_ISACHAR bei WM_CHAR Nachrichten
9475 // <char> bei einer Zeicheneingabe
9476 // lParam : Ist der L-Parameter des Tastendrucks (bzw. die Koordinaten)
9477 // Ergibt 1 das Editieren gestartet wurde, ansonsten 0
9478 // 0 wenn der Eintrag nicht gewählt wurde
9479 static int TreeListStartNotifyEdit(TreeListData
*pData
, unsigned uItem
, unsigned uSub
, WPARAM wParam
, LPARAM lParam
) {
9482 TV_STARTEDIT sNotify
;
9498 if(!(pData
->uStyle
& TVS_EDITLABELS
))
9500 if(uItem
== 0 || uItem
> pData
->uTreeItemsMax
)
9502 if(uSub
> 0 && uSub
>= pData
->uColumnCount
)
9505 pEntry
= pData
->pTreeItems
[uItem
];
9509 if(wParam
< ' ' && wParam
!= VK_RETURN
) { // Falsche Taste
9513 if(wParam
>= ' ' && wParam
<= 0xFFFF) { // Shift und Cltr prüfen
9514 if(GetKeyState(VK_MENU
) & 0x8000) {
9518 if(GetKeyState(VK_CONTROL
) & 0x8000) {
9523 sNotify
.hdr
.code
= TVN_STARTEDIT
;
9524 sNotify
.uAction
= (UINT
)wParam
;
9525 sNotify
.item
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBITEM
;
9526 sNotify
.item
.hItem
= (HTREEITEM
)uItem
;
9527 sNotify
.item
.stateMask
= 0xFFFFFFFF;
9528 sNotify
.item
.lParam
= pEntry
->lParam
;
9529 sNotify
.item
.cChildren
= uSub
;
9530 sNotify
.uHeight
= 0;
9531 sNotify
.pTextEntries
= 0;
9532 sNotify
.pTextList
= 0;
9533 sNotify
.uMaxEntries
= 255;
9534 sNotify
.ptAction
.x
= LOWORD(lParam
);
9535 sNotify
.ptAction
.y
= HIWORD(lParam
);
9537 if(uSub
) { // Spalte verwenden
9538 pExtra
= pData
->pExtraItems
[uSub
- 1][pData
->uSelectedItem
];
9541 sNotify
.item
.state
= pExtra
->uState
&~TVIS_BASEFLAGS
;
9542 sNotify
.item
.pszText
= pExtra
->pText
;
9543 sNotify
.item
.cchTextMax
= pExtra
->uTextSize
;
9545 sNotify
.item
.state
= 0;
9546 sNotify
.item
.cchTextMax
= 0;
9547 sNotify
.item
.pszText
= _T("");
9550 sNotify
.item
.state
|= pEntry
->uState
& TVIS_BASEFLAGS
;
9551 } else { // Haupteintrag
9552 sNotify
.item
.state
= pEntry
->uState
;
9553 sNotify
.item
.pszText
= pEntry
->pText
;
9554 sNotify
.item
.cchTextMax
= pEntry
->uTextSize
;
9558 lRet
= SendNotify(pData
, &sNotify
.hdr
);
9564 if(wParam
== VK_RETURN
) {
9568 if(wParam
== VK_EDITCLK
) {
9569 if(pData
->uStyleEx
& TVS_EX_NOCURSORSET
) {
9572 TreeListGetItemRect(pData
, uItem
, TVIR_COLTOSUB(uSub
) | TVIR_GETCOLUMN
| TVIR_TEXT
, &sRect
);
9573 uBits
= TVIR_SETAT(LOWORD(lParam
) - sRect
.left
);
9579 cChar
= (TCHAR
)((lRet
>> 8) & 0xFF);
9580 uBits
|= U(lRet
)&TVIR_EDITFULL
;
9582 if(U(lRet
)&TVIR_EDITCOMBOBOX
) { // Eine Combobox anzeigen
9583 uBits
|= (U(lRet
)&TVIR_EDITCOMBOLIST
) ? 0x40000000 : 0x20000000;
9586 hWnd
= TreeListEditLabel(pData
, uItem
, uSub
| uBits
);
9590 if(lRet
& TVIR_EDITCOMBOBOX
) { // Die Combobox füllen
9591 uMax
= sNotify
.uMaxEntries
;
9594 if(sNotify
.pTextList
) { // Texte über Listenfeld
9595 for(uCnt
= 0; uCnt
< uMax
; uCnt
++) {
9596 pText
= sNotify
.pTextList
[uCnt
];
9600 SendMessage(hWnd
, CB_ADDSTRING
, 1, (LPARAM
)pText
);
9602 if(sNotify
.item
.pszText
&& !_tcscmp(pText
, sNotify
.item
.pszText
)) {
9606 } else { // Text mit
9607 pText
= sNotify
.pTextEntries
;
9612 for(uCnt
= 0; uCnt
< uMax
; uCnt
++) {
9613 for(uLen
= 0; pText
[uLen
]; uLen
++) { // Subtextlänge holen
9614 if(pText
[uLen
] == cChar
)
9618 if(!uLen
&& !pText
[uLen
])
9622 if(uNum
>= sizeof(cText
) / sizeof(TCHAR
)) {
9623 uNum
= sizeof(cText
) / sizeof(TCHAR
) - 1;
9626 memcpy(cText
, pText
, uNum
* sizeof(TCHAR
));
9628 SendMessage(hWnd
, CB_ADDSTRING
, 1, (LPARAM
)cText
);
9630 if(sNotify
.item
.pszText
&& wParam
>= 0x10000 && !_tcscmp(cText
, sNotify
.item
.pszText
)) {
9635 if(!cChar
|| *pText
)
9639 if(lRet
& TVIR_EDITCOMBODEL
) { // Den Puffer löschen
9640 delete((TCHAR
*)sNotify
.pTextEntries
);
9644 if(iSel
>= 0) { // Listeneintrag auswählen
9645 SendMessage(hWnd
, CB_SETCURSEL
, iSel
, 0);
9648 if(sNotify
.uHeight
) { // Höhe der Dropdown-Liste einstellen
9649 SendMessage(hWnd
, CB_SETDROPPEDWIDTH
, sNotify
.uHeight
, 0);
9652 if(lRet
& TVIR_EDITCOMBODOWN
) { // Dropdown-Liste einblenden
9653 SendMessage(hWnd
, CB_SHOWDROPDOWN
, 1, 0);
9656 if(!(lRet
& TVIR_EDITCOMBOLIST
)) { // Textauswahl wiederherstellen
9657 SetWindowText(hWnd
, sNotify
.item
.pszText
);
9658 SendMessage(hWnd
, CB_SETEDITSEL
, 0, pData
->uLastSel
);
9662 if(wParam
< 0x10000) { // Taste an Fenster senden
9663 pData
->cColumnStart
= 1;
9665 sMsg
.lParam
= lParam
;
9666 sMsg
.wParam
= wParam
;
9667 sMsg
.message
= WM_KEYDOWN
;
9669 TranslateMessage(&sMsg
);
9671 if(wParam
& VK_ISACHAR
) {
9672 SendMessage(hWnd
, WM_CHAR
, wParam
& 0xFFFF, lParam
);
9674 pData
->cColumnStart
= 0;
9680 //*****************************************************************************
9682 //* TreeListStartAutoEdit
9684 //*****************************************************************************
9685 // Startet die Autoeditierung für eine Spalte
9686 // pData : Zeiger auf die Fensterdaten
9687 // uColumn : Ist die Nummer der Spalte
9688 // wParam : Ist der W-Parameter des Tastendrucks
9689 // VK_EDITCLK bei einem Clickauf das ausgewählte Feld
9690 // VK_ICONCLK bei einem Clickauf das Iion
9691 // VK_DBLCLK bei einem Doppelclick
9692 // lParam : Ist der L-Parameter des Tastendrucks (bzw. die Koordinaten)
9693 // Ergibt 1 das Editieren gestartet wurde, ansonsten 0
9694 // 0 wenn der Eintrag nicht gewählt wurde
9695 static int TreeListStartAutoEdit(TreeListData
*pData
, unsigned uColumn
, WPARAM wParam
, LPARAM lParam
) {
9718 if(pData
->uEditItem
)
9720 if(pData
->uColumnCount
<= uColumn
)
9722 if(!(pData
->uStyle
& TVS_EDITLABELS
))
9725 uBits
= pData
->aColumn
[uColumn
].bFlags
;
9726 uMode
= pData
->aColumn
[uColumn
].bEdit
;
9731 if(uBits
& TVAE_STATEENABLE
) { // Kann das Editieren gesperrt werden
9733 pExtra
= pData
->pExtraItems
[uColumn
- 1][pData
->uSelectedItem
];
9734 if(pExtra
&& (pExtra
->uState
& TVIS_DISABLEBIT
))
9737 pEntry
= pData
->pTreeItems
[pData
->uSelectedItem
];
9738 if(!pEntry
|| (pEntry
->uState
& TVIS_DISABLEBIT
))
9743 if(wParam
!= VK_RETURN
&& wParam
< 0x10000) { // Zeicheneingabe
9744 if(!TVIS_EDIT(uMode
))
9746 if(uBits
& TVAE_ONLYRETURN
)
9750 pData
->cColumnStart
= 1;
9752 pData
->cColumnStart
= 0;
9755 uMax
= pData
->aColumn
[uColumn
].bCbSize
;
9759 //******************** Weiterschalten mit Return ******************************
9760 if(uMode
>= TVAX_STEP
) {
9761 sItem
.mask
= TVIF_TEXT
| TVIF_SUBITEM
| TVIF_TEXTPTR
| ((uMode
< TVAX_CHECK
) ? 0 : TVIF_STATE
| TVIF_PARAM
);
9762 sItem
.stateMask
= 0xFFFFFFFF;
9763 sItem
.hItem
= (HTREEITEM
)pData
->uSelectedItem
;
9764 sItem
.cChildren
= uColumn
;
9766 if(!TreeListGetItem(pData
, &sItem
))
9769 if((uMode
& 1) && wParam
!= VK_ICONCLK
) { // Ein Edit-Feld öffnen
9774 if(uMode
>= TVAX_CHECK
) { // State-Bits bei Checkboxen setzen
9775 if(uBits
& TVAE_STATEENABLE
)
9776 uFlag
= sItem
.state
& (~TVIS_STATEIMAGEMASK
| TVIS_DISABLEBIT
);
9778 uFlag
= sItem
.state
& (~TVIS_STATEIMAGEMASK
);
9780 if(pData
->uStyleEx
& TVS_EX_BITCHECKBOX
)
9781 sItem
.state
= (sItem
.state
^ 0x1000);
9783 sItem
.state
= (sItem
.state
& 0x1000) ? 0x2000 : 0x1000;
9785 sItem
.state
|= uFlag
;
9787 sItem
.mask
&= ~TVIF_STATE
;
9790 if(uBits
& TVAE_PTRLIST
) { // Zeigerliste char *pTexte[]={"1","2",NULL};
9791 pList
= (LPTSTR
*)pData
->aColumn
[uColumn
].pCbData
;
9794 if(uMode
< TVAX_CHECK
)
9796 sItem
.mask
&= ~TVIF_TEXT
;
9797 pText
= sItem
.pszText
;
9802 for(uPos
= 0;; uPos
++) {
9803 if(uPos
>= uMax
|| !pList
[uPos
]){
9806 if(str_cmp(sItem
.pszText
, pList
[uPos
]))
9809 if(uPos
>= uMax
|| !pList
[uPos
])
9814 pText
= pList
[uPos
];
9816 if(uMode
< TVAX_CHECK
)
9818 sItem
.mask
&= ~TVIF_TEXT
;
9819 pText
= sItem
.pszText
;
9821 } else { // Textliste char *pText="1|2|3";
9822 pText
= (LPTSTR
)pData
->aColumn
[uColumn
].pCbData
;
9823 cChar
= (TCHAR
)pData
->aColumn
[uColumn
].bCbChar
;
9827 if(uMode
< TVAX_CHECK
)
9829 sItem
.mask
&= ~TVIF_TEXT
;
9830 pText
= sItem
.pszText
;
9835 for(uPos
= 0;; uPos
++) {
9837 pText
= (LPTSTR
)pData
->aColumn
[uColumn
].pCbData
;
9842 for(uLen
= 0; pText
[uLen
]; uLen
++) { // Subtextlänge bestimmen
9843 if(pText
[uLen
] == cChar
)
9847 if(sItem
.cchTextMax
== (int)uLen
) // Ist der Subtext der aktulle Text
9848 if(str_ncmp(sItem
.pszText
, pText
, uLen
) == 0) {
9852 pText
= (LPTSTR
)pData
->aColumn
[uColumn
].pCbData
;
9858 if(pText
[0] == cChar
)
9861 pText
= (LPTSTR
)pData
->aColumn
[uColumn
].pCbData
;
9869 if(pText
[0] == cChar
)
9872 pText
= (LPTSTR
)pData
->aColumn
[uColumn
].pCbData
;
9879 for(uLen
= 0; pText
[uLen
] && uLen
< 256; uLen
++) { // Ausgewählten Text kopiren
9880 if(pText
[uLen
] == cChar
)
9882 cBuffer
[uLen
] = pText
[uLen
];
9891 sItem
.mask
&= ~TVIF_TEXTPTR
;
9892 sItem
.stateMask
&= TVIS_STATEIMAGEMASK
;
9893 sItem
.hItem
= (HTREEITEM
)pData
->uSelectedItem
;
9894 sItem
.pszText
= pText
;
9895 sItem
.cchTextMax
= 256;
9896 sItem
.cChildren
= uColumn
;
9897 iIcon
= pData
->aColumn
[uColumn
].iCbIcon
;
9899 if(iIcon
>= 0) { // Auch ein Icon zuweisen
9900 sItem
.mask
|= TVIF_IMAGE
| TVIF_SELECTEDIMAGE
;
9901 sItem
.iImage
= iIcon
+ uPos
;
9902 sItem
.iSelectedImage
= sItem
.iImage
;
9905 iRet
= TreeListSetItem(pData
, &sItem
);
9907 sNotify
.hdr
.code
= (uMode
< TVAX_CHECK
) ? TVN_STEPSTATECHANGED
: TVN_CBSTATECHANGED
;
9908 sNotify
.action
= (UINT
)wParam
;
9909 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_TEXT
| TVIF_SUBITEM
;
9910 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
9911 sNotify
.itemNew
.hItem
= sItem
.hItem
;
9912 sNotify
.itemNew
.state
= sItem
.state
;
9913 sNotify
.itemNew
.lParam
= sItem
.lParam
;
9914 sNotify
.itemNew
.pszText
= sItem
.pszText
;
9915 sNotify
.itemNew
.cchTextMax
= sItem
.cchTextMax
;
9916 sNotify
.itemNew
.cChildren
= uColumn
;
9917 sNotify
.itemOld
.mask
= 0;
9918 sNotify
.ptDrag
.x
= LOWORD(lParam
);
9919 sNotify
.ptDrag
.y
= HIWORD(lParam
);
9922 SendNotify(pData
, &sNotify
.hdr
);
9928 //******************** Edit oder Combobox *************************************
9931 uSub
= (uMode
- 1) << 29;
9934 if(uBits
& TVAE_FULLWIDTH
) {
9935 uSub
|= TVIR_EDITFULL
;
9938 if(wParam
== VK_EDITCLK
) // Cursor auf Klickposition
9939 if(!(pData
->uStyleEx
& TVS_EX_NOCURSORSET
)) {
9940 TreeListGetItemRect(pData
, pData
->uSelectedItem
, TVIR_COLTOSUB(uColumn
) | TVIR_GETCOLUMN
| TVIR_TEXT
, &sRect
);
9941 uSub
|= TVIR_SETAT(LOWORD(lParam
) - sRect
.left
);
9944 hWnd
= TreeListEditLabel(pData
, pData
->uSelectedItem
, uSub
);
9948 if(uMode
!= TVAX_EDIT
) {
9949 iSel
= (uMode
!= TVAX_CBLIST
) ? -1 : 0;
9950 sItem
.mask
= TVIF_TEXT
| TVIF_SUBITEM
| TVIF_TEXTPTR
;
9951 sItem
.hItem
= (HTREEITEM
)pData
->uSelectedItem
;
9952 sItem
.cChildren
= uColumn
;
9954 if(!TreeListGetItem(pData
, &sItem
))
9957 if(uBits
& TVAE_PTRLIST
) { // Zeigerliste char *pTexte[]={"1","2",NULL};
9958 pList
= (LPTSTR
*)pData
->aColumn
[uColumn
].pCbData
;
9960 for(uPos
= 0; uPos
< uMax
; uPos
++) {
9963 if(!str_cmp(sItem
.pszText
, pList
[uPos
]))
9965 SendMessage(hWnd
, CB_ADDSTRING
, 0, (LPARAM
)pList
[uPos
]);
9967 } else { // Textliste char *pText="1|2|3";
9968 pText
= (LPTSTR
)pData
->aColumn
[uColumn
].pCbData
;
9969 cChar
= (TCHAR
)pData
->aColumn
[uColumn
].bCbChar
;
9972 for(uPos
= 0; uPos
< uMax
; uPos
++) {
9973 for(uLen
= 0; pText
[uLen
]; uLen
++) {
9974 if(pText
[uLen
] == cChar
)
9978 if(sItem
.cchTextMax
== (int)uLen
)
9979 if(str_ncmp(sItem
.pszText
, pText
, uLen
) == 0) {
9985 memcpy(cBuffer
, pText
, sizeof(TCHAR
)*uLen
);
9989 memcpy(cBuffer
, pText
, sizeof(TCHAR
) * 255);
9992 SendMessage(hWnd
, CB_ADDSTRING
, 0, (LPARAM
)cBuffer
);
9994 SendMessage(hWnd
, CB_ADDSTRING
, 0, (LPARAM
)pText
);
9998 if(pText
[0] == cChar
)
10006 SendMessage(hWnd
, CB_SETCURSEL
, iSel
, 0);
10010 if((uBits
& TVAE_DROPDOWN
) && (uMode
&~1) == 2) { // Dropdownliste aufklappen
10011 SendMessage(hWnd
, CB_SHOWDROPDOWN
, 1, 0);
10014 // Ersten Buchstaben ans Fenster übergeben
10015 if(TVIS_EDIT(uMode
) && pData
->cColumnStart
&& wParam
!= VK_EDITCLK
) {
10016 SendMessage(hWnd
, WM_CHAR
, wParam
, 0);
10022 //*****************************************************************************
10026 //*****************************************************************************
10027 // Ist die Fensterfunktion für das TreeList Fenster
10028 static LRESULT CALLBACK
TreeListProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
10030 TreeListData
*pData
;
10033 TV_HITTESTINFO sInfo
;
10035 SCROLLINFO sScroll
;
10049 case WM_CREATE
: // Das Fenster erzeugen
10051 pData
= new(TreeListData
, 1);
10055 memset(pData
, 0, sizeof(TreeListData
));
10056 pData
->pToolTipText
= new(TCHAR
, 256);
10057 pData
->uToolTipSize
= 256;
10059 if(!pData
->pToolTipText
) {
10064 pData
->pTreeItems
= new(BaseItem
*, 1);
10065 if(!pData
->pTreeItems
) {
10066 delete(pData
->pToolTipText
);
10071 pData
->pItemPos
= new(unsigned, 1);
10072 if(!pData
->pItemPos
) {
10073 delete(pData
->pToolTipText
);
10074 delete(pData
->pTreeItems
);
10081 pData
->pItemPos
[0] = 0;
10082 pData
->pTreeItems
[0] = NULL
;
10084 SetWindowLongPtr(hWnd
, 0, (LONG_PTR
)pData
);
10085 pData
->iIndent
= DEFAULT_IDENT
;
10086 pData
->iShift
= DEFAULT_SHIFT
;
10087 pData
->uStyle
= GetWindowLong(hWnd
, GWL_STYLE
);
10088 pData
->hSem
= CreateSemaphore(0, 1, 0x70000000, 0);
10089 pData
->hWnd
= hWnd
;
10090 pData
->cIsEnabled
= (char)IsWindowEnabled(hWnd
);
10091 pData
->iAutoAdd
= 1;
10092 pData
->aColumnPos
[0] = 0;
10093 pData
->aColumnPos
[1] = 1;
10095 if(!(pData
->uStyle
& (TVS_HASBUTTONS
| TVS_HASLINES
))) {
10096 pData
->cHasRootRow
= 0;
10098 pData
->cHasRootRow
= (char)((pData
->uStyle
& TVS_LINESATROOT
) ? 1 : 0);
10101 if(!(pData
->uStyle
& TVS_NOTOOLTIPS
)) {
10102 CreateToolTip(pData
);
10106 UpdateHeight(pData
);
10107 UpdateColorsList(pData
);
10108 UpdateScrollY(pData
);
10110 if(pOpenThemeData
) // Soll ein Thema angezeigt werden
10111 pData
->hTheme
= pOpenThemeData(hWnd
, L
"TREEVIEW");
10113 pData
->hTheme
= NULL
;
10115 pData
->cGlyphOk
= (char)((pData
->hTheme
) ? 1 : 0);
10117 if(pData
->uStyle
& TVS_CHECKBOXES
) {
10118 CreateStateImageList(pData
, 0);
10123 case WM_DESTROY
: // Das Fenster zerstören
10125 pData
= GetHandle(hWnd
);
10129 TreeListDeleteItem(pData
, U(TVI_ROOT
), 0);
10130 if(pData
->hStates
== THEMEIMGLIST
)
10131 pData
->hStates
= 0;
10132 if(pData
->hChecks
== THEMEIMGLIST
)
10133 pData
->hChecks
= 0;
10135 DestroyWindow(pData
->hEdit
);
10138 if(pData
->hHeader
){
10139 DestroyWindow(pData
->hHeader
);
10140 pData
->hHeader
= 0;
10142 if(pData
->hToolTip
){
10143 DestroyWindow(pData
->hToolTip
);
10144 pData
->hToolTip
= 0;
10146 if(pData
->hStates
){
10147 ImageList_Destroy(pData
->hStates
);
10148 pData
->hStates
= 0;
10151 if(pData
->uStyleEx
& TVS_EX_SHAREIMAGELISTS
) {
10152 if(pData
->hStates
&& pData
->iStatesMode
) {
10153 ImageList_Destroy(pData
->hStates
);
10154 pData
->hStates
= 0;
10156 if(pData
->hChecks
&& pData
->iChecksMode
) {
10157 ImageList_Destroy(pData
->hChecks
);
10158 pData
->hChecks
= 0;
10160 pData
->hImages
= 0;
10161 pData
->hSubImg
= 0;
10162 pData
->hHeadImg
= 0;
10164 if(pData
->hStates
){
10165 ImageList_Destroy(pData
->hStates
);
10166 pData
->hStates
= 0;
10168 if(pData
->hChecks
){
10169 ImageList_Destroy(pData
->hChecks
);
10170 pData
->hChecks
= 0;
10172 if(pData
->hImages
){
10173 ImageList_Destroy(pData
->hImages
);
10174 pData
->hImages
= 0;
10176 if(pData
->hSubImg
){
10177 ImageList_Destroy(pData
->hSubImg
);
10178 pData
->hSubImg
= 0;
10180 if(pData
->hHeadImg
){
10181 if(pData
->uStyleEx
& TVS_EX_HEADEROWNIMGLIST
)
10182 ImageList_Destroy(pData
->hHeadImg
);
10183 pData
->hHeadImg
= 0;
10187 if(pData
->hThemeBt
){
10188 pCloseThemeData(pData
->hThemeBt
);
10189 pData
->hThemeBt
= 0;
10192 pCloseThemeData(pData
->hTheme
);
10196 for(uVal
= 1; uVal
< pData
->uColumnCount
; uVal
++) {
10197 delete(pData
->pExtraItems
[uVal
- 1]);
10198 pData
->pExtraItems
[uVal
- 1] = 0;
10202 DeleteObject(pData
->hFontB
);
10206 pData
->uColumnCount
= 0;
10212 case WM_NCDESTROY
: // Das Fenster zerstören
10214 pData
= GetHandle(hWnd
);
10218 delete(pData
->pToolTipText
);
10219 delete(pData
->pTreeItems
);
10220 delete(pData
->pItemPos
);
10224 SetWindowLongPtr(hWnd
, 0, 0);
10225 CloseHandle(pData
->hSem
);
10226 memset(pData
, 0, sizeof(TreeListData
));
10233 case WM_SHOWWINDOW
: // Fenster ein/ausblenden
10236 pData
= GetHandle(hWnd
);
10238 sScroll
.cbSize
= sizeof(SCROLLINFO
);
10239 sScroll
.fMask
= SIF_ALL
;
10244 sScroll
.nTrackPos
= 0;
10246 SetScrollInfo(pData
->hWnd
, SB_VERT
, &sScroll
, TRUE
);
10247 SetScrollInfo(pData
->hWnd
, SB_HORZ
, &sScroll
, TRUE
);
10249 pData
->uOldXCount
= 0xFFFF;
10250 pData
->uOldYCount
= 0xFFFF;
10252 UpdateScrollY(pData
);
10253 UpdateScrollX(pData
);
10258 case WM_SIZE
: // Die Fenstergröße wurde verändert
10260 pData
= GetHandle(hWnd
);
10265 uVal
= LOWORD(lParam
);
10266 if(uVal
&& uVal
!= pData
->uSizeX
) {
10267 uOld
= pData
->uSizeX
;
10268 pData
->uSizeX
= uVal
;
10270 if(pData
->uColumnCountVar
) { // Spalten mit variabler Breite nach führen
10275 iDelta
= uVal
- uOld
;
10277 ChangeColSize(pData
, iDelta
);
10279 iNum
= UpdateColumns(pData
);
10280 GetClientRect(hWnd
, &sRect
);
10282 sRect
.left
-= pData
->uScrollX
;
10283 sRect
.top
= pData
->uStartPixel
;
10284 InvalidateRect(hWnd
, &sRect
, FALSE
);
10287 if(uVal
> uOld
) { // Hat sich die Breite vergrößert
10290 GetClientRect(hWnd
, &sRect
);
10291 sRect
.right
= uVal
;
10293 InvalidateRect(hWnd
, &sRect
, FALSE
);
10296 pData
->aColumnXpos
[pData
->uColumnCount
+ 1] = uVal
+ 1;
10298 MoveWindow(pData
->hHeader
, -(int)pData
->uScrollX
, 0, uVal
+ pData
->uScrollX
, pData
->uStartPixel
, uVal
> uOld
);
10299 UpdateScrollX(pData
);
10302 uVal
= HIWORD(lParam
);
10303 if(uVal
&& uVal
!= pData
->uSizeY
) {
10304 if(uVal
> pData
->uSizeY
) { // Hat sich die Höhe vergrößert
10307 GetClientRect(hWnd
, &sRect
);
10309 sRect
.bottom
= uVal
;
10310 sRect
.top
= pData
->uSizeY
;
10311 InvalidateRect(hWnd
, &sRect
, FALSE
);
10316 pData
->uSizeY
= uVal
;
10317 pData
->uSizeYsub
= (uVal
<= pData
->uStartPixel
) ? 0 : uVal
- pData
->uStartPixel
;
10319 if(pData
->uSizeY
> pData
->uStartPixel
) {
10320 pData
->uMaxEnties
= pData
->uSizeY
;
10321 pData
->uMaxEnties
-= pData
->uStartPixel
;
10323 pData
->uMaxEnties
= 0;
10326 pData
->uPageEnties
= pData
->uMaxEnties
;
10327 pData
->uMaxEnties
+= pData
->iRowHeight
- 1;
10328 pData
->uMaxEnties
/= pData
->iRowHeight
;
10329 pData
->uPageEnties
/= pData
->iRowHeight
;
10330 // Wenn Höhe vergrößert dann Scroll-Position prüfen
10331 if(uFlag
&& pData
->uPageEnties
> 2 && pData
->uScrollY
> 0) {
10332 if(pData
->uScrollY
+ pData
->uPageEnties
+ 1 > pData
->uItemPosCount
) {
10333 iPos
= pData
->uItemPosCount
- pData
->uPageEnties
+ 1;
10336 if(U(iPos
) != pData
->uScrollY
) {
10337 pData
->uScrollY
= iPos
;
10342 UpdateScrollY(pData
);
10348 RedrawWindow(pData
->hHeader
, NULL
, NULL
, RDW_INVALIDATE
| RDW_UPDATENOW
| RDW_ERASE
);
10353 case WM_ENABLE
: // Das Fenster feischalten oder sperren
10355 pData
= GetHandle(hWnd
);
10356 if(pData
->cIsEnabled
!= ((U(wParam
)) ? 1 : 0)) {
10357 uVal
= GetWindowLong(hWnd
, GWL_STYLE
);
10358 uVal
&= (0xFFFF0000 & ~WS_DISABLED
);
10359 uVal
|= (0x0000FFFF | WS_DISABLED
) & (pData
->uStyle
^ WS_DISABLED
);
10360 SetWindowLong(hWnd
, GWL_STYLE
, uVal
);
10365 case WM_SETFOCUS
: // Das Fenster bekommt den Focus
10367 pData
= GetHandle(hWnd
);
10368 if(!pData
->cHasFocus
) {
10372 pData
->cHasFocus
= 1;
10374 if(pData
->uSelectedCount
<= 1) {
10375 if(pData
->uSelectedItem
) {
10376 if(pData
->uStyleEx
& TVS_EX_FULLROWMARK
)
10377 UpdateRow(pData
, pData
->uSelectedItem
);
10379 UpdateRect(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
10387 sNotify
.code
= NM_SETFOCUS
;
10388 SendNotify(pData
, &sNotify
);
10393 case WM_KILLFOCUS
: // Das Fenster bekommt den Focus
10395 pData
= GetHandle(hWnd
);
10396 if(pData
->cHasFocus
) {
10400 pData
->cHasFocus
= 0;
10402 if(pData
->uSelectedCount
<= 1) {
10403 if(pData
->uSelectedItem
) {
10404 if(pData
->uStyleEx
& TVS_EX_FULLROWMARK
)
10405 UpdateRow(pData
, pData
->uSelectedItem
);
10407 UpdateRect(pData
, pData
->uSelectedItem
, pData
->uSelectedSub
);
10415 sNotify
.code
= NM_KILLFOCUS
;
10416 SendNotify(pData
, &sNotify
);
10421 case WM_MOUSEMOVE
: // Gab es eine Mausbewegung
10423 pData
= GetHandle(hWnd
);
10427 if(!(pData
->uStyle
& TVS_NOTOOLTIPS
)) {
10428 if(!pData
->cIsEnabled
) { // Ist das Fenster freigegeben
10434 sInfo
.pt
.x
= LOWORD(lParam
);
10435 sInfo
.pt
.y
= HIWORD(lParam
);
10436 TreeListHitTest(pData
, &sInfo
);
10437 UpdateToolTip(pData
, U(sInfo
.hItem
), sInfo
.flags
);
10442 if(pData
->uStyle
& TVS_TRACKSELECT
) {
10443 if(!pData
->cIsEnabled
) { // Ist das Fenster freigegeben
10450 sInfo
.pt
.x
= LOWORD(lParam
);
10451 sInfo
.pt
.y
= HIWORD(lParam
);
10452 TreeListHitTest(pData
, &sInfo
);
10455 if(sInfo
.hItem
&& (sInfo
.flags
& (TVHT_ONSUBITEM
| TVHT_ONSUBLABEL
| TVHT_ONITEM
))) {
10456 TreeListSetTrackItem(pData
, U(sInfo
.hItem
), TVHT_SUBTOCOL(sInfo
.flags
));
10462 if(wParam
& pData
->uDragFlags
) // Drag beginnen
10463 if(U(lParam
) != pData
->uLastMove
) {
10464 NMTREEVIEW sNotify
;
10469 iDiffX
= (short)(lParam
) - (short)(pData
->uLastMove
);
10470 iDiffY
= (short)(lParam
>> 16) - (short)(pData
->uLastMove
>> 16);
10477 if(iDiffX
<= 2 && iDiffY
<= 2) { // Mehr als zwei Pixel-Verschub
10483 if(pData
->uDragItem
> pData
->uTreeItemsMax
) {
10488 pEntry
= pData
->pTreeItems
[pData
->uDragItem
];
10494 sNotify
.hdr
.code
= TVN_BEGINDRAG
;
10495 sNotify
.action
= (pEntry
->uState
& TVIS_EXPANDED
) ? TVE_COLLAPSE
: TVE_EXPAND
;
10496 sNotify
.itemNew
.mask
= TVIF_HANDLE
| TVIF_PARAM
| TVIF_STATE
| TVIF_SUBNUMBER
;
10497 sNotify
.itemNew
.hItem
= (HTREEITEM
)pData
->uDragItem
;
10498 sNotify
.itemNew
.stateMask
= 0xFFFFFFFF;
10499 sNotify
.itemNew
.state
= pEntry
->uState
;
10500 sNotify
.itemNew
.lParam
= pEntry
->lParam
;
10501 sNotify
.itemNew
.cChildren
= pData
->uDragSub
;
10502 sNotify
.itemNew
.pszText
= (LPTSTR
) - 1;
10503 sNotify
.itemNew
.cchTextMax
= -1;
10504 sNotify
.itemOld
.mask
= 0;
10505 sNotify
.ptDrag
.x
= LOWORD(lParam
);
10506 sNotify
.ptDrag
.y
= HIWORD(lParam
);
10507 pData
->uDragFlags
= 0;
10508 pData
->cClickFlag
= 0;
10509 pData
->cClickEdit
= 0;
10513 SendNotify(pData
, &sNotify
.hdr
);
10516 pData
->uLastMove
= U(lParam
);
10520 case WM_LBUTTONUP
: // Linken Mausklick aufheben
10522 pData
= GetHandle(hWnd
);
10523 pData
->uDragFlags
&= ~MK_LBUTTON
;
10525 if(pData
->cClickFlag
|| pData
->cClickEdit
) {
10526 TreeListMouseClick(pData
, uMsg
, wParam
, lParam
);
10527 pData
->cClickFlag
= 0;
10528 pData
->cClickEdit
= 0;
10530 TreeListMouseNotify(pData
, TVN_LBUTTONUP
, wParam
, lParam
);
10535 case WM_RBUTTONUP
: // Linken Mausklick aufheben
10537 pData
= GetHandle(hWnd
);
10538 pData
->uDragFlags
&= ~MK_RBUTTON
;
10540 TreeListMouseNotify(pData
, TVN_RBUTTONUP
, wParam
, lParam
);
10544 case WM_LBUTTONDOWN
: // Mausklick
10546 pData
= GetHandle(hWnd
);
10550 uTime
= GetTickCount();
10552 if(pData
->cButtonFlag
&& pData
->uToolTipItem
) { // Doppelklick simulieren über ToolTip
10553 pData
->cButtonFlag
= 0;
10554 uDelta
= uTime
- pData
->uButtonLast
;
10557 iPos
= abs(LOWORD(lParam
) - LOWORD(pData
->uButtonPos
));
10558 iPos
+= abs(HIWORD(lParam
) - HIWORD(pData
->uButtonPos
));
10561 TreeListMouseClick(pData
, WM_LBUTTONDBLCLK
, wParam
, lParam
);
10567 pData
->cButtonFlag
= 1;
10568 pData
->uButtonLast
= uTime
;
10569 pData
->uButtonPos
= U(lParam
);
10571 TreeListMouseClick(pData
, uMsg
, wParam
, lParam
);
10575 case WM_LBUTTONDBLCLK
:
10576 case WM_RBUTTONDOWN
:
10577 case WM_RBUTTONDBLCLK
:
10579 pData
= GetHandle(hWnd
);
10583 pData
->cButtonFlag
= 0;
10584 TreeListMouseClick(pData
, uMsg
, wParam
, lParam
);
10588 case WM_KEYDOWN
: // Tastendruck
10590 pData
= GetHandle(hWnd
);
10592 TreeListKeyDown(pData
, wParam
, lParam
);
10596 case WM_KEYUP
: // Tastendruck
10598 DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
10601 case WM_CHAR
: // Zeicheneingabe
10603 pData
= GetHandle(hWnd
);
10604 iMax
= lParam
& 0xFFFF;
10606 for(iPos
= 0; iPos
< iMax
; iPos
++) {
10607 TreeListChar(pData
, (UINT
)wParam
, lParam
);
10612 case WM_DRAWITEM
: // Weietleiten von OwnerDraw des Headers
10615 pData
= GetHandle(hWnd
);
10616 return SendMessage(GetParent(hWnd
), uMsg
, GetWindowLong(hWnd
, GWL_ID
), lParam
);
10621 case WM_MOUSEWHEEL
: // Scrollen mit dem Mausrad
10623 if(!(LOWORD(wParam
) & (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
))) {
10624 pData
= GetHandle(hWnd
);
10626 if(pData
->uEditItem
)
10629 iDif
= (short)HIWORD(wParam
) / (WHEEL_DELTA
/ 2);
10631 if(wParam
& MK_CONTROL
) {
10634 if(wParam
& MK_SHIFT
) {
10638 iPos
= pData
->uScrollY
- iDif
;
10639 iMax
= pData
->uItemPosCount
;
10640 iMax
-= pData
->uPageEnties
- 1;
10646 if(iPos
!= (int)pData
->uScrollY
)
10647 if(!(pData
->uStyle
& TVS_NOSCROLL
)) {
10648 pData
->uScrollY
= iPos
;
10649 SetScrollPos(hWnd
, SB_VERT
, iPos
, TRUE
);
10658 case WM_HSCROLL
: // Vertikalles scrollen
10660 pData
= GetHandle(hWnd
);
10661 iPos
= pData
->uScrollX
;
10663 if(pData
->uEditItem
)
10666 switch(LOWORD(wParam
)) {
10674 iPos
+= pData
->uSizeX
;
10677 iPos
-= pData
->uSizeX
;
10679 case SB_THUMBPOSITION
:
10680 iPos
= HIWORD(wParam
);
10682 case SB_THUMBTRACK
:
10683 iPos
= HIWORD(wParam
);
10687 uVal
= pData
->uColumnCount
;
10689 iMax
= pData
->aColumnXpos
[uVal
] - pData
->uSizeX
/ 2;
10691 iMax
= pData
->iMaxSizeX
;
10692 iMax
-= pData
->uSizeX
/ 2;
10698 if(iPos
!= (int)pData
->uScrollX
) {
10699 pData
->uScrollX
= iPos
;
10700 SetScrollPos(hWnd
, SB_HORZ
, iPos
, TRUE
);
10703 if(pData
->hHeader
) {
10704 MoveWindow(pData
->hHeader
, -iPos
, 0, pData
->uSizeX
+ iPos
, pData
->uStartPixel
, TRUE
);
10710 case WM_VSCROLL
: // Vertikalles scrollen
10712 pData
= GetHandle(hWnd
);
10713 iPos
= pData
->uScrollY
;
10715 if(pData
->uEditItem
)
10718 switch(LOWORD(wParam
)) {
10726 iPos
+= (pData
->uPageEnties
> 1) ? pData
->uPageEnties
- 1 : 1;
10729 iPos
-= (pData
->uPageEnties
> 1) ? pData
->uPageEnties
- 1 : 1;
10731 case SB_THUMBPOSITION
:
10732 case SB_THUMBTRACK
:
10733 if(pData
->uItemPosCount
< 0x7F00) {
10734 iPos
= HIWORD(wParam
);
10736 sScroll
.cbSize
= sizeof(SCROLLINFO
);
10737 sScroll
.fMask
= SIF_TRACKPOS
;
10738 GetScrollInfo(hWnd
, SB_VERT
, &sScroll
);
10739 iPos
= sScroll
.nTrackPos
;
10743 iMax
= pData
->uItemPosCount
;
10744 iMax
-= pData
->uPageEnties
- 1;
10750 if(iPos
!= (int)pData
->uScrollY
) {
10751 pData
->uScrollY
= iPos
;
10752 SetScrollPos(hWnd
, SB_VERT
, iPos
, TRUE
);
10758 case WM_SYSCOLORCHANGE
: // Wurden die Systemfarben verändert
10760 pData
= GetHandle(hWnd
);
10764 if(pData
->hTheme
) {
10765 pCloseThemeData(pData
->hTheme
);
10766 pData
->hTheme
= NULL
;
10769 if(pData
->hThemeBt
) {
10770 pCloseThemeData(pData
->hThemeBt
);
10771 pData
->hThemeBt
= NULL
;
10774 if(pOpenThemeData
) {
10775 pData
->hTheme
= pOpenThemeData(hWnd
, L
"TREEVIEW");
10776 pData
->cGlyphOk
= (char)((pData
->hTheme
) ? 1 : 0);
10779 if(pData
->iStatesMode
)
10780 CreateStateImageList(pData
, 0);
10781 if(pData
->iChecksMode
)
10782 CreateStateImageList(pData
, 1);
10785 SendMessage(pData
->hHeader
, WM_SYSCOLORCHANGE
, 0, 0);
10786 UpdateColorsList(pData
);
10791 case WM_GETFONT
: //tell what font we are using
10794 pData
= GetHandle(hWnd
);
10797 hFont
= pData
->hFontN
;
10799 return (LRESULT
)hFont
;
10802 case WM_SETFONT
: // Einen neuen Font zuweisen
10804 pData
= GetHandle(hWnd
);
10808 if(CreateFontset(pData
, (HFONT
)wParam
)){
10809 if(UpdateFont(pData
))
10817 case WM_STYLECHANGED
: // Hat sich der Fenstersytle geändert
10819 if(wParam
== GWL_STYLE
) {
10820 pData
= GetHandle(hWnd
);
10821 lParam
= ((STYLESTRUCT
*)lParam
)->styleNew
;
10824 uChange
= U(lParam
) ^ pData
->uStyle
;
10825 pData
->uStyle
= U(lParam
);
10827 if(uChange
& (TVS_CHECKBOXES
| TVS_NONEVENHEIGHT
)) {
10828 if(lParam
& TVS_CHECKBOXES
) {
10829 if(pData
->hStates
== NULL
) {
10830 CreateStateImageList(pData
, 0);
10833 if(pData
->iStatesMode
&& pData
->hStates
) {
10834 if(pData
->hStates
!= THEMEIMGLIST
) {
10835 ImageList_Destroy(pData
->hStates
);
10838 pData
->hStates
= NULL
;
10839 pData
->iStatesMode
= 0;
10843 UpdateHeight(pData
);
10844 UpdateScrollY(pData
);
10847 if(uChange
& (TVS_HASBUTTONS
| TVS_HASLINES
| TVS_LINESATROOT
| TVS_RTLREADING
| TVS_CHECKBOXES
| TVS_TRACKSELECT
)) {
10848 if(!(pData
->uStyle
& (TVS_HASBUTTONS
| TVS_HASLINES
))) {
10849 pData
->cHasRootRow
= 0;
10851 pData
->cHasRootRow
= (char)((pData
->uStyle
& TVS_LINESATROOT
) ? 1 : 0);
10857 if(uChange
& TVS_NOSCROLL
) {
10858 pData
->uOldYCount
= 0xFFFF;
10859 pData
->uOldXCount
= 0xFFFF;
10861 UpdateScrollX(pData
);
10862 UpdateScrollY(pData
);
10865 if(uChange
& TVS_NOTOOLTIPS
) {
10866 if(pData
->uStyle
& TVS_NOTOOLTIPS
) {
10867 UpdateToolTip(pData
, 0, 0);
10869 CreateToolTip(pData
);
10873 if(uChange
& WS_DISABLED
) {
10874 pData
->cIsEnabled
= (char)((pData
->uStyle
& WS_DISABLED
) ? 0 : 1);
10876 if(!pData
->cIsEnabled
)
10877 UpdateToolTip(pData
, 0, 0);
10885 case WM_PAINT
: // Das Fenster zeichnen
10888 TreeListDraw(hWnd
, (HDC
)wParam
, NULL
);
10890 PAINTSTRUCT sPaint
;
10892 hDc
= BeginPaint(hWnd
, &sPaint
);
10894 if(pBeginBufferedPt
&& pEndBufferedPt
) {
10897 HANDLE hBufferedPaint
;
10899 GetClientRect(hWnd
, &sRect
);
10900 hBufferedPaint
= pBeginBufferedPt(hDc
, &sRect
, BPBF_COMPATIBLEBITMAP
, NULL
, &hDcBuffer
);
10902 if(hBufferedPaint
) {
10903 TreeListDraw(hWnd
, hDcBuffer
, &sRect
);
10904 pEndBufferedPt(hBufferedPaint
, TRUE
);
10906 TreeListDraw(hWnd
, hDc
, &sRect
);
10909 TreeListDraw(hWnd
, hDc
, &sPaint
.rcPaint
);
10912 EndPaint(hWnd
, &sPaint
);
10917 case WM_TIMER
: // Timer Funktion
10919 if(wParam
== ID_TOOLTIPCHECK
) {
10920 pData
= GetHandle(hWnd
);
10921 if(pData
->uToolTipItem
) {
10922 if(pData
->uToolTipShow
) { // Verzögertes einblenden
10923 pData
->uToolTipShow
--;
10924 if(pData
->uToolTipShow
)
10929 GetCursorPos(&sPoint
);
10931 sInfo
.pt
.x
= sPoint
.x
;
10932 sInfo
.pt
.y
= sPoint
.y
;
10934 ScreenToClient(hWnd
, &sInfo
.pt
);
10936 if(WindowFromPoint(sPoint
) == hWnd
) {
10937 TreeListHitTest(pData
, &sInfo
);
10943 if(sInfo
.flags
& TVHT_ONITEM
)
10944 if(pData
->uToolTipItem
== U(sInfo
.hItem
) && pData
->uToolTipSub
== 0) {
10949 sInfo
.cbSize
= sizeof(sInfo
);
10950 sInfo
.hwnd
= pData
->hWnd
;
10951 sInfo
.uId
= (UINT_PTR
)pData
->hWnd
;
10953 if(pData
->uToolTipItem
) {
10954 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 0, (LPARAM
)&sInfo
);
10957 SendMessage(pData
->hToolTip
, TTM_TRACKPOSITION
, 0, MAKELONG(pData
->sToolTipPos
.x
, pData
->sToolTipPos
.y
));
10958 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 1, (LPARAM
)&sInfo
);
10963 if(sInfo
.flags
& TVHT_ONSUBITEM
)
10964 if(pData
->uToolTipItem
== U(sInfo
.hItem
) && TVHT_SUBTOCOL(sInfo
.flags
) == pData
->uToolTipSub
) {
10969 sInfo
.cbSize
= sizeof(sInfo
);
10970 sInfo
.hwnd
= pData
->hWnd
;
10971 sInfo
.uId
= (UINT_PTR
)pData
->hWnd
;
10973 if(pData
->uToolTipItem
) {
10974 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 0, (LPARAM
)&sInfo
);
10977 SendMessage(pData
->hToolTip
, TTM_TRACKPOSITION
, 0, MAKELONG(pData
->sToolTipPos
.x
, pData
->sToolTipPos
.y
));
10978 SendMessage(pData
->hToolTip
, TTM_TRACKACTIVATE
, 1, (LPARAM
)&sInfo
);
10983 // ToolTip wieder entferenen
10984 UpdateToolTip(pData
, U(sInfo
.hItem
), sInfo
.flags
);
10990 GetCursorPos(&sInfo
.pt
);
10991 ScreenToClient(hWnd
, &sInfo
.pt
);
10992 TreeListHitTest(pData
, &sInfo
);
10993 UpdateToolTip(pData
, U(sInfo
.hItem
), sInfo
.flags
);
11001 case WM_COMMAND
: // Kommando Nachrichnten
11003 if(wParam
== MAKELONG(3, EN_KILLFOCUS
) || wParam
== MAKELONG(3, EN_RETURN
) || wParam
== MAKELONG(3, CBN_KILLFOCUS
)) {
11004 pData
= GetHandle(hWnd
);
11005 if(pData
->uEditItem
) {
11007 TreeListEndLabelEdit(pData
, (wParam
== MAKELONG(3, EN_RETURN
)) ? 2 : 1);
11009 if(pData
->uEditMode
)
11010 if(wParam
!= MAKELONG(3, EN_KILLFOCUS
)) {
11011 SetFocus(pData
->hWnd
);
11015 if(wParam
== MAKELONG(3, EN_ESCAPE
)) { // ESC-Taste in Edit-Fenster
11016 pData
= GetHandle(hWnd
);
11017 if(pData
->uEditItem
) {
11019 TreeListEndLabelEdit(pData
, 0);
11021 if(pData
->uEditMode
)
11022 SetFocus(pData
->hWnd
);
11024 } // Änderung in Edit-Fenster
11026 if(wParam
== MAKELONG(3, EN_CHANGE
) || wParam
== MAKELONG(3, CBN_EDITCHANGE
) || wParam
== MAKELONG(3, CBN_SELCHANGE
) || wParam
== MAKELONG(3, EN_SETTEXT
)) {
11027 pData
= GetHandle(hWnd
);
11028 pData
->cColumnStart
= 1;
11033 case WM_NOTIFY
: // Notify Nachrichnten
11035 if(wParam
== 1) { // Nachricht vom Header
11036 NMHEADER
*pHdr
= (NMHEADER
*)lParam
;
11047 iCode
= pHdr
->hdr
.code
;
11048 // Hat sich die Spaltenbreite verändert
11049 if(iCode
== HDN_ITEMCHANGED
&& (pHdr
->pitem
->mask
& HDI_WIDTH
)) {
11050 pData
= GetHandle(hWnd
);
11051 iCol
= pHdr
->iItem
;
11053 if(pData
->aColumn
[iCol
].sReal
!= pHdr
->pitem
->cxy
) {
11058 if(iCode
== HDN_BEGINDRAG
) { // Drag&Drop im Header
11059 pData
= GetHandle(hWnd
);
11061 if(!(pData
->uStyleEx
& TVS_EX_HEADERDRAGDROP
) || pHdr
->iItem
== 0) {
11068 if(iCode
== HDN_ENDDRAG
) { // Drag&Drop im Header fertig
11069 if(pHdr
->pitem
->iOrder
== 0 || pHdr
->iItem
== 0) {
11073 pData
= GetHandle(hWnd
);
11075 if(!(pData
->uStyleEx
& TVS_EX_HEADERDRAGDROP
)) {
11079 PostMessage(hWnd
, TVM_SETCOLUMNORDERARRAY
, FROM_HEADER
, 0);
11084 if(iCode
== HDN_BEGINTRACK
) { // User will die Spaltenbreite ändern
11085 pData
= GetHandle(hWnd
);
11087 if(!pData
->cHasFocus
) {
11088 SetFocus(pData
->hWnd
);
11091 if(pData
->uStyleEx
& TVS_EX_NOCOLUMNRESIZE
) { // Darf der User die Spaltenbreite ändern
11095 if(pData
->uStyleEx
& TVS_EX_FIXEDCOLSIZE
) { // Fixe gesammte Spaltenbreite
11096 iNext
= pData
->aColumn
[pHdr
->iItem
].bIndex
;
11098 for(iNext
++;; iNext
++) { // Suche nächste veränerbare Spalte
11099 if(U(iNext
) >= pData
->uColumnCount
) {
11103 iSub
= pData
->aColumnPos
[iNext
];
11105 if(pData
->aColumn
[iSub
].sFixed
== 0) {
11111 if(U(pHdr
->iItem
) < pData
->uColumnCount
) // Darf die Spalte verändert werden
11112 if(pData
->aColumn
[pHdr
->iItem
].sFixed
) {
11117 if(pData
->aColumn
[pHdr
->iItem
].sReal
|| pHdr
->iItem
< 0) {
11121 GetCursorPos(&sPoint
); // Die nächste veränderbare Spalte greifen
11122 ScreenToClient(pData
->hHeader
, &sPoint
);
11124 PostMessage(pData
->hHeader
, WM_LBUTTONUP
, 0, MAKELONG(sPoint
.x
, sPoint
.y
));
11126 iCol
= pData
->aColumn
[pHdr
->iItem
].bIndex
;
11127 iSub
= pData
->aColumnPos
[iCol
- 1];
11129 PostMessage(pData
->hHeader
, WM_LBUTTONDOWN
, 0, MAKELONG(pData
->aColumnXpos
[iSub
+ 1] - 2, sPoint
.y
));
11135 if(iCode
== HDN_DIVIDERDBLCLICK
) { // Doppelcklick auf Spaltentrenner
11136 pData
= GetHandle(hWnd
);
11138 if(!pData
->cHasFocus
) {
11139 SetFocus(pData
->hWnd
);
11142 if(pData
->uStyleEx
& TVS_EX_NOCOLUMNRESIZE
) { // Darf der User die Spaltenbreite ändern
11146 if(U(pHdr
->iItem
) < pData
->uColumnCount
) // Darf die Spalte verändert werden
11147 if(pData
->aColumn
[pHdr
->iItem
].sFixed
) {
11153 iSize
= TreeListScanColumn(pData
, pHdr
->iItem
);
11154 if(iSize
) { // Spalte auf maximale Textbreite
11156 pHdr
->pitem
= &sItem
;
11157 iCode
= HDN_ENDTRACK
;
11159 if(pData
->aColumn
[pHdr
->iItem
].bMinEx
) // Minimale Breite prüfen
11160 if(pData
->aColumn
[pHdr
->iItem
].sMin
> sItem
.cxy
) {
11161 sItem
.cxy
= pData
->aColumn
[pHdr
->iItem
].sMin
;
11168 if(iCode
== HDN_TRACK
|| iCode
== HDN_ENDTRACK
) { // Wurde die Spaltenbreite verändert
11169 pData
= GetHandle(hWnd
);
11171 if(!pData
->cHasFocus
&& iCode
== HDN_ENDTRACK
) {
11172 SetFocus(pData
->hWnd
);
11177 iCol
= pHdr
->iItem
;
11178 sItem
.mask
= HDI_WIDTH
;
11179 sItem
.cxy
= pHdr
->pitem
->cxy
;
11181 if(pData
->aColumn
[iCol
].bMinEx
) // Minimale Breite prüfen
11182 if(pData
->aColumn
[iCol
].sMin
> sItem
.cxy
) {
11183 sItem
.cxy
= pData
->aColumn
[iCol
].sMin
;
11184 pHdr
->pitem
->cxy
= sItem
.cxy
;
11186 if(sItem
.cxy
== pData
->aColumn
[iCol
].sSize
) {
11192 if(pData
->uStyleEx
& TVS_EX_FIXEDCOLSIZE
) { // Fixe gesammte Spaltenbreite
11193 if(iCol
== 0 && sItem
.cxy
<= 0) {
11195 pHdr
->pitem
->cxy
= 1;
11197 if(sItem
.cxy
== pData
->aColumn
[iCol
].sSize
) {
11203 iNext
= pData
->aColumn
[iCol
].bIndex
;
11205 for(iNext
++;; iNext
++) { // Überspringe fixierte Spalten
11206 if(U(iNext
) >= pData
->uColumnCount
) {
11211 iSub
= pData
->aColumnPos
[iNext
];
11213 if(pData
->aColumn
[iSub
].sFixed
== 0) {
11218 iDelta
= pData
->aColumn
[iCol
].sReal
- sItem
.cxy
;
11219 sTemp
.cxy
= pData
->aColumn
[iSub
].sReal
+ iDelta
;
11221 if(iDelta
< 0) { // Nächste Spalte wird zu klein
11222 if(sTemp
.cxy
< 0) {
11224 iDelta
= -pData
->aColumn
[iSub
].sReal
;
11225 sItem
.cxy
= pData
->aColumn
[iCol
].sReal
- iDelta
;
11228 if(pData
->aColumn
[iSub
].bMinEx
) // Minimale Breite prüfen
11229 if(pData
->aColumn
[iSub
].sMin
> sTemp
.cxy
) {
11230 iDelta
+= pData
->aColumn
[iSub
].sMin
- sTemp
.cxy
;
11231 sTemp
.cxy
= pData
->aColumn
[iSub
].sMin
;
11232 sItem
.cxy
= pData
->aColumn
[iCol
].sReal
- iDelta
;
11235 pHdr
->pitem
->cxy
= sItem
.cxy
;
11237 if(iDelta
>= 0) { // Keine Änderung
11243 if(pData
->aColumn
[iSub
].bWeight
) { // Variable Spalte
11244 pData
->iVarSize
-= pData
->aColumn
[iSub
].sSize
;
11245 pData
->iVarSize
+= sTemp
.cxy
;
11246 } else { // Fixe Spalte
11247 pData
->iFixSize
-= pData
->aColumn
[iSub
].sSize
;
11248 pData
->iFixSize
+= sTemp
.cxy
;
11251 sTemp
.mask
= HDI_WIDTH
;
11253 iDif
= pData
->aColumn
[iSub
].sReal
;
11254 pData
->aColumn
[iSub
].sSize
= (short)sTemp
.cxy
;
11255 pData
->aColumn
[iSub
].sReal
= (short)sTemp
.cxy
;
11256 Header_SetItem(pData
->hHeader
, iSub
, &sTemp
);
11258 // Breite verändert
11259 if(iDif
!= sTemp
.cxy
&& (pData
->uStyleEx
& TVS_EX_HEADERCHGNOTIFY
)) {
11260 TV_COLSIZE sNotify
;
11262 sNotify
.hdr
.code
= TVN_COLUMNCHANGED
;
11263 sNotify
.uColumn
= iSub
;
11264 sNotify
.uIndex
= pData
->aColumn
[iSub
].bIndex
;
11265 sNotify
.uPosX
= pData
->aColumnXpos
[iSub
];
11266 sNotify
.iSize
= sTemp
.cxy
;
11269 SendNotify(pData
, &sNotify
.hdr
);
11274 if(pData
->aColumn
[iCol
].bWeight
) { // Ist es eine variable Spalte
11275 pData
->iVarSize
-= pData
->aColumn
[iCol
].sSize
;
11276 pData
->iVarSize
+= sItem
.cxy
;
11277 } else { // Fixe Spalte
11278 pData
->iFixSize
-= pData
->aColumn
[iCol
].sSize
;
11279 pData
->iFixSize
+= sItem
.cxy
;
11282 iDif
= pData
->aColumn
[iCol
].sReal
;
11283 pData
->aColumn
[iCol
].sSize
= (short)sItem
.cxy
;
11284 pData
->aColumn
[iCol
].sReal
= (short)sItem
.cxy
;
11285 Header_SetItem(pData
->hHeader
, iCol
, &sItem
);
11287 iSize
= UpdateColumns(pData
);
11288 if(iSize
< 0x10000) { // Spalten neu zeichnen
11289 GetClientRect(hWnd
, &sRect
);
11290 sRect
.left
= iSize
;
11291 sRect
.left
-= pData
->uScrollX
;
11292 InvalidateRect(hWnd
, &sRect
, FALSE
);
11295 UpdateScrollX(pData
);
11298 // Breite verändert
11299 if(iDif
!= sItem
.cxy
&& (pData
->uStyleEx
& TVS_EX_HEADERCHGNOTIFY
)) {
11300 TV_COLSIZE sNotify
;
11302 sNotify
.hdr
.code
= TVN_COLUMNCHANGED
;
11303 sNotify
.uColumn
= iCol
;
11304 sNotify
.uIndex
= pData
->aColumn
[iCol
].bIndex
;
11305 sNotify
.uPosX
= pData
->aColumnXpos
[iCol
];
11306 sNotify
.iSize
= sItem
.cxy
;
11309 SendNotify(pData
, &sNotify
.hdr
);
11313 // Weiterleiten an Elternfenster
11314 if(iCode
== HDN_ITEMCLICK
|| iCode
== HDN_ITEMDBLCLICK
) {
11315 pData
= GetHandle(hWnd
);
11317 if(!pData
->cHasFocus
) {
11318 SetFocus(pData
->hWnd
);
11321 SendNotify(pData
, &pHdr
->hdr
);
11324 NMHDR
*pHdr
= (NMHDR
*)lParam
;
11325 NMTTDISPINFO
*pInfo
;
11327 switch(pHdr
->code
) {
11328 case TTN_GETDISPINFO
:
11330 pData
= GetHandle(hWnd
);
11331 pInfo
= (NMTTDISPINFO
*)pHdr
;
11332 pInfo
->lpszText
= pData
->pToolTipText
;
11333 SendMessage(pData
->hToolTip
, WM_SETFONT
, (WPARAM
)pData
->hFontT
, 0);
11340 case WM_GETDLGCODE
: // Welche Tasten werden im Dialog benutzt
11342 pMsg
= (MSG
*)lParam
;
11343 if(pMsg
&& pMsg
->message
== WM_KEYDOWN
&& pMsg
->wParam
== VK_RETURN
) {
11344 return DLGC_WANTALLKEYS
;
11347 return DLGC_WANTCHARS
| DLGC_WANTARROWS
;
11349 case WM_PASTE
: // Weiterleiten an Edit-Control
11354 pData
= GetHandle(hWnd
);
11357 PostMessage(pData
->hEdit
, uMsg
, 0, 0);
11363 case TVM_SETIMAGELIST
: // Die Image-Liste einstellen
11365 pData
= GetHandle(hWnd
);
11370 sprintf(dbg
, "TVM_SETIMAGELIST %d", (int)wParam
);
11371 OutputDebugStringA(dbg
);
11373 switch((int)wParam
) {
11375 lRet
= (LPARAM
)pData
->hImages
;
11379 pData
->hImages
= (HIMAGELIST
)lParam
;
11380 if(!pData
->hImages
) {
11381 pData
->iImagesXsize
= 0;
11382 pData
->iImagesYsize
= 0;
11385 ImageList_GetImageInfo(pData
->hImages
, 0, &sInfo
);
11386 pData
->iImagesXsize
= sInfo
.rcImage
.right
- sInfo
.rcImage
.left
;
11387 pData
->iImagesYsize
= sInfo
.rcImage
.bottom
- sInfo
.rcImage
.top
;
11388 if(pData
->hHeader
&& ((pData
->uStyleEx
& TVS_EX_HEADEROWNIMGLIST
) == 0))
11389 SendMessage(pData
->hHeader
, HDM_SETIMAGELIST
, 0, (LPARAM
)pData
->hImages
);
11392 if(!pData
->iSubImgMode
|| pData
->hSubImg
== pData
->hImages
) {
11393 pData
->iSubImgMode
= 0;
11394 pData
->hSubImg
= pData
->hImages
;
11395 pData
->iSubImgXsize
= pData
->iImagesXsize
;
11396 pData
->iSubImgYsize
= pData
->iImagesXsize
;
11399 if(!pData
->cFixedHeight
) {
11400 pData
->iRowHeight
= 1;
11401 UpdateHeight(pData
);
11402 UpdateScrollY(pData
);
11410 lRet
= pData
->uStyleEx
& TVS_EX_HEADEROWNIMGLIST
;
11414 lRet
= (LPARAM
)pData
->hHeadImg
;
11418 pData
->hHeadImg
= (HIMAGELIST
)lParam
;
11421 SendMessage(pData
->hHeader
, HDM_SETIMAGELIST
, 0, (LPARAM
)pData
->hHeadImg
);
11423 if(!pData
->cFixedHeight
) {
11424 pData
->iRowHeight
= 1;
11425 UpdateHeight(pData
);
11426 UpdateScrollY(pData
);
11433 lRet
= (LPARAM
)pData
->hStates
;
11437 if(pData
->iStatesMode
) {
11438 if(pData
->hStates
!= THEMEIMGLIST
) {
11439 ImageList_Destroy(pData
->hStates
);
11442 pData
->iStatesMode
= 0;
11445 pData
->hStates
= (HIMAGELIST
)lParam
;
11446 if(!pData
->hStates
) {
11447 pData
->iStatesXsize
= 0;
11448 pData
->iStatesYsize
= 0;
11450 if(pData
->uStyle
& TVS_CHECKBOXES
) {
11451 CreateStateImageList(pData
, 0);
11454 if(pData
->hStates
== THEMEIMGLIST
) {
11455 pData
->iStatesXsize
= 16;
11456 pData
->iStatesYsize
= 16;
11457 pData
->iStatesMode
= 1;
11458 if(!pData
->hThemeBt
)
11459 CreateStateImageList(pData
, 0);
11462 ImageList_GetImageInfo(pData
->hStates
, 0, &sInfo
);
11463 pData
->iStatesXsize
= sInfo
.rcImage
.right
- sInfo
.rcImage
.left
;
11464 pData
->iStatesYsize
= sInfo
.rcImage
.bottom
- sInfo
.rcImage
.top
;
11465 pData
->iStatesMode
= 0;
11468 if(!pData
->cFixedHeight
) {
11469 pData
->iRowHeight
= 1;
11470 UpdateHeight(pData
);
11471 UpdateScrollY(pData
);
11479 lRet
= (LPARAM
)pData
->hChecks
;
11483 if(pData
->iChecksMode
) {
11484 if(pData
->hChecks
!= THEMEIMGLIST
) {
11485 ImageList_Destroy(pData
->hChecks
);
11488 pData
->iChecksMode
= 0;
11491 pData
->hChecks
= (HIMAGELIST
)lParam
;
11492 if(!pData
->hChecks
) {
11493 pData
->iChecksXsize
= 0;
11494 pData
->iChecksYsize
= 0;
11496 for(uVal
= 0; uVal
< pData
->uColumnCount
; uVal
++) {
11497 if(pData
->aColumn
[uVal
].bEdit
< TVSIL_CHECK
)
11499 CreateStateImageList(pData
, 1);
11503 if(pData
->hChecks
== THEMEIMGLIST
) {
11504 pData
->iChecksXsize
= 16;
11505 pData
->iChecksYsize
= 16;
11506 pData
->iChecksMode
= 1;
11507 if(!pData
->hThemeBt
)
11508 CreateStateImageList(pData
, 1);
11511 ImageList_GetImageInfo(pData
->hChecks
, 0, &sInfo
);
11512 pData
->iChecksXsize
= sInfo
.rcImage
.right
- sInfo
.rcImage
.left
;
11513 pData
->iChecksYsize
= sInfo
.rcImage
.bottom
- sInfo
.rcImage
.top
;
11514 pData
->iChecksMode
= 0;
11517 if(!pData
->cFixedHeight
) {
11518 pData
->iRowHeight
= 1;
11519 UpdateHeight(pData
);
11520 UpdateScrollY(pData
);
11527 case TVSIL_SUBIMAGES
:
11528 lRet
= (LPARAM
)pData
->hSubImg
;
11532 if(pData
->iSubImgMode
) {
11533 ImageList_Destroy(pData
->hSubImg
);
11534 pData
->iSubImgMode
= 0;
11537 pData
->hSubImg
= (HIMAGELIST
)lParam
;
11538 if(!pData
->hSubImg
|| pData
->hSubImg
== pData
->hImages
) {
11539 pData
->iSubImgMode
= 0;
11540 pData
->hSubImg
= pData
->hImages
;
11541 pData
->iSubImgXsize
= pData
->iImagesXsize
;
11542 pData
->iSubImgYsize
= pData
->iImagesXsize
;
11545 ImageList_GetImageInfo(pData
->hSubImg
, 0, &sInfo
);
11546 pData
->iSubImgXsize
= sInfo
.rcImage
.right
- sInfo
.rcImage
.left
;
11547 pData
->iSubImgYsize
= sInfo
.rcImage
.bottom
- sInfo
.rcImage
.top
;
11548 pData
->iSubImgMode
= 1;
11551 if(!pData
->cFixedHeight
) {
11552 pData
->iRowHeight
= 1;
11553 UpdateHeight(pData
);
11554 UpdateScrollY(pData
);
11569 case TVM_GETIMAGELIST
: // Die Image-Liste abfragen
11571 pData
= GetHandle(hWnd
);
11575 switch((int)wParam
) {
11577 lRet
= (LPARAM
)pData
->hImages
;
11580 lRet
= (LPARAM
)pData
->hImages
;
11583 lRet
= (LPARAM
)pData
->hChecks
;
11586 lRet
= (LPARAM
)pData
->hHeadImg
;
11595 case TVM_GETSETOPTION
: // Diverse Optionen einstellen
11597 pData
= GetHandle(hWnd
);
11600 switch(U(wParam
) & ~TVOP_WRITEOPTION
) {
11601 case TVOP_AUTOEXPANDOFF
: // Icon Offset für TVS_EX_AUTOEXPANDICON
11603 lRet
= pData
->iAutoAdd
;
11605 if((wParam
& TVOP_WRITEOPTION
) && lParam
!= lRet
) {
11608 pData
->iAutoAdd
= (int)lParam
;
11609 if(pData
->uItemPosCount
> 0) {
11621 case TVM_GETITEMSTATE
: // Die Statusbits eines Eintrags abfragen
11623 pData
= GetHandle(hWnd
);
11626 if(U(wParam
) <= pData
->uTreeItemsMax
) {
11629 pEntry
= pData
->pTreeItems
[U(wParam
)];
11633 lRet
= pEntry
->uState
;
11643 case TVM_GETITEM
: // Einträge abfragen
11645 pData
= GetHandle(hWnd
);
11647 lRet
= TreeListGetItem(pData
, (TV_ITEM
*)lParam
);
11652 case TVM_SETITEM
: // Einträge einfügen
11654 pData
= GetHandle(hWnd
);
11656 lRet
= TreeListSetItem(pData
, (TV_ITEM
*)lParam
);
11661 case TVM_INSERTITEM
: // Einträge einfügen
11663 pData
= GetHandle(hWnd
);
11665 lRet
= TreeListInsertItem(pData
, (TV_INSERTSTRUCT
*)lParam
);
11670 case TVM_DELETEITEM
: // Einträge löschen
11672 pData
= GetHandle(hWnd
);
11674 lRet
= TreeListDeleteItem(pData
, U(lParam
), (U(wParam
) == 0x88) ? 2 : 1);
11679 case TVM_FINDITEM
: // Einträge suchen
11681 pData
= GetHandle(hWnd
);
11683 lRet
= TreeListFindItem(pData
, U(wParam
), (TV_FIND
*)lParam
);
11688 case TVM_DELETECOLUMN
: // Löschen einer Salte im Header
11690 pData
= GetHandle(hWnd
);
11692 lRet
= TreeListDeleteColumn(pData
, U(wParam
));
11697 case TVM_INSERTCOLUMN
: // Einfügen einer Salte im Header
11699 pData
= GetHandle(hWnd
);
11701 lRet
= TreeListInsertColumn(pData
, (int)wParam
, (TV_COLUMN
*)lParam
);
11706 case TVM_GETCOLUMNCOUNT
: // Abfragen der Spaltenanzahl
11708 pData
= GetHandle(hWnd
);
11709 return (LRESULT
)pData
->uColumnCount
;
11711 case TVM_GETHEADER
: // Abfragen des Header-Fensters
11713 pData
= GetHandle(hWnd
);
11714 return (LRESULT
)pData
->hHeader
;
11716 case TVM_GETEXTENDEDSTYLE
: // Abfragen der erweiterten Style-Bits
11718 pData
= GetHandle(hWnd
);
11719 return pData
->uStyleEx
;
11721 case TVM_SETEXTENDEDSTYLE
: // Einstellen der erweiterten Style-Bits
11723 pData
= GetHandle(hWnd
);
11725 wParam
= 0xFFFFFFFF;
11727 uVal
= pData
->uStyleEx
& ~U(wParam
);
11728 uVal
|= U(lParam
) & U(wParam
);
11730 if(pData
->uStyleEx
!= uVal
) { // Has it changed?
11732 uChange
= pData
->uStyleEx
^ uVal
;
11733 pData
->uStyleEx
= uVal
;
11735 if(uChange
& TVS_EX_AUTOHSCROLL
) {
11736 UpdateScrollX(pData
);
11739 if((uChange
& TVS_EX_GRAYEDDISABLE
) && !pData
->cIsEnabled
) {
11743 if(uChange
& TVS_EX_ITEMLINES
) {
11744 UpdateHeight(pData
);
11745 UpdateScrollY(pData
);
11748 if(uChange
& (TVS_EX_ALTERNATECOLOR
| TVS_EX_SUBSELECT
| TVS_EX_MULTISELECT
| TVS_EX_FULLROWMARK
| TVS_EX_FULLROWITEMS
)) {
11752 if((uChange
&~U(lParam
)) & TVS_EX_SUBSELECT
) {
11753 TreeListSelectItem(pData
, pData
->uSelectedItem
, 0, TVC_UNKNOWN
);
11756 if(pData
->hHeader
){
11757 if((uChange
& TVS_EX_HIDEHEADERS
) || (uChange
& TVS_EX_HEADEROWNIMGLIST
)) {
11758 pData
->uStartPixel
= (pData
->uStyleEx
& TVS_EX_HIDEHEADERS
) ? 0 : bDrawWithTheme
? GetSystemMetrics(SM_CYHSCROLL
) : 17;
11759 MoveWindow(pData
->hHeader
, -(int)pData
->uScrollX
, 0, pData
->uSizeX
+ pData
->uScrollX
, pData
->uStartPixel
, TRUE
);
11761 if(pData
->uStyleEx
& TVS_EX_HEADEROWNIMGLIST
){
11762 SendMessage(pData
->hHeader
, HDM_SETIMAGELIST
, 0, (LPARAM
)pData
->hHeadImg
);
11764 SendMessage(pData
->hHeader
, HDM_SETIMAGELIST
, 0, (LPARAM
)pData
->hImages
);
11776 case TVM_GETINSERTMARKCOLOR
: // Farben abfragen
11777 wParam
= TVC_INSERT
;
11779 case TVM_GETLINECOLOR
:
11782 case TVM_GETTEXTCOLOR
:
11784 case TVM_GETBKCOLOR
:
11787 if(wParam
< 0 || wParam
>= MAX_COLORS
)
11789 pData
= GetHandle(hWnd
);
11790 return pData
->uColors
[U(wParam
)];
11792 case TVM_SETINSERTMARKCOLOR
: // Farben einstellen
11793 wParam
= TVC_INSERT
;
11795 case TVM_SETLINECOLOR
:
11798 case TVM_SETTEXTCOLOR
:
11800 case TVM_SETBKCOLOR
:
11803 if(wParam
< 0 || wParam
>= MAX_COLORS
)
11806 pData
= GetHandle(hWnd
);
11810 lRet
= pData
->uColors
[U(wParam
)];
11812 if((COLORREF
)lParam
== TV_NOCOLOR
) { // Standartfarbe einstellen
11813 if(pData
->cColorChanged
[U(wParam
)]) {
11814 pData
->cColorChanged
[U(wParam
)] = 0;
11815 UpdateColorsList(pData
);
11819 pData
->cColorChanged
[U(wParam
)] = 1;
11820 pData
->uColors
[U(wParam
)] = (COLORREF
)lParam
;
11822 if(lRet
!= lParam
) {
11823 UpdateColorsList(pData
);
11832 case TVM_HITTEST
: // Abfragen von Koortinatenpositionen
11834 pData
= GetHandle(hWnd
);
11837 lRet
= TreeListHitTest(pData
, (LPTV_HITTESTINFO
)lParam
);
11842 case TVM_SELECTCHILDS
: // Mehrere Einträge auswählen
11844 pData
= GetHandle(hWnd
);
11847 lRet
= TreeListSelectChilds(pData
, U(lParam
), U(wParam
));
11852 case TVM_SELECTSUBITEM
: // Einen (Sub)Eintrag auswählen
11854 pData
= GetHandle(hWnd
);
11857 if(!(pData
->uStyleEx
& TVS_EX_SUBSELECT
))
11859 lRet
= TreeListSelectItem(pData
, U(lParam
), U(wParam
), TVC_UNKNOWN
);
11866 case TVM_SELECTDROP
: // Den unterstrichenen Eintrags auswählen
11868 pData
= GetHandle(hWnd
);
11871 lRet
= TreeListSetTrackItem(pData
, U(lParam
), U(wParam
));
11876 case TVM_SELECTITEM
: // Einen Eintrag auswählen
11878 pData
= GetHandle(hWnd
);
11884 lRet
= TreeListSelectItem(pData
, U(lParam
), 0, TVC_UNKNOWN
);
11888 case TVGN_DROPHILITE
:
11889 lRet
= TreeListSetTrackItem(pData
, U(lParam
), 0);
11892 case TVGN_FIRSTVISIBLE
:
11893 lRet
= TreeListEnsureVisible(pData
, U(lParam
), FIRST_LINE
);
11894 lRet
= (lRet
< 0) ? 0 : 1;
11906 case TVM_GETCOLUMNORDERARRAY
: // Spaltensortierung abfragen
11911 pData
= GetHandle(hWnd
);
11913 if(!pData
->hHeader
)
11916 return Header_GetOrderArray(pData
->hHeader
, U(wParam
), lParam
);
11918 case TVM_SETCOLUMNORDERARRAY
: // Spalten sortieren
11920 pData
= GetHandle(hWnd
);
11922 lRet
= TreeListSetOrderArray(pData
, U(wParam
), (unsigned *)lParam
);
11927 case TVM_GETCOUNT
: // Anzahl der Einträge abfragen
11929 pData
= GetHandle(hWnd
);
11930 return pData
->uTreeItemsCount
;
11932 case TVM_GETINDENT
: // Einrückung abfragen
11934 pData
= GetHandle(hWnd
);
11935 return pData
->iIndent
;
11937 case TVM_SETINDENT
: // Einrückung einstellen
11939 pData
= GetHandle(hWnd
);
11940 lRet
= pData
->iIndent
;
11945 if(lRet
!= (LPARAM
)wParam
) {
11947 pData
->iIndent
= (int)wParam
;
11954 case TVM_GETITEMHEIGHT
: // Zeilenhöhe abfragen
11956 pData
= GetHandle(hWnd
);
11957 return pData
->iRowHeight
;
11959 case TVM_SETITEMHEIGHT
: // Zeilenhöhe abfragen
11961 pData
= GetHandle(hWnd
);
11962 lRet
= pData
->iRowHeight
;
11966 pData
->cFixedHeight
= 0;
11967 UpdateHeight(pData
);
11968 UpdateScrollY(pData
);
11974 if(!(pData
->uStyleEx
& TVS_NONEVENHEIGHT
))
11981 if(lRet
!= (LPARAM
)wParam
) {
11983 pData
->cFixedHeight
= 1;
11984 pData
->iRowHeight
= (int)wParam
;
11991 case TVM_GETVISIBLECOUNT
: // Abfragen der sichtbaren Zeilen
11993 pData
= GetHandle(hWnd
);
11994 return pData
->uPageEnties
;
11996 case TVM_ENSUREVISIBLE
: // Einen Eintrag ins Sichtfenster legen
11998 pData
= GetHandle(hWnd
);
12000 lRet
= TreeListEnsureVisible(pData
, U(lParam
), (int)wParam
);
12005 case TVM_ISITEMVISIBLE
: // Ist ein Eintrag sichtbar
12007 pData
= GetHandle(hWnd
);
12009 lRet
= TreeListIsVisible(pData
, U(lParam
), (int)wParam
);
12014 case TVM_GETNEXTITEM
: // Einen Eintrag suchen
12016 pData
= GetHandle(hWnd
);
12018 lRet
= TreeListGetNextItem(pData
, U(lParam
), (int)wParam
);
12023 case TVM_GETITEMRECT
: // Das Rechteck eines Eintrages abfragen
12025 pData
= GetHandle(hWnd
);
12027 uVal
= *(unsigned *)lParam
;
12028 lRet
= TreeListGetItemRect(pData
, uVal
, U(wParam
), (RECT
*)lParam
);
12033 case TVM_EXPAND
: // Einen Eintrag umklappen
12035 pData
= GetHandle(hWnd
);
12039 if(U(lParam
) <= pData
->uTreeItemsMax
) {
12041 #ifndef __REACTOS__
12045 pEntry
= pData
->pTreeItems
[U(lParam
)];
12050 if(wParam
& TVE_EXPANDNEXT
) { // Bei erstem Eltereneintrag beginnen
12051 if(!pEntry
->uParent
) {
12056 lParam
= pEntry
->uParent
;
12057 pEntry
= pData
->pTreeItems
[U(lParam
)];
12058 wParam
&= ~TVE_EXPANDNEXT
;
12061 switch(wParam
& 0x0F) {
12063 if(pEntry
->uState
& TVIS_EXPANDED
) {
12064 lRet
= (TreeListToggleItem(pData
, U(lParam
), 0)) ? 0 : 1;
12065 } else { // Nur Flag löschen
12066 pEntry
->uState
&= ~TVIS_EXPANDPARTIAL
;
12070 if(wParam
& TVE_COLLAPSERESET
) {
12071 pEntry
->uState
&= TVIS_EXPANDEDONCE
;
12073 while(pEntry
->uLastChild
) {
12074 if(!TreeListDeleteItem(pData
, pEntry
->uLastChild
, 1))
12076 pEntry
= pData
->pTreeItems
[U(lParam
)];
12079 // Auch Eltern zuklappen
12080 if(!(wParam
& TVE_EXPANDRECURSIVE
)) {
12084 if(!pEntry
->uParent
) {
12088 lParam
= pEntry
->uParent
;
12093 if(!(pEntry
->uState
& TVIS_EXPANDED
)) {
12094 uVal
= (wParam
& TVE_EXPANDPARTIAL
) ? TVIS_EXPANDPARTIAL
: 0;
12095 lRet
= (TreeListToggleItem(pData
, U(lParam
), uVal
)) ? 0 : 1;
12096 } else { // Schon aufgeklappt
12099 if(wParam
& TVE_EXPANDPARTIAL
) {
12100 if(!(wParam
& TVE_EXPANDFORCE
))
12101 if((pEntry
->uState
& (TVIS_EXPANDPARTIAL
| TVIS_EXPANDEDONCE
)) != (TVIS_EXPANDPARTIAL
| TVIS_EXPANDEDONCE
)) {
12102 lRet
= (TreeListToggleItem(pData
, U(lParam
), TVE_EXPAND
| TVIS_EXPANDPARTIAL
)) ? 0 : 1;
12105 if(pEntry
->uState
& TVIS_EXPANDPARTIAL
) {
12106 lRet
= (TreeListToggleItem(pData
, U(lParam
), TVE_EXPAND
)) ? 0 : 1;
12110 // Auch Eltern aufklappen
12111 if(!(wParam
& TVE_EXPANDRECURSIVE
)) {
12115 if(!pEntry
->uParent
) {
12119 lParam
= pEntry
->uParent
;
12124 lRet
= (TreeListToggleItem(pData
, U(lParam
), 0)) ? 0 : 1;
12128 // Aktion auch auf alle Kinder anwenden
12129 if((wParam
& TVE_ALLCHILDS
) && pEntry
->uFirstChild
) {
12130 lParam
= pEntry
->uFirstChild
;
12131 wParam
&= ~(TVE_EXPANDRECURSIVE
| TVE_EXPANDNEXT
| TVE_ONLYCHILDS
);
12138 TreeListProc(hWnd
, uMsg
, wParam
, lParam
);
12142 if(U(lParam
) > pData
->uTreeItemsMax
) {
12146 pEntry
= pData
->pTreeItems
[U(lParam
)];
12147 if(!pEntry
|| !pEntry
->uNextItem
)
12150 lParam
= pEntry
->uNextItem
;
12160 case TVM_SETINSERTMARK
: // Einfügemarke eintellen
12162 pData
= GetHandle(hWnd
);
12165 lRet
= TreeListSetInsertMark(pData
, U(lParam
), (int)wParam
);
12170 case TVM_SETITEMBKCOLOR
: // Hintergrundfarbe eines Eintrages ändern
12172 pData
= GetHandle(hWnd
);
12175 lRet
= TreeListSetItemColor(pData
, U(wParam
& 0xFFFFFF), U(wParam
) >> 24, (COLORREF
)lParam
, 0);
12180 case TVM_SETITEMTEXTCOLOR
: // Textfarbe eines Eintrages ändern
12182 pData
= GetHandle(hWnd
);
12185 lRet
= TreeListSetItemColor(pData
, U(wParam
& 0xFFFFFF), U(wParam
) >> 24, (COLORREF
)lParam
, 1);
12190 case TVM_GETITEMBKCOLOR
: // Hintergrundfarbe eines Eintrages abfragen
12192 pData
= GetHandle(hWnd
);
12195 lRet
= TreeListGetItemColor(pData
, U(wParam
), U(lParam
), 0);
12200 case TVM_GETITEMTEXTCOLOR
: // Textfarbe eines Eintrages abfragen
12202 pData
= GetHandle(hWnd
);
12205 lRet
= TreeListGetItemColor(pData
, U(wParam
), U(lParam
), 1);
12210 case TVM_SORTCHILDRENEX
: // Sortieren mit Funktion
12212 pData
= GetHandle(hWnd
);
12215 lRet
= TreeListSortItemsEx(pData
, (TV_SORTEX
*)lParam
, (int)wParam
);
12220 case TVM_SORTCHILDRENCB
: // Sortieren mit Funktion
12222 pData
= GetHandle(hWnd
);
12225 lRet
= TreeListSortItemsCb(pData
, (TV_SORTCB
*)lParam
, (int)wParam
);
12230 case TVM_SORTCHILDREN
: // Sortieren der Kindereinträge
12232 pData
= GetHandle(hWnd
);
12235 lRet
= TreeListSortItems(pData
, U(lParam
), (int)wParam
);
12240 case TVM_GETITEMOFROW
: // Hole den Eintrag von einer Reihe
12242 pData
= GetHandle(hWnd
);
12245 if(U(lParam
) < pData
->uItemPosCount
)
12246 lRet
= pData
->pItemPos
[U(lParam
)];
12253 case TVM_GETROWCOUNT
: // Hole die Anzahl der sichtbaren Reihen
12255 pData
= GetHandle(hWnd
);
12257 return pData
->uItemPosCount
;
12259 case TVM_GETCOUNTPERPAGE
: // Hole die Anzahl der darstelbaren Reihen
12261 pData
= GetHandle(hWnd
);
12263 return pData
->uMaxEnties
;
12265 case TVM_GETROWOFITEM
: // Suche Reihe zu einem Eintrag
12267 pData
= GetHandle(hWnd
);
12270 if(U(lParam
) <= pData
->uTreeItemsMax
) {
12273 pEntry
= pData
->pTreeItems
[U(lParam
)];
12277 lRet
= pEntry
->uShowPos
- 1;
12285 case TVM_EDITLABEL
: // Einen Eintrag editieren
12287 pData
= GetHandle(hWnd
);
12288 if(!(pData
->uStyle
& TVS_EDITLABELS
))
12293 if((wParam
& 0xFFFFFF00) == TVLE_DONOTIFY
) { // Notify starten
12294 lRet
= TreeListStartNotifyEdit(pData
, U(lParam
), TVIR_EDITCOL(wParam
), VK_RETURN
, 0);
12296 pData
->cColumnStart
= 0;
12297 lRet
= (LRESULT
)TreeListEditLabel(pData
, U(lParam
), U(wParam
));
12304 case TVM_GETEDITCONTROL
: // Das Handle des Edit-Fensters abfragen
12306 pData
= GetHandle(hWnd
);
12307 return (LRESULT
)pData
->hEdit
;
12309 case TVM_GETTOOLTIPS
: // Das Handle des ToolTip-Fensters abfragen
12311 pData
= GetHandle(hWnd
);
12312 return (LRESULT
)pData
->hToolTip
;
12314 case TVM_SETTOOLTIPS
: // Das Handle für das ToolTip-Fensters setzen
12316 pData
= GetHandle(hWnd
);
12317 lRet
= (LRESULT
)pData
->hToolTip
;
12318 pData
->hToolTip
= (HWND
)wParam
;
12321 case TVM_SETUSERDATASIZE
: // Einstellen der Größe der User-Daten
12323 if(lParam
< 0 || lParam
> 0x1000000)
12325 pData
= GetHandle(hWnd
);
12329 if(pData
->uTreeItemsCount
> 0) {
12332 pData
->uUserDataSize
= U(lParam
);
12340 case TVM_GETUSERDATASIZE
: // Abfragen der Größe der User-Daten
12342 pData
= GetHandle(hWnd
);
12343 return pData
->uUserDataSize
;
12345 case TVM_GETUSERDATA
: // Einen Zeiger auf die User-Daten holen
12347 pData
= GetHandle(hWnd
);
12349 if(pData
->uUserDataSize
&& U(lParam
) <= pData
->uTreeItemsMax
) {
12352 pEntry
= pData
->pTreeItems
[U(lParam
)];
12354 return (LRESULT
)(pEntry
+ 1);
12359 case TVM_SETCOLUMN
: // Einen Spalten-Header einstellen
12361 pData
= GetHandle(hWnd
);
12363 if(pData
->hHeader
&& U(wParam
) < pData
->uColumnCount
) {
12369 pCol
= (TV_COLUMN
*)lParam
;
12373 if(uVal
== TVCF_LASTSIZE
) { // Breite vor Fixierung benutzen
12374 if(pData
->aColumn
[uCol
].sFixed
> 0) {
12375 uVal
= pData
->aColumn
[uCol
].sFixed
;
12377 uVal
= pData
->aColumn
[uCol
].sReal
;
12381 if(pCol
->mask
& TVCF_FIXED
) { // Die Spalte fixieren
12382 uBit
= pCol
->fmt
& TVCFMT_FIXED
;
12384 if(uBit
!= 0 && pData
->aColumn
[uCol
].sFixed
== 0) {
12385 pData
->aColumn
[uCol
].sFixed
= pData
->aColumn
[uCol
].sReal
;
12386 if(!pData
->aColumn
[uCol
].sFixed
)
12387 pData
->aColumn
[uCol
].sFixed
= 100;
12390 if(uBit
== 0 && pData
->aColumn
[uCol
].sFixed
!= 0) {
12391 pData
->aColumn
[uCol
].sFixed
= 0;
12396 if(pCol
->mask
& TVCF_FMT
){
12397 sItem
.mask
|= HDI_FORMAT
;
12398 sItem
.fmt
= pCol
->fmt
| HDF_STRING
;
12400 if(pCol
->mask
& TVCF_IMAGE
){
12401 sItem
.mask
|= HDI_IMAGE
;
12402 sItem
.iImage
= pCol
->iImage
;
12404 if(pCol
->mask
& TVCF_WIDTH
){
12405 sItem
.mask
|= HDI_WIDTH
;
12407 pData
->aColumn
[uCol
].sSize
= (short)sItem
.cxy
;
12409 if(pCol
->mask
& TVCF_TEXT
){
12410 sItem
.mask
|= HDI_TEXT
;
12411 sItem
.pszText
= pCol
->pszText
;
12412 sItem
.cchTextMax
= pCol
->cchTextMax
;
12416 lRet
= SendMessage(pData
->hHeader
, HDM_SETITEM
, uCol
, (LPARAM
)&sItem
);
12421 if(lRet
&& (pCol
->mask
& TVCF_FMT
)) { // Hat sich die Ausrichtung verändert
12424 switch(pCol
->fmt
) {
12425 case TVCFMT_CENTER
: bAlign
= DT_CENTER
; break;
12426 case TVCFMT_RIGHT
: bAlign
= DT_RIGHT
; break;
12427 default: bAlign
= DT_LEFT
; break;
12430 if(pData
->aColumn
[uCol
].bAlign
!= bAlign
) {
12431 pData
->aColumn
[uCol
].bAlign
= bAlign
;
12432 UpdateColRect(pData
, uCol
);
12436 if(lRet
&& (pCol
->mask
& TVCF_MARK
)) { // Die Spalte markieren
12440 uVal
= (pCol
->fmt
& TVCFMT_MARK
) ? 1 : 0;
12441 if(uVal
!= pData
->aColumn
[uCol
].bMark
) {
12442 pData
->aColumn
[uCol
].bMark
= (BYTE
)uVal
;
12443 pData
->uMarkedCols
+= uVal
* 2 - 1;
12445 uNext
= pData
->aColumn
[uCol
].bNext
;
12446 sRect
.left
= pData
->aColumnXpos
[uCol
];
12447 sRect
.right
= pData
->aColumnXpos
[uNext
] + 1;
12448 sRect
.bottom
= pData
->uScrollX
;
12449 sRect
.top
= pData
->uSizeY
;
12450 InvalidateRect(pData
->hWnd
, &sRect
, FALSE
);
12459 case TVM_GETCOLUMN
: // Einen Spalten-Header abfragen
12461 pData
= GetHandle(hWnd
);
12462 if(pData
->hHeader
) {
12464 TV_COLUMN
*pCol
= (TV_COLUMN
*)lParam
;
12470 if(pCol
->mask
& TVCF_FMT
) {
12471 sItem
.mask
|= HDI_FORMAT
;
12472 bWantMark
= pCol
->fmt
& TVCFMT_MARK
; //memorize if we want the marked state
12474 if(pCol
->mask
& TVCF_IMAGE
){
12475 sItem
.mask
|= HDI_IMAGE
;
12477 if(pCol
->mask
& TVCF_WIDTH
){
12478 sItem
.mask
|= HDI_WIDTH
;
12480 if(pCol
->mask
& TVCF_TEXT
){
12481 sItem
.mask
|= HDI_TEXT
;
12482 sItem
.pszText
= pCol
->pszText
;
12483 sItem
.cchTextMax
= pCol
->cchTextMax
;
12486 lRet
= SendMessage(pData
->hHeader
, HDM_GETITEM
, wParam
, (LPARAM
)&sItem
);
12490 if(sItem
.mask
& HDI_FORMAT
) {
12491 pCol
->mask
|= TVCF_FMT
;
12492 pCol
->fmt
= sItem
.fmt
;
12494 if(bWantMark
&& pData
->aColumn
[uCol
].bMark
)
12495 pCol
->fmt
|= TVCFMT_MARK
;
12496 if(!pData
->aColumn
[uCol
].sReal
&& pData
->aColumn
[uCol
].sFixed
)
12497 pCol
->fmt
|= TVCFMT_FIXED
;
12499 if(sItem
.mask
& HDI_IMAGE
){
12500 pCol
->mask
|= TVCF_IMAGE
;
12501 pCol
->iImage
= sItem
.iImage
;
12503 if(sItem
.mask
& HDI_WIDTH
){
12504 pCol
->mask
|= TVCF_WIDTH
;
12505 pCol
->cx
= sItem
.cxy
;
12507 if(sItem
.mask
& HDI_TEXT
){
12508 pCol
->mask
|= TVCF_TEXT
;
12509 pCol
->pszText
= sItem
.pszText
;
12510 pCol
->cchTextMax
= sItem
.cchTextMax
;
12519 case TVM_SETFOCUSITEM
: // Focus einstellen
12521 pData
= GetHandle(hWnd
);
12524 lRet
= TreeListSetFocus(pData
, U(lParam
), U(wParam
));
12529 case TVM_SETCOLUMNWIDTH
: // Die Spaltenbreite einstellen
12531 pData
= GetHandle(hWnd
);
12533 if(pData
->hHeader
&& U(wParam
) < pData
->uColumnCount
&& (int)lParam
>= 0) {
12536 sItem
.mask
= HDI_WIDTH
;
12537 sItem
.cxy
= (int)lParam
;
12538 lRet
= SendMessage(pData
->hHeader
, HDM_SETITEM
, wParam
, (LPARAM
)&sItem
);
12545 case TVM_COLUMNAUTOEDIT
: // AutoEdit für eine Spalte einstellen
12547 pData
= GetHandle(hWnd
);
12548 uVal
= (wParam
>> 11) & 0x3F;
12550 if(uVal
>= pData
->uColumnCount
) {
12554 uMode
= (U(wParam
) >> TVAE_MODEPOS
) & 7;
12556 if(uMode
== TVAX_NONE
) {
12559 if(uVal
== 0 && uMode
>= TVAX_CHECK
) { // Checkboxes are not allowed in the first column
12565 uChange
= pData
->aColumn
[uVal
].bEdit
<< TVAE_MODEPOS
;
12566 uChange
|= pData
->aColumn
[uVal
].bFlags
& TVAE_STATEENABLE
;
12568 pData
->aColumn
[uVal
].bEdit
= (BYTE
)(uMode
);
12569 pData
->aColumn
[uVal
].bFlags
= (BYTE
)(wParam
);
12570 pData
->aColumn
[uVal
].bCbChar
= (BYTE
)(wParam
>> 17);
12571 pData
->aColumn
[uVal
].bCbSize
= (BYTE
)(wParam
>> 25);
12572 pData
->aColumn
[uVal
].pCbData
= (void *)lParam
;
12573 pData
->aColumn
[uVal
].iCbIcon
= -1;
12575 if(uMode
>= TVAX_CHECK
) { // Sollen Checkboxen dargestetllt werden
12576 if(!pData
->hChecks
) {
12577 CreateStateImageList(pData
, 1);
12578 UpdateHeight(pData
);
12581 if((uChange
^ wParam
) & ((TVAE_MODEMASK
^ TVAE_CHECK
^ TVAE_CHECKED
) | TVAE_STATEENABLE
)) {
12582 UpdateColRect(pData
, uVal
);
12585 if((uChange
& TVAE_MODEMASK
) >= TVAE_CHECK
) { // Waren Checkboxen dargestetllt
12586 if((uChange
^ wParam
) & ((TVAE_MODEMASK
^ TVAE_CHECK
^ TVAE_CHECKED
) | TVAE_STATEENABLE
)) {
12587 UpdateColRect(pData
, uVal
);
12595 case TVM_COLUMNAUTOICON
: // Icons für AutoEdit einstellen
12597 pData
= GetHandle(hWnd
);
12600 if(uVal
>= pData
->uColumnCount
|| !pData
->aColumn
[uVal
].bEdit
) {
12606 pData
->aColumn
[uVal
].iCbIcon
= (int)lParam
;
12612 case TVM_GETCOLUMNWIDTH
: // Die Spaltenbreite abfragen
12614 pData
= GetHandle(hWnd
);
12615 if(pData
->hHeader
) {
12618 sItem
.mask
= HDI_WIDTH
;
12619 sItem
.cxy
= (int)lParam
;
12620 SendMessage(pData
->hHeader
, HDM_GETITEM
, wParam
, (LPARAM
)&sItem
);
12628 case TVM_CREATEDRAGIMAGE
: // Ein Drag-Image erzeugen
12630 pData
= GetHandle(hWnd
);
12632 lRet
= (LRESULT
)CreateDragImage(pData
, U(lParam
), U(wParam
));
12636 case TVM_ENDEDITLABELNOW
: // Die aktuelle Eingabe abbrechen
12638 pData
= GetHandle(hWnd
);
12640 lRet
= (TreeListEndLabelEdit(pData
, (wParam
) ? 0 : 1)) ? 1 : 0;
12644 case TVM_GETISEARCHSTRING
: // Holt den aktuellen Suchtext
12646 uDelta
= GetTickCount() - uKeyLast
;
12649 return (uDelta
<= 750) ? uKeyPos
: 0;
12653 ((TCHAR
*)lParam
)[0] = 0;
12657 memcpy((TCHAR
*)lParam
, cKeyData
, uKeyPos
* sizeof(TCHAR
));
12658 ((TCHAR
*)lParam
)[uKeyPos
] = 0;
12661 case TVM_GETUNICODEFORMAT
: // Wird gerade UNI-Code verwendet
12671 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
12675 //*****************************************************************************
12679 //*****************************************************************************
12680 // Zeichnet das Fenster
12681 static void TreeListDraw(HWND hWnd
, HDC hDc
, RECT
*pRect
) {
12691 COLORREF uOldColor
;
12692 COLORREF uOutColor
;
12693 COLORREF uNextColor
;
12694 COLORREF uTempColor
;
12696 HRGN aRgn
[MAX_COLUMNS
+ 1];
12701 TreeListData
*pData
;
12706 HIMAGELIST hImgList
;
12707 unsigned uTextSize
;
12708 unsigned uRgnCount
;
12709 unsigned uAutoMask
;
12710 unsigned uFirstPos
;
12724 int iRnType
[MAX_COLUMNS
+ 1];
12742 pData
= GetHandle(hWnd
);
12746 GetClientRect(hWnd
, &sRect
);
12751 iXscroll
= -(int)pData
->uScrollX
;
12752 pOffsets
= pData
->aColumnXpos
;
12753 hRgnMain
= CreateRectRgn(pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
12755 uMax
= pData
->uColumnCount
;
12757 aRgn
[ 0 ] = CreateRectRgn(sRect
.left
, sRect
.top
, sRect
.right
, sRect
.bottom
);
12758 iRnType
[ 0 ] = CombineRgn(aRgn
[0], aRgn
[0], hRgnMain
, RGN_AND
);
12761 for(uPos
= 0; uPos
< uMax
; uPos
++) {
12762 uExtra
= pData
->aColumnPos
[uPos
];
12763 uNext
= pData
->aColumnPos
[uPos
+ 1];
12764 aRgn
[uExtra
] = CreateRectRgn(sRect
.left
+ pOffsets
[uExtra
] + iXscroll
, sRect
.top
, sRect
.left
+ pOffsets
[uNext
] + iXscroll
, sRect
.bottom
);
12765 iRnType
[uExtra
] = CombineRgn(aRgn
[uExtra
], aRgn
[uExtra
], hRgnMain
, RGN_AND
);
12768 aRgn
[uPos
] = CreateRectRgn(sRect
.left
+ pOffsets
[uPos
] + iXscroll
, sRect
.top
, sRect
.right
, sRect
.bottom
);
12769 iRnType
[uPos
] = CombineRgn(aRgn
[uPos
], aRgn
[uPos
], hRgnMain
, RGN_AND
);
12771 uRgnCount
= uMax
+ 1;
12774 iHeight
= pData
->iRowHeight
;
12775 uStyleEx
= pData
->uStyleEx
;
12776 uStyle
= pData
->uStyle
;
12777 iIndent
= pData
->iIndent
;
12778 iShift
= pData
->iShift
;
12779 uPos
= pData
->uScrollY
;
12780 uMax
= pData
->uMaxEnties
+ uPos
;
12781 uNext
= (pData
->uColumnCount
<= 1) ? 1 : pData
->aColumn
[1].bIndex
;
12782 uFirstPos
= pData
->aColumnXpos
[uNext
];
12784 if(iRnType
[0] == NULLREGION
)
12785 iMaxX
= pData
->iMaxSizeX
;
12787 iMaxX
= uFirstPos
- 1;
12789 if(uStyleEx
& TVS_EX_ITEMLINES
) {
12793 if(uStyleEx
& TVS_EX_AUTOEXPANDICON
) {
12794 uAutoMask
= TVIS_EXPANDED
;
12799 if(uMax
> pData
->uItemPosCount
) {
12800 uMax
= pData
->uItemPosCount
;
12803 uBkColor
= pData
->uColors
[TVC_BK
];
12804 uFrColor
= pData
->uColors
[TVC_FRAME
];
12806 if(pData
->uStyleEx
& TVS_EX_ALTERNATECOLOR
) { // Abwechselnde Farben
12807 uOdColor
= pData
->uColors
[TVC_ODD
];
12808 uEvColor
= pData
->uColors
[TVC_EVEN
];
12809 uOcColor
= pData
->uColors
[TVC_COLODD
];
12810 uEcColor
= pData
->uColors
[TVC_COLEVEN
];
12812 uOdColor
= uBkColor
;
12813 uEvColor
= uBkColor
;
12814 uOcColor
= pData
->uColors
[TVC_COLBK
];
12815 uEcColor
= pData
->uColors
[TVC_COLBK
];
12818 if(!pData
->cIsEnabled
) // Wenn Fenster gessperrt grau zeichnen
12819 if(pData
->uStyleEx
& TVS_EX_GRAYEDDISABLE
) {
12820 uBkColor
= pData
->uColors
[TVC_GRAYED
];
12821 uEvColor
= uEcColor
;
12822 uOdColor
= uOcColor
;
12825 uInColor
= pData
->uColors
[TVC_LINE
];
12826 uBtColor
= pData
->uColors
[TVC_BOX
];
12830 sArea
.top
= sRect
.top
+ pData
->uStartPixel
;
12831 SelectObject(hDc
, pData
->hFontN
);
12832 SelectObject(hDc
, hPatternPen
);
12833 SetBkColor(hDc
, uBkColor
);
12834 SetBkMode(hDc
, TRANSPARENT
);
12835 SetTextAlign(hDc
, TA_LEFT
| TA_TOP
);
12836 SetTextColor(hDc
, pData
->uColors
[TVC_TEXT
]);
12838 //******************** Einträge zeichnen **************************************
12839 for(; uPos
< uMax
; uPos
++) { // Alle Einträge ausgeben
12840 uItem
= pData
->pItemPos
[uPos
];
12842 pEntry
= pData
->pTreeItems
[uItem
];
12846 if((pEntry
->uState
& TVIS_SELECTED
) && (uStyleEx
& TVS_EX_FULLROWMARK
)) {
12847 if(uStyleEx
& TVS_EX_ALTERNATECOLOR
)
12848 uOutColor
= (uPos
& 1) ? pData
->uColors
[TVC_MARKODD
] : pData
->uColors
[TVC_MARKEVEN
];
12850 uOutColor
= pData
->uColors
[TVC_MARK
];
12852 uMark
= (unsigned)~TVIS_BKCOLOR
;
12855 if(uPos
& 1) { // Farbe wechselweise ändern
12856 uColMark
= pData
->aColumn
[0].bMark
;
12857 uOutColor
= (uColMark
) ? uOcColor
: uOdColor
;
12858 uMark
= 0xFFFFFFFF;
12860 uColMark
= pData
->aColumn
[0].bMark
;
12861 uOutColor
= (uColMark
) ? uEcColor
: uEvColor
;
12862 uMark
= 0xFFFFFFFF;
12865 sArea
.bottom
= sArea
.top
+ pData
->iRowHeight
;
12866 sArea
.left
= iXscroll
;
12867 iLevel
= pEntry
->uLevel
;
12869 if(iRnType
[0] == NULLREGION
) {
12873 uBits
= pEntry
->uState
& 0xFFFF;
12874 uBits
|= pEntry
->bFlags
<< 16;
12876 iImage
= (uBits
& LVIS_SELECTED
) ? pEntry
->iSelectedImage
: pEntry
->iImage
;
12877 pText
= pEntry
->pText
;
12878 uTextSize
= pEntry
->uTextSize
;
12880 if(pData
->uSelectedSub
&& uItem
== pData
->uSelectedItem
) {
12881 if(pData
->uSelectedCount
<= 1 || !(pData
->uStyleEx
& TVS_EX_SUBSELECT
)) {
12882 uBits
&= ~TVIS_SELECTED
;
12886 if(pEntry
->bCallback
) {
12887 CallbackEntry(pData
, pEntry
, uItem
, pEntry
->bCallback
, &iImage
, &uTextSize
, &pText
);
12889 pEntry
= pData
->pTreeItems
[uItem
];
12894 SelectObject(hDc
, aRgn
[0]);
12896 if((uStyleEx
& (TVS_EX_ITEMLINES
| TVS_EX_FULLROWITEMS
)) == (TVS_EX_ITEMLINES
| TVS_EX_FULLROWITEMS
)) {
12898 sButton
.right
= iIndent
* (iLevel
+ 1) + 2;
12899 sButton
.bottom
= sArea
.bottom
+ 1;
12900 sButton
.top
= sArea
.bottom
- 2;
12902 SetBkColor(hDc
, uFrColor
);
12903 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sButton
, NULL
, 0, NULL
);
12906 if(pData
->aColumn
[0].bMark
) { // Ist die erste Spalte markiert
12907 uBkColor
= pData
->uColors
[TVC_COLBK
];
12910 SetBkColor(hDc
, (uStyleEx
& TVS_EX_FULLROWITEMS
) ? uOutColor
: uBkColor
);
12912 if(pData
->cHasRootRow
)
12918 if(uStyle
& (TVS_HASBUTTONS
| TVS_HASLINES
)) {
12922 if(uStyleEx
& TVS_EX_FULLROWITEMS
) {
12929 if(uStyle
& TVS_HASLINES
) {
12930 pTemp
= pData
->pTreeItems
[pEntry
->uParent
];
12931 sArea
.right
= sArea
.left
+ 1; // Eine leerer Pixelreihe am Anfang
12932 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
12933 sArea
.left
+= iIndent
* iLevel
+ 1;
12935 for(i
= iLevel
; i
> 0; i
--) { // Bereich vor Schaltflächen
12936 sArea
.right
= sArea
.left
;
12937 sArea
.left
-= iIndent
;
12939 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
12941 iXpos
= sArea
.left
+ iShift
;
12944 if(pTemp
->uNextItem
) { // Zeichne vertikale Linien
12945 MoveToEx(hDc
, iXpos
, sArea
.top
| 1, NULL
);
12946 LineTo(hDc
, iXpos
, sArea
.bottom
+ iAdd
);
12949 pTemp
= pData
->pTreeItems
[pTemp
->uParent
];
12953 sArea
.left
+= iIndent
* iLevel
;
12954 } else { // Ohne Linien zeichnen
12956 sArea
.right
= sArea
.left
+ iIndent
* iLevel
;
12957 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
12958 sArea
.left
+= sArea
.right
;
12962 if(uStyle
& TVS_HASBUTTONS
) { // Fenster mit Schaltflächen ?
12963 sArea
.right
= sArea
.left
+ iIndent
;
12964 iXpos
= sArea
.left
+ iShift
;
12965 iYpos
= sArea
.top
+ pData
->iRowHeight
/ 2;
12967 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
12969 if(uStyle
& TVS_HASLINES
) { // Linien unter Schaltflächen
12970 MoveToEx(hDc
, iXpos
, sArea
.top
| 1, NULL
);
12972 if(pEntry
->uNextItem
)
12973 LineTo(hDc
, iXpos
, sArea
.bottom
+ iAdd
);
12975 LineTo(hDc
, iXpos
, iYpos
+ 1);
12977 MoveToEx(hDc
, iXpos
+ 1 + (iYpos
& 1), iYpos
, NULL
);
12978 LineTo(hDc
, sArea
.right
, iYpos
);
12981 if(pEntry
->bFlags
& TVIX_HASBUTTON
) { // Schaltflächen zeichnen
12982 sButton
.left
= iXpos
- 4;
12983 sButton
.top
= iYpos
- 4;
12984 sButton
.right
= iXpos
+ 5;
12985 sButton
.bottom
= iYpos
+ 5;
12987 if(pData
->cGlyphOk
) { // Thema benutzen
12988 uState
= ((uBits
^ TVIS_EXPANDED
) & (TVIS_EXPANDED
| TVIS_EXPANDPARTIAL
)) ? GLPS_CLOSED
: GLPS_OPENED
;
12989 pDrawThemeBackg(pData
->hTheme
, hDc
, TVP_GLYPH
, uState
, &sButton
, 0);
12991 SetBkColor(hDc
, uBtColor
);
12992 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sButton
, NULL
, 0, NULL
);
12996 sButton
.right
-= 1;
12997 sButton
.bottom
-= 1;
12999 SetBkColor(hDc
, pData
->uColors
[TVC_BOXBG
]);
13000 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sButton
, NULL
, 0, NULL
);
13002 sButton
.left
= iXpos
- 2;
13003 sButton
.top
= iYpos
;
13004 sButton
.right
= iXpos
+ 3;
13005 sButton
.bottom
= iYpos
+ 1;
13007 SetBkColor(hDc
, uInColor
);
13008 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sButton
, NULL
, 0, NULL
);
13010 // '+' statt '-' Schaltfläsche zeichnenen
13011 if((uBits
^ TVIS_EXPANDED
) & (TVIS_EXPANDED
| TVIS_EXPANDPARTIAL
)) {
13012 sButton
.left
= iXpos
;
13013 sButton
.top
= iYpos
- 2;
13014 sButton
.right
= iXpos
+ 1;
13015 sButton
.bottom
= iYpos
+ 3;
13016 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sButton
, NULL
, 0, NULL
);
13020 SetBkColor(hDc
, uBkColor
);
13023 sArea
.left
+= iIndent
;
13025 if(uStyle
& TVS_HASLINES
) { // Nur Linien zeichnen ohne Schaltflächen
13026 sArea
.right
= sArea
.left
+ iIndent
;
13027 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13029 iYpos
= sArea
.top
+ pData
->iRowHeight
/ 2;
13030 iXpos
= sArea
.left
+ iShift
;
13031 MoveToEx(hDc
, iXpos
, sArea
.top
| 1, NULL
);
13033 if(pEntry
->uNextItem
)
13034 LineTo(hDc
, iXpos
, sArea
.bottom
);
13036 LineTo(hDc
, iXpos
, iYpos
+ 1);
13038 MoveToEx(hDc
, iXpos
+ 1 + (iYpos
& 1), iYpos
, NULL
);
13039 LineTo(hDc
, sArea
.right
, iYpos
);
13041 sArea
.left
+= iIndent
;
13044 if(uStyleEx
& TVS_EX_FULLROWITEMS
)
13049 if(uStyleEx
& TVS_EX_ITEMLINES
) { // Linien um den Eintrag zeichnen
13051 sArea
.right
= sArea
.left
+ 1;
13053 if(uStyleEx
& TVS_EX_FULLROWITEMS
) {
13054 iStart
= sArea
.left
;
13058 SetBkColor(hDc
, uFrColor
);
13059 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13063 iStart
= sArea
.left
;
13065 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13069 iStart
= sArea
.left
- 1;
13075 SetBkColor(hDc
, (uBits
& TVIS_BKCOLOR
) ? pEntry
->uColorBk
: uOutColor
);
13076 SelectObject(hDc
, (uBits
& TVIS_BOLD
) ? pData
->hFontB
: pData
->hFontN
);
13078 if(pData
->hStates
) { // State-Icons anzeigen
13079 sArea
.right
= sArea
.left
+ pData
->iStatesXsize
;
13080 iYpos
= sArea
.top
+ (iHeight
- pData
->iStatesYsize
) / 2;
13081 i
= (uBits
& LVIS_STATEIMAGEMASK
) >> 12;
13083 sArea
.right
+= iAdd
;
13084 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13085 sArea
.left
+= iAdd
;
13087 if(pData
->hStates
== THEMEIMGLIST
) { // Mit Thema zeichnen
13088 if(pData
->uStyleEx
& TVS_EX_BITCHECKBOX
)
13091 if(i
>= 1 && i
<= 2) {
13092 uState
= (i
== 1) ? CBS_UNCHECKEDNORMAL
: CBS_CHECKEDNORMAL
;
13093 pDrawThemeBackg(pData
->hThemeBt
, hDc
, BP_CHECKBOX
, uState
, &sArea
, 0);
13096 ImageList_Draw(pData
->hStates
, i
, hDc
, sArea
.left
, iYpos
, ILD_TRANSPARENT
);
13099 sArea
.left
+= pData
->iStatesXsize
;
13103 if(pData
->hImages
&& iImage
!= TV_NOIMAGE
) { // Icon zeichnen vom Haupteintrag
13104 if(iImage
>= TV_SECONDICON
) { // Sub-Image-Liste verwenden
13105 if(iImage
& TV_NOAUTOEXPAND
) {
13106 iImage
&= ~TV_NOAUTOEXPAND
; // Kein Auto-Expant bei diesem Icon
13108 if((pEntry
->uState
& uAutoMask
) && pEntry
->uFirstChild
) {
13109 iImage
+= 1; // Auto-Expant aktivieren
13112 iImage
-= TV_SECONDICON
;
13113 sArea
.right
= sArea
.left
+ pData
->iSubImgXsize
;
13114 iYpos
= sArea
.top
+ (iHeight
- pData
->iSubImgYsize
) / 2;
13115 pEntry
->bFlags
|= TVIX_HASIMAGE
;
13117 sArea
.right
+= iAdd
;
13118 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13119 sArea
.left
+= iAdd
;
13120 ImageList_Draw(pData
->hSubImg
, iImage
, hDc
, sArea
.left
, iYpos
, ILD_TRANSPARENT
| (uBits
& (TVIS_OVERLAYMASK
| LVIS_CUT
)));
13122 sArea
.left
+= pData
->iSubImgXsize
;
13124 } else { // Haup-Image-Liste verwenden
13125 if(iImage
& TV_NOAUTOEXPAND
) {
13126 iImage
&= ~TV_NOAUTOEXPAND
; // Kein Auto-Expant bei diesem Icon
13128 if((pEntry
->uState
& uAutoMask
) && pEntry
->uFirstChild
) {
13129 iImage
+= pData
->iAutoAdd
; // Auto-Expant aktivieren
13132 sArea
.right
= sArea
.left
+ pData
->iImagesXsize
;
13133 iYpos
= sArea
.top
+ (iHeight
- pData
->iImagesYsize
) / 2;
13134 pEntry
->bFlags
|= TVIX_HASIMAGE
;
13136 sArea
.right
+= iAdd
;
13137 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13138 sArea
.left
+= iAdd
;
13139 ImageList_Draw(pData
->hImages
, iImage
, hDc
, sArea
.left
, iYpos
, ILD_TRANSPARENT
| (uBits
& (TVIS_OVERLAYMASK
| LVIS_CUT
)));
13141 sArea
.left
+= pData
->iImagesXsize
;
13145 pEntry
->bFlags
&= ~TVIX_HASIMAGE
;
13148 sArea
.right
= uFirstPos
; // Text ausgeben vom Haupteintrag
13149 iYpos
= sArea
.top
+ (iHeight
- pData
->iFontHeight
) / 2;
13151 if(uBits
& (TVIS_SELECTED
| TVIS_DROPHILITED
| TVIS_UNDERLINE
| TVIS_TRACKED
| TVIS_TEXTCOLOR
| TVIS_FOCUSED
)) {
13152 // Das Feld speziel zeichnen
13153 TCHAR
*pPtr
= (TCHAR
*)new(TCHAR
, uTextSize
+ 4);
13154 INT
*pPos
= (INT
*)new(INT
, uTextSize
+ 4);
13156 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, NULL
, 0, NULL
);
13158 sButton
.top
= iYpos
;
13159 sButton
.left
= sArea
.left
+ 4;
13160 sButton
.right
= sArea
.right
;
13161 sButton
.bottom
= iYpos
+ pData
->iFontHeight
+ 2;
13163 if(!uTextSize
) { // Feld ohne Text ?
13164 sButton
.right
-= 2;
13166 pEntry
->iTextPixels
= 0;
13168 if(pData
->uStyleEx
& TVS_EX_FULLROWMARK
)
13169 if(pData
->cHasFocus
== 0 || uItem
!= pData
->uSelectedItem
|| pData
->uSelectedSub
)
13170 if((uBits
& TVIS_SELECTED
) && !(uBits
& (TVIS_DROPHILITED
| TVIS_FOCUSED
))) {
13174 DrawText(hDc
, pText
, uTextSize
, &sButton
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
| DT_CALCRECT
);
13175 pEntry
->iTextPixels
= sButton
.right
- sButton
.left
;
13178 // Passt der Text in die Spalte
13179 if(sButton
.left
+ pEntry
->iTextPixels
>= (int)(sArea
.right
- pData
->uScrollX
)) {
13180 iSize
= sArea
.right
- pData
->uScrollX
- sButton
.left
- 2;
13181 iSize
-= (uBits
& TVIS_BOLD
) ? pData
->uTrippleB
: pData
->uTrippleN
;
13185 GetTextExtentExPoint(hDc
, pText
, uTextSize
, iSize
, &iCount
, pPos
, &sSize
);
13187 // Temporären Text mit "..." erzeugen
13188 memcpy(pPtr
, pText
, iCount
* sizeof(TCHAR
));
13189 memcpy(pPtr
+ iCount
, _T("..."), 4 * sizeof(TCHAR
));
13192 uTextSize
= iCount
+ 3;
13193 sButton
.right
= sArea
.right
- 2;
13196 // Das Feld selektiert zeichnen
13197 if((uBits
& TVIS_SELECTED
) && pData
->cHasFocus
&& uItem
== pData
->uSelectedItem
&& !pData
->uSelectedSub
) {
13198 uTempColor
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
13199 SelectObject(hDc
, GetSysColorBrush(COLOR_HIGHLIGHT
));
13200 Rectangle(hDc
, sButton
.left
- 2, sButton
.top
- 1, sButton
.right
+ 2, sButton
.bottom
+ 1);
13202 if(uBits
& TVIS_DROPHILITED
) {
13203 uTempColor
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
13204 SelectObject(hDc
, GetSysColorBrush(COLOR_HIGHLIGHT
));
13205 SelectObject(hDc
, GetStockObject(NULL_PEN
));
13206 Rectangle(hDc
, sButton
.left
- 2, sButton
.top
- 1, sButton
.right
+ 2, sButton
.bottom
+ 1);
13208 if(uBits
& TVIS_SELECTED
) { // Ist das Feld ohne Focus ausgewählt
13209 if(pData
->cHasFocus
) {
13210 uTempColor
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
13211 SelectObject(hDc
, GetSysColorBrush(COLOR_HIGHLIGHT
));
13212 SelectObject(hDc
, GetStockObject(NULL_PEN
));
13214 if(uBits
& TVIS_TEXTCOLOR
)
13215 uTempColor
= pEntry
->uColorText
;
13217 uTempColor
= pData
->uColors
[TVC_TEXT
];
13219 if(pData
->uStyleEx
& TVS_EX_FULLROWMARK
)
13220 SelectObject(hDc
, GetStockObject(NULL_BRUSH
));
13222 SelectObject(hDc
, GetSysColorBrush(COLOR_3DFACE
));
13224 SelectObject(hDc
, GetStockObject(NULL_PEN
));
13227 Rectangle(hDc
, sButton
.left
- 2, sButton
.top
- 1, sButton
.right
+ 2, sButton
.bottom
+ 1);
13228 } else { // Das Feld normal zeichnen
13229 if(uBits
& TVIS_TRACKED
)
13230 uTempColor
= pData
->uColors
[TVC_TRACK
];
13232 if(uBits
& TVIS_TEXTCOLOR
)
13233 uTempColor
= pEntry
->uColorText
;
13235 uTempColor
= pData
->uColors
[TVC_TEXT
];
13240 SelectObject(hDc
, hPatternPen
);
13242 if(uBits
& TVIS_FOCUSED
) { // Einen punktierten Rahmen um den Text zeichnen
13243 SelectObject(hDc
, GetStockObject(NULL_BRUSH
));
13244 Rectangle(hDc
, sButton
.left
- 2, sButton
.top
- 1, sButton
.right
+ 2, sButton
.bottom
+ 1);
13248 SetTextColor(hDc
, uTempColor
);
13249 sButton
.left
+= pData
->iFontOff
;
13250 DrawText(hDc
, pText
, uTextSize
, &sButton
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
);
13252 if(uBits
& (TVIS_UNDERLINE
| TVIS_TRACKED
)) // Text unterstreichen
13253 if(pText
&& *pText
) {
13254 sButton
.left
-= pData
->iFontOff
;
13255 sButton
.right
-= pData
->iFontOff
+ 1;
13256 sButton
.top
+= pData
->iFontLine
;
13257 sButton
.bottom
= sButton
.top
+ 1;
13258 uOldColor
= SetBkColor(hDc
, uTempColor
);
13259 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
, &sButton
, NULL
, 0, NULL
);
13260 SetBkColor(hDc
, uOldColor
);
13263 SetTextColor(hDc
, pData
->uColors
[TVC_TEXT
]);
13267 } else { // Das Feld normal ausgeben
13268 if(!pEntry
->iTextPixels
&& uTextSize
) {
13269 sButton
.top
= iYpos
;
13270 sButton
.left
= sArea
.left
+ 4;
13271 sButton
.right
= sArea
.right
;
13272 sButton
.bottom
= iYpos
+ pData
->iFontHeight
+ 2;
13273 // Textbreite berechen
13274 DrawText(hDc
, pText
, uTextSize
, &sButton
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
| DT_CALCRECT
);
13276 pEntry
->iTextPixels
= sButton
.right
- sButton
.left
;
13279 // Ist der Text größer als die Spalte
13280 if(sArea
.left
+ pEntry
->iTextPixels
>= (int)(sArea
.right
- pData
->uScrollX
)) {
13281 INT
*pPos
= (INT
*)new(INT
, uTextSize
);
13283 iSize
= sArea
.right
- sArea
.left
- pData
->uScrollX
;
13284 iSize
-= (uBits
& TVIS_BOLD
) ? pData
->uTrippleB
: pData
->uTrippleN
;
13288 GetTextExtentExPoint(hDc
, pText
, uTextSize
, iSize
, &iCount
, pPos
, &sSize
);
13291 if(iCount
> 0) { // Passen noch Buchstaben vor "..."
13292 sButton
.right
= sArea
.right
;
13293 sArea
.right
= sArea
.left
+ 2 + pPos
[iCount
- 1];
13295 ExtTextOut(hDc
, sArea
.left
+ 2, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, pText
, iCount
, NULL
);
13297 sArea
.left
= sArea
.right
;
13298 sArea
.right
= sButton
.right
;
13300 ExtTextOut(hDc
, sArea
.left
, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, _T("..."), 3, NULL
);
13302 ExtTextOut(hDc
, sArea
.left
+ 2, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, _T("..."), 3, NULL
);
13307 ExtTextOut(hDc
, sArea
.left
+ 2, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, pText
, uTextSize
, NULL
);
13311 i
= sArea
.left
- iXscroll
;
13312 i
+= pEntry
->iTextPixels
+ 5;
13316 if(uStyleEx
& TVS_EX_ITEMLINES
) { // Linien um den Eintrag zeichnen
13317 SetBkColor(hDc
, uFrColor
);
13319 if(iLast
> iStart
) { // Ist das Feld nach links eingerückt gegenüber dem oberen
13321 sArea
.bottom
= sArea
.top
+ 1;
13322 sArea
.left
= iStart
- 1;
13323 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13327 iLast
= iStart
; // Linie unter Feld zeichnen
13328 sArea
.top
+= iHeight
;
13329 sArea
.left
= iStart
;
13330 sArea
.bottom
= sArea
.top
+ 1;
13332 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13334 sArea
.top
-= iHeight
;
13337 //************ Extraeinträge zeichnen *********************************
13341 uNextColor
= uOutColor
; // Hintergrundfarbe für die nächste Spalte
13343 if(pData
->aColumn
[0].bMark
) { // Ist die erste Spalte markiert
13344 uBkColor
= pData
->uColors
[TVC_BK
];
13347 for(uColumn
= 1; uColumn
<= pData
->uColumnCount
; uColumn
++) { // Extra Spalten zeichnen
13348 uExtra
= pData
->aColumnPos
[uColumn
];
13349 uNext
= pData
->aColumnPos
[uColumn
+ 1];
13351 if(pData
->aColumn
[uExtra
].sReal
== 0) // Ist die Spalte sichtbar
13352 if(uColumn
< pData
->uColumnCount
) {
13356 if(uColMark
!= pData
->aColumn
[uExtra
].bMark
) // Ist die Spalte anderst markiert
13357 if(!(pEntry
->uState
& TVIS_SELECTED
) || !(uStyleEx
& TVS_EX_FULLROWMARK
)) {
13359 uColMark
= pData
->aColumn
[uExtra
].bMark
;
13360 uOutColor
= (uColMark
) ? uOcColor
: uOdColor
;
13362 uColMark
= pData
->aColumn
[uExtra
].bMark
;
13363 uOutColor
= (uColMark
) ? uEcColor
: uEvColor
;
13367 GetRgnBox(aRgn
[uExtra
], &sButton
);
13369 if(iRnType
[uExtra
] == NULLREGION
)
13372 SelectObject(hDc
, aRgn
[uExtra
]);
13374 sArea
.left
= pData
->aColumnXpos
[uExtra
];
13375 sArea
.left
+= iXscroll
;
13377 if(uStyleEx
& TVS_EX_ITEMLINES
) { // Linie um den Eintrag zeichnen
13378 SetBkColor(hDc
, uFrColor
);
13380 sArea
.right
= sArea
.left
+ 1;
13383 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13385 sArea
.left
+= 1; // Untere Linie
13386 sArea
.top
+= iHeight
;
13387 sArea
.bottom
= sArea
.top
+ 1;
13388 sArea
.right
= pData
->aColumnXpos
[uNext
];
13389 if(uColumn
< pData
->uColumnCount
)
13390 sArea
.right
+= iXscroll
;
13392 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13394 sArea
.top
-= iHeight
;
13399 if(sArea
.left
> (int)pData
->uSizeX
)
13400 break; // Noch im sichtbaren Bereich
13402 sArea
.right
= pData
->aColumnXpos
[uNext
];
13404 if(uColumn
< pData
->uColumnCount
) { // Ist es die letze Spalte ?
13405 sArea
.right
+= iXscroll
;
13406 pExtra
= pData
->pExtraItems
[uExtra
- 1][uItem
];
13408 uNextColor
= uOutColor
;
13413 if(!pExtra
) { // Leeres Feld zeichnen
13414 SetBkColor(hDc
, uNextColor
);
13415 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13417 iSize
= pData
->iSubImgXsize
;
13418 hImgList
= pData
->hSubImg
;
13419 iImage
= pExtra
->iImage
;
13420 pText
= pExtra
->pText
;
13421 uTextSize
= pExtra
->uTextSize
;
13422 uBits
= (pExtra
->uState
& 0xFFFF);
13423 uBits
|= (pExtra
->bFlags
<< 16);
13424 uBits
|= pEntry
->uState
& TVIS_BASEFLAGS
;
13427 if(uExtra
!= pData
->uSelectedSub
) {
13428 uBits
&= ~TVIS_SELECTED
;
13431 if(pExtra
->bCallback
) { // Text über Callback holen
13432 CallbackExtra(pData
, pEntry
, pExtra
, uItem
, uExtra
, pExtra
->bCallback
, &iImage
, &uTextSize
, &pText
);
13433 pExtra
= pData
->pExtraItems
[uExtra
- 1][uItem
];
13438 uNextColor
= (uBits
& TVIS_BKCOLOR
) ? pExtra
->uColorBk
: uOutColor
;
13439 SetBkColor(hDc
, uNextColor
);
13441 if(pData
->aColumn
[uExtra
].bEdit
>= TVAX_CHECK
) { // Checkboxen statt Icons
13442 hImgList
= pData
->hChecks
;
13443 iSize
= pData
->iChecksXsize
;
13444 iImage
= (pExtra
->uState
& TVIS_STATEIMAGEMASK
) >> 12;
13445 uBits
&= ~TVIS_OVERLAYMASK
;
13448 if(pData
->aColumn
[uExtra
].bFlags
& TVAE_STATEENABLE
) {
13453 if(hImgList
&& iImage
> TV_NOIMAGE
) { // Icon zeichnen
13454 sArea
.right
= sArea
.left
+ iSize
+ 2;
13455 iYpos
= sArea
.top
+ (iHeight
- iSize
) / 2;
13456 pExtra
->bFlags
|= TVIX_HASIMAGE
;
13458 SelectObject(hDc
, (uBits
& TVIS_BOLD
) ? pData
->hFontB
: pData
->hFontN
);
13459 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sArea
, NULL
, 0, NULL
);
13461 if(hImgList
== THEMEIMGLIST
) { // Mit Thema zeichnen
13462 if(pData
->uStyleEx
& TVS_EX_BITCHECKBOX
)
13465 if(iImage
== 1 || iImage
== 2) {
13466 uState
= (iImage
== 1) ? CBS_UNCHECKEDNORMAL
: CBS_CHECKEDNORMAL
;
13467 pDrawThemeBackg(pData
->hThemeBt
, hDc
, BP_CHECKBOX
, uState
, &sArea
, 0);
13470 ImageList_Draw(hImgList
, iImage
, hDc
, sArea
.left
+ 1, iYpos
, ILD_TRANSPARENT
| (uBits
& (TVIS_OVERLAYMASK
| LVIS_CUT
)));
13473 sArea
.left
+= iSize
+ 1;
13474 sArea
.right
= pData
->aColumnXpos
[uNext
];
13475 sArea
.right
+= iXscroll
;
13477 pExtra
->bFlags
&= ~TVIX_HASIMAGE
;
13480 iYpos
= sArea
.top
+ (iHeight
- pData
->iFontHeight
) / 2;
13481 SelectObject(hDc
, (uBits
& TVIS_BOLD
) ? pData
->hFontB
: pData
->hFontN
);
13483 if(uBits
& (TVIS_SELECTED
| TVIS_DROPHILITED
| TVIS_UNDERLINE
| TVIS_TRACKED
| TVIS_TEXTCOLOR
| TVIS_FOCUSED
)) {
13484 // Text ausgeben in spezilem Format
13485 TCHAR
*pPtr
= (TCHAR
*)new(TCHAR
, uTextSize
+ 4);
13486 INT
*pPos
= (INT
*)new(INT
, uTextSize
+ 4);
13488 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, NULL
, 0, NULL
);
13490 sButton
.top
= iYpos
;
13491 sButton
.left
= sArea
.left
+ 4;
13492 sButton
.right
= sArea
.right
;
13493 sButton
.bottom
= iYpos
+ pData
->iFontHeight
+ 2;
13497 sButton
.right
-= 2;
13499 pExtra
->iTextPixels
= 0;
13501 if(pData
->uStyleEx
& TVS_EX_FULLROWMARK
)
13502 if(pData
->cHasFocus
== 0 || uItem
!= pData
->uSelectedItem
)
13503 if((uBits
& TVIS_SELECTED
) && !(uBits
& (TVIS_DROPHILITED
| TVIS_FOCUSED
))) {
13507 DrawText(hDc
, pText
, uTextSize
, &sButton
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
| DT_CALCRECT
);
13508 pExtra
->iTextPixels
= sButton
.right
- sButton
.left
;
13511 // Passt der Text in die Spalte
13512 if(sButton
.left
+ pExtra
->iTextPixels
>= sArea
.right
) {
13513 if(uTextSize
> 253)
13516 iSize
= sArea
.right
- sButton
.left
- 2;
13517 iSize
-= (uBits
& TVIS_BOLD
) ? pData
->uTrippleB
: pData
->uTrippleN
;
13521 GetTextExtentExPoint(hDc
, pText
, uTextSize
, iSize
, &iCount
, pPos
, &sSize
);
13524 memcpy(pPtr
, pText
, iCount
* sizeof(TCHAR
));
13525 memcpy(pPtr
+ iCount
, _T("..."), 4 * sizeof(TCHAR
));
13528 uTextSize
= iCount
+ 3;
13529 sButton
.right
= sArea
.right
- 2;
13532 switch(pData
->aColumn
[uExtra
].bAlign
) { // Textausrichtung ausgleichen
13534 iDelta
= sArea
.right
- sArea
.left
;
13535 iDelta
-= sButton
.right
- sButton
.left
;
13538 sButton
.right
+= iDelta
;
13539 sButton
.left
+= iDelta
;
13543 iDelta
= sArea
.right
- sArea
.left
;
13544 iDelta
-= sButton
.right
- sButton
.left
;
13546 sButton
.right
+= iDelta
;
13547 sButton
.left
+= iDelta
;
13551 // Ist das Feld ohne Focus ausgewählt
13552 if((uBits
& TVIS_SELECTED
) && pData
->cHasFocus
&& uItem
== pData
->uSelectedItem
) {
13553 uTempColor
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
13554 SelectObject(hDc
, GetSysColorBrush(COLOR_HIGHLIGHT
));
13555 Rectangle(hDc
, sButton
.left
- 2, sButton
.top
- 1, sButton
.right
+ 2, sButton
.bottom
+ 1);
13557 if(uBits
& TVIS_DROPHILITED
) {
13558 uTempColor
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
13559 SelectObject(hDc
, GetSysColorBrush(COLOR_HIGHLIGHT
));
13560 SelectObject(hDc
, GetStockObject(NULL_PEN
));
13561 Rectangle(hDc
, sButton
.left
- 2, sButton
.top
- 1, sButton
.right
+ 2, sButton
.bottom
+ 1);
13563 if(uBits
& TVIS_SELECTED
&& uItem
== pData
->uSelectedItem
) {
13564 if(uBits
& TVIS_TEXTCOLOR
)
13565 uTempColor
= pEntry
->uColorText
;
13567 uTempColor
= pData
->uColors
[TVC_TEXT
];
13569 if(pData
->uStyleEx
& TVS_EX_FULLROWMARK
)
13570 SelectObject(hDc
, GetStockObject(NULL_BRUSH
));
13572 SelectObject(hDc
, GetSysColorBrush(COLOR_3DFACE
));
13574 SelectObject(hDc
, GetStockObject(NULL_PEN
));
13575 Rectangle(hDc
, sButton
.left
- 2, sButton
.top
- 1, sButton
.right
+ 2, sButton
.bottom
+ 1);
13577 if(uBits
& TVIS_TRACKED
)
13578 uTempColor
= pData
->uColors
[TVC_TRACK
];
13580 if(uBits
& TVIS_TEXTCOLOR
)
13581 uTempColor
= pExtra
->uColorText
;
13583 uTempColor
= pData
->uColors
[TVC_TEXT
];
13588 SelectObject(hDc
, hPatternPen
);
13590 if(uBits
& TVIS_FOCUSED
) { // Punktierten Rahmen um Text zeichnen
13591 SelectObject(hDc
, GetStockObject(NULL_BRUSH
));
13592 Rectangle(hDc
, sButton
.left
- 2, sButton
.top
- 1, sButton
.right
+ 2, sButton
.bottom
+ 1);
13596 SetTextColor(hDc
, uTempColor
);
13597 sButton
.left
+= pData
->iFontOff
;
13599 DrawText(hDc
, pText
, uTextSize
, &sButton
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
);
13601 if(uBits
& (TVIS_UNDERLINE
| TVIS_TRACKED
)) // Text unterstreichen
13602 if(pText
&& *pText
) {
13603 sButton
.left
-= pData
->iFontOff
;
13604 sButton
.right
-= pData
->iFontOff
+ 1;
13605 sButton
.top
+= pData
->iFontLine
;
13606 sButton
.bottom
= sButton
.top
+ 1;
13607 uOldColor
= SetBkColor(hDc
, uTempColor
);
13608 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
, &sButton
, NULL
, 0, NULL
);
13609 SetBkColor(hDc
, uOldColor
);
13612 SetTextColor(hDc
, pData
->uColors
[TVC_TEXT
]);
13616 } else { // Den Text ganz normal ausgeben
13617 if(!pExtra
->iTextPixels
) {
13618 sButton
.top
= iYpos
;
13619 sButton
.left
= sArea
.left
+ 4;
13620 sButton
.right
= sArea
.right
;
13621 sButton
.bottom
= iYpos
+ pData
->iFontHeight
+ 2;
13623 if(uTextSize
) { // Textbreite berechen
13624 DrawText(hDc
, pText
, uTextSize
, &sButton
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOPREFIX
| DT_CALCRECT
);
13625 pExtra
->iTextPixels
= sButton
.right
- sButton
.left
;
13627 pExtra
->iTextPixels
= 0;
13630 // Ist der Text größer als die Spalte
13631 if(sArea
.left
+ pExtra
->iTextPixels
>= sArea
.right
) {
13632 INT
*pPos
= (INT
*)new(INT
, uTextSize
);
13634 iSize
= sArea
.right
- sArea
.left
;
13635 iSize
-= (uBits
& TVIS_BOLD
) ? pData
->uTrippleB
: pData
->uTrippleN
;
13639 GetTextExtentExPoint(hDc
, pText
, uTextSize
, iSize
, &iCount
, pPos
, &sSize
);
13642 if(iCount
> 0) { // Passen noch Buchstaben vor "..."
13643 sButton
.right
= sArea
.right
;
13644 sArea
.right
= sArea
.left
+ 2 + pPos
[iCount
- 1];
13646 ExtTextOut(hDc
, sArea
.left
+ 2, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, pText
, iCount
, NULL
);
13648 sArea
.left
= sArea
.right
;
13649 sArea
.right
= sButton
.right
;
13651 ExtTextOut(hDc
, sArea
.left
, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, _T("..."), 3, NULL
);
13653 ExtTextOut(hDc
, sArea
.left
+ 2, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, _T("..."), 3, NULL
);
13658 switch(pData
->aColumn
[uExtra
].bAlign
) { // Textausrichtung
13660 SetTextAlign(hDc
, TA_CENTER
| TA_TOP
);
13661 ExtTextOut(hDc
, (sArea
.right
+ sArea
.left
) / 2, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, pText
, uTextSize
, NULL
);
13662 SetTextAlign(hDc
, TA_LEFT
| TA_TOP
);
13666 SetTextAlign(hDc
, TA_RIGHT
| TA_TOP
);
13667 ExtTextOut(hDc
, sArea
.right
- 2, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, pText
, uTextSize
, NULL
);
13668 SetTextAlign(hDc
, TA_LEFT
| TA_TOP
);
13673 ExtTextOut(hDc
, sArea
.left
+ 2, iYpos
, ETO_OPAQUE
| ETO_CLIPPED
, &sArea
, pText
, uTextSize
, NULL
);
13681 sArea
.top
+= pData
->iRowHeight
;
13684 if(sArea
.top
< sRect
.bottom
) { // Untere Fläche ohne Einträge füllen
13685 SelectObject(hDc
, hRgnMain
);
13687 // Gibt es markierte Spalten
13688 if(pData
->uMarkedCols
> 0 && (pData
->cIsEnabled
|| !(pData
->uStyleEx
& TVS_EX_GRAYEDDISABLE
))) {
13689 sRect
.right
= 0 - pData
->uScrollX
;
13691 for(uColumn
= 0; uColumn
< pData
->uColumnCount
; uColumn
++) {
13692 uExtra
= pData
->aColumnPos
[uColumn
];
13693 uNext
= pData
->aColumnPos
[uColumn
+ 1];
13694 uMark
= pData
->aColumn
[uExtra
].bMark
;
13695 sRect
.top
= sArea
.top
;
13696 sRect
.left
= sRect
.right
;
13697 sRect
.right
= pData
->aColumnXpos
[uNext
] + uMark
;
13698 sRect
.right
-= pData
->uScrollX
;
13699 if(sRect
.right
== sRect
.left
+ 1)
13701 SetBkColor(hDc
, (uMark
) ? pData
->uColors
[TVC_COLBK
] : uBkColor
);
13702 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sRect
, NULL
, 0, NULL
);
13705 sRect
.top
= sArea
.top
;
13706 sRect
.left
= sRect
.right
;
13707 sRect
.right
= pData
->uSizeX
;
13708 SetBkColor(hDc
, uBkColor
);
13709 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sRect
, NULL
, 0, NULL
);
13710 } else { // Keine markierten Spalten
13711 sRect
.top
= sArea
.top
;
13712 SetBkColor(hDc
, uBkColor
);
13713 ExtTextOut(hDc
, 0, 0, ETO_OPAQUE
, &sRect
, NULL
, 0, NULL
);
13717 if(pData
->iMaxSizeX
!= iMaxX
) { // X-Scrollbar aktuallisieren
13718 pData
->iMaxSizeX
= iMaxX
;
13719 if(pData
->uColumnCount
== 0)
13720 if(pData
->iMaxSizeX
!= (int)pData
->uOldXCount
) {
13721 UpdateScrollX(pData
);
13727 DeleteObject(hRgnMain
);
13729 for(uPos
= 0; uPos
< uRgnCount
; uPos
++) {
13730 DeleteObject(aRgn
[uPos
]);