diff options
Diffstat (limited to 'docs/release/src/osd/winui/picker.cpp')
-rw-r--r-- | docs/release/src/osd/winui/picker.cpp | 1603 |
1 files changed, 1603 insertions, 0 deletions
diff --git a/docs/release/src/osd/winui/picker.cpp b/docs/release/src/osd/winui/picker.cpp new file mode 100644 index 00000000000..300c63be467 --- /dev/null +++ b/docs/release/src/osd/winui/picker.cpp @@ -0,0 +1,1603 @@ +// For licensing and usage information, read docs/winui_license.txt +// MASTER +//**************************************************************************** + +// standard windows headers +#define _WIN32_IE 0x0501 +#include <windows.h> +#include <windowsx.h> +#include <commctrl.h> + +// standard C headers +#include <tchar.h> + +// MAME/MAMEUI headers +#include "picker.h" +#include "winui.h" +#include "mui_opts.h" +#include "treeview.h" + + +// fix warning: cast does not match function type +#if defined(__GNUC__) && defined(ListView_GetHeader) +#undef ListView_GetHeader +#endif +#if defined(__GNUC__) && defined(ListView_GetImageList) +#undef ListView_GetImageList +#undef ListView_GetItemRect +#endif + +#ifndef ListView_GetItemRect +#define ListView_GetItemRect(w,i,p,c) \ + (BOOL)SNDMSG((w),LVM_GETITEMRECT,i,((p != NULL)?(((LPRECT)(p))->left=(c),(LPARAM)(LPRECT)(p)):0)) +#endif + +#ifndef ListView_GetImageList +#define ListView_GetImageList(w,i) (HIMAGELIST)(LRESULT)(int)SendMessage((w),LVM_GETIMAGELIST,(i),0) +#endif // ListView_GetImageList + +#ifndef ListView_GetHeader +#define ListView_GetHeader(w) (HWND)(LRESULT)(int)SNDMSG((w),LVM_GETHEADER,0,0) +#endif // ListView_GetHeader + +#ifndef HDM_SETIMAGELIST +#define HDM_SETIMAGELIST (HDM_FIRST + 8) +#endif // HDM_SETIMAGELIST + +#ifndef Header_SetImageList +#define Header_SetImageList(h,i) (HIMAGELIST)(LRESULT)(int)SNDMSG((h), HDM_SETIMAGELIST, 0, (LPARAM)i) +#endif // Header_SetImageList + +#ifndef HDF_SORTUP +#define HDF_SORTUP 0x400 +#endif + +#ifndef HDF_SORTDOWN +#define HDF_SORTDOWN 0x200 +#endif + + + +struct PickerInfo +{ + const struct PickerCallbacks *pCallbacks; + WNDPROC pfnParentWndProc; + int nCurrentViewID; + int nLastItem; + int nColumnCount; + int *pnColumnsShown; + int *pnColumnsOrder; + UINT_PTR nTimer; + const LPCTSTR *ppszColumnNames; +}; + + +static struct PickerInfo *GetPickerInfo(HWND hWnd) +{ + LONG_PTR l = GetWindowLongPtr(hWnd, GWLP_USERDATA); + return (struct PickerInfo *) l; +} + + + +static LRESULT CallParentWndProc(WNDPROC pfnParentWndProc, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT rc; + + if (!pfnParentWndProc) + pfnParentWndProc = GetPickerInfo(hWnd)->pfnParentWndProc; + + if (IsWindowUnicode(hWnd)) + rc = CallWindowProcW(pfnParentWndProc, hWnd, message, wParam, lParam); + else + rc = CallWindowProcA(pfnParentWndProc, hWnd, message, wParam, lParam); + return rc; +} + +static BOOL ListViewOnErase(HWND hWnd, HDC hDC) +{ + MYBITMAPINFO *pbmDesc = GetBackgroundInfo(); + HBITMAP hBackground = GetBackgroundBitmap(); + HPALETTE hPALbg = GetBackgroundPalette(); + + // this does not draw the background properly in report view + + RECT rcClient; + GetClientRect(hWnd, &rcClient); + + HDC htempDC = CreateCompatibleDC(hDC); + HBITMAP hOldBitmap = (HBITMAP)SelectObject(htempDC, hBackground); + + HRGN rgnBitmap = CreateRectRgnIndirect(&rcClient); + SelectClipRgn(hDC, rgnBitmap); + DeleteBitmap(rgnBitmap); + + HPALETTE hPAL = (!hPALbg) ? CreateHalftonePalette(hDC) : hPALbg; + + if (GetDeviceCaps(htempDC, RASTERCAPS) & RC_PALETTE && hPAL != NULL) + { + SelectPalette(htempDC, hPAL, false); + RealizePalette(htempDC); + } + + // Get x and y offset + POINT pt = {0,0}; + MapWindowPoints(hWnd, GetTreeView(), &pt, 1); + POINT ptOrigin; + GetDCOrgEx(hDC, &ptOrigin); + ptOrigin.x -= pt.x; + ptOrigin.y -= pt.y; + ptOrigin.x = -GetScrollPos(hWnd, SB_HORZ); + ptOrigin.y = -GetScrollPos(hWnd, SB_VERT); + + if (pbmDesc->bmWidth && pbmDesc->bmHeight) + for (int i = ptOrigin.x; i < rcClient.right; i += pbmDesc->bmWidth) + for (int j = ptOrigin.y; j < rcClient.bottom; j += pbmDesc->bmHeight) + BitBlt(hDC, i, j, pbmDesc->bmWidth, pbmDesc->bmHeight, htempDC, 0, 0, SRCCOPY); + + SelectObject(htempDC, hOldBitmap); + DeleteDC(htempDC); + + if (!pbmDesc->bmColors) + { + DeletePalette(hPAL); + hPAL = 0; + } + + return true; +} + + + +static BOOL ListViewNotify(HWND hWnd, LPNMHDR lpNmHdr) +{ + // This code is for using bitmap in the background + // Invalidate the right side of the control when a column is resized + if (lpNmHdr->code == HDN_ITEMCHANGINGA || lpNmHdr->code == HDN_ITEMCHANGINGW) + { + DWORD dwPos = GetMessagePos(); + POINT pt; + pt.x = LOWORD(dwPos); + pt.y = HIWORD(dwPos); + + RECT rcClient; + GetClientRect(hWnd, &rcClient); + ScreenToClient(hWnd, &pt); + rcClient.left = pt.x; + InvalidateRect(hWnd, &rcClient, false); + } + return false; +} + + + +static BOOL ListViewContextMenu(HWND hwndPicker, LPARAM lParam) +{ + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hwndPicker); + + // Extract the point out of the lparam + POINT pt; + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + if (pt.x < 0 && pt.y < 0) + GetCursorPos(&pt); + + // Figure out which header column was clicked, if at all + int nViewID = Picker_GetViewID(hwndPicker); + int nColumn = -1; + + if ((nViewID == VIEW_REPORT) || (nViewID == VIEW_GROUPED)) + { + HWND hwndHeader = ListView_GetHeader(hwndPicker); + POINT headerPt = pt; + ScreenToClient(hwndHeader, &headerPt); + + RECT rcCol; + for (int i = 0; Header_GetItemRect(hwndHeader, i, &rcCol); i++) + { + if (PtInRect(&rcCol, headerPt)) + { + nColumn = i; + break; + } + } + } + + if (nColumn >= 0) + { + // A column header was clicked + if (pPickerInfo->pCallbacks->pfnOnHeaderContextMenu) + pPickerInfo->pCallbacks->pfnOnHeaderContextMenu(pt, nColumn); + } + else + { + // The body was clicked + if (pPickerInfo->pCallbacks->pfnOnBodyContextMenu) + pPickerInfo->pCallbacks->pfnOnBodyContextMenu(pt); + } + return true; +} + + + +static void Picker_Free(struct PickerInfo *pPickerInfo) +{ + // Free up all resources associated with this picker structure + if (pPickerInfo->pnColumnsShown) + free(pPickerInfo->pnColumnsShown); + if (pPickerInfo->pnColumnsOrder) + free(pPickerInfo->pnColumnsOrder); + free(pPickerInfo); +} + + + +static LRESULT CALLBACK ListViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + struct PickerInfo *pPickerInfo; + LRESULT rc = 0; + BOOL bHandled = false; + WNDPROC pfnParentWndProc; + HWND hwndHeaderCtrl = NULL; + HFONT hHeaderCtrlFont = NULL; + + pPickerInfo = GetPickerInfo(hWnd); + pfnParentWndProc = pPickerInfo->pfnParentWndProc; + + switch(message) + { + case WM_MOUSEMOVE: + if (MouseHasBeenMoved()) + ShowCursor(true); + break; + + case WM_ERASEBKGND: + if (GetBackgroundBitmap()) + { + rc = ListViewOnErase(hWnd, (HDC) wParam); + bHandled = true; + } + break; + + case WM_NOTIFY: + bHandled = ListViewNotify(hWnd, (LPNMHDR) lParam); + break; + + case WM_SETFONT: + hwndHeaderCtrl = ListView_GetHeader(hWnd); + if (hwndHeaderCtrl) + hHeaderCtrlFont = GetWindowFont(hwndHeaderCtrl); + break; + + case WM_CONTEXTMENU: + bHandled = ListViewContextMenu(hWnd, lParam); + break; + + case WM_DESTROY: + // Received WM_DESTROY; time to clean up + if (pPickerInfo->pCallbacks->pfnSetViewMode) + pPickerInfo->pCallbacks->pfnSetViewMode(pPickerInfo->nCurrentViewID); + Picker_Free(pPickerInfo); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR) pfnParentWndProc); + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) NULL); + break; + } + + if (!bHandled) + rc = CallParentWndProc(pfnParentWndProc, hWnd, message, wParam, lParam); + + // If we received WM_SETFONT, reset header ctrl font back to original font + if (hwndHeaderCtrl) + SetWindowFont(hwndHeaderCtrl, hHeaderCtrlFont, true); + + return rc; +} + + + +// Re/initialize the ListControl Columns +static void Picker_InternalResetColumnDisplay(HWND hWnd, BOOL bFirstTime) +{ + LV_COLUMN lvc; + int i = 0; + int nColumn = 0; + //int shown_columns; + LVCOLUMN col; + struct PickerInfo *pPickerInfo; + HRESULT res = 0; + BOOL b_res = 0; + + pPickerInfo = GetPickerInfo(hWnd); + + int *widths, *order, *shown; + widths = (int*)malloc(pPickerInfo->nColumnCount * sizeof(*widths)); + order = (int*)malloc(pPickerInfo->nColumnCount * sizeof(*order)); + shown = (int*)malloc(pPickerInfo->nColumnCount * sizeof(*shown)); + if (!widths || !order || !shown) + goto done; + + memset(widths, 0, pPickerInfo->nColumnCount * sizeof(*widths)); + memset(order, 0, pPickerInfo->nColumnCount * sizeof(*order)); + memset(shown, 0, pPickerInfo->nColumnCount * sizeof(*shown)); + pPickerInfo->pCallbacks->pfnGetColumnWidths(widths); + pPickerInfo->pCallbacks->pfnGetColumnOrder(order); + pPickerInfo->pCallbacks->pfnGetColumnShown(shown); + + if (!bFirstTime) + { + DWORD style = GetWindowLong(hWnd, GWL_STYLE); + + // switch the list view to LVS_REPORT style so column widths reported correctly + SetWindowLong(hWnd, GWL_STYLE, (GetWindowLong(hWnd, GWL_STYLE) & ~LVS_TYPEMASK) | LVS_REPORT); + + // Retrieve each of the column widths + i = 0; + memset(&col, 0, sizeof(col)); + col.mask = LVCF_WIDTH; + while(ListView_GetColumn(hWnd, 0, &col)) + { + nColumn = Picker_GetRealColumnFromViewColumn(hWnd, i++); + widths[nColumn] = col.cx; + b_res = ListView_DeleteColumn(hWnd, 0); + } + + pPickerInfo->pCallbacks->pfnSetColumnWidths(widths); + + // restore old style + SetWindowLong(hWnd, GWL_STYLE, style); + } + + nColumn = 0; + for (i = 0; i < pPickerInfo->nColumnCount; i++) + { + if (shown[order[i]]) + { + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT; + lvc.pszText = (LPTSTR) pPickerInfo->ppszColumnNames[order[i]]; + lvc.iSubItem = nColumn; + lvc.cx = widths[order[i]]; + lvc.fmt = LVCFMT_LEFT; + if (lvc.pszText[0] > 0) // column name cannot be blank + { + res = ListView_InsertColumn(hWnd, nColumn, &lvc); + pPickerInfo->pnColumnsOrder[nColumn] = order[i]; + //printf("Visible column %d: Logical column %d; Width=%d\n", nColumn, order[i], widths[order[i]]); + nColumn++; + } + } + } + + //shown_columns = nColumn; + + /* Fill this in so we can still sort on columns NOT shown */ + for (i = 0; i < pPickerInfo->nColumnCount && nColumn < pPickerInfo->nColumnCount; i++) + { + if (!shown[order[i]]) + { + pPickerInfo->pnColumnsOrder[nColumn] = order[i]; + nColumn++; + } + } + + if (GetListFontColor() == RGB(255, 255, 255)) + b_res = ListView_SetTextColor(hWnd, RGB(240, 240, 240)); + else + b_res = ListView_SetTextColor(hWnd, GetListFontColor()); + +done: + if (widths) + free(widths); + if (order) + free(order); + if (shown) + free(shown); + res++; + b_res++; +} + + + +void Picker_ResetColumnDisplay(HWND hWnd) +{ + Picker_InternalResetColumnDisplay(hWnd, false); +} + + + +void Picker_ClearIdle(HWND hwndPicker) +{ + struct PickerInfo *pPickerInfo; + + pPickerInfo = GetPickerInfo(hwndPicker); + if (pPickerInfo->nTimer) + { + KillTimer(hwndPicker, 0); + pPickerInfo->nTimer = 0; + } +} + + + +static void CALLBACK Picker_TimerProc(HWND hwndPicker, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + struct PickerInfo *pPickerInfo; + DWORD nTickCount = 0; + DWORD nMaxIdleTicks = 50; + + pPickerInfo = GetPickerInfo(hwndPicker); + BOOL bContinueIdle = false; + DWORD nBaseTickCount = GetTickCount(); + + // This idle procedure will loop until either idling is over, or until + // a specified amount of time elapses (in this case, 50ms). This frees + // idle callbacks of any responsibility for balancing their workloads; the + // picker code will + do + { + if (pPickerInfo->pCallbacks->pfnOnIdle) + bContinueIdle = pPickerInfo->pCallbacks->pfnOnIdle(hwndPicker); + nTickCount = GetTickCount(); + } + while(bContinueIdle && ((nTickCount - nBaseTickCount) < nMaxIdleTicks)); + + if (!bContinueIdle) + Picker_ClearIdle(hwndPicker); +} + + + +// Instructs this picker to reset idling; idling will continue until the +// idle function returns false +void Picker_ResetIdle(HWND hwndPicker) +{ + struct PickerInfo *pPickerInfo; + + pPickerInfo = GetPickerInfo(hwndPicker); + + Picker_ClearIdle(hwndPicker); + if (pPickerInfo->pCallbacks->pfnOnIdle) + pPickerInfo->nTimer = SetTimer(hwndPicker, 0, 0, Picker_TimerProc); +} + + + +BOOL Picker_IsIdling(HWND hwndPicker) +{ + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hwndPicker); + return pPickerInfo->nTimer != 0; +} + + + +BOOL SetupPicker(HWND hwndPicker, const struct PickerOptions *pOptions) +{ + struct PickerInfo *pPickerInfo; + int i = 0; + LONG_PTR l = 0; + HRESULT res = 0; + + //assert(hwndPicker); + + // Allocate the list view struct + pPickerInfo = (struct PickerInfo *) malloc(sizeof(struct PickerInfo)); + if (!pPickerInfo) + return false; + + // And fill it out + memset(pPickerInfo, 0, sizeof(*pPickerInfo)); + pPickerInfo->pCallbacks = pOptions->pCallbacks; + pPickerInfo->nColumnCount = pOptions->nColumnCount; + pPickerInfo->ppszColumnNames = pOptions->ppszColumnNames; + pPickerInfo->nLastItem = -1; + + if (pPickerInfo->nColumnCount) + { + // Allocate space for the column order and columns shown array + pPickerInfo->pnColumnsOrder = (int*)malloc(pPickerInfo->nColumnCount * + sizeof(*pPickerInfo->pnColumnsOrder)); + pPickerInfo->pnColumnsShown = (int*)malloc(pPickerInfo->nColumnCount * + sizeof(*pPickerInfo->pnColumnsShown)); + if (!pPickerInfo->pnColumnsOrder || !pPickerInfo->pnColumnsShown) + goto error; + + // set up initial values + for (i = 0; i < pPickerInfo->nColumnCount; i++) + { + pPickerInfo->pnColumnsOrder[i] = i; + pPickerInfo->pnColumnsShown[i] = true; + } + + if (GetUseOldControl()) + { + if (pPickerInfo->pCallbacks->pfnSetColumnOrder) + pPickerInfo->pCallbacks->pfnSetColumnOrder(pPickerInfo->pnColumnsOrder); + if (pPickerInfo->pCallbacks->pfnSetColumnShown) + pPickerInfo->pCallbacks->pfnSetColumnShown(pPickerInfo->pnColumnsShown); + } + else + { + if (pPickerInfo->pCallbacks->pfnGetColumnOrder) + pPickerInfo->pCallbacks->pfnGetColumnOrder(pPickerInfo->pnColumnsOrder); + if (pPickerInfo->pCallbacks->pfnGetColumnShown) + pPickerInfo->pCallbacks->pfnGetColumnShown(pPickerInfo->pnColumnsShown); + } + } + + // Hook in our wndproc and userdata pointer + l = GetWindowLongPtr(hwndPicker, GWLP_WNDPROC); + pPickerInfo->pfnParentWndProc = (WNDPROC) l; + SetWindowLongPtr(hwndPicker, GWLP_USERDATA, (LONG_PTR) pPickerInfo); + SetWindowLongPtr(hwndPicker, GWLP_WNDPROC, (LONG_PTR) ListViewWndProc); + + res = ListView_SetExtendedListViewStyle(hwndPicker, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | + LVS_EX_UNDERLINEHOT | LVS_EX_UNDERLINECOLD | LVS_EX_LABELTIP); + + Picker_InternalResetColumnDisplay(hwndPicker, true); + Picker_ResetIdle(hwndPicker); + res++; + return true; + +error: + if (pPickerInfo) + Picker_Free(pPickerInfo); + return false; +} + + + +int Picker_GetViewID(HWND hwndPicker) +{ + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hwndPicker); + return pPickerInfo->nCurrentViewID; +} + + + +void Picker_SetViewID(HWND hwndPicker, int nViewID) +{ + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hwndPicker); + + // Change the nCurrentViewID member + pPickerInfo->nCurrentViewID = nViewID; + if (pPickerInfo->pCallbacks->pfnSetViewMode) + pPickerInfo->pCallbacks->pfnSetViewMode(pPickerInfo->nCurrentViewID); + + // Change the ListView flags in accordance + LONG_PTR nListViewStyle; + switch(nViewID) + { + case VIEW_LARGE_ICONS: + nListViewStyle = LVS_ICON; + break; + case VIEW_SMALL_ICONS: + nListViewStyle = LVS_SMALLICON; + break; + case VIEW_INLIST: + nListViewStyle = LVS_LIST; + break; + case VIEW_GROUPED: + case VIEW_REPORT: + default: + nListViewStyle = LVS_REPORT; + break; + } + + DWORD dwStyle = GetWindowLong(hwndPicker, GWL_STYLE); + if (GetUseXPControl()) + { + // RS Microsoft must have changed something in the Ownerdraw handling with Version 6 of the Common Controls + // as on all other OSes it works without this... + if (nViewID == VIEW_LARGE_ICONS || nViewID == VIEW_SMALL_ICONS) + { + // remove Ownerdraw style for Icon views + dwStyle &= ~LVS_OWNERDRAWFIXED; + if( nViewID == VIEW_SMALL_ICONS ) + { + // to properly get them to arrange, otherwise the entries might overlap + // we have to call SetWindowLong to get it into effect !! + // It's no use just setting the Style, as it's changed again further down... + SetWindowLong(hwndPicker, GWL_STYLE, (GetWindowLong(hwndPicker, GWL_STYLE) & ~LVS_TYPEMASK) | LVS_ICON); + } + } + else + { + // add again.. + dwStyle |= LVS_OWNERDRAWFIXED; + } + } + + dwStyle &= ~LVS_TYPEMASK; + dwStyle |= nListViewStyle; + SetWindowLong(hwndPicker, GWL_STYLE, dwStyle); + RedrawWindow(hwndPicker, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME); +} + + +static BOOL PickerHitTest(HWND hWnd) +{ + LVHITTESTINFO htInfo; + memset(&htInfo, 0, sizeof(htInfo)); + RECT rect; + GetWindowRect(hWnd, &rect); + DWORD res = GetMessagePos(); + POINTS p = MAKEPOINTS(res); + htInfo.pt.x = p.x - rect.left; + htInfo.pt.y = p.y - rect.top; + HRESULT result = ListView_HitTest(hWnd, &htInfo); + result++; + return (! (htInfo.flags & LVHT_NOWHERE)); +} + + +int Picker_GetSelectedItem(HWND hWnd) +{ + int nItem = ListView_GetNextItem(hWnd, -1, LVIS_SELECTED | LVIS_FOCUSED); + if (nItem < 0) + return nItem; + + LV_ITEM lvi; + memset(&lvi, 0, sizeof(lvi)); + lvi.iItem = nItem; + lvi.mask = LVIF_PARAM; + BOOL res = ListView_GetItem(hWnd, &lvi); + res++; + return lvi.lParam; +} + + +// This highlights a selected game, and scrolls it into view +void Picker_SetSelectedPick(HWND hWnd, uint32_t nIndex) +{ + // nCount is one more than number of last game + int nCount = ListView_GetItemCount(hWnd); + // No games to show + if (nCount < 1) + return; + nCount--; + if (nCount < nIndex) + nIndex = nCount; + // Highlight a game + ListView_SetItemState(hWnd, nIndex, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); + // Bring the game into view + (void)ListView_EnsureVisible(hWnd, nIndex, false); +} + + + +void Picker_SetSelectedItem(HWND hWnd, uint32_t nItem) +{ + LV_FINDINFO lvfi; + lvfi.flags = LVFI_PARAM; + lvfi.lParam = nItem; + int i = ListView_FindItem(hWnd, -1, &lvfi); + if (i == -1) + { + POINT p = {0,0}; + lvfi.flags = LVFI_NEARESTXY; + lvfi.pt = p; + i = ListView_FindItem(hWnd, -1, &lvfi); + } + Picker_SetSelectedPick(hWnd, (i == -1) ? 0 : i); +} + + + +static const TCHAR *Picker_CallGetItemString(HWND hwndPicker, int nItem, int nColumn, TCHAR *pszBuffer, UINT nBufferLength) +{ + // this call wraps the pfnGetItemString callback to properly set up the + // buffers, and normalize the results + struct PickerInfo *pPickerInfo; + const TCHAR *s; + + pPickerInfo = GetPickerInfo(hwndPicker); + pszBuffer[0] = '\0'; + s = NULL; + + if (pPickerInfo->pCallbacks->pfnGetItemString) + s = pPickerInfo->pCallbacks->pfnGetItemString(hwndPicker, nItem, nColumn, pszBuffer, nBufferLength); + + if (!s) + s = pszBuffer; + return s; +} + + + +// put the arrow on the new sort column +static void Picker_ResetHeaderSortIcon(HWND hwndPicker) +{ + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hwndPicker); + HWND hwndHeader = ListView_GetHeader(hwndPicker); + BOOL res; + + // take arrow off non-current columns + HD_ITEM hdi; + hdi.mask = HDI_FORMAT; + hdi.fmt = HDF_STRING; + for (int i = 0; i < pPickerInfo->nColumnCount; i++) + if (i != pPickerInfo->pCallbacks->pfnGetSortColumn()) + res = Header_SetItem(hwndHeader, Picker_GetViewColumnFromRealColumn(hwndPicker, i), &hdi); + + if (GetUseXPControl()) + { + // use built in sort arrows + hdi.mask = HDI_FORMAT; + hdi.fmt = HDF_STRING | (pPickerInfo->pCallbacks->pfnGetSortReverse() ? HDF_SORTDOWN : HDF_SORTUP); + } + else + { + // put our arrow icon next to the text + hdi.mask = HDI_FORMAT | HDI_IMAGE; + hdi.fmt = HDF_STRING | HDF_IMAGE | HDF_BITMAP_ON_RIGHT; + hdi.iImage = pPickerInfo->pCallbacks->pfnGetSortReverse() ? 1 : 0; + } + + int nViewColumn = Picker_GetViewColumnFromRealColumn(hwndPicker, pPickerInfo->pCallbacks->pfnGetSortColumn()); + res = Header_SetItem(hwndHeader, nViewColumn, &hdi); + res++; +} + + + +struct CompareProcParams +{ + HWND hwndPicker; + struct PickerInfo *pPickerInfo; + int nSortColumn; + int nViewMode; + BOOL bReverse; +}; + + + +static void Picker_PopulateCompareProcParams(HWND hwndPicker, struct CompareProcParams *pParams) +{ + struct PickerInfo *pPickerInfo; + + pPickerInfo = GetPickerInfo(hwndPicker); + + // populate the CompareProcParams structure + memset(pParams, 0, sizeof(*pParams)); + pParams->hwndPicker = hwndPicker; + pParams->pPickerInfo = pPickerInfo; + pParams->nViewMode = pPickerInfo->pCallbacks->pfnGetViewMode(); + if (pPickerInfo->pCallbacks->pfnGetSortColumn) + pParams->nSortColumn = pPickerInfo->pCallbacks->pfnGetSortColumn(); + if (pPickerInfo->pCallbacks->pfnGetSortReverse) + pParams->bReverse = pPickerInfo->pCallbacks->pfnGetSortReverse(); +} + + + +static int CALLBACK Picker_CompareProc(LPARAM index1, LPARAM index2, LPARAM nParamSort) +{ + struct CompareProcParams *pcpp = (struct CompareProcParams *) nParamSort; + struct PickerInfo *pPickerInfo = pcpp->pPickerInfo; + BOOL bCallCompare = true; + int nResult = 0, nParent1 = 0, nParent2 = 0; + TCHAR szBuffer1[256], szBuffer2[256]; + const TCHAR *s1, *s2; + + if (pcpp->nViewMode == VIEW_GROUPED) + { + // do our fancy compare, with clones grouped under parents + // first thing we need to do is identify both item's parents + if (pPickerInfo->pCallbacks->pfnFindItemParent) + { + nParent1 = pPickerInfo->pCallbacks->pfnFindItemParent(pcpp->hwndPicker, index1); + nParent2 = pPickerInfo->pCallbacks->pfnFindItemParent(pcpp->hwndPicker, index2); + } + else + { + nParent1 = nParent2 = -1; + } + + if ((nParent1 < 0) && (nParent2 < 0)) + { + // if both entries are both parents, we just do a basic sort + } + else if ((nParent1 >= 0) && (nParent2 >= 0)) + { + // if both entries are children and the parents are different, + // sort on their parents + if (nParent1 != nParent2) + { + index1 = nParent1; + index2 = nParent2; + } + } + else + { + // one parent, one child + if (nParent1 >= 0) + { + // first one is a child + if (nParent1 == index2) + { + // if this is a child and its parent, put child after + nResult = 1; + bCallCompare = false; + } + else + { + // sort on parent + index1 = nParent1; + } + } + else + { + // second one is a child + if (nParent2 == index1) + { + // if this is a child and its parent, put child after + nResult = -1; + bCallCompare = false; + } + else + { + // sort on parent + index2 = nParent2; + } + } + } + } + + if (bCallCompare) + { + if (pPickerInfo->pCallbacks->pfnCompare) + { + nResult = pPickerInfo->pCallbacks->pfnCompare(pcpp->hwndPicker, + index1, index2, pcpp->nSortColumn); + } + else + { + // no default sort proc, just get the string and compare them + s1 = Picker_CallGetItemString(pcpp->hwndPicker, index1, pcpp->nSortColumn, + szBuffer1, sizeof(szBuffer1) / sizeof(szBuffer1[0])); + s2 = Picker_CallGetItemString(pcpp->hwndPicker, index2, pcpp->nSortColumn, + szBuffer2, sizeof(szBuffer2) / sizeof(szBuffer2[0])); + nResult = _tcsicmp(s1, s2); + } + + if (pcpp->bReverse) + nResult = -nResult; + } + return nResult; +} + + + +void Picker_Sort(HWND hwndPicker) +{ + //struct PickerInfo *pPickerInfo; + struct CompareProcParams params; + + //pPickerInfo = GetPickerInfo(hwndPicker); + + // populate the CompareProcParams structure + Picker_PopulateCompareProcParams(hwndPicker, ¶ms); + + BOOL res = ListView_SortItems(hwndPicker, Picker_CompareProc, (LPARAM) ¶ms); + + Picker_ResetHeaderSortIcon(hwndPicker); + + LV_FINDINFO lvfi; + memset(&lvfi, 0, sizeof(lvfi)); + lvfi.flags = LVFI_PARAM; + lvfi.lParam = Picker_GetSelectedItem(hwndPicker); + int nItem = ListView_FindItem(hwndPicker, -1, &lvfi); + + res = ListView_EnsureVisible(hwndPicker, nItem, false); + res++; +} + + + +int Picker_InsertItemSorted(HWND hwndPicker, int nParam) +{ + //struct PickerInfo *pPickerInfo; + int nLow = 0, nMid = 0; + struct CompareProcParams params; + int nCompareResult = 0; + LVITEM lvi; + BOOL res = 0; + + //pPickerInfo = GetPickerInfo(hwndPicker); + + int nHigh = ListView_GetItemCount(hwndPicker); + + // populate the CompareProcParams structure + Picker_PopulateCompareProcParams(hwndPicker, ¶ms); + + while(nLow < nHigh) + { + nMid = (nHigh + nLow) / 2; + + memset(&lvi, 0, sizeof(lvi)); + lvi.mask = LVIF_PARAM; + lvi.iItem = nMid; + res = ListView_GetItem(hwndPicker, &lvi); + nCompareResult = Picker_CompareProc(nParam, lvi.lParam, (LPARAM) ¶ms); + + if (nCompareResult > 0) + nLow = nMid + 1; + else if (nCompareResult < 0) + nHigh = nMid; + else + { + nLow = nMid; + break; + } + } + + res++; + memset(&lvi, 0, sizeof(lvi)); + lvi.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM; + lvi.iItem = nLow; + lvi.iSubItem = 0; + lvi.lParam = nParam; + lvi.pszText = LPSTR_TEXTCALLBACK; + lvi.iImage = I_IMAGECALLBACK; + + return ListView_InsertItem(hwndPicker, &lvi); +} + + + +int Picker_GetRealColumnFromViewColumn(HWND hWnd, int nViewColumn) +{ + struct PickerInfo *pPickerInfo; + int nRealColumn = 0; + + pPickerInfo = GetPickerInfo(hWnd); + if (nViewColumn >= 0 && nViewColumn < pPickerInfo->nColumnCount) + nRealColumn = pPickerInfo->pnColumnsOrder[nViewColumn]; + return nRealColumn; +} + + + +int Picker_GetViewColumnFromRealColumn(HWND hWnd, int nRealColumn) +{ + struct PickerInfo *pPickerInfo; + + pPickerInfo = GetPickerInfo(hWnd); + for (int i = 0; i < pPickerInfo->nColumnCount; i++) + if (pPickerInfo->pnColumnsOrder[i] == nRealColumn) + return i; + + // major error, shouldn't be possible, but no good way to warn + return 0; +} + + + +BOOL Picker_HandleNotify(LPNMHDR lpNmHdr) +{ + struct PickerInfo *pPickerInfo; + HWND hWnd; + BOOL bResult = false; + NM_LISTVIEW *pnmv; + LV_DISPINFO *pDispInfo; + int nItem = 0, nColumn = 0; + const TCHAR *s; + BOOL bReverse = 0; + + hWnd = lpNmHdr->hwndFrom; + pPickerInfo = GetPickerInfo(hWnd); + pnmv = (NM_LISTVIEW *) lpNmHdr; + + switch(lpNmHdr->code) + { + case NM_RCLICK: + case NM_CLICK: + case NM_DBLCLK: + // don't allow selection of blank spaces in the listview + if (!PickerHitTest(hWnd)) + { + // we have no current item selected + if (pPickerInfo->nLastItem != -1) + { + Picker_SetSelectedItem(hWnd, pPickerInfo->nLastItem); + } + bResult = true; + } + else if ((lpNmHdr->code == NM_DBLCLK) && (pPickerInfo->pCallbacks->pfnDoubleClick)) + { + // double click! + pPickerInfo->pCallbacks->pfnDoubleClick(); + bResult = true; + } + break; + + case LVN_GETDISPINFO: + pDispInfo = (LV_DISPINFO *) lpNmHdr; + nItem = (int) pDispInfo->item.lParam; + + if (pDispInfo->item.mask & LVIF_IMAGE) + { + // retrieve item image + if (pPickerInfo->pCallbacks->pfnGetItemImage) + pDispInfo->item.iImage = pPickerInfo->pCallbacks->pfnGetItemImage(hWnd, nItem); + else + pDispInfo->item.iImage = 0; + bResult = true; + } + + if (pDispInfo->item.mask & LVIF_STATE) + { + pDispInfo->item.state = 0; + bResult = true; + } + + if (pDispInfo->item.mask & LVIF_TEXT) + { + // retrieve item text + nColumn = Picker_GetRealColumnFromViewColumn(hWnd, pDispInfo->item.iSubItem); + + s = Picker_CallGetItemString(hWnd, nItem, nColumn, + pDispInfo->item.pszText, pDispInfo->item.cchTextMax); + + pDispInfo->item.pszText = (TCHAR *) s; + bResult = true; + } + break; + + case LVN_ITEMCHANGED: + if ((pnmv->uOldState & LVIS_SELECTED) + && !(pnmv->uNewState & LVIS_SELECTED)) + { + if (pnmv->lParam != -1) + pPickerInfo->nLastItem = pnmv->lParam; + if (pPickerInfo->pCallbacks->pfnLeavingItem) + pPickerInfo->pCallbacks->pfnLeavingItem(hWnd, pnmv->lParam); + } + if (!(pnmv->uOldState & LVIS_SELECTED) + && (pnmv->uNewState & LVIS_SELECTED)) + { + if (pPickerInfo->pCallbacks->pfnEnteringItem) + pPickerInfo->pCallbacks->pfnEnteringItem(hWnd, pnmv->lParam); + } + bResult = true; + break; + + case LVN_COLUMNCLICK: + // if clicked on the same column we're sorting by, reverse it + if (pPickerInfo->pCallbacks->pfnGetSortColumn() == Picker_GetRealColumnFromViewColumn(hWnd, pnmv->iSubItem)) + bReverse = !pPickerInfo->pCallbacks->pfnGetSortReverse(); + else + bReverse = false; + pPickerInfo->pCallbacks->pfnSetSortReverse(bReverse); + pPickerInfo->pCallbacks->pfnSetSortColumn(Picker_GetRealColumnFromViewColumn(hWnd, pnmv->iSubItem)); + Picker_Sort(hWnd); + bResult = true; + break; + + case LVN_BEGINDRAG: + if (pPickerInfo->pCallbacks->pfnBeginListViewDrag) + pPickerInfo->pCallbacks->pfnBeginListViewDrag(pnmv); + break; + } + return bResult; +} + + + +int Picker_GetNumColumns(HWND hWnd) +{ + int nColumnCount = 0; + int *shown; + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hWnd); + + shown = (int*)malloc(pPickerInfo->nColumnCount * sizeof(*shown)); + if (!shown) + return -1; + + pPickerInfo->pCallbacks->pfnGetColumnShown(shown); + HWND hwndHeader = ListView_GetHeader(hWnd); + + if (GetUseOldControl() || (nColumnCount = Header_GetItemCount(hwndHeader)) < 1) + { + nColumnCount = 0; + for (int i = 0; i < pPickerInfo->nColumnCount ; i++ ) + if (shown[i]) + nColumnCount++; + } + + free(shown); + return nColumnCount; +} + + + +/* Add ... to Items in ListView if needed */ +static LPCTSTR MakeShortString(HDC hDC, LPCTSTR lpszLong, int nColumnLen, int nOffset) +{ + static const TCHAR szThreeDots[] = TEXT("..."); + static TCHAR szShort[MAX_PATH]; + int nStringLen = lstrlen(lpszLong); + SIZE size; + + GetTextExtentPoint32(hDC, lpszLong, nStringLen, &size); + if (nStringLen == 0 || size.cx + nOffset <= nColumnLen) + return lpszLong; + + lstrcpy(szShort, lpszLong); + GetTextExtentPoint32(hDC, szThreeDots, ARRAY_LENGTH(szThreeDots), &size); + int nAddLen = size.cx; + + for (int i = nStringLen - 1; i > 0; i--) + { + szShort[i] = 0; + GetTextExtentPoint32(hDC, szShort, i, &size); + if (size.cx + nOffset + nAddLen <= nColumnLen) + break; + } + + lstrcat(szShort, szThreeDots); + + return szShort; +} + +#define ListView_GetItemRect_Modified(hwnd,i,prc,code) (BOOL)SNDMSG((hwnd),LVM_GETITEMRECT,(WPARAM)(int)(i),(((RECT *)(prc))->left = (code),(LPARAM)(RECT *)(prc))) + +void Picker_HandleDrawItem(HWND hWnd, LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hWnd); + int *order; + order = (int*)malloc(pPickerInfo->nColumnCount * sizeof(*order)); + if (!order) + return; + + HDC hDC = lpDrawItemStruct->hDC; + RECT rcItem = lpDrawItemStruct->rcItem; + UINT uiFlags = ILD_TRANSPARENT; + HIMAGELIST hImageList; + int nItem = lpDrawItemStruct->itemID; + COLORREF clrTextSave = 0; + COLORREF clrBkSave = 0; + COLORREF clrImage = GetSysColor(COLOR_WINDOW); + static TCHAR szBuff[MAX_PATH]; + BOOL bFocus = (GetFocus() == hWnd); + LPCTSTR pszText; + UINT nStateImageMask = 0; + BOOL bSelected = 0; + LV_COLUMN lvc; + LV_ITEM lvi; + RECT rcAllLabels; + RECT rcLabel; + RECT rcIcon; + int offset = 0; + SIZE size; + int i = 0, j = 0; + int nColumn = 0; + BOOL bDrawAsChild = 0; + int indent_space = 0; + BOOL bColorChild = false; + BOOL bParentFound = false; + int nParent = 0; + HBITMAP hBackground = GetBackgroundBitmap(); + MYBITMAPINFO *pbmDesc = GetBackgroundInfo(); + BOOL res = 0; + + int nColumnMax = Picker_GetNumColumns(hWnd); + + if (GetUseOldControl()) + pPickerInfo->pCallbacks->pfnGetColumnOrder(order); + else + { + /* Get the Column Order and save it */ + res = ListView_GetColumnOrderArray(hWnd, nColumnMax, order); + + /* Disallow moving column 0 */ + if (order[0] != 0) + { + for (i = 0; i < nColumnMax; i++) + { + if (order[i] == 0) + { + order[i] = order[0]; + order[0] = 0; + } + } + res = ListView_SetColumnOrderArray(hWnd, nColumnMax, order); + } + } + + /* Labels are offset by a certain amount */ + /* This offset is related to the width of a space character */ + GetTextExtentPoint32(hDC, TEXT(" "), 1, &size); + offset = size.cx; + + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM; + lvi.iItem = nItem; + lvi.iSubItem = order[0]; + lvi.pszText = szBuff; + lvi.cchTextMax = sizeof(szBuff) / sizeof(szBuff[0]); + lvi.stateMask = 0xFFFF; /* get all state flags */ + res = ListView_GetItem(hWnd, &lvi); + + bSelected = ((lvi.state & LVIS_DROPHILITED) || ( (lvi.state & LVIS_SELECTED) && ((bFocus) || (GetWindowLong(hWnd, GWL_STYLE) & LVS_SHOWSELALWAYS)))); + + /* figure out if we indent and draw grayed */ + if (pPickerInfo->pCallbacks->pfnFindItemParent) + nParent = pPickerInfo->pCallbacks->pfnFindItemParent(hWnd, lvi.lParam); + else + nParent = -1; + bDrawAsChild = (pPickerInfo->pCallbacks->pfnGetViewMode() == VIEW_GROUPED && (nParent >= 0)); + + /* only indent if parent is also in this view */ +#if 1 // minimal listview flickering. + if ((nParent >= 0) && bDrawAsChild) + { + if (GetParentFound(lvi.lParam)) + bParentFound = TRUE; + } +#else + if ((nParent >= 0) && bDrawAsChild) + { + for (i = 0; i < ListView_GetItemCount(hWnd); i++) + { + lvi.mask = LVIF_PARAM; + lvi.iItem = i; + res = ListView_GetItem(hWnd, &lvi); + + if (lvi.lParam == nParent) + { + bParentFound = TRUE; + break; + } + } + } +#endif + + if (pPickerInfo->pCallbacks->pfnGetOffsetChildren && pPickerInfo->pCallbacks->pfnGetOffsetChildren()) + { + if (!bParentFound && bDrawAsChild) + { + /*Reset it, as no Parent is there*/ + bDrawAsChild = false; + bColorChild = true; + } + else + { + nParent = -1; + bParentFound = false; + } + } + + res = ListView_GetItemRect_Modified(hWnd, nItem, &rcAllLabels, LVIR_BOUNDS); + res = ListView_GetItemRect_Modified(hWnd, nItem, &rcLabel, LVIR_LABEL); + + rcAllLabels.left = rcLabel.left; + + if (hBackground) + { + RECT rcClient; + HRGN rgnBitmap; + RECT rcTmpBmp = rcItem; + RECT rcFirstItem; + HPALETTE hPAL; + + HDC htempDC = CreateCompatibleDC(hDC); + + HBITMAP oldBitmap = (HBITMAP)SelectObject(htempDC, hBackground); + + GetClientRect(hWnd, &rcClient); + rcTmpBmp.right = rcClient.right; + /* We also need to check whether it is the last item + The update region has to be extended to the bottom if it is */ + if (nItem == ListView_GetItemCount(hWnd) - 1) + rcTmpBmp.bottom = rcClient.bottom; + + rgnBitmap = CreateRectRgnIndirect(&rcTmpBmp); + SelectClipRgn(hDC, rgnBitmap); + DeleteBitmap(rgnBitmap); + + hPAL = GetBackgroundPalette(); + if (hPAL == NULL) + hPAL = CreateHalftonePalette(hDC); + + if (GetDeviceCaps(htempDC, RASTERCAPS) & RC_PALETTE && hPAL != NULL) + { + SelectPalette(htempDC, hPAL, false); + RealizePalette(htempDC); + } + + res = ListView_GetItemRect_Modified(hWnd, 0, &rcFirstItem, LVIR_BOUNDS); + + for (i = rcFirstItem.left; i < rcClient.right; i += pbmDesc->bmWidth) + for (j = rcFirstItem.top; j < rcClient.bottom; j += pbmDesc->bmHeight) + BitBlt(hDC, i, j, pbmDesc->bmWidth, pbmDesc->bmHeight, htempDC, 0, 0, SRCCOPY); + + SelectObject(htempDC, oldBitmap); + DeleteDC(htempDC); + + if (GetBackgroundPalette() == NULL) + { + DeletePalette(hPAL); + hPAL = NULL; + } + } + + indent_space = 0; + + if (bDrawAsChild) + { + RECT rect; + + res = ListView_GetItemRect_Modified(hWnd, nItem, &rect, LVIR_ICON); + + /* indent width of icon + the space between the icon and text + * so left of clone icon starts at text of parent + */ + indent_space = rect.right - rect.left + offset; + } + + rcAllLabels.left += indent_space; + + if (bSelected) + { + HBRUSH hBrush; + HBRUSH hOldBrush; + + if (bFocus) + { + clrTextSave = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + clrBkSave = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT)); + hBrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)); + } + else + { + clrTextSave = SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT)); + clrBkSave = SetBkColor(hDC, GetSysColor(COLOR_BTNFACE)); + hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); + } + + hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); + FillRect(hDC, &rcAllLabels, hBrush); + SelectObject(hDC, hOldBrush); + DeleteBrush(hBrush); + } + else + { + if (hBackground == NULL) + { + HBRUSH hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); + FillRect(hDC, &rcAllLabels, hBrush); + DeleteBrush(hBrush); + } + + if (pPickerInfo->pCallbacks->pfnGetOffsetChildren && pPickerInfo->pCallbacks->pfnGetOffsetChildren()) + { + if (bDrawAsChild || bColorChild) + clrTextSave = SetTextColor(hDC, GetListCloneColor()); + else + clrTextSave = SetTextColor(hDC, GetListFontColor()); + } + else + { + if (bDrawAsChild) + clrTextSave = SetTextColor(hDC, GetListCloneColor()); + else + clrTextSave = SetTextColor(hDC, GetListFontColor()); + } + + clrBkSave = SetBkColor(hDC, GetSysColor(COLOR_WINDOW)); + } + + + if (lvi.state & LVIS_CUT) + { + clrImage = GetSysColor(COLOR_WINDOW); + uiFlags |= ILD_BLEND50; + } + else + if (bSelected) + { + if (bFocus) + clrImage = GetSysColor(COLOR_HIGHLIGHT); + else + clrImage = GetSysColor(COLOR_BTNFACE); + + uiFlags |= ILD_BLEND50; + } + + nStateImageMask = lvi.state & LVIS_STATEIMAGEMASK; + + if (nStateImageMask) + { + int nImage = (nStateImageMask >> 12) - 1; + hImageList = ListView_GetImageList(hWnd, LVSIL_STATE); + if (hImageList) + ImageList_Draw(hImageList, nImage, hDC, rcItem.left, rcItem.top, ILD_TRANSPARENT); + } + + res = ListView_GetItemRect_Modified(hWnd, nItem, &rcIcon, LVIR_ICON); + + rcIcon.left += indent_space; + + res = ListView_GetItemRect_Modified(hWnd, nItem, &rcItem, LVIR_LABEL); + + hImageList = ListView_GetImageList(hWnd, LVSIL_SMALL); + if (hImageList) + { + UINT nOvlImageMask = lvi.state & LVIS_OVERLAYMASK; + if (rcIcon.left + 16 + indent_space < rcItem.right) + ImageList_DrawEx(hImageList, lvi.iImage, hDC, rcIcon.left, rcIcon.top, 16, 16, GetSysColor(COLOR_WINDOW), clrImage, uiFlags | nOvlImageMask); + } + + res = ListView_GetItemRect_Modified(hWnd, nItem, &rcItem, LVIR_LABEL); + + pszText = MakeShortString(hDC, szBuff, rcItem.right - rcItem.left, 2*offset + indent_space); + + rcLabel = rcItem; + rcLabel.left += offset + indent_space; + rcLabel.right -= offset; + + DrawText(hDC, pszText, -1, &rcLabel, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER); + + for (nColumn = 1; nColumn < nColumnMax; nColumn++) + { + int nRetLen; + UINT nJustify; + LV_ITEM lvItem; + + lvc.mask = LVCF_FMT | LVCF_WIDTH; + res = ListView_GetColumn(hWnd, order[nColumn], &lvc); + + lvItem.mask = LVIF_TEXT; + lvItem.iItem = nItem; + lvItem.iSubItem = order[nColumn]; + lvItem.pszText = szBuff; + lvItem.cchTextMax = sizeof(szBuff) / sizeof(szBuff[0]); + + if (ListView_GetItem(hWnd, &lvItem) == false) + continue; + + rcItem.left = rcItem.right; + rcItem.right += lvc.cx; + + nRetLen = _tcslen(szBuff); + if (nRetLen == 0) + continue; + + pszText = MakeShortString(hDC, szBuff, rcItem.right - rcItem.left, 2 * offset); + + nJustify = DT_LEFT; + + if (pszText == szBuff) + { + switch (lvc.fmt & LVCFMT_JUSTIFYMASK) + { + case LVCFMT_RIGHT: + nJustify = DT_RIGHT; + break; + + case LVCFMT_CENTER: + nJustify = DT_CENTER; + break; + + default: + break; + } + } + + rcLabel = rcItem; + rcLabel.left += offset; + rcLabel.right -= offset; + DrawText(hDC, pszText, -1, &rcLabel, nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER); + } + + if (lvi.state & LVIS_FOCUSED && bFocus) + DrawFocusRect(hDC, &rcAllLabels); + + SetTextColor(hDC, clrTextSave); + SetBkColor(hDC, clrBkSave); + free(order); + res++; +} + + + + +const struct PickerCallbacks *Picker_GetCallbacks(HWND hwndPicker) +{ + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hwndPicker); + return pPickerInfo->pCallbacks; +} + + + +int Picker_GetColumnCount(HWND hwndPicker) +{ + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hwndPicker); + return pPickerInfo->nColumnCount; +} + + + +const LPCTSTR *Picker_GetColumnNames(HWND hwndPicker) +{ + struct PickerInfo *pPickerInfo; + pPickerInfo = GetPickerInfo(hwndPicker); + return pPickerInfo->ppszColumnNames; +} + + + +void Picker_SetHeaderImageList(HWND hwndPicker, HIMAGELIST hHeaderImages) +{ + HWND hwndHeader; + hwndHeader = ListView_GetHeader(hwndPicker); + SendMessage(hwndHeader, HDM_SETIMAGELIST, 0, (LPARAM) (void *) hHeaderImages); +} + + + +BOOL Picker_SaveColumnWidths(HWND hwndPicker) +{ + struct PickerInfo *pPickerInfo; + int nColumnMax = 0, i = 0; + BOOL bSuccess = false; + BOOL res = 0; + + pPickerInfo = GetPickerInfo(hwndPicker); + + /* allocate space for the column info */ + int *widths, *order, *tmpOrder; + widths = (int*)malloc(pPickerInfo->nColumnCount * sizeof(*widths)); + order = (int*)malloc(pPickerInfo->nColumnCount * sizeof(*order)); + tmpOrder = (int*)malloc(pPickerInfo->nColumnCount * sizeof(*tmpOrder)); + if (!widths || !order || !tmpOrder) + goto done; + + /* retrieve the values */ + memset(widths, 0, pPickerInfo->nColumnCount * sizeof(*widths)); + memset(order, 0, pPickerInfo->nColumnCount * sizeof(*order)); + pPickerInfo->pCallbacks->pfnGetColumnWidths(widths); + pPickerInfo->pCallbacks->pfnGetColumnOrder(order); + + /* switch the list view to LVS_REPORT style so column widths reported correctly */ + SetWindowLong(hwndPicker, GWL_STYLE, (GetWindowLong(hwndPicker, GWL_STYLE) & ~LVS_TYPEMASK) | LVS_REPORT); + + nColumnMax = Picker_GetNumColumns(hwndPicker); + + if (GetUseOldControl()) + for (i = 0; i < nColumnMax; i++) + widths[Picker_GetRealColumnFromViewColumn(hwndPicker, i)] = ListView_GetColumnWidth(hwndPicker, i); + else + { + /* Get the Column Order and save it */ + res = ListView_GetColumnOrderArray(hwndPicker, nColumnMax, tmpOrder); + + for (i = 0; i < nColumnMax; i++) + { + widths[Picker_GetRealColumnFromViewColumn(hwndPicker, i)] = ListView_GetColumnWidth(hwndPicker, i); + order[i] = Picker_GetRealColumnFromViewColumn(hwndPicker, tmpOrder[i]); + } + } + + pPickerInfo->pCallbacks->pfnSetColumnWidths(widths); + pPickerInfo->pCallbacks->pfnSetColumnOrder(order); + bSuccess = true; + +done: + if (widths) + free(widths); + if (order) + free(order); + if (tmpOrder) + free(tmpOrder); + res++; + return bSuccess; +} |