tbar95.cpp

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

CPP
1,707
字号
    const long styleOld = GetWindowStyle();

    wxToolBarBase::SetWindowStyleFlag(style);

    // don't recreate an empty toolbar: not only this is unnecessary, but it is
    // also fatal as we'd then try to recreate the toolbar when it's just being
    // created
    if ( GetToolsCount() &&
            (style & MASK_NEEDS_RECREATE) != (styleOld & MASK_NEEDS_RECREATE) )
    {
        // to remove the text labels, simply re-realizing the toolbar is enough
        // but I don't know of any way to add the text to an existing toolbar
        // other than by recreating it entirely
        Recreate();
    }
}

// ----------------------------------------------------------------------------
// tool state
// ----------------------------------------------------------------------------

void wxToolBar::DoEnableTool(wxToolBarToolBase *tool, bool enable)
{
    ::SendMessage(GetHwnd(), TB_ENABLEBUTTON,
                  (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0));
}

void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool toggle)
{
    ::SendMessage(GetHwnd(), TB_CHECKBUTTON,
                  (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0));
}

void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
{
    // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or
    //     without, so we really need to delete the button and recreate it here
    wxFAIL_MSG( _T("not implemented") );
}

// ----------------------------------------------------------------------------
// event handlers
// ----------------------------------------------------------------------------

// Responds to colour changes, and passes event on to children.
void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent& event)
{
    wxRGBToColour(m_backgroundColour, ::GetSysColor(COLOR_BTNFACE));

    // Remap the buttons
    Realize();

    // Relayout the toolbar
    int nrows = m_maxRows;
    m_maxRows = 0;      // otherwise SetRows() wouldn't do anything
    SetRows(nrows);

    Refresh();

    // let the event propagate further
    event.Skip();
}

void wxToolBar::OnMouseEvent(wxMouseEvent& event)
{
    if (event.Leaving() && m_pInTool)
    {
        OnMouseEnter( -1 );
        event.Skip();
        return;
    }

    if ( event.RightDown() )
    {
        // find the tool under the mouse
        wxCoord x,y;
        event.GetPosition(&x, &y);

        wxToolBarToolBase *tool = FindToolForPosition(x, y);
        OnRightClick(tool ? tool->GetId() : -1, x, y);
    }
    else
    {
        event.Skip();
    }
}

// This handler is required to allow the toolbar to be set to a non-default
// colour: for example, when it must blend in with a notebook page.
void wxToolBar::OnEraseBackground(wxEraseEvent& event)
{
    wxColour bgCol = GetBackgroundColour();
    if (!bgCol.Ok())
    {
        event.Skip();
        return;
    }

    // notice that this 'dumb' implementation may cause flicker for some of the
    // controls in which case they should intercept wxEraseEvent and process it
    // themselves somehow

    RECT rect;
    ::GetClientRect(GetHwnd(), &rect);

    HBRUSH hBrush = ::CreateSolidBrush(wxColourToRGB(bgCol));

    HDC hdc = GetHdcOf((*event.GetDC()));

#ifndef __WXWINCE__
    int mode = ::SetMapMode(hdc, MM_TEXT);
#endif

    ::FillRect(hdc, &rect, hBrush);
    ::DeleteObject(hBrush);

#ifndef __WXWINCE__
    ::SetMapMode(hdc, mode);
#endif
}

bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
{
    // calculate our minor dimension ourselves - we're confusing the standard
    // logic (TB_AUTOSIZE) with our horizontal toolbars and other hacks
    RECT r;
    if ( ::SendMessage(GetHwnd(), TB_GETITEMRECT, 0, (LPARAM)&r) )
    {
        int w, h;

        if ( GetWindowStyle() & wxTB_VERTICAL )
        {
            w = r.right - r.left;
            if ( m_maxRows )
            {
                w *= (m_nButtons + m_maxRows - 1)/m_maxRows;
            }
            h = HIWORD(lParam);
        }
        else
        {
            w = LOWORD(lParam);
            if (HasFlag( wxTB_FLAT ))
                h = r.bottom - r.top - 3;
            else
                h = r.bottom - r.top;
            if ( m_maxRows )
            {
                // FIXME: hardcoded separator line height...
                h += HasFlag(wxTB_NODIVIDER) ? 4 : 6;
                h *= m_maxRows;
            }
        }

        if ( MAKELPARAM(w, h) != lParam )
        {
            // size really changed
            SetSize(w, h);
        }

        // message processed
        return true;
    }

    return false;
}

bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
{
    // erase any dummy separators which we used for aligning the controls if
    // any here

    // first of all, do we have any controls at all?
    wxToolBarToolsList::compatibility_iterator node;
    for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
    {
        if ( node->GetData()->IsControl() )
            break;
    }

    if ( !node )
    {
        // no controls, nothing to erase
        return false;
    }

    // prepare the DC on which we'll be drawing
    wxClientDC dc(this);
    dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID));
    dc.SetPen(*wxTRANSPARENT_PEN);

    RECT r;
    if ( !::GetUpdateRect(GetHwnd(), &r, FALSE) )
    {
        // nothing to redraw anyhow
        return false;
    }

    wxRect rectUpdate;
    wxCopyRECTToRect(r, rectUpdate);

    dc.SetClippingRegion(rectUpdate);

    // draw the toolbar tools, separators &c normally
    wxControl::MSWWindowProc(WM_PAINT, wParam, lParam);

    // for each control in the toolbar find all the separators intersecting it
    // and erase them
    //
    // NB: this is really the only way to do it as we don't know if a separator
    //     corresponds to a control (i.e. is a dummy one) or a real one
    //     otherwise
    for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
    {
        wxToolBarToolBase *tool = node->GetData();
        if ( tool->IsControl() )
        {
            // get the control rect in our client coords
            wxControl *control = tool->GetControl();
            wxRect rectCtrl = control->GetRect();

            // iterate over all buttons
            TBBUTTON tbb;
            int count = ::SendMessage(GetHwnd(), TB_BUTTONCOUNT, 0, 0);
            for ( int n = 0; n < count; n++ )
            {
                // is it a separator?
                if ( !::SendMessage(GetHwnd(), TB_GETBUTTON,
                                    n, (LPARAM)&tbb) )
                {
                    wxLogDebug(_T("TB_GETBUTTON failed?"));

                    continue;
                }

                if ( tbb.fsStyle != TBSTYLE_SEP )
                    continue;

                // get the bounding rect of the separator
                RECT r;
                if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT,
                                    n, (LPARAM)&r) )
                {
                    wxLogDebug(_T("TB_GETITEMRECT failed?"));

                    continue;
                }

                // does it intersect the control?
                wxRect rectItem;
                wxCopyRECTToRect(r, rectItem);
                if ( rectCtrl.Intersects(rectItem) )
                {
                    // yes, do erase it!
                    dc.DrawRectangle(rectItem);

                    // Necessary in case we use a no-paint-on-size
                    // style in the parent: the controls can disappear
                    control->Refresh(false);
                }
            }
        }
    }

    return true;
}

void wxToolBar::HandleMouseMove(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
{
    wxCoord x = GET_X_LPARAM(lParam),
            y = GET_Y_LPARAM(lParam);
    wxToolBarToolBase* tool = FindToolForPosition( x, y );

    // cursor left current tool
    if( tool != m_pInTool && !tool )
    {
        m_pInTool = 0;
        OnMouseEnter( -1 );
    }

    // cursor entered a tool
    if( tool != m_pInTool && tool )
    {
        m_pInTool = tool;
        OnMouseEnter( tool->GetId() );
    }
}

WXLRESULT wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
    switch ( nMsg )
    {
        case WM_MOUSEMOVE:
            // we don't handle mouse moves, so always pass the message to
            // wxControl::MSWWindowProc (HandleMouseMove just calls OnMouseEnter)
            HandleMouseMove(wParam, lParam);
            break;

        case WM_SIZE:
            if ( HandleSize(wParam, lParam) )
                return 0;
            break;

#ifndef __WXWINCE__
        case WM_PAINT:
            if ( HandlePaint(wParam, lParam) )
                return 0;
#endif
    }

    return wxControl::MSWWindowProc(nMsg, wParam, lParam);
}

// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------

WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height)
{
    MemoryHDC hdcMem;

    if ( !hdcMem )
    {
        wxLogLastError(_T("CreateCompatibleDC"));

        return bitmap;
    }

    SelectInHDC bmpInHDC(hdcMem, (HBITMAP)bitmap);

    if ( !bmpInHDC )
    {
        wxLogLastError(_T("SelectObject"));

        return bitmap;
    }

    wxCOLORMAP *cmap = wxGetStdColourMap();

    for ( int i = 0; i < width; i++ )
    {
        for ( int j = 0; j < height; j++ )
        {
            COLORREF pixel = ::GetPixel(hdcMem, i, j);

            for ( size_t k = 0; k < wxSTD_COL_MAX; k++ )
            {
                COLORREF col = cmap[k].from;
                if ( abs(GetRValue(pixel) - GetRValue(col)) < 10 &&
                     abs(GetGValue(pixel) - GetGValue(col)) < 10 &&
                     abs(GetBValue(pixel) - GetBValue(col)) < 10 )
                {
                    ::SetPixel(hdcMem, i, j, cmap[k].to);
                    break;
                }
            }
        }
    }

    return bitmap;

    // VZ: I leave here my attempts to map the bitmap to the system colours
    //     faster by using BitBlt() even though it's broken currently - but
    //     maybe someone else can finish it? It should be faster than iterating
    //     over all pixels...
#if 0
    MemoryHDC hdcMask, hdcDst;
    if ( !hdcMask || !hdcDst )
    {
        wxLogLastError(_T("CreateCompatibleDC"));

        return bitmap;
    }

    // create the target bitmap
    HBITMAP hbmpDst = ::CreateCompatibleBitmap(hdcDst, width, height);
    if ( !hbmpDst )
    {
        wxLogLastError(_T("CreateCompatibleBitmap"));

        return bitmap;
    }

    // create the monochrome mask bitmap
    HBITMAP hbmpMask = ::CreateBitmap(width, height, 1, 1, 0);
    if ( !hbmpMask )
    {
        wxLogLastError(_T("CreateBitmap(mono)"));

        ::DeleteObject(hbmpDst);

        return bitmap;
    }

    SelectInHDC bmpInDst(hdcDst, hbmpDst),
                bmpInMask(hdcMask, hbmpMask);

    // for each colour:
    for ( n = 0; n < NUM_OF_MAPPED_COLOURS; n++ )
    {
        // create the mask for this colour
        ::SetBkColor(hdcMem, ColorMap[n].from);
        ::BitBlt(hdcMask, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);

        // replace this colour with the target one in the dst bitmap
        HBRUSH hbr = ::CreateSolidBrush(ColorMap[n].to);
        HGDIOBJ hbrOld = ::SelectObject(hdcDst, hbr);

        ::MaskBlt(hdcDst, 0, 0, width, height,
                  hdcMem, 0, 0,
                  hbmpMask, 0, 0,
                  MAKEROP4(PATCOPY, SRCCOPY));

        (void)::SelectObject(hdcDst, hbrOld);
        ::DeleteObject(hbr);
    }

    ::DeleteObject((HBITMAP)bitmap);

    return (WXHBITMAP)hbmpDst;
#endif // 0
}

#endif // wxUSE_TOOLBAR && Win95

⌨️ 快捷键说明

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