https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2fdfb411b69932e765ed8…
commit 2fdfb411b69932e765ed8b64646cae76f3e3193f
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Sun Jan 28 22:10:51 2018 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Tue Nov 6 00:09:14 2018 +0100
[REACTOS] Add a TreeList control (TreeView with columns).
Add the TreeList control from Anton Zechner and Sébastien Kirche
from
https://github.com/sebkirche/treelist (under GPL-3.0+) as a
*TEMPORARY* solution until a better-suited control for ReactOS is
developed.
- Compilation fixes for the TreeList control.
---
base/setup/reactos/CMakeLists.txt | 1 +
base/setup/reactos/treelist.c | 13733 ++++++++++++++++++++++++++++++++++++
base/setup/reactos/treelist.h | 493 ++
3 files changed, 14227 insertions(+)
diff --git a/base/setup/reactos/CMakeLists.txt b/base/setup/reactos/CMakeLists.txt
index 39225e758e..8c58f9e360 100644
--- a/base/setup/reactos/CMakeLists.txt
+++ b/base/setup/reactos/CMakeLists.txt
@@ -11,6 +11,7 @@ list(APPEND SOURCE
spapisup/infsupp.c
drivepage.c
reactos.c
+ treelist.c
reactos.h)
file(GLOB reactos_rc_deps res/*.*)
diff --git a/base/setup/reactos/treelist.c b/base/setup/reactos/treelist.c
new file mode 100644
index 0000000000..1681b6189a
--- /dev/null
+++ b/base/setup/reactos/treelist.c
@@ -0,0 +1,13733 @@
+/*
+ * PROJECT: ReactOS GUI first stage setup application
+ * LICENSE: GPL-3.0-or-later (
https://spdx.org/licenses/GPL-3.0-or-later)
+ * PURPOSE: Implements a TreeList control: a tree window with columns.
+ * COPYRIGHT: Copyright (C) Anton Zechner (az_software(a)inode.at) 2007
+ * Copyright (C) S�bastien Kirche (sebastien.kirche(a)free.fr) 2014
+ *
+ * NOTE: Taken from the TreeList code found at
https://github.com/sebkirche/treelist
+ */
+
+//*****************************************************************************
+//*
+//*
+//* TreeListWnd.cpp
+//*
+//*
+//*****************************************************************************
+//
+// This code creates a tree window with a list
+//
+//
+// Copyright (C) Anton Zechner (az_software(a)inode.at) 2007
+// Copyright (C) S�bastien Kirche (sebastien.kirche(a)free.fr) 2014
+//
+// TreeListWnd is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+// Sourcecode which use TreeListWnd must be published. Commercial users
+// must published their code too, or make an licence agreement with me.
+//
+//
+// TreeListWnd wird unter GNU GENERAL PUBLIC LICENSE (GPL) vertreiben.
+// Sourcecode welcher TreeListWnd verwendet muss ver�ffendlicht werden.
+// Komerzielle Nutzer m�ssen ihren Code ebenfalls ver�ffentlichen, oder
+// eine Nutzungsvereinbarung mit mir treffen.
+//
+//
+// Version: 2.04
+//
+#ifdef UNICODE
+#ifndef _UNICODE
+#define _UNICODE
+#endif
+#endif
+
+#if 0
+ #include <stdio.h>
+ #include <windows.h>
+ #include <string.h>
+ #include <malloc.h>
+ #include <tchar.h>
+#else
+ #include "reactos.h"
+#endif
+
+#define new(TYPE, numElems) \
+ HeapAlloc(GetProcessHeap(), 0, (numElems) * sizeof(TYPE))
+#define delete(ptr) \
+ HeapFree(GetProcessHeap(), 0, (ptr))
+
+
+#include "treelist.h"
+
+#ifndef GWLP_USERDATA
+#define GWLP_USERDATA GWL_USERDATA
+#endif
+#ifndef GWLP_WNDPROC
+#define GWLP_WNDPROC GWL_WNDPROC
+#endif
+#ifndef _WIN64
+#ifndef SetWindowLongPtr
+#define SetWindowLongPtr SetWindowLong
+#endif
+#ifndef GetWindowLongPtr
+#define GetWindowLongPtr GetWindowLong
+#endif
+#ifndef DWORD_PTR
+#define DWORD_PTR DWORD
+#endif
+#ifndef LONG_PTR
+#define LONG_PTR LONG
+#endif
+#endif
+#ifdef UNICODE
+#define str_len (unsigned)wcslen
+#define str_cmp wcscmp
+#define str_ncpy wcsncpy
+#define str_ncmp wcsncmp
+#define str_icmp _wcsicmp
+#else
+#define str_len (unsigned)strlen
+#define str_cmp strcmp
+#define str_ncpy strncpy
+#define str_ncmp strncmp
+#define str_icmp _stricmp
+#endif
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x020A
+#endif
+#ifndef WHEEL_DELTA
+#define WHEEL_DELTA 120
+#endif
+#ifndef MAX_COLUMNS
+#define MAX_COLUMNS 32
+#endif
+#define MAX_COLORS 16
+#define EN_SETTEXT 0x1000
+#define EN_RETURN 0x1578
+#define EN_ESCAPE 0x1579
+#define ID_TOOLTIPCHECK 0x3912
+#define SORT_NOUPDATE 1234567
+#define VK_ISACHAR 0x01000000
+#define FIRST_LINE 0xFFFFFFFE
+#define FROM_HEADER 0x88776655
+#define I_CCB I_CHILDRENCALLBACK
+#define U(h) ((unsigned)(h))
+#define THEMEIMGLIST ((HIMAGELIST)1)
+#define GetHandle(h) ((TreeListData*)GetWindowLongPtr(h,0))
+#define
TVIF_ALL (TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_PARAM|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT)
+#define UNLOCK(d) ReleaseSemaphore(d->hSem,1,NULL)
+#define LOCK(d) WaitForSingleObject(d->hSem,INFINITE)
+#define
TVIS_EDIT(m) ((1<<m)&((1<<TVAX_EDIT)|(1<<TVAX_COMBO)|(1<<TVAX_STEPED)|(1<<TVAX_CHECKED)))
+#define
TVIS_BASEFLAGS (TVIS_EXPANDED|TVIS_EXPANDEDONCE|TVIS_EXPANDPARTIAL|TVIS_SELECTED)
+#define TVIS_TRACKED (TVIX_TRACKED<<16)
+#define TVIS_BKCOLOR (TVIX_BKCOLOR<<16)
+#undef TVIS_FOCUSED
+#define TVIS_FOCUSED (TVIX_FOCUSED<<16)
+#define TVIS_TEXTCOLOR (TVIX_TEXTCOLOR<<16)
+#define TVC_ONLYFOCUS TVIF_ONLYFOCUS
+#define TVC_UNSELECT 0x4000
+#define TVC_DESELECT 0x8000
+#define DEFAULT_IDENT 19
+#define DEFAULT_SHIFT 7
+#ifndef BPBF_COMPATIBLEBITMAP
+#define BPBF_COMPATIBLEBITMAP 0
+#endif
+#ifndef TVP_GLYPH
+#define TVP_GLYPH 2
+#endif
+#ifndef GLPS_CLOSED
+#define GLPS_CLOSED 1
+#endif
+#ifndef GLPS_OPENED
+#define GLPS_OPENED 2
+#endif
+#ifndef BP_CHECKBOX
+#define BP_CHECKBOX 3
+#endif
+#ifndef CBS_UNCHECKEDNORMAL
+#define CBS_UNCHECKEDNORMAL 1
+#endif
+#ifndef CBS_CHECKEDNORMAL
+#define CBS_CHECKEDNORMAL 5
+#endif
+
+
+#define TVAX_NONE (TVAE_NONE >>TVAE_MODEPOS)// No automatic edit
+#define TVAX_EDIT (TVAE_EDIT >>TVAE_MODEPOS)// automatic edit with edit
+#define TVAX_COMBO (TVAE_COMBO >>TVAE_MODEPOS)// automatic edit with ComboBox
+#define TVAX_CBLIST (TVAE_CBLIST >>TVAE_MODEPOS)// automatic edit with
ComboListBox
+#define TVAX_STEP (TVAE_STEP >>TVAE_MODEPOS)// Einzelnes Weiterschalten mit
Enter
+#define TVAX_STEPED (TVAE_STEPED >>TVAE_MODEPOS)// Einzelnes Weiterschalten mit
Enter und Edit
+#define TVAX_CHECK (TVAE_CHECK >>TVAE_MODEPOS)// automatic edit with CheckBox
+#define TVAX_CHECKED (TVAE_CHECKED>>TVAE_MODEPOS)// automatic edit with CheckBox
and Edit
+
+#define TVIX_VARBUTTON 0x01 // buttons are not permanent
+#define TVIX_HASBUTTON 0x02 // entry has button
+#define TVIX_HASIMAGE 0x04 // entry has icon
+#define TVIX_TRACKED 0x08 // entry under the cursor
+#define TVIX_TEXTCOLOR 0x10 // entry has its own text color
+#define TVIX_BKCOLOR 0x20 // entry has its own backround color
+#define TVIX_FOCUSED 0x40 // entry has the focus
+
+typedef struct {
+ LPARAM lParam; // LPARAM argument for the item
+ LPTSTR pText; // pointer to the item text
+ UINT uState; // item state
+ int iImage; // item image index
+ int iSelectedImage; // item selected image index
+ unsigned uShowPos; // Ist die Position in der Sichtbarliste (0=unsichtbar)
+ unsigned uFirstChild; // Ist die Nummer des ersten Kind-Eintrages (0=keines)
+ unsigned uLastChild; // Ist die Nummer des letzten Kind-Eintrages (0=keines)
+ unsigned uPrevItem; // Ist die Nummer des vorherigen Eintrages (0=keines)
+ unsigned uNextItem; // Ist die Nummer des n�chsten Eintrages (0=keines)
+ unsigned uParent; // Ist die Nummer des Elterneintrages (0=Root)
+ unsigned uLevel; // Ist die Ebene des Eintrages (0=Root)
+ int iTextPixels; // Ist die Breites des Textes in Pixel
+ WORD uTextSize; // L�nge des Textes in Zeichen
+ BYTE bCallback; // Sind Bits f�r Callbacks
+ BYTE bFlags; // Diverse Flags
+ COLORREF uColorText; // Spezielle Textfarbe
+ COLORREF uColorBk; // Spezielle Hintergrundfarbe
+} BaseItem;
+
+typedef struct {
+ LPTSTR pText; // Zeiger auf Tree-Text
+ UINT uState; // Zustand des Eintrages
+ int iImage; // Ist die Nummer des an zu zeigenden Icons
+ int iTextPixels; // Ist die Breites des Textes in Pixel
+ WORD uTextSize; // L�nge des Textes in Zeichen
+ BYTE bCallback; // Sind Bits f�r Callbacks
+ BYTE bFlags; // Diverse Flags
+ COLORREF uColorText; // Spezielle Textfarbe
+ COLORREF uColorBk; // Spezielle Hintergrundfarbe
+} ExtraItem;
+
+typedef struct {
+ void *pCbData; // Data for autoedit
+ INT iCbIcon; // Starting offset for in icon list for autoedit
+ short sSize; // width of the column
+ short sReal; // real width of the column
+ short sMin; // minimum width
+ short sFixed; // fixed width
+ BYTE bMinEx; // the width cannot be less than min width
+ BYTE bWeight; // weight for variable columns
+ BYTE bNext; // Ist die Spalte die nach der eigenen sichtbar ist (gespeicherte
Reihenfolge)
+ BYTE bIndex; // Ist die Spalte in der diese Reihe sichtbar ist (sichtbarer
Index)
+ BYTE bAlign; // Text alignment
+ BYTE bEdit; // Automaisches Editiern einer Spalte (siehe
TVAE_???>>7)
+ BYTE bFlags; // Automaisches Editiern einer Spalte (siehe TVAE_???)
+ BYTE bEnable; // Automaisches einer mit Statebits aktivieren
+ BYTE bCbSize; // Maximum number of entries in the data list
+ BYTE bCbChar; // separator for the data list
+ BYTE bMark; // is column marked ?
+ BYTE bDummy[32 - 23 - sizeof(void *)]; // padding bytes - 32 bytes alignment
+} ColumnData;
+
+typedef struct {
+ HWND hWnd; // handle of the control
+ HANDLE hSem; // access semaphore
+ LPVOID hTheme; // Handle f�r benutztes Thema (TREELIST)
+ LPVOID hThemeBt; // Handle f�r benutztes Thema (BUTTON)
+ WNDPROC pProcId3; // Fenster Funktion f�r ID3 Fenster
+ HIMAGELIST hStates; // Handle der Icon-Liste f�r States und Overlay
+ HIMAGELIST hImages; // Handle der Icon-Liste
+ HIMAGELIST hChecks; // Handle der Icon-Liste f�r die Checkboxen in den Spalten
+ HIMAGELIST hSubImg; // Handle der Icon-Liste f�r die Spalten
+ HIMAGELIST hHeadImg; // Handle for header images
+ HFONT hFontN; // Normal font
+ HFONT hFontB; // Bold fonts
+ HFONT hFontL; // Last used font
+ HFONT hFontT; // Tooltip font
+ HWND hEdit; // Handle des Edit-Fensters
+ HWND hHeader; // Handle des Header Fensters
+ HWND hToolTip; // Handle des Tooltip-Fensters
+ WNDPROC pToolProc; // Alte Fensterfunktion des Tooltips
+ COLORREF uColors[MAX_COLORS]; // 0=Hintergrundfarbe 1=Abwechselnte Farbe 2=Farbe
f�r Trennlinien 3=Textfarbe
+ int iFontHeight; // Ist die H�he des Fonts
+ int iFontLine; // Ist die Position der Linie beim unterstreichen
+ int iFontOff; // Ist die Position um der ein Text horizontal verschoben wird
+ int iStatesMode; // Die hStates Image-Liste wurde f�r die Checkboxen erzeugt
+ int iStatesXsize; // Breite der States und Overlay Icons
+ int iStatesYsize; // H�he der States und Overlay Icons
+ int iChecksMode; // Die hChecks Image-Liste wurde f�r die Checkboxen erzeugt
+ int iChecksXsize; // Breite der States und Overlay Icons
+ int iChecksYsize; // H�he der States und Overlay Icons
+ int iImagesXsize; // Breite der Icons
+ int iImagesYsize; // H�he der Icons
+ int iSubImgMode; // Die SubImg Image-Liste ist nicht die hImages Liste
+ int iSubImgXsize; // Breite der Icons
+ int iSubImgYsize; // H�he der Icons
+ int iRowHeight; // Ist die H�he einer Zeile
+ int iAllWeight; // Das Gewicht aller variablen Spalten
+ int iVarSize; // Ist die Breite aller variablen Spalten
+ int iFixSize; // Ist die Breite aller fixen Spalten
+ int iIndent; // Einr�ckung der Kindereint�ge
+ int iShift; // Einr�ckung der vertikalen Linien
+ int iAutoAdd; // Offset zum Open-Icon f�r TVS_EX_AUTOEXPANDICON
+ int iMaxSizeX; // Die Gr��e des breitesten sichtbaren Eintrages
+ unsigned uItemPosCount; // Anzahl der sichtbaren Eintr�ge
+ unsigned *pItemPos; // Liste mit den Offsets der sichtbaren Eintr�ge
+ BaseItem **pTreeItems; // Zeiger auf Item Zeiger
+ ExtraItem **pExtraItems[MAX_COLUMNS - 1]; // Zeiger auf die Spalteneintr�ge
+ unsigned uTreeItemsMax; // Gr��e der Liste mit den vorhanden Eintr�ge (alociert
um 1 gr��er)
+ unsigned uTreeItemsCount; // Anzahl der vorhanden Eintr�ge
+ unsigned uNextSeachPos; // N�chste Position zum suchen von freien Eintr�gen
+ unsigned uUserDataSize; // Ist die Gr��e der Userdaten in einem Eintrag
+ unsigned uFirstChild; // Ist die Nummer des ersten Kind-Eintrages (0=keines)
+ unsigned uLastChild; // Ist die Nummer des letzten Kind-Eintrages (0=keines)
+ unsigned uSingleSel; // Ist die Nummer des gew�hlten Eintrages (bei Checkboxen)
+ unsigned uScrollX; // Aktuelle X-Scroll-Position
+ unsigned uScrollY; // Aktuelle Y-Scroll-Position
+ unsigned uSizeX; // Aktuelle X-Fenster-Gr��e
+ unsigned uSizeY; // Aktuelle Y-Fenster-Gr��e
+ unsigned uSizeYsub; // Aktuelle Y-Fenster-Gr��e ohne Header
+ unsigned uStyle; // Ist der aktuele Style des Fensters
+ unsigned uStyleEx; // Erweiterte Sytle-Flags (siehe TVS_EX_???)
+ unsigned uStartPixel; // Ist die Y-Koordinate bei der der erste Eintrag beginnt
+ unsigned uMaxEnties; // Anzahl der sichtbaren Eintr�ge (inkl. halbsichtbare)
+ unsigned uPageEnties; // Anzahl der sichtbaren Eintr�ge (ohne halbsichtbare)
+ unsigned uColumnCount; // Anzahl der Spalten
+ unsigned uColumnCountVar; // Anzahl der variabeln Spalten
+ unsigned uSelectedCount; // Anzahl der ausgew�hlten Eintr�ge
+ unsigned uSelectedBase; // Ist der Eintrag ab dem gew�hlt wurde
+ unsigned uSelectedItem; // Ist der Eintrag der gerade gew�hlt ist
+ unsigned uSelectedSub; // Ist die Spalte die gerade gew�hlt ist
+ unsigned uFocusItem; // Ist der Eintrag der einen leeren Focus hat
+ unsigned uFocusSub; // Ist die Spalte die einen leeren Focus hat
+ unsigned uToolTipItem; // Ist der ToolTip-Eintrag der gerade gew�hlt ist
+ unsigned uToolTipShow; // Ist die Zeitverz�gerung in 500 ms Schritten f�r das
Tooltip
+ unsigned uToolTipSub; // Ist die ToolTip-Spalte die gerade gew�hlt ist
+ POINT sToolTipPos; // Ist die globale Koordinate des ToolTips
+ unsigned uEditMode; // Ist der Modus des Editfensters (0=Edit 1=ComboBox
2=ComboBox fix)
+ unsigned uEditItem; // Ist der Eintrag der gerade editiert wird
+ unsigned uEditSub; // Ist die Spalte die gerade editiert wird
+ unsigned uOldXPage; // Alte Werte f�r X-Scroll-Bar
+ unsigned uOldXCount; // *
+ unsigned uOldYPage; // Alte Werte f�r Y-Scroll-Bar
+ unsigned uOldYCount; // *
+ unsigned uTrippleB; // Bereite des "..." Strings f�r den fetten Fonts
+ unsigned uTrippleN; // Bereite des "..." Strings f�r den normalen
Fonts
+ unsigned uTrackedItem; // Ist der Eintrag der unterstrichen werden soll
+ unsigned uTrackedSub; // Ist die Spalte des Eintrages der unterstrichen werden
soll
+ unsigned uInsertMark; // Ist der Eintrag mit der Einf�gemarke
+ unsigned uMarkedCols; // Anzahl der markierten Spalten
+ unsigned uDragFlags; // Welche Maustasten sind an
+ unsigned uDragItem; // Eintrag f�r Dragoperation
+ unsigned uDragSub; // Untereintrag f�r Dragoperation
+ unsigned uLastSel; // Letzte Textauswahl beim Editieren
+ unsigned uLastMove; // Letzte Cursorposition bei WM_MOUSEMOVE
+ unsigned uButtonPos; // Wo wurde eine Maustaste wurde zuletzt gedr�ckt
+ unsigned uButtonLast; // Wann wurde eine Maustaste wurde zuletzt gedr�ckt
+ unsigned uToolTipSize; // Textspeichergr��e f�r Tooltip
+ LPTSTR pToolTipText; // Textspeicher f�r Tooltip
+ TCHAR cTempText1 [260]; // Erster Textpuffer f�r Callbacks
+ TCHAR cTempText2 [260]; // Zeiter Textpuffer f�r Callbacks
+ ColumnData aColumn [MAX_COLUMNS]; // Daten der Spalten
+ int aColumnXpos [MAX_COLUMNS + 2]; // Array mit den Positionen der Spalten
+ BYTE aColumnPos [MAX_COLUMNS + 2]; // Array mit Anzeigepositionen der Spalten
+ char cColorChanged[MAX_COLORS ]; // Welche Farbe wurden ver�ndert
+ char cColumnStart; // Wurde das Autoeditiren mit einer WM_CHAR Eingabe
gestartet
+ char cFixedHeight; // Ist eine fixe H�he eingestellt
+ char cLockChanges; // Sperren von Fenster�nderungen
+ char cHasRootRow; // Wird gesetzt wenn eine Root-Spalte eingef�gt wird
+ char cKeyIgnore; // Die n�chste Taste nicht f�r Sucher verwenden
+ char cClickFlag; // Merker f�r LBUTTON-DOWN bei Multiselect
+ char cClickEdit; // Merker f�r LBUTTON-DOWN bei Edit-Click
+ char cIsEnabled; // Ist das Fenster freigegeben
+ char cHasFocus; // Hat das Fenster den Focus
+ char cReSelect; // Soll die Auswahl neu selektiert werden
+ char cGlyphOk; // Die Schaltf�che �ber Themen zeichnen
+ char cEditCb; // Muss das Edit-Fenster einen Callback aufrufen
+ char cButtonFlag; // Welche Maustaste wurde zuletzt gedr�ckt
+} TreeListData;
+
+typedef HRESULT(WINAPI *SetWindowThemeT)(HWND, LPCWSTR, LPCWSTR);
+typedef HRESULT(WINAPI *EndBufferedPtT)(HANDLE, BOOL);
+typedef HANDLE(WINAPI *BeginBufferedPnT)(HDC, RECT *, DWORD, LPVOID, HDC *);
+typedef HRESULT(WINAPI *BufferedPtInitT)(VOID);
+typedef HRESULT(WINAPI *BufferedPtInitT)(VOID);
+typedef LPVOID (WINAPI *OpenThemeDataT)(HWND hwnd, LPCWSTR pszClassList);
+typedef HRESULT(WINAPI *CloseThemeDataT)(LPVOID);
+typedef HRESULT(WINAPI *DrawThemeBackgT)(LPVOID, HDC, int, int, const RECT *, const RECT
*);
+typedef HRESULT(WINAPI *GetThemeBackgRcT)(LPVOID, HDC, int, int, LPCRECT, LPRECT);
+typedef BOOL (WINAPI *IsAppThemedT)();
+typedef BOOL (WINAPI *IsThemeActiveT)();
+
+static HMODULE hUxThemeDll = NULL;
+static SetWindowThemeT pSetWindowTheme = NULL;
+static EndBufferedPtT pEndBufferedPt = NULL;
+static BeginBufferedPnT pBeginBufferedPt = NULL;
+static BufferedPtInitT pBufferedPtInit = NULL;
+static BufferedPtInitT pBufferedPtExit = NULL;
+static OpenThemeDataT pOpenThemeData = NULL;
+static CloseThemeDataT pCloseThemeData = NULL;
+static DrawThemeBackgT pDrawThemeBackg = NULL;
+static GetThemeBackgRcT pGetThemeBackgRc = NULL;
+static IsAppThemedT pIsAppThemed = NULL;
+static IsThemeActiveT pIsThemeActive = NULL;
+static HPEN hPatternPen = NULL;
+static HFONT hDefaultFontN = NULL;
+static HFONT hDefaultFontB = NULL;
+static LONG lWindowCount = -1;
+#ifndef __REACTOS__
+static RECT sToolRect = { -2, 0, 2, 64};
+#endif
+static TCHAR cKeyData[16];
+static unsigned uKeyLast;
+static unsigned uKeyPos;
+static void TreeListDraw(HWND hWnd, HDC hDc, RECT *pRect);
+static LRESULT CALLBACK TreeListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
lParam);
+static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem,
int iMode);
+static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags,
RECT *pRect);
+static int TreeListStartNotifyEdit(TreeListData *pData, unsigned uItem, unsigned uSub,
WPARAM wParam, LPARAM lParam);
+static int TreeListStartAutoEdit(TreeListData *pData, unsigned uColumn, WPARAM wParam,
LPARAM lParam);
+static int TreeListEndLabelEdit(TreeListData *pData, int iMode);
+static BOOL bDrawWithTheme = FALSE;
+
+//*****************************************************************************
+//*
+//* TreeListRegister
+//*
+//*****************************************************************************
+// Registiert das TreeList Fenster.
+// Ergibt 1 wenn das Fenster erfolgreich registiert wurde.
+int TreeListRegister(HINSTANCE hInstance) {
+
+ static int iIsRegistered = FALSE;
+ WNDCLASSEX sClass;
+
+ OutputDebugString(TEXT("TreeListRegister() - before checking\n"));
+
+ if(iIsRegistered)
+ return TRUE;
+
+ OutputDebugString(TEXT("TreeListRegister() - before registration\n"));
+
+ memset(&sClass, 0, sizeof(sClass));
+ sClass.cbSize = sizeof(sClass);
+ sClass.style = CS_DBLCLKS | CS_GLOBALCLASS;
+ sClass.lpfnWndProc = TreeListProc;
+ sClass.cbClsExtra = 0;
+ sClass.cbWndExtra = sizeof(TreeListData *);
+ sClass.hInstance = hInstance;
+ sClass.hIcon = NULL;
+ sClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ sClass.hbrBackground = NULL;
+ sClass.lpszMenuName = NULL;
+ sClass.hIconSm = NULL;
+ sClass.lpszClassName = _T(TVC_CLASSNAME);
+
+ if(!RegisterClassEx(&sClass))
+ return 0;
+
+ OutputDebugString(TEXT("TreeListRegister() - registration done\n"));
+ iIsRegistered = TRUE;
+
+ return TRUE;
+}
+
+BOOL TreeListUnregister(HINSTANCE hInstance){
+ return UnregisterClass(_T(TVC_CLASSNAME),hInstance);
+}
+
+//*****************************************************************************
+//*
+//* GlobalInit
+//*
+//*****************************************************************************
+static void GlobalInit() {
+
+ LOGBRUSH sLog;
+ long lCount;
+
+
+
+ lCount = InterlockedIncrement(&lWindowCount);
+ if(lCount > 0)
+ return;
+
+ sLog.lbColor = GetSysColor(COLOR_BTNSHADOW);
+ sLog.lbStyle = PS_SOLID;
+ sLog.lbHatch = 0;
+ hPatternPen = ExtCreatePen(PS_COSMETIC | PS_ALTERNATE, 1, &sLog, 0, NULL);
+
+ if(!hPatternPen) {
+ hPatternPen = CreatePen(PS_DOT, 1, RGB(0, 0, 0));
+ }
+
+
+ if(!hUxThemeDll) {
+ hUxThemeDll = LoadLibrary(_T("UxTheme.dll"));
+ if(hUxThemeDll) {
+ pSetWindowTheme = (SetWindowThemeT)GetProcAddress(hUxThemeDll,
"SetWindowTheme");
+ pEndBufferedPt = (EndBufferedPtT)GetProcAddress(hUxThemeDll,
"EndBufferedPaint");
+ pBeginBufferedPt = (BeginBufferedPnT)GetProcAddress(hUxThemeDll,
"BeginBufferedPaint");
+ pBufferedPtInit = (BufferedPtInitT)GetProcAddress(hUxThemeDll,
"BufferedPaintInit");
+ pBufferedPtExit = (BufferedPtInitT)GetProcAddress(hUxThemeDll,
"BufferedPaintUnInit");
+ pOpenThemeData = (OpenThemeDataT)GetProcAddress(hUxThemeDll,
"OpenThemeData");
+ pCloseThemeData = (CloseThemeDataT)GetProcAddress(hUxThemeDll,
"CloseThemeData");
+ pDrawThemeBackg = (DrawThemeBackgT)GetProcAddress(hUxThemeDll,
"DrawThemeBackground");
+ pGetThemeBackgRc = (GetThemeBackgRcT)GetProcAddress(hUxThemeDll,
"GetThemeBackgroundContentRect");
+ pIsAppThemed = (IsAppThemedT)GetProcAddress(hUxThemeDll,
"IsAppThemed");
+ pIsThemeActive = (IsThemeActiveT)GetProcAddress(hUxThemeDll,
"IsThemeActive");
+
+ if(pIsAppThemed && pIsThemeActive)
+ bDrawWithTheme = pIsAppThemed() && pIsThemeActive();
+ }
+ }
+
+ if(pBufferedPtInit) {
+ pBufferedPtInit();
+ }
+
+}
+
+
+//*****************************************************************************
+//*
+//* GlobalDeinit
+//*
+//*****************************************************************************
+static void GlobalDeinit() {
+
+ int lCount;
+
+ lCount = InterlockedDecrement(&lWindowCount);
+ if(lCount >= 0)
+ return;
+
+ if(hDefaultFontN) {
+ DeleteObject(hDefaultFontN);
+ hDefaultFontN = NULL;
+ }
+
+ if(hDefaultFontB) {
+ DeleteObject(hDefaultFontB);
+ hDefaultFontB = NULL;
+ }
+
+ if(hPatternPen) {
+ DeleteObject(hPatternPen);
+ hPatternPen = NULL;
+ }
+
+ if(pBufferedPtExit) {
+ pBufferedPtExit();
+ }
+
+}
+
+
+//*****************************************************************************
+//*
+//* SendNotify
+//*
+//*****************************************************************************
+// Sendet eine WM_NOTIFY Nachricht and das Elternfenster
+// pData : Zeiger auf die Fensterdaten
+// pNotify : Zeiger auf die Notify-Daten
+// Ergibt den R�ckgabewert der WM_NOTIFY Nachrich
+static LRESULT SendNotify(TreeListData *pData, NMHDR *pNotify) {
+
+ pNotify->hwndFrom = pData->hWnd;
+ pNotify->idFrom = GetWindowLong(pNotify->hwndFrom, GWL_ID);
+
+ return SendMessage(GetParent(pNotify->hwndFrom), WM_NOTIFY, pNotify->idFrom,
(LPARAM)pNotify);
+}
+
+
+//*****************************************************************************
+//*
+//* CallbackEntry
+//*
+//*****************************************************************************
+// Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen
+// pData : Zeiger auf die Fensterdaten
+// pEntry : Zeiger auf den Eintrag
+// uItem : Nummer des Eintrages
+// uFlags : Welche Daten sollen abgefragt werden
+// Ergibt den R�ckgabewert der WM_NOTIFY Nachrich
+static void CallbackEntry(TreeListData *pData, BaseItem *pEntry, unsigned uItem, unsigned
uFlags, int *iImage, unsigned *uTextSize, LPCTSTR *pText) {
+
+ NMTVDISPINFO sInfo;
+
+ sInfo.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | uFlags;
+ sInfo.item.lParam = pEntry->lParam;
+ sInfo.item.hItem = (HTREEITEM)uItem;
+ sInfo.item.state = pEntry->uState;
+ sInfo.item.stateMask = 0xFFFFFFFF;
+ sInfo.item.iImage = I_IMAGECALLBACK;
+ sInfo.item.iSelectedImage = I_IMAGECALLBACK;
+ sInfo.item.cChildren = I_CHILDRENCALLBACK;
+
+ if(uFlags & TVIF_TEXT) {
+ if(*uTextSize) {
+ pData->cTempText2[sizeof(pData->cTempText2) / sizeof(TCHAR) - 1] = 0;
+ pData->cTempText2[0] = 0;
+ sInfo.item.pszText = pData->cTempText2;
+ sInfo.item.cchTextMax = sizeof(pData->cTempText2) / sizeof(TCHAR) - 1;
+ } else {
+ pData->cTempText1[sizeof(pData->cTempText1) / sizeof(TCHAR) - 1] = 0;
+ pData->cTempText1[0] = 0;
+ sInfo.item.pszText = pData->cTempText1;
+ sInfo.item.cchTextMax = sizeof(pData->cTempText1) / sizeof(TCHAR) - 1;
+ }
+ } else {
+ sInfo.item.pszText = 0;
+ sInfo.item.cchTextMax = 0;
+ }
+
+ sInfo.hdr.hwndFrom = pData->hWnd;
+ sInfo.hdr.idFrom = GetWindowLong(pData->hWnd, GWL_ID);
+ sInfo.hdr.code = TVN_GETDISPINFO;
+
+ UNLOCK(pData);
+ SendMessage(GetParent(sInfo.hdr.hwndFrom), WM_NOTIFY, sInfo.hdr.idFrom,
(LPARAM)&sInfo);
+ LOCK(pData);
+
+ if(uFlags & TVIF_IMAGE) {
+ if(!(pEntry->uState & TVIS_SELECTED))
+ *iImage = sInfo.item.iImage;
+ } else
+ if(uFlags & TVIF_SELECTEDIMAGE) {
+ if(pEntry->uState & TVIS_SELECTED)
+ *iImage = sInfo.item.iSelectedImage;
+ }
+
+ if(uFlags & TVIF_CHILDREN) {
+ switch(sInfo.item.cChildren) {
+ case 0:
+ pEntry->bFlags &= ~TVIX_HASBUTTON;
+ pEntry->bFlags |= TVIX_VARBUTTON;
+ break;
+
+ case 1:
+ pEntry->bFlags &= ~TVIX_VARBUTTON;
+ pEntry->bFlags |= TVIX_HASBUTTON;
+ break;
+
+ default
+ :
+ pEntry->bFlags |= TVIX_VARBUTTON;
+
+ if(pEntry->uFirstChild)
+ pEntry->bFlags |= TVIX_HASBUTTON;
+ else
+ pEntry->bFlags &= ~TVIX_HASBUTTON;
+ }
+ }
+
+ if(uFlags & TVIF_TEXT) {
+ *pText = sInfo.item.pszText;
+ *uTextSize = str_len(sInfo.item.pszText);
+ pEntry->iTextPixels = 0;
+ }
+
+}
+
+//*****************************************************************************
+//*
+//* CallbackExtra
+//*
+//*****************************************************************************
+// Sendet eine WM_NOTIFY Nachricht and das Elternfenster um Daten zuholen
+// pData : Zeiger auf die Fensterdaten
+// pEntry : Zeiger auf den Eintrag
+// uItem : Nummer des Eintrages
+// uFlags : Welche Daten sollen abgefragt werden
+// Ergibt den R�ckgabewert der WM_NOTIFY Nachrich
+static void CallbackExtra(TreeListData *pData, BaseItem *pEntry, ExtraItem *pExtra,
unsigned uItem, unsigned uSub, unsigned uFlags, int *iImage, unsigned *uTextSize, LPCTSTR
*pText) {
+
+ NMTVDISPINFO sInfo;
+
+ sInfo.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM | uFlags;
+ sInfo.item.lParam = pEntry->lParam;
+ sInfo.item.hItem = (HTREEITEM)uItem;
+ sInfo.item.state = pExtra->uState;
+ sInfo.item.state |= (pEntry->uState & TVIS_BASEFLAGS);
+ sInfo.item.stateMask = 0xFFFFFFFF;
+ sInfo.item.iImage = I_IMAGECALLBACK;
+ sInfo.item.iSelectedImage = I_IMAGECALLBACK;
+ sInfo.item.cChildren = uSub;
+
+ if(uFlags & TVIF_TEXT) {
+ pData->cTempText1[sizeof(pData->cTempText1) / sizeof(TCHAR) - 1] = 0;
+ pData->cTempText1[0] = 0;
+ sInfo.item.pszText = pData->cTempText1;
+ sInfo.item.cchTextMax = sizeof(pData->cTempText1) / sizeof(TCHAR) - 1;
+ } else {
+ sInfo.item.pszText = 0;
+ sInfo.item.cchTextMax = 0;
+ }
+
+ sInfo.hdr.hwndFrom = pData->hWnd;
+ sInfo.hdr.idFrom = GetWindowLong(pData->hWnd, GWL_ID);
+ sInfo.hdr.code = TVN_GETDISPINFO;
+
+ UNLOCK(pData);
+ SendMessage(GetParent(sInfo.hdr.hwndFrom), WM_NOTIFY, sInfo.hdr.idFrom,
(LPARAM)&sInfo);
+ LOCK(pData);
+
+
+ if(uFlags & TVIF_IMAGE)
+ *iImage = sInfo.item.iImage;
+ if(uFlags & TVIF_TEXT) {
+ *pText = sInfo.item.pszText;
+ *uTextSize = str_len(sInfo.item.pszText);
+ }
+
+}
+
+//*****************************************************************************
+//*
+//* EditProc
+//*
+//*****************************************************************************
+// Ist die Fensterfunktion f�r das Edit Fenster
+static LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+
+ TreeListData *pData;
+ WNDPROC pProc;
+ DWORD dwStop;
+ DWORD dwStart;
+ DWORD dwCount;
+ LRESULT lResult;
+ HWND hParent;
+ HWND hCombo;
+ int iDelta;
+ int iState;
+ int iPos;
+ int iId;
+
+
+ hParent = GetParent(hWnd);
+ iId = GetWindowLong(hWnd, GWL_ID);
+
+ if(iId == 3) {
+ hCombo = hWnd;
+ pData = GetHandle(hParent);
+ pProc = pData->pProcId3;
+ } else {
+ hCombo = hParent;
+ hParent = GetParent(hParent);
+ pData = GetHandle(hParent);
+ pProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ }
+
+ if(uMsg == WM_KEYDOWN) {
+ if(wParam == VK_RETURN) {
+ SendMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
+ return 0;
+ }
+
+ if(wParam == VK_ESCAPE) {
+ SendMessage(hParent, WM_COMMAND, MAKELONG(3, EN_ESCAPE), (LPARAM)hWnd);
+ return 0;
+ }
+
+ if((pData->uStyleEx & TVS_EX_STEPOUT) && !(GetAsyncKeyState(VK_SHIFT)
& 0x8000)) {
+ switch(wParam) { // Aus Fenster springen
+
+ case VK_UP:
+ if(pData->uEditMode)
+ break;
+ PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
+ PostMessage(hParent, WM_KEYDOWN, VK_UP , 0x00500001);
+ PostMessage(hParent, WM_KEYUP , VK_UP , 0x00500001);
+ return 0;
+
+ case VK_DOWN:
+ if(pData->uEditMode)
+ break;
+ PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
+ PostMessage(hParent, WM_KEYDOWN, VK_DOWN, 0x00500001);
+ PostMessage(hParent, WM_KEYUP , VK_DOWN, 0x00500001);
+ return 0;
+
+ case VK_LEFT:
+ if(pData->uEditMode && iId == 3)
+ break;
+ SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwStop);
+ if(dwStart || dwStop)
+ break;
+ PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
+ PostMessage(hParent, WM_KEYDOWN, VK_LEFT, 0x00500001);
+ PostMessage(hParent, WM_KEYUP , VK_LEFT, 0x00500001);
+ return 0;
+
+ case VK_RIGHT:
+ if(pData->uEditMode && iId == 3)
+ break;
+ SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwStop);
+ dwCount = (DWORD)SendMessage(hWnd, EM_LINELENGTH, 0, 0);
+ if(dwCount > dwStart)
+ break;
+ if(dwCount > dwStop)
+ break;
+
+ PostMessage(hParent, WM_COMMAND, MAKELONG(3, EN_RETURN), (LPARAM)hWnd);
+ PostMessage(hParent, WM_KEYDOWN, VK_RIGHT, 0x00500001);
+ PostMessage(hParent, WM_KEYUP , VK_RIGHT, 0x00500001);
+ return 0;
+ }
+ }
+
+ if(wParam == VK_DOWN && pData->uEditMode) {
+ if(!SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0)) {
+ SendMessage(hCombo, CB_SHOWDROPDOWN, 1, 0);
+ return 0;
+ }
+ }
+ } else
+ if(uMsg == WM_CHAR) {
+ if(wParam == VK_RETURN) {
+ return 0;
+ }
+
+ if(wParam == VK_ESCAPE) {
+ return 0;
+ }
+ } else
+ if(uMsg == WM_COMMAND) {
+ if(wParam == MAKELONG(3, EN_ESCAPE) || wParam == MAKELONG(3, EN_RETURN)) {
+ SendMessage(hParent, WM_COMMAND, wParam, (LPARAM)hWnd);
+ return 0;
+ }
+ } else
+ if(uMsg == WM_MOUSEWHEEL) {
+ iState = (int)CallWindowProc(pProc, hWnd, CB_GETDROPPEDSTATE, 0, 0);
+ if(iState) {
+ iDelta = (short)HIWORD(wParam);
+ iDelta /= WHEEL_DELTA;
+ iPos = (int)CallWindowProc(pProc, hWnd, CB_GETTOPINDEX, 0, 0);
+ iPos -= iDelta;
+ CallWindowProc(pProc, hWnd, CB_SETTOPINDEX, iPos, 0);
+ return 0;
+ }
+ } else
+ if(uMsg == WM_GETDLGCODE) { // Welche Tasten werden im Dialog benutzt
+ return DLGC_WANTALLKEYS;
+ } else
+ if(uMsg == WM_SETTEXT) {
+ lResult = CallWindowProc(pProc, hWnd, uMsg, wParam, lParam);;
+ SendMessage(hParent, WM_COMMAND, MAKELONG(3, EN_SETTEXT), (LPARAM)hWnd);
+ return lResult;
+ }
+
+ return CallWindowProc(pProc, hWnd, uMsg, wParam, lParam);
+}
+
+//*****************************************************************************
+//*
+//* ToolProc
+//*
+//*****************************************************************************
+// Ist die Fensterfunktion f�r das ToolTip Fenster
+static LRESULT CALLBACK ToolProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+
+ TreeListData *pData;
+ POINT sPoint;
+ UINT uPos;
+
+ if(uMsg == WM_SETFOCUS) {
+ SetFocus((HWND)lParam);
+ return 0;
+ }
+
+ pData = (TreeListData *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+
+ if(uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) { // Mausklicks auf
Tooltip zum Elternfenster
+ sPoint.x = LOWORD(lParam);
+ sPoint.y = HIWORD(lParam);
+
+ ClientToScreen(hWnd , &sPoint);
+ ScreenToClient(pData->hWnd, &sPoint);
+
+ uPos = MAKELONG(sPoint.x, sPoint.y);
+
+ return TreeListProc(pData->hWnd, uMsg, wParam, uPos);
+ }
+
+ return CallWindowProc(pData->pToolProc, hWnd, uMsg, wParam, lParam);
+}
+
+//*****************************************************************************
+//*
+//* ChangeColSize
+//*
+//*****************************************************************************
+// �ndert die Gr��e der variablen Spalten
+// pData : Zeiger auf die Fensterdaten
+// iDelta : Ist die Gr��en�nderung in Pixel
+static void ChangeColSize(TreeListData *pData, int iDelta) {
+
+ unsigned uPos;
+ HDITEM sItem;
+ RECT sRect;
+ TV_COLSIZE sNotify;
+ int iWeight;
+ int iValue;
+ int iPoint;
+ int iStart;
+ int iSize;
+ int iRest;
+ int iOff;
+ int iNum;
+ int iCnt;
+ int iAll;
+ int iVar;
+ int iFix;
+
+ sItem.mask = HDI_WIDTH;
+ iAll = pData->iAllWeight;
+ iCnt = pData->uColumnCountVar;
+
+ if(iCnt <= 1) { // Nur eine variable Spalte
+ for(uPos = 0; uPos < pData->uColumnCount; uPos++) {
+ iWeight = pData->aColumn[uPos].bWeight;
+ if(!iWeight)
+ continue;
+
+ iValue = pData->aColumn[uPos].sSize;
+ iValue += iDelta;
+ sItem.cxy = iValue;
+
+ pData->aColumn[uPos].sSize = (short)iValue;
+ pData->iVarSize = iValue;
+
+ if(sItem.cxy < pData->aColumn[uPos].sMin) {
+ sItem.cxy = pData->aColumn[uPos].sMin;
+ }
+
+ if(pData->aColumn[uPos].sReal != sItem.cxy) { // �ndert sich die Breite
+ pData->aColumn[uPos].sReal = (short)sItem.cxy;
+ Header_SetItem(pData->hHeader, uPos, &sItem);
+
+ if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) {
+ sNotify.hdr.code = TVN_COLUMNCHANGED;
+ sNotify.uColumn = uPos;
+ sNotify.uIndex = pData->aColumn[uPos].bIndex;
+ sNotify.uPosX = pData->aColumnXpos[uPos];
+ sNotify.iSize = sItem.cxy;
+
+ UNLOCK(pData);
+ SendNotify(pData, &sNotify.hdr);
+ LOCK(pData);
+ }
+ }
+
+ break;
+ }
+
+ return;
+ }
+
+ if(iDelta > 0)
+ iStart = (pData->uSizeX) % iAll;
+ else
+ iStart = (pData->uSizeX - iDelta) % iAll;
+
+ iOff = 0;
+
+ for(uPos = 0;; uPos++) { // Suchen die Anfangsspalte
+ iWeight = pData->aColumn[uPos].bWeight;
+ if(!iWeight)
+ continue;
+
+ iOff += iWeight;
+ if(iOff > iStart)
+ break;
+ }
+
+
+ iPoint = 0;
+ iSize = iDelta / iAll;
+ iRest = iDelta % iAll;
+ iNum = iRest;
+ iOff -= iStart;
+
+ iWeight = iOff;
+ iValue = pData->aColumn[uPos].sSize;
+ iValue += iSize * iWeight;
+ iPoint += iRest * iWeight;
+ iValue += iPoint / iAll;
+ iNum -= iPoint / iAll;
+ iPoint %= iAll;
+
+ pData->aColumn[uPos].sSize = (short)iValue;
+
+
+ if(iWeight >= pData->aColumn[uPos].bWeight) { // Wurde die ganze Spalte
berechnet
+ iCnt--;
+ iOff = 0;
+ }
+
+ while(iCnt > 0) {
+ uPos++;
+
+ if(uPos >= pData->uColumnCount)
+ uPos = 0;
+ iWeight = pData->aColumn[uPos].bWeight;
+ if(!iWeight)
+ continue;
+
+ iValue = pData->aColumn[uPos].sSize;
+
+ iCnt--;
+ if(iCnt) {
+ iValue += iSize * iWeight;
+ iPoint += iRest * iWeight;
+ iValue += iPoint / iAll;
+ iNum -= iPoint / iAll;
+ iPoint %= iAll;
+ } else {
+ iWeight -= iOff;
+ iValue += iSize * iWeight;
+ iValue += iNum;
+ }
+
+ pData->aColumn[uPos].sSize = (short)iValue;
+ }
+
+ iVar = 0;
+ iFix = 0;
+ iCnt = pData->uColumnCountVar;
+
+ for(uPos = 0; iCnt > 0; uPos++) { // Ausgeben der neuen Breiten
+ iWeight = pData->aColumn[uPos].bWeight;
+ if(!iWeight) {
+ iFix += pData->aColumn[uPos].sSize;
+ continue;
+ }
+
+ iVar += pData->aColumn[uPos].sSize;
+ sItem.cxy = pData->aColumn[uPos].sSize;
+
+ if(sItem.cxy < pData->aColumn[uPos].sMin) {
+ sItem.cxy = pData->aColumn[uPos].sMin;
+ }
+
+ if(pData->aColumn[uPos].sReal != sItem.cxy) { // �ndert sich die Breite
+ pData->aColumn[uPos].sReal = (short)sItem.cxy;
+ Header_SetItem(pData->hHeader, uPos, &sItem);
+
+ if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) {
+ sNotify.hdr.code = TVN_COLUMNCHANGED;
+ sNotify.uColumn = uPos;
+ sNotify.uIndex = pData->aColumn[uPos].bIndex;
+ sNotify.uPosX = pData->aColumnXpos[uPos];
+ sNotify.iSize = sItem.cxy;
+
+ UNLOCK(pData);
+ SendNotify(pData, &sNotify.hdr);
+ LOCK(pData);
+ }
+ }
+
+ iCnt--;
+ }
+
+ pData->iFixSize = iFix;
+ pData->iVarSize = iVar;
+
+ if(iDelta > 0) {
+ GetClientRect(pData->hHeader, &sRect);
+ InvalidateRect(pData->hHeader, NULL, FALSE);
+ }
+
+}
+
+//*****************************************************************************
+//*
+//* CreateToolTip
+//*
+//*****************************************************************************
+// Erzeugt ein ToolTip Fenster
+// pData : Zeiger auf die Fensterdaten
+static void CreateToolTip(TreeListData *pData) {
+
+ TOOLINFO sInfo;
+
+ if(pData->hToolTip)
+ return;
+
+ pData->hToolTip = CreateWindow(TOOLTIPS_CLASS, NULL, WS_POPUP, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, pData->hWnd, NULL, NULL, NULL);
+ pData->pToolProc = (WNDPROC)GetWindowLongPtr(pData->hToolTip, GWLP_WNDPROC);
+
+ sInfo.cbSize = sizeof(TOOLINFO);
+ sInfo.uFlags = TTF_ABSOLUTE | TTF_TRACK | TTF_IDISHWND;
+ sInfo.hwnd = pData->hWnd;
+ sInfo.hinst = NULL;
+ sInfo.uId = (LPARAM)(pData->hWnd);
+ sInfo.lpszText = LPSTR_TEXTCALLBACK;
+
+ GetClientRect(pData->hWnd, &sInfo.rect);
+ SendMessage(pData->hToolTip, TTM_ADDTOOL, 0, (LPARAM)&sInfo);
+ SendMessage(pData->hToolTip, TTM_SETMAXTIPWIDTH, 0, 10000);
+ SetWindowLong(pData->hToolTip, GWL_ID, 2);
+ SetWindowLongPtr(pData->hToolTip, GWLP_USERDATA, (LPARAM)pData);
+ SetWindowLongPtr(pData->hToolTip, GWLP_WNDPROC , (LPARAM)ToolProc);
+}
+
+//*****************************************************************************
+//*
+//* CreateStateImageList
+//*
+//*****************************************************************************
+// Erzeugt eine Image-Liste mit zwei Checkboxen
+// pData : Zeiger auf die Fensterdaten
+// iMode : Welche Imageliste soll erzeugt werden (0=hStates 1=hChecks)
+static void CreateStateImageList(TreeListData *pData, int iMode) {
+
+ BITMAPINFO sInfo;
+ BYTE aMem[0x1000];
+ HDC hDcSrc;
+ HDC hDc;
+ HBITMAP hBmp;
+ HBITMAP hBmpNew;
+ RECT sRect;
+ int iBits;
+
+ if(pOpenThemeData) { // �ber Thema zeichnen
+ if(!pData->hThemeBt) {
+ pData->hThemeBt = pOpenThemeData(pData->hWnd, L"BUTTON");
+ }
+
+ if(pData->hThemeBt) {
+ if(iMode) {
+ if(pData->hChecks && pData->hChecks != THEMEIMGLIST) {
+ ImageList_Destroy(pData->hChecks);
+ }
+
+ pData->hChecks = THEMEIMGLIST;
+ pData->iChecksXsize = 16;
+ pData->iChecksYsize = 16;
+ pData->iChecksMode = 1;
+ } else {
+ if(pData->hStates && pData->hStates != THEMEIMGLIST) {
+ ImageList_Destroy(pData->hStates);
+ }
+
+ pData->hStates = THEMEIMGLIST;
+ pData->iStatesXsize = 16;
+ pData->iStatesYsize = 16;
+ pData->iStatesMode = 1;
+ }
+
+ return;
+ }
+ }
+
+ if(iMode) {
+ if(pData->hChecks && pData->hChecks != THEMEIMGLIST)
+ return;
+ } else {
+ if(pData->hStates && pData->hStates != THEMEIMGLIST)
+ return;
+ }
+
+ hDcSrc = GetDC(NULL);
+ hDc = CreateCompatibleDC(NULL);
+ hBmp = CreateCompatibleBitmap(hDcSrc, 16 * 3, 16);
+
+ SelectObject(hDc, hBmp);
+ SelectObject(hDc, GetStockObject(NULL_PEN));
+ SetBkMode(hDc, OPAQUE);
+ SetBkColor(hDc, GetSysColor(COLOR_WINDOW));
+ SelectObject(hDc, GetSysColorBrush(COLOR_HIGHLIGHT));
+ Rectangle(hDc, -1, -1, 16 * 3 + 2, 16 + 2);
+
+ sRect.top = 8 - 6;
+ sRect.bottom = 8 + 7;
+ sRect.left = 16 * 1 + 8 - 7;
+ sRect.right = 16 * 1 + 8 + 6;
+
+ DrawFrameControl(hDc, &sRect, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT);
+
+ sRect.left = 16 * 2 + 8 - 7;
+ sRect.right = 16 * 2 + 8 + 6;
+
+ DrawFrameControl(hDc, &sRect, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_CHECKED |
DFCS_FLAT);
+
+ iBits = GetDeviceCaps(hDc, BITSPIXEL);
+
+ sInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ sInfo.bmiHeader.biWidth = 16 * 3;
+ sInfo.bmiHeader.biHeight = 16;
+ sInfo.bmiHeader.biPlanes = 1;
+ sInfo.bmiHeader.biBitCount = (WORD)iBits;
+ sInfo.bmiHeader.biCompression = BI_RGB;
+ sInfo.bmiHeader.biSizeImage = 0;
+ sInfo.bmiHeader.biXPelsPerMeter = 0;
+ sInfo.bmiHeader.biYPelsPerMeter = 0;
+ sInfo.bmiHeader.biClrUsed = (iBits > 8) ? 0 : 1 << iBits;;
+ sInfo.bmiHeader.biClrImportant = (iBits > 8) ? 0 : 1 << iBits;;
+
+ GetDIBits(hDc, hBmp, 0, 0 , NULL, &sInfo, (iBits > 8) ? DIB_RGB_COLORS :
DIB_PAL_COLORS);
+ GetDIBits(hDc, hBmp, 0, 16, aMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS :
DIB_PAL_COLORS);
+
+ hBmpNew = CreateCompatibleBitmap(hDc, 16 * 3, 16);
+
+ SetDIBits(hDc, hBmpNew, 0, 16, aMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS :
DIB_PAL_COLORS);
+
+ if(iMode == 0) {
+ pData->hStates = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 3, 14);
+ pData->iStatesXsize = 16;
+ pData->iStatesYsize = 16;
+ pData->iStatesMode = 1;
+
+ ImageList_AddMasked(pData->hStates, hBmpNew, GetSysColor(COLOR_HIGHLIGHT));
+ } else {
+ pData->hChecks = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 3, 14);
+ pData->iChecksXsize = 16;
+ pData->iChecksYsize = 16;
+ pData->iChecksMode = 1;
+
+ ImageList_AddMasked(pData->hChecks, hBmpNew, GetSysColor(COLOR_HIGHLIGHT));
+ }
+
+ DeleteObject(hBmpNew);
+ DeleteObject(hBmp);
+ DeleteDC(hDc);
+ ReleaseDC(NULL, hDcSrc);
+}
+
+//*****************************************************************************
+//*
+//* CreateDragImage
+//*
+//*****************************************************************************
+// Erzeugt eine Image-Liste mit zwei Checkboxen
+// pData : Zeiger auf die Fensterdaten
+// uSub : Ist die Spalte f�r die das Drag-Image erzeugt werden soll
+// Ergibt ein Handle mit der Imageliste oder NULL bei einem Fehler
+static HIMAGELIST CreateDragImage(TreeListData *pData, unsigned uItem, unsigned uSub) {
+
+ ExtraItem *pExtra;
+ BaseItem *pEntry;
+ HIMAGELIST hList;
+ BITMAPINFO sInfo;
+ BYTE *pMem;
+ HDC hDcSrc;
+ HDC hDc;
+ HBITMAP hBmp;
+ HBITMAP hBmpNew;
+ RECT sRect;
+ unsigned uTSize;
+ int iAdd;
+ int iBits;
+ int iWidth;
+ int iHeigh;
+ int iImage;
+ int iYpos;
+ LPCTSTR pText;
+
+ if(uItem > pData->uTreeItemsMax)
+ return NULL;
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+
+ iHeigh = pData->iFontHeight;
+
+ if(uSub) { // Image f�r Extraeintrag erzeugen
+ if(uSub >= pData->uColumnCount)
+ return 0;
+
+ pExtra = pData->pExtraItems[uSub - 1][uItem];
+ if(!pExtra) {
+ pText = _T("????");
+ uTSize = 4;
+ iImage = -1;
+ iWidth = pData->iFontHeight * 4;
+ } else {
+ pText = pExtra->pText;
+ uTSize = pExtra->uTextSize;
+ iImage = pExtra->iImage;
+ iWidth = pExtra->iTextPixels;
+
+ if(pExtra->bCallback & (TVIF_IMAGE | TVIF_TEXT)) {
+ CallbackExtra(pData, pEntry, pExtra, uItem, uSub, pExtra->bCallback, &iImage,
&uTSize, &pText);
+ }
+ }
+ } else { // Image f�r Haupteintrag erzeugen
+ pText = pEntry->pText;
+ uTSize = pEntry->uTextSize;
+ iImage = pEntry->iImage;
+ iWidth = pEntry->iTextPixels;
+
+ if(pEntry->bCallback & (TVIF_IMAGE | TVIF_TEXT)) {
+ CallbackEntry(pData, pEntry, uItem, pEntry->bCallback, &iImage, &uTSize,
&pText);
+ }
+ }
+
+ if(pData->hImages && iImage >= 0) { // Gr��en f�r Images anpassen
+ if(iHeigh < pData->iImagesYsize)
+ iHeigh = pData->iImagesYsize;
+ iAdd = pData->iImagesXsize + 2;
+ iWidth += iAdd;
+ } else {
+ iAdd = 0;
+ iImage = 1;
+ }
+
+ if(iWidth > 240)
+ iWidth = 240;
+ if(iHeigh > 32)
+ iHeigh = 32;
+
+ pMem = new(BYTE, iHeigh * (iWidth + 4) * 4 + 1024);
+ if(!pMem)
+ return NULL;
+
+ hDcSrc = GetDC(NULL);
+ hDc = CreateCompatibleDC(NULL);
+ hBmp = CreateCompatibleBitmap(hDcSrc, iWidth, iHeigh);
+
+ SelectObject(hDc, hBmp);
+ SelectObject(hDc, GetStockObject(NULL_PEN));
+ SelectObject(hDc, (pEntry->uState & TVIS_BOLD) ? pData->hFontB :
pData->hFontN);
+ SetTextColor(hDc, pData->uColors[TVC_TEXT]);
+ SetBkColor(hDc, RGB(123, 77, 91));
+
+ sRect.top = 0;
+ sRect.bottom = iHeigh;
+ sRect.left = 0;
+ sRect.right = iWidth;
+ iYpos = (iHeigh - pData->iFontHeight) / 2;
+
+ ExtTextOut(hDc, iAdd, iYpos, ETO_OPAQUE | ETO_CLIPPED, &sRect, pText, uTSize,
NULL);
+
+ if(iImage >= 0) {
+ SetBkColor(hDc, GetSysColor(COLOR_WINDOW));
+ ImageList_Draw(pData->hImages, iImage, hDc, 0, 0, ILD_TRANSPARENT);
+ }
+
+ iBits = GetDeviceCaps(hDc, BITSPIXEL);
+
+ sInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ sInfo.bmiHeader.biWidth = iWidth;
+ sInfo.bmiHeader.biHeight = iHeigh;
+ sInfo.bmiHeader.biPlanes = 1;
+ sInfo.bmiHeader.biBitCount = (WORD)iBits;
+ sInfo.bmiHeader.biCompression = BI_RGB;
+ sInfo.bmiHeader.biSizeImage = 0;
+ sInfo.bmiHeader.biXPelsPerMeter = 0;
+ sInfo.bmiHeader.biYPelsPerMeter = 0;
+ sInfo.bmiHeader.biClrUsed = (iBits > 8) ? 0 : 1 << iBits;;
+ sInfo.bmiHeader.biClrImportant = (iBits > 8) ? 0 : 1 << iBits;;
+
+ GetDIBits(hDc, hBmp, 0, 0 , NULL, &sInfo, (iBits > 8) ? DIB_RGB_COLORS :
DIB_PAL_COLORS);
+ GetDIBits(hDc, hBmp, 0, iHeigh, pMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS :
DIB_PAL_COLORS);
+
+ hBmpNew = CreateCompatibleBitmap(hDc, iWidth, iHeigh);
+
+ SetDIBits(hDc, hBmpNew, 0, iHeigh, pMem, &sInfo, (iBits > 8) ? DIB_RGB_COLORS :
DIB_PAL_COLORS);
+
+ hList = ImageList_Create(iWidth, iHeigh, ILC_COLORDDB | ILC_MASK, 1, 0);
+
+ ImageList_AddMasked(hList, hBmpNew, RGB(123, 77, 91));
+
+ DeleteObject(hBmpNew);
+ DeleteObject(hBmp);
+ DeleteDC(hDc);
+ ReleaseDC(NULL, hDcSrc);
+
+ delete(pMem);
+
+ return hList;
+}
+
+
+//*****************************************************************************
+//*
+//* UpdateColorsList
+//*
+//*****************************************************************************
+// Aktualisiert alle Farben
+// pData : Zeiger auf die Fensterdaten
+static void UpdateColorsList(TreeListData *pData) {
+
+ unsigned uColOdd;
+ unsigned uColor;
+ int iDiff;
+ int iSum;
+
+ if(!pData->cColorChanged[TVC_BK ])
+ pData->uColors[TVC_BK ] = GetSysColor(COLOR_WINDOW);
+ if(!pData->cColorChanged[TVC_BOX ])
+ pData->uColors[TVC_BOX ] = GetSysColor(COLOR_BTNSHADOW);
+ if(!pData->cColorChanged[TVC_EVEN ])
+ pData->uColors[TVC_EVEN ] = GetSysColor(COLOR_WINDOW);
+ if(!pData->cColorChanged[TVC_TEXT ])
+ pData->uColors[TVC_TEXT ] = GetSysColor(COLOR_WINDOWTEXT);
+ if(!pData->cColorChanged[TVC_LINE ])
+ pData->uColors[TVC_LINE ] = GetSysColor(COLOR_WINDOWTEXT);
+ if(!pData->cColorChanged[TVC_FRAME ])
+ pData->uColors[TVC_FRAME ] = GetSysColor(COLOR_3DFACE);
+ if(!pData->cColorChanged[TVC_TRACK ])
+ pData->uColors[TVC_TRACK ] = GetSysColor(COLOR_WINDOWTEXT) ^ RGB(0, 0, 255);
+ if(!pData->cColorChanged[TVC_INSERT ])
+ pData->uColors[TVC_INSERT ] = GetSysColor(COLOR_INFOBK);
+ if(!pData->cColorChanged[TVC_ODD ])
+ pData->uColors[TVC_ODD ] = GetSysColor(COLOR_INFOBK);
+ if(!pData->cColorChanged[TVC_BOXBG ])
+ pData->uColors[TVC_BOXBG ] = GetSysColor(COLOR_WINDOW);
+ if(!pData->cColorChanged[TVC_COLBK ])
+ pData->uColors[TVC_COLBK ] = GetSysColor(COLOR_WINDOW);
+ if(!pData->cColorChanged[TVC_COLODD ])
+ pData->uColors[TVC_COLODD ] = GetSysColor(COLOR_BTNSHADOW);
+ if(!pData->cColorChanged[TVC_COLEVEN])
+ pData->uColors[TVC_COLEVEN] = GetSysColor(COLOR_WINDOW);
+ if(!pData->cColorChanged[TVC_GRAYED ])
+ pData->uColors[TVC_GRAYED ] = GetSysColor(COLOR_SCROLLBAR);
+
+
+ if(pData->hTheme && !pData->cColorChanged[TVC_BOXBG] &&
!pData->cColorChanged[TVC_BOX] && !pData->cColorChanged[TVC_LINE]) {
+ pData->cGlyphOk = 1;
+ } else {
+ pData->cGlyphOk = 0;
+ }
+
+
+ if(!pData->cColorChanged[TVC_GRAYED]) {
+ pData->uColors[TVC_GRAYED] = (GetSysColor(COLOR_SCROLLBAR) & 0x00FEFEFE)
>> 1;
+ pData->uColors[TVC_GRAYED] += (GetSysColor(COLOR_WINDOW) & 0x00FEFEFE) >>
1;
+ }
+
+ if(!pData->cColorChanged[TVC_ODD]) {
+ uColOdd = pData->uColors[TVC_ODD];
+ iDiff = ((uColOdd) & 0xFF) - ((pData->uColors[TVC_EVEN]) & 0xFF);
+ iSum = iDiff * iDiff;
+ iDiff = ((uColOdd >> 8) & 0xFF) - ((pData->uColors[TVC_EVEN] >> 8)
& 0xFF);
+ iSum += iDiff * iDiff;
+ iDiff = ((uColOdd >> 16) & 0xFF) - ((pData->uColors[TVC_EVEN] >>
16) & 0xFF);
+ iSum += iDiff * iDiff;
+
+ if(iSum < 64) { // Ist die alternierente Farbe fast gleich ?
+ uColOdd = pData->uColors[TVC_EVEN] & 0x0000FFFF;
+ uColOdd |= ((pData->uColors[TVC_EVEN] & 0x00FF0000) - 0x00080000) &
0x00FF0000;
+ }
+
+ pData->uColors[TVC_ODD] = uColOdd;
+ }
+
+ if(!pData->cColorChanged[TVC_COLBK]) {
+ uColor = GetSysColor(COLOR_WINDOW);
+ if(uColor & 0x00F00000)
+ uColor -= 0x00100000;
+ if(uColor & 0x0000F000)
+ uColor -= 0x00001000;
+ if(uColor & 0x000000F0)
+ uColor -= 0x00000010;
+
+ pData->uColors[TVC_COLBK] = uColor;
+ }
+
+ if(!pData->cColorChanged[TVC_COLODD]) {
+ uColor = pData->uColors[TVC_ODD];
+ if(uColor & 0x00F00000)
+ uColor -= 0x00100000;
+ if(uColor & 0x0000F000)
+ uColor -= 0x00001000;
+ if(uColor & 0x000000F0)
+ uColor -= 0x00000010;
+
+ pData->uColors[TVC_COLODD] = uColor;
+ }
+
+ if(!pData->cColorChanged[TVC_COLEVEN]) {
+ uColor = GetSysColor(COLOR_WINDOW);
+ if(uColor & 0x00F00000)
+ uColor -= 0x00100000;
+ if(uColor & 0x0000F000)
+ uColor -= 0x00001000;
+ if(uColor & 0x000000F0)
+ uColor -= 0x00000010;
+
+ pData->uColors[TVC_COLEVEN] = uColor;
+ }
+
+ if(!pData->cColorChanged[TVC_MARKODD ])
+ pData->uColors[TVC_MARKODD ] = ((pData->uColors[TVC_ODD ] >> 3) &
0x1F1F1F) * 7;
+ if(!pData->cColorChanged[TVC_MARKODD ])
+ pData->uColors[TVC_MARKODD ] += ((GetSysColor(COLOR_HIGHLIGHT) >> 3) &
0x1F1F1F) * 1;
+ if(!pData->cColorChanged[TVC_MARKEVEN])
+ pData->uColors[TVC_MARKEVEN] = ((pData->uColors[TVC_EVEN ] >> 3) &
0x1F1F1F) * 7;
+ if(!pData->cColorChanged[TVC_MARKEVEN])
+ pData->uColors[TVC_MARKEVEN] += ((GetSysColor(COLOR_HIGHLIGHT) >> 3) &
0x1F1F1F) * 1;
+}
+
+//*****************************************************************************
+//*
+//* UpdateHeight
+//*
+//*****************************************************************************
+// Checks if the row height has changed
+// pData : pointer to the window data
+// Returns 1 if changed or 0 else.
+static int UpdateHeight(TreeListData *pData) {
+
+ int iHeight;
+ RECT sRect;
+
+ if(pData->cFixedHeight)
+ return 0;
+
+ iHeight = 10;
+
+ if(pData->hChecks)
+ if(iHeight < pData->iChecksYsize + 2)
+ iHeight = pData->iChecksYsize + 2;
+ if(pData->hStates)
+ if(iHeight < pData->iStatesYsize + 2)
+ iHeight = pData->iStatesYsize + 2;
+ if(iHeight < pData->iSubImgYsize + 2)
+ iHeight = pData->iSubImgYsize + 2;
+ if(iHeight < pData->iImagesYsize + 2)
+ iHeight = pData->iImagesYsize + 2;
+ if(iHeight < pData->iFontHeight + 2)
+ iHeight = pData->iFontHeight + 2;
+ if(pData->uStyleEx & TVS_EX_ITEMLINES)
+ iHeight++;
+ if(pData->uStyle & TVS_NONEVENHEIGHT && (iHeight & 1))
+ iHeight++;
+ if(pData->iRowHeight == iHeight)
+ return 0;
+
+ pData->iRowHeight = iHeight;
+
+ if(pData->uSizeY > pData->uStartPixel) {
+ pData->uMaxEnties = pData->uSizeY;
+ pData->uMaxEnties -= pData->uStartPixel;
+ } else {
+ pData->uMaxEnties = 0;
+ }
+
+ pData->uPageEnties = pData->uMaxEnties;
+ pData->uMaxEnties += pData->iRowHeight - 1;
+ pData->uMaxEnties /= pData->iRowHeight;
+ pData->uPageEnties /= pData->iRowHeight;
+
+ GetClientRect(pData->hWnd, &sRect);
+ InvalidateRect(pData->hWnd, &sRect, FALSE);
+
+ return 1;
+}
+
+//*****************************************************************************
+//*
+//* UpdateRect
+//*
+//*****************************************************************************
+// Zeichnet einen Eintrag neu
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages
+// uSub : Ist die Spaltennummer
+// Ergibt 1 wenn der Eintrag sichtbar war
+static int UpdateRect(TreeListData *pData, unsigned uItem, unsigned uSub) {
+
+ BaseItem *pEntry;
+ RECT sRect;
+ UINT uNext;
+ UINT uPos;
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry || !pEntry->uShowPos)
+ return 0; // Ist der Eintrag aufgeklappt
+
+ uPos = pEntry->uShowPos - pData->uScrollY - 1;
+ if(uPos >= pData->uMaxEnties)
+ return 0; // Eintrag im Fenster sichtbar
+
+ uNext = pData->aColumn[uSub].bNext;
+ sRect.left = pData->aColumnXpos[uSub ];
+ sRect.left -= pData->uScrollX;
+ sRect.right = pData->aColumnXpos[uNext];
+ sRect.right -= pData->uScrollX;
+ sRect.top = pData->uStartPixel;
+ sRect.top += pData->iRowHeight * uPos;
+ sRect.bottom = pData->iRowHeight + sRect.top;
+
+ InvalidateRect(pData->hWnd, &sRect, FALSE);
+
+ return 1;
+}
+
+//*****************************************************************************
+//*
+//* UpdateColRect
+//*
+//*****************************************************************************
+// Zeichnet einen ganze Spalte neu
+// pData : Zeiger auf die Fensterdaten
+// uColumn : Die nummer der Spalte
+// Ergibt 1 wenn der Eintrag sichtbar war
+static int UpdateColRect(TreeListData *pData, unsigned uColumn) {
+
+ RECT sRect;
+ UINT uNext;
+
+ if(uColumn >= pData->uColumnCount)
+ return 0;
+
+ sRect.left = pData->aColumnXpos[uColumn];
+ sRect.left -= pData->uScrollX;
+ if(sRect.left > (int)pData->uSizeX)
+ return 0;
+
+ uNext = pData->aColumn[uColumn].bNext;
+
+ sRect.right = pData->aColumnXpos[uNext];
+ sRect.right -= pData->uScrollX;
+ if(sRect.right < 0)
+ return 0;
+
+ sRect.top = 0;
+ sRect.bottom = pData->uSizeY;
+
+ InvalidateRect(pData->hWnd, &sRect, FALSE);
+
+ return 1;
+}
+
+//*****************************************************************************
+//*
+//* UpdateRow
+//*
+//*****************************************************************************
+// Zeichnet einen Eintrag �ber die ganze Zeile neu
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages
+// Ergibt 1 wenn der Eintrag sichtbar war
+static int UpdateRow(TreeListData *pData, unsigned uItem) {
+
+ BaseItem *pEntry;
+ RECT sRect;
+ unsigned uPos;
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry || !pEntry->uShowPos)
+ return 0; // Ist der Eintrag aufgeklappt
+
+ uPos = pEntry->uShowPos - pData->uScrollY - 1;
+ if(uPos >= pData->uMaxEnties)
+ return 0; // Eintrag im Fenster sichtbar
+
+ sRect.left = 0;
+ sRect.right = pData->uSizeX;
+ sRect.top = pData->uStartPixel;
+ sRect.top += pData->iRowHeight * uPos;
+ sRect.bottom = pData->iRowHeight + sRect.top;
+ InvalidateRect(pData->hWnd, &sRect, FALSE);
+
+ return 1;
+}
+
+//*****************************************************************************
+//*
+//* UpdateView
+//*
+//*****************************************************************************
+// Redraw the whole window
+// pData : Zeiger auf die Fensterdaten
+// Ergibt 1 wenn der Eintrag sichtbar war
+static void UpdateView(TreeListData *pData) {
+
+ RECT sRect;
+
+ GetClientRect(pData->hWnd, &sRect);
+ sRect.top = pData->uStartPixel;
+ InvalidateRect(pData->hWnd, &sRect, FALSE);
+
+ if(pData->hHeader && ((pData->uStyleEx & TVS_EX_HIDEHEADERS) == 0)){
+ GetClientRect(pData->hHeader, &sRect);
+ InvalidateRect(pData->hHeader, &sRect, FALSE);
+ }
+}
+
+//*****************************************************************************
+//*
+//* UpdateScrollX
+//*
+//*****************************************************************************
+// Aktualisiert die X-Scroolbar
+// pData : Zeiger auf die Fensterdaten
+// Ergibt 1 wenn der sich Einstellungen ver�ndert haben
+static void UpdateScrollX(TreeListData *pData) {
+
+ SCROLLINFO sInfo;
+ unsigned uSize;
+ unsigned uCols;
+
+ uCols = pData->uColumnCount;
+ if(uCols)
+ uSize = pData->aColumnXpos[uCols] - 1;
+ else
+ uSize = pData->iMaxSizeX - 1;
+
+
+ if(pData->uOldXCount == uSize)
+ if(pData->uOldXPage == pData->uSizeX) {
+ return;
+ }
+
+ pData->uOldXPage = pData->uSizeX;
+ pData->uOldXCount = uSize;
+
+ UNLOCK(pData);
+
+ sInfo.cbSize = sizeof(SCROLLINFO);
+ sInfo.fMask = SIF_ALL;
+ sInfo.nMin = 0;
+ sInfo.nMax = uSize;
+ sInfo.nPage = pData->uSizeX;
+ sInfo.nPos = pData->uScrollX;
+ sInfo.nTrackPos = 0;
+
+ if(pData->uStyle & TVS_NOSCROLL) {
+ sInfo.nMax = 0;
+ } else
+ if(pData->uStyleEx & TVS_EX_AUTOHSCROLL) {
+ sInfo.nMax = 0;
+ } else
+ if(sInfo.nMax > 0) {
+ sInfo.nMax--;
+ }
+
+
+ if((int)sInfo.nPage >= sInfo.nMax && pData->uScrollX > 0) {
+ sInfo.nPos = 0;
+ pData->uScrollX = 0;
+
+ UpdateView(pData);
+
+ if(pData->hHeader) {
+ MoveWindow(pData->hHeader, 0, 0, pData->uSizeX, pData->uStartPixel, TRUE);
+ }
+ }
+
+ SetScrollInfo(pData->hWnd, SB_HORZ, &sInfo, TRUE);
+
+ LOCK(pData);
+}
+
+//*****************************************************************************
+//*
+//* UpdateScrollY
+//*
+//*****************************************************************************
+// Aktualisiert die Y-Scroolbar
+// pData : Zeiger auf die Fensterdaten
+// Ergibt 1 wenn der sich Einstellungen ver�ndert haben
+static void UpdateScrollY(TreeListData *pData) {
+
+ SCROLLINFO sInfo;
+
+ if(pData->uOldYCount == pData->uItemPosCount)
+ if(pData->uOldYPage == pData->uPageEnties) {
+ return;
+ }
+
+ pData->uOldYPage = pData->uPageEnties;
+ pData->uOldYCount = pData->uItemPosCount;
+
+ UNLOCK(pData);
+
+ sInfo.cbSize = sizeof(SCROLLINFO);
+ sInfo.fMask = SIF_ALL;
+ sInfo.nMin = 0;
+ sInfo.nMax = pData->uItemPosCount;
+ sInfo.nPage = pData->uPageEnties;
+ sInfo.nPos = pData->uScrollY;
+ sInfo.nTrackPos = 0;
+
+ if(pData->uStyle & TVS_NOSCROLL) {
+ sInfo.nMax = 0;
+ }
+
+ if((int)sInfo.nPage >= sInfo.nMax && pData->uScrollY > 0) {
+ sInfo.nPos = 0;
+ pData->uScrollY = 0;
+
+ UpdateView(pData);
+ }
+
+ SetScrollInfo(pData->hWnd, SB_VERT, &sInfo, TRUE);
+
+ LOCK(pData);
+}
+
+//*****************************************************************************
+//*
+//* UpdateToolTip
+//*
+//*****************************************************************************
+// Aktualisiert den Text f�r das Tootip
+// pData : Zeiger auf Fensterdaten
+// uItem : Item auf den der Mauszeiger zeigt
+// uFlags : Flags vom HitTest
+static void UpdateToolTip(TreeListData *pData, unsigned uItem, unsigned uFlags) {
+
+ TCHAR cTemp[INFOTIPSIZE];
+#ifndef __REACTOS__
+ HWND hToolTip;
+#endif
+ NMTVGETINFOTIP sToolNv;
+ NMTREEVIEW sNotify;
+ TOOLINFO sInfo;
+ ExtraItem *pExtra;
+ BaseItem *pEntry;
+ LPCTSTR pText;
+ RECT sRect;
+ unsigned uSize;
+ unsigned uCol;
+ unsigned uLen;
+ LRESULT lRet;
+ int iTemp;
+ // Tooltip ausbelnden
+ if(!uItem || (uItem == pData->uEditItem && TVHT_SUBTOCOL(uFlags) ==
pData->uEditSub)) {
+ if(pData->uToolTipItem)
+ goto ExitTip;
+ return;
+ }
+
+ pEntry = pData->pTreeItems[uItem];
+
+ if(uFlags & TVHT_ONITEM) {
+ if(pData->uToolTipItem != uItem || pData->uToolTipSub != 0) {
+ if(!pData->pTreeItems[uItem]) { // Existiert der Eintag noch ?
+ goto ExitTip;
+ }
+
+ TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT, &sRect);
+
+ if(sRect.right > (int)pData->uSizeX) {
+ sRect.right = pData->uSizeX;
+ }
+
+ lRet = 0;
+
+ if(pData->uStyleEx & TVS_EX_TOOLTIPNOTIFY) { // Tooltip-Daten via speziellem
Notify holen
+ sNotify.hdr.code = TVN_ITEMTOOLTIP;
+ sNotify.action = 0;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = pEntry->uState;
+ sNotify.itemNew.lParam = pEntry->lParam;
+ sNotify.itemNew.pszText = pEntry->pText;
+ sNotify.itemNew.cchTextMax = pEntry->uTextSize;
+ sNotify.itemNew.cChildren = 0;
+ sNotify.itemOld.mask = 0;
+ sNotify.ptDrag.x = sRect.left;
+ sNotify.ptDrag.y = sRect.top;
+
+ UNLOCK(pData);
+ lRet = SendNotify(pData, &sNotify.hdr);
+ LOCK(pData);
+
+ if(lRet)
+ goto UserTip;
+ } else
+ if(pData->uStyle & TVS_INFOTIP) { // Tooltip-Daten via normalem Notify
holen
+ sToolNv.hdr.code = TVN_GETINFOTIP;
+ sToolNv.cchTextMax = INFOTIPSIZE;
+ sToolNv.hItem = (HTREEITEM)uItem;
+ sToolNv.lParam = pEntry->lParam;
+ sToolNv.pszText = cTemp;
+
+ str_ncpy(cTemp, pEntry->pText, INFOTIPSIZE);
+ cTemp[INFOTIPSIZE - 1] = 0;
+
+ UNLOCK(pData);
+ lRet = SendNotify(pData, &sNotify.hdr);
+ LOCK(pData);
+
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.pszText = sToolNv.pszText;
+ sNotify.itemNew.cchTextMax = str_len(sToolNv.pszText);
+ sNotify.itemNew.cChildren = 0;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = pEntry->uState;
+ sNotify.itemNew.lParam = pEntry->lParam;
+ sNotify.ptDrag.x = sRect.left;
+ sNotify.ptDrag.y = sRect.top;
+
+ goto UserTip;
+ }
+ // Passt der Text in die Spalte
+ if(sRect.right - sRect.left <= pEntry->iTextPixels + 4) {
+ pText = pEntry->pText;
+ uSize = pEntry->uTextSize;
+
+ if(pEntry->bCallback & TVIF_TEXT) {
+ CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iTemp, &uSize, &pText);
+ }
+
+ if(!pText || *pText == 0)
+ goto ExitTip;
+
+ uLen = str_len(pText) + 1;
+ if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergr��ern
+ delete(pData->pToolTipText);
+ pData->uToolTipSize = (uLen + 255)&~0xFF;
+ pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4);
+ }
+
+ memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR));
+ pData->hFontT = (pEntry->uState & TVIS_BOLD) ? pData->hFontB :
pData->hFontN;
+
+#ifndef __REACTOS__
+ hToolTip = pData->hToolTip;
+#endif
+ pData->sToolTipPos.x = sRect.left;
+ pData->sToolTipPos.y = sRect.top;
+
+ ClientToScreen(pData->hWnd, &pData->sToolTipPos);
+
+ UNLOCK(pData);
+
+ sInfo.cbSize = sizeof(sInfo);
+ sInfo.hwnd = pData->hWnd;
+ sInfo.uId = (UINT_PTR)pData->hWnd;
+
+ if(pData->uToolTipItem) {
+ SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
+ pData->uToolTipItem = 0;
+ }
+
+ SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0,
MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y));
+ SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
+
+ LOCK(pData);
+
+ pData->uToolTipItem = uItem;
+ pData->uToolTipShow = 0;
+ pData->uToolTipSub = 0;
+
+ SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);
+ } else {
+ if(pData->uToolTipItem)
+ goto ExitTip;
+ }
+ }
+
+ return;
+ }
+
+ if(uFlags & (TVHT_ONSUBICON | TVHT_ONSUBLABEL)) {
+ if(pData->uToolTipItem != uItem || TVHT_SUBTOCOL(uFlags) != pData->uToolTipSub)
{
+ lRet = 0;
+ uCol = TVHT_SUBTOCOL(uFlags);
+ pExtra = pData->pExtraItems[uCol - 1][uItem];
+
+ if(pData->uStyleEx & TVS_EX_TOOLTIPNOTIFY) { // Tooltip-Daten via Notify
holen
+ TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT | TVIR_COLTOSUB(uCol),
&sRect);
+
+ if(sRect.right > (int)pData->uSizeX) {
+ sRect.right = pData->uSizeX;
+ }
+
+ if(pExtra) {
+ sNotify.itemNew.state = pExtra->uState;
+ sNotify.itemNew.pszText = pExtra->pText;
+ sNotify.itemNew.cchTextMax = pExtra->uTextSize;
+ } else {
+ sNotify.itemNew.state = 0;
+ sNotify.itemNew.cchTextMax = 0;
+ sNotify.itemNew.pszText = _T("");
+ }
+
+ sNotify.hdr.code = TVN_ITEMTOOLTIP;
+ sNotify.action = 0;
+ sNotify.itemNew.lParam = pEntry->lParam;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.cChildren = uCol;
+ sNotify.itemOld.mask = 0;
+ sNotify.ptDrag.x = sRect.left;
+ sNotify.ptDrag.y = sRect.top;
+
+ UNLOCK(pData);
+ lRet = SendNotify(pData, &sNotify.hdr);
+ LOCK(pData);
+
+ if(lRet)
+ goto UserTip;
+ }
+
+ if(pExtra) { // Tooltip auf Unterspalte ?
+ TreeListGetItemRect(pData, uItem, TVIR_GETCOLUMN | TVIR_TEXT | TVIR_COLTOSUB(uCol),
&sRect);
+
+ if(sRect.right > (int)pData->uSizeX) {
+ sRect.right = pData->uSizeX;
+ }
+
+ if(sRect.right - sRect.left <= pExtra->iTextPixels + 4) {
+ pText = pExtra->pText;
+ uSize = pExtra->uTextSize;
+
+ if(pExtra->bCallback & TVIF_TEXT) {
+ CallbackExtra(pData, pEntry, pExtra, uItem, uCol, TVIF_TEXT, &iTemp,
&uSize, &pText);
+ }
+
+ if(!pText || *pText == 0)
+ goto ExitTip;
+
+ uLen = str_len(pText) + 1;
+ if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergr��ern
+ delete(pData->pToolTipText);
+ pData->uToolTipSize = (uLen + 255)&~0xFF;
+ pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4);
+ }
+
+ memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR));
+ pData->hFontT = (pExtra->uState & TVIS_BOLD) ? pData->hFontB :
pData->hFontN;
+
+ pData->sToolTipPos.x = sRect.left;
+ pData->sToolTipPos.y = sRect.top;
+#ifndef __REACTOS__
+ hToolTip = pData->hToolTip;
+#endif
+
+ ClientToScreen(pData->hWnd, &pData->sToolTipPos);
+
+ UNLOCK(pData);
+
+ sInfo.cbSize = sizeof(sInfo);
+ sInfo.hwnd = pData->hWnd;
+ sInfo.uId = (UINT_PTR)pData->hWnd;
+
+ if(pData->uToolTipItem) {
+ SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
+ pData->uToolTipItem = 0;
+ }
+
+ SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0,
MAKELONG(pData->sToolTipPos.x, pData->sToolTipPos.y));
+ SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
+
+ LOCK(pData);
+
+ pData->uToolTipItem = uItem;
+ pData->uToolTipSub = uCol;
+ pData->uToolTipShow = 0;
+
+ SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);
+ } else {
+ if(pData->uToolTipItem)
+ goto ExitTip;
+ }
+ } else {
+ if(pData->uToolTipItem)
+ goto ExitTip;
+ }
+ }
+
+ return;
+ }
+
+ExitTip:
+
+ if(pData->uToolTipItem) { // Tooltip ausblenden
+ UNLOCK(pData);
+
+ sInfo.cbSize = sizeof(sInfo);
+ sInfo.hwnd = pData->hWnd;
+ sInfo.uId = (UINT_PTR)pData->hWnd;
+
+ SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
+
+ LOCK(pData);
+
+ pData->uToolTipItem = 0;
+ pData->uToolTipSub = 0;
+ pData->uToolTipShow = 0;
+
+ KillTimer(pData->hWnd, ID_TOOLTIPCHECK);
+ }
+
+ return;
+
+UserTip:
+
+ pText = sNotify.itemNew.pszText; // Soll ein User-Tooltip angezeigt werden
+ uSize = sNotify.itemNew.cchTextMax;
+ sRect.left = sNotify.ptDrag.x;
+ sRect.top = sNotify.ptDrag.y;
+
+ if(!pText || *pText == 0)
+ goto ExitTip;
+
+ uLen = str_len(pText) + 1;
+ if(uLen >= pData->uToolTipSize) { // Tooltipspeicher vergr��ern
+
+ delete(pData->pToolTipText);
+ pData->uToolTipSize = (uLen + 255)&~0xFF;
+ pData->pToolTipText = new(TCHAR, pData->uToolTipSize + 4);
+ }
+
+ memcpy(pData->pToolTipText, pText, uLen * sizeof(TCHAR));
+ pData->hFontT = (pEntry->uState & TVIS_BOLD) ? pData->hFontB :
pData->hFontN;
+
+ ClientToScreen(pData->hWnd, &sNotify.ptDrag);
+ pData->sToolTipPos = sNotify.ptDrag;
+#ifndef __REACTOS__
+ hToolTip = pData->hToolTip;
+#endif
+ // Tooltip verz�gert anzeigen
+ if((sNotify.itemNew.mask & TVIF_TOOLTIPTIME) && sNotify.itemNew.lParam >
0) {
+ pData->uToolTipShow = (unsigned)(sNotify.itemNew.lParam + 499) / 500;
+ pData->uToolTipSub = sNotify.itemNew.cChildren;
+ pData->uToolTipItem = uItem;
+
+ SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 500, NULL);
+
+ return;
+ }
+
+ UNLOCK(pData);
+
+ sInfo.cbSize = sizeof(sInfo);
+ sInfo.hwnd = pData->hWnd;
+ sInfo.uId = (UINT_PTR)pData->hWnd;
+
+ if(pData->uToolTipItem) { // Tooltip Fenster aktivieren
+ SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 0, (LPARAM)&sInfo);
+ pData->uToolTipItem = 0;
+ }
+
+ SendMessage(pData->hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(sNotify.ptDrag.x,
sNotify.ptDrag.y));
+ SendMessage(pData->hToolTip, TTM_TRACKACTIVATE, 1, (LPARAM)&sInfo);
+
+ LOCK(pData);
+
+ pData->uToolTipShow = 0;
+ pData->uToolTipItem = uItem;
+ pData->uToolTipSub = sNotify.itemNew.cChildren;
+
+ SetTimer(pData->hWnd, ID_TOOLTIPCHECK, 1500, NULL);
+}
+
+//*****************************************************************************
+//*
+//* CreateFontset
+//*
+//*****************************************************************************
+// Create the font set (normal, bold, etc...) from the given HFONT
+static int CreateFontset(TreeListData *pData, HFONT hFont){
+ LOGFONT sLog;
+ HFONT hBold;
+ int iRet = 0;
+
+ if(GetObject(hFont, sizeof(sLog), &sLog)){
+ sLog.lfWeight = FW_BOLD;
+ if((hBold = CreateFontIndirect(&sLog))){
+ pData->hFontN = hFont; //store the given font
+ if(pData->hFontB != hDefaultFontB){
+ //if the current bold is not the default bold, free it
+ DeleteObject(pData->hFontB);
+ }
+ pData->hFontB = hBold; //store the created bold
+ iRet = 1;
+ }
+ }
+ return iRet;
+}
+
+//*****************************************************************************
+//*
+//* UpdateFont
+//*
+//*****************************************************************************
+// Erzeugt einen den fetten Font f�r das Fenster
+// pData : Zeiger auf die Fensterdaten
+// iRedraw : Soll das Fenster neugezeichnet werden
+// Ergibt 1 wenn der Font ver�ndert wurde
+static int UpdateFont(TreeListData *pData) {
+
+ int iPos;
+ int iRet;
+ HDC hDc;
+ LOGFONT sLog;
+ SIZE sSize;
+ TEXTMETRIC sMetrics;
+ BaseItem *pEntry;
+ BaseItem **pList;
+ ExtraItem *pExtra;
+ ExtraItem **pItems;
+ unsigned uSub;
+
+ if(!hDefaultFontN) { // Den Standard-Font erzeugen
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(sLog), &sLog, 0);
+ sLog.lfWeight = FW_NORMAL;
+ hDefaultFontN = CreateFontIndirect(&sLog);
+ sLog.lfWeight = FW_BOLD;
+ hDefaultFontB = CreateFontIndirect(&sLog);
+ }
+
+
+ if(!pData->hFontN)
+ pData->hFontN = hDefaultFontN;
+ if(!pData->hFontB)
+ pData->hFontB = hDefaultFontB;
+
+/*
+ if(pData->hFontN == hDefaultFontN) { // Ist der Standard-Font eingestellt
+ pData->hFontB = hDefaultFontB;
+ } else {
+ pData->hFontB = pData->hFontN;
+ }
+*/
+
+ if(pData->hFontN != pData->hFontL) {
+ pData->hFontL = pData->hFontN;
+
+ hDc = GetDC(NULL);
+ SelectObject(hDc, pData->hFontN);
+ GetTextMetrics(hDc, &sMetrics);
+ pData->iFontHeight = sMetrics.tmHeight;
+ pData->iFontLine = sMetrics.tmAscent + 1;
+ pData->iFontOff = (sMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH) ? 0 : -1;
+ ReleaseDC(NULL, hDc);
+
+ pList = pData->pTreeItems;
+ iPos = pData->uTreeItemsMax;
+
+ for(; iPos >= 0; iPos--) { // Alle Textbreiten zur�cksetzen
+ pEntry = pList[iPos];
+ if(!pEntry)
+ continue;
+
+ pEntry->iTextPixels = 0;
+ }
+
+
+ for(uSub = 1; uSub < pData->uColumnCount; uSub++) {
+ iPos = pData->uTreeItemsMax;
+ pItems = pData->pExtraItems[uSub - 1];
+
+ for(; iPos >= 0; iPos--) {
+ pExtra = pItems[iPos];
+ if(!pExtra)
+ continue;
+
+ pExtra->iTextPixels = 0;
+ }
+ }
+
+ iRet = 1;
+ } else {
+ iRet = 0;
+ }
+
+ // compute Width of "..." text
+ hDc = GetDC(NULL);
+ SelectObject(hDc, pData->hFontN);
+ GetTextExtentExPoint(hDc, _T("..."), 3, 256, NULL, NULL, &sSize);
+ pData->uTrippleN = sSize.cx;
+ SelectObject(hDc, pData->hFontB);
+ GetTextExtentExPoint(hDc, _T("..."), 3, 256, NULL, NULL, &sSize);
+ pData->uTrippleB = sSize.cx;
+ ReleaseDC(NULL, hDc);
+
+ return iRet;
+}
+
+
+//*****************************************************************************
+//*
+//* UpdateItems
+//*
+//*****************************************************************************
+// Berechnet die Positionen der Zeilen f�r die sichtbaren Eintr�ge
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist der Eintrag ab dem begonnen wird
+static void UpdateItems(TreeListData *pData, unsigned uItem) {
+
+ unsigned uPos;
+ unsigned uOld;
+ unsigned uNum;
+ unsigned uTemp;
+ unsigned uStart;
+ unsigned *pLines;
+ BaseItem **pItems;
+ BaseItem *pEntry;
+ BaseItem *pTemp;
+ RECT sRect;
+
+ uOld = pData->uItemPosCount;
+ pLines = pData->pItemPos;
+ pItems = pData->pTreeItems;
+
+ if(!uItem) { // Am Anfang beginnen
+ uItem = pData->uFirstChild;
+ if(!uItem) { // Leere Liste
+ if(!uOld)
+ return;
+
+ for(uNum = 0; uNum < uOld; uNum++) { // Die alten Eintr�ge zur�cksetzen
+ uTemp = pLines[uNum];
+ if(!uTemp)
+ continue;
+ pLines[uNum] = 0;
+ pTemp = pItems[uTemp];
+ if(!pTemp)
+ continue;
+ pTemp->uShowPos = 0;
+ }
+
+ pData->uItemPosCount = 0;
+
+ GetClientRect(pData->hWnd, &sRect);
+ InvalidateRect(pData->hWnd, &sRect, TRUE);
+
+ memset(pLines, 0, sizeof(unsigned)*uOld);
+ return;
+ }
+
+ for(uNum = 0; uNum < uOld; uNum++) { // Die alten Eintr�ge zur�cksetzen
+ uTemp = pLines[uNum];
+ if(!uTemp)
+ continue;
+ pLines[uNum] = 0;
+ pTemp = pItems[uTemp];
+ if(!pTemp)
+ continue;
+ pTemp->uShowPos = 0;
+ }
+
+ pEntry = pItems[uItem];
+ pEntry->uShowPos = 1;
+ pLines[0] = uItem;
+ uPos = 1;
+ uStart = 0;
+ } else { // Bei einem Eintrag beginnen
+ pEntry = pItems[uItem];
+ uPos = pEntry->uShowPos;
+ if(uPos)
+ uStart = uPos - 1;
+ else
+ uStart = 0;
+
+ for(uNum = uPos; uNum < uOld; uNum++) { // Die alten Eintr�ge zur�cksetzen
+ uTemp = pLines[uNum];
+ if(!uTemp)
+ continue;
+ pLines[uNum] = 0;
+ pTemp = pItems[uTemp];
+ if(!pTemp)
+ continue;
+ pTemp->uShowPos = 0;
+ }
+ }
+
+ for(;;) { // Die Zeilen neu zuordnen
+ if(pEntry->uFirstChild && (pEntry->uState & TVIS_EXPANDED)) {
+ uItem = pEntry->uFirstChild;
+ } else
+ if(pEntry->uNextItem) {
+ uItem = pEntry->uNextItem;
+ } else {
+ for(;;) {
+ uItem = pEntry->uParent;
+ if(!uItem)
+ break;
+
+ pEntry = pItems[uItem];
+ if(pEntry->uNextItem) { // Gibt es etwas in der gleichen Ebene
+ uItem = pEntry->uNextItem;
+ break;
+ }
+ }
+
+ if(!uItem)
+ break;
+ }
+
+ pEntry = pItems[uItem];
+
+ if(pLines[uPos] != uItem) {
+ pLines[uPos] = uItem;
+ } else {
+ if(uStart == uPos)
+ uStart++;
+ }
+
+ uPos++;
+ pEntry->uShowPos = uPos;
+ }
+
+ pData->uItemPosCount = uPos;
+
+ if(uStart > pData->uScrollY) // Neu zu zeichnenten Bereich bestimmen
+ uStart -= pData->uScrollY;
+ else
+ uStart = 0;
+
+ GetClientRect(pData->hWnd, &sRect);
+
+ sRect.top = pData->uStartPixel + pData->iRowHeight * uStart;
+
+ if(sRect.top <= sRect.bottom) {
+ InvalidateRect(pData->hWnd, &sRect, FALSE);
+ }
+
+ if(uOld != uPos)
+ UpdateScrollY(pData);
+}
+
+//*****************************************************************************
+//*
+//* UpdateColumns
+//*
+//*****************************************************************************
+// Pr�ft ob es Ver�nderungen in Spaltenbreiten gab
+// pData : Zeiger auf die Fensterdaten
+// Ergibt die Breite ab der die Spalten ver�ndert wurden oder 0x10000
+static int UpdateColumns(TreeListData *pData) {
+#ifndef __REACTOS__
+ HWND hHeader;
+#endif
+ UINT uNext;
+ UINT uCol;
+ UINT uSub;
+ int iSize;
+ int iNum;
+ int iNow;
+ int iOld;
+ int iRet;
+
+#ifndef __REACTOS__
+ hHeader = pData->hHeader;
+#endif
+ pData->aColumnXpos[0] = 0;
+
+ iRet = 0x10000;
+ iOld = 0;
+ iNow = 0;
+
+ for(uCol = 0; uCol < pData->uColumnCount;) { // Suche die erste ge�nderte
Spalte
+ uSub = pData->aColumnPos[uCol];
+ iSize = pData->aColumn[uSub].sReal;
+ uSub = pData->aColumn[uSub].bNext;
+ iOld = iNow;
+ iNow += iSize;
+ uCol += 1;
+
+ if(uCol == 1)
+ iNow -= 1;
+ if(iNow < iOld)
+ iNow = iOld;
+ if(uSub == pData->uColumnCount)
+ if(iNow >= (int)pData->uSizeX - 1) {
+ iNow++;
+ }
+
+ iNum = pData->aColumnXpos[uSub];
+
+ if(iNum == iNow)
+ continue;
+ if(iNum == 0)
+ iNum = iOld;
+ if(iNum >= iNow) {
+ iRet = iOld;
+ } else {
+ iRet = iOld;
+
+ if(pData->uSelectedItem) { // Problem bei ausgew�hlten leeren Eintr�gen
+ uNext = pData->aColumn[pData->uSelectedSub].bNext;
+ if(uNext == uSub) {
+ UpdateRect(pData, pData->uSelectedItem, pData->uSelectedSub);
+ }
+ }
+
+ if(pData->uTrackedItem) {
+ uNext = pData->aColumn[pData->uTrackedSub].bNext;
+ if(uNext == uSub) {
+ UpdateRect(pData, pData->uTrackedItem, pData->uTrackedSub);
+ }
+ }
+ }
+
+ pData->aColumnXpos[uSub] = iNow;
+ break;
+ }
+
+ while(uCol < pData->uColumnCount) { // Restliche Spalten berechen
+ iOld = iNow;
+ uSub = pData->aColumnPos[uCol];
+ iNow += pData->aColumn[uSub].sReal;
+ uSub = pData->aColumn[uSub].bNext;
+ uCol += 1;
+
+ if(uCol == pData->uColumnCount)
+ if(iNow >= (int)pData->uSizeX - 1) {
+ iNow++;
+ }
+
+ pData->aColumnXpos[uSub] = iNow;
+ }
+
+ pData->aColumnXpos[pData->uColumnCount + 1] = pData->uSizeX + 1;
+
+ return iRet;
+}
+
+//*****************************************************************************
+//*
+//* TreeListSetOrderArray
+//*
+//*****************************************************************************
+// Stellt die anzeige Reihenfolge der Spalten ein
+// pData : Zeiger auf die Fensterdaten
+// uItems : Ist die Nummer des Eintrages
+// pArray : Zeiger auf die Eintr�ge. Null steht f�r die Standartreihenfolge.
+// z.B. {0,2,1} meint die sichtbare Reihenfolge Col0,Col2,Col1
+// Der erste Eintrag muss 0 immer sein.
+// Ergibt 1 = Ok
+// 0 = Fehler
+static int TreeListSetOrderArray(TreeListData *pData, unsigned uItems, unsigned *pArray)
{
+
+ BYTE aFlags[MAX_COLUMNS + 1];
+ UINT aArray[MAX_COLUMNS + 1];
+ TV_COLSIZE sNotify;
+ UINT uDiff;
+ UINT uCol;
+ UINT uSub;
+
+ if(!pArray) { // Spezialreihenfolge setzen
+ if(uItems == FROM_HEADER) { // Array aus Header holen
+ if(!Header_GetOrderArray(pData->hHeader, pData->uColumnCount, aArray)) {
+ return 0;
+ }
+
+ if(aArray[0] != 0) {
+ return 0;
+ }
+ } else {
+ for(uCol = pData->uColumnCount; uCol > 0; uCol++) { // Standartreihenfolge
+ uCol--;
+ aArray[uCol] = uCol;
+ }
+ }
+
+ uItems = pData->uColumnCount;
+ pArray = aArray;
+ } else { // Pr�fe Array
+ if(pData->uColumnCount != uItems || uItems == 0 || *pArray) {
+ return 0;
+ }
+ }
+
+ memset(aFlags, 0, sizeof(aFlags) - 1);
+
+ for(uCol = 0, uDiff = 0; uCol < uItems; uCol++) { // Die Eintr�ge pr�fen
+ uSub = pArray[uCol];
+ if(uSub >= uItems)
+ return 0;
+ if(aFlags[uSub])
+ return 0;
+
+ aFlags[uSub] = (BYTE)uCol;
+
+ uDiff |= uCol ^ pData->aColumnPos[uSub];
+ }
+
+ if(uDiff == 0) { // Alles blieb gleich
+ return 1;
+ }
+
+ aFlags[0 ] = 0;
+ aFlags[uItems] = (BYTE)uItems;
+
+ for(uCol = 1; uCol < uItems; uCol++) { // Die Eintr�ge anpassen
+ pData->aColumnPos[uCol] = (BYTE)pArray[uCol];
+ }
+
+ for(uCol = 0; uCol < uItems; uCol++) {
+ uSub = aFlags[uCol];
+ pData->aColumn[uCol].bIndex = (BYTE)uSub;
+ pData->aColumn[uCol].bNext = pData->aColumnPos[uSub + 1];
+ }
+
+ Header_SetOrderArray(pData->hHeader, uItems, pArray);
+ UpdateColumns(pData);
+ UpdateView(pData);
+
+ if(pData->uStyleEx & TVS_EX_HEADERCHGNOTIFY) { // Alle Spalten haben sich
ver�ndert
+ UNLOCK(pData);
+
+ for(uCol = 0; uCol < uItems; uCol++) {
+ sNotify.hdr.code = TVN_COLUMNCHANGED;
+ sNotify.uColumn = uCol;
+ sNotify.uIndex = pData->aColumn[uCol].bIndex;
+ sNotify.uPosX = pData->aColumnXpos[uCol];
+ sNotify.iSize = pData->aColumn[uCol].sReal;
+
+ SendNotify(pData, &sNotify.hdr);
+ }
+
+ LOCK(pData);
+ }
+
+ return 1;
+}
+
+//*****************************************************************************
+//*
+//* TreeListToggleItem
+//*
+//*****************************************************************************
+// Klappt bei einem Eintrag die Kinder um, und schickt alle Notify-Nachrichten.
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages
+// uAddFlags : Sind die State-Flags die hinzugef�gt werden sollen
+// Bits 0..3 entahlen das Kommando, bei automatisch ermitteln
+// Ergibt -1 = Fehler
+// 0 = Ausgef�hrt
+// 1 = Abbruch
+static int TreeListToggleItem(TreeListData *pData, unsigned uItem, unsigned uAddFlags) {
+
+ NMTREEVIEW sNotify;
+ BaseItem **pList;
+ BaseItem *pEntry;
+ BaseItem *pTemp;
+ unsigned uAction;
+ unsigned uLevel;
+ unsigned uNext;
+ LRESULT lRet;
+ BOOL bDo;
+
+ if(uItem > pData->uTreeItemsMax)
+ return 0;
+
+ pList = pData->pTreeItems;
+ pEntry = pList[uItem];
+ if(!pEntry)
+ return -1;
+
+ uAction = uAddFlags & 0x0F;
+ if(!uAction) {
+ uAction = ((pEntry->uState ^ TVIS_EXPANDED) & (TVIS_EXPANDED |
TVIS_EXPANDPARTIAL)) ? TVE_EXPAND : TVE_COLLAPSE;
+ }
+
+ sNotify.action = uAction;
+ sNotify.hdr.code = TVN_ITEMEXPANDING;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = pEntry->uState;
+ sNotify.itemNew.lParam = pEntry->lParam;
+ sNotify.itemNew.pszText = (LPTSTR) - 1;
+ sNotify.itemNew.cchTextMax = -1;
+ sNotify.itemOld.mask = 0;
+ sNotify.ptDrag.x = 0;
+ sNotify.ptDrag.y = 0;
+
+ UNLOCK(pData);
+
+ lRet = SendNotify(pData, &sNotify.hdr);
+
+ LOCK(pData);
+
+ pList = pData->pTreeItems;
+ pEntry = pList[uItem];
+
+ if(pEntry == 0)
+ return -1; // Eintrag inzischen gel�scht ?
+ if(lRet != 0)
+ return 1; // User-Abbruch ?
+
+ if(uAction == TVE_EXPAND) { // Aufklappen
+ if(pEntry->uState & TVIS_EXPANDED) {
+ bDo = FALSE; // Nur von + auf -
+ } else {
+ pEntry->uState |= TVIS_EXPANDED; // Kinder Aufklappen
+ bDo = TRUE;
+ }
+ } else { // Zuklappen
+ pEntry->uState &= ~TVIS_EXPANDED;
+ bDo = TRUE;
+ }
+
+ pEntry->uState &= ~TVIS_EXPANDPARTIAL;
+ pEntry->uState |= uAddFlags&~0x0F;
+
+ if(pEntry->uShowPos && bDo) {
+ if(pEntry->uState & TVIS_EXPANDED) { // Kinderfenster aktuallisieren
+ uLevel = 0;
+ uNext = pEntry->uFirstChild;
+
+ while(uNext) {
+ pTemp = pList[uNext];
+ pTemp->uShowPos = 0;
+
+ if(pTemp->uFirstChild) {
+ uNext = pTemp->uFirstChild;
+ uLevel++;
+ continue;
+ }
+
+ if(pTemp->uNextItem) {
+ uNext = pTemp->uNextItem;
+ continue;
+ }
+
+ if(uLevel == 0)
+ break;
+
+ uNext = pList[pTemp->uParent]->uNextItem;
+ uLevel--;
+ }
+ }
+
+ UpdateItems(pData, uItem);
+ }
+
+ sNotify.action = uAction;
+ sNotify.hdr.code = TVN_ITEMEXPANDED;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = pEntry->uState;
+ sNotify.itemNew.lParam = pEntry->lParam;
+ sNotify.itemNew.pszText = (LPTSTR) - 1;
+ sNotify.itemNew.cchTextMax = -1;
+ sNotify.itemOld.mask = 0;
+ sNotify.ptDrag.x = 0;
+ sNotify.ptDrag.y = 0;
+
+ UNLOCK(pData);
+
+ SendNotify(pData, &sNotify.hdr);
+
+ LOCK(pData);
+
+ pList = pData->pTreeItems;
+ pEntry = pData->pTreeItems[uItem];
+
+ if(!pEntry)
+ return -1; // Eintrag inzischen gel�scht ?
+
+ if(uAction == TVE_EXPAND) { // ONCE setzen nach Expandieren
+ pEntry->uState |= TVIS_EXPANDEDONCE;
+ }
+
+ if(pData->uSelectedItem && bDo) { // Ist der ausgew�hlten Eintrag
sichtbar ?
+ pEntry = pList[pData->uSelectedItem];
+ if(!pEntry) {
+ pData->uSelectedItem = 0;
+ pData->uSelectedSub = 0;
+ } else
+ if(!pEntry->uShowPos) {
+ while(!pEntry->uShowPos) {
+ uItem = pEntry->uParent;
+ pEntry = pList[uItem];
+ }
+
+ TreeListSelectItem(pData, uItem, pData->uSelectedSub, TVC_UNKNOWN);
+ }
+ }
+
+ if(bDo == FALSE) { // Nur von + auf -
+ UpdateRect(pData, uItem, 0);
+ }
+
+ return 0;
+}
+
+//*****************************************************************************
+//*
+//* TreeListGetItemRect
+//*
+//*****************************************************************************
+// Holt das Rechteck eines Eintrages
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages
+// uFlags : Bit 0 : 0=volle Zeile 1=nur Text
+// Bit 7 : 1=nur Spalte
+// Bit 24.. : Spaltennummer
+// Ergibt 1 wenn der Eintrag sichtbar war
+static int TreeListGetItemRect(TreeListData *pData, unsigned uItem, unsigned uFlags, RECT
*pRect) {
+
+ ExtraItem *pExtra;
+ BaseItem *pEntry;
+ unsigned uNext;
+ unsigned uPos;
+ unsigned uSub;
+
+ if(uItem > pData->uTreeItemsMax) {
+ memset(pRect, 0, sizeof(RECT));
+ return 0;
+ }
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry->uShowPos) { // Ist der Eintrag aufgeklappt
+ memset(pRect, 0, sizeof(RECT));
+ return 0;
+ }
+
+ uPos = pEntry->uShowPos - pData->uScrollY - 1;
+ if(uPos >= pData->uMaxEnties) { // Eintrag im Fenster sichtbar
+ memset(pRect, 0, sizeof(RECT));
+ return 0;
+ }
+
+ pRect->top = pData->uStartPixel;
+ pRect->top += pData->iRowHeight * uPos;
+ pRect->bottom = pData->iRowHeight + pRect->top;
+
+ if((uFlags & 0xFC) == TVIR_GETCOLUMN) { // Nur Spalten
+ uSub = uFlags >> 24;
+ if(uSub >= pData->uColumnCount)
+ uSub = 0;
+
+ uNext = pData->aColumn[uSub].bNext;
+ pRect->left = pData->aColumnXpos[uSub];
+ pRect->left -= pData->uScrollX;
+ pRect->right = pData->aColumnXpos[uNext];
+ pRect->right -= pData->uScrollX;
+ } else {
+ uSub = 0;
+ pRect->left = 0;
+ pRect->left -= pData->uScrollX;
+ pRect->right = pData->uSizeX;
+ }
+
+ if(uFlags & TVIR_TEXT) { // Nur Text ausgeben
+ if(uSub > 0) {
+ pExtra = pData ->pExtraItems[uSub - 1][uItem];
+
+ if(pData->aColumn[uSub].bEdit == TVAX_CHECK) {
+ pRect->left += pData->iChecksXsize;
+ if(pRect->left > pRect->right)
+ pRect->left = pRect->right;
+ } else
+ if(pExtra && pExtra->bFlags & TVIX_HASIMAGE) {
+ pRect->left += pData->iImagesXsize;
+ if(pRect->left > pRect->right)
+ pRect->left = pRect->right;
+ }
+ } else {
+ if(pData->cHasRootRow) { // Root-Linien ausgleichen
+ pRect->left += pData->iIndent;
+ }
+
+ pRect->left += pData->iIndent * pEntry->uLevel;
+
+ if(pData->hStates) {
+ pRect->left += pData->iStatesXsize;
+ }
+
+ if(!(pData->uStyle & TVS_HASLINES)) {
+ pRect->left -= 1;
+ }
+
+ if(pData->uStyleEx & TVS_EX_ITEMLINES) {
+ pRect->left += 1;
+ if(pEntry->bFlags & TVIX_HASIMAGE)
+ pRect->left++;
+ }
+
+ if(pEntry->bFlags & TVIX_HASIMAGE) {
+ pRect->left += pData->iImagesXsize;
+ }
+
+ if(pRect->left > pRect->right) {
+ pRect->left = pRect->right;
+ }
+ }
+ }
+
+ return 1;
+}
+
+//*****************************************************************************
+//*
+//* TreeListEnsureVisible
+//*
+//*****************************************************************************
+// Macht einen Eintrag sichtbar
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages
+// uSub : Untereintrag der sichtbar sein soll
+// 0xFFFFFFFF nur Zeile
+// FIRST_LINE als oberster Eintrag
+// Ergibt 1 wenn nur zum Eintrag gescrollt wurde bzw. 0 wenn aufgeklapt wurde
+static int TreeListEnsureVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
+
+ BaseItem *pEntry;
+ BaseItem *pTemp;
+ unsigned uTemp;
+ unsigned uNext;
+ unsigned uPos;
+ int iNum;
+ int iAnf;
+ int iOff;
+ int iEnd;
+ int iMax;
+ int iRet;
+
+ if(uItem > pData->uTreeItemsMax)
+ return -1;
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return -1;
+
+ uPos = pEntry->uShowPos;
+ if(!uPos) { // Zweige aufklappen wenn Eintrag zugeklappt
+
+ iRet = 0;
+
+ for(pTemp = pEntry;;) {
+ uTemp = pTemp->uParent;
+ pTemp = pData->pTreeItems[uTemp];
+ if(!pTemp)
+ break;
+ if((pTemp->uState & TVIS_EXPANDED) == 0) {
+ if(TreeListToggleItem(pData, uTemp, 0))
+ return 0;
+ }
+ }
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+
+ uPos = pEntry->uShowPos;
+ if(!uPos)
+ return 0;
+ } else { // Nur Scrollen
+ iRet = 1;
+ }
+
+ uPos--;
+ if(uPos < pData->uScrollY) { // Vor erster Zeile
+ pData->uScrollY = uPos;
+ SetScrollPos(pData->hWnd, SB_VERT, uPos, TRUE);
+ UpdateView(pData);
+ } else
+ if(uSub == FIRST_LINE) { // Als ersten Eintrag
+ if(uPos != pData->uScrollY) {
+ pData->uScrollY = uPos;
+ SetScrollPos(pData->hWnd, SB_VERT, uPos, TRUE);
+ UpdateView(pData);
+ }
+
+ return iRet;
+ } else
+ if(uPos >= pData->uScrollY + pData->uPageEnties) { // Nach letzter Zeile
+ iOff = uPos - (pData->uPageEnties - 1);
+ iMax = pData->uItemPosCount;
+ iMax -= pData->uPageEnties - 1;
+
+ if(iOff >= iMax)
+ iOff = iMax;
+ if(iOff < 0)
+ iOff = 0;
+ if(iOff != (int)pData->uScrollY) {
+ pData->uScrollY = iOff;
+ SetScrollPos(pData->hWnd, SB_VERT, iOff, TRUE);
+ UpdateView(pData);
+ }
+ }
+
+ if(uSub < pData->uColumnCount) { // Horizontal einrichten
+ uNext = pData->aColumn[uSub].bNext;
+ iNum = pData->uSizeX;
+ iOff = pData->uScrollX;
+ iAnf = pData->aColumnXpos[uSub ];
+ iEnd = pData->aColumnXpos[uNext];
+
+ if(iOff + iNum < iAnf)
+ iOff = iAnf;
+ if(iOff >= iEnd)
+ iOff = iAnf;
+ if(iOff + iNum < iEnd)
+ iOff = iEnd - iNum;
+ if(iOff > iAnf)
+ iOff = iAnf;
+
+ iMax = pData->aColumnXpos[pData->uColumnCount];
+ iMax -= pData->uSizeX / 2;
+
+ if(iOff > iMax)
+ iOff = iMax;
+ if(iOff < 0)
+ iOff = 0;
+ if(iOff != (int)pData->uScrollX) {
+ pData->uScrollX = iOff;
+ SetScrollPos(pData->hWnd, SB_HORZ, iOff, TRUE);
+ UpdateView(pData);
+ MoveWindow(pData->hHeader, -iOff, 0, iNum + iOff, pData->uStartPixel, TRUE);
+ }
+ }
+ return iRet;
+}
+
+//*****************************************************************************
+//*
+//* TreeListIsVisible
+//*
+//*****************************************************************************
+// Pr�ft ob ein Eintrag sichtbar ist
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages
+// uSub : Untereintrag der gepr�ft werden soll
+// 0xFFFFFFFF nur Zeile pr�fen
+// Ergibt den Zustand des Eintrages:
+// -1 = Unbekannter Eintrag
+// 0 = Eintrag ist zugeklappt
+// 1 = Eintrag ist aufgeklappt aber nicht sichtbar
+// 2 = Eintrag ist aufgeklappt und teilweise sichtbar
+// 3 = Eintrag ist aufgeklappt und Spalte ist nur teilweise sichtbar
+// 4 = Eintrag ist aufgeklappt und ganz sichtbar
+static int TreeListIsVisible(TreeListData *pData, unsigned uItem, unsigned uSub) {
+
+ BaseItem *pEntry;
+ unsigned uNext;
+ unsigned uPos;
+ int iNum;
+ int iAnf;
+ int iOff;
+ int iEnd;
+
+ if(uItem > pData->uTreeItemsMax)
+ return -1;
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return -1;
+
+ uPos = pEntry->uShowPos;
+ if(!uPos) { // Ist der Eintrag zugeklappt
+ return 0;
+ }
+
+ uPos--;
+ if(uPos < pData->uScrollY) { // Vor erster Zeile
+
+ return 1;
+ }
+
+ if(uPos >= pData->uScrollY + pData->uMaxEnties) { // Nach letzter Zeile
+ return 1;
+ }
+
+ if(uPos == pData->uScrollY + pData->uPageEnties) { // Auf halbsichtbarer Zeile
+ if(uSub < pData->uColumnCount) {
+ uNext = pData->aColumn[uSub].bNext;
+ iNum = pData->uSizeX;
+ iOff = pData->uScrollX;
+ iAnf = pData->aColumnXpos[uSub ];
+ iEnd = pData->aColumnXpos[uNext];
+
+ if(iOff + iNum < iAnf)
+ return 1;
+ if(iOff >= iEnd)
+ return 1;
+ }
+
+ return 2;
+ }
+
+ if(uSub < pData->uColumnCount) { // Spalte pr�fen
+ uNext = pData->aColumn[uSub].bNext;
+ iNum = pData->uSizeX;
+ iOff = pData->uScrollX;
+ iAnf = pData->aColumnXpos[uSub ];
+ iEnd = pData->aColumnXpos[uNext];
+
+ if(iOff + iNum < iAnf)
+ return 1;
+ if(iOff >= iEnd)
+ return 1;
+ if(iOff + iNum < iEnd)
+ return 3;
+ if(iOff > iAnf)
+ return 3;
+ }
+
+ return 4;
+}
+
+//*****************************************************************************
+//*
+//* TreeListDeleteItem
+//*
+//*****************************************************************************
+// L�scht einen Eintrag aus dem Fenster
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages der gel�scht werden soll
+// iMode : Wie soll der Eintrag gel�scht werden
+// 0 = Eintrag l�schen und nicht neu zeichnen
+// 1 = Eintrag l�schen und neu zeichnen
+// 2 = Nur Kindereintr�ge l�schen und neu zeichnen
+// Ergibt 1 wenn der Eintrag gel�scht wurde.
+static int TreeListDeleteItem(TreeListData *pData, unsigned uItem, int iMode) {
+
+ NMTREEVIEW sNotify;
+ ExtraItem **pList;
+ ExtraItem *pExtra;
+ BaseItem *pEntry;
+ BaseItem *pTemp;
+ unsigned uPos;
+ int iOff;
+ int iMax;
+
+ if(pData->cLockChanges)
+ return 0;
+
+ if(uItem > pData->uTreeItemsMax) { // Pr�fe den Eintrag
+ if(uItem != U(TVI_ROOT))
+ return 0; // Alles l�schen
+ if(pData->uLastChild == 0)
+ return 0;
+
+ while(pData->uLastChild) {
+ TreeListDeleteItem(pData, pData->uLastChild, 0);
+ }
+
+ pData->uItemPosCount = 0;
+
+ UpdateScrollY(pData);
+ UpdateView(pData);
+
+ return 1;
+ }
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry) { // Pr�fe den Eintrag
+ if(uItem != 0)
+ return 0; // Alles l�schen
+ if(pData->uLastChild == 0)
+ return 0;
+
+ while(pData->uLastChild) {
+ TreeListDeleteItem(pData, pData->uLastChild, 0);
+ }
+
+ pData->uItemPosCount = 0;
+
+ UpdateScrollY(pData);
+ UpdateView(pData);
+
+ return 1;
+ }
+
+ if(iMode == 2) { // Nur Kindereintr�ge l�schen
+ if(!pEntry->uFirstChild) {
+ return 0;
+ }
+
+ while(pEntry->uLastChild) { // Alle Kinder l�schen
+ TreeListDeleteItem(pData, pEntry->uLastChild, 0);
+ }
+
+ uPos = pEntry->uShowPos;
+ if(uPos) {
+ UpdateItems(pData, uItem);
+ }
+
+ return 1;
+ }
+
+ while(pEntry->uLastChild) { // Alle Kinder l�schen
+ TreeListDeleteItem(pData, pEntry->uLastChild, 0);
+ }
+
+ if(uItem == pData->uSelectedItem) { // Einen ausgew�hlten Eintrag l�schen
+ sNotify.hdr.code = TVN_SELCHANGED;
+ sNotify.action = TVC_UNKNOWN;
+ sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemOld.hItem = (HTREEITEM)uItem;
+ sNotify.itemOld.stateMask = 0xFFFFFFFF;
+ sNotify.itemOld.state = pEntry->uState&~TVIS_SELECTED;
+ sNotify.itemOld.lParam = pEntry->lParam;
+ sNotify.itemOld.cChildren = 0;
+ sNotify.itemOld.pszText = (LPTSTR) - 1;
+ sNotify.itemOld.cchTextMax = -1;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemNew.hItem = NULL;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = 0;
+ sNotify.itemNew.lParam = 0;
+ sNotify.itemNew.cChildren = 0;
+ sNotify.itemNew.pszText = (LPTSTR) - 1;
+ sNotify.itemNew.cchTextMax = -1;
+ sNotify.ptDrag.x = 0;
+ sNotify.ptDrag.y = 0;
+
+ UNLOCK(pData);
+ SendNotify(pData, &sNotify.hdr); // Bekant geben das der Eintrag nicht mehr
ausgew�hlt ist
+ LOCK(pData);
+
+ pData->uSelectedItem = 0;
+ pData->uSelectedSub = 0;
+ }
+
+ sNotify.hdr.code = TVN_DELETEITEM;
+ sNotify.itemNew.mask = 0;
+ sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ sNotify.itemOld.hItem = (HTREEITEM)uItem;
+ sNotify.itemOld.lParam = pEntry->lParam;
+ sNotify.itemOld.pszText = (LPTSTR) - 1;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = pEntry->uState;
+ sNotify.itemOld.cchTextMax = -1;
+ sNotify.ptDrag.x = 0;
+ sNotify.ptDrag.y = 0;
+
+ UNLOCK(pData);
+ SendNotify(pData, &sNotify.hdr);
+ LOCK(pData);
+
+ pEntry = pData->pTreeItems[uItem]; // Pr�fen ob der Eintrag noch existiert
+ if(!pEntry)
+ return 0;
+
+ if(uItem == pData->uTrackedItem) { // Einen unterstrichenen Eintrag l�schen
+ pData->uTrackedItem = 0;
+ pData->uTrackedSub = 0;
+ }
+
+ if(pData->uInsertMark == uItem) {
+ pData->uInsertMark = 0;
+ }
+
+ if(pData->uSingleSel == uItem) {
+ pData->uSingleSel = 0;
+ }
+
+ if(pEntry->uPrevItem) { // Gibt es einen vorherigen Eintrag
+ pTemp = pData->pTreeItems[pEntry->uPrevItem];
+ pTemp->uNextItem = pEntry->uNextItem;
+ } else {
+ if(pEntry->uParent) { // Neues erstes Kind in Elterneintrag
+ pTemp = pData->pTreeItems[pEntry->uParent];
+ pTemp->uFirstChild = pEntry->uNextItem;
+ } else {
+ pData->uFirstChild = pEntry->uNextItem;
+ }
+ }
+
+ if(pEntry->uNextItem) { // Gibt es einen vorherigen Eintrag
+ pTemp = pData->pTreeItems[pEntry->uNextItem];
+ pTemp->uPrevItem = pEntry->uPrevItem;
+ } else {
+ if(pEntry->uParent) { // Neues letztes Kind in Elterneintrag
+ pTemp = pData->pTreeItems[pEntry->uParent];
+ pTemp->uLastChild = pEntry->uPrevItem;
+
+ if(pTemp->uFirstChild == 0 && pTemp->uLastChild == 0) {
+ pTemp->bFlags &= ~TVIX_HASBUTTON;
+ }
+ } else {
+ pData->uLastChild = pEntry->uPrevItem;
+ }
+ }
+
+ for(uPos = 1; uPos < pData->uColumnCount; uPos++) { // Alle Extraeintr�ge
l�schen
+ pList = pData->pExtraItems[uPos - 1];
+
+ pExtra = pList[uItem];
+ if(!pExtra)
+ continue;
+
+ pList[uItem] = NULL;
+
+ if(pExtra->pText) {
+ pExtra->uTextSize = 0;
+ delete(pExtra->pText);
+ }
+
+ delete(pExtra);
+ }
+
+
+ pData->pTreeItems[uItem] = NULL; // Den Eintrag l�schen
+
+ if(pEntry->pText) {
+ pEntry->uTextSize = 0;
+ delete(pEntry->pText);
+ }
+
+ if(iMode) { // Den Eintrag neuzeichnen
+ uItem = pEntry->uPrevItem;
+ if(!uItem && !pEntry->uNextItem) {
+ uItem = pEntry->uParent;
+ if(!uItem)
+ uPos = 1;
+ else
+ uPos = pData->pTreeItems[uItem]->uShowPos;
+ } else {
+ uPos = pEntry->uShowPos;
+ }
+
+ if(uPos) {
+ UpdateItems(pData, uItem);
+ }
+ }
+
+ if(pEntry->uState & TVIS_SELECTED) // Ausgew�hlte Eintr�ge runterz�hlen
+ if(pData->uSelectedCount > 0) {
+ pData->uSelectedCount--;
+ }
+
+ delete(pEntry);
+
+ pData->uTreeItemsCount--;
+
+ iOff = pData->uScrollY; // Pr�fe die Scrollposition
+ iMax = pData->uItemPosCount;
+ iMax -= pData->uPageEnties - 1;
+
+ if(iOff >= iMax)
+ iOff = iMax;
+ if(iOff < 0)
+ iOff = 0;
+ if(iOff != (int)pData->uScrollY) {
+ pData->uScrollY = iOff;
+ SetScrollPos(pData->hWnd, SB_VERT, iOff, TRUE);
+ UpdateView(pData);
+ }
+
+ return 1;
+}
+
+//*****************************************************************************
+//*
+//* TreeListXorSelectItem
+//*
+//*****************************************************************************
+// W�hlt einen Eintrag ab bzw. an
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages der ausgew�hlt werden soll
+// iMode : Ist der Grund f�r die �nderung
+// TVC_BYKEYBOARD
+// TVC_BYMOUSE
+// TVC_UNKNOWN
+// Ergibt 1 wenn der Eintrag ab/angew�hlt wurde
+// 0 wenn der Eintrag nicht ver�ndert wurde
+static int TreeListXorSelectItem(TreeListData *pData, unsigned uItem, int iMode) {
+
+ NMTREEVIEW sNotify;
+ BaseItem *pEntry;
+ unsigned uOld;
+ unsigned uRet;
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+ if(uItem == pData->uSelectedItem)
+ return 0;
+
+ uOld = pEntry->uState;
+
+ sNotify.hdr.code = TVN_SELCHANGING;
+ sNotify.action = iMode;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = pEntry->uState;
+ sNotify.itemNew.lParam = pEntry->lParam;
+ sNotify.itemNew.cChildren = 0;
+ sNotify.itemNew.pszText = (LPTSTR) - 1;
+ sNotify.itemNew.cchTextMax = -1;
+ sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemOld.hItem = NULL;
+ sNotify.itemOld.stateMask = 0xFFFFFFFF;
+ sNotify.itemOld.state = 0;
+ sNotify.itemOld.lParam = 0;
+ sNotify.itemOld.cChildren = 0;
+ sNotify.itemOld.pszText = (LPTSTR) - 1;
+ sNotify.itemOld.cchTextMax = -1;
+ sNotify.ptDrag.x = 0;
+ sNotify.ptDrag.y = 0;
+
+ UNLOCK(pData);
+ uRet = U(SendNotify(pData, &sNotify.hdr));
+ LOCK(pData);
+
+ if(uRet)
+ return 0;
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+ pEntry->uState ^= TVIS_SELECTED;
+
+ sNotify.hdr.code = TVN_SELCHANGED;
+ sNotify.action = iMode;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = pEntry->uState;
+ sNotify.itemNew.lParam = pEntry->lParam;
+ sNotify.itemNew.cChildren = 0;
+ sNotify.itemNew.pszText = (LPTSTR) - 1;
+ sNotify.itemNew.cchTextMax = -1;
+ sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemOld.hItem = NULL;
+ sNotify.itemOld.stateMask = 0xFFFFFFFF;
+ sNotify.itemOld.state = 0;
+ sNotify.itemOld.lParam = 0;
+ sNotify.itemOld.cChildren = 0;
+ sNotify.itemOld.pszText = (LPTSTR) - 1;
+ sNotify.itemOld.cchTextMax = -1;
+ sNotify.ptDrag.x = 0;
+ sNotify.ptDrag.y = 0;
+
+ UNLOCK(pData);
+ SendNotify(pData, &sNotify.hdr);
+ LOCK(pData);
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+ if(pEntry->uShowPos) {
+ if(pData->uStyleEx & TVS_EX_FULLROWMARK)
+ UpdateRow(pData, uItem);
+ else
+ UpdateRect(pData, uItem, 0);
+ }
+
+ if((uOld ^ pEntry->uState)&TVIS_SELECTED) {
+ if(pEntry->uState & TVIS_SELECTED)
+ pData->uSelectedCount++;
+ else
+ pData->uSelectedCount--;
+ }
+
+ return 1;
+}
+
+
+//*****************************************************************************
+//*
+//* TreeListRemoveFocus
+//*
+//*****************************************************************************
+// W�hlt den Focus ab
+// pData : Zeiger auf die Fensterdaten
+static void TreeListRemoveFocus(TreeListData *pData) {
+
+ ExtraItem *pExtra;
+ BaseItem *pEntry;
+ unsigned uItem;
+ unsigned uSub;
+
+ if(!pData->uFocusItem)
+ return;
+
+ uItem = pData->uFocusItem;
+ pEntry = pData->pTreeItems[uItem];
+
+ if(pEntry) {
+ pEntry->bFlags &= ~TVIX_FOCUSED;
+
+ uSub = pData->uFocusSub;
+
+ if(uSub) {
+ pExtra = pData->pExtraItems[uSub - 1][uItem];
+ if(pExtra)
+ pExtra->bFlags &= ~TVIX_FOCUSED;
+ }
+
+ UpdateRect(pData, uItem, uSub);
+ }
+
+ pData->uFocusItem = 0;
+ pData->uFocusSub = 0;
+}
+
+//*****************************************************************************
+//*
+//* TreeListSetFocus
+//*
+//*****************************************************************************
+// W�hlt den Focus-Eintrag
+// pData : Zeiger auf die Fensterdaten
+// uItem : Eintrag f�r den Focus (0xFFFFFFFF=keine �nderung)
+// uSub : Spalte f�r den Focus (0xFFFFFFFF=keine �nderung)
+// Ergibt 1 wenn der Focus gesetzt wurde, bzw 0 bei einem Fehler
+static int TreeListSetFocus(TreeListData *pData, unsigned uItem, unsigned uSub) {
+
+ ExtraItem *pExtra;
+ BaseItem *pEntry;
+ BaseItem *pTemp;
+ unsigned uTemp;
+ unsigned uCol;
+
+ if(pData->uFocusItem) {
+ if(uSub == 0xFFFFFFFF)
+ uSub = pData->uFocusSub;
+ if(uItem == 0xFFFFFFFF)
+ uItem = pData->uFocusItem;
+ } else {
+ if(uSub == 0xFFFFFFFF)
+ uSub = pData->uSelectedSub;
+ if(uItem == 0xFFFFFFFF)
+ uItem = pData->uSelectedItem;
+ }
+
+ if(pData->uFocusItem == uItem)
+ if(pData->uFocusSub == uSub)
+ return 1;
+
+ if(!uItem) { // Focus abw�hlen
+ TreeListRemoveFocus(pData);
+ return 1;
+ }
+
+
+ if(uItem > pData->uTreeItemsMax) { // Den Eintrag pr�fen
+ return 0;
+ }
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry) {
+ return 0;
+ }
+
+ if(!(pData->uStyleEx & TVS_EX_SUBSELECT))
+ uSub = 0;
+
+ if(!(pData->uStyleEx & TVS_EX_MULTISELECT)) { // Einzel auswahl
+ return TreeListSelectItem(pData, uItem, uSub, TVC_UNKNOWN);
+ }
+
+ uTemp = pData->uFocusItem;
+ pTemp = pData->pTreeItems[uTemp];
+
+ if(pTemp) { // Den alten Eintrag abw�hlen
+ pTemp->bFlags &= ~TVIX_FOCUSED;
+ uCol = pData->uFocusSub;
+
+ if(uCol) {
+ pExtra = pData->pExtraItems[uCol - 1][uTemp];
+ if(pExtra)
+ pExtra->bFlags &= ~TVIX_FOCUSED;
+ }
+
+ UpdateRect(pData, uItem, uSub);
+ }
+
+
+ if(uSub) { // Neuen Eintrag w�hlen
+ pExtra = pData->pExtraItems[uSub - 1][uItem];
+ if(pExtra)
+ pExtra->bFlags |= TVIX_FOCUSED;
+ } else {
+ pEntry->bFlags |= TVIX_FOCUSED;
+ }
+
+ pData->uFocusItem = uItem;
+ pData->uFocusSub = uSub;
+
+ if(pEntry->uState & TVIS_SELECTED) { // Auch die Auswahl nachziehen
+ if(pData->uSelectedItem != uItem) {
+ uTemp = pData->uSelectedItem;
+ uCol = pData->uSelectedSub;
+ } else {
+ uTemp = 0;
+ uCol = pData->uSelectedSub;
+ }
+
+ pData->uSelectedItem = uItem;
+ pData->uSelectedSub = uSub;
+
+ if(pData->uStyleEx & TVS_EX_FULLROWMARK) {
+ uCol = uSub + 1;
+ }
+
+ if(uTemp) {
+ if(uCol != uSub)
+ UpdateRow(pData, uTemp);
+ else
+ UpdateRect(pData, uTemp, uCol);
+ }
+
+
+ if(uCol != uSub)
+ UpdateRow(pData, uItem);
+ else
+ UpdateRect(pData, uItem, uCol);
+ } else {
+ UpdateRect(pData, uItem, uSub);
+ }
+
+ return 1;
+}
+
+//*****************************************************************************
+//*
+//* TreeListSelectItem
+//*
+//*****************************************************************************
+// W�hlt einen Eintrag aus
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages der ausgew�hlt werden soll
+// uSubItem : Ist die Spalte die gew�hlt werden soll
+// iMode : Ist der Grund f�r die �nderung
+// TVC_BYKEYBOARD
+// TVC_BYMOUSE
+// TVC_UNKNOWN
+// TVC_ONLYFOCUS (nur der Focus hat sich ver�ndert)
+// TVC_DESELECT (dieses Flag l�scht die alte Auswahl)
+// TVC_UNSELECT (dieses Flag l�scht Auswahl bei MultiSel)
+// Ergibt 2 wenn der Eintrag gew�hlt und umgeklapt wurde
+// 1 wenn der Eintrag gew�hlt wurde
+// 0 wenn der Eintrag nicht gew�hlt wurde
+static int TreeListSelectItem(TreeListData *pData, unsigned uItem, unsigned uSubItem, int
iMode) {
+
+ NMTREEVIEW sNotify;
+ ExtraItem *pExtra;
+ BaseItem *pEntry;
+ BaseItem *pTemp;
+ LPARAM lParam;
+ LPARAM lPaOld;
+ unsigned uState;
+ unsigned uStOld;
+ unsigned uNext;
+ unsigned uPos;
+ unsigned uOld;
+ unsigned uSub;
+ unsigned uRet;
+ int iDel;
+ int iSel;
+
+ uOld = pData->uSelectedItem;
+ uSub = pData->uSelectedSub;
+
+ if(uSubItem >= pData->uColumnCount && uSubItem > 0)
+ return 0;
+ if(uItem > pData->uTreeItemsMax)
+ return 0;
+ if(uItem == uOld)
+ if(uSubItem == uSub)
+ if(pData->uSelectedCount <= 1 || !(pData->uStyleEx & TVS_EX_MULTISELECT))
{
+ return 1;
+ }
+
+ if(pData->uStyleEx & TVS_EX_MULTISELECT) { // Ist die Mehrfachauswahl
m�glich
+ iSel = iMode & TVC_UNSELECT;
+ iDel = iMode & TVC_DESELECT;
+ if(!iDel) {
+ if(pData->uStyleEx & (TVS_EX_FULLROWMARK | TVS_EX_SUBSELECT))
+ UpdateRow(pData, uOld);
+ else
+ UpdateRect(pData, uOld, uSub);
+
+ uOld = 0;
+ uSub = 0;
+ } else { // Alle gew�hlten Eintr�ge abw�hlen
+ if(pData->uSelectedCount > 1 && pData->uTreeItemsMax) {
+ for(uPos = pData->uTreeItemsMax; uPos; uPos--) {
+ pEntry = pData->pTreeItems[uPos];
+ if(!pEntry || !(pEntry->uState & TVIS_SELECTED))
+ continue;
+ if(TreeListXorSelectItem(pData, uPos, iMode))
+ if(!pData->uSelectedCount)
+ break; // Wurden alle Eintr�ge abgew�hlt
+ }
+ }
+ }
+ } else { // Altes Select l�schen
+ iMode &= ~TVC_ONLYFOCUS;
+ iDel = 1;
+ iSel = 0;
+ }
+
+ iMode &= ~(TVC_DESELECT | TVC_UNSELECT);
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry) { // Neuen Statatus holen
+ if(uItem)
+ return 0;
+ uState = 0;
+ lParam = 0;
+ } else {
+ uState = pEntry->uState;
+ lParam = pEntry->lParam;
+
+ if(uSubItem) {
+ uState &= TVIS_BASEFLAGS;
+ pExtra = pData->pExtraItems[uSubItem - 1][uItem];
+ if(pExtra)
+ uState |= pExtra->uState;
+ }
+ }
+
+ pTemp = pData->pTreeItems[uOld];
+ if(!pTemp) { // Alten Status holen
+ uStOld = 0;
+ lPaOld = 0;
+ } else {
+ uStOld = pTemp->uState;
+ lPaOld = pTemp->lParam;
+
+ if(uSub) {
+ uStOld &= TVIS_BASEFLAGS;
+ pExtra = pData->pExtraItems[uSub - 1][uOld];
+ if(pExtra)
+ uStOld |= pExtra->uState;
+ }
+ }
+
+ sNotify.hdr.code = TVN_SELCHANGING;
+ sNotify.action = iMode;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = uState;
+ sNotify.itemNew.lParam = lParam;
+ sNotify.itemNew.cChildren = uSubItem;
+ sNotify.itemNew.pszText = (LPTSTR) - 1;
+ sNotify.itemNew.cchTextMax = -1;
+ sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemOld.hItem = (HTREEITEM)uOld;
+ sNotify.itemOld.stateMask = 0xFFFFFFFF;
+ sNotify.itemOld.state = uStOld;
+ sNotify.itemNew.lParam = lPaOld;
+ sNotify.itemOld.cChildren = uSub;
+ sNotify.itemOld.pszText = (LPTSTR) - 1;
+ sNotify.itemOld.cchTextMax = -1;
+ sNotify.ptDrag.x = 0;
+ sNotify.ptDrag.y = 0;
+
+
+ UNLOCK(pData);
+
+ if(SendNotify(pData, &sNotify.hdr)) { // Abfragen ob der Eintrag gew�hlt werden
darf
+ LOCK(pData);
+ return 0;
+ }
+
+ LOCK(pData);
+
+ if(uItem) { // Pr�fen ob der Eintrag noch existiert
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+ }
+
+ if(iDel) {
+ uOld = pData->uSelectedItem;
+ pTemp = pData->pTreeItems[uOld];
+ }
+
+
+ if(pTemp) { // Den alten Eintrag abw�hlen
+ if(pTemp->uShowPos) { // Den Eintrag neu zeichnen
+ if((pData->uStyleEx & TVS_EX_FULLROWMARK) || pData->uSelectedSub)
+ UpdateRow(pData, uOld);
+ else
+ UpdateRect(pData, uOld, uSub);
+ }
+
+ if(pTemp->uState & TVIS_SELECTED) {
+ uStOld &= ~TVIS_SELECTED;
+ pTemp->uState &= ~TVIS_SELECTED;
+
+ if(pData->uSelectedCount > 0) {
+ pData->uSelectedCount -= 1;
+ }
+ }
+
+ pData->uSelectedSub = 0;
+ pData->uSelectedItem = 0;
+ } else {
+ uOld = 0;
+ }
+
+
+ if(uItem) { // Den neuen Eintrag w�hlen
+ if(iSel) {
+ if(pEntry->uState & TVIS_SELECTED) {
+ uState &= ~TVIS_SELECTED;
+ pEntry->uState &= ~TVIS_SELECTED;
+ if(pData->uSelectedCount)
+ pData->uSelectedCount--;
+ }
+ } else {
+ if(!(pEntry->uState & TVIS_SELECTED)) {
+ uState |= TVIS_SELECTED;
+ pEntry->uState |= TVIS_SELECTED;
+ pData->uSelectedCount += 1;
+ }
+ }
+
+ if(uSubItem && uSubItem < pData->uColumnCount) {
+ pExtra = pData->pExtraItems[uSubItem - 1][uItem];
+ if(!pExtra) {
+ pExtra = new(ExtraItem, 1);
+ memset(pExtra, 0, sizeof(ExtraItem));
+ pExtra->iImage = TV_NOIMAGE;
+ pExtra->uState = pEntry->uState & (TVIS_BOLD | TVIS_UNDERLINE);
+ pData->pExtraItems[uSubItem - 1][uItem] = pExtra;
+ }
+
+ uState = pExtra->uState;
+ uState |= pEntry->uState & TVIS_BASEFLAGS;
+ } else {
+ uState = pEntry->uState;
+ }
+
+ if(pEntry->uShowPos) { // Den Eintrag neu zeichnen
+ if(pData->uStyleEx & (TVS_EX_FULLROWMARK | TVS_EX_SUBSELECT))
+ UpdateRow(pData, uItem);
+ else
+ UpdateRect(pData, uItem, uSubItem);
+ }
+
+ pData->uSelectedSub = uSubItem;
+ pData->uSelectedItem = uItem;
+ } else {
+ pData->uSelectedItem = 0;
+ pData->uSelectedSub = 0;
+ uState = 0;
+ }
+
+ sNotify.hdr.code = TVN_SELCHANGED;
+ sNotify.action = iMode;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = uState;
+ sNotify.itemNew.lParam = lParam;
+ sNotify.itemNew.cChildren = uSubItem;
+ sNotify.itemNew.pszText = (LPTSTR) - 1;
+ sNotify.itemNew.cchTextMax = -1;
+ sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_SUBITEM |
TVIF_PARAM;
+ sNotify.itemOld.hItem = (HTREEITEM)uOld;
+ sNotify.itemOld.stateMask = 0xFFFFFFFF;
+ sNotify.itemOld.state = uStOld;
+ sNotify.itemOld.lParam = lPaOld;
+ sNotify.itemOld.cChildren = uSub;
+ sNotify.itemOld.pszText = (LPTSTR) - 1;
+ sNotify.itemOld.cchTextMax = -1;
+ sNotify.ptDrag.x = 0;
+ sNotify.ptDrag.y = 0;
+
+ UNLOCK(pData);
+ SendNotify(pData, &sNotify.hdr);
+ LOCK(pData);
+
+ if(!(pData->uStyle & TVS_SINGLEEXPAND)) { // Einzelmodus aktiv
+ if(pData->uStyle & TVS_SHOWSELALWAYS)
+ if(pData->uSelectedItem) {
+ TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
+ }
+
+ return 1;
+ }
+
+
+ //*****************************************************************************
+
+
+ sNotify.hdr.code = TVN_SINGLEEXPAND;
+ sNotify.action = iMode;
+ sNotify.itemNew.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ sNotify.itemNew.hItem = (HTREEITEM)uItem;
+ sNotify.itemNew.stateMask = 0xFFFFFFFF;
+ sNotify.itemNew.state = (pEntry) ? pEntry->uState : 0;
+ sNotify.itemNew.cChildren = 0;
+ sNotify.itemNew.pszText = (LPTSTR) - 1;
+ sNotify.itemNew.cchTextMax = -1;
+ sNotify.itemOld.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ sNotify.itemOld.hItem = (HTREEITEM)uOld;
+ sNotify.itemOld.stateMask = 0xFFFFFFFF;
+ sNotify.itemOld.state = (pTemp) ? pTemp->uState : 0;
+ sNotify.itemOld.cChildren = 0;
+ sNotify.itemOld.pszText = (LPTSTR) - 1;
+ sNotify.itemOld.cchTextMax = -1;
+ sNotify.ptDrag.x = 0;
+ sNotify.ptDrag.y = 0;
+
+ UNLOCK(pData);
+ uRet = U(SendNotify(pData, &sNotify.hdr)); // Anfragen ob die Zweige umgeklappt
werden d�rfen
+ LOCK(pData);
+
+
+ pTemp = pData->pTreeItems[uOld ]; // Zeiger neu holen falls es �nderungen gab
+ pEntry = pData->pTreeItems[uItem];
+
+ while(pTemp && pEntry) { // Beide Zweige sysnchronisieren
+ if(pEntry->uLevel > pTemp->uLevel) {
+ uNext = pEntry->uParent;
+
+ if(!(uRet & TVNRET_SKIPNEW))
+ if(!(pEntry->uState & TVIS_EXPANDED)) {
+ TreeListToggleItem(pData, uItem, 0);
+ }
+
+ pEntry = pData->pTreeItems[uNext];
+ uItem = uNext;
+
+ if(!uItem)
+ break;
+
+ continue;
+ }
+
+ if(uItem == uOld)
+ goto EndSel; // Bis zum gleichen Knoten
+
+ uNext = pTemp->uParent;
+
+ if(!(uRet & TVNRET_SKIPOLD))
+ if(pTemp->uState & TVIS_EXPANDED) {
+ TreeListToggleItem(pData, uOld, 0);
+ }
+
+ pTemp = pData->pTreeItems[uNext];
+ uOld = uNext;
+ }
+
+ if(!uItem) {
+ if(!(uRet & TVNRET_SKIPOLD))
+ while(pTemp) { // Alten Zweig zuklappen
+ uNext = pTemp->uParent;
+
+ if(pTemp->uState & TVIS_EXPANDED) {
+ TreeListToggleItem(pData, uOld, 0);
+ }
+
+ pTemp = pData->pTreeItems[uNext];
+ uOld = uNext;
+ }
+
+ goto EndSel;
+ }
+
+ if(!uOld) {
+ if(!(uRet & TVNRET_SKIPNEW))
+ while(pEntry) { // Neuen Zweig aufklappen
+ uNext = pEntry->uParent;
+
+ if(!(pEntry->uState & TVIS_EXPANDED)) {
+ TreeListToggleItem(pData, uItem, 0);
+ }
+
+ pEntry = pData->pTreeItems[uNext];
+ uItem = uNext;
+ }
+ }
+
+EndSel:
+
+ if(pData->uStyle & TVS_SHOWSELALWAYS)
+ if(pData->uSelectedItem) {
+ TreeListEnsureVisible(pData, pData->uSelectedItem, pData->uSelectedSub);
+ }
+
+ return 2;
+}
+
+//*****************************************************************************
+//*
+//* TreeListSelectChilds
+//*
+//*****************************************************************************
+// W�hlt einen Eintrag aus
+// pData : Zeiger auf die Fensterdaten
+// uItem : Ist die Nummer des Eintrages der ausgew�hlt werden soll
+// iMode : Bit 0 = Untereint�ge auch �ndern
+// Bit 1 = Eintr�ge abw�hlen
+// Ergibt 1 wenn die Auswahl funktioniert hat, bzw. 0 bei einem Fehler
+static int TreeListSelectChilds(TreeListData *pData, unsigned uItem, int iMode) {
+
+ BaseItem *pEntry;
+ unsigned uLevel;
+ unsigned uXor;
+
+ if(!(pData->uStyleEx & TVS_EX_MULTISELECT))
+ return 0;
+
+ uLevel = 0;
+
+ if(uItem == U(TVI_ROOT)) {
+ uItem = pData->uFirstChild;
+ } else {
+ if(uItem > pData->uTreeItemsMax)
+ return 0;
+ }
+
+ if(!pData->pTreeItems[uItem]) {
+ return 0;
+ }
+
+
+ uXor = (iMode & TVIS_DESELECT) ? 0 : TVIS_SELECTED;
+ iMode &= TVIS_WITHCHILDS;
+
+ for(;;) {
+ pEntry = pData->pTreeItems[uItem];
+
+ if((pEntry->uState ^ uXor)&TVIS_SELECTED) {
+ TreeListXorSelectItem(pData, uItem, TVC_UNKNOWN);
+ }
+
+ if(iMode && pEntry->uFirstChild) { // Auch Kinder �ndern
+ uItem = pEntry->uFirstChild;
+ uLevel++;
+ continue;
+ }
+
+ for(;;) { // Eine Ebene h�her
+ uItem = pEntry->uNextItem;
+ if(uItem != 0)
+ break;
+ if(uLevel == 0)
+ return 1;
+
+ uLevel--;
+
+ uItem = pEntry->uParent;
+ pEntry = pData->pTreeItems[uItem];
+ }
+ }
+}
+
+//*****************************************************************************
+//*
+//* TreeListInsertItem
+//*
+//*****************************************************************************
+// F�gt einen Eintrag ins Fenster ein
+// pData : Zeiger auf die Fensterdaten
+// pInsert : Zeiger auf die ein zu f�genden Daten
+// Ergibt die Einf�geposition des neuen Eintrages oder 0 bei einem Fehler
+static unsigned TreeListInsertItem(TreeListData *pData, TV_INSERTSTRUCT *pInsert) {
+
+ char *pTemp;
+ BYTE bFlag;
+ LPCTSTR pText;
+ LPCTSTR pTextTemp;
+ PFNTVSORTEX pCompare;
+ ExtraItem **pExOld[MAX_COLUMNS];
+ ExtraItem **pExNew[MAX_COLUMNS];
+ BaseItem *pNew;
+ BaseItem **pOld;
+ BaseItem **pItems;
+ BaseItem *pEntry;
+ BaseItem *pParent;
+ unsigned *pPosNew;
+ unsigned *pPosOld;
+ unsigned *pFirst;
+ unsigned *pLast;
+ unsigned uBefore;
+ unsigned uParent;
+ unsigned uAfter;
+ unsigned uFirst;
+ unsigned uSize;
+ unsigned uBits;
+ unsigned uItem;
+ unsigned uNext;
+ unsigned uMax;
+ unsigned uPos;
+ unsigned uNum;
+ int iCmp;
+ int iNone;
+ int iCount;
+ int iShift;
+
+ if(pData->cLockChanges)
+ return 0;
+
+ uParent = U(pInsert->hParent);
+ if(uParent > pData->uTreeItemsMax) { // Pr�fe das Elternelement
+ if(pInsert->hParent != TVI_ROOT) {
+ return 0;
+ }
+
+ pParent = NULL;
+ } else {
+ pParent = pData->pTreeItems[uParent];
+ if(!pParent) {
+ if(uParent)
+ return 0;
+ pParent = NULL;
+ }
+ }
+
+ if(pData->uTreeItemsCount + 1 > pData->uTreeItemsMax) { // Gr��e der Liste
erh�hen
+ pPosOld = pData->pItemPos;
+ pOld = pData->pTreeItems;
+ uMax = pData->uTreeItemsMax;
+ uMax += pData->uTreeItemsMax / 2;
+ uMax += 64;
+ pItems = new(BaseItem*, uMax + 1);
+
+ if(!pItems) {
+ return 0;
+ }
+
+ pPosNew = new(unsigned, uMax);
+ if(!pPosNew) {
+ delete(pItems);
+ return 0;
+ }
+
+ for(uPos = 1; uPos < pData->uColumnCount; uPos++) {
+ pExOld[uPos] = pData->pExtraItems[uPos - 1];
+ pExNew[uPos] = new(ExtraItem*, uMax + 1);
+
+ if(!pExNew[uPos]) {
+ for(uPos--; uPos > 0; uPos--)
+ delete(pExNew[uPos]);
+ delete(pPosNew);
+ delete(pItems);
+ return 0;
+ }
+ }
+
+ memcpy(pItems , pData->pTreeItems , sizeof(BaseItem *) *
(pData->uTreeItemsMax + 1));
+ memset(pItems + pData->uTreeItemsMax + 1, 0, sizeof(BaseItem *) * (uMax -
pData->uTreeItemsMax));
+ memcpy(pPosNew, pData->pItemPos , sizeof(unsigned) *
(pData->uTreeItemsCount));
+ memset(pPosNew + pData->uTreeItemsCount, 0, sizeof(unsigned) * (uMax -
pData->uTreeItemsCount));
+
+ for(uPos = 1; uPos < pData->uColumnCount; uPos++) {
+ memcpy(pExNew[uPos], pExOld[uPos] , sizeof(ExtraItem *) *
(pData->uTreeItemsMax + 1));
+ memset(pExNew[uPos] + pData->uTreeItemsMax + 1, 0, sizeof(ExtraItem *) * (uMax -
pData->uTreeItemsMax));
+ pData->pExtraItems[uPos - 1] = pExNew[uPos];
+ delete(pExOld[uPos]);
+ }
+
+ pData->uTreeItemsMax = uMax;
+ pData->pTreeItems = pItems;
+ pData->pItemPos = pPosNew;
+ delete(pPosOld);
+ delete(pOld);
+ }
+
+ //******************** Den neuen Eintrag erzeugen *****************************
+ pItems = pData->pTreeItems;
+ uPos = pData->uNextSeachPos + 1;
+ pTemp = new(char, sizeof(BaseItem) + pData->uUserDataSize);
+ pNew = (BaseItem *)pTemp;
+
+ if(!pNew) { // Konnte der Speicher reserviert werden
+ return 0;
+ }
+
+ if(pData->uUserDataSize) { // Die Userdaten auf 0 setzen
+ memset(pTemp + sizeof(BaseItem), 0, pData->uUserDataSize);
+ }
+
+ for(;; uPos++) { // Suche freie Position
+ if(uPos > pData->uTreeItemsMax)
+ uPos = 1;
+ if(pItems[uPos] == NULL)
+ break;
+ }
+
+ pData->uNextSeachPos = uPos;
+
+ memset(pNew, 0, sizeof(BaseItem)); // Erstelle den neuen Eintrag
+ pNew->iImage = TV_NOIMAGE;
+ pNew->iSelectedImage = TV_NOIMAGE;
+
+ uBits = pInsert->item.mask;
+
+ if(uBits & TVIF_STATE) {
+ pNew->uState = pInsert->item.state & pInsert->item.stateMask;
+ } else {
+ if(pData->uStyle & TVS_CHECKBOXES)
+ if(!(pData->uStyleEx & TVS_EX_BITCHECKBOX)) {
+ pNew->uState = 0x1000;
+ }
+ }
+
+ if(uBits & TVIF_PARAM) {
+ pNew->lParam = pInsert->item.lParam;
+ }
+
+ if(uBits & TVIF_IMAGE) {
+ pNew->iImage = pInsert->item.iImage;
+ if(pNew->iImage == I_IMAGECALLBACK)
+ pNew->bCallback |= TVIF_IMAGE;
+ }
+
+ if(uBits & TVIF_SELECTEDIMAGE) {
+ pNew->iSelectedImage = pInsert->item.iSelectedImage;
+ if(pNew->iSelectedImage == I_IMAGECALLBACK)
+ pNew->bCallback |= TVIF_SELECTEDIMAGE;
+ }
+
+ if(uBits & TVIF_CHILDREN) { // Art der Schaltfl�chen
+ switch(pInsert->item.cChildren) {
+ case 0:
+ break;
+ case 1:
+ pNew->bFlags |= TVIX_HASBUTTON;
+ break;
+ case I_CCB:
+ pNew->bCallback |= TVIF_CHILDREN;
+ break;
+ default
+ :
+ pNew->bFlags |= TVIX_VARBUTTON;
+ break;
+ }
+ } else {
+ pNew->bFlags |= TVIX_VARBUTTON;
+ }
+
+ if(pData->uStyle & TVS_SINGLEEXPAND) { // Nicht aufklappen bei Einzelmodus
+ pNew->uState &= ~TVIS_EXPANDED;
+ }
+
+ if(uBits & TVIF_TEXT) { // Text einf�gen
+ if(pInsert->item.pszText == LPSTR_TEXTCALLBACK) {
+ pNew->bCallback |= TVIF_TEXT;
+ pNew->uTextSize = 0;
+ pNew->pText = 0;
+ } else {
+ pNew->uTextSize = (WORD)str_len(pInsert->item.pszText);
+ pNew->pText = new(TCHAR, pNew->uTextSize + 1);
+ memcpy(pNew->pText, pInsert->item.pszText, sizeof(TCHAR) * (pNew->uTextSize +
1));
+ }
+ } else {
+ pNew->pText = new(TCHAR, 1);
+ pNew->pText[0] = 0;
+ pNew->uTextSize = 0;
+ }
+
+ if(!pParent) { // Einen Root-Eintrag einf�gen
+ pNew->uParent = 0;
+ uParent = 0;
+ bFlag = 0;
+ uFirst = 0xFFFFFFFF;
+ pFirst = &pData->uFirstChild;
+ pLast = &pData->uLastChild;
+ } else { // Einen Tree-Eintrag einf�gen
+ pNew->uParent = uParent;
+ pNew->uLevel = pParent->uLevel + 1;
+ uFirst = pParent->uFirstChild;
+ pFirst = &pParent->uFirstChild;
+ pLast = &pParent->uLastChild;
+ bFlag = pParent->bFlags;
+
+ if(pParent->bFlags & TVIX_VARBUTTON) {
+ pParent->bFlags |= TVIX_HASBUTTON;
+ }
+ }
+
+ //******************** Eintrage einf�gen **************************************
+ uAfter = U(pInsert->hInsertAfter);
+
+ switch(uAfter) {
+ case U(TVI_BEFORE): // Nach einem Eintrag einf�gen
+ if(pParent) { // Einen Root-Eintrag einf�gen
+ pEntry = pParent;
+ pParent ->bFlags = bFlag;
+ uParent = pParent->uParent;
+ pParent = pItems [uParent];
+
+ if(!pParent) {
+ pNew->uParent = 0;
+ pNew->uLevel = 0;
+ uParent = 0;
+ uFirst = 0xFFFFFFFF;
+ pFirst = &pData->uFirstChild;
+ pLast = &pData->uLastChild;
+ } else { // Einen Tree-Eintrag einf�gen
+ pNew->uParent = uParent;
+ pNew->uLevel = pParent->uLevel + 1;
+ uFirst = pParent->uFirstChild;
+ pFirst = &pParent->uFirstChild;
+ pLast = &pParent->uLastChild;
+
+ if(pParent->bFlags & TVIX_VARBUTTON) {
+ pParent->bFlags |= TVIX_HASBUTTON;
+ }
+ }
+
+ if(pEntry->uPrevItem) {
+ uAfter = pEntry->uPrevItem;
+ goto DoInsert;
+ }
+ }
+
+ case U(TVI_FIRST): // Am Anfang einf�gen
+ if(pFirst[0]) { // Gibt es schon Eintr�ge
+ pEntry = pItems[pFirst[0]];
+ pEntry->uPrevItem = uPos;
+ } else {
+ pFirst[0] = uPos;
+ pLast [0] = uPos;
+ break;
+ }
+
+ pNew ->uNextItem = pFirst[0]; // Eintrag einf�gen
+ pFirst[0] = uPos;
+ break;
+
+ case U(TVI_ROOT): // Als Root-Eintrag einf�gen
+ pNew->uParent = 0;
+ uParent = 0;
+ pFirst = &pData->uFirstChild;
+ pLast = &pData->uLastChild;
+
+ case U(TVI_LAST): // Am Ende einf�gen
+ if(pLast[0]) { // Gibt es schon Eintr�ge
+ pEntry = pItems[pLast[0]];
+ pEntry->uNextItem = uPos;
+ } else {
+ pFirst[0] = uPos;
+ pLast [0] = uPos;
+ break;
+ }
+
+ pNew ->uPrevItem = pLast[0]; // Eintrag einf�gen
+ pLast[0] = uPos;
+ break;
+
+
+ case U(TVI_SORTEX): // Einf�gen mittels Funktion
+ uItem = pFirst[0];
+ if(!uItem) { // Gibt es keine Kindeintr�ge
+ pFirst[0] = uPos;
+ pLast [0] = uPos;
+ break;
+ }
+
+ if(pNew->bCallback & TVIF_TEXT) { // Text �ber Callback holen
+ uSize = 1;
+ LOCK(pData);
+ CallbackEntry(pData, pNew, uPos, TVIF_TEXT, &iNone, &uSize, &pText);
+ UNLOCK(pData);
+ } else {
+ pText = pNew->pText;
+ }
+
+ pData->cLockChanges = 1;
+
+ pCompare = (PFNTVSORTEX)(pInsert->item.hItem);
+ if(!pCompare)
+ break;
+ uNext = uItem;
+ iCount = 0;
+ uBefore = 0;
+
+ while(uNext) { // Z�hle die Eintr�ge
+ iCount++;
+ uNext = pItems[uNext]->uNextItem;
+ }
+
+ while(iCount > 0) { // Binary-Seach Algorithnus
+ iShift = iCount / 2;
+ uNext = uItem;
+
+ while(iShift > 0) {
+ uNext = pItems[uNext]->uNextItem;
+ iShift--;
+ }
+
+ pEntry = pItems[uNext];
+ if(pEntry->bCallback & TVIF_TEXT) { // Text �ber Callback holen
+ uSize = 0;
+ LOCK(pData);
+ CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize,
&pTextTemp);
+ UNLOCK(pData);
+ } else {
+ pTextTemp = pEntry->pText;
+ }
+
+ iCmp = pCompare(pData->hWnd, (HTREEITEM)uNext, pTextTemp, pText,
pEntry->lParam, pInsert->item.lParam);
+ if(iCmp < 0) {
+ iCount -= (iCount + 1) / 2;
+ continue;
+ }
+
+ if(iCmp > 0) {
+ iCount -= iCount / 2 + 1;
+ uBefore = uNext;
+ uItem = pItems[uNext]->uNextItem;
+ continue;
+ }
+
+ uBefore = pEntry->uPrevItem;
+ uItem = uNext;
+ break;
+ }
+
+ pData->cLockChanges = 0;
+
+ pNew->uNextItem = uItem;
+ pNew->uPrevItem = uBefore;
+
+ if(uBefore) { // Vorherigen Eintrag anpassen
+ pEntry = pItems[uBefore];
+ pEntry->uNextItem = uPos;
+ } else { // Am Anfang einf�gen
+ pFirst[0] = uPos;
+ }
+
+ if(uItem) { // N�chsten Eintrag anpassen
+ pEntry = pItems[uItem];
+ pEntry->uPrevItem = uPos;
+ } else { // Am Ende anh�ngen
+ pLast[0] = uPos;
+ }
+ break;
+
+ case U(TVI_SORT): // Alphapetisch einf�gen
+ uItem = pFirst[0];
+ if(!uItem) { // Gibt es keine Kindeintr�ge
+ pFirst[0] = uPos;
+ pLast [0] = uPos;
+ break;
+ }
+
+ if(pNew->bCallback & TVIF_TEXT) { // Text �ber Callback holen
+ uSize = 1;
+ LOCK(pData);
+ CallbackEntry(pData, pNew, uPos, TVIF_TEXT, &iNone, &uSize, &pText);
+ UNLOCK(pData);
+ } else {
+ pText = pNew->pText;
+ }
+
+ pData->cLockChanges = 1;
+
+ uNext = uItem;
+ iCount = 0;
+ uBefore = 0;
+
+ while(uNext) { // Z�hle die Eintr�ge
+ iCount++;
+ uNext = pItems[uNext]->uNextItem;
+ }
+
+ while(iCount > 0) { // Binary-Seach Algorithnus
+ iShift = iCount / 2;
+ uNext = uItem;
+
+ while(iShift > 0) {
+ uNext = pItems[uNext]->uNextItem;
+ iShift--;
+ }
+
+
+ pEntry = pItems[uNext];
+ if(pEntry->bCallback & TVIF_TEXT) { // Text �ber Callback holen
+ uSize = 0;
+ LOCK(pData);
+ CallbackEntry(pData, pEntry, uItem, TVIF_TEXT, &iNone, &uSize,
&pTextTemp);
+ UNLOCK(pData);
+ } else {
+ pTextTemp = pEntry->pText;
+ }
+
+ iCmp = str_icmp(pText, pTextTemp);
+
+ if(iCmp < 0) {
+ iCount -= (iCount + 1) / 2;
+ continue;
+ }
+
+ if(iCmp > 0) {
+ iCount -= iCount / 2 + 1;
+ uBefore = uNext;
+ uItem = pItems[uNext]->uNextItem;
+ continue;
+ }
+
+ uBefore = pEntry->uPrevItem;
+ uItem = uNext;
+ break;
+ }
+
+
+ pData->cLockChanges = 0;
+
+ pNew->uNextItem = uItem;
+ pNew->uPrevItem = uBefore;
+
+ if(uBefore) { // Vorherigen Eintrag anpassen
+ pEntry = pItems[uBefore];
+ pEntry->uNextItem = uPos;
+ } else { // Am Anfang einf�gen
+ pFirst[0] = uPos;
+ }
+
+ if(uItem) { // N�chsten Eintrag anpassen
+ pEntry = pItems[uItem];
+ pEntry->uPrevItem = uPos;
+ } else { // Am Ende anh�ngen
+ pLast[0] = uPos;
+ }
+ break;
+
+ case U(TVI_AFTER): // Nach einem Eintrag einf�gen
+ uAfter = uParent;
+
+ if(pParent) { // Einen Root-Eintrag einf�gen
+ pParent ->bFlags = bFlag;
+ uParent = pParent->uParent;
+ pParent = pItems [uParent];
+
+ if(!pParent) {
+ pNew->uParent = 0;
+ pNew->uLevel = 0;
+ uParent = 0;
+ uFirst = 0xFFFFFFFF;
+ pFirst = &pData->uFirstChild;
+ pLast = &pData->uLastChild;
+ } else { // Einen Tree-Eintrag einf�gen
+ pNew->uParent = uParent;
+ pNew->uLevel = pParent->uLevel + 1;
+ uFirst = pParent->uFirstChild;
+ pFirst = &pParent->uFirstChild;
+ pLast = &pParent->uLastChild;
+
+ if(pParent->bFlags & TVIX_VARBUTTON) {
+ pParent->bFlags |= TVIX_HASBUTTON;
+ }
+ }
+ }
+
+ default
+ : // Hinter einen Eintrag einf�gen
+DoInsert:
+ uItem = pFirst[0];
+ if(!uItem) { // Gibt es keine Kindeintr�ge
+ pFirst[0] = uPos;
+ pLast [0] = uPos;
+ break;
+ }
+
+ if(uAfter > pData->uTreeItemsMax) {
+ if((uAfter & 0xFFF00000) == 0xFFE00000) { // In einer genauen Reihe nach Patent
einf�gen
+ uAfter &= 0xFFFFF;
+
+ uItem = pFirst[0];
+ if(!uItem) { // Gibt es keine Kindeintr�ge
+ pFirst[0] = uPos;
+ pLast [0] = uPos;
+ break;
+ }
+
+ if(uAfter == 0) { // In die erste Reihe einf�gen
+ pEntry = pItems[uItem];
+ pEntry->uPrevItem = uPos;
+ pNew ->uNextItem = uItem;
+ pFirst[0] = uPos;
+ break;
+ }
+
+ uNum = 1;
+ uBefore = 0;
+ // Suche Einf�gereihe
+ for(; uItem; uItem = pItems[uItem]->uNextItem) {
+ uBefore = uItem;
+
+ if(uNum == uAfter) {
+ uItem = pItems[uItem]->uNextItem;
+ break;
+ }
+
+ uNum++;
+ }
+
+ pNew->uNextItem = uItem;
+ pNew->uPrevItem = uBefore;
+
+ if(uBefore) { // Vorherigen Eintrag anpassen
+ pEntry = pItems[uBefore];
+ pEntry->uNextItem = uPos;
+ } else { // Am Anfang einf�gen
+ pFirst[0] = uPos;
+ }
+
+ if(uItem) { // N�chsten Eintrag anpassen
+ pEntry = pItems[uItem];
+ pEntry->uPrevItem = uPos;
+ } else { // Am Ende anh�ngen
+ pLast[0] = uPos;
+ }
+
+ break;
+ }
+
+ pEntry = NULL;
+ } else {
+ pEntry = pItems[uAfter];
+ }
+
+ if(pEntry && uParent == pEntry->uParent) { // Stimmt der Elterneintrag ?
+ uItem = pEntry->uNextItem;
+ uBefore = uAfter;
+ } else {
+ uItem = 0;
+ uBefore = pLast[0];
+ pEntry = pItems[uBefore];
+ }
+
+ pNew->uNextItem = uItem;
+ pNew->uPrevItem = uBefore;
+
+ if(uBefore) { // Vorherigen Eintrag anpassen
+ pEntry->uNextItem = uPos;
+ } else { // Am Anfang einf�gen
+ pFirst[0] = uPos;
+ }
+
+ if(uItem) { // N�chsten Eintrag anpassen
+ pEntry = pItems[uItem];
+ pEntry->uPrevItem = uPos;
+ } else { // Am Ende anh�ngen
+ pLast[0] = uPos;
+ }
+
+ break;
+ }
+
+ pItems[uPos] = pNew;
+ pData->uTreeItemsCount++;
+ // Die Anzeigezeilen akualisieren
+ if(!pParent || !uFirst || (pParent->uState & TVIS_EXPANDED)) {
+ uItem = pNew->uPrevItem;
+ if(!uItem)
+ uItem = uParent;
+
+ if(!uItem)
+ UpdateItems(pData, 0);
+ else {
+ pEntry = pItems[uItem];
+ if(pEntry && pEntry->uShowPos)
+ UpdateItems(pData, uItem);
+ }
+ }
+
+ if(pNew->uState & TVIS_SELECTED) { // Den ausgew�hlten Eintrag ausw�hlen
+ TreeListSelectItem(pData, uPos, 0, TVC_UNKNOWN);
+ }
+
+ return uPos;
+}
+
+//*****************************************************************************
+//*
+//* TreeListSetItem
+//*
+//*****************************************************************************
+// �ndert einen Eintrag im Fenster
+// pData : Zeiger auf die Fensterdaten
+// pItem : Zeiger auf die ein zu �ndernden Daten
+// Ergibt 1 wenn ok oder 0 bei einem Fehler
+static int TreeListSetItem(TreeListData *pData, const TV_ITEM *pItem) {
+
+ BYTE bCall;
+ BYTE bFlags;
+ ExtraItem **pList;
+ ExtraItem *pExtra;
+ BaseItem *pEntry;
+ unsigned uChange;
+ unsigned uMask;
+ unsigned uBits;
+ unsigned uItem;
+ unsigned uSub;
+ unsigned uLen;
+ int iVal;
+ int iRet;
+
+ uChange = 0;
+
+ uItem = U(pItem->hItem);
+ if(uItem > pData->uTreeItemsMax)
+ return 0;
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+
+ uBits = pItem->mask;
+
+ if(uBits & TVIF_SUBITEM) { // Einen Extraeintrag �ndern
+ uSub = pItem->cChildren;
+ if(uSub > 0) {
+ if(uSub >= pData->uColumnCount)
+ return 0;
+ pList = pData->pExtraItems[uSub - 1];
+ pExtra = pList[uItem];
+
+ if(!pExtra) { // Einen neuen Eintrag erzeugen
+ pExtra = new(ExtraItem, 1);
+ memset(pExtra, 0, sizeof(ExtraItem));
+ pExtra->iImage = TV_NOIMAGE;
+ pExtra->uState = pEntry->uState & (TVIS_BOLD | TVIS_UNDERLINE);
+ pList[uItem] = pExtra;
+ }
+
+ if(uBits & TVIF_PARAM) {
+ pEntry->lParam = pItem->lParam;
+ }
+
+ if((uBits & TVIF_IMAGE) && pExtra->iImage != pItem->iImage) {
+ if(pData->hImages)
+ uChange = 1;
+ pExtra->iImage = pItem->iImage;
+ if(pExtra->iImage == I_IMAGECALLBACK)
+ pExtra->bCallback |= TVIF_IMAGE;
+ else
+ pExtra->bCallback &= TVIF_IMAGE;
+ }
+
+ if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen
+ if(pItem->pszText == LPSTR_TEXTCALLBACK) {
+ if(pExtra->pText)
+ delete(pExtra->pText);
+ pExtra->bCallback |= TVIF_TEXT;
+ pExtra->uTextSize = 0;
+ pExtra->pText = 0;
+ uChange = 1;
+ } else {
+ uLen = str_len(pItem->pszText);
+
+ if(uLen > pExtra->uTextSize || !pExtra->pText) {
+ if(pExtra->pText)
+ delete(pExtra->pText);
+ pExtra->pText = new(TCHAR, uLen + 1);
+ }
+
+ memcpy(pExtra->pText, pItem->pszText, (uLen + 1)*sizeof(TCHAR));
+ pExtra->bCallback &= ~TVIF_TEXT;
+ pExtra->uTextSize = (WORD)uLen;
+ pExtra->iTextPixels = 0;
+ uChange = 1;
+ }
+ }
+
+ if(uBits & TVIF_STATE) { // Den Status �ndern
+ uMask = pItem->stateMask&~TVIS_BASEFLAGS;
+ uBits = uMask & (pExtra->uState ^ pItem->state);
+ uBits |= (pItem->stateMask & TVIS_BASEFLAGS) & (pEntry->uState ^
pItem->state);
+ pExtra->uState &= ~uMask;
+ pExtra->uState |= uMask & pItem->state;
+
+ if((uBits & (TVIS_OVERLAYMASK | TVIS_CUT)) && (pData->hImages ||
pData->aColumn[uSub].bEdit >= TVAX_CHECK)) {
+ uChange = 1; // Ein Icon hats sich ver�ndert
+ }
+
+ if(uBits & (TVIS_BOLD | TVIS_DROPHILITED)) {
+ pExtra->iTextPixels = 0;
+ uChange = 1;
+ }
+
+ if((uBits & TVIS_EXPANDED) && pEntry->uFirstChild) {
+ iVal = TreeListToggleItem(pData, uItem, 0);
+ if(iVal < 0)
+ return 0;
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+ }
+
+ if(uBits & TVIS_SELECTED) { // Hat sich die Auswahl ge�ndert
+ iVal = (pData->uStyleEx & TVS_EX_SUBSELECT) ? uSub : 0;
+
+ if(pItem->state & TVIS_SELECTED) {
+ iRet = TreeListSelectItem(pData, uItem, iVal, TVC_UNKNOWN);
+ } else
+ if(pData->uStyleEx & TVS_EX_MULTISELECT) {
+ TreeListSelectItem(pData, 0 , 0, TVC_UNKNOWN);
+ iRet = TreeListXorSelectItem(pData, uItem, TVC_UNKNOWN);
+ } else {
+ iRet = TreeListSelectItem(pData, 0, 0, TVC_UNKNOWN);
+ }
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+
+ if(iRet >= 2) {
+ pList = pData->pExtraItems[uSub - 1];
+ pExtra = pList[uItem];
+ if(!pExtra)
+ return 0;
+ } else
+ if(iRet == 1) {
+ uChange = 1;
+ }
+ }
+ }
+
+ if(!uChange || !pEntry->uShowPos)
+ return 1; // Neuzeichnen des Eintrages
+
+ UpdateRect(pData, uItem, uSub);
+
+ return 1;
+ }
+
+ uBits &= ~TVIF_CHILDREN;
+ }
+
+ //******************** Einen Basis Eintrag �ndern *****************************
+ if(uBits & TVIF_PARAM) {
+ pEntry->lParam = pItem->lParam;
+ }
+
+ if((uBits & TVIF_IMAGE) && pEntry->iImage != pItem->iImage) {
+ pEntry->iImage = pItem->iImage;
+ if(!(pEntry->uState & TVIS_SELECTED) && pData->hImages)
+ uChange = 1;
+ if(pEntry->iImage == I_IMAGECALLBACK)
+ pEntry->bCallback |= TVIF_IMAGE;
+ else
+ pEntry->bCallback &= TVIF_IMAGE;
+ }
+
+ if((uBits & TVIF_SELECTEDIMAGE) && pEntry->iSelectedImage !=
pItem->iSelectedImage) {
+ pEntry->iSelectedImage = pItem->iSelectedImage;
+ if((pEntry->uState & TVIS_SELECTED) && pData->hImages)
+ uChange = 1;
+ if(pEntry->iSelectedImage == I_IMAGECALLBACK)
+ pEntry->bCallback |= TVIF_SELECTEDIMAGE;
+ else
+ pEntry->bCallback &= TVIF_SELECTEDIMAGE;
+ }
+
+ if(uBits & TVIF_CHILDREN) {
+ bCall = pEntry->bCallback;
+ bFlags = pEntry->bFlags;
+
+ switch(pItem->cChildren) {
+ case 0:
+ pEntry->bCallback &= ~TVIF_CHILDREN;
+ pEntry->bFlags &= ~TVIX_HASBUTTON;
+ pEntry->bFlags |= TVIX_VARBUTTON;
+ break;
+
+ case 1:
+ pEntry->bCallback &= ~TVIF_CHILDREN;
+ pEntry->bFlags &= TVIX_VARBUTTON;
+ pEntry->bFlags |= TVIX_HASBUTTON;
+ break;
+
+ case I_CCB:
+ pEntry->bCallback |= TVIF_CHILDREN;
+ pEntry->bFlags &= ~TVIX_VARBUTTON;
+ break;
+
+ default
+ :
+ pEntry->bCallback &= ~TVIF_CHILDREN;
+ pEntry->bFlags |= TVIX_VARBUTTON;
+
+ if(pEntry->uFirstChild)
+ pEntry->bFlags |= TVIX_HASBUTTON;
+ else
+ pEntry->bFlags &= ~TVIX_HASBUTTON;
+ }
+
+ if(bCall != pEntry->bCallback || bFlags != pEntry->bFlags) {
+ uChange = 1;
+ }
+ }
+
+ if(uBits & TVIF_TEXT) { // Einen neuen Text einstellen
+ if(pItem->pszText == LPSTR_TEXTCALLBACK) {
+ if(pEntry->pText)
+ delete(pEntry->pText);
+ pEntry->bCallback |= TVIF_TEXT;
+ pEntry->uTextSize = 0;
+ pEntry->pText = 0;
+ uChange = 1;
+ } else {
+ uLen = str_len(pItem->pszText);
+
+ if(uLen > pEntry->uTextSize) {
+ if(pEntry->pText)
+ delete(pEntry->pText);
+ pEntry->pText = new(TCHAR, uLen + 1);
+ }
+
+ memcpy(pEntry->pText, pItem->pszText, (uLen + 1)*sizeof(TCHAR));
+ pEntry->bCallback &= ~TVIF_TEXT;
+ pEntry->uTextSize = (WORD)uLen;
+ pEntry->iTextPixels = 0;
+ uChange = 1;
+ }
+ }
+
+ if(uBits & TVIF_STATE) {
+ uMask = pItem->stateMask;
+
+ if(pData->uStyle & TVS_SINGLEEXPAND) { // Nicht aufklappen bei Einzelmodus
+ uMask &= ~TVIS_EXPANDED;
+ }
+
+ uBits = uMask & (pEntry->uState ^ pItem->state);
+ pEntry->uState &= ~uMask;
+ pEntry->uState |= uMask & pItem->state;
+
+
+ if((uBits & (TVIS_OVERLAYMASK | TVIS_CUT)) && pData->hImages) {
+ uChange = 1;
+ }
+
+ if(uBits & TVIS_STATEIMAGEMASK) { // Haben sich die State-Bits ver�ndert
+ if(pData->hStates) {
+ uChange = 1;
+ }
+
+ if(pData->uStyleEx & TVS_EX_BITCHECKBOX) {
+ if(pEntry->uState & 0x1000) {
+ pData->uSingleSel = uItem;
+ } else
+ if(pData->uSingleSel == uItem) {
+ pData->uSingleSel = 0;
+ }
+ } else {
+ if((pEntry->uState & TVIS_STATEIMAGEMASK) == 0x2000) {
+ pData->uSingleSel = uItem;
+ } else
+ if(pData->uSingleSel == uItem) {
+ pData->uSingleSel = 0;
+ }
+ }
+ }
+
+ if(uBits & (TVIS_BOLD | TVIS_DROPHILITED)) {
+ pEntry->iTextPixels = 0;
+ uChange = 1;
+ }
+
+ if(uBits & TVIS_SELECTED) { // Hat sich die Auswahl ge�ndert
+ pEntry->uState ^= TVIS_SELECTED;
+
+ if(pItem->state & TVIS_SELECTED) {
+ iRet = TreeListSelectItem(pData, uItem, 0, TVC_UNKNOWN);
+ } else
+ if(pData->uStyleEx & TVS_EX_MULTISELECT) {
+ TreeListSelectItem(pData, 0 , 0, TVC_UNKNOWN);
+ iRet = TreeListXorSelectItem(pData, uItem, TVC_UNKNOWN);
+ } else {
+ iRet = TreeListSelectItem(pData, 0, 0, TVC_UNKNOWN);
+ }
+
+ pEntry = pData->pTreeItems[uItem];
+ if(!pEntry)
+ return 0;
+
+ if(iRet == 1) {
+ uChange = 1;
+ }
+ }
+
+ if((uBits & TVIS_EXPANDED) && pEntry->uFirstChild) { // Sollen Teile
auf/zugeklappt werden
+ uMask &= TVIS_EXPANDPARTIAL | TVIS_EXPANDPARTIAL;
+ pEntry->uState ^= TVIS_EXPANDED;
+ pEntry->uState ^= uBits & uMask;
+ iVal = uMask & pItem->state;
+
+ iRet = TreeListToggleItem(pData, uItem, iVal);
+ if(iRet) { // Abbruch oder Fehler beim Auf/Zuklappen
+ if(uChange && pEntry->uShowPos) { // Neuzeichnen des Eintrages
+ UpdateRect(pData, uItem, 0);
+ }
+
+ return 0;
+ }
+
+ pEntry->uState &= ~uMask;
+ pEntry->uState |= iVal;
+ }
+ }
+
+ if(uChange && pEntry->uShowPos) { // Neuzeichnen des Eintrages
+ UpdateRect(pData, uItem, 0);
+ }
+ return 1;
+}
+
+
+//*****************************************************************************
+//*
+//* TreeListGetItem
+//*
+//*****************************************************************************
+// Daten vone einem Eintrag abfragen
... 9270 lines suppressed ...