⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tab.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * Tab control
 *
 * Copyright 1998 Anders Carlsson
 * Copyright 1999 Alex Priem <alexp@sci.kun.nl>
 * Copyright 1999 Francis Beaudet
 * Copyright 2003 Vitaliy Margolen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * NOTES
 *
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on May. 20, 2005, by James Hawkins.
 *
 * Unless otherwise noted, we believe this code to be complete, as per
 * the specification mentioned above.
 * If you discover missing features, or bugs, please note them below.
 *
 * TODO:
 *
 *  Styles:
 *   TCS_MULTISELECT
 *   TCS_RIGHT
 *   TCS_RIGHTJUSTIFY
 *   TCS_SCROLLOPPOSITE
 *   TCS_SINGLELINE
 *   TCIF_RTLREADING
 *
 *  Extended Styles:
 *   TCS_EX_FLATSEPARATORS
 *   TCS_EX_REGISTERDROP
 *
 *  States:
 *   TCIS_BUTTONPRESSED
 *
 *  Notifications:
 *   NM_RELEASEDCAPTURE
 *   TCN_FOCUSCHANGE
 *   TCN_GETOBJECT
 *   TCN_KEYDOWN
 *
 *  Messages:
 *   TCM_REMOVEIMAGE
 *   TCM_DESELECTALL
 *   TCM_GETEXTENDEDSTYLE
 *   TCM_SETEXTENDEDSTYLE
 *
 *  Macros:
 *   TabCtrl_AdjustRect
 *
 */

#include <stdarg.h>
#include <string.h>

#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "commctrl.h"
#include "comctl32.h"
#include "uxtheme.h"
#include "tmschema.h"
#include "wine/debug.h"
#include <math.h>

WINE_DEFAULT_DEBUG_CHANNEL(tab);

typedef struct
{
  UINT   mask;
  DWORD  dwState;
  LPWSTR pszText;
  INT    iImage;
  RECT   rect;      /* bounding rectangle of the item relative to the
                     * leftmost item (the leftmost item, 0, would have a
                     * "left" member of 0 in this rectangle)
                     *
                     * additionally the top member holds the row number
                     * and bottom is unused and should be 0 */
  BYTE   extra[1];  /* Space for caller supplied info, variable size */
} TAB_ITEM;

/* The size of a tab item depends on how much extra data is requested */
#define TAB_ITEM_SIZE(infoPtr) (sizeof(TAB_ITEM) - sizeof(BYTE) + infoPtr->cbInfo)

typedef struct
{
  HWND       hwnd;            /* Tab control window */
  HWND       hwndNotify;      /* notification window (parent) */
  UINT       uNumItem;        /* number of tab items */
  UINT       uNumRows;	      /* number of tab rows */
  INT        tabHeight;       /* height of the tab row */
  INT        tabWidth;        /* width of tabs */
  INT        tabMinWidth;     /* minimum width of items */
  USHORT     uHItemPadding;   /* amount of horizontal padding, in pixels */
  USHORT     uVItemPadding;   /* amount of vertical padding, in pixels */
  USHORT     uHItemPadding_s; /* Set amount of horizontal padding, in pixels */
  USHORT     uVItemPadding_s; /* Set amount of vertical padding, in pixels */
  HFONT      hFont;           /* handle to the current font */
  HCURSOR    hcurArrow;       /* handle to the current cursor */
  HIMAGELIST himl;            /* handle to an image list (may be 0) */
  HWND       hwndToolTip;     /* handle to tab's tooltip */
  INT        leftmostVisible; /* Used for scrolling, this member contains
                               * the index of the first visible item */
  INT        iSelected;       /* the currently selected item */
  INT        iHotTracked;     /* the highlighted item under the mouse */
  INT        uFocus;          /* item which has the focus */
  TAB_ITEM*  items;           /* pointer to an array of TAB_ITEM's */
  BOOL       DoRedraw;        /* flag for redrawing when tab contents is changed*/
  BOOL       needsScrolling;  /* TRUE if the size of the tabs is greater than
                               * the size of the control */
  BOOL       fHeightSet;      /* was the height of the tabs explicitly set? */
  BOOL       bUnicode;        /* Unicode control? */
  HWND       hwndUpDown;      /* Updown control used for scrolling */
  INT        cbInfo;          /* Number of bytes of caller supplied info per tab */
} TAB_INFO;

/******************************************************************************
 * Positioning constants
 */
#define SELECTED_TAB_OFFSET     2
#define ROUND_CORNER_SIZE       2
#define DISPLAY_AREA_PADDINGX   2
#define DISPLAY_AREA_PADDINGY   2
#define CONTROL_BORDER_SIZEX    2
#define CONTROL_BORDER_SIZEY    2
#define BUTTON_SPACINGX         3
#define BUTTON_SPACINGY         3
#define FLAT_BTN_SPACINGX       8
#define DEFAULT_MIN_TAB_WIDTH   54
#define DEFAULT_TAB_WIDTH_FIXED 96
#define DEFAULT_PADDING_X       6
#define EXTRA_ICON_PADDING      3

#define TAB_GetInfoPtr(hwnd) ((TAB_INFO *)GetWindowLongPtrW(hwnd,0))
/* Since items are variable sized, cannot directly access them */
#define TAB_GetItem(info,i) \
  ((TAB_ITEM*)((LPBYTE)info->items + (i) * TAB_ITEM_SIZE(info)))

#define GET_DEFAULT_MIN_TAB_WIDTH(infoPtr) (DEFAULT_MIN_TAB_WIDTH - (DEFAULT_PADDING_X - (infoPtr)->uHItemPadding) * 2)

/******************************************************************************
 * Hot-tracking timer constants
 */
#define TAB_HOTTRACK_TIMER            1
#define TAB_HOTTRACK_TIMER_INTERVAL   100   /* milliseconds */

static const WCHAR themeClass[] = { 'T','a','b',0 };

/******************************************************************************
 * Prototypes
 */
static void TAB_InvalidateTabArea(TAB_INFO *);
static void TAB_EnsureSelectionVisible(TAB_INFO *);
static void TAB_DrawItemInterior(TAB_INFO *, HDC, INT, RECT*);

static BOOL
TAB_SendSimpleNotify (const TAB_INFO *infoPtr, UINT code)
{
    NMHDR nmhdr;

    nmhdr.hwndFrom = infoPtr->hwnd;
    nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwnd, GWLP_ID);
    nmhdr.code = code;

    return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
            (WPARAM) nmhdr.idFrom, (LPARAM) &nmhdr);
}

static void
TAB_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
            WPARAM wParam, LPARAM lParam)
{
    MSG msg;

    msg.hwnd = hwndMsg;
    msg.message = uMsg;
    msg.wParam = wParam;
    msg.lParam = lParam;
    msg.time = GetMessageTime ();
    msg.pt.x = (short)LOWORD(GetMessagePos ());
    msg.pt.y = (short)HIWORD(GetMessagePos ());

    SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
}

static void
TAB_DumpItemExternalT(TCITEMW *pti, UINT iItem, BOOL isW)
{
    if (TRACE_ON(tab)) {
	TRACE("external tab %d, mask=0x%08x, dwState=0x%08x, dwStateMask=0x%08x, cchTextMax=0x%08x\n",
	      iItem, pti->mask, pti->dwState, pti->dwStateMask, pti->cchTextMax);
	TRACE("external tab %d,   iImage=%d, lParam=0x%08lx, pszTextW=%s\n",
	      iItem, pti->iImage, pti->lParam, isW ? debugstr_w(pti->pszText) : debugstr_a((LPSTR)pti->pszText));
    }
}

static void
TAB_DumpItemInternal(TAB_INFO *infoPtr, UINT iItem)
{
    if (TRACE_ON(tab)) {
	TAB_ITEM *ti;

	ti = TAB_GetItem(infoPtr, iItem);
	TRACE("tab %d, mask=0x%08x, dwState=0x%08x, pszText=%s, iImage=%d\n",
	      iItem, ti->mask, ti->dwState, debugstr_w(ti->pszText),
	      ti->iImage);
	TRACE("tab %d, rect.left=%d, rect.top(row)=%d\n",
	      iItem, ti->rect.left, ti->rect.top);
    }
}

/* RETURNS
 *   the index of the selected tab, or -1 if no tab is selected. */
static inline LRESULT TAB_GetCurSel (const TAB_INFO *infoPtr)
{
    return infoPtr->iSelected;
}

/* RETURNS
 *   the index of the tab item that has the focus
 * NOTE
 *   we have not to return negative value
 * TODO
 *   test for windows */
static inline LRESULT
TAB_GetCurFocus (const TAB_INFO *infoPtr)
{
    if (infoPtr->uFocus<0)
    {
        FIXME("we have not to return negative value\n");
        return 0;
    }
    return infoPtr->uFocus;
}

static inline LRESULT TAB_GetToolTips (const TAB_INFO *infoPtr)
{
    if (infoPtr == NULL) return 0;
    return (LRESULT)infoPtr->hwndToolTip;
}

static inline LRESULT TAB_SetCurSel (TAB_INFO *infoPtr, INT iItem)
{
  INT prevItem = -1;

  if (iItem >= 0 && iItem < infoPtr->uNumItem) {
      prevItem=infoPtr->iSelected;
      if (infoPtr->iSelected != iItem) {
          infoPtr->iSelected=iItem;
          TAB_EnsureSelectionVisible(infoPtr);
          TAB_InvalidateTabArea(infoPtr);
      }
  }
  return prevItem;
}

static LRESULT TAB_SetCurFocus (TAB_INFO *infoPtr, INT iItem)
{
  if (iItem < 0 || iItem >= infoPtr->uNumItem) return 0;

  if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_BUTTONS) {
    FIXME("Should set input focus\n");
  } else {
    int oldFocus = infoPtr->uFocus;
    if (infoPtr->iSelected != iItem || oldFocus == -1 ) {
      infoPtr->uFocus = iItem;
      if (oldFocus != -1) {
        if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING))  {
          infoPtr->iSelected = iItem;
          TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
        }
        else
          infoPtr->iSelected = iItem;
        TAB_EnsureSelectionVisible(infoPtr);
        TAB_InvalidateTabArea(infoPtr);
      }
    }
  }
  return 0;
}

static inline LRESULT
TAB_SetToolTips (TAB_INFO *infoPtr, HWND hwndToolTip)
{
    if (infoPtr)
        infoPtr->hwndToolTip = hwndToolTip;
    return 0;
}

static inline LRESULT
TAB_SetPadding (TAB_INFO *infoPtr, LPARAM lParam)
{
    if (infoPtr)
    {
        infoPtr->uHItemPadding_s=LOWORD(lParam);
        infoPtr->uVItemPadding_s=HIWORD(lParam);
    }
    return 0;
}

/******************************************************************************
 * TAB_InternalGetItemRect
 *
 * This method will calculate the rectangle representing a given tab item in
 * client coordinates. This method takes scrolling into account.
 *
 * This method returns TRUE if the item is visible in the window and FALSE
 * if it is completely outside the client area.
 */
static BOOL TAB_InternalGetItemRect(
  const TAB_INFO* infoPtr,
  INT         itemIndex,
  RECT*       itemRect,
  RECT*       selectedRect)
{
  RECT tmpItemRect,clientRect;
  LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);

  /* Perform a sanity check and a trivial visibility check. */
  if ( (infoPtr->uNumItem <= 0) ||
       (itemIndex >= infoPtr->uNumItem) ||
       (!((lStyle & TCS_MULTILINE) || (lStyle & TCS_VERTICAL)) && (itemIndex < infoPtr->leftmostVisible)) )
    {
        TRACE("Not Visible\n");
        /* need to initialize these to empty rects */
        if (itemRect)
        {
            memset(itemRect,0,sizeof(RECT));
            itemRect->bottom = infoPtr->tabHeight;
        }
        if (selectedRect)
            memset(selectedRect,0,sizeof(RECT));
        return FALSE;
    }

  /*
   * Avoid special cases in this procedure by assigning the "out"
   * parameters if the caller didn't supply them
   */
  if (itemRect == NULL)
    itemRect = &tmpItemRect;

  /* Retrieve the unmodified item rect. */
  *itemRect = TAB_GetItem(infoPtr,itemIndex)->rect;

  /* calculate the times bottom and top based on the row */
  GetClientRect(infoPtr->hwnd, &clientRect);

  if ((lStyle & TCS_BOTTOM) && (lStyle & TCS_VERTICAL))
  {
    itemRect->right  = clientRect.right - SELECTED_TAB_OFFSET - itemRect->left * infoPtr->tabHeight -
                       ((lStyle & TCS_BUTTONS) ? itemRect->left * BUTTON_SPACINGX : 0);
    itemRect->left   = itemRect->right - infoPtr->tabHeight;
  }
  else if (lStyle & TCS_VERTICAL)
  {
    itemRect->left   = clientRect.left + SELECTED_TAB_OFFSET + itemRect->left * infoPtr->tabHeight +
                       ((lStyle & TCS_BUTTONS) ? itemRect->left * BUTTON_SPACINGX : 0);
    itemRect->right  = itemRect->left + infoPtr->tabHeight;
  }
  else if (lStyle & TCS_BOTTOM)
  {
    itemRect->bottom = clientRect.bottom - itemRect->top * infoPtr->tabHeight -
                       ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET);
    itemRect->top    = itemRect->bottom - infoPtr->tabHeight;
  }
  else /* not TCS_BOTTOM and not TCS_VERTICAL */
  {
    itemRect->top    = clientRect.top + itemRect->top * infoPtr->tabHeight +
                       ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET);
    itemRect->bottom = itemRect->top + infoPtr->tabHeight;
 }

  /*
   * "scroll" it to make sure the item at the very left of the
   * tab control is the leftmost visible tab.
   */
  if(lStyle & TCS_VERTICAL)
  {
    OffsetRect(itemRect,
	     0,
	     -TAB_GetItem(infoPtr, infoPtr->leftmostVisible)->rect.top);

    /*
     * Move the rectangle so the first item is slightly offset from
     * the bottom of the tab control.
     */
    OffsetRect(itemRect,
	     0,
	     SELECTED_TAB_OFFSET);

  } else
  {
    OffsetRect(itemRect,
	     -TAB_GetItem(infoPtr, infoPtr->leftmostVisible)->rect.left,
	     0);

    /*
     * Move the rectangle so the first item is slightly offset from
     * the left of the tab control.
     */
    OffsetRect(itemRect,
	     SELECTED_TAB_OFFSET,
	     0);
  }
  TRACE("item %d tab h=%d, rect=(%d,%d)-(%d,%d)\n",
	itemIndex, infoPtr->tabHeight,
	itemRect->left, itemRect->top, itemRect->right, itemRect->bottom);

  /* Now, calculate the position of the item as if it were selected. */
  if (selectedRect!=NULL)
  {
    CopyRect(selectedRect, itemRect);

    /* The rectangle of a selected item is a bit wider. */
    if(lStyle & TCS_VERTICAL)
      InflateRect(selectedRect, 0, SELECTED_TAB_OFFSET);
    else

⌨️ 快捷键说明

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