radiobox.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 856 行 · 第 1/2 页

CPP
856
字号
    if( changed )
        InvalidateBestSize();
    return changed;
}

WX_FORWARD_STD_METHODS_TO_SUBWINDOWS(wxRadioBox, wxStaticBox, m_radioButtons)

// ----------------------------------------------------------------------------
// size calculations
// ----------------------------------------------------------------------------

wxSize wxRadioBox::GetMaxButtonSize() const
{
    // calculate the max button size
    int widthMax = 0,
        heightMax = 0;
    const int count = GetCount();
    for ( int i = 0 ; i < count; i++ )
    {
        int width, height;
        if ( m_radioWidth[i] < 0 )
        {
            GetTextExtent(wxStripMenuCodes(wxGetWindowText((*m_radioButtons)[i])), &width, &height);

            // adjust the size to take into account the radio box itself
            // FIXME this is totally bogus!
            width += RADIO_SIZE;
            height *= 3;
            height /= 2;
        }
        else
        {
            width = m_radioWidth[i];
            height = m_radioHeight[i];
        }

        if ( widthMax < width )
            widthMax = width;
        if ( heightMax < height )
            heightMax = height;
    }

    return wxSize(widthMax, heightMax);
}

wxSize wxRadioBox::GetTotalButtonSize(const wxSize& sizeBtn) const
{
    // the radiobox should be big enough for its buttons
    int cx1, cy1;
    wxGetCharSize(m_hWnd, &cx1, &cy1, GetFont());

    int extraHeight = cy1;

    int height = GetNumVer() * sizeBtn.y + cy1/2 + extraHeight;
    int width  = GetNumHor() * (sizeBtn.x + cx1) + cx1;

    // Add extra space under the label, if it exists.
    if (!wxControl::GetLabel().empty())
        height += cy1/2;

    // and also wide enough for its label
    int widthLabel;
    GetTextExtent(wxStripMenuCodes(GetTitle()), &widthLabel, NULL);
    widthLabel += RADIO_SIZE; // FIXME this is bogus too
    if ( widthLabel > width )
        width = widthLabel;

    return wxSize(width, height);
}

wxSize wxRadioBox::DoGetBestSize() const
{
    wxSize best = GetTotalButtonSize(GetMaxButtonSize());
    CacheBestSize(best);
    return best;
}

// Restored old code.
void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
    int currentX, currentY;
    GetPosition(&currentX, &currentY);
    int widthOld, heightOld;
    GetSize(&widthOld, &heightOld);

    int xx = x;
    int yy = y;

    if (x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
        xx = currentX;
    if (y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
        yy = currentY;

    int y_offset = yy;
    int x_offset = xx;

    int cx1, cy1;
    wxGetCharSize(m_hWnd, &cx1, &cy1, GetFont());

    // Attempt to have a look coherent with other platforms: We compute the
    // biggest toggle dim, then we align all items according this value.
    wxSize maxSize = GetMaxButtonSize();
    int maxWidth = maxSize.x,
        maxHeight = maxSize.y;

    wxSize totSize = GetTotalButtonSize(maxSize);
    int totWidth = totSize.x,
        totHeight = totSize.y;

    // only change our width/height if asked for
    if ( width == wxDefaultCoord )
    {
        if ( sizeFlags & wxSIZE_AUTO_WIDTH )
            width = totWidth;
        else
            width = widthOld;
    }

    if ( height == wxDefaultCoord )
    {
        if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
            height = totHeight;
        else
            height = heightOld;
    }

    DoMoveWindow(xx, yy, width, height);

    // Now position all the buttons: the current button will be put at
    // wxPoint(x_offset, y_offset) and the new row/column will start at
    // startX/startY. The size of all buttons will be the same wxSize(maxWidth,
    // maxHeight) except for the buttons in the last column which should extend
    // to the right border of radiobox and thus can be wider than this.

    // Also, remember that wxRA_SPECIFY_COLS means that we arrange buttons in
    // left to right order and m_majorDim is the number of columns while
    // wxRA_SPECIFY_ROWS means that the buttons are arranged top to bottom and
    // m_majorDim is the number of rows.

    x_offset += cx1;
    y_offset += cy1;

    // Add extra space under the label, if it exists.
    if (!wxControl::GetLabel().empty())
        y_offset += cy1/2;

    int startX = x_offset;
    int startY = y_offset;

    const int count = GetCount();
    for ( int i = 0; i < count; i++ )
    {
        // the last button in the row may be wider than the other ones as the
        // radiobox may be wider than the sum of the button widths (as it
        // happens, for example, when the radiobox label is very long)
        bool isLastInTheRow;
        if ( m_windowStyle & wxRA_SPECIFY_COLS )
        {
            // item is the last in its row if it is a multiple of the number of
            // columns or if it is just the last item
            int n = i + 1;
            isLastInTheRow = ((n % m_majorDim) == 0) || (n == count);
        }
        else // wxRA_SPECIFY_ROWS
        {
            // item is the last in the row if it is in the last columns
            isLastInTheRow = i >= (count/m_majorDim)*m_majorDim;
        }

        // is this the start of new row/column?
        if ( i && (i % m_majorDim == 0) )
        {
            if ( m_windowStyle & wxRA_SPECIFY_ROWS )
            {
                // start of new column
                y_offset = startY;
                x_offset += maxWidth + cx1;
            }
            else // start of new row
            {
                x_offset = startX;
                y_offset += maxHeight;
                if (m_radioWidth[0]>0)
                    y_offset += cy1/2;
            }
        }

        int widthBtn;
        if ( isLastInTheRow )
        {
            // make the button go to the end of radio box
            widthBtn = startX + width - x_offset - 2*cx1;
            if ( widthBtn < maxWidth )
                widthBtn = maxWidth;
        }
        else
        {
            // normal button, always of the same size
            widthBtn = maxWidth;
        }

        // make all buttons of the same, maximal size - like this they cover
        // the radiobox entirely and the radiobox tooltips are always shown
        // (otherwise they are not when the mouse pointer is in the radiobox
        // part not belonging to any radiobutton)
        DoMoveSibling((*m_radioButtons)[i], x_offset, y_offset, widthBtn, maxHeight);

        // where do we put the next button?
        if ( m_windowStyle & wxRA_SPECIFY_ROWS )
        {
            // below this one
            y_offset += maxHeight;
            if (m_radioWidth[0]>0)
                y_offset += cy1/2;
        }
        else
        {
            // to the right of this one
            x_offset += widthBtn + cx1;
        }
    }
}

// ----------------------------------------------------------------------------
// radio box drawing
// ----------------------------------------------------------------------------

#ifndef __WXWINCE__

WXHRGN wxRadioBox::MSWGetRegionWithoutChildren()
{
    RECT rc;
    ::GetWindowRect(GetHwnd(), &rc);
    HRGN hrgn = ::CreateRectRgn(rc.left, rc.top, rc.right + 1, rc.bottom + 1);

    const size_t count = GetCount();
    for ( size_t i = 0; i < count; ++i )
    {
        ::GetWindowRect((*m_radioButtons)[i], &rc);
        AutoHRGN hrgnchild(::CreateRectRgnIndirect(&rc));
        ::CombineRgn(hrgn, hrgn, hrgnchild, RGN_DIFF);
    }

    return (WXHRGN)hrgn;
}

WXLRESULT
wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
    return wxStaticBox::MSWWindowProc(nMsg, wParam, lParam);
}

#endif // __WXWINCE__

// ---------------------------------------------------------------------------
// window proc for radio buttons
// ---------------------------------------------------------------------------

LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd,
                                           UINT message,
                                           WPARAM wParam,
                                           LPARAM lParam)
{
    switch ( message )
    {
        case WM_GETDLGCODE:
            // we must tell IsDialogMessage()/our kbd processing code that we
            // want to process arrows ourselves because neither of them is
            // smart enough to handle arrows properly for us
            {
                long lDlgCode = ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd,
                                                 message, wParam, lParam);

                return lDlgCode | DLGC_WANTARROWS;
            }

#if wxUSE_TOOLTIPS
        case WM_NOTIFY:
            {
                NMHDR* hdr = (NMHDR *)lParam;
                if ( hdr->code == TTN_NEEDTEXT )
                {
                    wxRadioBox *
                        radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);

                    wxCHECK_MSG( radiobox, 0,
                                 wxT("radio button without radio box?") );

                    wxToolTip *tooltip = radiobox->GetToolTip();
                    if ( tooltip )
                    {
                        TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam;
                        ttt->lpszText = (wxChar *)tooltip->GetTip().c_str();
                    }

                    // processed
                    return 0;
                }
            }
            break;
#endif // wxUSE_TOOLTIPS

        case WM_KEYDOWN:
            {
                wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);

                wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );

                bool processed = true;

                wxDirection dir;
                switch ( wParam )
                {
                    case VK_UP:
                        dir = wxUP;
                        break;

                    case VK_LEFT:
                        dir = wxLEFT;
                        break;

                    case VK_DOWN:
                        dir = wxDOWN;
                        break;

                    case VK_RIGHT:
                        dir = wxRIGHT;
                        break;

                    default:
                        processed = false;

                        // just to suppress the compiler warning
                        dir = wxALL;
                }

                if ( processed )
                {
                    int selOld = radiobox->GetSelection();
                    int selNew = radiobox->GetNextItem
                                 (
                                  selOld,
                                  dir,
                                  radiobox->GetWindowStyle()
                                 );

                    if ( selNew != selOld )
                    {
                        radiobox->SetSelection(selNew);
                        radiobox->SetFocus();

                        // emulate the button click
                        radiobox->SendNotificationEvent();

                        return 0;
                    }
                }
            }
            break;

        case WM_SETFOCUS:
        case WM_KILLFOCUS:
            {
                wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);

                wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );

                // if we don't do this, no focus events are generated for the
                // radiobox and, besides, we need to notify the parent about
                // the focus change, otherwise the focus handling logic in
                // wxControlContainer doesn't work
                if ( message == WM_SETFOCUS )
                    radiobox->HandleSetFocus((WXHWND)wParam);
                else
                    radiobox->HandleKillFocus((WXHWND)wParam);
            }
            break;

#ifndef __WXWINCE__
        case WM_HELP:
            {
                wxRadioBox *radiobox = (wxRadioBox *)wxGetWindowUserData(hwnd);

                wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") );

                bool processed = false;

                wxEvtHandler * const handler = radiobox->GetEventHandler();

                HELPINFO* info = (HELPINFO*) lParam;
                if ( info->iContextType == HELPINFO_WINDOW )
                {
                    for ( wxWindow* subjectOfHelp = radiobox;
                          subjectOfHelp;
                          subjectOfHelp = subjectOfHelp->GetParent() )
                    {
                        wxHelpEvent helpEvent(wxEVT_HELP,
                                              subjectOfHelp->GetId(),
                                              wxPoint(info->MousePos.x,
                                                      info->MousePos.y));
                        helpEvent.SetEventObject(radiobox);
                        if ( handler->ProcessEvent(helpEvent) )
                        {
                            processed = true;
                            break;
                        }
                    }
                }
                else if (info->iContextType == HELPINFO_MENUITEM)
                {
                    wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
                    helpEvent.SetEventObject(radiobox);
                    processed = handler->ProcessEvent(helpEvent);
                }

                if ( processed )
                    return 0;
            }
            break;
#endif // !__WXWINCE__
    }

    return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, message, wParam, lParam);
}

#endif // wxUSE_RADIOBOX

⌨️ 快捷键说明

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