listbox.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,516 行 · 第 1/3 页

CPP
1,516
字号
}

void wxListBox::ChangeCurrent(int diff)
{
    int current = m_current == -1 ? 0 : m_current;

    current += diff;

    int last = GetCount() - 1;
    if ( current < 0 )
        current = 0;
    else if ( current > last )
        current = last;

    SetCurrentItem(current);
}

void wxListBox::ExtendSelection(int itemTo)
{
    // if we don't have the explicit values for selection start/end, make them
    // up
    if ( m_selAnchor == -1 )
        m_selAnchor = m_current;

    if ( itemTo == -1 )
        itemTo = m_current;

    // swap the start/end of selection range if necessary
    int itemFrom = m_selAnchor;
    if ( itemFrom > itemTo )
    {
        int itemTmp = itemFrom;
        itemFrom = itemTo;
        itemTo = itemTmp;
    }

    // the selection should now include all items in the range between the
    // anchor and the specified item and only them

    int n;
    for ( n = 0; n < itemFrom; n++ )
    {
        Deselect(n);
    }

    for ( ; n <= itemTo; n++ )
    {
        SetSelection(n);
    }

    int count = GetCount();
    for ( ; n < count; n++ )
    {
        Deselect(n);
    }
}

void wxListBox::DoSelect(int item, bool sel)
{
    if ( item != -1 )
    {
        // go to this item first
        SetCurrentItem(item);
    }

    // the current item is the one we want to change: either it was just
    // changed above to be the same as item or item == -1 in which we case we
    // are supposed to use the current one anyhow
    if ( m_current != -1 )
    {
        // [de]select it
        SetSelection(m_current, sel);
    }
}

void wxListBox::SelectAndNotify(int item)
{
    DoSelect(item);

    SendEvent(wxEVT_COMMAND_LISTBOX_SELECTED);
}

void wxListBox::Activate(int item)
{
    if ( item != -1 )
        SetCurrentItem(item);
    else
        item = m_current;

    if ( !(GetWindowStyle() & wxLB_MULTIPLE) )
    {
        DeselectAll(item);
    }

    if ( item != -1 )
    {
        DoSelect(item);

        SendEvent(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED);
    }
}

// ----------------------------------------------------------------------------
// input handling
// ----------------------------------------------------------------------------

/*
   The numArg here is the listbox item index while the strArg is used
   differently for the different actions:

   a) for wxACTION_LISTBOX_FIND it has the natural meaning: this is the string
      to find

   b) for wxACTION_LISTBOX_SELECT and wxACTION_LISTBOX_EXTENDSEL it is used
      to decide if the listbox should send the notification event (it is empty)
      or not (it is not): this allows us to reuse the same action for when the
      user is dragging the mouse when it has been released although in the
      first case no notification is sent while in the second it is sent.
 */
bool wxListBox::PerformAction(const wxControlAction& action,
                              long numArg,
                              const wxString& strArg)
{
    int item = (int)numArg;

    if ( action == wxACTION_LISTBOX_SETFOCUS )
    {
        SetCurrentItem(item);
    }
    else if ( action == wxACTION_LISTBOX_ACTIVATE )
    {
        Activate(item);
    }
    else if ( action == wxACTION_LISTBOX_TOGGLE )
    {
        if ( item == -1 )
            item = m_current;

        if ( IsSelected(item) )
            DoUnselect(item);
        else
            SelectAndNotify(item);
    }
    else if ( action == wxACTION_LISTBOX_SELECT )
    {
        DeselectAll(item);

        if ( strArg.empty() )
            SelectAndNotify(item);
        else
            DoSelect(item);
    }
    else if ( action == wxACTION_LISTBOX_SELECTADD )
        DoSelect(item);
    else if ( action == wxACTION_LISTBOX_UNSELECT )
        DoUnselect(item);
    else if ( action == wxACTION_LISTBOX_MOVEDOWN )
        ChangeCurrent(1);
    else if ( action == wxACTION_LISTBOX_MOVEUP )
        ChangeCurrent(-1);
    else if ( action == wxACTION_LISTBOX_PAGEDOWN )
        ChangeCurrent(GetItemsPerPage());
    else if ( action == wxACTION_LISTBOX_PAGEUP )
        ChangeCurrent(-GetItemsPerPage());
    else if ( action == wxACTION_LISTBOX_START )
        SetCurrentItem(0);
    else if ( action == wxACTION_LISTBOX_END )
        SetCurrentItem(GetCount() - 1);
    else if ( action == wxACTION_LISTBOX_UNSELECTALL )
        DeselectAll(item);
    else if ( action == wxACTION_LISTBOX_EXTENDSEL )
        ExtendSelection(item);
    else if ( action == wxACTION_LISTBOX_FIND )
        FindNextItem(strArg);
    else if ( action == wxACTION_LISTBOX_ANCHOR )
        AnchorSelection(item == -1 ? m_current : item);
    else if ( action == wxACTION_LISTBOX_SELECTALL ||
              action == wxACTION_LISTBOX_SELTOGGLE )
        wxFAIL_MSG(_T("unimplemented yet"));
    else
        return wxControl::PerformAction(action, numArg, strArg);

    return true;
}

// ============================================================================
// implementation of wxStdListboxInputHandler
// ============================================================================

wxStdListboxInputHandler::wxStdListboxInputHandler(wxInputHandler *handler,
                                                   bool toggleOnPressAlways)
                        : wxStdInputHandler(handler)
{
    m_btnCapture = 0;
    m_toggleOnPressAlways = toggleOnPressAlways;
    m_actionMouse = wxACTION_NONE;
    m_trackMouseOutside = true;
}

int wxStdListboxInputHandler::HitTest(const wxListBox *lbox,
                                      const wxMouseEvent& event)
{
    int item = HitTestUnsafe(lbox, event);

    return FixItemIndex(lbox, item);
}

int wxStdListboxInputHandler::HitTestUnsafe(const wxListBox *lbox,
                                            const wxMouseEvent& event)
{
    wxPoint pt = event.GetPosition();
    pt -= lbox->GetClientAreaOrigin();
    int y;
    lbox->CalcUnscrolledPosition(0, pt.y, NULL, &y);
    return y / lbox->GetLineHeight();
}

int wxStdListboxInputHandler::FixItemIndex(const wxListBox *lbox,
                                           int item)
{
    if ( item < 0 )
    {
        // mouse is above the first item
        item = 0;
    }
    else if ( item >= lbox->GetCount() )
    {
        // mouse is below the last item
        item = lbox->GetCount() - 1;
    }

    return item;
}

bool wxStdListboxInputHandler::IsValidIndex(const wxListBox *lbox, int item)
{
    return item >= 0 && item < lbox->GetCount();
}

wxControlAction
wxStdListboxInputHandler::SetupCapture(wxListBox *lbox,
                                       const wxMouseEvent& event,
                                       int item)
{
    // we currently only allow selecting with the left mouse button, if we
    // do need to allow using other buttons too we might use the code
    // inside #if 0
#if 0
    m_btnCapture = event.LeftDown()
                    ? 1
                    : event.RightDown()
                        ? 3
                        : 2;
#else
    m_btnCapture = 1;
#endif // 0/1

    wxControlAction action;
    if ( lbox->HasMultipleSelection() )
    {
        if ( lbox->GetWindowStyle() & wxLB_MULTIPLE )
        {
            if ( m_toggleOnPressAlways )
            {
                // toggle the item right now
                action = wxACTION_LISTBOX_TOGGLE;
            }
            //else: later

            m_actionMouse = wxACTION_LISTBOX_SETFOCUS;
        }
        else // wxLB_EXTENDED listbox
        {
            // simple click in an extended sel listbox clears the old
            // selection and adds the clicked item to it then, ctrl-click
            // toggles an item to it and shift-click adds a range between
            // the old selection anchor and the clicked item
            if ( event.ControlDown() )
            {
                lbox->PerformAction(wxACTION_LISTBOX_ANCHOR, item);

                action = wxACTION_LISTBOX_TOGGLE;
            }
            else if ( event.ShiftDown() )
            {
                action = wxACTION_LISTBOX_EXTENDSEL;
            }
            else // simple click
            {
                lbox->PerformAction(wxACTION_LISTBOX_ANCHOR, item);

                action = wxACTION_LISTBOX_SELECT;
            }

            m_actionMouse = wxACTION_LISTBOX_EXTENDSEL;
        }
    }
    else // single selection
    {
        m_actionMouse =
        action = wxACTION_LISTBOX_SELECT;
    }

    // by default we always do track it
    m_trackMouseOutside = true;

    return action;
}

bool wxStdListboxInputHandler::HandleKey(wxInputConsumer *consumer,
                                         const wxKeyEvent& event,
                                         bool pressed)
{
    // we're only interested in the key press events
    if ( pressed && !event.AltDown() )
    {
        bool isMoveCmd = true;
        int style = consumer->GetInputWindow()->GetWindowStyle();

        wxControlAction action;
        wxString strArg;

        int keycode = event.GetKeyCode();
        switch ( keycode )
        {
            // movement
            case WXK_UP:
                action = wxACTION_LISTBOX_MOVEUP;
                break;

            case WXK_DOWN:
                action = wxACTION_LISTBOX_MOVEDOWN;
                break;

            case WXK_PAGEUP:

            case WXK_PRIOR:
                action = wxACTION_LISTBOX_PAGEUP;
                break;

            case WXK_PAGEDOWN:

            case WXK_NEXT:
                action = wxACTION_LISTBOX_PAGEDOWN;
                break;

            case WXK_HOME:
                action = wxACTION_LISTBOX_START;
                break;

            case WXK_END:
                action = wxACTION_LISTBOX_END;
                break;

            // selection
            case WXK_SPACE:
                if ( style & wxLB_MULTIPLE )
                {
                    action = wxACTION_LISTBOX_TOGGLE;
                    isMoveCmd = false;
                }
                break;

            case WXK_RETURN:
                action = wxACTION_LISTBOX_ACTIVATE;
                isMoveCmd = false;
                break;

            default:
                if ( (keycode < 255) && wxIsalnum((wxChar)keycode) )
                {
                    action = wxACTION_LISTBOX_FIND;
                    strArg = (wxChar)keycode;
                }
        }

        if ( !action.IsEmpty() )
        {
            consumer->PerformAction(action, -1, strArg);

            if ( isMoveCmd )
            {
                if ( style & wxLB_SINGLE )
                {
                    // the current item is always the one selected
                    consumer->PerformAction(wxACTION_LISTBOX_SELECT);
                }
                else if ( style & wxLB_EXTENDED )
                {
                    if ( event.ShiftDown() )
                        consumer->PerformAction(wxACTION_LISTBOX_EXTENDSEL);
                    else
                    {
                        // select the item and make it the new selection anchor
                        consumer->PerformAction(wxACTION_LISTBOX_SELECT);
                        consumer->PerformAction(wxACTION_LISTBOX_ANCHOR);
                    }
                }
                //else: nothing to do for multiple selection listboxes
            }

            return true;
        }
    }

    return wxStdInputHandler::HandleKey(consumer, event, pressed);
}

bool wxStdListboxInputHandler::HandleMouse(wxInputConsumer *consumer,
                                           const wxMouseEvent& event)
{
    wxListBox *lbox = wxStaticCast(consumer->GetInputWindow(), wxListBox);
    int item = HitTest(lbox, event);
    wxControlAction action;

    // when the left mouse button is pressed, capture the mouse and track the
    // item under mouse (if the mouse leaves the window, we will still be
    // getting the mouse move messages generated by wxScrollWindow)
    if ( event.LeftDown() )
    {
        // capture the mouse to track the selected item
        lbox->CaptureMouse();

        action = SetupCapture(lbox, event, item);
    }
    else if ( m_btnCapture && event.ButtonUp(m_btnCapture) )
    {
        // when the left mouse button is released, release the mouse too
        wxWindow *winCapture = wxWindow::GetCapture();
        if ( winCapture )
        {
            winCapture->ReleaseMouse();
            m_btnCapture = 0;

            action = m_actionMouse;
        }
        //else: the mouse wasn't presed over the listbox, only released here
    }
    else if ( event.LeftDClick() )
    {
        action = wxACTION_LISTBOX_ACTIVATE;
    }

    if ( !action.IsEmpty() )
    {
        lbox->PerformAction(action, item);

        return true;
    }

    return wxStdInputHandler::HandleMouse(consumer, event);
}

bool wxStdListboxInputHandler::HandleMouseMove(wxInputConsumer *consumer,
                                               const wxMouseEvent& event)
{
    wxWindow *winCapture = wxWindow::GetCapture();
    if ( winCapture && (event.GetEventObject() == winCapture) )
    {
        wxListBox *lbox = wxStaticCast(consumer->GetInputWindow(), wxListBox);

        if ( !m_btnCapture || !m_trackMouseOutside )
        {
            // someone captured the mouse for us (we always set m_btnCapture
            // when we do it ourselves): in this case we only react to
            // the mouse messages when they happen inside the listbox
            if ( lbox->HitTest(event.GetPosition()) != wxHT_WINDOW_INSIDE )
                return false;
        }

        int item = HitTest(lbox, event);
        if ( !m_btnCapture )
        {
            // now that we have the mouse inside the listbox, do capture it
            // normally - but ensure that we will still ignore the outside
            // events
            SetupCapture(lbox, event, item);

            m_trackMouseOutside = false;
        }

        if ( IsValidIndex(lbox, item) )
        {
            // pass something into strArg to tell the listbox that it shouldn't
            // send the notification message: see PerformAction() above
            lbox->PerformAction(m_actionMouse, item, _T("no"));
        }
        // else: don't pass invalid index to the listbox
    }
    else // we don't have capture any more
    {
        if ( m_btnCapture )
        {
            // if we lost capture unexpectedly (someone else took the capture
            // from us), return to a consistent state
            m_btnCapture = 0;
        }
    }

    return wxStdInputHandler::HandleMouseMove(consumer, event);
}

#endif // wxUSE_LISTBOX

⌨️ 快捷键说明

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