mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1188 lines
41 KiB
1188 lines
41 KiB
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright © 1993, 1994 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// PROGRAM: TREEVIEW.c
|
|
//
|
|
// PURPOSE: TREEVIEW template for Windows applications
|
|
//
|
|
//
|
|
// PLATFORMS: Chicago,NT
|
|
//
|
|
// FUNCTIONS:
|
|
// WinMain() - calls initialization function, processes message loop
|
|
// InitApplication() - initializes window data and registers window
|
|
// InitInstance() - saves instance handle and creates main window
|
|
// WndProc() - processes messages
|
|
// CenterWindow() - used to center the "About" box over application window
|
|
// About() - processes messages for "About" dialog box
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// The Windows SDK TREEVIEW Application Example is a sample application
|
|
// that you can use to get an idea of how to perform some of the simple
|
|
// functionality that all Applications written for Microsoft Windows
|
|
// should implement. You can use this application as either a starting
|
|
// point from which to build your own applications, or for quickly
|
|
// testing out functionality of an interesting Windows API.
|
|
//
|
|
// This application is source compatible for with Windows 3.1 and
|
|
// Windows NT.
|
|
//
|
|
// SPECIAL INSTRUCTIONS: N/A
|
|
//
|
|
|
|
#include <windows.h> // required for all Windows applications
|
|
#if !defined(_WIN32)
|
|
#include <ver.h>
|
|
#endif
|
|
|
|
|
|
#include "TREEVIEW.h" // specific to this program
|
|
|
|
|
|
//****************** NEW CODE START *********
|
|
|
|
#include <commctrl.h> // Common controls
|
|
#include <stdlib.h> // for atoi
|
|
|
|
|
|
//****************** NEW CODE END *********
|
|
|
|
// Windows NT defines APIENTRY, but 3.x doesn't
|
|
#if !defined (APIENTRY)
|
|
#define APIENTRY far pascal
|
|
#endif
|
|
|
|
// Windows 3.x uses a FARPROC for dialogs
|
|
#if !defined(_WIN32)
|
|
#define DLGPROC FARPROC
|
|
#endif
|
|
|
|
HINSTANCE hInst; // current instance
|
|
|
|
//******** NEW CODE START **************
|
|
|
|
HWND ghWnd; // Handle of main window
|
|
HWND hWndTreeView; // Handle of TreeView control
|
|
HIMAGELIST hCoasterImageList; // Roller coaster images
|
|
int iImageWood ; // Image number for the "Wood" roler coaster
|
|
int iImageSteel ; // Image number for the "Steel" roler coaster
|
|
int iImageCA ; // Images for states in open/closed... state
|
|
int iImageNY ; //
|
|
int iImageOH ; //
|
|
int iImageCA_OPEN; //
|
|
int iImageNY_OPEN; //
|
|
int iImageOH_OPEN; //
|
|
int iImageRider1 ; // Image of the coaster rider when not selected
|
|
int iImageRider2 ; // Image of the coaster rider when selected
|
|
|
|
// These are stored in lParam of the TV_ITEM structure, to
|
|
// help identify what type of thing the item is.
|
|
|
|
#define ITEM_TYPE_STATE_START 0
|
|
#define ITEM_TYPE_STATE_CA 0
|
|
#define ITEM_TYPE_STATE_NY 1 // The Coney Island Cyclone!
|
|
#define ITEM_TYPE_STATE_OH 2
|
|
#define ITEM_TYPE_STATE_END 50
|
|
|
|
#define ITEM_TYPE_COASTER_TYPE 100
|
|
#define ITEM_TYPE_COASTER_NAME 101
|
|
|
|
void FillTreeView ( HWND ); // Function to fill our TreeView with data
|
|
void Sample_Init ( void ); // All added init code
|
|
void Sample_Shutdown ( void ); // All added shutdown code
|
|
|
|
//******** NEW CODE END **************
|
|
|
|
char szAppName[] = "TREEVIEW"; // The name of this application
|
|
char szTitle[] = "TREEVIEW Sample Application"; // The title bar text
|
|
|
|
//
|
|
// FUNCTION: WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
|
//
|
|
// PURPOSE: calls initialization function, processes message loop
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// Windows recognizes this function by name as the initial entry point
|
|
// for the program. This function calls the application initialization
|
|
// routine, if no other instance of the program is running, and always
|
|
// calls the instance initialization routine. It then executes a
|
|
// message retrieval and dispatch loop that is the top-level control
|
|
// structure for the remainder of execution. The loop is terminated
|
|
// when a WM_QUIT message is received, at which time this function
|
|
// exits the application instance by returning the value passed by
|
|
// PostQuitMessage().
|
|
//
|
|
// If this function must abort before entering the message loop, it
|
|
// returns the conventional value NULL.
|
|
//
|
|
|
|
int APIENTRY WinMain(
|
|
HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nCmdShow
|
|
)
|
|
{
|
|
MSG msg;
|
|
HANDLE hAccelTable;
|
|
|
|
// Other instances of app running?
|
|
if (!hPrevInstance) {
|
|
// Initialize shared things
|
|
if (!InitApplication(hInstance)) {
|
|
return (FALSE); // Exits if unable to initialize
|
|
}
|
|
}
|
|
|
|
// Perform initializations that apply to a specific instance
|
|
if (!InitInstance(hInstance, nCmdShow)) {
|
|
return (FALSE);
|
|
}
|
|
|
|
//****************** NEW CODE START *********
|
|
|
|
Sample_Init ( );
|
|
|
|
//****************** NEW CODE END *********
|
|
|
|
hAccelTable = LoadAccelerators (hInstance, szAppName);
|
|
|
|
// Acquire and dispatch messages until a WM_QUIT message is received.
|
|
while (GetMessage(&msg, // message structure
|
|
NULL, // handle of window receiving the message
|
|
0, // lowest message to examine
|
|
0)){ // highest message to examine
|
|
if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg)) {
|
|
TranslateMessage(&msg);// Translates virtual key codes
|
|
DispatchMessage(&msg); // Dispatches message to window
|
|
}
|
|
}
|
|
|
|
//****************** NEW CODE START *********
|
|
|
|
Sample_Shutdown ( );
|
|
|
|
//****************** NEW CODE END *********
|
|
|
|
// Returns the value from PostQuitMessage
|
|
return (msg.wParam);
|
|
|
|
// This will prevent 'unused formal parameter' warnings
|
|
lpCmdLine;
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: InitApplication(HINSTANCE)
|
|
//
|
|
// PURPOSE: Initializes window data and registers window class
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// This function is called at initialization time only if no other
|
|
// instances of the application are running. This function performs
|
|
// initialization tasks that can be done once for any number of running
|
|
// instances.
|
|
//
|
|
// In this case, we initialize a window class by filling out a data
|
|
// structure of type WNDCLASS and calling the Windows RegisterClass()
|
|
// function. Since all instances of this application use the same
|
|
// window class, we only need to do this when the first instance is
|
|
// initialized.
|
|
//
|
|
|
|
BOOL InitApplication(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
// Fill in window class structure with parameters that describe the
|
|
// main window.
|
|
wc.style = CS_HREDRAW | CS_VREDRAW; // Class style(s).
|
|
wc.lpfnWndProc = (WNDPROC)WndProc; // Window Procedure
|
|
wc.cbClsExtra = 0; // No per-class extra data.
|
|
wc.cbWndExtra = 0; // No per-window extra data.
|
|
wc.hInstance = hInstance; // Owner of this class
|
|
wc.hIcon = LoadIcon (hInstance, szAppName);// Icon name from .RC
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Cursor
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);// Default color
|
|
wc.lpszMenuName = szAppName; // Menu name from .RC
|
|
wc.lpszClassName = szAppName; // Name to register as
|
|
|
|
// Register the window class and return success/failure code.
|
|
return (RegisterClass(&wc));
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: InitInstance(HINSTANCE, int)
|
|
//
|
|
// PURPOSE: Saves instance handle and creates main window
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// This function is called at initialization time for every instance of
|
|
// this application. This function performs initialization tasks that
|
|
// cannot be shared by multiple instances.
|
|
//
|
|
// In this case, we save the instance handle in a static variable and
|
|
// create and display the main program window.
|
|
//
|
|
|
|
BOOL InitInstance(
|
|
HINSTANCE hInstance,
|
|
int nCmdShow
|
|
)
|
|
{
|
|
HWND hWnd; // Main window handle.
|
|
|
|
// Save the instance handle in static variable, which will be used in
|
|
// many subsequence calls from this application to Windows.
|
|
|
|
hInst = hInstance; // Store instance handle in our global variable
|
|
|
|
// Create a main window for this application instance.
|
|
hWnd = CreateWindow(
|
|
szAppName, // See RegisterClass() call.
|
|
szTitle, // Text for window title bar.
|
|
WS_OVERLAPPEDWINDOW,// Window style.
|
|
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,// Use default positioning
|
|
NULL, // Overlapped windows have no parent.
|
|
NULL, // Use the window class menu.
|
|
hInstance, // This instance owns this window.
|
|
NULL // We don't use any data in our WM_CREATE
|
|
);
|
|
|
|
// If window could not be created, return "failure"
|
|
if (!hWnd) {
|
|
return (FALSE);
|
|
}
|
|
|
|
//****************** NEW CODE START *********
|
|
|
|
ghWnd = hWnd;
|
|
|
|
//****************** NEW CODE END *********
|
|
|
|
// Make the window visible; update its client area; and return "success"
|
|
ShowWindow(hWnd, nCmdShow); // Show the window
|
|
UpdateWindow(hWnd); // Sends WM_PAINT message
|
|
|
|
return (TRUE); // We succeeded...
|
|
}
|
|
|
|
//****************** NEW CODE START *********
|
|
|
|
//*****************************************************
|
|
//
|
|
// Sample_Init: Creates the Image List, the TreeView, and
|
|
// calls the FillTreeView function to put some stuff into it
|
|
//
|
|
//*****************************************************
|
|
|
|
void Sample_Init ( void ) // All added init code
|
|
{
|
|
RECT rc;
|
|
|
|
InitCommonControls(); // This MUST be called once per instance
|
|
// to register the TreeView class.
|
|
|
|
hCoasterImageList = ImageList_Create
|
|
(
|
|
32, 32,
|
|
TRUE,
|
|
5,
|
|
1
|
|
);
|
|
|
|
iImageWood = ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "WOOD" ));
|
|
iImageSteel = ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "STEEL" ));
|
|
iImageOH = ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "OH" ));
|
|
iImageNY = ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "NY" ));
|
|
iImageCA = ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "CA" ));
|
|
iImageOH_OPEN= ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "OH_OPEN"));
|
|
iImageNY_OPEN= ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "NY_OPEN"));
|
|
iImageCA_OPEN= ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "CA_OPEN"));
|
|
|
|
iImageRider1 = ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "RIDER1" ));
|
|
iImageRider2 = ImageList_AddIcon ( hCoasterImageList, LoadIcon ( hInst, "RIDER2" ));
|
|
|
|
GetClientRect ( ghWnd, &rc );
|
|
|
|
hWndTreeView = CreateWindow ( WC_TREEVIEW,
|
|
"",
|
|
WS_VISIBLE | WS_CHILD | WS_BORDER |
|
|
TVS_HASLINES | TVS_EDITLABELS,
|
|
0, 0,
|
|
rc.right, rc.bottom,
|
|
ghWnd,
|
|
(HMENU)NULL,
|
|
hInst,
|
|
NULL
|
|
);
|
|
|
|
if (hWndTreeView)
|
|
{
|
|
TreeView_SetImageList ( hWndTreeView, hCoasterImageList, 0 );
|
|
ImageList_SetBkColor ( hCoasterImageList, GetSysColor ( COLOR_WINDOW ));
|
|
FillTreeView ( hWndTreeView );
|
|
}
|
|
}
|
|
|
|
//*****************************************************
|
|
//
|
|
// Sample_Shutdown: Deletes the Image List
|
|
//
|
|
//*****************************************************
|
|
|
|
void Sample_Shutdown ( void ) // All added shutdown code
|
|
{
|
|
if (hCoasterImageList) ImageList_Destroy ( hCoasterImageList );
|
|
}
|
|
|
|
//*****************************************************
|
|
//
|
|
// iNumCoasters: Returns the number of coasters in the
|
|
// string table. The stringtable must have
|
|
// the form where the string at the iCoasterIndex
|
|
// is an ascii string with the number of coasters,
|
|
// and then the strings from iCoasterIndex+1 to
|
|
// iCoasterIndex+n+1 have the actual coasters.
|
|
//
|
|
//*****************************************************
|
|
|
|
int iNumCoasters ( int iCoasterIndex )
|
|
{
|
|
char sz[16];
|
|
|
|
if (LoadString ( hInst, iCoasterIndex, sz, sizeof(sz)))
|
|
return atoi ( sz );
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//*****************************************************
|
|
//
|
|
// CoastersInfo: Your basic, boring string parser routine.
|
|
// This function loads a string from the
|
|
// string table with the format of
|
|
// STATE,COASTER,TYPE and puts the individual
|
|
// peices in the pointers passed into this
|
|
// function. Yawn.
|
|
//
|
|
//*****************************************************
|
|
|
|
BOOL CoasterInfo ( int iCoasterIndex,
|
|
LPSTR szState,
|
|
LPSTR szCoaster,
|
|
LPSTR szType
|
|
)
|
|
{
|
|
char szRaw[256];
|
|
LPSTR szPtr;
|
|
int i, iLen;
|
|
int iWZIQ = 0;
|
|
|
|
// Get the string from the resource template
|
|
|
|
if (!LoadString ( hInst, iCoasterIndex, szRaw, sizeof(szRaw)))
|
|
return FALSE;
|
|
|
|
// Change the comma delimiters to NULLs, chopping the one string
|
|
// into a bunch of little ones
|
|
|
|
iLen = lstrlen ( szRaw );
|
|
for ( i = 0; i < iLen; i++ ) if ( ',' == szRaw[i] ) szRaw[i] = 0;
|
|
|
|
// Copy the info into the parameters
|
|
|
|
szPtr = szRaw;
|
|
|
|
lstrcpy ( szState, szPtr ); szPtr += lstrlen ( szPtr ) + 1;
|
|
lstrcpy ( szCoaster, szPtr ); szPtr += lstrlen ( szPtr ) + 1;
|
|
lstrcpy ( szType, szPtr );
|
|
|
|
// Success! Let's ride!
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*****************************************************
|
|
//
|
|
// AddTreeViewItem: This function adds an item to the
|
|
// TreeView control, you give it the
|
|
// string, images, lParam, parent,
|
|
// and sibling, and it fills out the
|
|
// data structures and makes the actual
|
|
// calls into the TreeView via the
|
|
// macros from COMMCTRL.H.
|
|
//
|
|
//*****************************************************
|
|
|
|
HTREEITEM AddTreeViewItem ( HWND hWndTV,
|
|
HTREEITEM hParent,
|
|
HTREEITEM hInsertAfter,
|
|
int iImage,
|
|
int iSelectedImage,
|
|
LPSTR szText,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
TV_ITEM tvItem;
|
|
TV_INSERTSTRUCT tvIns;
|
|
|
|
// Set which attribytes we are going to fill out.
|
|
tvItem.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
|
|
|
|
// Set the attribytes
|
|
tvItem.pszText = szText;
|
|
tvItem.iImage = iImage;
|
|
tvItem.iSelectedImage = iSelectedImage;
|
|
tvItem.lParam = lParam;
|
|
|
|
// Fill out the TV_INSERTSTRUCT
|
|
tvIns.hParent = hParent;
|
|
tvIns.hInsertAfter = hInsertAfter;
|
|
tvIns.item = tvItem;
|
|
|
|
// And insert the item, returning its handle
|
|
return TreeView_InsertItem ( hWndTV, &tvIns );
|
|
}
|
|
|
|
//*****************************************************
|
|
//
|
|
// FindOrAddTreeViewItem: This function will add an item to
|
|
// a TreeView in the right spot. You
|
|
// must specify the parent node of where
|
|
// this item is to be added, and then
|
|
// this function will check to see if a
|
|
// node already exists with this name.
|
|
// If a node with this name already
|
|
// exists, then its handle is returned.
|
|
// If the node does not exist, then the
|
|
// AddTreeViewItem function from
|
|
// above is called to add the item.
|
|
// See how this function is used
|
|
// in the FillTreeView function down
|
|
// below.
|
|
//
|
|
//*****************************************************
|
|
|
|
HTREEITEM FindOrAddTreeViewItem ( HWND hWndTV,
|
|
HTREEITEM hParent,
|
|
int iImage,
|
|
int iSelectedImage,
|
|
LPSTR szText,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
TV_ITEM tvItem; // Temporary item
|
|
HTREEITEM hItem; // Handle to item
|
|
HTREEITEM hPrevItem = (HTREEITEM) TVI_FIRST; // Handle to previous item
|
|
char szBuffer[256]; // Temporary buffer
|
|
|
|
// Get the first child of the passed in parent
|
|
hItem = TreeView_GetChild ( hWndTV, hParent );
|
|
|
|
// Loop through all children, looking for an already existing
|
|
// child.
|
|
|
|
while ( hItem )
|
|
{
|
|
tvItem.mask = TVIF_TEXT; // We want the text
|
|
tvItem.hItem = hItem; // Indicate the item to fetch
|
|
tvItem.pszText = szBuffer; // Indicate the buffer
|
|
tvItem.cchTextMax = sizeof(szBuffer); // Indicate buffer's size
|
|
|
|
TreeView_GetItem ( hWndTV, &tvItem ); // Fetch, Rover!
|
|
|
|
if (!lstrcmpi (tvItem.pszText, szText)) // Found it! Just return item
|
|
return hItem;
|
|
|
|
hPrevItem = hItem; // Remember the last item, since the next line
|
|
// of code will eventually put a NULL in the
|
|
// hItem variable, and we want to know the
|
|
// last item under the parent in case we need
|
|
// to add a new item.
|
|
|
|
// Get the next sibling item in the TreeView, if any.
|
|
hItem = TreeView_GetNextSibling ( hWndTV, hItem );
|
|
}
|
|
|
|
// If we made it here, then the item needs to be added
|
|
// onto the end of the list
|
|
|
|
return AddTreeViewItem ( hWndTV, // Handle of TreeView
|
|
hParent, // Parent item
|
|
hPrevItem, // Last child in list (from above loop)
|
|
iImage, // These are the parameters
|
|
iSelectedImage,// passed into this
|
|
szText, // function.
|
|
lParam //
|
|
);
|
|
}
|
|
|
|
//***************************************************************
|
|
//
|
|
// This function fills the TreeView control with our coasters!
|
|
//
|
|
//***************************************************************
|
|
|
|
#define ADDSTATEROOT(iType) \
|
|
FindOrAddTreeViewItem ( hWndTV, \
|
|
TVGN_ROOT, \
|
|
I_IMAGECALLBACK, \
|
|
I_IMAGECALLBACK, \
|
|
szState, \
|
|
iType)
|
|
|
|
#define ADDTYPENODE(iImageType) \
|
|
FindOrAddTreeViewItem ( hWndTV, \
|
|
hParent, \
|
|
iImageType, \
|
|
iImageType, \
|
|
szType, \
|
|
ITEM_TYPE_COASTER_TYPE)
|
|
|
|
void FillTreeView ( HWND hWndTV )
|
|
{
|
|
int i; // Counter
|
|
int iNum; // Number of coasters in stringtable
|
|
|
|
char szState[64]; // State coaster is in
|
|
char szCoaster[128]; // Coaster's name
|
|
char szType[64]; // Type of coaster (wood or steel)
|
|
|
|
HTREEITEM hParent; // Parent node to add to.
|
|
|
|
iNum = iNumCoasters ( COASTERSTRING ); // Figure number of coasters
|
|
|
|
// Run through string table, adding each coaster. This algorithm
|
|
// calls the CoasterInfo function to parse the stringtable
|
|
// entry into the state, type, and coaster name. The state
|
|
// string is the topmost node, the coaster type is the secondary
|
|
// node, and the coaster name is the actual item.
|
|
// This loop first tries to find the topmost state node, and if
|
|
// it can't find it, it adds it by using the FindOrAddTreeViewItem
|
|
// function. Then, once the state node is added, the same process
|
|
// is done for the coaster type node under the appropriate state.
|
|
// Once the state node is determined, then the actual item is
|
|
// added to the TreeView in the correct place.
|
|
|
|
for ( i = 1; i <= iNum; i++ )
|
|
{
|
|
// Get string from stringtable and parse it
|
|
if (CoasterInfo ( i + COASTERSTRING, szState, szCoaster, szType ))
|
|
{
|
|
// Add or find the state node. The ADDSTATEROOT macro defined
|
|
// above is used for readibility.
|
|
|
|
switch (*szState)
|
|
{
|
|
case 'C': hParent = ADDSTATEROOT (ITEM_TYPE_STATE_CA); break;
|
|
case 'N': hParent = ADDSTATEROOT (ITEM_TYPE_STATE_NY); break;
|
|
case 'O': hParent = ADDSTATEROOT (ITEM_TYPE_STATE_OH); break;
|
|
}
|
|
|
|
// Now that we know what state node to use, add or find
|
|
// the type of the coaster node. The ADDTYPENODE macro defined
|
|
// above is used for readibility.
|
|
|
|
if ('W' == *szType)
|
|
hParent = ADDTYPENODE (iImageWood);
|
|
else
|
|
hParent = ADDTYPENODE (iImageSteel);
|
|
|
|
// Now that we know the parent for the actual coaster, add that
|
|
// to the list.
|
|
|
|
FindOrAddTreeViewItem ( hWndTV, // TreeView control
|
|
hParent, // Parent type node
|
|
iImageRider1, // Placid rider
|
|
iImageRider2, // Screaming rider
|
|
szCoaster, // Coaster name
|
|
ITEM_TYPE_COASTER_NAME );
|
|
}
|
|
}
|
|
}
|
|
|
|
//****************** NEW CODE END *********
|
|
|
|
//
|
|
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
|
|
//
|
|
// PURPOSE: Processes messages
|
|
//
|
|
// MESSAGES:
|
|
//
|
|
// WM_COMMAND - application menu (About dialog box)
|
|
// WM_DESTROY - destroy window
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// To process the IDM_ABOUT message, call MakeProcInstance() to get the
|
|
// current instance address of the About() function. Then call Dialog
|
|
// box which will create the box according to the information in your
|
|
// TREEVIEW.rc file and turn control over to the About() function. When
|
|
// it returns, free the intance address.
|
|
//
|
|
|
|
|
|
LRESULT CALLBACK WndProc(
|
|
HWND hWnd, // window handle
|
|
UINT message, // type of message
|
|
WPARAM uParam, // additional information
|
|
LPARAM lParam // additional information
|
|
)
|
|
{
|
|
FARPROC lpProcAbout; // pointer to the "About" function
|
|
int wmId, wmEvent;
|
|
|
|
//****************** NEW CODE START *********
|
|
|
|
#define ptrNMHDR ((LPNMHDR)lParam)
|
|
#define ptrNM_TREEVIEW ((NM_TREEVIEW *)lParam)
|
|
#define ptrTV_DISPINFO ((TV_DISPINFO *)lParam)
|
|
|
|
RECT rcItem;
|
|
static HIMAGELIST hDragImage;
|
|
static BOOL bDragging;
|
|
static HTREEITEM hDragItem;
|
|
|
|
switch (message) {
|
|
|
|
case WM_NOTIFY: // This is a new Chicago message for control
|
|
// notifications
|
|
|
|
switch (ptrNMHDR->code)
|
|
{
|
|
case TVN_BEGINDRAG: // Sent by TreeView when user
|
|
// wants to drag an item.
|
|
|
|
// Only allow drag & drop for the actual coaster
|
|
// items. The "itemNew" field of the NM_TREEVIEW
|
|
// structure contains the attribytes of the item
|
|
// we are going to drag. Therefore, since we are
|
|
// using the lParam field to store an ITEM_TYPE_*
|
|
// value, we check that field.
|
|
|
|
if ( ITEM_TYPE_COASTER_NAME == ptrNM_TREEVIEW->itemNew.lParam)
|
|
{
|
|
// The hDragImage variable is declared static,
|
|
// so the code in WM_LBUTTONUP can delete it when
|
|
// the user stops dragging. Here we create a
|
|
// drag image to use for the ImageList_StartDrag
|
|
// API.
|
|
|
|
hDragImage = TreeView_CreateDragImage
|
|
(
|
|
ptrNMHDR->hwndFrom,
|
|
ptrNM_TREEVIEW->itemNew.hItem
|
|
);
|
|
|
|
// Get the location of the item rectangle's text.
|
|
|
|
TreeView_GetItemRect
|
|
(
|
|
ptrNMHDR->hwndFrom, // Handle of TreeView
|
|
ptrNM_TREEVIEW->itemNew.hItem, // Item in TreeView
|
|
&rcItem, // RECT to store result
|
|
TRUE // Rect of label text only
|
|
);
|
|
|
|
// Cache away the handle of the item to drag into a
|
|
// staticly declared variable, so the code in
|
|
// WM_LBUTTONUP can know what the user is dragging.
|
|
|
|
hDragItem = ptrNM_TREEVIEW->itemNew.hItem;
|
|
|
|
// Start the drag ala ImageList
|
|
|
|
ImageList_BeginDrag(hDragImage, 0,
|
|
ptrNM_TREEVIEW->ptDrag.x - rcItem.left, // Offset hotspot
|
|
ptrNM_TREEVIEW->ptDrag.y - rcItem.top);
|
|
|
|
|
|
ImageList_DragEnter(ptrNMHDR->hwndFrom,
|
|
ptrNM_TREEVIEW->ptDrag.x, // Coords of image to drag
|
|
ptrNM_TREEVIEW->ptDrag.y);
|
|
|
|
// Capture the mousey to this window
|
|
|
|
ShowCursor ( FALSE );
|
|
SetCapture ( hWnd );
|
|
|
|
// Set a staticly declared drag flag so the WM_MOUSEMOVE
|
|
// and WM_LBUTTONUP messages know to take action.
|
|
|
|
bDragging = TRUE;
|
|
}
|
|
|
|
return 0L; // Return value is irrelevant
|
|
|
|
case TVN_GETDISPINFO: // Sent by TreeView just before it paints
|
|
// an item declared with callback values.
|
|
|
|
// Our "state" items have the I_IMAGECALLBACK value
|
|
// used for the iImage and iSelectedImage fields. This
|
|
// TVN_GETDISPINFO code will be called whenever the
|
|
// item is about to be drawn. It is out responsibility
|
|
// to add code to fill in the images. The code below
|
|
// uses a different image depending on if the item is
|
|
// expanded or collapsed. That attribute is in the
|
|
// state field of the item passed in the TV_DISPINFO
|
|
// structure.
|
|
|
|
// Our lParam is where we store what state the item
|
|
// represents. Therefore, we will switch on that so
|
|
// we can indicate the correct image to use.
|
|
|
|
if ( ptrTV_DISPINFO->item.state & TVIS_EXPANDED )
|
|
{
|
|
switch (ptrTV_DISPINFO->item.lParam)
|
|
{
|
|
case ITEM_TYPE_STATE_CA:
|
|
|
|
ptrTV_DISPINFO->item.iImage =
|
|
ptrTV_DISPINFO->item.iSelectedImage = iImageCA_OPEN;
|
|
break;
|
|
|
|
case ITEM_TYPE_STATE_NY:
|
|
|
|
ptrTV_DISPINFO->item.iImage =
|
|
ptrTV_DISPINFO->item.iSelectedImage = iImageNY_OPEN;
|
|
break;
|
|
|
|
case ITEM_TYPE_STATE_OH:
|
|
|
|
ptrTV_DISPINFO->item.iImage =
|
|
ptrTV_DISPINFO->item.iSelectedImage = iImageOH_OPEN;
|
|
break;
|
|
}
|
|
}
|
|
else // Collapsed item
|
|
{
|
|
switch (ptrTV_DISPINFO->item.lParam)
|
|
{
|
|
case ITEM_TYPE_STATE_CA:
|
|
|
|
ptrTV_DISPINFO->item.iImage =
|
|
ptrTV_DISPINFO->item.iSelectedImage = iImageCA;
|
|
break;
|
|
|
|
case ITEM_TYPE_STATE_NY:
|
|
|
|
ptrTV_DISPINFO->item.iImage =
|
|
ptrTV_DISPINFO->item.iSelectedImage = iImageNY;
|
|
break;
|
|
|
|
case ITEM_TYPE_STATE_OH:
|
|
|
|
ptrTV_DISPINFO->item.iImage =
|
|
ptrTV_DISPINFO->item.iSelectedImage = iImageOH;
|
|
break;
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case TVN_BEGINLABELEDIT: // Sent by TreeView when user single
|
|
// clicks on an item in a TreeView
|
|
// that has the TVS_EDITLABELS style
|
|
// bit set.
|
|
|
|
// Only allow label editing for the coaster names
|
|
|
|
if (ITEM_TYPE_COASTER_NAME == ptrTV_DISPINFO->item.lParam)
|
|
return 0; // Return 0 to OK edit
|
|
else
|
|
return 1; // Return non-zero to disallow edit
|
|
break;
|
|
|
|
case TVN_ENDLABELEDIT: // Sent by TreeView when user presses
|
|
// the ENTER key or ESC key, to end
|
|
// an in-place edit session. If the user
|
|
// pressed the ESC key, the pszText
|
|
// field of the item in the TV_DISPINFO
|
|
// field is NULL.
|
|
|
|
// if user pressed ENTER to accept edits
|
|
|
|
|
|
if ( ptrTV_DISPINFO->item.pszText)
|
|
{
|
|
// Set the "change mask" to indicate that the only attribute
|
|
// we wish to change is the text field. The TV_DISPINFO
|
|
// structure has already been filled out with the new
|
|
// text the user typed in, we just need to pass that on
|
|
// to the TreeView control. This is our chance to evaluate
|
|
// the contents of this field and change it.
|
|
|
|
|
|
ptrTV_DISPINFO->item.mask = TVIF_TEXT;
|
|
|
|
TreeView_SetItem
|
|
(
|
|
ptrNMHDR->hwndFrom, // Handle of TreeView
|
|
&(ptrTV_DISPINFO->item) // TV_ITEM structure w/changes
|
|
);
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
return (DefWindowProc(hWnd, message, uParam, lParam));
|
|
|
|
case WM_MOUSEMOVE: // Since the mouse capture is set to this
|
|
// window while we do our drag & drop,
|
|
// we check for the drag flag and process
|
|
// the WM_MOUSEMOVE message.
|
|
|
|
if (bDragging)
|
|
{
|
|
HTREEITEM hTarget; // Item under mouse
|
|
TV_HITTESTINFO tvht; // Used for hit testing
|
|
|
|
// Do standard drag drop movement
|
|
|
|
ImageList_DragMove ( LOWORD (lParam), HIWORD (lParam));
|
|
|
|
// Fill out hit test struct with mouse pos
|
|
|
|
tvht.pt.x = LOWORD (lParam);
|
|
tvht.pt.y = HIWORD (lParam);
|
|
|
|
// Check to see if an item lives under the mouse
|
|
|
|
if ( hTarget = TreeView_HitTest
|
|
(
|
|
hWndTreeView, // This is the global variable
|
|
&tvht // TV_HITTESTINFO struct
|
|
)
|
|
)
|
|
{
|
|
TV_ITEM tvi; // Temporary Item
|
|
|
|
tvi.mask = TVIF_PARAM; // We want to fetch the
|
|
// lParam field.
|
|
|
|
tvi.hItem = hTarget; // Set the handle of the
|
|
// item to fetch.
|
|
|
|
TreeView_GetItem ( hWndTreeView, &tvi ); // Fetch, spot!
|
|
|
|
// Check to see if the lParam is a valid item to drop
|
|
// onto (in this case, another roller coaster, such as
|
|
// the Coney Island Cyclone). Skip this operation if
|
|
// the item is already selected (to avoid flicker)
|
|
|
|
if ( ITEM_TYPE_COASTER_NAME == tvi.lParam )
|
|
{
|
|
if ( hTarget != TreeView_GetDropHilight (hWndTreeView))
|
|
{
|
|
// Hide the drag image
|
|
ImageList_DragShowNolock ( FALSE ); //DragShow to DragShowNoLock lithangw
|
|
// Select the item
|
|
TreeView_SelectDropTarget ( hWndTreeView, hTarget );
|
|
// Show the drag image
|
|
ImageList_DragShowNolock ( TRUE ); //DragShow to DragShowNoLock lithangw
|
|
}
|
|
return 0L;
|
|
}
|
|
}
|
|
|
|
// If we made it here, then the user has either
|
|
// dragged the mouse over an invalid item, or no item.
|
|
// Hide any current drop target, this is a no-no drop
|
|
ImageList_DragShowNolock ( FALSE ); //screen update problem tokuroy
|
|
TreeView_SelectDropTarget ( hWndTreeView, NULL );
|
|
ImageList_DragShowNolock ( TRUE ); //screen update problem tokuroy
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONUP: // Since the mouse capture is set to this
|
|
// window while we do our drag & drop,
|
|
// we check for the drag flag and process
|
|
// the WM_LBUTTONUP message.
|
|
|
|
|
|
if (bDragging)
|
|
{
|
|
HTREEITEM hTarget; // Item under mouse
|
|
TV_ITEM tvi; // Temporary Item
|
|
TV_INSERTSTRUCT tvIns; // Insert struct
|
|
char szBuffer[256]; // Item text buffer
|
|
|
|
// End the drag
|
|
ImageList_EndDrag();
|
|
// Bring back the cursor
|
|
ShowCursor ( TRUE );
|
|
// Release the mouse capture
|
|
ReleaseCapture();
|
|
// Clear the drag flag
|
|
bDragging = FALSE;
|
|
// Clean up the image list object
|
|
ImageList_Destroy ( hDragImage );
|
|
hDragImage = NULL;
|
|
|
|
// First, check to see if there is a valid drop point.
|
|
// The cheezy way to do this is to check for a highlighted
|
|
// drop target, since the logic to validate drop points
|
|
// is in the WM_MOUSEMOVE. Duping that code here would
|
|
// be a headache.
|
|
|
|
if ( hTarget = TreeView_GetDropHilight (hWndTreeView))
|
|
{
|
|
// If we made it here, then we need to move the item.
|
|
// First, we will fetch it, specifying the attributes
|
|
// we need to copy.
|
|
|
|
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
|
|
tvi.hItem = hDragItem;
|
|
tvi.pszText = szBuffer;
|
|
tvi.cchTextMax = sizeof(szBuffer);
|
|
|
|
TreeView_GetItem ( hWndTreeView, &tvi );
|
|
|
|
// Now, figure the new place to put it by filling out
|
|
// the TV_INSERTSTRUCT structure, to use the drop target
|
|
// as the sibling to insert after, and using the drop
|
|
// target's parent as the parent to insert this one
|
|
// after as well.
|
|
|
|
tvIns.hParent = TreeView_GetParent ( hWndTreeView, hTarget );
|
|
tvIns.hInsertAfter = hTarget;
|
|
tvIns.item = tvi;
|
|
|
|
// Delete the old item
|
|
|
|
TreeView_DeleteItem ( hWndTreeView, hDragItem );
|
|
|
|
// And add the new item (if your app tracks the handles of
|
|
// the items, you want to use the return value
|
|
// of this function to update your data structure that
|
|
// tracks the handles.
|
|
|
|
TreeView_InsertItem ( hWndTreeView, &tvIns );
|
|
}
|
|
|
|
// Clear any drop highlights on the TreeView
|
|
|
|
TreeView_SelectDropTarget ( hWndTreeView, NULL );
|
|
}
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
|
|
if ( hWndTreeView ) // Standard code to keep the TreeView
|
|
// sized up with the main window
|
|
{
|
|
SetWindowPos ( hWndTreeView,
|
|
NULL,
|
|
0, 0,
|
|
LOWORD (lParam),
|
|
HIWORD (lParam),
|
|
SWP_NOZORDER
|
|
);
|
|
}
|
|
break;
|
|
|
|
//****************** NEW CODE END *********
|
|
|
|
case WM_COMMAND: // message: command from application menu
|
|
|
|
// Message packing of uParam and lParam have changed for Win32,
|
|
// let us handle the differences in a conditional compilation:
|
|
#if defined (_WIN32)
|
|
wmId = LOWORD(uParam);
|
|
wmEvent = HIWORD(uParam);
|
|
#else
|
|
wmId = uParam;
|
|
wmEvent = HIWORD(lParam);
|
|
#endif
|
|
|
|
switch (wmId) {
|
|
case IDM_ABOUT:
|
|
lpProcAbout = MakeProcInstance((FARPROC)About, hInst);
|
|
|
|
DialogBox(hInst, // current instance
|
|
"AboutBox", // dlg resource to use
|
|
hWnd, // parent handle
|
|
(DLGPROC)lpProcAbout); // About() instance address
|
|
|
|
FreeProcInstance(lpProcAbout);
|
|
break;
|
|
|
|
case IDM_EXIT:
|
|
DestroyWindow (hWnd);
|
|
break;
|
|
|
|
case IDM_HELPCONTENTS:
|
|
if (!WinHelp (hWnd, "TREEVIEW.HLP", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
|
|
MessageBox (GetFocus(),
|
|
"Unable to activate help",
|
|
szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
|
|
|
|
}
|
|
break;
|
|
|
|
case IDM_HELPSEARCH:
|
|
if (!WinHelp(hWnd, "TREEVIEW.HLP", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
|
|
MessageBox (GetFocus(),
|
|
"Unable to activate help",
|
|
szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
|
|
}
|
|
break;
|
|
|
|
case IDM_HELPHELP:
|
|
if(!WinHelp(hWnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
|
|
MessageBox (GetFocus(),
|
|
"Unable to activate help",
|
|
szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
|
|
}
|
|
break;
|
|
|
|
// Here are all the other possible menu options,
|
|
// all of these are currently disabled:
|
|
case IDM_NEW:
|
|
case IDM_OPEN:
|
|
case IDM_SAVE:
|
|
case IDM_SAVEAS:
|
|
case IDM_UNDO:
|
|
case IDM_CUT:
|
|
case IDM_COPY:
|
|
case IDM_PASTE:
|
|
case IDM_LINK:
|
|
case IDM_LINKS:
|
|
|
|
default:
|
|
return (DefWindowProc(hWnd, message, uParam, lParam));
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY: // message: window being destroyed
|
|
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
default: // Passes it on if unproccessed
|
|
return (DefWindowProc(hWnd, message, uParam, lParam));
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// FUNCTION: CenterWindow (HWND, HWND)
|
|
//
|
|
// PURPOSE: Center one window over another
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// Dialog boxes take on the screen position that they were designed
|
|
// at, which is not always appropriate. Centering the dialog over a
|
|
// particular window usually results in a better position.
|
|
//
|
|
|
|
BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
|
|
{
|
|
RECT rChild, rParent;
|
|
int wChild, hChild, wParent, hParent;
|
|
int wScreen, hScreen, xNew, yNew;
|
|
HDC hdc;
|
|
|
|
// Get the Height and Width of the child window
|
|
GetWindowRect (hwndChild, &rChild);
|
|
wChild = rChild.right - rChild.left;
|
|
hChild = rChild.bottom - rChild.top;
|
|
|
|
// Get the Height and Width of the parent window
|
|
GetWindowRect (hwndParent, &rParent);
|
|
wParent = rParent.right - rParent.left;
|
|
hParent = rParent.bottom - rParent.top;
|
|
|
|
// Get the display limits
|
|
hdc = GetDC (hwndChild);
|
|
wScreen = GetDeviceCaps (hdc, HORZRES);
|
|
hScreen = GetDeviceCaps (hdc, VERTRES);
|
|
ReleaseDC (hwndChild, hdc);
|
|
|
|
// Calculate new X position, then adjust for screen
|
|
xNew = rParent.left + ((wParent - wChild) /2);
|
|
if (xNew < 0) {
|
|
xNew = 0;
|
|
}
|
|
else if ((xNew+wChild) > wScreen) {
|
|
xNew = wScreen - wChild;
|
|
}
|
|
|
|
// Calculate new Y position, then adjust for screen
|
|
yNew = rParent.top + ((hParent - hChild) /2);
|
|
if (yNew < 0) {
|
|
yNew = 0;
|
|
}
|
|
else if ((yNew+hChild) > hScreen) {
|
|
yNew = hScreen - hChild;
|
|
}
|
|
|
|
// Set it, and return
|
|
return SetWindowPos (hwndChild, NULL,
|
|
xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: About(HWND, UINT, WPARAM, LPARAM)
|
|
//
|
|
// PURPOSE: Processes messages for "About" dialog box
|
|
//
|
|
// MESSAGES:
|
|
//
|
|
// WM_INITDIALOG - initialize dialog box
|
|
// WM_COMMAND - Input received
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// Display version information from the version section of the
|
|
// application resource.
|
|
//
|
|
// Wait for user to click on "Ok" button, then close the dialog box.
|
|
//
|
|
|
|
LRESULT CALLBACK About(
|
|
HWND hDlg, // window handle of the dialog box
|
|
UINT message, // type of message
|
|
WPARAM uParam, // message-specific information
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
static HFONT hfontDlg;
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG: // message: initialize dialog box
|
|
// Create a font to use
|
|
hfontDlg = CreateFont(14, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
VARIABLE_PITCH | FF_SWISS, "");
|
|
|
|
// Center the dialog over the application window
|
|
CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
|
|
|
|
return (TRUE);
|
|
|
|
case WM_COMMAND: // message: received a command
|
|
if (LOWORD(uParam) == IDOK // "OK" box selected?
|
|
|| LOWORD(uParam) == IDCANCEL) {// System menu close command?
|
|
EndDialog(hDlg, TRUE); // Exit the dialog
|
|
DeleteObject (hfontDlg);
|
|
return (TRUE);
|
|
}
|
|
break;
|
|
}
|
|
return (FALSE); // Didn't process the message
|
|
|
|
lParam; // This will prevent 'unused formal parameter' warnings
|
|
}
|