notebook.cpp

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

CPP
1,389
字号
    rc.left = rc.top = 0;
    GetSize((int *)&rc.right, (int *)&rc.bottom);

    // save the total size, we'll use it below
    int widthNbook = rc.right - rc.left,
        heightNbook = rc.bottom - rc.top;

    // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
    // returns completely false values for multiline tab controls after the tabs
    // are added but before getting the first WM_SIZE (off by ~50 pixels, see
    //
    // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
    //
    // and the only work around I could find was this ugly hack... without it
    // simply toggling the "multiline" checkbox in the notebook sample resulted
    // in a noticeable page displacement
    if ( HasFlag(wxNB_MULTILINE) )
    {
        // avoid an infinite recursion: we get another notification too!
        static bool s_isInOnSize = false;

        if ( !s_isInOnSize )
        {
            s_isInOnSize = true;
            SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
                    MAKELPARAM(rc.right, rc.bottom));
            s_isInOnSize = false;
        }
    }

#if wxUSE_UXTHEME
    // background bitmap size has changed, update the brush using it too
    UpdateBgBrush();
#endif // wxUSE_UXTHEME

    TabCtrl_AdjustRect(GetHwnd(), false, &rc);

    int width = rc.right - rc.left,
        height = rc.bottom - rc.top;
    size_t nCount = m_pages.Count();
    for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
        wxNotebookPage *pPage = m_pages[nPage];
        pPage->SetSize(rc.left, rc.top, width, height);
    }


    // unless we had already repainted everything, we now need to refresh
    if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
    {
        // invalidate areas not covered by pages
        RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
        RefreshRect(wxRect(0, rc.top, rc.left, height), false);
        RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
                    false);
        RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.right, height),
                    false);
    }

#if USE_NOTEBOOK_ANTIFLICKER
    // subclass the spin control used by the notebook to scroll pages to
    // prevent it from flickering on resize
    if ( !m_hasSubclassedUpdown )
    {
        // iterate over all child windows to find spin button
        for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
              child;
              child = ::GetWindow(child, GW_HWNDNEXT) )
        {
            wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);

            // see if it exists, if no wxWindow found then assume it's the spin
            // btn
            if ( !childWindow )
            {
                // subclass the spin button to override WM_ERASEBKGND
                if ( !gs_wndprocNotebookSpinBtn )
                    gs_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);

                wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
                m_hasSubclassedUpdown = true;
                break;
            }
        }
    }
#endif // USE_NOTEBOOK_ANTIFLICKER

    event.Skip();
}

void wxNotebook::OnSelChange(wxNotebookEvent& event)
{
  // is it our tab control?
  if ( event.GetEventObject() == this )
  {
      int sel = event.GetOldSelection();
      if ( sel != -1 )
        m_pages[sel]->Show(false);

      sel = event.GetSelection();
      if ( sel != -1 )
      {
        wxNotebookPage *pPage = m_pages[sel];
        pPage->Show(true);

        // As per bug report:
        // http://sourceforge.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
        // we should not set the page focus (and thereby the focus for
        // a child window) since it erroneously selects radio button controls and also
        // breaks keyboard handling for a notebook's scroll buttons. So
        // we always focus the notebook and not the page.
        SetFocus();

      }
      else // no pages in the notebook, give the focus to itself
      {
          SetFocus();
      }

      m_nSelection = sel;
  }

  // we want to give others a chance to process this message as well
  event.Skip();
}

bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
{
    const MSG * const msg = (MSG *)wxmsg;

    // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
    // TAB will be passed to the currently selected page, CTRL+TAB and
    // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
    // intercept SHIFT+TAB. This goes to the parent of the notebook which will
    // process it.
    if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
            msg->hwnd == GetHwnd() &&
                (wxIsCtrlDown() || !wxIsShiftDown()) )
    {
        return MSWProcessMessage(wxmsg);
    }

    return false;
}

void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
{
    if ( event.IsWindowChange() ) {
        // change pages
        AdvanceSelection(event.GetDirection());
    }
    else {
        // we get this event in 3 cases
        //
        // a) one of our pages might have generated it because the user TABbed
        // out from it in which case we should propagate the event upwards and
        // our parent will take care of setting the focus to prev/next sibling
        //
        // or
        //
        // b) the parent panel wants to give the focus to us so that we
        // forward it to our selected page. We can't deal with this in
        // OnSetFocus() because we don't know which direction the focus came
        // from in this case and so can't choose between setting the focus to
        // first or last panel child
        //
        // or
        //
        // c) we ourselves (see MSWTranslateMessage) generated the event
        //
        wxWindow * const parent = GetParent();

        // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
        const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
        const bool isFromSelf = event.GetEventObject() == (wxObject*) this;

        if ( isFromParent || isFromSelf )
        {
            // no, it doesn't come from child, case (b) or (c): forward to a
            // page but only if direction is backwards (TAB) or from ourselves,
            if ( m_nSelection != -1 &&
                    (!event.GetDirection() || isFromSelf) )
            {
                // so that the page knows that the event comes from it's parent
                // and is being propagated downwards
                event.SetEventObject(this);

                wxWindow *page = m_pages[m_nSelection];
                if ( !page->GetEventHandler()->ProcessEvent(event) )
                {
                    page->SetFocus();
                }
                //else: page manages focus inside it itself
            }
            else // otherwise set the focus to the notebook itself
            {
                SetFocus();
            }
        }
        else
        {
            // it comes from our child, case (a), pass to the parent, but only
            // if the direction is forwards. Otherwise set the focus to the
            // notebook itself. The notebook is always the 'first' control of a
            // page.
            if ( !event.GetDirection() )
            {
                SetFocus();
            }
            else if ( parent )
            {
                event.SetCurrentFocus(this);
                parent->GetEventHandler()->ProcessEvent(event);
            }
        }
    }
}

#if wxUSE_UXTHEME

bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
{
    wxUxThemeHandle theme(child ? child : this, L"TAB");
    if ( !theme )
        return false;

    // get the notebook client rect (we're not interested in drawing tabs
    // themselves)
    wxRect r = GetPageSize();
    if ( r.IsEmpty() )
        return false;

    RECT rc;
    wxCopyRectToRECT(r, rc);

    // map rect to the coords of the window we're drawing in
    if ( child )
        ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);

    // we have the content area (page size), but we need to draw all of the
    // background for it to be aligned correctly
    wxUxThemeEngine::Get()->GetThemeBackgroundExtent
                            (
                                theme,
                                (HDC) hDC,
                                9 /* TABP_PANE */,
                                0,
                                &rc,
                                &rc
                            );
    wxUxThemeEngine::Get()->DrawThemeBackground
                            (
                                theme,
                                (HDC) hDC,
                                9 /* TABP_PANE */,
                                0,
                                &rc,
                                NULL
                            );

    return true;
}

WXHBRUSH wxNotebook::QueryBgBitmap()
{
    wxRect r = GetPageSize();
    if ( r.IsEmpty() )
        return 0;

    WindowHDC hDC(GetHwnd());
    MemoryHDC hDCMem(hDC);
    CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);

    SelectInHDC selectBmp(hDCMem, hBmp);

    if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
        return 0;

    return (WXHBRUSH)::CreatePatternBrush(hBmp);
}

void wxNotebook::UpdateBgBrush()
{
    if ( m_hbrBackground )
        ::DeleteObject((HBRUSH)m_hbrBackground);

    if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
    {
        m_hbrBackground = QueryBgBitmap();
    }
    else // no themes or we've got user-defined solid colour
    {
        m_hbrBackground = NULL;
    }
}

WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
{
    if ( m_hbrBackground )
    {
        // before drawing with the background brush, we need to position it
        // correctly
        RECT rc;
        ::GetWindowRect((HWND)hWnd, &rc);

        ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);

        if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
        {
            wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
        }

        return m_hbrBackground;
    }

    return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
}

bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
{
    // solid background colour overrides themed background drawing
    if ( !UseBgCol() && DoDrawBackground(hDC, child) )
        return true;

    // If we're using a solid colour (for example if we've switched off
    // theming for this notebook), paint it
    if (UseBgCol())
    {
        wxRect r = GetPageSize();
        if ( r.IsEmpty() )
            return false;

        RECT rc;
        wxCopyRectToRECT(r, rc);

        // map rect to the coords of the window we're drawing in
        if ( child )
            ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);

        wxBrush brush(GetBackgroundColour());
        HBRUSH hbr = GetHbrushOf(brush);

        ::FillRect((HDC) hDC, &rc, hbr);

        return true;
    }

    return wxNotebookBase::MSWPrintChild(hDC, child);
}

#endif // wxUSE_UXTHEME

// Windows only: attempts to get colour for UX theme page background
wxColour wxNotebook::GetThemeBackgroundColour() const
{
#if wxUSE_UXTHEME
    if (wxUxThemeEngine::Get())
    {
        wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
        if (hTheme)
        {
            // This is total guesswork.
            // See PlatformSDK\Include\Tmschema.h for values
            COLORREF themeColor;
            wxUxThemeEngine::Get()->GetThemeColor(
                                        hTheme,
                                        10 /* TABP_BODY */,
                                        1 /* NORMAL */,
                                        3821 /* FILLCOLORHINT */,
                                        &themeColor);

            /*
            [DS] Workaround for WindowBlinds:
            Some themes return a near black theme color using FILLCOLORHINT,
            this makes notebook pages have an ugly black background and makes
            text (usually black) unreadable. Retry again with FILLCOLOR.

            This workaround potentially breaks appearance of some themes,
            but in practice it already fixes some themes.
            */
            if (themeColor == 1)
            {
                wxUxThemeEngine::Get()->GetThemeColor(
                                            hTheme,
                                            10 /* TABP_BODY */,
                                            1 /* NORMAL */,
                                            3802 /* FILLCOLOR */,
                                            &themeColor);
            }

            return wxRGBToColour(themeColor);
        }
    }
#endif // wxUSE_UXTHEME

    return GetBackgroundColour();
}

// ----------------------------------------------------------------------------
// wxNotebook base class virtuals
// ----------------------------------------------------------------------------

#if wxUSE_CONSTRAINTS

// override these 2 functions to do nothing: everything is done in OnSize

void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
{
  // don't set the sizes of the pages - their correct size is not yet known
  wxControl::SetConstraintSizes(false);
}

bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
{
  return true;
}

#endif // wxUSE_CONSTRAINTS

// ----------------------------------------------------------------------------
// wxNotebook Windows message handlers
// ----------------------------------------------------------------------------

bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
                             WXWORD pos, WXHWND control)
{
    // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
    // up-down control
    if ( control )
        return false;

    return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
}

bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
{
  wxNotebookEvent event(wxEVT_NULL, m_windowId);

  NMHDR* hdr = (NMHDR *)lParam;
  switch ( hdr->code ) {
    case TCN_SELCHANGE:
      event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
      break;

    case TCN_SELCHANGING:
      event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
      break;

    default:
      return wxControl::MSWOnNotify(idCtrl, lParam, result);
  }

  event.SetSelection(TabCtrl_GetCurSel(GetHwnd()));
  event.SetOldSelection(m_nSelection);
  event.SetEventObject(this);
  event.SetInt(idCtrl);

  bool processed = GetEventHandler()->ProcessEvent(event);
  *result = !event.IsAllowed();
  return processed;
}

#endif // wxUSE_NOTEBOOK

⌨️ 快捷键说明

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