/* * Listbox controls * * Copyright Martin Ayotte, 1993 * Constantine Sapuntzakis, 1995 * Alex Korobka, 1995, 1996 * */ /* * FIXME: * - proper scrolling for multicolumn style * - anchor and caret for LBS_EXTENDEDSEL * - proper selection with keyboard * - how to handle (LBS_EXTENDEDSEL | LBS_MULTIPLESEL) style * - support for LBS_NOINTEGRALHEIGHT and LBS_OWNERDRAWVARIABLE styles */ #include #include #include #include #include "windows.h" #include "win.h" #include "gdi.h" #include "msdos.h" #include "listbox.h" #include "dos_fs.h" #include "drive.h" #include "file.h" #include "heap.h" #include "stddebug.h" #include "debug.h" #include "xmalloc.h" #define LIST_HEAP_ALLOC(lphl,f,size) \ LOCAL_Alloc( lphl->HeapSel, LMEM_FIXED, (size) ) #define LIST_HEAP_FREE(lphl,handle) \ LOCAL_Free( lphl->HeapSel, (handle) ) #define LIST_HEAP_ADDR(lphl,handle) \ ((handle) ? PTR_SEG_OFF_TO_LIN(lphl->HeapSel, (handle)) : NULL) #define LIST_HEAP_SIZE 0x10000 #define LBMM_EDGE 4 /* distance inside box which is same as moving mouse outside box, to trigger scrolling of LB */ #define MATCH_SUBSTR 2 #define MATCH_EXACT 1 #define MATCH_NEAREST 0 static void ListBoxInitialize(LPHEADLIST lphl) { lphl->lpFirst = NULL; lphl->ItemsCount = 0; lphl->ItemsVisible = 0; lphl->FirstVisible = 0; lphl->ColumnsVisible = 1; lphl->ItemsPerColumn = 0; lphl->ItemFocused = -1; lphl->PrevFocused = -1; } void CreateListBoxStruct(HWND hwnd, WORD CtlType, LONG styles, HWND parent) { LPHEADLIST lphl; HDC hdc; lphl = (LPHEADLIST)xmalloc(sizeof(HEADLIST)); SetWindowLong32A(hwnd, 0, (LONG)lphl); ListBoxInitialize(lphl); lphl->DrawCtlType = CtlType; lphl->CtlID = GetWindowWord(hwnd,GWW_ID); lphl->bRedrawFlag = TRUE; lphl->iNumStops = 0; lphl->TabStops = NULL; lphl->hFont = GetStockObject(SYSTEM_FONT); lphl->hSelf = hwnd; if (CtlType==ODT_COMBOBOX) /* use the "faked" style for COMBOLBOX */ /* LBS_SORT instead CBS_SORT e.g. */ lphl->dwStyle = MAKELONG(LOWORD(styles),HIWORD(GetWindowLong32A(hwnd,GWL_STYLE))); else lphl->dwStyle = GetWindowLong32A(hwnd,GWL_STYLE); /* use original style dword */ lphl->hParent = parent; lphl->StdItemHeight = 15; /* FIXME: should get the font height */ lphl->OwnerDrawn = styles & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE); lphl->HasStrings = (styles & LBS_HASSTRINGS) || !lphl->OwnerDrawn; /* create dummy hdc to set text height */ if ((hdc = GetDC(0))) { TEXTMETRIC16 tm; GetTextMetrics16( hdc, &tm ); lphl->StdItemHeight = tm.tmHeight; dprintf_listbox(stddeb,"CreateListBoxStruct: font height %d\n", lphl->StdItemHeight); ReleaseDC( 0, hdc ); } if (lphl->OwnerDrawn) { LISTSTRUCT dummyls; lphl->needMeasure = TRUE; dummyls.mis.CtlType = lphl->DrawCtlType; dummyls.mis.CtlID = lphl->CtlID; dummyls.mis.itemID = -1; dummyls.mis.itemWidth = 0; /* ignored */ dummyls.mis.itemData = 0; ListBoxAskMeasure(lphl,&dummyls); } lphl->HeapSel = GlobalAlloc16(GMEM_FIXED,LIST_HEAP_SIZE); LocalInit( lphl->HeapSel, 0, LIST_HEAP_SIZE-1); } void DestroyListBoxStruct(LPHEADLIST lphl) { /* XXX need to free lphl->Heap */ GlobalFree16(lphl->HeapSel); free(lphl); } static LPHEADLIST ListBoxGetStorageHeader(HWND hwnd) { return (LPHEADLIST)GetWindowLong32A(hwnd,0); } /* Send notification "code" as part of a WM_COMMAND-message if hwnd has the LBS_NOTIFY style */ void ListBoxSendNotification(LPHEADLIST lphl, WORD code) { if (lphl->dwStyle & LBS_NOTIFY) SendMessage32A( lphl->hParent, WM_COMMAND, MAKEWPARAM( lphl->CtlID, code), (LPARAM)lphl->hSelf ); } /* get the maximum value of lphl->FirstVisible */ int ListMaxFirstVisible(LPHEADLIST lphl) { int m = lphl->ItemsCount-lphl->ItemsVisible; return (m < 0) ? 0 : m; } void ListBoxUpdateWindow(HWND hwnd, LPHEADLIST lphl, BOOL repaint) { if (lphl->dwStyle & WS_VSCROLL) SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE); if ((lphl->dwStyle & WS_HSCROLL) && (lphl->ItemsPerColumn != 0)) SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible / lphl->ItemsPerColumn + 1, TRUE); if (repaint && lphl->bRedrawFlag) InvalidateRect32( hwnd, NULL, TRUE ); } /* Returns: 0 if nothing needs to be changed */ /* 1 if FirstVisible changed */ int ListBoxScrollToFocus(LPHEADLIST lphl) { short end; if (lphl->ItemsCount == 0) return 0; if (lphl->ItemFocused == -1) return 0; end = lphl->FirstVisible + lphl->ItemsVisible - 1; if (lphl->ItemFocused < lphl->FirstVisible ) { lphl->FirstVisible = lphl->ItemFocused; return 1; } else { if (lphl->ItemFocused > end) { WORD maxFirstVisible = ListMaxFirstVisible(lphl); lphl->FirstVisible = lphl->ItemFocused; if (lphl->FirstVisible > maxFirstVisible) { lphl->FirstVisible = maxFirstVisible; } return 1; } } return 0; } LPLISTSTRUCT ListBoxGetItem(LPHEADLIST lphl, UINT uIndex) { LPLISTSTRUCT lpls; UINT Count = 0; if (uIndex >= lphl->ItemsCount) return NULL; lpls = lphl->lpFirst; while (Count++ < uIndex) lpls = lpls->lpNext; return lpls; } void ListBoxDrawItem (HWND hwnd, LPHEADLIST lphl, HDC hdc, LPLISTSTRUCT lpls, RECT16 *rect, WORD itemAction, WORD itemState) { if (lphl->OwnerDrawn) { DRAWITEMSTRUCT32 dis; dis.CtlID = lpls->mis.CtlID; dis.CtlType = lpls->mis.CtlType; dis.itemID = lpls->mis.itemID; dis.hDC = hdc; dis.hwndItem = hwnd; dis.itemData = lpls->mis.itemData; dis.itemAction = itemAction; dis.itemState = itemState; CONV_RECT16TO32( rect, &dis.rcItem ); SendMessage32A( lphl->hParent, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis ); return; } if (itemAction == ODA_DRAWENTIRE || itemAction == ODA_SELECT) { int OldBkMode; DWORD dwOldTextColor = 0; OldBkMode = SetBkMode(hdc, TRANSPARENT); if (itemState != 0) { dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL); FillRect16(hdc, rect, GetStockObject(BLACK_BRUSH)); } if (lphl->dwStyle & LBS_USETABSTOPS) { TabbedTextOut(hdc, rect->left + 5, rect->top + 2, (char *)lpls->itemText, strlen((char *)lpls->itemText), lphl->iNumStops, lphl->TabStops, 0); } else { TextOut16(hdc, rect->left + 5, rect->top + 2, (char *)lpls->itemText, strlen((char *)lpls->itemText)); } if (itemState != 0) { SetTextColor(hdc, dwOldTextColor); } SetBkMode(hdc, OldBkMode); } else DrawFocusRect16(hdc, rect); } int ListBoxFindMouse(LPHEADLIST lphl, int X, int Y) { LPLISTSTRUCT lpls = lphl->lpFirst; int i, j; POINT16 point; point.x = X; point.y = Y; if (lphl->ItemsCount == 0) return LB_ERR; for(i = 0; i < lphl->FirstVisible; i++) { if (lpls == NULL) return LB_ERR; lpls = lpls->lpNext; } for(j = 0; j < lphl->ItemsVisible; i++, j++) { if (lpls == NULL) return LB_ERR; if (PtInRect16(&lpls->itemRect,point)) { return i; } lpls = lpls->lpNext; } dprintf_listbox(stddeb,"ListBoxFindMouse: not found\n"); return LB_ERR; } BOOL32 lbDeleteItemNotify(LPHEADLIST lphl, LPLISTSTRUCT lpls) { /* called only for owner drawn listboxes */ BOOL32 ret; DELETEITEMSTRUCT16 *delItem = SEGPTR_NEW(DELETEITEMSTRUCT16); if (!delItem) return FALSE; delItem->CtlType = lphl->DrawCtlType; delItem->CtlID = lphl->CtlID; delItem->itemID = lpls->mis.itemID; delItem->hwndItem = lphl->hSelf; delItem->itemData = lpls->mis.itemData; ret = SendMessage16( lphl->hParent, WM_DELETEITEM, (WPARAM)lphl->CtlID, (LPARAM)SEGPTR_GET(delItem) ); SEGPTR_FREE(delItem); return ret; } void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls) { MEASUREITEMSTRUCT16 *lpmeasure = SEGPTR_NEW(MEASUREITEMSTRUCT16); if (!lpmeasure) return; *lpmeasure = lpls->mis; lpmeasure->itemHeight = lphl->StdItemHeight; SendMessage16( lphl->hParent, WM_MEASUREITEM, lphl->CtlID, (LPARAM)SEGPTR_GET(lpmeasure) ); if (lphl->dwStyle & LBS_OWNERDRAWFIXED) { if (lpmeasure->itemHeight > lphl->StdItemHeight) lphl->StdItemHeight = lpmeasure->itemHeight; lpls->mis.itemHeight = lpmeasure->itemHeight; } SEGPTR_FREE(lpmeasure); } /* -------------------- strings and item data ---------------------- */ LPLISTSTRUCT ListBoxCreateItem(LPHEADLIST lphl, int id) { LPLISTSTRUCT lplsnew = (LPLISTSTRUCT)malloc(sizeof(LISTSTRUCT)); if (lplsnew == NULL) return NULL; lplsnew->itemState = 0; lplsnew->mis.CtlType = lphl->DrawCtlType; lplsnew->mis.CtlID = lphl->CtlID; lplsnew->mis.itemID = id; lplsnew->mis.itemHeight = lphl->StdItemHeight; lplsnew->mis.itemWidth = 0; /* ignored */ lplsnew->mis.itemData = 0; SetRectEmpty16( &lplsnew->itemRect ); return lplsnew; } int ListBoxAskCompare(LPHEADLIST lphl, int startItem, SEGPTR matchData, BOOL exactMatch ) { /* Do binary search for sorted listboxes. Linked list item storage sort of * defeats the purpose ( forces to traverse item list all the time ) but M$ does it this way... * * MATCH_NEAREST (0) - return position for insertion - for all styles * MATCH_EXACT (1) - search for an item, return index or LB_ERR * MATCH_SUBSTR (2) - same as exact match but with strncmp for string comparision */ COMPAREITEMSTRUCT16 *itemCmp; LPLISTSTRUCT currentItem = NULL; LPCSTR matchStr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(matchData):NULL; int head, pos = -1, tail, loop = 1; short b = 0, s_length = 0; /* check if empty */ if( !lphl->ItemsCount ) return (exactMatch)? LB_ERR: 0; /* set up variables */ if( exactMatch == MATCH_NEAREST ) startItem = 0; else if( ++startItem ) { loop = 2; if( startItem >= lphl->ItemsCount ) startItem = lphl->ItemsCount - 1; } if( exactMatch == MATCH_SUBSTR && lphl->HasStrings ) { s_length = strlen( matchStr ); if( !s_length ) return 0; /* head of the list - empty string */ } head = startItem; tail = lphl->ItemsCount - 1; dprintf_listbox(stddeb,"AskCompare: head = %i, tail = %i, data = %08x\n", head, tail, (unsigned)matchData ); if (!(itemCmp = SEGPTR_NEW(COMPAREITEMSTRUCT16))) return 0; itemCmp->CtlType = lphl->DrawCtlType; itemCmp->CtlID = lphl->CtlID; itemCmp->hwndItem = lphl->hSelf; /* search from startItem */ while ( loop-- ) { while( head <= tail ) { pos = (tail + head)/2; currentItem = ListBoxGetItem( lphl, pos ); if( lphl->HasStrings ) { b = ( s_length )? lstrncmpi32A( currentItem->itemText, matchStr, s_length) : lstrcmpi32A( currentItem->itemText, matchStr); } else { itemCmp->itemID1 = pos; itemCmp->itemData1 = currentItem->mis.itemData; itemCmp->itemID2 = -1; itemCmp->itemData2 = matchData; b = SendMessage16( lphl->hParent, WM_COMPAREITEM, (WPARAM)lphl->CtlID, (LPARAM)SEGPTR_GET(itemCmp) ); } if( b == 0 ) { SEGPTR_FREE(itemCmp); return pos; /* found exact match */ } else if( b < 0 ) head = ++pos; else if( b > 0 ) tail = pos - 1; } /* reset to search from the first item */ head = 0; tail = startItem - 1; } dprintf_listbox(stddeb,"\t-> pos = %i\n", pos ); SEGPTR_FREE(itemCmp); /* if we got here match is not exact */ if( pos < 0 ) pos = 0; else if( pos > lphl->ItemsCount ) pos = lphl->ItemsCount; return (exactMatch)? LB_ERR: pos; } int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPCSTR newstr) { LPLISTSTRUCT *lppls, lplsnew, lpls; HANDLE hStr; LPSTR str; UINT Count; dprintf_listbox(stddeb,"ListBoxInsertString(%d, %p);\n", uIndex, newstr); if (!newstr) return -1; if (uIndex == (UINT)-1) uIndex = lphl->ItemsCount; lppls = &lphl->lpFirst; for(Count = 0; Count < uIndex; Count++) { if (*lppls == NULL) return LB_ERR; lppls = (LPLISTSTRUCT *) &(*lppls)->lpNext; } lplsnew = ListBoxCreateItem(lphl, Count); if (lplsnew == NULL) { fprintf(stdnimp,"ListBoxInsertString() out of memory !\n"); return LB_ERRSPACE; } lplsnew->lpNext = *lppls; *lppls = lplsnew; lphl->ItemsCount++; hStr = 0; if (lphl->HasStrings) { dprintf_listbox(stddeb," string: %s\n", newstr); hStr = LIST_HEAP_ALLOC(lphl, LMEM_MOVEABLE, strlen(newstr) + 1); str = (LPSTR)LIST_HEAP_ADDR(lphl, hStr); if (str == NULL) return LB_ERRSPACE; strcpy(str, newstr); lplsnew->itemText = str; /* I'm not so sure about the next one */ lplsnew->mis.itemData = 0; } else { lplsnew->itemText = NULL; lplsnew->mis.itemData = (DWORD)newstr; } lplsnew->mis.itemID = uIndex; lplsnew->hData = hStr; /* adjust the itemID field of the following entries */ for(lpls = lplsnew->lpNext; lpls != NULL; lpls = lpls->lpNext) { lpls->mis.itemID++; } if (lphl->needMeasure) { ListBoxAskMeasure(lphl, lplsnew); } dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount); return uIndex; } int ListBoxAddString(LPHEADLIST lphl, SEGPTR itemData) { UINT pos = (UINT) -1; LPCSTR newstr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(itemData):(LPCSTR)itemData; if ( lphl->dwStyle & LBS_SORT ) pos = ListBoxAskCompare( lphl, -1, itemData, MATCH_NEAREST ); return ListBoxInsertString(lphl, pos, newstr); } int ListBoxGetText(LPHEADLIST lphl, UINT uIndex, LPSTR OutStr) { LPLISTSTRUCT lpls; if (!OutStr) { dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n"); return 0; } *OutStr = '\0'; lpls = ListBoxGetItem (lphl, uIndex); if (lpls == NULL) return LB_ERR; if (!lphl->HasStrings) { *((long *)OutStr) = lpls->mis.itemData; return 4; } strcpy(OutStr, lpls->itemText); return strlen(OutStr); } DWORD ListBoxGetItemData(LPHEADLIST lphl, UINT uIndex) { LPLISTSTRUCT lpls; lpls = ListBoxGetItem (lphl, uIndex); if (lpls == NULL) return LB_ERR; return lpls->mis.itemData; } int ListBoxSetItemData(LPHEADLIST lphl, UINT uIndex, DWORD ItemData) { LPLISTSTRUCT lpls = ListBoxGetItem(lphl, uIndex); if (lpls == NULL) return LB_ERR; lpls->mis.itemData = ItemData; return 1; } int ListBoxDeleteString(LPHEADLIST lphl, UINT uIndex) { LPLISTSTRUCT lpls, lpls2; UINT Count; if (uIndex >= lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; if (uIndex == 0) { if( lphl->OwnerDrawn ) lbDeleteItemNotify( lphl, lpls); lphl->lpFirst = lpls->lpNext; } else { LPLISTSTRUCT lpls2 = NULL; for(Count = 0; Count < uIndex; Count++) { if (lpls->lpNext == NULL) return LB_ERR; lpls2 = lpls; lpls = (LPLISTSTRUCT)lpls->lpNext; } if( lphl->OwnerDrawn ) lbDeleteItemNotify( lphl, lpls); lpls2->lpNext = lpls->lpNext; } /* adjust the itemID field of the following entries */ for(lpls2 = lpls->lpNext; lpls2 != NULL; lpls2 = lpls2->lpNext) { lpls2->mis.itemID--; } lphl->ItemsCount--; if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData); free(lpls); return lphl->ItemsCount; } int lbFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr, BOOL match) { /* match is either MATCH_SUBSTR or MATCH_EXACT */ LPLISTSTRUCT lpls; UINT Count; UINT First = nFirst + 1; int s_length = 0; LPSTR lpMatchStr = (LPSTR)MatchStr; if (First > lphl->ItemsCount) return LB_ERR; if (lphl->dwStyle & LBS_SORT ) return ListBoxAskCompare( lphl, nFirst, MatchStr, match ); if (lphl->HasStrings ) { lpMatchStr = PTR_SEG_TO_LIN(MatchStr); if( match == MATCH_SUBSTR ) { s_length = strlen(lpMatchStr); if( !s_length ) return (lphl->ItemsCount)?0:LB_ERR; } } lpls = ListBoxGetItem(lphl, First); Count = 0; while(lpls != NULL) { if (lphl->HasStrings) { if ( ( s_length )? !lstrncmpi32A(lpls->itemText, lpMatchStr, s_length) : !lstrcmpi32A(lpls->itemText, lpMatchStr) ) return Count; } else if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count; lpls = lpls->lpNext; Count++; } /* Start over at top */ Count = 0; lpls = lphl->lpFirst; while (Count < First) { if (lphl->HasStrings) { if ( ( s_length )? !lstrncmpi32A(lpls->itemText, lpMatchStr, s_length) : !lstrcmpi32A(lpls->itemText, lpMatchStr) ) return Count; } else if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count; lpls = lpls->lpNext; Count++; } return LB_ERR; } int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr) { return lbFindString(lphl, nFirst, MatchStr, MATCH_SUBSTR ); } int ListBoxFindStringExact(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr) { return lbFindString(lphl, nFirst, MatchStr, MATCH_EXACT ); } int ListBoxResetContent(LPHEADLIST lphl) { LPLISTSTRUCT lpls; int i; if (lphl->ItemsCount == 0) return 0; dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n", lphl->ItemsCount); for(i = 0; i < lphl->ItemsCount; i++) { lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; if (lphl->OwnerDrawn) lbDeleteItemNotify(lphl, lpls); lphl->lpFirst = lpls->lpNext; if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData); free(lpls); } ListBoxInitialize(lphl); return TRUE; } /* --------------------- selection ------------------------- */ int ListBoxSetCurSel(LPHEADLIST lphl, WORD wIndex) { LPLISTSTRUCT lpls; /* use ListBoxSetSel instead */ if (lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ) return 0; /* unselect previous item */ if (lphl->ItemFocused != -1) { lphl->PrevFocused = lphl->ItemFocused; lpls = ListBoxGetItem(lphl, lphl->ItemFocused); if (lpls == 0) return LB_ERR; lpls->itemState = 0; } if ((wIndex != (UINT)-1) && (wIndex < lphl->ItemsCount)) { lphl->ItemFocused = wIndex; lpls = ListBoxGetItem(lphl, wIndex); if (lpls == 0) return LB_ERR; lpls->itemState = ODS_SELECTED | ODS_FOCUS; return 0; } return LB_ERR; } int ListBoxSetSel(LPHEADLIST lphl, WORD wIndex, WORD state) { LPLISTSTRUCT lpls; int n = 0; if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )) return LB_ERR; if (wIndex == (UINT)-1) { for (lpls = lphl->lpFirst; lpls != NULL; lpls = lpls->lpNext) { if( lpls->itemState & ODS_SELECTED) n++; lpls->itemState = state? lpls->itemState | ODS_SELECTED : lpls->itemState & ~ODS_SELECTED; } return n; } if (wIndex >= lphl->ItemsCount) return LB_ERR; lpls = ListBoxGetItem(lphl, wIndex); lpls->itemState = state? lpls->itemState | ODS_SELECTED : lpls->itemState & ~ODS_SELECTED; return 0; } int ListBoxGetSel(LPHEADLIST lphl, WORD wIndex) { LPLISTSTRUCT lpls = ListBoxGetItem(lphl, wIndex); if (lpls == NULL) return LB_ERR; return lpls->itemState & ODS_SELECTED; } /* ------------------------- dir listing ------------------------ */ LONG ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPCSTR filespec) { char mask[13]; char* temp = NULL; const char* ptr; int skip, count; LONG ret; DOS_DIRENT entry; char *path, *p; dprintf_listbox(stddeb, "ListBoxDirectory: '%s' %04x\n", filespec, attrib); if (!filespec) return LB_ERR; if (!(ptr = DOSFS_GetUnixFileName( filespec, FALSE ))) return LB_ERR; path = xstrdup(ptr); p = strrchr( path, '/' ); *p++ = '\0'; if (!(ptr = DOSFS_ToDosFCBFormat( p )) || !(temp = SEGPTR_ALLOC( sizeof(char) * 16 )) ) { free( path ); return LB_ERR; } strcpy( mask, ptr ); dprintf_listbox(stddeb, "ListBoxDirectory: path=%s mask=%s\n", path, mask); skip = ret = 0; attrib &= ~FA_LABEL; while ((count = DOSFS_FindNext( path, mask, 0, attrib, skip, &entry )) > 0) { skip += count; if (entry.attr & FA_DIRECTORY) { if ((attrib & DDL_DIRECTORY) && strcmp(entry.name, ". ")) { sprintf(temp, "[%s]", DOSFS_ToDosDTAFormat( entry.name ) ); AnsiLower( temp ); if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break; } } else /* not a directory */ { if (!(attrib & DDL_EXCLUSIVE) || ((attrib & (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_ARCHIVE)) == (entry.attr & (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_ARCHIVE)))) { strcpy( temp, DOSFS_ToDosDTAFormat( entry.name ) ); AnsiLower( temp ); if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break; } } dprintf_listbox(stddeb,"\tn - %i, file '%s'\n", count, temp); } if (attrib & DDL_DRIVES) { int x; strcpy( temp, "[-a-]" ); for (x = 0; x < MAX_DOS_DRIVES; x++, temp[2]++) { if (DRIVE_IsValid(x)) if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break; } } free( path ); SEGPTR_FREE( temp ); return ret; } /* ------------------------- dimensions ------------------------- */ int ListBoxGetItemRect(LPHEADLIST lphl, WORD wIndex, LPRECT16 lprect) { LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wIndex); if (lpls == NULL) return LB_ERR; *lprect = lpls->itemRect; return 0; } int ListBoxSetItemHeight(LPHEADLIST lphl, WORD wIndex, long height) { LPLISTSTRUCT lpls; if (!(lphl->dwStyle & LBS_OWNERDRAWVARIABLE)) { lphl->StdItemHeight = (short)height; return 0; } lpls = ListBoxGetItem(lphl, wIndex); if (lpls == NULL) return LB_ERR; lpls->mis.itemHeight = height; return 0; } /* -------------------------- string search ------------------------ */ int ListBoxFindNextMatch(LPHEADLIST lphl, WORD wChar) { LPLISTSTRUCT lpls; UINT count,first; if ((char)wChar < ' ') return LB_ERR; if (!lphl->HasStrings) return LB_ERR; lpls = lphl->lpFirst; for (count = 0; lpls != NULL; lpls = lpls->lpNext, count++) { if (tolower(*lpls->itemText) == tolower((char)wChar)) break; } if (lpls == NULL) return LB_ERR; first = count; for(; lpls != NULL; lpls = lpls->lpNext, count++) { if (*lpls->itemText != (char)wChar) break; if ((short) count > lphl->ItemFocused) return count; } return first; } /*********************************************************************** * LBCreate */ static LONG LBCreate(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl; LONG dwStyle = GetWindowLong32A(hwnd,GWL_STYLE); RECT16 rect; CreateListBoxStruct(hwnd, ODT_LISTBOX, dwStyle, GetParent(hwnd)); lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb,"ListBox created: lphl = %p dwStyle = %04x:%04x\n", lphl, HIWORD(dwStyle), LOWORD(dwStyle)); GetClientRect16(hwnd,&rect); lphl->ColumnsWidth = rect.right - rect.left; if (dwStyle & WS_VSCROLL) SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE); if (dwStyle & WS_HSCROLL) SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE); return 0; } /*********************************************************************** * LBDestroy */ static LONG LBDestroy(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); ListBoxResetContent(lphl); DestroyListBoxStruct(lphl); dprintf_listbox(stddeb,"ListBox destroyed: lphl = %p\n",lphl); return 0; } /*********************************************************************** * LBNCCalcSize */ static LONG LBNCCalcSize(HWND hwnd, WORD wParam, LONG lParam) { LONG ret = DefWindowProc16(hwnd, WM_NCCALCSIZE, wParam, lParam); return (GetWindowLong32A(hwnd,GWL_STYLE) & LBS_MULTICOLUMN)? WVR_VREDRAW : ret; } /*********************************************************************** * LBVScroll */ static LONG LBVScroll(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); int y; dprintf_listbox(stddeb,"ListBox WM_VSCROLL w=%04X l=%08lX !\n", wParam, lParam); y = lphl->FirstVisible; switch(wParam) { case SB_LINEUP: if (lphl->FirstVisible > 0) lphl->FirstVisible--; break; case SB_LINEDOWN: lphl->FirstVisible++; break; case SB_PAGEUP: if (lphl->FirstVisible > lphl->ItemsVisible) { lphl->FirstVisible -= lphl->ItemsVisible; } else { lphl->FirstVisible = 0; } break; case SB_PAGEDOWN: lphl->FirstVisible += lphl->ItemsVisible; break; case SB_THUMBTRACK: lphl->FirstVisible = LOWORD(lParam); break; } if (lphl->FirstVisible > ListMaxFirstVisible(lphl)) lphl->FirstVisible = ListMaxFirstVisible(lphl); if (y != lphl->FirstVisible) { SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); InvalidateRect32( hwnd, NULL, TRUE ); } return 0; } /*********************************************************************** * LBHScroll */ static LONG LBHScroll(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl; int y; dprintf_listbox(stddeb,"ListBox WM_HSCROLL w=%04X l=%08lX !\n", wParam, lParam); lphl = ListBoxGetStorageHeader(hwnd); y = lphl->FirstVisible; switch(wParam) { case SB_LINEUP: if (lphl->FirstVisible > lphl->ItemsPerColumn) { lphl->FirstVisible -= lphl->ItemsPerColumn; } else { lphl->FirstVisible = 0; } break; case SB_LINEDOWN: lphl->FirstVisible += lphl->ItemsPerColumn; break; case SB_PAGEUP: if (lphl->ItemsPerColumn != 0) { int lbsub = lphl->ItemsVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn; if (lphl->FirstVisible > lbsub) { lphl->FirstVisible -= lbsub; } else { lphl->FirstVisible = 0; } } break; case SB_PAGEDOWN: if (lphl->ItemsPerColumn != 0) lphl->FirstVisible += lphl->ItemsVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn; break; case SB_THUMBTRACK: lphl->FirstVisible = lphl->ItemsPerColumn * LOWORD(lParam); break; } if (lphl->FirstVisible > ListMaxFirstVisible(lphl)) lphl->FirstVisible = ListMaxFirstVisible(lphl); if (lphl->ItemsPerColumn != 0) { lphl->FirstVisible = lphl->FirstVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1; if (y != lphl->FirstVisible) { SetScrollPos(hwnd, SB_HORZ, lphl->FirstVisible / lphl->ItemsPerColumn + 1, TRUE); InvalidateRect32( hwnd, NULL, TRUE ); } } return 0; } /*********************************************************************** * LBLButtonDown */ static LONG LBLButtonDown(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); WORD wRet; int y,n; RECT16 rectsel; SetFocus(hwnd); SetCapture(hwnd); lphl->PrevFocused = lphl->ItemFocused; y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam)); if (y == -1) return 0; if (lphl->dwStyle & LBS_NOTIFY && y!= LB_ERR ) if( SendMessage16(lphl->hParent, WM_LBTRACKPOINT, y, lParam) ) return 0; switch( lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ) { case LBS_MULTIPLESEL: lphl->ItemFocused = y; wRet = ListBoxGetSel(lphl, y); ListBoxSetSel(lphl, y, !wRet); break; case LBS_EXTENDEDSEL: /* should handle extended mode here and in kbd handler */ if ( lphl->PrevFocused != y && y!= LB_ERR) { LPLISTSTRUCT lpls = ListBoxGetItem( lphl, lphl->ItemFocused = y ); n = ListBoxSetSel(lphl,-1,FALSE); lpls->itemState = ODS_FOCUS | ODS_SELECTED; if( n > 1 && n != LB_ERR ) InvalidateRect32( hwnd,NULL,TRUE ); } else return 0; break; case 0: if( y!=lphl->ItemFocused ) ListBoxSetCurSel(lphl, y); else return 0; break; default: fprintf(stdnimp,"Listbox: LBS_MULTIPLESEL and LBS_EXTENDEDSEL are on!\n"); return 0; } /* invalidate changed items */ if( lphl->dwStyle & LBS_MULTIPLESEL || y!=lphl->PrevFocused ) { ListBoxGetItemRect(lphl, y, &rectsel); InvalidateRect16( hwnd, &rectsel, TRUE ); } if( lphl->PrevFocused!=-1 && y!=lphl->PrevFocused ) { ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel); InvalidateRect16( hwnd, &rectsel, TRUE ); } if (GetWindowLong32A(lphl->hSelf,GWL_EXSTYLE) & WS_EX_DRAGDETECT) if( DragDetect(lphl->hSelf,MAKEPOINT16(lParam)) ) SendMessage16(lphl->hParent, WM_BEGINDRAG,0,0L); return 0; } /*********************************************************************** * LBLButtonUp */ static LONG LBLButtonUp(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); if (GetCapture() == hwnd) ReleaseCapture(); if (lphl->PrevFocused != lphl->ItemFocused) ListBoxSendNotification(lphl, LBN_SELCHANGE); return 0; } /*********************************************************************** * LBRButtonUp */ static LONG LBRButtonUp(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); SendMessage16(lphl->hParent, WM_COMMAND, GetWindowWord(hwnd,GWW_ID), MAKELONG(hwnd, LBN_DBLCLK)); return 0; } /*********************************************************************** * LBMouseMove */ static LONG LBMouseMove(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); int y,redraw_prev = 0; int iRet; RECT16 rect, rectsel; /* XXX Broken */ dprintf_listbox(stddeb,"LBMouseMove %d %d\n",SLOWORD(lParam),SHIWORD(lParam)); if ((wParam & MK_LBUTTON) != 0) { y = SHIWORD(lParam); if (y < LBMM_EDGE) { if (lphl->FirstVisible > 0) { lphl->FirstVisible--; SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); InvalidateRect32( hwnd, NULL, TRUE ); return 0; } } GetClientRect16(hwnd, &rect); if (y >= (rect.bottom-LBMM_EDGE)) { if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) { lphl->FirstVisible++; SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); InvalidateRect32( hwnd, NULL, TRUE ); return 0; } } if ((y > 0) && (y < (rect.bottom - LBMM_EDGE))) { if ((y < rectsel.top) || (y > rectsel.bottom)) { iRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam)); if (iRet == lphl->ItemFocused || iRet == -1) { return 0; } if (lphl->dwStyle & LBS_MULTIPLESEL) { lphl->ItemFocused = iRet; ListBoxSendNotification(lphl, LBN_SELCHANGE); } else if ( lphl->dwStyle & LBS_EXTENDEDSEL ) { /* Fixme: extended selection mode */ ListBoxSetSel( lphl, lphl->ItemFocused, 0); lphl->PrevFocused = lphl->ItemFocused; lphl->ItemFocused = iRet; ListBoxSetSel( lphl, iRet, TRUE); redraw_prev = 1; } else { ListBoxSetCurSel(lphl, (WORD)iRet); redraw_prev = 1; } if( lphl->PrevFocused!=-1 && redraw_prev ) { ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel); InvalidateRect16( hwnd, &rectsel, TRUE ); } ListBoxGetItemRect(lphl, iRet, &rectsel); InvalidateRect16( hwnd, &rectsel, TRUE ); } } } return 0; } /*********************************************************************** * LBKeyDown * * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL */ static LONG LBKeyDown(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); WORD newFocused = 0xFFFF; RECT16 rect; ListBoxGetItemRect(lphl,lphl->ItemFocused,&rect); switch(wParam) { case VK_HOME: case VK_END: case VK_LEFT: case VK_RIGHT: case VK_UP: case VK_DOWN: case VK_PRIOR: case VK_NEXT: if ( lphl->dwStyle & LBS_WANTKEYBOARDINPUT ) { newFocused = (WORD)(INT)SendMessage16(lphl->hParent,WM_VKEYTOITEM, wParam,MAKELPARAM(lphl->ItemFocused,hwnd)); if ( newFocused == 0xFFFE ) return 0L; } if ( newFocused == 0xFFFF ) { newFocused = lphl->ItemFocused; /* nested switch */ switch(wParam) { case VK_HOME: newFocused = 0; break; case VK_END: newFocused = lphl->ItemsCount - 1; break; case VK_LEFT: if (lphl->dwStyle & LBS_MULTICOLUMN) { if (newFocused >= lphl->ItemsPerColumn) { newFocused -= lphl->ItemsPerColumn; } else { newFocused = 0; } } break; case VK_UP: if (newFocused > 0) newFocused--; break; case VK_RIGHT: if (lphl->dwStyle & LBS_MULTICOLUMN) newFocused += lphl->ItemsPerColumn; break; case VK_DOWN: newFocused++; break; case VK_PRIOR: if (newFocused > lphl->ItemsVisible) newFocused -= lphl->ItemsVisible; else newFocused = 0; break; case VK_NEXT: newFocused += lphl->ItemsVisible; break; default: return 0; } /* end of nested switch */ } break; case VK_SPACE: if (lphl->dwStyle & LBS_MULTIPLESEL) { WORD wRet = ListBoxGetSel(lphl, lphl->ItemFocused); ListBoxSetSel(lphl, lphl->ItemFocused, !wRet); } return 0; /* chars are handled in LBChar */ default: return 0; } /* at this point newFocused is set up */ if (newFocused >= lphl->ItemsCount) newFocused = lphl->ItemsCount - 1; if (!(lphl->dwStyle & LBS_MULTIPLESEL)) { ListBoxSetCurSel(lphl, newFocused); ListBoxSendNotification(lphl, LBN_SELCHANGE); } lphl->ItemFocused = newFocused; if( ListBoxScrollToFocus(lphl) || (lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) ) InvalidateRect32( hwnd, NULL, TRUE ); else { InvalidateRect16( hwnd, &rect, TRUE ); if( newFocused < 0x8000 ) { ListBoxGetItemRect(lphl, newFocused, &rect); InvalidateRect16( hwnd, &rect, TRUE ); } } SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); return 0; } /*********************************************************************** * LBChar */ static LONG LBChar(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); WORD newFocused = 0xFFFF; if ( (lphl->dwStyle & LBS_WANTKEYBOARDINPUT) && !(lphl->HasStrings)) { newFocused = (WORD)(INT)SendMessage16(lphl->hParent,WM_CHARTOITEM, wParam,MAKELPARAM(lphl->ItemFocused,hwnd)); if ( newFocused == 0xFFFE ) return 0L; } if (newFocused == 0xFFFF ) newFocused = ListBoxFindNextMatch(lphl, wParam); if (newFocused == (WORD)LB_ERR) return 0; if (newFocused >= lphl->ItemsCount) newFocused = lphl->ItemsCount - 1; if (!(lphl->dwStyle & LBS_MULTIPLESEL)) { ListBoxSetCurSel(lphl, newFocused); ListBoxSendNotification(lphl, LBN_SELCHANGE); } lphl->ItemFocused = newFocused; ListBoxScrollToFocus(lphl); SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); InvalidateRect32( hwnd, NULL, TRUE ); return 0; } /*********************************************************************** * LBSetRedraw */ static LONG LBSetRedraw(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb,"ListBox WM_SETREDRAW hWnd=%04x w=%04x !\n", hwnd, wParam); lphl->bRedrawFlag = wParam; return 0; } /*********************************************************************** * LBSetFont */ static LONG LBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); HDC hdc; if (wParam == 0) lphl->hFont = GetStockObject(SYSTEM_FONT); else lphl->hFont = (HFONT) wParam; /* a new font means possible new text height */ /* does this mean the height of each entry must be separately changed? */ /* or are we guaranteed to get a LBSetFont before the first insert/add? */ if ((hdc = GetDC(0))) { TEXTMETRIC16 tm; GetTextMetrics16( hdc, &tm ); lphl->StdItemHeight = tm.tmHeight; dprintf_listbox(stddeb,"LBSetFont: new font %d with height %d\n", lphl->hFont, lphl->StdItemHeight); ReleaseDC( 0, hdc ); } return 0; } /*********************************************************************** * LBPaint */ static LONG LBPaint(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); LPLISTSTRUCT lpls; PAINTSTRUCT16 ps; HBRUSH hBrush; HFONT hOldFont; HDC16 hdc = BeginPaint16( hwnd, &ps ); DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC); RECT16 rect, paintRect, scratchRect; int i, top, height, maxwidth, ipc; top = 0; if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) { EndPaint16(hwnd, &ps); return 0; } GetRgnBox16(dc->w.hGCClipRgn,&paintRect); GetClientRect16(hwnd, &rect); IntersectRect16(&paintRect,&rect,&paintRect); hOldFont = SelectObject(hdc, lphl->hFont); hBrush = (HBRUSH)SendMessage32A( lphl->hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc, (LPARAM)hwnd); if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH); FillRect16(hdc, &rect, hBrush); maxwidth = rect.right; if (lphl->dwStyle & LBS_MULTICOLUMN) { rect.right = lphl->ColumnsWidth; } lpls = lphl->lpFirst; lphl->ItemsVisible = 0; lphl->ItemsPerColumn = ipc = 0; for(i = 0; i < lphl->ItemsCount; i++) { if (lpls == NULL) break; if (i >= lphl->FirstVisible) { height = lpls->mis.itemHeight; if (top > (rect.bottom-height+1)) { if (lphl->dwStyle & LBS_MULTICOLUMN) { lphl->ItemsPerColumn = MAX(lphl->ItemsPerColumn, ipc); ipc = 0; top = 0; rect.left += lphl->ColumnsWidth; rect.right += lphl->ColumnsWidth; if (rect.left > maxwidth) break; } else { break; } } lpls->itemRect.top = top; lpls->itemRect.bottom = top + height; lpls->itemRect.left = rect.left; lpls->itemRect.right = rect.right; if( IntersectRect16(&scratchRect,&paintRect,&lpls->itemRect) ) { dprintf_listbox(stddeb,"LBPaint: drawing item: %d %d %d %d %d\n", rect.left,top,rect.right,top+height,lpls->itemState); if (lphl->OwnerDrawn && (lphl->ItemFocused == i) && GetFocus() == hwnd) { ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, lpls->itemState & ~ODS_FOCUS); ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, lpls->itemState & ~ODS_FOCUS); ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, lpls->itemState); } else ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, lpls->itemState); } top += height; lphl->ItemsVisible++; ipc++; } lpls = lpls->lpNext; } ListBoxUpdateWindow(hwnd,lphl,FALSE); SelectObject(hdc,hOldFont); EndPaint16( hwnd, &ps ); return 0; } /*********************************************************************** * LBSetFocus */ static LONG LBSetFocus(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb,"ListBox WM_SETFOCUS for %04x\n",hwnd); if(!(lphl->dwStyle & LBS_MULTIPLESEL) ) if( lphl->ItemsCount && lphl->ItemFocused != -1) { HDC hDC = GetDC(hwnd); HFONT hOldFont = SelectObject(hDC, lphl->hFont); LPLISTSTRUCT lpls; lpls = ListBoxGetItem(lphl,lphl->ItemFocused); lpls->itemState |= ODS_FOCUS; ListBoxDrawItem(hwnd,lphl,hDC,lpls,&lpls->itemRect, ODA_FOCUS, lpls->itemState); SelectObject(hDC, hOldFont); ReleaseDC(hwnd,hDC); } ListBoxSendNotification(lphl, LBN_SETFOCUS); return 0; } /*********************************************************************** * LBKillFocus */ static LONG LBKillFocus(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb,"ListBox WM_KILLFOCUS for %04x\n",hwnd); if (!(lphl->dwStyle & LBS_MULTIPLESEL)) { if( lphl->ItemsCount ) if( lphl->ItemFocused != -1 ) { HDC hDC = GetDC(hwnd); HFONT hOldFont = SelectObject(hDC, lphl->hFont); LPLISTSTRUCT lpls; lpls = ListBoxGetItem(lphl,lphl->ItemFocused); lpls->itemState &= ~ODS_FOCUS; ListBoxDrawItem(hwnd,lphl,hDC,lpls,&lpls->itemRect, ODA_FOCUS, lpls->itemState); SelectObject(hDC, hOldFont); ReleaseDC(hwnd,hDC); } else dprintf_listbox(stddeb,"LBKillFocus: no focused item!\n"); } else InvalidateRect32( hwnd, NULL, TRUE ); ListBoxSendNotification(lphl, LBN_KILLFOCUS); return 0; } /*********************************************************************** * LBResetContent */ static LONG LBResetContent(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb,"ListBox LB_RESETCONTENT !\n"); ListBoxResetContent(lphl); ListBoxUpdateWindow(hwnd, lphl, TRUE); return 0; } /*********************************************************************** * LBDir */ static LONG LBDir(HWND hwnd, WORD wParam, LONG lParam) { LONG ret; LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb,"ListBox LB_DIR !\n"); ret = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam)); ListBoxUpdateWindow(hwnd, lphl, TRUE); return ret; } /*********************************************************************** * LBAddString */ static LONG LBAddString(HWND hwnd, WORD wParam, LONG lParam) { WORD wRet; LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); wRet = ListBoxAddString(lphl, (SEGPTR)lParam); ListBoxUpdateWindow(hwnd,lphl,TRUE); return wRet; } /*********************************************************************** * LBGetText */ static LONG LBGetText(HWND hwnd, WORD wParam, LONG lParam) { LONG wRet; LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb, "LB_GETTEXT wParam=%d\n",wParam); wRet = ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam)); return wRet; } /*********************************************************************** * LBInsertString */ static LONG LBInsertString(HWND hwnd, WORD wParam, LONG lParam) { WORD wRet; LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); if (lphl->HasStrings) wRet = ListBoxInsertString(lphl, wParam, (LPCSTR)PTR_SEG_TO_LIN(lParam)); else wRet = ListBoxInsertString(lphl, wParam, (LPCSTR)lParam); ListBoxUpdateWindow(hwnd,lphl,TRUE); return wRet; } /*********************************************************************** * LBDeleteString */ static LONG LBDeleteString(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); LONG lRet = ListBoxDeleteString(lphl,wParam); ListBoxUpdateWindow(hwnd,lphl,TRUE); return lRet; } /*********************************************************************** * LBFindString */ static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR); } /*********************************************************************** * LBFindStringExact */ static LONG LBFindStringExact(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_EXACT); } /*********************************************************************** * LBGetCaretIndex */ static LONG LBGetCaretIndex(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); return lphl->ItemFocused; } /*********************************************************************** * LBGetCount */ static LONG LBGetCount(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl; lphl = ListBoxGetStorageHeader(hwnd); return lphl->ItemsCount; } /*********************************************************************** * LBGetCurSel */ static LONG LBGetCurSel(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl; lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb,"ListBox LB_GETCURSEL %i !\n", lphl->ItemFocused); return lphl->ItemFocused; } /*********************************************************************** * LBGetHorizontalExtent */ static LONG LBGetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam) { return 0; } /*********************************************************************** * LBGetItemHeight */ static LONG LBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam); if (lpls == NULL) return LB_ERR; return lpls->mis.itemHeight; } /*********************************************************************** * LBGetItemRect */ static LONG LBGetItemRect(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); return ListBoxGetItemRect(lphl, wParam, PTR_SEG_TO_LIN(lParam)); } /*********************************************************************** * LBGetSel */ static LONG LBGetSel(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); int iSel = ListBoxGetSel(lphl, wParam); dprintf_listbox(stdnimp,"LBGetSel: item %u - %i\n",wParam,iSel); return (iSel)? 1 : 0; } /*********************************************************************** * LBGetSelCount */ static LONG LBGetSelCount(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); LPLISTSTRUCT lpls; int cnt = 0; int items = 0; if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )) return LB_ERR; for( lpls = lphl->lpFirst; lpls; lpls = lpls->lpNext ) { items++; if (lpls->itemState ) cnt++; } return cnt; } /*********************************************************************** * LBGetSelItems */ static LONG LBGetSelItems(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); LPLISTSTRUCT lpls; int cnt, idx; int *lpItems = PTR_SEG_TO_LIN(lParam); if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )) return LB_ERR; if (wParam == 0) return 0; lpls = lphl->lpFirst; cnt = 0; idx = 0; while (lpls != NULL) { if (lpls->itemState > 0) lpItems[cnt++] = idx; if (cnt == wParam) break; idx++; lpls = lpls->lpNext; } return cnt; } /*********************************************************************** * LBGetTextLen */ static LONG LBGetTextLen(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam); if (lpls == NULL || !lphl->HasStrings) return LB_ERR; return strlen(lpls->itemText); } /*********************************************************************** * LBGetDlgCode */ static LONG LBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam) { return DLGC_WANTARROWS | DLGC_WANTCHARS; } /*********************************************************************** * LBGetTopIndex */ static LONG LBGetTopIndex(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); return lphl->FirstVisible; } /*********************************************************************** * LBSelectString */ static LONG LBSelectString(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); INT iRet; iRet = lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR); if( iRet != LB_ERR) { if( lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ) ListBoxSetSel(lphl,iRet,TRUE); else ListBoxSetCurSel(lphl,iRet); lphl->ItemFocused = iRet; InvalidateRect32( hwnd, 0, TRUE ); } return iRet; } /*********************************************************************** * LBSelItemRange */ static LONG LBSelItemRange(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); LPLISTSTRUCT lpls; WORD cnt; WORD first = LOWORD(lParam); WORD last = HIWORD(lParam); BOOL select = wParam; if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )) return LB_ERR; if (first >= lphl->ItemsCount || last >= lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; cnt = 0; while (lpls != NULL) { if (cnt++ >= first) lpls->itemState = select ? lpls->itemState | ODS_SELECTED : 0; if (cnt > last) break; lpls = lpls->lpNext; } return 0; } /*********************************************************************** * LBSetCaretIndex */ static LONG LBSetCaretIndex(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); int i; if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )) return 0; dprintf_listbox(stddeb,"LBSetCaretIndex: hwnd %04x n=%i\n",hwnd,wParam); if (wParam >= lphl->ItemsCount) return LB_ERR; lphl->ItemFocused = wParam; i = ListBoxScrollToFocus (lphl); SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); if(i) InvalidateRect32( hwnd, NULL, TRUE ); return 1; } /*********************************************************************** * LBSetColumnWidth */ static LONG LBSetColumnWidth(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); lphl->ColumnsWidth = wParam; InvalidateRect32( hwnd, NULL, TRUE ); return 0; } /*********************************************************************** * LBSetHorizontalExtent */ static LONG LBSetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam) { return 0; } /*********************************************************************** * LBGetItemData */ static LONG LBGetItemData(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb, "LB_GETITEMDATA wParam=%x\n", wParam); return ListBoxGetItemData(lphl, wParam); } /*********************************************************************** * LBSetItemData */ static LONG LBSetItemData(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam, lParam); return ListBoxSetItemData(lphl, wParam, lParam); } /*********************************************************************** * LBSetTabStops */ static LONG LBSetTabStops(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl; lphl = ListBoxGetStorageHeader(hwnd); if (lphl->TabStops != NULL) { lphl->iNumStops = 0; free (lphl->TabStops); } lphl->TabStops = malloc (wParam * sizeof (short)); if (lphl->TabStops) { lphl->iNumStops = wParam; memcpy (lphl->TabStops, PTR_SEG_TO_LIN(lParam), wParam * sizeof (short)); return TRUE; } return FALSE; } /*********************************************************************** * LBSetCurSel */ static LONG LBSetCurSel(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); WORD wRet; dprintf_listbox(stddeb,"ListBox LB_SETCURSEL wParam=%x !\n", wParam); wRet = ListBoxSetCurSel(lphl, wParam); SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); InvalidateRect32( hwnd, NULL, TRUE ); return wRet; } /*********************************************************************** * LBSetSel */ static LONG LBSetSel(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); RECT16 rect; int iRet; dprintf_listbox(stddeb,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam); iRet = ListBoxSetSel(lphl, LOWORD(lParam), wParam); if( iRet > 1 ) InvalidateRect32( hwnd, NULL, TRUE ); else if( iRet != LB_ERR ) { if( lphl->dwStyle & LBS_EXTENDEDSEL && lphl->ItemFocused != LOWORD(lParam) ) { ListBoxGetItemRect(lphl, lphl->ItemFocused , &rect); InvalidateRect16( hwnd, &rect, TRUE ); lphl->ItemFocused = LOWORD(lParam); } ListBoxGetItemRect(lphl,LOWORD(lParam),&rect); InvalidateRect16( hwnd, &rect, TRUE ); } return (iRet == (WORD)LB_ERR)? LB_ERR: 0; } /*********************************************************************** * LBSetTopIndex */ static LONG LBSetTopIndex(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); dprintf_listbox(stddeb,"ListBox LB_SETTOPINDEX wParam=%x !\n", wParam); lphl->FirstVisible = wParam; SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); InvalidateRect32( hwnd, NULL, TRUE ); return 0; } /*********************************************************************** * LBSetItemHeight */ static LONG LBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam) { LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); WORD wRet; dprintf_listbox(stddeb,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam); wRet = ListBoxSetItemHeight(lphl, wParam, lParam); InvalidateRect32( hwnd, NULL, TRUE ); return wRet; } /*********************************************************************** * LBPassToParent */ static LRESULT LBPassToParent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { WND* ptrWnd = WIN_FindWndPtr(hwnd); if( ptrWnd ) if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */ ptrWnd->parent ) return SendMessage16(ptrWnd->parent->hwndSelf,message,wParam,lParam); return 0; } /*********************************************************************** * ListBoxWndProc */ LRESULT ListBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: return LBCreate(hwnd, wParam, lParam); case WM_DESTROY: return LBDestroy(hwnd, wParam, lParam); case WM_GETDLGCODE: return LBGetDlgCode(hwnd, wParam, lParam); case WM_VSCROLL: return LBVScroll(hwnd, wParam, lParam); case WM_HSCROLL: return LBHScroll(hwnd, wParam, lParam); case WM_LBUTTONDOWN: return LBLButtonDown(hwnd, wParam, lParam); case WM_LBUTTONUP: return LBLButtonUp(hwnd, wParam, lParam); case WM_RBUTTONUP: return LBRButtonUp(hwnd, wParam, lParam); case WM_LBUTTONDBLCLK: return LBRButtonUp(hwnd, wParam, lParam); case WM_MOUSEMOVE: return LBMouseMove(hwnd, wParam, lParam); case WM_KEYDOWN: return LBKeyDown(hwnd, wParam, lParam); case WM_CHAR: return LBChar(hwnd, wParam, lParam); case WM_SETFONT: return LBSetFont(hwnd, wParam, lParam); case WM_SETREDRAW: return LBSetRedraw(hwnd, wParam, lParam); case WM_PAINT: return LBPaint(hwnd, wParam, lParam); case WM_SETFOCUS: return LBSetFocus(hwnd, wParam, lParam); case WM_KILLFOCUS: return LBKillFocus(hwnd, wParam, lParam); case WM_NCCALCSIZE: return LBNCCalcSize(hwnd, wParam, lParam); case LB_RESETCONTENT: return LBResetContent(hwnd, wParam, lParam); case LB_DIR: return LBDir(hwnd, wParam, lParam); case LB_ADDSTRING: return LBAddString(hwnd, wParam, lParam); case LB_INSERTSTRING: return LBInsertString(hwnd, wParam, lParam); case LB_DELETESTRING: return LBDeleteString(hwnd, wParam, lParam); case LB_FINDSTRING: return LBFindString(hwnd, wParam, lParam); case LB_FINDSTRINGEXACT: return LBFindStringExact(hwnd, wParam, lParam); case LB_GETCARETINDEX: return LBGetCaretIndex(hwnd, wParam, lParam); case LB_GETCOUNT: return LBGetCount(hwnd, wParam, lParam); case LB_GETCURSEL: return LBGetCurSel(hwnd, wParam, lParam); case LB_GETHORIZONTALEXTENT: return LBGetHorizontalExtent(hwnd, wParam, lParam); case LB_GETITEMDATA: return LBGetItemData(hwnd, wParam, lParam); case LB_GETITEMHEIGHT: return LBGetItemHeight(hwnd, wParam, lParam); case LB_GETITEMRECT: return LBGetItemRect(hwnd, wParam, lParam); case LB_GETSEL: return LBGetSel(hwnd, wParam, lParam); case LB_GETSELCOUNT: return LBGetSelCount(hwnd, wParam, lParam); case LB_GETSELITEMS: return LBGetSelItems(hwnd, wParam, lParam); case LB_GETTEXT: return LBGetText(hwnd, wParam, lParam); case LB_GETTEXTLEN: return LBGetTextLen(hwnd, wParam, lParam); case LB_GETTOPINDEX: return LBGetTopIndex(hwnd, wParam, lParam); case LB_SELECTSTRING: return LBSelectString(hwnd, wParam, lParam); case LB_SELITEMRANGE: return LBSelItemRange(hwnd, wParam, lParam); case LB_SETCARETINDEX: return LBSetCaretIndex(hwnd, wParam, lParam); case LB_SETCOLUMNWIDTH: return LBSetColumnWidth(hwnd, wParam, lParam); case LB_SETHORIZONTALEXTENT: return LBSetHorizontalExtent(hwnd, wParam, lParam); case LB_SETITEMDATA: return LBSetItemData(hwnd, wParam, lParam); case LB_SETTABSTOPS: return LBSetTabStops(hwnd, wParam, lParam); case LB_SETCURSEL: return LBSetCurSel(hwnd, wParam, lParam); case LB_SETSEL: return LBSetSel(hwnd, wParam, lParam); case LB_SETTOPINDEX: return LBSetTopIndex(hwnd, wParam, lParam); case LB_SETITEMHEIGHT: return LBSetItemHeight(hwnd, wParam, lParam); case WM_DROPFILES: return LBPassToParent(hwnd, message, wParam, lParam); /* these will have to be implemented for proper LBS_EXTENDEDSEL - * * anchor item is an item that with caret (focused) item defines a * range of currently selected items when listbox is in the extended * selection mode. */ case LB_SETANCHORINDEX: return LB_SETANCHORINDEX; /* that's what Windows returns */ case LB_GETANCHORINDEX: return 0; case WM_DROPOBJECT: case WM_QUERYDROPOBJECT: case WM_DRAGSELECT: case WM_DRAGMOVE: { LPDRAGINFO lpDragInfo = (LPDRAGINFO) PTR_SEG_TO_LIN((SEGPTR)lParam); LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd); lpDragInfo->l = ListBoxFindMouse(lphl,lpDragInfo->pt.x, lpDragInfo->pt.y); return LBPassToParent(hwnd, message, wParam, lParam); } } return DefWindowProc16(hwnd, message, wParam, lParam); } /********************************************************************** * DlgDirSelect (USER.99) */ BOOL DlgDirSelect( HWND hDlg, LPSTR lpStr, INT id ) { char *buffer; INT i; dprintf_listbox( stddeb, "DlgDirSelect: %04x '%s' %d\n", hDlg, lpStr, id ); if ((i = SendDlgItemMessage16( hDlg, id, LB_GETCURSEL, 0, 0 )) == LB_ERR) return FALSE; if (!(buffer = SEGPTR_ALLOC( 20 * sizeof(char) ))) return FALSE; SendDlgItemMessage16(hDlg, id, LB_GETTEXT, i, (LPARAM)SEGPTR_GET(buffer) ); if (buffer[0] == '[') /* drive or directory */ { if (buffer[1] == '-') /* drive */ { lpStr[0] = buffer[2]; lpStr[1] = ':'; lpStr[2] = '\0'; dprintf_listbox( stddeb, "Returning drive '%s'\n", lpStr ); SEGPTR_FREE(buffer); return TRUE; } strcpy( lpStr, buffer + 1 ); lpStr[strlen(lpStr)-1] = '\\'; dprintf_listbox( stddeb, "Returning directory '%s'\n", lpStr ); SEGPTR_FREE(buffer); return TRUE; } strcpy( lpStr, buffer ); dprintf_listbox( stddeb, "Returning file '%s'\n", lpStr ); SEGPTR_FREE(buffer); return FALSE; } /********************************************************************** * DlgDirList (USER.100) */ INT DlgDirList( HWND hDlg, SEGPTR spec, INT idLBox, INT idStatic, UINT attrib ) { char *filespec = (char *)PTR_SEG_TO_LIN( spec ); int drive; HWND hwnd; #define SENDMSG(msg,wparam,lparam) \ ((attrib & DDL_POSTMSGS) ? PostMessage( hwnd, msg, wparam, lparam ) \ : SendMessage16( hwnd, msg, wparam, lparam )) dprintf_listbox( stddeb, "DlgDirList: %04x '%s' %d %d %04x\n", hDlg, filespec ? filespec : "NULL", idLBox, idStatic, attrib ); if (filespec && filespec[0] && (filespec[1] == ':')) { drive = toupper( filespec[0] ) - 'A'; filespec += 2; if (!DRIVE_SetCurrentDrive( drive )) return FALSE; } else drive = DRIVE_GetCurrentDrive(); if (idLBox && ((hwnd = GetDlgItem( hDlg, idLBox )) != 0)) { char mask[20]; if (!filespec || !filespec[0]) strcpy( mask, "*.*" ); else { /* If the path exists and is a directory, chdir to it */ if (DRIVE_Chdir( drive, filespec )) strcpy( mask, "*.*" ); else { char *p, *p2; p = filespec; if ((p2 = strrchr( p, '\\' ))) p = p2 + 1; if ((p2 = strrchr( p, '/' ))) p = p2 + 1; lstrcpyn32A( mask, p, sizeof(mask) ); if (p != filespec) { p[-1] = '\0'; if (!DRIVE_Chdir( drive, filespec )) return FALSE; } } } strcpy( (char *)PTR_SEG_TO_LIN(spec), mask ); dprintf_listbox(stddeb, "ListBoxDirectory: path=%c:\\%s mask=%s\n", 'A' + drive, DRIVE_GetDosCwd(drive), mask); SENDMSG( LB_RESETCONTENT, 0, 0 ); if ((attrib & DDL_DIRECTORY) && !(attrib & DDL_EXCLUSIVE)) { char *temp; if (SENDMSG( LB_DIR, attrib & ~(DDL_DIRECTORY | DDL_DRIVES), (LPARAM)spec ) == LB_ERR) return FALSE; if (!(temp = SEGPTR_ALLOC( 4*sizeof(char) ))) return FALSE; strcpy( temp, "*.*" ); /* FIXME: this won't work with PostMessage(), as temp will */ /* have been freed by the time we do a DispatchMessage(). */ if (SENDMSG( LB_DIR, (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE, (LPARAM)SEGPTR_GET(temp) ) == LB_ERR) { SEGPTR_FREE(temp); return FALSE; } SEGPTR_FREE(temp); } else { if (SENDMSG( LB_DIR, attrib, (LPARAM)spec) == LB_ERR) return FALSE; } } if (idStatic && ((hwnd = GetDlgItem( hDlg, idStatic )) != 0)) { char temp[512]; int drive = DRIVE_GetCurrentDrive(); strcpy( temp, "A:\\" ); temp[0] += drive; lstrcpyn32A( temp + 3, DRIVE_GetDosCwd(drive), sizeof(temp)-3 ); AnsiLower( temp ); /* Can't use PostMessage() here, because the string is on the stack */ SetDlgItemText32A( hDlg, idStatic, temp ); } return TRUE; #undef SENDMSG }