home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / Dita / source / w32listview.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  10.6 KB  |  406 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2004 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <stdafx.h>
  19. #include <vd2/system/w32assist.h>
  20. #include <vd2/system/vdstl.h>
  21. #include <windows.h>
  22. #include <commctrl.h>
  23. #include <vector>
  24.  
  25. #include <vd2/Dita/w32control.h>
  26.  
  27. #ifdef _MSC_VER
  28.     #pragma comment(lib, "comctl32")
  29. #endif
  30.  
  31. class VDUIListViewW32 : public VDUIControlW32, public IVDUIListView, public IVDUIList {
  32. public:
  33.     VDUIListViewW32();
  34.  
  35.     void *AsInterface(uint32 id);
  36.  
  37.     bool Create(IVDUIParameters *);
  38.     void PreLayoutBaseW32(const VDUILayoutSpecs&);
  39.  
  40.     int GetValue();
  41.     void SetValue(int);
  42.  
  43. protected:
  44.     void Clear();
  45.     int GetItemCount();
  46.     uintptr GetItemData(int index);
  47.     void SetItemData(int index, uintptr value);
  48.     int AddItem(const wchar_t *text, uintptr data);
  49.  
  50.     void SetListCallback(IVDUIListCallback *cb);
  51.     void SetItemText(int item, int subitem, const wchar_t *text);
  52.     void AddColumn(const wchar_t *name, int width, int affinity);
  53.     void SetItemChecked(int item, bool checked);
  54.     bool IsItemChecked(int item);
  55.     void OnNotifyCallback(const NMHDR *);
  56.     void OnResize();
  57.  
  58.     struct Column {
  59.         int mWidth;
  60.         int mAffinity;
  61.     };
  62.  
  63.     int mSelected;
  64.     int        mTotalAffinity;
  65.     int        mTotalWidth;
  66.     bool    mbCheckable;
  67.     vdfastvector<Column>    mColumns;
  68.  
  69.     IVDUIListCallback *mpListCB;
  70.  
  71.     // Temporary storage for strings that have been returned to the list view. We must
  72.     // triple buffer these according to the docs for NMLVDISPINFO.
  73.     int mListTextIndex;
  74.     VDStringW    mListTextW[3];
  75.     VDStringA    mListTextA[3];
  76. };
  77.  
  78. extern IVDUIWindow *VDCreateUIListView() { return new VDUIListViewW32; }
  79.  
  80. VDUIListViewW32::VDUIListViewW32()
  81.     : mSelected(-1)
  82.     , mTotalAffinity(0)
  83.     , mTotalWidth(0)
  84.     , mpListCB(NULL)
  85.     , mListTextIndex(0)
  86. {
  87.     InitCommonControls();
  88. }
  89.  
  90. void *VDUIListViewW32::AsInterface(uint32 id) {
  91.     if (id == IVDUIListView::kTypeID) return static_cast<IVDUIListView *>(this);
  92.     if (id == IVDUIList::kTypeID) return static_cast<IVDUIList *>(this);
  93.  
  94.     return VDUIControlW32::AsInterface(id);
  95. }
  96.  
  97. bool VDUIListViewW32::Create(IVDUIParameters *pParameters) {
  98.     mbCheckable = pParameters->GetB(nsVDUI::kUIParam_Checkable, false);
  99.  
  100.     DWORD dwFlags = LVS_REPORT | WS_TABSTOP;
  101.  
  102.     if (pParameters->GetB(nsVDUI::kUIParam_NoHeader, false))
  103.         dwFlags |= LVS_NOCOLUMNHEADER;
  104.  
  105.     if (!CreateW32(pParameters, WC_LISTVIEW, dwFlags))
  106.         return false;
  107.  
  108.     ListView_SetExtendedListViewStyle(mhwnd, LVS_EX_FULLROWSELECT | ListView_GetExtendedListViewStyle(mhwnd));
  109.  
  110.     if (mbCheckable) {
  111.         const int cx = GetSystemMetrics(SM_CXMENUCHECK);
  112.         const int cy = GetSystemMetrics(SM_CYMENUCHECK);
  113.  
  114.         if (HBITMAP hbm = CreateBitmap(cx, cy, 1, 1, NULL)) {
  115.             if (HDC hdc = CreateCompatibleDC(NULL)) {
  116.                 if (HGDIOBJ hbmOld = SelectObject(hdc, hbm)) {
  117.                     bool success = false;
  118.  
  119.                     RECT r = { 0, 0, cx, cy };
  120.  
  121.                     SetBkColor(hdc, PALETTEINDEX(0));
  122.                     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &r, "", 0, NULL);
  123.                     DrawFrameControl(hdc, &r, DFC_BUTTON, DFCS_BUTTONCHECK|DFCS_CHECKED);
  124.  
  125.                     SelectObject(hdc, hbmOld);
  126.  
  127.                     if (HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR, 1, 1)) {
  128.                         if (ImageList_Add(himl, hbm, NULL) >= 0)
  129.                             ListView_SetImageList(mhwnd, himl, LVSIL_STATE);
  130.                         else
  131.                             ImageList_Destroy(himl);
  132.                     }
  133.                 }
  134.  
  135.                 DeleteDC(hdc);
  136.             }
  137.  
  138.             DeleteObject(hbm);
  139.         }
  140.     }
  141.  
  142.     return true;
  143. }
  144.  
  145. void VDUIListViewW32::PreLayoutBaseW32(const VDUILayoutSpecs& parentConstraints) {
  146. }
  147.  
  148. int VDUIListViewW32::GetValue() {
  149.     return mSelected;
  150. }
  151.  
  152. void VDUIListViewW32::SetValue(int value) {
  153.     if (mSelected != value) {
  154.         mSelected = value;        // prevents recursion
  155.  
  156.         if (value >= 0)
  157.             ListView_SetItemState(mhwnd, value, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
  158.     }
  159. }
  160.  
  161. void VDUIListViewW32::Clear() {
  162.     ListView_DeleteAllItems(mhwnd);
  163. }
  164.  
  165. int VDUIListViewW32::GetItemCount() {
  166.     return (int)ListView_GetItemCount(mhwnd);
  167. }
  168.  
  169. uintptr VDUIListViewW32::GetItemData(int index) {
  170.     LVITEMA lvia={0};
  171.     lvia.mask        = LVIF_PARAM;
  172.     lvia.iItem        = index;
  173.     lvia.iSubItem    = 0;
  174.  
  175.     if (ListView_GetItem(mhwnd, &lvia))
  176.         return lvia.lParam;
  177.  
  178.     return 0;
  179. }
  180.  
  181. void VDUIListViewW32::SetItemData(int index, uintptr value) {
  182.     LVITEMA lvia={0};
  183.     lvia.mask        = LVIF_PARAM;
  184.     lvia.iItem        = index;
  185.     lvia.iSubItem    = 0;
  186.     lvia.lParam        = (LPARAM)value;
  187.  
  188.     ListView_SetItem(mhwnd, &lvia);
  189. }
  190.  
  191. int VDUIListViewW32::AddItem(const wchar_t *text, uintptr data) {
  192.     DWORD dwMask = LVIF_PARAM | LVIF_TEXT;
  193.  
  194.     if (mbCheckable)
  195.         dwMask |= LVIF_STATE;
  196.  
  197.     int item;
  198.     if (VDIsWindowsNT()) {
  199.         LVITEMW lviw={0};
  200.  
  201.         lviw.mask        = dwMask;
  202.         lviw.iItem        = 0x1FFFFFFF;
  203.         lviw.iSubItem    = 0;
  204.         lviw.state        = 0x1000;
  205.         lviw.stateMask    = (UINT)-1;
  206.         lviw.pszText    = (LPWSTR)text;
  207.         lviw.lParam        = (LPARAM)data;
  208.  
  209.         item = (int)SendMessageW(mhwnd, LVM_INSERTITEMW, 0, (LPARAM)&lviw);
  210.     } else {
  211.         LVITEMA lvia={0};
  212.  
  213.         VDStringA textA(VDTextWToA(text));
  214.  
  215.         lvia.mask        = dwMask;
  216.         lvia.iItem        = 0x1FFFFFFF;
  217.         lvia.iSubItem    = 0;
  218.         lvia.state        = 0x1000;
  219.         lvia.stateMask    = (UINT)-1;
  220.         lvia.pszText    = (LPSTR)textA.c_str();
  221.         lvia.lParam        = (LPARAM)data;
  222.  
  223.         item = (int)SendMessageA(mhwnd, LVM_INSERTITEMA, 0, (LPARAM)&lvia);
  224.     }
  225.  
  226.     return item;
  227. }
  228.  
  229. void VDUIListViewW32::SetListCallback(IVDUIListCallback *cb) {
  230.     mpListCB = cb;
  231. }
  232.  
  233. void VDUIListViewW32::SetItemText(int item, int subitem, const wchar_t *text) {
  234.     DWORD dwMask = LVIF_TEXT;
  235.  
  236.     if (VDIsWindowsNT()) {
  237.         LVITEMW lviw={0};
  238.  
  239.         lviw.mask        = dwMask;
  240.         lviw.iItem        = item;
  241.         lviw.iSubItem    = subitem;
  242.         lviw.pszText    = (LPWSTR)text;
  243.  
  244.         SendMessageW(mhwnd, LVM_SETITEMTEXTW, (WPARAM)item, (LPARAM)&lviw);
  245.     } else {
  246.         LVITEMA lvia={0};
  247.  
  248.         VDStringA textA(VDTextWToA(text));
  249.  
  250.         lvia.mask        = dwMask;
  251.         lvia.iItem        = item;
  252.         lvia.iSubItem    = subitem;
  253.         lvia.pszText    = (LPSTR)textA.c_str();
  254.  
  255.         SendMessageA(mhwnd, LVM_SETITEMTEXTA, (WPARAM)item, (LPARAM)&lvia);
  256.     }
  257. }
  258.  
  259. void VDUIListViewW32::AddColumn(const wchar_t *name, int width, int affinity) {
  260.     VDASSERT(affinity >= 0);
  261.     VDASSERT(width >= 0);
  262.  
  263.     if (VDIsWindowsNT()) {
  264.         LVCOLUMNW lvcw={0};
  265.  
  266.         lvcw.mask        = LVCF_TEXT | LVCF_WIDTH;
  267.         lvcw.pszText    = (LPWSTR)name;
  268.         lvcw.cx            = width;
  269.  
  270.         SendMessageW(mhwnd, LVM_INSERTCOLUMNW, mColumns.size(), (LPARAM)&lvcw);
  271.     } else {
  272.         LVCOLUMNA lvca={0};
  273.         VDStringA nameA(VDTextWToA(name));
  274.  
  275.         lvca.mask        = LVCF_TEXT | LVCF_WIDTH;
  276.         lvca.pszText    = (LPSTR)nameA.c_str();
  277.         lvca.cx            = width;
  278.  
  279.         SendMessageA(mhwnd, LVM_INSERTCOLUMNA, mColumns.size(), (LPARAM)&lvca);
  280.     }
  281.  
  282.     mColumns.push_back(Column());
  283.     Column& col = mColumns.back();
  284.  
  285.     col.mWidth        = width;
  286.     col.mAffinity    = affinity;
  287.  
  288.     mTotalWidth        += width;
  289.     mTotalAffinity    += affinity;
  290.  
  291.     OnResize();
  292. }
  293.  
  294. void VDUIListViewW32::SetItemChecked(int item, bool checked) {
  295.     ListView_SetItemState(mhwnd, item, checked ? INDEXTOSTATEIMAGEMASK(1) : 0, LVIS_STATEIMAGEMASK);
  296.     ListView_RedrawItems(mhwnd, item, item);
  297. }
  298.  
  299. bool VDUIListViewW32::IsItemChecked(int item) {
  300.     UINT oldState = ListView_GetItemState(mhwnd, item, -1);
  301.  
  302.     return 0 != (oldState & 0x1000);
  303. }
  304.  
  305. void VDUIListViewW32::OnNotifyCallback(const NMHDR *pHdr) {
  306.        if (pHdr->code == LVN_ITEMCHANGED) {
  307.            const NMLISTVIEW *plvn = (const NMLISTVIEW *)pHdr;
  308.    
  309.            if ((plvn->uOldState|plvn->uNewState) & LVIS_SELECTED) {
  310.                int iSel = (int)SendMessage(mhwnd, LVM_GETNEXTITEM, -1, LVNI_ALL|LVNI_SELECTED);
  311.    
  312.                if (iSel != mSelected) {
  313.                    mSelected = iSel;
  314.    
  315.                 mpBase->ProcessValueChange(this, mID);
  316.                    mpBase->DispatchEvent(this, mID, IVDUICallback::kEventSelect, mSelected);
  317.                }
  318.            }
  319.     } else if (pHdr->code == LVN_GETDISPINFO) {
  320.         NMLVDISPINFOA& lvdi = *(NMLVDISPINFOA *)pHdr;
  321.         LVITEMA& lvi = lvdi.item;
  322.  
  323.         VDASSERTCT(sizeof(NMLVDISPINFOW) == sizeof(NMLVDISPINFOA));
  324.  
  325.         if (mpListCB && (lvi.mask & LVIF_TEXT)) {
  326.             if (mpListCB->GetListText(lvi.iItem, lvi.iSubItem, mListTextW[mListTextIndex])) {
  327.                 if (VDIsWindowsNT()) {
  328.                     NMLVDISPINFOW& lvdiw = *(NMLVDISPINFOW *)pHdr;
  329.                     LVITEMW& lviw = lvdiw.item;
  330.  
  331.                     lviw.pszText = const_cast<WCHAR *>(mListTextW[mListTextIndex].c_str());
  332.                 } else {
  333.                     mListTextA[mListTextIndex] = VDTextWToA(mListTextW[mListTextIndex]);
  334.  
  335.                     lvi.pszText = const_cast<CHAR *>(mListTextA[mListTextIndex].c_str());
  336.                 }
  337.  
  338.                 if (++mListTextIndex >= 3)
  339.                     mListTextIndex = 0;
  340.             }
  341.         }
  342.     } else if (mbCheckable) {
  343.         if (pHdr->code == LVN_KEYDOWN && ((const NMLVKEYDOWN *)pHdr)->wVKey == VK_SPACE) {
  344.             int idx = -1;
  345.             bool first = true;
  346.             bool select = false;
  347.  
  348.             while((idx = ListView_GetNextItem(mhwnd, idx, LVNI_SELECTED)) >= 0) {
  349.                 if (first) {
  350.                     UINT oldState = ListView_GetItemState(mhwnd, idx, -1);
  351.  
  352.                     select = !(oldState & INDEXTOSTATEIMAGEMASK(1));
  353.                     first = false;
  354.                 }
  355.  
  356.                 ListView_SetItemState(mhwnd, idx, select ? INDEXTOSTATEIMAGEMASK(1) : 0, LVIS_STATEIMAGEMASK);
  357.                 ListView_RedrawItems(mhwnd, idx, idx);
  358.             }
  359.         } else if (pHdr->code == NM_CLICK || pHdr->code == NM_DBLCLK) {
  360.              DWORD pos = GetMessagePos();
  361.  
  362.             LVHITTESTINFO lvhi = {0};
  363.  
  364.             lvhi.pt.x = (SHORT)LOWORD(pos);
  365.             lvhi.pt.y = (SHORT)HIWORD(pos);
  366.  
  367.             ScreenToClient(mhwnd, &lvhi.pt);
  368.  
  369.             int idx = ListView_HitTest(mhwnd, &lvhi);
  370.  
  371.             if (idx >= 0) {
  372.                 UINT oldState = ListView_GetItemState(mhwnd, idx, -1);
  373.  
  374.                 ListView_SetItemState(mhwnd, idx, oldState ^ INDEXTOSTATEIMAGEMASK(1), LVIS_STATEIMAGEMASK);
  375.                 ListView_RedrawItems(mhwnd, idx, idx);
  376.             }
  377.         }
  378.     }
  379. }
  380.  
  381. void VDUIListViewW32::OnResize() {
  382.     const int ncols = mColumns.size();
  383.     const Column *pcol = mColumns.data();
  384.     RECT r;
  385.  
  386.     GetClientRect(mhwnd, &r);
  387.  
  388.     int spaceLeft = r.right - mTotalWidth;
  389.     int affinityLeft = mTotalAffinity;
  390.  
  391.     for(int i=0; i<ncols; ++i) {
  392.         const Column& col = *pcol++;
  393.         int width = col.mWidth;
  394.  
  395.         if (affinityLeft && col.mAffinity) {
  396.             int extra = (spaceLeft * col.mAffinity + affinityLeft - 1) / affinityLeft;
  397.  
  398.             affinityLeft -= col.mAffinity;
  399.             spaceLeft -= extra;
  400.             width += extra;
  401.         }    
  402.  
  403.         SendMessageA(mhwnd, LVM_SETCOLUMNWIDTH, i, MAKELPARAM((int)width, 0));
  404.     }
  405. }
  406.