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