#define STRICT #include #include #include #include #include "wclist.h" #include "trsim.h" extern HINSTANCE ghInstance; #define ErrorHandler() ErrorHandlerEx(__LINE__, __FILE__) void ErrorHandlerEx(WORD, LPSTR); LRESULT ListViewNotify(HWND, LPARAM); void SwitchView(HWND, DWORD); BOOL DoContextMenu(HWND, WPARAM, LPARAM); void UpdateMenu(HWND, HMENU); BOOL InsertListViewItems(HWND); void PositionHeader(HWND); /************************************************************************** Global Variables **************************************************************************/ HWND ghSchedWnd, ghSchedListWnd; HANDLE g_hInst; TCHAR g_szClassName[] = TEXT("VListVwClass"); char *hello = "Hello"; char *get_clist_value(void *ptr, int row, int col) { static char buff[64]; sprintf(buff, "<%d,%d>", row, col); return buff; } #define ITEM_COUNT 100000 BOOL CALLBACK AboutDlgProc( HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam) { switch (uMessage) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch(wParam) { case IDOK: EndDialog(hDlg, IDOK); break; case IDCANCEL: EndDialog(hDlg, IDOK); break; } return TRUE; } return FALSE; } HWND CreateListView(HINSTANCE hInstance, HWND hwndParent) { DWORD dwStyle; HWND hwndListView; HIMAGELIST himlSmall; HIMAGELIST himlLarge; BOOL bSuccess = TRUE; dwStyle = WS_TABSTOP | WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_AUTOARRANGE | LVS_REPORT | LVS_OWNERDATA; hwndListView = CreateWindowEx( WS_EX_CLIENTEDGE, // ex style WC_LISTVIEW, // class name - defined in commctrl.h "", // dummy text dwStyle, // style 0, // x position 0, // y position 0, // width 0, // height hwndParent, // parent /*(HMENU)ID_LISTVIEW*/0, // ID g_hInst, // instance hello); // no extra data if(!hwndListView) return NULL; ResizeListView(hwndListView, hwndParent); #if 0 //set the image lists himlSmall = ImageList_Create(16, 16, ILC_COLORDDB | ILC_MASK, 1, 0); himlLarge = ImageList_Create(32, 32, ILC_COLORDDB | ILC_MASK, 1, 0); if (himlSmall && himlLarge) { HICON hIcon; //set up the small image list hIcon = LoadImage(g_hInst, MAKEINTRESOURCE(IDI_DISK), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); ImageList_AddIcon(himlSmall, hIcon); //set up the large image list hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_DISK)); ImageList_AddIcon(himlLarge, hIcon); ListView_SetImageList(hwndListView, himlSmall, LVSIL_SMALL); ListView_SetImageList(hwndListView, himlLarge, LVSIL_NORMAL); } #endif return hwndListView; } void ResizeListView(HWND hwndListView, HWND hwndParent) { RECT rc; GetClientRect(hwndParent, &rc); MoveWindow( hwndListView, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); //only call this if we want the LVS_NOSCROLL style //PositionHeader(hwndListView); } /****************************************************************************** PositionHeader this needs to be called when the ListView is created, resized, the view is changed or a WM_SYSPARAMETERCHANGE message is recieved ******************************************************************************/ void PositionHeader(HWND hwndListView) { HWND hwndHeader = GetWindow(hwndListView, GW_CHILD); DWORD dwStyle = GetWindowLong(hwndListView, GWL_STYLE); /*To ensure that the first item will be visible, create the control without the LVS_NOSCROLL style and then add it here*/ dwStyle |= LVS_NOSCROLL; SetWindowLong(hwndListView, GWL_STYLE, dwStyle); //only do this if we are in report view and were able to get the header hWnd if(((dwStyle & LVS_TYPEMASK) == LVS_REPORT) && hwndHeader) { RECT rc; HD_LAYOUT hdLayout; WINDOWPOS wpos; GetClientRect(hwndListView, &rc); hdLayout.prc = &rc; hdLayout.pwpos = &wpos; Header_Layout(hwndHeader, &hdLayout); SetWindowPos( hwndHeader, wpos.hwndInsertAfter, wpos.x, wpos.y, wpos.cx, wpos.cy, wpos.flags | SWP_SHOWWINDOW); ListView_EnsureVisible(hwndListView, 0, FALSE); } } BOOL InitListView(HWND hwndListView, struct clist *lstp) { LV_COLUMN lvColumn; int i; //empty the list ListView_DeleteAllItems(hwndListView); //initialize the columns lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 120; for(i = 0; lstp->headers[i] != 0; ++i) { lvColumn.pszText = lstp->headers[i]; lvColumn.cx = lstp->col_width[i]; ListView_InsertColumn(hwndListView, i, &lvColumn); } InsertListViewItems(hwndListView); return TRUE; } LRESULT CALLBACK MainWndProc( HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { static HWND hwndListView; CREATESTRUCT *lpc; struct clist *cp; switch (uMessage) { case WM_CREATE: /* create the TreeView control */ lpc = (LPCREATESTRUCT)lParam; cp = (struct clist *)lpc->lpCreateParams; SetWindowLong(hWnd, 0, (LPARAM)cp); hwndListView = CreateListView(g_hInst, hWnd); ghSchedListWnd = hwndListView; /* initialize the ListView control */ InitListView(hwndListView, cp); break; case WM_NOTIFY: return ListViewNotify(hWnd, lParam); case WM_SIZE: ResizeListView(hwndListView, hWnd); break; case WM_INITMENUPOPUP: UpdateMenu(hwndListView, GetMenu(hWnd)); break; case WM_CONTEXTMENU: if(DoContextMenu(hWnd, wParam, lParam)) return FALSE; break; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDM_LARGE_ICONS: SwitchView(hwndListView, LVS_ICON); break; case IDM_SMALL_ICONS: SwitchView(hwndListView, LVS_SMALLICON); break; case IDM_LIST: SwitchView(hwndListView, LVS_LIST); break; case IDM_REPORT: SwitchView(hwndListView, LVS_REPORT); break; case IDM_EXIT: DestroyWindow(hWnd); break; case IDM_ABOUT: DialogBox(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutDlgProc); break; } break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, uMessage, wParam, lParam); } BOOL InsertListViewItems(HWND hwndListView) { //empty the list ListView_DeleteAllItems(hwndListView); //set the number of items in the list ListView_SetItemCount(hwndListView, ITEM_COUNT); return TRUE; } void ErrorHandlerEx( WORD wLine, LPSTR lpszFile ) { LPVOID lpvMessage; DWORD dwError; char szBuffer[256]; // Allow FormatMessage() to look up the error code returned by GetLastError dwError = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPTSTR)&lpvMessage, 0, NULL); // Check to see if an error occured calling FormatMessage() if (!dwError) { sprintf( szBuffer, "An error occured calling FormatMessage()." "Error Code %d", GetLastError()); MessageBox( NULL, szBuffer, "Generic", MB_ICONSTOP | MB_ICONEXCLAMATION); return; } // Display the error infromation along with the place the error happened. sprintf(szBuffer, "Generic, Line=%d, File=%s", wLine, lpszFile); MessageBox(NULL, lpvMessage, szBuffer, MB_ICONEXCLAMATION | MB_OK); } void SwitchView(HWND hwndListView, DWORD dwView) { DWORD dwStyle = GetWindowLong(hwndListView, GWL_STYLE); SetWindowLong(hwndListView, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK) | dwView); ResizeListView(hwndListView, GetParent(hwndListView)); } BOOL DoContextMenu( HWND hWnd, WPARAM wParam, LPARAM lParam) { HWND hwndListView = (HWND)wParam; HMENU hMenuLoad, hMenu; if(hwndListView != GetDlgItem(hWnd, ID_LISTVIEW)) return FALSE; hMenuLoad = LoadMenu(g_hInst, MAKEINTRESOURCE(IDM_CONTEXT_MENU)); hMenu = GetSubMenu(hMenuLoad, 0); UpdateMenu(hwndListView, hMenu); TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, LOWORD(lParam), HIWORD(lParam), 0, hWnd, NULL); DestroyMenu(hMenuLoad); return TRUE; } void UpdateMenu(HWND hwndListView, HMENU hMenu) { UINT uID; DWORD dwStyle; //uncheck all of these guys CheckMenuItem(hMenu, IDM_LARGE_ICONS, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_SMALL_ICONS, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_LIST, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, IDM_REPORT, MF_BYCOMMAND | MF_UNCHECKED); //check the appropriate view menu item dwStyle = GetWindowLong(hwndListView, GWL_STYLE); switch(dwStyle & LVS_TYPEMASK) { case LVS_ICON: uID = IDM_LARGE_ICONS; break; case LVS_SMALLICON: uID = IDM_SMALL_ICONS; break; case LVS_LIST: uID = IDM_LIST; break; case LVS_REPORT: uID = IDM_REPORT; break; } CheckMenuRadioItem(hMenu, IDM_LARGE_ICONS, IDM_REPORT, uID, MF_BYCOMMAND | MF_CHECKED); } LRESULT ListViewNotify(HWND hWnd, LPARAM lParam) { LPNMHDR lpnmh = (LPNMHDR) lParam; HWND hwndListView = GetDlgItem(hWnd, ID_LISTVIEW); switch(lpnmh->code) { case LVN_GETDISPINFO: { LV_DISPINFO *lpdi = (LV_DISPINFO *)lParam; char *cp; struct clist *lp; cp = 0; lp = GetWindowLong(hWnd, 0); if(lpdi->item.iSubItem) { if(lpdi->item.mask & LVIF_TEXT) cp = lp->col_string(lpdi->item.iItem, lpdi->item.iSubItem, NULL); } else { if(lpdi->item.mask & LVIF_TEXT) cp = lp->col_string(lpdi->item.iItem, 0, NULL); if(lpdi->item.mask & LVIF_IMAGE) lpdi->item.iImage = 0; } if(cp) strcpy(lpdi->item.pszText, cp); } return 0; case LVN_ODCACHEHINT: { LPNMLVCACHEHINT lpCacheHint = (LPNMLVCACHEHINT)lParam; /* This sample doesn't use this notification, but this is sent when the ListView is about to ask for a range of items. On this notification, you should load the specified items into your local cache. It is still possible to get an LVN_GETDISPINFO for an item that has not been cached, therefore, your application must take into account the chance of this occurring. */ } return 0; case LVN_ODFINDITEM: { LPNMLVFINDITEM lpFindItem = (LPNMLVFINDITEM)lParam; /* This sample doesn't use this notification, but this is sent when the ListView needs a particular item. Return -1 if the item is not found. */ } return 0; } return 0; } /****************************************************************************** InitApplication ******************************************************************************/ BOOL InitApplication(HINSTANCE hInstance) { WNDCLASSEX wcex; ATOM aReturn; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0; wcex.lpfnWndProc = (WNDPROC)MainWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(char *); wcex.hInstance = hInstance; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCE(IDM_MAIN_MENU); wcex.lpszClassName = g_szClassName; wcex.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_MAINICON)); wcex.hIconSm = LoadImage(g_hInst, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, 16, 16, 0); aReturn = RegisterClassEx(&wcex); if(!aReturn) { WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = (WNDPROC)MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(char *); wc.hInstance = hInstance; wc.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_MAINICON)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = MAKEINTRESOURCE(IDM_MAIN_MENU); wc.lpszClassName = g_szClassName; aReturn = RegisterClass(&wc); } return aReturn; } HWND InitInstance(HINSTANCE hInstance, struct clist *ptr) { HWND hWnd; TCHAR szTitle[MAX_PATH] = ""; g_hInst = hInstance; LoadString(g_hInst, IDS_APPTITLE, szTitle, sizeof(szTitle)); /* Create a main window for this application instance. */ hWnd = GetActiveWindow(); hWnd = CreateWindowEx(hWnd, g_szClassName, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, ptr); /* If window could not be created, return "failure" */ if (!hWnd) return 0; /* Make the window visible; update its client area; and return "success" */ ShowWindow(hWnd, SW_SHOWNORMAL); UpdateWindow(hWnd); return hWnd; } void wcreate_list(struct clist *p) { static int firsttime = 1; if(firsttime) { firsttime = 0; InitApplication(ghInstance); } ghSchedWnd = InitInstance(ghInstance, p); } extern unsigned char colortable[12][3]; #define SETI(x, y, s) item.iItem = x, item.iSubItem = y, \ item.pszText = s, ListView_SetItem(ghSchedListWnd, &item) win_update_schedule(Train *t, int i) { LVITEM item; COLORREF style; memset(&item, 0, sizeof(item)); item.mask = LVIF_TEXT; switch(t->status) { case train_READY: style = RGB(0, 0, 255); break; case train_ARRIVED: case train_DERAILED: style = RGB(0, 255, 0); break; default: style = RGB(0, 0, 0); } ListView_SetTextColor(ghSchedListWnd, style); SETI(5, i, current_speed); SETI(6, i, current_delay); SETI(7, i, current_late); SETI(8, i, current_status); ListView_Update(ghSchedListWnd, i); }