⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 listbox.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * Listbox controls
 *
 * Copyright 1996 Alexandre Julliard
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <user32.h>

#include <wine/debug.h>

/* Start of hack section -------------------------------- */

typedef short *LPINT16;

BOOL is_old_app(HWND hwnd)
{
	return FALSE;
}

#define WM_LBTRACKPOINT     0x0131
#define WS_EX_DRAGDETECT    0x00000002L
#define WM_BEGINDRAG        0x022C

UINT STDCALL SetSystemTimer(HWND,UINT_PTR,UINT,TIMERPROC);
BOOL STDCALL KillSystemTimer(HWND,UINT_PTR);

/* End of hack section -------------------------------- */

/* Unimplemented yet:
 * - LBS_USETABSTOPS
 * - Locale handling
 *
 * Probably needs improvement:
 * - LBS_NOSEL
 */

/* Items array granularity */
#define LB_ARRAY_GRANULARITY 16

/* Scrolling timeout in ms */
#define LB_SCROLL_TIMEOUT 50

/* Listbox system timer id */
#define LB_TIMER_ID  2

/* flag listbox changed while setredraw false - internal style */
#define LBS_DISPLAYCHANGED 0x80000000

/* Item structure */
typedef struct
{
    LPWSTR  str;       /* Item text */
    BOOL    selected;  /* Is item selected? */
    UINT    height;    /* Item height (only for OWNERDRAWVARIABLE) */
    DWORD   data;      /* User data */
} LB_ITEMDATA;

/* Listbox structure */
typedef struct
{
    HWND        self;           /* Our own window handle */
    HWND        owner;          /* Owner window to send notifications to */
    UINT        style;          /* Window style */
    INT         width;          /* Window width */
    INT         height;         /* Window height */
    LB_ITEMDATA  *items;          /* Array of items */
    INT         nb_items;       /* Number of items */
    INT         top_item;       /* Top visible item */
    INT         selected_item;  /* Selected item */
    INT         focus_item;     /* Item that has the focus */
    INT         anchor_item;    /* Anchor item for extended selection */
    INT         item_height;    /* Default item height */
    INT         page_size;      /* Items per listbox page */
    INT         column_width;   /* Column width for multi-column listboxes */
    INT         horz_extent;    /* Horizontal extent (0 if no hscroll) */
    INT         horz_pos;       /* Horizontal position */
    INT         nb_tabs;        /* Number of tabs in array */
    INT        *tabs;           /* Array of tabs */
    INT         avg_char_width; /* Average width of characters */
    BOOL        caret_on;       /* Is caret on? */
    BOOL        captured;       /* Is mouse captured? */
    BOOL	in_focus;
    HFONT       font;           /* Current font */
    LCID          locale;         /* Current locale for string comparisons */
    LPHEADCOMBO   lphc;		  /* ComboLBox */
} LB_DESCR;


#define IS_OWNERDRAW(descr) \
    ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))

#define HAS_STRINGS(descr) \
    (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))


#define IS_MULTISELECT(descr) \
    ((descr)->style & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL) && \
     !((descr)->style & LBS_NOSEL))

#define SEND_NOTIFICATION(descr,code) \
    (SendMessageW( (descr)->owner, WM_COMMAND, \
     MAKEWPARAM( GetWindowLongPtrW((descr->self),GWLP_ID), (code)), (LPARAM)(descr->self) ))

#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)

/* Current timer status */
typedef enum
{
    LB_TIMER_NONE,
    LB_TIMER_UP,
    LB_TIMER_LEFT,
    LB_TIMER_DOWN,
    LB_TIMER_RIGHT
} TIMER_DIRECTION;

static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;

static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );

static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect );

/*********************************************************************
 * listbox class descriptor
 */
const struct builtin_class_descr LISTBOX_builtin_class =
{
#ifdef __REACTOS__
    L"ListBox",            /* name */
    CS_DBLCLKS /*| CS_PARENTDC*/,  /* style */
    (WNDPROC)ListBoxWndProcW,      /* procW */
    (WNDPROC)ListBoxWndProcA,      /* procA */
    sizeof(LB_DESCR *),   /* extra */
    (LPCWSTR) IDC_ARROW,           /* cursor */
    0                     /* brush */
#else
    "ListBox",            /* name */
    CS_DBLCLKS /*| CS_PARENTDC*/,  /* style */
    ListBoxWndProcA,      /* procA */
    ListBoxWndProcW,      /* procW */
    sizeof(LB_DESCR *),   /* extra */
    IDC_ARROW,            /* cursor */
    0                     /* brush */
#endif
};


/*********************************************************************
 * combolbox class descriptor
 */
const struct builtin_class_descr COMBOLBOX_builtin_class =
{
#ifdef __REACTOS__
    L"ComboLBox",          /* name */
    CS_DBLCLKS | CS_SAVEBITS,  /* style */
    (WNDPROC)ListBoxWndProcW,      /* procW */
    (WNDPROC)ListBoxWndProcA,      /* procA */
    sizeof(LB_DESCR *),   /* extra */
    (LPCWSTR) IDC_ARROW,           /* cursor */
    0                     /* brush */
#else
    "ComboLBox",          /* name */
    CS_DBLCLKS | CS_SAVEBITS,  /* style */
    ListBoxWndProcA,      /* procA */
    ListBoxWndProcW,      /* procW */
    sizeof(LB_DESCR *),   /* extra */
    IDC_ARROW,            /* cursor */
    0                     /* brush */
#endif
};

#ifndef __REACTOS__
/* check whether app is a Win 3.1 app */
inline static BOOL is_old_app( HWND hwnd )
{
    return (GetExpWinVer16( GetWindowLongA(hwnd,GWL_HINSTANCE) ) & 0xFF00 ) == 0x0300;
}
#endif


/***********************************************************************
 *           LISTBOX_Dump
 */
void LISTBOX_Dump( HWND hwnd )
{
    INT i;
    LB_ITEMDATA *item;
    LB_DESCR *descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 );

    TRACE( "Listbox:\n" );
    TRACE( "hwnd=%p descr=%08x items=%d top=%d\n",
           hwnd, (UINT)descr, descr->nb_items, descr->top_item );
    for (i = 0, item = descr->items; i < descr->nb_items; i++, item++)
    {
        TRACE( "%4d: %-40s %d %08lx %3d\n",
               i, debugstr_w(item->str), item->selected, item->data, item->height );
    }
}


/***********************************************************************
 *           LISTBOX_GetCurrentPageSize
 *
 * Return the current page size
 */
static INT LISTBOX_GetCurrentPageSize( LB_DESCR *descr )
{
    INT i, height;
    if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
    for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
    {
        if ((height += descr->items[i].height) > descr->height) break;
    }
    if (i == descr->top_item) return 1;
    else return i - descr->top_item;
}


/***********************************************************************
 *           LISTBOX_GetMaxTopIndex
 *
 * Return the maximum possible index for the top of the listbox.
 */
static INT LISTBOX_GetMaxTopIndex( LB_DESCR *descr )
{
    INT max, page;

    if (descr->style & LBS_OWNERDRAWVARIABLE)
    {
        page = descr->height;
        for (max = descr->nb_items - 1; max >= 0; max--)
            if ((page -= descr->items[max].height) < 0) break;
        if (max < descr->nb_items - 1) max++;
    }
    else if (descr->style & LBS_MULTICOLUMN)
    {
        if ((page = descr->width / descr->column_width) < 1) page = 1;
        max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
        max = (max - page) * descr->page_size;
    }
    else
    {
        max = descr->nb_items - descr->page_size;
    }
    if (max < 0) max = 0;
    return max;
}


/***********************************************************************
 *           LISTBOX_UpdateScroll
 *
 * Update the scrollbars. Should be called whenever the content
 * of the listbox changes.
 */
static void LISTBOX_UpdateScroll( LB_DESCR *descr )
{
    SCROLLINFO info;

    /* Check the listbox scroll bar flags individually before we call
       SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
       no WS_VSCROLL, we end up with an uninitialized, visible horizontal
       scroll bar when we do not need one.
    if (!(descr->style & WS_VSCROLL)) return;
    */

    /*   It is important that we check descr->style, and not wnd->dwStyle,
       for WS_VSCROLL, as the former is exactly the one passed in
       argument to CreateWindow.
         In Windows (and from now on in Wine :) a listbox created
       with such a style (no WS_SCROLL) does not update
       the scrollbar with listbox-related data, thus letting
       the programmer use it for his/her own purposes. */

    if (descr->style & LBS_NOREDRAW) return;
    info.cbSize = sizeof(info);

    if (descr->style & LBS_MULTICOLUMN)
    {
        info.nMin  = 0;
        info.nMax  = (descr->nb_items - 1) / descr->page_size;
        info.nPos  = descr->top_item / descr->page_size;
        info.nPage = descr->width / descr->column_width;
        if (info.nPage < 1) info.nPage = 1;
        info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
        if (descr->style & LBS_DISABLENOSCROLL)
            info.fMask |= SIF_DISABLENOSCROLL;
        if (descr->style & WS_HSCROLL)
            SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
        info.nMax = 0;
        info.fMask = SIF_RANGE;
        if (descr->style & WS_VSCROLL)
            SetScrollInfo( descr->self, SB_VERT, &info, TRUE );
    }
    else
    {
        info.nMin  = 0;
        info.nMax  = descr->nb_items - 1;
        info.nPos  = descr->top_item;
        info.nPage = LISTBOX_GetCurrentPageSize( descr );
        info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
        if (descr->style & LBS_DISABLENOSCROLL)
            info.fMask |= SIF_DISABLENOSCROLL;
        if (descr->style & WS_VSCROLL)
            SetScrollInfo( descr->self, SB_VERT, &info, TRUE );

        if (descr->horz_extent)
        {
            info.nMin  = 0;
            info.nMax  = descr->horz_extent - 1;
            info.nPos  = descr->horz_pos;
            info.nPage = descr->width;
            info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
            if (descr->style & LBS_DISABLENOSCROLL)
                info.fMask |= SIF_DISABLENOSCROLL;
            if (descr->style & WS_HSCROLL)
                SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
        }
    }
}


/***********************************************************************
 *           LISTBOX_SetTopItem
 *
 * Set the top item of the listbox, scrolling up or down if necessary.
 */
static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index,
                                   BOOL scroll )
{
    INT max = LISTBOX_GetMaxTopIndex( descr );
    if (index > max) index = max;
    if (index < 0) index = 0;
    if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
    if (descr->top_item == index) return LB_OKAY;
    if (descr->style & LBS_MULTICOLUMN)
    {
        INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
        if (scroll && (abs(diff) < descr->width))
            ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL,
                              SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );

        else
            scroll = FALSE;
    }
    else if (scroll)
    {
        INT diff;
        if (descr->style & LBS_OWNERDRAWVARIABLE)
        {
            INT i;
            diff = 0;
            if (index > descr->top_item)
            {
                for (i = index - 1; i >= descr->top_item; i--)
                    diff -= descr->items[i].height;
            }
            else
            {
                for (i = index; i < descr->top_item; i++)
                    diff += descr->items[i].height;
            }
        }
        else
            diff = (descr->top_item - index) * descr->item_height;

        if (abs(diff) < descr->height)
            ScrollWindowEx( descr->self, 0, diff, NULL, NULL, 0, NULL,
                              SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
        else
            scroll = FALSE;
    }
    if (!scroll) InvalidateRect( descr->self, NULL, TRUE );
    descr->top_item = index;
    LISTBOX_UpdateScroll( descr );
    return LB_OKAY;
}


/***********************************************************************
 *           LISTBOX_UpdatePage

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -