notebook.cpp

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

CPP
1,389
字号
    TC_ITEM tcItem;
    tcItem.mask = TCIF_TEXT;
    tcItem.pszText = (wxChar *)strText.c_str();

    if ( !HasFlag(wxNB_MULTILINE) )
        return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;

    // multiline - we need to set new page size if a line is added or removed
    int rows = GetRowCount();
    bool ret = TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;

    if ( ret && rows != GetRowCount() )
    {
        const wxRect r = GetPageSize();
        const size_t count = m_pages.Count();
        for ( size_t page = 0; page < count; page++ )
            m_pages[page]->SetSize(r);
    }

    return ret;
}

wxString wxNotebook::GetPageText(size_t nPage) const
{
  wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("notebook page out of range") );

  wxChar buf[256];
  TC_ITEM tcItem;
  tcItem.mask = TCIF_TEXT;
  tcItem.pszText = buf;
  tcItem.cchTextMax = WXSIZEOF(buf);

  wxString str;
  if ( TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) )
    str = tcItem.pszText;

  return str;
}

int wxNotebook::GetPageImage(size_t nPage) const
{
  wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );

  TC_ITEM tcItem;
  tcItem.mask = TCIF_IMAGE;

  return TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) ? tcItem.iImage : -1;
}

bool wxNotebook::SetPageImage(size_t nPage, int nImage)
{
  wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );

  TC_ITEM tcItem;
  tcItem.mask = TCIF_IMAGE;
  tcItem.iImage = nImage;

  return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
}

void wxNotebook::SetImageList(wxImageList* imageList)
{
  wxNotebookBase::SetImageList(imageList);

  if ( imageList )
  {
    (void) TabCtrl_SetImageList(GetHwnd(), (HIMAGELIST)imageList->GetHIMAGELIST());
  }
}

// ----------------------------------------------------------------------------
// wxNotebook size settings
// ----------------------------------------------------------------------------

wxRect wxNotebook::GetPageSize() const
{
    wxRect r;

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

    // This check is to work around a bug in TabCtrl_AdjustRect which will
    // cause a crash on win2k or on XP with themes disabled if either
    // wxNB_MULTILINE is used or tabs are placed on a side, if the rectangle
    // is too small.
    //
    // The value of 20 is chosen arbitrarily but seems to work
    if ( rc.right > 20 && rc.bottom > 20 )
    {
        TabCtrl_AdjustRect(GetHwnd(), false, &rc);

        wxCopyRECTToRect(rc, r);
    }

    return r;
}

void wxNotebook::SetPageSize(const wxSize& size)
{
    // transform the page size into the notebook size
    RECT rc;
    rc.left =
    rc.top = 0;
    rc.right = size.x;
    rc.bottom = size.y;

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

    // and now set it
    SetSize(rc.right - rc.left, rc.bottom - rc.top);
}

void wxNotebook::SetPadding(const wxSize& padding)
{
    TabCtrl_SetPadding(GetHwnd(), padding.x, padding.y);
}

// Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
// style.
void wxNotebook::SetTabSize(const wxSize& sz)
{
    ::SendMessage(GetHwnd(), TCM_SETITEMSIZE, 0, MAKELPARAM(sz.x, sz.y));
}

wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
{
    wxSize sizeTotal = sizePage;

    // We need to make getting tab size part of the wxWidgets API.
    wxSize tabSize;
    if (GetPageCount() > 0)
    {
        RECT rect;
        TabCtrl_GetItemRect((HWND) GetHWND(), 0, & rect);
        tabSize.x = rect.right - rect.left;
        tabSize.y = rect.bottom - rect.top;
    }
    if ( HasFlag(wxNB_LEFT) || HasFlag(wxNB_RIGHT) )
    {
        sizeTotal.x += tabSize.x + 7;
        sizeTotal.y += 7;
    }
    else
    {
        sizeTotal.x += 7;
        sizeTotal.y += tabSize.y + 7;
    }

    return sizeTotal;
}

void wxNotebook::AdjustPageSize(wxNotebookPage *page)
{
    wxCHECK_RET( page, _T("NULL page in wxNotebook::AdjustPageSize") );

    const wxRect r = GetPageSize();
    if ( !r.IsEmpty() )
    {
        page->SetSize(r);
    }
}

// ----------------------------------------------------------------------------
// wxNotebook operations
// ----------------------------------------------------------------------------

// remove one page from the notebook, without deleting
wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage)
{
    wxNotebookPage *pageRemoved = wxNotebookBase::DoRemovePage(nPage);
    if ( !pageRemoved )
        return NULL;

    TabCtrl_DeleteItem(GetHwnd(), nPage);

    if ( m_pages.IsEmpty() )
    {
        // no selection any more, the notebook becamse empty
        m_nSelection = -1;
    }
    else // notebook still not empty
    {
        int selNew = TabCtrl_GetCurSel(GetHwnd());
        if (selNew != -1)
        {
            // No selection change, just refresh the current selection.
            // Because it could be that the slection index changed
            // we need to update it.
            // Note: this does not mean the selection it self changed.
            m_nSelection = selNew;
            m_pages[m_nSelection]->Refresh();
        }
        else if (int(nPage) == m_nSelection)
        {
            // The selection was deleted.

            // Determine new selection.
            if (m_nSelection == int(GetPageCount()))
                selNew = m_nSelection - 1;
            else
                selNew = m_nSelection;

            // m_nSelection must be always valid so reset it before calling
            // SetSelection()
            m_nSelection = -1;
            SetSelection(selNew);
        }
        else
        {
            wxFAIL; // Windows did not behave ok.
        }
    }

    return pageRemoved;
}

// remove all pages
bool wxNotebook::DeleteAllPages()
{
  size_t nPageCount = GetPageCount();
  size_t nPage;
  for ( nPage = 0; nPage < nPageCount; nPage++ )
    delete m_pages[nPage];

  m_pages.Clear();

  TabCtrl_DeleteAllItems(GetHwnd());

  m_nSelection = -1;

  InvalidateBestSize();
  return true;
}

// same as AddPage() but does it at given position
bool wxNotebook::InsertPage(size_t nPage,
                            wxNotebookPage *pPage,
                            const wxString& strText,
                            bool bSelect,
                            int imageId)
{
    wxCHECK_MSG( pPage != NULL, false, _T("NULL page in wxNotebook::InsertPage") );
    wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
                 _T("invalid index in wxNotebook::InsertPage") );

    wxASSERT_MSG( pPage->GetParent() == this,
                    _T("notebook pages must have notebook as parent") );

    // add a new tab to the control
    // ----------------------------

    // init all fields to 0
    TC_ITEM tcItem;
    wxZeroMemory(tcItem);

    // set the image, if any
    if ( imageId != -1 )
    {
        tcItem.mask |= TCIF_IMAGE;
        tcItem.iImage  = imageId;
    }

    // and the text
    if ( !strText.empty() )
    {
        tcItem.mask |= TCIF_TEXT;
        tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
    }

    // hide the page: unless it is selected, it shouldn't be shown (and if it
    // is selected it will be shown later)
    HWND hwnd = GetWinHwnd(pPage);
    SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);

    // this updates internal flag too -- otherwise it would get out of sync
    // with the real state
    pPage->Show(false);


    // fit the notebook page to the tab control's display area: this should be
    // done before adding it to the notebook or TabCtrl_InsertItem() will
    // change the notebooks size itself!
    AdjustPageSize(pPage);

    // finally do insert it
    if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
    {
        wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());

        return false;
    }

    // succeeded: save the pointer to the page
    m_pages.Insert(pPage, nPage);

    // we may need to adjust the size again if the notebook size changed:
    // normally this only happens for the first page we add (the tabs which
    // hadn't been there before are now shown) but for a multiline notebook it
    // can happen for any page at all as a new row could have been started
    if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
    {
        AdjustPageSize(pPage);
    }

    // now deal with the selection
    // ---------------------------

    // if the inserted page is before the selected one, we must update the
    // index of the selected page
    if ( int(nPage) <= m_nSelection )
    {
        // one extra page added
        m_nSelection++;
    }

    // some page should be selected: either this one or the first one if there
    // is still no selection
    int selNew = -1;
    if ( bSelect )
        selNew = nPage;
    else if ( m_nSelection == -1 )
        selNew = 0;

    if ( selNew != -1 )
        SetSelection(selNew);

    InvalidateBestSize();

    return true;
}

int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
{
    TC_HITTESTINFO hitTestInfo;
    hitTestInfo.pt.x = pt.x;
    hitTestInfo.pt.y = pt.y;
    int item = TabCtrl_HitTest(GetHwnd(), &hitTestInfo);

    if ( flags )
    {
        *flags = 0;

        if ((hitTestInfo.flags & TCHT_NOWHERE) == TCHT_NOWHERE)
            *flags |= wxNB_HITTEST_NOWHERE;
        if ((hitTestInfo.flags & TCHT_ONITEM) == TCHT_ONITEM)
            *flags |= wxNB_HITTEST_ONITEM;
        if ((hitTestInfo.flags & TCHT_ONITEMICON) == TCHT_ONITEMICON)
            *flags |= wxNB_HITTEST_ONICON;
        if ((hitTestInfo.flags & TCHT_ONITEMLABEL) == TCHT_ONITEMLABEL)
            *flags |= wxNB_HITTEST_ONLABEL;
    }

    return item;
}

// ----------------------------------------------------------------------------
// flicker-less notebook redraw
// ----------------------------------------------------------------------------

#if USE_NOTEBOOK_ANTIFLICKER

// wnd proc for the spin button
LRESULT APIENTRY _EXPORT wxNotebookSpinBtnWndProc(HWND hwnd,
                                                  UINT message,
                                                  WPARAM wParam,
                                                  LPARAM lParam)
{
    if ( message == WM_ERASEBKGND )
        return 0;

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

LRESULT APIENTRY _EXPORT wxNotebookWndProc(HWND hwnd,
                                           UINT message,
                                           WPARAM wParam,
                                           LPARAM lParam)
{
    return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebook,
                            hwnd, message, wParam, lParam);
}



void wxNotebook::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
{
    // do nothing here
}

void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event))
{
    wxPaintDC dc(this);
    wxMemoryDC memdc;
    RECT rc;
    ::GetClientRect(GetHwnd(), &rc);
    wxBitmap bmp(rc.right, rc.bottom);
    memdc.SelectObject(bmp);

    // if there is no special brush just use the solid background colour
#if wxUSE_UXTHEME
    HBRUSH hbr = (HBRUSH)m_hbrBackground;
#else
    HBRUSH hbr = 0;
#endif    
    wxBrush brush;
    if ( !hbr )
    {
        brush = wxBrush(GetBackgroundColour());
        hbr = GetHbrushOf(brush);
    }

    ::FillRect(GetHdcOf(memdc), &rc, hbr);

    MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);

    dc.Blit(0, 0, rc.right, rc.bottom, &memdc, 0, 0);
}

#endif // USE_NOTEBOOK_ANTIFLICKER

// ----------------------------------------------------------------------------
// wxNotebook callbacks
// ----------------------------------------------------------------------------

void wxNotebook::OnSize(wxSizeEvent& event)
{
    if ( GetPageCount() == 0 )
    {
        // Prevents droppings on resize, but does cause some flicker
        // when there are no pages.
        Refresh();
        event.Skip();
        return;
    }
#ifndef __WXWINCE__
    else
    {
        // Without this, we can sometimes get droppings at the edges
        // of a notebook, for example a notebook in a splitter window.
        // This needs to be reconciled with the RefreshRect calls
        // at the end of this function, which weren't enough to prevent
        // the droppings.

        wxSize sz = GetClientSize();

        // Refresh right side
        wxRect rect(sz.x-4, 0, 4, sz.y);
        RefreshRect(rect);

        // Refresh bottom side
        rect = wxRect(0, sz.y-4, sz.x, 4);
        RefreshRect(rect);

        // Refresh left side
        rect = wxRect(0, 0, 4, sz.y);
        RefreshRect(rect);
    }
#endif // !__WXWINCE__

    // fit all the notebook pages to the tab control's display area

    RECT rc;

⌨️ 快捷键说明

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