Example #1
0
void CVideoMarkup::EmptyTrash() {

    // delete all the samples in the "trash" group
    int iItem = ListView_GetNextItem(m_sampleListView, -1, LVNI_ALL);
    while (iItem != -1) {
        LVITEM lvi;
        lvi.mask = LVIF_IMAGE | LVIF_STATE | LVIF_GROUPID;
        lvi.state = 0;
        lvi.stateMask = 0;
        lvi.iItem = iItem;
        lvi.iSubItem = 0;
        ListView_GetItem(m_sampleListView, &lvi);

        int iNextItem = ListView_GetNextItem(m_sampleListView, iItem, LVNI_ALL);
        if (lvi.iGroupId == GROUPID_TRASH) {

            // remove this sample from the listview
            UINT sampleIdToDelete = ListView_MapIndexToID(m_sampleListView, iItem);
            ListView_DeleteItem(m_sampleListView, iItem);

            // update sample in training set too
            sampleSet.RemoveSample(sampleIdToDelete);

            // indices have changed so we need to start at the beginning of the list again
            iNextItem = ListView_GetNextItem(m_sampleListView, -1, LVNI_ALL);
        }
        iItem = iNextItem;
    }
}
Example #2
0
// Constructor for motion training sample (includes motion history image)
TrainingSample::TrainingSample(IplImage* srcImage, IplImage* motionHist, HWND lc, HIMAGELIST il, Rect bounds, int groupId) {
	// this constructor should only be called for motion sample type
	assert(groupId == GROUPID_MOTIONSAMPLES);

	hwndListControl = lc;
    hImageList = il;
    iGroupId = groupId;
	iOrigId = groupId;
	selectBounds = bounds;
    motionTrack.clear();

    fullImageCopy = cvCreateImage(cvSize(bounds.Width,bounds.Height),IPL_DEPTH_8U, 3); 
    motionHistory = cvCreateImage(cvSize(motionHist->width,motionHist->height),IPL_DEPTH_32F, 1);
	resizedImage = cvCreateImage(cvSize(LISTVIEW_SAMPLE_X,LISTVIEW_SAMPLE_Y),IPL_DEPTH_8U, 3); 
    bmpImage = new Bitmap(LISTVIEW_SAMPLE_X, LISTVIEW_SAMPLE_Y, PixelFormat24bppRGB);

    cvSetImageROI(srcImage, cvRect( bounds.X, bounds.Y, bounds.Width, bounds.Height));
    cvCopyImage(srcImage, fullImageCopy);

    if (srcImage->width >= LISTVIEW_SAMPLE_X && srcImage->height >= LISTVIEW_SAMPLE_Y) {
        cvResize(srcImage, resizedImage, CV_INTER_AREA);
    } else { 
        cvResize(srcImage, resizedImage, CV_INTER_LINEAR);
    }
    cvResetImageROI(srcImage);

	// copy entire frame motion history image (motion history analysis doesn't work as well on partial frame)
	cvCopyImage(motionHist, motionHistory);

    IplToBitmap(resizedImage, bmpImage);
    bmpImage->GetHBITMAP(NULL, &hbmImage);

    // Add image to imagelist
    int imgIndex = ImageList_Add(hImageList, hbmImage, NULL);

    // Add item to list view
    lvi.mask = LVIF_IMAGE | LVIF_STATE | LVIF_GROUPID;
    lvi.state = 0;
    lvi.stateMask = 0;
    lvi.iGroupId = groupId;
    lvi.iItem = imgIndex;
    lvi.iImage = imgIndex;
    lvi.iSubItem = 0;
    int newListItemPos = ListView_InsertItem(hwndListControl, &lvi);

    id = ListView_MapIndexToID(hwndListControl, newListItemPos);
}
Example #3
0
// Constructor for loading sample from image file
TrainingSample::TrainingSample(char *filename, HWND lc, HIMAGELIST il, int groupId) {
	// this constructor should only be called for positive and negative sample types
	assert((groupId == GROUPID_POSSAMPLES) || (groupId == GROUPID_NEGSAMPLES));
	
	hwndListControl = lc;
    hImageList = il;
    iGroupId = groupId;
	iOrigId = groupId;
    motionTrack.clear();
	motionHistory = NULL;

    fullImageCopy = cvLoadImage(filename, 1);
    if (fullImageCopy == NULL) {
        fullImageCopy = cvCreateImage(cvSize(LISTVIEW_SAMPLE_X,LISTVIEW_SAMPLE_Y),IPL_DEPTH_8U, 3);
        cvZero(fullImageCopy);
    }

    resizedImage = cvCreateImage(cvSize(LISTVIEW_SAMPLE_X,LISTVIEW_SAMPLE_Y),IPL_DEPTH_8U, 3); 
    bmpImage = new Bitmap(LISTVIEW_SAMPLE_X, LISTVIEW_SAMPLE_Y, PixelFormat24bppRGB);

    if (fullImageCopy->width >= LISTVIEW_SAMPLE_X && fullImageCopy->height >= LISTVIEW_SAMPLE_Y) {
        cvResize(fullImageCopy, resizedImage, CV_INTER_AREA);
    } else { 
        cvResize(fullImageCopy, resizedImage, CV_INTER_LINEAR);
    }

    IplToBitmap(resizedImage, bmpImage);
    bmpImage->GetHBITMAP(NULL, &hbmImage);

    // Add image to imagelist
    int imgIndex = ImageList_Add(hImageList, hbmImage, NULL);

    // Add item to list view
    lvi.mask = LVIF_IMAGE | LVIF_STATE | LVIF_GROUPID;
    lvi.state = 0;
    lvi.stateMask = 0;
    lvi.iGroupId = groupId;
    lvi.iItem = imgIndex;
    lvi.iImage = imgIndex;
    lvi.iSubItem = 0;
    int newListItemPos = ListView_InsertItem(hwndListControl, &lvi);

    id = ListView_MapIndexToID(hwndListControl, newListItemPos);
}
Example #4
0
// Constructor for range sample (includes motion track)
TrainingSample::TrainingSample(IplImage *frame, MotionTrack mt, HWND lc, HIMAGELIST il, int groupId) {
	// this constructor should only be called for range sample type
	assert(groupId == GROUPID_RANGESAMPLES);

	hwndListControl = lc;
    hImageList = il;
    iGroupId = groupId;
	iOrigId = groupId;
    motionTrack = mt;
    motionHistory = NULL;

    fullImageCopy = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U, 3);
    cvZero(fullImageCopy);
    cvAddWeighted(frame, 0.5, fullImageCopy, 0.5, 0.0, fullImageCopy);
    
    // draw the trajectory in the sample image
	Template t("", mt);
    DrawTrack(fullImageCopy, t.m_points, CV_RGB(100,255,100), 3, GESTURE_SQUARE_SIZE);

    resizedImage = cvCreateImage(cvSize(LISTVIEW_SAMPLE_X,LISTVIEW_SAMPLE_Y),IPL_DEPTH_8U, 3); 
    bmpImage = new Bitmap(LISTVIEW_SAMPLE_X, LISTVIEW_SAMPLE_Y, PixelFormat24bppRGB);

    cvResize(fullImageCopy, resizedImage, CV_INTER_AREA);

    IplToBitmap(resizedImage, bmpImage);
    bmpImage->GetHBITMAP(NULL, &hbmImage);

    // Add image to imagelist
    int imgIndex = ImageList_Add(hImageList, hbmImage, NULL);

    // Add item to list view
    lvi.mask = LVIF_IMAGE | LVIF_STATE | LVIF_GROUPID;
    lvi.state = 0;
    lvi.stateMask = 0;
    lvi.iGroupId = groupId;
    lvi.iItem = imgIndex;
    lvi.iImage = imgIndex;
    lvi.iSubItem = 0;
    int newListItemPos = ListView_InsertItem(hwndListControl, &lvi);

    id = ListView_MapIndexToID(hwndListControl, newListItemPos);
}
Example #5
0
LRESULT CVideoMarkup::OnButtonUp( UINT, WPARAM, LPARAM lParam, BOOL&)
{
    POINT p;
    p.x = LOWORD(lParam);
    p.y = HIWORD(lParam);

    if (draggingIcon) { // we just completed an icon drag
        // End the drag-and-drop process
        draggingIcon = FALSE;
        ImageList_DragLeave(m_sampleListView);
        ImageList_EndDrag();
        ImageList_Destroy(hDragImageList);
        SetCursor(LoadCursor(NULL, IDC_ARROW));
        ReleaseCapture();

        // Determine the position of the drop point
        LVHITTESTINFO lvhti;
        lvhti.pt = p;
        ClientToScreen(&lvhti.pt);
        ::ScreenToClient(m_sampleListView, &lvhti.pt);
        ListView_HitTestEx(m_sampleListView, &lvhti);
        CRect posRect, negRect, motionRect, rangeRect;
        ListView_GetGroupRect(m_sampleListView, GROUPID_POSSAMPLES, LVGGR_GROUP, &posRect);
        ListView_GetGroupRect(m_sampleListView, GROUPID_NEGSAMPLES, LVGGR_GROUP, &negRect);
        ListView_GetGroupRect(m_sampleListView, GROUPID_MOTIONSAMPLES, LVGGR_GROUP, &motionRect);
        ListView_GetGroupRect(m_sampleListView, GROUPID_RANGESAMPLES, LVGGR_GROUP, &rangeRect);

        int newGroupId;
        if (posRect.PtInRect(lvhti.pt)) newGroupId = GROUPID_POSSAMPLES;
        else if (negRect.PtInRect(lvhti.pt)) newGroupId = GROUPID_NEGSAMPLES;
        else if (motionRect.PtInRect(lvhti.pt)) newGroupId = GROUPID_MOTIONSAMPLES;
        else if (rangeRect.PtInRect(lvhti.pt)) newGroupId = GROUPID_RANGESAMPLES;
        else newGroupId = GROUPID_TRASH;

        // update group membership of selected items based on drop location
        int numSelected = ListView_GetSelectedCount(m_sampleListView);
        int iSelection = -1;
        for (int iIndex=0; iIndex<numSelected; iIndex++) {

            // retrieve the selected item 
            LVITEM lvi;
            iSelection = ListView_GetNextItem(m_sampleListView, iSelection, LVNI_SELECTED);
            lvi.mask = LVIF_IMAGE | LVIF_STATE | LVIF_GROUPID;
            lvi.state = 0;
            lvi.stateMask = 0;
            lvi.iItem = iSelection;
            lvi.iSubItem = 0;
            ListView_GetItem(m_sampleListView, &lvi);

			// Get the ID of this selected item
            UINT sampleId = ListView_MapIndexToID(m_sampleListView, iSelection);

			// test if this is an allowable group membership change
			int origGroupId = sampleSet.GetOriginalSampleGroup(sampleId);
			if (!GroupTransitionIsAllowed(origGroupId, newGroupId)) {
				// this is not a valid change so we'll move to the next item
				continue;
			}

            // update sample group in training set
            sampleSet.SetSampleGroup(sampleId, newGroupId);

            // Update item in list view with new group id
			lvi.iGroupId = newGroupId;
            ListView_SetItem(m_sampleListView, &lvi);
        }
        m_sampleListView.Invalidate(FALSE);

    } else if (m_videoLoader.videoLoaded && selectingRegion) { // we just finished drawing a selection
        ClipCursor(NULL);   // restore full cursor movement
        if (!m_videoRect.PtInRect(p)) {
            InvalidateRect(&m_videoRect,FALSE);
            return 0;
        }
        selectingRegion = false;

        Rect selectRect;
        selectRect.X = (INT) min(selectStart.X, selectCurrent.X);
        selectRect.Y = (INT) min(selectStart.Y, selectCurrent.Y);
        selectRect.Width = (INT) abs(selectStart.X - selectCurrent.X);
        selectRect.Height = (INT) abs(selectStart.Y - selectCurrent.Y);

        Rect drawBounds(0,0,VIDEO_X,VIDEO_Y);
        selectRect.Intersect(drawBounds);
        double scaleX = ((double)m_videoLoader.videoX) / ((double)VIDEO_X);
        double scaleY = ((double)m_videoLoader.videoY) / ((double)VIDEO_Y);
        selectRect.X = (INT) (scaleX * selectRect.X);
        selectRect.Y = (INT) (scaleY * selectRect.Y);
        selectRect.Width = (INT) (scaleX * selectRect.Width);
        selectRect.Height = (INT) (scaleY * selectRect.Height);

        // discard tiny samples since they won't help
        if ((selectRect.Width > 10) && (selectRect.Height > 10)) {
			TrainingSample *sample;
			// if we're in motion mode, the behavior is a little special
			if (recognizerMode == MOTION_FILTER) {
				sample = new TrainingSample(m_videoLoader.copyFrame, m_videoLoader.GetMotionHistory(), m_sampleListView, m_hImageList, selectRect, GROUPID_MOTIONSAMPLES);
			} else {
				sample = new TrainingSample(m_videoLoader.copyFrame, m_sampleListView, m_hImageList, selectRect, currentGroupId);
			}
            sampleSet.AddSample(sample);
        }
        InvalidateRect(&m_videoRect, FALSE);
    }
	return 0;
}
Example #6
0
LRESULT CALLBACK PhpExtendedListViewWndProc(
    __in HWND hwnd,
    __in UINT uMsg,
    __in WPARAM wParam,
    __in LPARAM lParam
    )
{
    PPH_EXTLV_CONTEXT context;
    WNDPROC oldWndProc;

    context = (PPH_EXTLV_CONTEXT)GetProp(hwnd, PhpMakeExtLvContextAtom());
    oldWndProc = context->OldWndProc;

    switch (uMsg)
    {
    case WM_DESTROY:
        {
            SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc);

            if (context->TickHashtable)
                PhDereferenceObject(context->TickHashtable);

            PhFree(context);
            RemoveProp(hwnd, PhpMakeExtLvContextAtom());
        }
        break;
    case WM_NOTIFY:
        {
            LPNMHDR header = (LPNMHDR)lParam;

            switch (header->code)
            {
            case HDN_ITEMCLICK:
                {
                    HWND headerHandle;

                    headerHandle = (HWND)CallWindowProc(context->OldWndProc, hwnd, LVM_GETHEADER, 0, 0);

                    if (header->hwndFrom == headerHandle)
                    {
                        LPNMHEADER header2 = (LPNMHEADER)header;

                        if (header2->iItem == context->SortColumn)
                        {
                            if (context->TriState)
                            {
                                if (context->SortOrder == AscendingSortOrder)
                                    context->SortOrder = DescendingSortOrder;
                                else if (context->SortOrder == DescendingSortOrder)
                                    context->SortOrder = NoSortOrder;
                                else
                                    context->SortOrder = AscendingSortOrder;
                            }
                            else
                            {
                                if (context->SortOrder == AscendingSortOrder)
                                    context->SortOrder = DescendingSortOrder;
                                else
                                    context->SortOrder = AscendingSortOrder;
                            }
                        }
                        else
                        {
                            context->SortColumn = header2->iItem;
                            context->SortOrder = AscendingSortOrder;
                        }

                        PhSetHeaderSortIcon(headerHandle, context->SortColumn, context->SortOrder);
                        ExtendedListView_SortItems(hwnd);
                    }
                }
                break;
            }
        }
        break;
    case WM_REFLECT + WM_NOTIFY:
        {
            LPNMHDR header = (LPNMHDR)lParam;

            switch (header->code)
            {
            case NM_CUSTOMDRAW:
                {
                    if (header->hwndFrom == hwnd)
                    {
                        LPNMLVCUSTOMDRAW customDraw = (LPNMLVCUSTOMDRAW)header;

                        switch (customDraw->nmcd.dwDrawStage)
                        {
                        case CDDS_PREPAINT:
                            return CDRF_NOTIFYITEMDRAW;
                        case CDDS_ITEMPREPAINT:
                            {
                                LVITEM item;
                                PH_ITEM_STATE itemState;
                                BOOLEAN colorChanged = FALSE;
                                HFONT newFont = NULL;

                                item.mask = LVIF_STATE;
                                item.iItem = (INT)customDraw->nmcd.dwItemSpec;
                                item.iSubItem = 0;
                                item.stateMask = LVIS_STATEIMAGEMASK;
                                CallWindowProc(oldWndProc, hwnd, LVM_GETITEM, 0, (LPARAM)&item);
                                itemState = PH_GET_ITEM_STATE(item.state);

                                if (!context->EnableState || itemState == NormalItemState)
                                {
                                    if (context->ItemColorFunction)
                                    {
                                        customDraw->clrTextBk = context->ItemColorFunction(
                                            (INT)customDraw->nmcd.dwItemSpec,
                                            (PVOID)customDraw->nmcd.lItemlParam,
                                            context->Context
                                            );
                                        colorChanged = TRUE;
                                    }

                                    if (context->ItemFontFunction)
                                    {
                                        newFont = context->ItemFontFunction(
                                            (INT)customDraw->nmcd.dwItemSpec,
                                            (PVOID)customDraw->nmcd.lItemlParam,
                                            context->Context
                                            );
                                    }

                                    if (newFont)
                                        SelectObject(customDraw->nmcd.hdc, newFont);
                                }
                                else if (itemState == NewItemState)
                                {
                                    customDraw->clrTextBk = context->NewColor;
                                    colorChanged = TRUE;
                                }
                                else if (itemState == RemovingItemState)
                                {
                                    customDraw->clrTextBk = context->RemovingColor;
                                    colorChanged = TRUE;
                                }

                                if (colorChanged)
                                {
                                    if (PhGetColorBrightness(customDraw->clrTextBk) > 100) // slightly less than half
                                        customDraw->clrText = RGB(0x00, 0x00, 0x00);
                                    else
                                        customDraw->clrText = RGB(0xff, 0xff, 0xff);
                                }

                                if (!newFont)
                                    return CDRF_DODEFAULT;
                                else
                                    return CDRF_NEWFONT;
                            }
                            break;
                        }
                    }
                }
                break;
            }
        }
        break;
    case WM_SETCURSOR:
        {
            if (context->Cursor)
            {
                SetCursor(context->Cursor);
                return TRUE;
            }
        }
        break;
    case WM_UPDATEUISTATE:
        {
            // Disable focus rectangles by setting or masking out the flag where appropriate.
            switch (LOWORD(wParam))
            {
            case UIS_SET:
                wParam |= UISF_HIDEFOCUS << 16;
                break;
            case UIS_CLEAR:
            case UIS_INITIALIZE:
                wParam &= ~(UISF_HIDEFOCUS << 16);
                break;
            }
        }
        break;
    case LVM_INSERTITEM:
        {
            LPLVITEM item = (LPLVITEM)lParam;
            INT index;

            if (!context->EnableState)
                break; // pass through

            if (!(item->mask & LVIF_STATE))
            {
                item->mask |= LVIF_STATE;
                item->stateMask = LVIS_STATEIMAGEMASK;
                item->state = 0;
            }
            else
            {
                item->stateMask |= LVIS_STATEIMAGEMASK;
                item->state &= ~LVIS_STATEIMAGEMASK;
            }

            if (context->EnableStateHighlighting > 0)
            {
                item->state |= INDEXTOSTATEIMAGEMASK(NewItemState);
            }
            else
            {
                item->state = NormalItemState;
            }

            if ((index = (INT)CallWindowProc(oldWndProc, hwnd, LVM_INSERTITEM, 0, (LPARAM)item)) == -1)
                return -1;

            if (context->EnableStateHighlighting > 0)
            {
                PH_TICK_ENTRY entry;

                PhpEnsureTickHashtableCreated(context);

                entry.Id = ListView_MapIndexToID(hwnd, index);
                entry.TickCount = GetTickCount();

                PhAddEntryHashtable(context->TickHashtable, &entry);
            }

            return index;
        }
    case LVM_DELETEITEM:
        {
            if (!context->EnableState)
                break; // pass through

            if (context->EnableStateHighlighting > 0)
            {
                LVITEM item;

                item.mask = LVIF_STATE | LVIF_PARAM;
                item.iItem = (INT)wParam;
                item.iSubItem = 0;
                item.stateMask = LVIS_STATEIMAGEMASK;
                item.state = INDEXTOSTATEIMAGEMASK(RemovingItemState);

                // IMPORTANT:
                // We need to null the param. This is important because the user
                // will most likely be storing pointers to heap allocations in
                // here, and free the allocation after it has deleted the
                // item. The user may allocate sometime in the future and receive
                // the same pointer as is stored here. The user may call
                // LVM_FINDITEM or LVM_GETNEXTITEM and find this item, which
                // is supposed to be deleted. It may then attempt to delete
                // this item *twice*, which leads to bad things happening,
                // including *not* deleting the item that the user wanted to delete.
                item.lParam = (LPARAM)NULL;

                CallWindowProc(context->OldWndProc, hwnd, LVM_SETITEM, 0, (LPARAM)&item);

                {
                    PH_TICK_ENTRY localEntry;
                    PPH_TICK_ENTRY entry;

                    PhpEnsureTickHashtableCreated(context);

                    localEntry.Id = ListView_MapIndexToID(hwnd, (INT)wParam);
                    entry = PhAddEntryHashtableEx(context->TickHashtable, &localEntry, NULL);

                    entry->TickCount = GetTickCount();
                }

                return TRUE;
            }
            else
            {
                // The item may still be under state highlighting.
                if (context->TickHashtable)
                {
                    PH_TICK_ENTRY entry;

                    entry.Id = ListView_MapIndexToID(hwnd, (INT)wParam);
                    PhRemoveEntryHashtable(context->TickHashtable, &entry);
                }
            }
        }
        break;
    case LVM_GETITEM:
        {
            LVITEM item;
            ULONG itemState;
            ULONG oldMask;
            ULONG oldStateMask;

            if (!context->EnableState)
                break; // pass through

            memcpy(&item, (LPLVITEM)lParam, sizeof(LVITEM));

            oldMask = item.mask;
            oldStateMask = item.stateMask;

            if (!(item.mask & LVIF_STATE))
            {
                item.mask |= LVIF_STATE;
                item.stateMask = LVIS_STATEIMAGEMASK;
            }
            else
            {
                item.stateMask |= LVIS_STATEIMAGEMASK;
            }

            if (!CallWindowProc(oldWndProc, hwnd, LVM_GETITEM, 0, (LPARAM)&item))
                return FALSE;

            // Check if the item is being deleted. If so, pretend it doesn't
            // exist.

            itemState = PH_GET_ITEM_STATE(item.state);

            if (itemState == RemovingItemState)
                return FALSE;

            item.mask = oldMask;
            item.stateMask = oldStateMask;
            item.state &= item.stateMask;

            memcpy((LPLVITEM)lParam, &item, sizeof(LVITEM));
        }
        return TRUE;
    case ELVM_ADDFALLBACKCOLUMN:
        {
            if (context->NumberOfFallbackColumns < PH_MAX_COMPARE_FUNCTIONS)
                context->FallbackColumns[context->NumberOfFallbackColumns++] = (ULONG)wParam;
            else
                return FALSE;
        }
        return TRUE;
    case ELVM_ADDFALLBACKCOLUMNS:
        {
            ULONG numberOfColumns = (ULONG)wParam;
            PULONG columns = (PULONG)lParam;

            if (context->NumberOfFallbackColumns + numberOfColumns <= PH_MAX_COMPARE_FUNCTIONS)
            {
                memcpy(
                    &context->FallbackColumns[context->NumberOfFallbackColumns],
                    columns,
                    numberOfColumns * sizeof(ULONG)
                    );
                context->NumberOfFallbackColumns += numberOfColumns;
            }
            else
            {
                return FALSE;
            }
        }
        return TRUE;
    case ELVM_ENABLESTATE:
        {
            context->EnableState = !!wParam;
        }
        return TRUE;
    case ELVM_INIT:
        {
            PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder);

            // HACK to fix tooltips showing behind Always On Top windows.
            SetWindowPos(ListView_GetToolTips(hwnd), HWND_TOPMOST, 0, 0, 0, 0,
                SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);

            // Make sure focus rectangles are disabled.
            SendMessage(hwnd, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0);
        }
        return TRUE;
    case ELVM_SETCOLUMNWIDTH:
        {
            ULONG column = (ULONG)wParam;
            LONG width = (LONG)lParam;

            if (width == ELVSCW_AUTOSIZE_REMAININGSPACE)
            {
                RECT clientRect;
                LONG availableWidth;
                ULONG i;
                LVCOLUMN lvColumn;

                GetClientRect(hwnd, &clientRect);
                availableWidth = clientRect.right;
                i = 0;
                lvColumn.mask = LVCF_WIDTH;

                while (TRUE)
                {
                    if (i != column)
                    {
                        if (CallWindowProc(oldWndProc, hwnd, LVM_GETCOLUMN, i, (LPARAM)&lvColumn))
                        {
                            availableWidth -= lvColumn.cx;
                        }
                        else
                        {
                            break;
                        }
                    }

                    i++;
                }

                if (availableWidth >= 40)
                    return CallWindowProc(oldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, availableWidth);
            }

            return CallWindowProc(oldWndProc, hwnd, LVM_SETCOLUMNWIDTH, column, width);
        }
        break;
    case ELVM_SETCOMPAREFUNCTION:
        {
            ULONG column = (ULONG)wParam;
            PPH_COMPARE_FUNCTION compareFunction = (PPH_COMPARE_FUNCTION)lParam;

            if (column >= PH_MAX_COMPARE_FUNCTIONS)
                return FALSE;

            context->CompareFunctions[column] = compareFunction;
        }
        return TRUE;
    case ELVM_SETCONTEXT:
        {
            context->Context = (PVOID)lParam;
        }
        return TRUE;
    case ELVM_SETCURSOR:
        {
            context->Cursor = (HCURSOR)lParam;
        }
        return TRUE;
    case ELVM_SETHIGHLIGHTINGDURATION:
        {
            context->HighlightingDuration = (ULONG)wParam;
        }
        return TRUE;
    case ELVM_SETITEMCOLORFUNCTION:
        {
            context->ItemColorFunction = (PPH_EXTLV_GET_ITEM_COLOR)lParam;
        }
        return TRUE;
    case ELVM_SETITEMFONTFUNCTION:
        {
            context->ItemFontFunction = (PPH_EXTLV_GET_ITEM_FONT)lParam;
        }
        return TRUE;
    case ELVM_SETNEWCOLOR:
        {
            context->NewColor = (COLORREF)wParam;
        }
        return TRUE;
    case ELVM_SETREDRAW:
        {
            if (wParam)
                context->EnableRedraw++;
            else
                context->EnableRedraw--;

            if (context->EnableRedraw == 1)
            {
                SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
                InvalidateRect(hwnd, NULL, FALSE);
            }
            else if (context->EnableRedraw == 0)
            {
                SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
            }
        }
        return TRUE;
    case ELVM_SETREMOVINGCOLOR:
        {
            context->RemovingColor = (COLORREF)wParam;
        }
        return TRUE;
    case ELVM_SETSORT:
        {
            context->SortColumn = (ULONG)wParam;
            context->SortOrder = (PH_SORT_ORDER)lParam;

            PhSetHeaderSortIcon(ListView_GetHeader(hwnd), context->SortColumn, context->SortOrder);
        }
        return TRUE;
    case ELVM_SETSORTFAST:
        {
            context->SortFast = !!wParam;
        }
        return TRUE;
    case ELVM_SETSTATEHIGHLIGHTING:
        {
            if (wParam)
                context->EnableStateHighlighting++;
            else
                context->EnableStateHighlighting--;
        }
        return TRUE;
    case ELVM_SETTRISTATE:
        {
            context->TriState = !!wParam;
        }
        return TRUE;
    case ELVM_SETTRISTATECOMPAREFUNCTION:
        {
            context->TriStateCompareFunction = (PPH_COMPARE_FUNCTION)lParam;
        }
        return TRUE;
    case ELVM_SORTITEMS:
        {
            if (context->SortFast)
            {
                // This sort method is faster than the normal sort because our comparison function
                // doesn't have to call the list view window procedure to get the item lParam values.
                // The disadvantage of this method is that default sorting is not available - if a
                // column doesn't have a comparison function, it doesn't get sorted at all.

                ListView_SortItems(
                    hwnd,
                    PhpExtendedListViewCompareFastFunc,
                    (LPARAM)context
                    );
            }
            else
            {
                ListView_SortItemsEx(
                    hwnd,
                    PhpExtendedListViewCompareFunc,
                    (LPARAM)context
                    );
            }
        }
        return TRUE;
    case ELVM_TICK:
        {
            if (
                context->EnableStateHighlighting > 0 &&
                context->TickHashtable &&
                context->TickHashtable->Count != 0
                )
            {
                PhListTick(context);
            }
        }
        return TRUE;
    }

    return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
}