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

📄 xlistbox.cpp

📁 俄罗斯人开发的大名鼎鼎的Pocket Pc 阅读器haaliread的源代码,visual c
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    for (i=0;i<x->num_items;++i) {
      free(x->items[i].text1);
      free(x->items[i].text2);
    }
    free(x->items);
    free(x->vitems);
    free(x);
    break;

  case WM_PAINT: {
    PAINTSTRUCT ps;
    hDC=::BeginPaint(hWnd,&ps);
    XLB_PaintAll(x,hDC);
    ::EndPaint(hWnd,&ps);
    break; }

  case WM_VSCROLL:
    i=-1;
    j=x->visible_items*x->item_height-x->scroll_page;
    switch (LOWORD(wParam)) {
    case SB_BOTTOM:
      i=j;
      break;
    case SB_LINEDOWN:
      i=min(x->top_offset+x->item_height,j);
      break;
    case SB_LINEUP:
      i=max(x->top_offset-x->item_height,0);
      break;
    case SB_PAGEDOWN:
      i=min(x->top_offset+x->scroll_page,j);
      break;
    case SB_PAGEUP:
      i=max(x->top_offset-x->scroll_page,0);
      break;
    case SB_THUMBPOSITION:
    case SB_THUMBTRACK: {
      SCROLLINFO si;
      si.cbSize=sizeof(si);
      si.fMask=SIF_TRACKPOS;
      ::GetScrollInfo(hWnd,SB_VERT,&si);
      i=min(si.nTrackPos,j);
      break; }
    case SB_TOP:
      i=0;
      break;
    }
    if (i>=0 && i<=j && i!=x->top_offset)
      XLB_ScrollTo(x,i);
    break;

  case WM_KEYDOWN:
    i=-1;
    j=XLB_GetVFromI(x,x->selection);
    switch (wParam) {
    case VK_RIGHT: case VK_ADD:
      // expand item
      if (x->flags & XLF_TREE && x->selection>=0 &&
	x->items[x->selection].flags & XIF_COLLAPSED &&
	XLB_HasChildren(x,x->selection))
      {
	x->items[x->selection].flags &= ~XIF_COLLAPSED;
	XLB_UpdateVisibleItems(x);
	XLB_UpdateScrollbar(x);
	::InvalidateRect(x->hWnd,NULL,FALSE);
      }
      return 0;
    case VK_LEFT: case VK_SUBTRACT:
      // collapse item
      if (x->flags & XLF_TREE && x->selection>=0 &&
	!(x->items[x->selection].flags & XIF_COLLAPSED) &&
	XLB_HasChildren(x,x->selection))
      {
	x->items[x->selection].flags |= XIF_COLLAPSED;
	XLB_UpdateVisibleItems(x);
	XLB_UpdateScrollbar(x);
	::InvalidateRect(x->hWnd,NULL,FALSE);
      }
      return 0;
    case VK_UP:
      i=j-1;
      break;
    case VK_DOWN:
      i=j+1;
      break;
    case VK_PRIOR:
      i=max(j-(x->scroll_page+x->item_height-1)/x->item_height,0);
      break;
    case VK_NEXT:
      i=min(j+(x->scroll_page+x->item_height-1)/x->item_height,x->visible_items-1);
      break;
    case VK_HOME:
      i=0;
      break;
    case VK_END:
      i=x->visible_items-1;
      break;
    }
    if (i>=0 && i<x->visible_items && i!=j) {
      j=i*x->item_height-x->top_offset;
      // if the item is not fully visible, then
      // scroll and repaint completely
      if (j<0 || j+x->item_height>x->scroll_page) {
	x->selection=XLB_GetIFromV(x,i);
	XLB_EnsureVisible2(x,x->selection);
	::InvalidateRect(x->hWnd,NULL,FALSE);
      } else
	XLB_SetSelection(hWnd,XLB_GetIFromV(x,i));
    }
    break;

  case WM_LBUTTONDOWN:
    i=(HIWORD(lParam)+x->top_offset)/x->item_height;
    if (i>=0 && i<x->visible_items) {
      j=XLB_GetIFromV(x,i);
      XLB_SetSelection(hWnd,j);

      // if we are in tree mode and hit a control icon,
      // then collapse/uncollapse an item
      if (x->flags & XLF_TREE && x->tree_icons) {
	int   iw,ih;
	::ImageList_GetIconSize(x->tree_icons,&iw,&ih);

	if (LOWORD(lParam) < x->items[j].level*INDENT_PER_LEVEL + iw &&
	    XLB_HasChildren(x,j))
	{
	  x->items[j].flags ^= XIF_COLLAPSED;
	  XLB_UpdateVisibleItems(x);
	  XLB_UpdateScrollbar(x);
	  ::InvalidateRect(x->hWnd,NULL,FALSE);
	}
      }
#if POCKETPC
      SHRGINFO	shrg;
      memset(&shrg,0,sizeof(shrg));
      shrg.cbSize=sizeof(shrg);
      shrg.hwndClient=hWnd;
      shrg.ptDown.x=LOWORD(lParam);
      shrg.ptDown.y=HIWORD(lParam);
      shrg.dwFlags=SHRG_RETURNCMD;
      if (SHRecognizeGesture(&shrg)==GN_CONTEXTMENU)
	::SendMessage(::GetParent(hWnd),XLM_CONTEXTMENU,lParam,(LPARAM)hWnd);
#endif
    }
    break;

  case WM_LBUTTONUP:
    i=(HIWORD(lParam)+x->top_offset)/x->item_height;
    if (i>=0 && i<x->visible_items && x->selection>=0)
      ::SendMessage(::GetParent(hWnd),XLM_CLICK,lParam,(LPARAM)hWnd);
    break;

  case WM_RBUTTONDOWN:
    i=(HIWORD(lParam)+x->top_offset)/x->item_height;
    if (i>=0 && i<x->visible_items) {
      XLB_SetSelection(hWnd,XLB_GetIFromV(x,i));
      ::SendMessage(::GetParent(hWnd),XLM_CONTEXTMENU,lParam,(LPARAM)hWnd);
    }
    break;

  case WM_LBUTTONDBLCLK:
    i=(HIWORD(lParam)+x->top_offset)/x->item_height;
    if (i>=0 && i<x->visible_items)
      ::SendMessage(::GetParent(hWnd),XLM_DBLCLK,lParam,(LPARAM)hWnd);
    break;

  case WM_GETDLGCODE:
    return DLGC_WANTARROWS | DLGC_WANTCHARS;

#if defined(WM_MOUSEWHEEL) && defined(SPI_GETWHEELSCROLLLINES) && defined(WHEEL_DELTA)
  case WM_MOUSEWHEEL: {
    UINT    lines=3;
    ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&lines,0);
    int	    scrl=(short)HIWORD(wParam)*(int)lines*x->item_height;
    scrl/=WHEEL_DELTA;
    j=x->visible_items*x->item_height-x->scroll_page;
    i=max(min(x->top_offset-scrl,j),0);
    if (i!=x->top_offset)
      XLB_ScrollTo(x,i);
    break; }
#endif

  default:
    return ::DefWindowProc(hWnd,uMsg,wParam,lParam);
  }

  return 0;
}

void  XLB_SetImageList(HWND hWnd,HIMAGELIST hIml,bool shared) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);
  if (!x)
    return;

  if (x->icons && !x->icons_shared)
    ::ImageList_Destroy(x->icons);

  x->icons=hIml;
  x->icons_shared=shared;

  if (hIml) {
    int	    dummy;
    ::ImageList_GetIconSize(hIml,&x->uicon_w,&dummy);
    x->uicon_w+=UICON_PAD*2;
  } else
    x->uicon_w=0;
}

void  XLB_UpdateScrollbar(XLB *x) {
  RECT	  rc;
  ::GetClientRect(x->hWnd,&rc);

  x->scroll_page=rc.bottom-rc.top;

  SCROLLINFO  si;
  memset(&si,0,sizeof(si));
  si.cbSize=sizeof(si);

  si.fMask=SIF_PAGE|SIF_RANGE;
  si.nMin=0;
  si.nMax=x->visible_items*x->item_height-1;
  if (si.nMax<x->scroll_page) {
    si.nMax=0;
    si.nPage=0;
  } else
    si.nPage=x->scroll_page;
  ::SetScrollInfo(x->hWnd,SB_VERT,&si,TRUE);
}

struct XLB_Handle *XLB_GetHandle(HWND hWnd) {
  return (XLB_Handle *)::GetWindowLong(hWnd,0);
}

bool  XLB_AppendItem(struct XLB_Handle *handle,
		     const TCHAR *text1,const TCHAR *text2,
		     int icon,int level,
		     LONG user_data)
{
  XLB	*x=(XLB*)handle;

  if (!x)
    return false;

  if (x->num_items >= x->max_items && !XLB_GrowList(x))
    return false;

  XLBItem *ii=&x->items[x->num_items];

  ii->text1=ii->text2=NULL;

  if (text1) {
    ii->text1=_tcsdup(text1);
    if (ii->text1==NULL)
      return false;
  }

  if (text2) {
    ii->text2=_tcsdup(text2);
    if (ii->text2==NULL) {
      free(ii->text1);
      return false;
    }
  }

  ii->icon_index=icon;
  ii->level=level;
  ii->user_data=user_data;
  ii->flags=0;

  x->num_items++;

  return true;
}

int	XLB_GetSelection(HWND hWnd) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x)
    return -1;

  return x->selection;
}

static void	XLB_GetItemRect(XLB *x,int item,RECT& r) {
  memset(&r,0,sizeof(r));

  if (item<0 || item>=x->num_items)
    return;

  item=XLB_GetVFromI(x,item);

  if (item<0)
    return;

  ::GetClientRect(x->hWnd,&r);

  r.top+=x->item_height*item;
  r.top-=x->top_offset;
  r.bottom=r.top+x->item_height;
}

static void	XLB_InvalidateItem(XLB *x,int item) {
  RECT	  ri;

  XLB_GetItemRect(x,item,ri);
  ::InvalidateRect(x->hWnd,&ri,FALSE);
}

void	XLB_SetSelection(HWND hWnd,int sel) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x || sel<0 || sel>=x->num_items || sel==x->selection)
    return;

  if (XLB_GetVFromI(x,sel)<0) {
    XLB_Restore(x,sel);
    XLB_UpdateScrollbar(x);
  }

  if (x->selection!=-1)
    XLB_InvalidateItem(x,x->selection);
  if (sel!=-1)
    XLB_InvalidateItem(x,sel);

  x->selection=sel;
}

int	XLB_GetItemCount(HWND hWnd) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x)
    return 0;

  return x->num_items;
}

LONG XLB_GetData(HWND hWnd,int item) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x || item<0 || item>=x->num_items)
    return 0;

  return x->items[item].user_data;
}

void	XLB_EnsureVisible(HWND hWnd,int item,bool middle) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x || item<0 || item>=x->num_items)
    return;

  int	v=XLB_GetVFromI(x,item);

  if (v<0) { // item is not currently visble
    XLB_Restore(x,item);
    XLB_UpdateScrollbar(x);
    v=XLB_GetVFromI(x,item);
  }

  int   cvis=x->scroll_page/x->item_height; // completely visible items
  if (cvis==0)
    cvis=1;

  if (middle) { // scroll the view so the item is in the middle
    int	  new_offset=(v-cvis/2)*x->item_height;
    if (new_offset+x->scroll_page > x->visible_items*x->item_height)
      new_offset=x->visible_items*x->item_height - x->scroll_page;
    if (new_offset<0)
      new_offset=0;

    if (x->top_offset != new_offset)
      XLB_ScrollTo(x,new_offset);
    return;
  }

  int item_offset=v*x->item_height-x->top_offset;
  // if the item is not fully visible, then
  // scroll and repaint completely
  if (item_offset<0)
    XLB_ScrollTo(x,v*x->item_height);
  else if (item_offset+x->item_height>x->scroll_page)
    XLB_ScrollTo(x,(v-cvis+1)*x->item_height);
}

// TODO: avoid unneeded redraws
void	XLB_DeleteItem(HWND hWnd,int item) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x || item<0 || item>=x->num_items)
    return;

  free(x->items[item].text1);
  free(x->items[item].text2);

  memmove(&x->items[item],&x->items[item+1],sizeof(XLBItem)*(x->num_items-item-1));

  x->num_items--;

  if (x->selection>=x->num_items)
    x->selection=x->num_items-1;

  XLB_UpdateVisibleItems(x);

  XLB_EnsureVisible(hWnd,x->selection);
  ::InvalidateRect(hWnd,NULL,FALSE);
  XLB_UpdateScrollbar(x);
}

void	XLB_SetItemText1(HWND hWnd,int item,const TCHAR *text) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x || item<0 || item>=x->num_items)
    return;

  free(x->items[item].text1);
  x->items[item].text1=_tcsdup(text);

  XLB_InvalidateItem(x,item);
}

void	XLB_DeleteAllItems(HWND hWnd) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x)
    return;

  for (int i=0;i<x->num_items;++i) {
    free(x->items[i].text1);
    free(x->items[i].text2);
  }

  x->num_items=0;
  x->visible_items=0;
  x->selection=-1;
  x->top_offset=0;
  ::SetScrollPos(hWnd,SB_VERT,0,TRUE);
  XLB_UpdateScrollbar(x);
}

void  XLB_UpdateState(HWND hWnd) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x)
    return;

  XLB_UpdateVisibleItems(x);
  XLB_UpdateScrollbar(x);
}

void  XLB_CollapseLevel(HWND hWnd,int level) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x)
    return;

  if (level<0)
    level = 0x7fffffff; // XXX should be maxint

  XLBItem *ii=x->items;
  XLBItem *jj=ii+x->num_items;

  while (ii<jj) {
    if (ii->level >= level)
      ii->flags |= XIF_COLLAPSED;
    else
      ii->flags &= ~XIF_COLLAPSED;
    ++ii;
  }

  if (x->top_offset >= x->visible_items)
    x->top_offset = 0; // XXX can do something better

  XLB_UpdateState(hWnd);
  ::InvalidateRect(hWnd,NULL,FALSE); // XXX can be avoided sometimes
}

// custom sort function
static int  compare_items(const void *v1,const void *v2) {
  const XLBItem *i1=(XLBItem*)v1;
  const XLBItem *i2=(XLBItem*)v2;

  int   i=i1->user_data-i2->user_data;
  if (i!=0)
    return i;
  bool	e1=!i1->text1 || !*i1->text1;
  bool	e2=!i2->text1 || !*i2->text1;
  if (e1)
    return e2 ? 0 : -1;
  if (e2)
    return 1;
  return CmpI(i1->text1,i2->text1);
}

void	XLB_SortItems(HWND hWnd) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x)
    return;

  qsort(x->items,x->num_items,sizeof(XLBItem),compare_items);
}

const TCHAR *XLB_GetItemText1(HWND hWnd,int item) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x || item<0 || item>=x->num_items)
    return NULL;

  return x->items[item].text1;
}

void	XLB_SetGTFunc(HWND hWnd,XLB_GetText fn,void *ugtdata) {
  XLB	*x=(XLB*)::GetWindowLong(hWnd,0);

  if (!x)
    return;

  x->gtf=fn;
  x->gtdata=ugtdata;
}


void   XLB_Init() {
  WNDCLASS    wc;

  memset(&wc,0,sizeof(wc));

  wc.style=CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
  wc.lpfnWndProc=XLB_WndProc;
  wc.cbWndExtra=sizeof(XLB*);
  wc.hInstance=::GetModuleHandle(NULL);
  // assume the SDK always defines this via macro
#if defined(LoadCursor)
  wc.hCursor=::LoadCursor(NULL,IDC_ARROW);
#endif
  wc.lpszClassName=_T("XListBox");

  ATOM cls=::RegisterClass(&wc);
}

⌨️ 快捷键说明

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