|
|
#include <windows.h>
#include <custcntl.h>
#include <commdlg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "hlist.h"
typedef DWORD (CALLBACK* HLISTCALLBACK)(LPDWORD,LPSTR*,LPSTR,DWORD,DWORD);
#define XBITMAP 16
#define YBITMAP 16
#define MARGIN 6
#define INDENT (XBITMAP + MARGIN)
#define MIDDLE ((XBITMAP/2) + MARGIN)
#define LINE_COLOR RGB(255,0,0)
#define CLASS_NAME "HList"
#define DESCRIPTION "Heir List Box"
#define DEFAULT_STYLE WS_CHILD | \
WS_VISIBLE | \ WS_VSCROLL | \ WS_HSCROLL | \ WS_BORDER | \ LBS_NOTIFY | \ LBS_NOINTEGRALHEIGHT | \ LBS_WANTKEYBOARDINPUT | \ LBS_SORT | \ LBS_OWNERDRAWFIXED
typedef struct _HLISTTYPE { struct _HLISTTYPE *next; DWORD type; HBITMAP bitmap; } HLISTTYPE, *LPHLISTTYPE;
typedef struct _HLISTINFO { HWND hwndList; LPHLISTTYPE typeList; HLISTCALLBACK lpCallback; } HLISTINFO, *LPHLISTINFO;
typedef struct _ITEMDATA { struct _ITEMDATA *parent; DWORD type; DWORD level; DWORD nchild; DWORD childnum; LPSTR str; HBITMAP bitmap; } ITEMDATA, *LPITEMDATA;
static HMODULE hInstance;
LRESULT HListWndProc(HWND,UINT,WPARAM,LPARAM);
BOOL HListInitialize( HMODULE hModule ) { WNDCLASS wndclass;
hInstance = hModule;
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS; wndclass.lpfnWndProc = HListWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 4; wndclass.hInstance = hInstance; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = CLASS_NAME; if (!RegisterClass( &wndclass )) { return FALSE; }
return TRUE; }
VOID CollapseNode( HWND hwnd, LPITEMDATA lpid, DWORD nItem ) { DWORD i; LPITEMDATA lpidChild;
for (i=0; i<lpid->nchild; i++) { lpidChild = (LPITEMDATA) SendMessage( hwnd, LB_GETITEMDATA, nItem, 0 ); if (lpidChild->nchild) { CollapseNode( hwnd, lpidChild, nItem+1 ); } SendMessage( hwnd, LB_DELETESTRING, nItem, 0 ); }
lpid->nchild = 0; }
LRESULT HListWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { RECT cRect; HFONT hFont; LPHLISTINFO hli; LPHLISTTYPE hlt; LPHLISTTYPE hltNext; LPMEASUREITEMSTRUCT lpmis; LPDELETEITEMSTRUCT lplis; LPDRAWITEMSTRUCT lpdis; HBITMAP hbmp; HBITMAP hbmpOld; HDC hdc; TEXTMETRIC tm; int x; int y; int nItem; RECT rcBitmap; LPITEMDATA lpid; LPITEMDATA lpidParent; DWORD type; LPSTR str; DWORD rval; DWORD level; LPSTR ref; LPSTR p; POINT pt; DWORD childnum; DWORD i; HPEN hpen; HPEN oldhpen;
switch (message) { case WM_CREATE: hli = (LPHLISTINFO) malloc( sizeof(HLISTINFO) ); ZeroMemory( hli, sizeof(HLISTINFO) ); GetClientRect( hwnd, &cRect ); hli->hwndList = CreateWindow( "LISTBOX", NULL, DEFAULT_STYLE, cRect.left, cRect.top, cRect.right - cRect.left, cRect.bottom - cRect.top, hwnd, NULL, GetModuleHandle(NULL), NULL ); hFont = GetStockObject( SYSTEM_FIXED_FONT ); SendMessage( hli->hwndList, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE ); SetFocus( hli->hwndList ); SetWindowLong( hwnd, 0, (DWORD)hli ); break;
case WM_SIZE: hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); GetClientRect( hwnd, &cRect ); MoveWindow( hli->hwndList, cRect.left, cRect.top, cRect.right - cRect.left, cRect.bottom - cRect.top, TRUE ); break;
case WM_DESTROY: hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); hlt = hli->typeList; while (hlt) { hltNext = hlt->next; free( hlt ); hlt = hltNext; } DestroyWindow( hli->hwndList ); hli->hwndList = NULL; free( hli ); SetWindowLong( hwnd, 0, 0 ); break;
case WM_COMMAND: if (HIWORD(wParam) == LBN_DBLCLK) { hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); if (hli->lpCallback) { nItem = SendMessage( hli->hwndList, LB_GETCURSEL, 0, 0 );
lpidParent = (LPITEMDATA) SendMessage( hli->hwndList, LB_GETITEMDATA, nItem, 0 );
y = 0; lpid = lpidParent; while (lpid) { y += (strlen(lpid->str) + 1); lpid = lpid->parent; } y += 16; p = ref = malloc( y ); lpid = lpidParent; while (lpid) { strcpy( p, lpid->str ); p += (strlen(p) + 1); lpid = lpid->parent; } *p = '\0';
level = lpidParent->level + 1; type = lpidParent->type; str = lpidParent->str; rval = (hli->lpCallback)( &type, &str, ref, level, lpidParent->nchild );
if (rval == HLB_COLLAPSE) { CollapseNode( hli->hwndList, lpidParent, nItem+1 ); break; }
childnum = 1; while (rval != HLB_END) { if (rval == HLB_EXPAND) { hlt = hli->typeList; while (hlt && hlt->type != type) { hlt = hlt->next; } if (!hlt) { break; } lpidParent->nchild++; lpid = (LPITEMDATA) malloc( sizeof(ITEMDATA) ); lpid->type = type; lpid->nchild = 0; lpid->level = level; lpid->bitmap = hlt->bitmap; lpid->str = _strdup( (LPSTR)str ); lpid->parent = lpidParent; lpid->childnum = childnum++; nItem = SendMessage( hli->hwndList, LB_INSERTSTRING, nItem+1, (LPARAM)lpid->str ); SendMessage( hli->hwndList, LB_SETITEMDATA, nItem, (LPARAM) lpid ); } rval = (hli->lpCallback)( &type, &str, ref, level, 0 ); } free( ref ); } } break;
case HLB_REGISTER_CALLBACK: hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); hli->lpCallback = (HLISTCALLBACK) lParam; return 1;
case HLB_REGISTER_TYPE: //
// wParam = type token
// lParam = the bitmap
//
hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); if (!hli->typeList) { hli->typeList = (LPHLISTTYPE) malloc( sizeof(HLISTTYPE) ); hlt = hli->typeList; } else { hlt = hli->typeList; while (hlt->next) { hlt = hlt->next; } hlt->next = (LPHLISTTYPE) malloc( sizeof(HLISTTYPE) ); hlt = hlt->next; } hlt->type = (WPARAM) wParam; hlt->bitmap = (HBITMAP) lParam; hlt->next = NULL; return 1;
case HLB_ADDSTRING: //
// wParam = type
// lParam = string
//
hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); hlt = hli->typeList; while (hlt && hlt->type != wParam) { hlt = hlt->next; } if (!hlt) { return 0; } lpid = (LPITEMDATA) malloc( sizeof(ITEMDATA) ); lpid->type = hlt->type; lpid->level = 0; lpid->nchild = 0; lpid->bitmap = hlt->bitmap; lpid->str = _strdup( (LPSTR)lParam ); lpid->parent = NULL; lpid->childnum = 0; nItem = SendMessage( hli->hwndList, LB_ADDSTRING, 0, (LPARAM)lpid->str ); SendMessage( hli->hwndList, LB_SETITEMDATA, nItem, (LPARAM) lpid ); return 1;
case WM_MEASUREITEM: lpmis = (LPMEASUREITEMSTRUCT) lParam; lpmis->itemHeight = YBITMAP; return 1;
case WM_DELETEITEM: lplis = (LPDELETEITEMSTRUCT) lParam; lpid = (LPITEMDATA) lplis->itemData; free( lpid->str ); free( lpid ); return 1;
case WM_DRAWITEM: lpdis = (LPDRAWITEMSTRUCT) lParam;
if (lpdis->itemID == -1) { break; }
switch (lpdis->itemAction) { case ODA_SELECT: case ODA_DRAWENTIRE: lpid = (LPITEMDATA) SendMessage( lpdis->hwndItem, LB_GETITEMDATA, lpdis->itemID, 0 ); hbmp = lpid->bitmap;
hdc = CreateCompatibleDC( lpdis->hDC ); hbmpOld = SelectObject( hdc, hbmp );
lpdis->rcItem.left += (lpid->level * INDENT);
BitBlt( lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, lpdis->rcItem.right - lpdis->rcItem.left, lpdis->rcItem.bottom - lpdis->rcItem.top, hdc, 0, 0, SRCCOPY );
GetTextMetrics( lpdis->hDC, &tm );
y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
TextOut( lpdis->hDC, XBITMAP + MARGIN + (lpid->level * INDENT), y, lpid->str, strlen(lpid->str) );
SelectObject( hdc, hbmpOld );
//
// now draw lines
//
if (lpid->level) {
hpen = CreatePen( PS_SOLID, 1, LINE_COLOR ); oldhpen = SelectObject( lpdis->hDC, hpen );
y = lpdis->rcItem.top + ((lpdis->rcItem.bottom - lpdis->rcItem.top) / 2); MoveToEx( lpdis->hDC, lpdis->rcItem.left - 1, y, &pt );
LineTo( lpdis->hDC, lpdis->rcItem.left - MIDDLE, y );
MoveToEx( lpdis->hDC, lpdis->rcItem.left - MIDDLE, lpdis->rcItem.top, &pt );
if (lpid->childnum < lpid->parent->nchild) { y = lpdis->rcItem.bottom; } else { y++; }
LineTo( lpdis->hDC, lpdis->rcItem.left - MIDDLE, y );
if (lpid->level > 1) { x = lpdis->rcItem.left - MIDDLE; y = lpdis->rcItem.top; for (i=1; i<lpid->level; i++) { MoveToEx( lpdis->hDC, x - (i * INDENT), y, &pt ); LineTo( lpdis->hDC, x - (i * INDENT), lpdis->rcItem.bottom ); } }
SelectObject( lpdis->hDC, oldhpen ); DeleteObject( hpen ); }
DeleteDC( hdc );
if (lpdis->itemState & ODS_SELECTED) { rcBitmap.left = lpdis->rcItem.left; rcBitmap.top = lpdis->rcItem.top; rcBitmap.right = lpdis->rcItem.left + XBITMAP + (tm.tmMaxCharWidth * strlen(lpid->str)) + MARGIN + 2; rcBitmap.bottom = lpdis->rcItem.top + YBITMAP; DrawFocusRect( lpdis->hDC, &rcBitmap ); }
break;
case ODA_FOCUS: break; } return 1;
case LB_ADDSTRING: return SendMessage( hwnd, HLB_ADDSTRING, 1, lParam );
case LB_INSERTSTRING: case LB_DELETESTRING: case LB_SELITEMRANGEEX: case LB_RESETCONTENT: case LB_SETSEL: case LB_SETCURSEL: case LB_GETSEL: case LB_GETCURSEL: case LB_GETTEXT: case LB_GETTEXTLEN: case LB_GETCOUNT: case LB_SELECTSTRING: case LB_DIR: case LB_ADDFILE: case LB_GETTOPINDEX: case LB_FINDSTRING: case LB_GETSELCOUNT: case LB_GETSELITEMS: case LB_SETTABSTOPS: case LB_GETHORIZONTALEXTENT: case LB_SETHORIZONTALEXTENT: case LB_SETCOLUMNWIDTH: case LB_SETTOPINDEX: case LB_GETITEMRECT: case LB_GETITEMDATA: case LB_SETITEMDATA: case LB_SELITEMRANGE: case LB_SETANCHORINDEX: case LB_GETANCHORINDEX: case LB_SETCARETINDEX: case LB_GETCARETINDEX: case LB_SETITEMHEIGHT: case LB_GETITEMHEIGHT: case LB_FINDSTRINGEXACT: case LB_SETLOCALE: case LB_GETLOCALE: case LB_SETCOUNT: hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 ); return SendMessage( hli->hwndList, message, wParam, lParam ); }
return DefWindowProc( hwnd, message, wParam, lParam ); }
|