📄 osdtreeview.c
字号:
#include "osdwindows.h"
#include"osdcommctrl.h"
#define TVBoxHalfHeight 4
#define TVBoxGap 3
#define TVICONGAP 3 /*ICON 间隙宽度*/
#define ICON_FOLD 1//GetLargeSystemIcon (5)
#define ICON_UNFOLD 2 // GetLargeSystemIcon (6)
/*****************************************************************************
*****************************************************************************/
typedef struct tagTVDATA
{
DWORD dwStyle; // draw icon or not;
INT nVisCount; // how many items can be showed in client area.
INT nItemHeight; // the height of one item.
INT nItemCount; // Number of all items in treeview.
INT nVisItemCount; //可视项总数 Number of items which can(not should) be drawed in client area. That means excluding children of fold items.
INT nItemTop; // how many items are above the client area and should not be drawed.
INT nWidth; // the width of treeview.
INT nVisWidth; // how many pixels can be showed in client area.
PTVITEM pItemSelected; // this item is selected.
PTVITEM root; //根节点 the root item of treeview.
} TVDATA,* PTVDATA;
static UINT TreeViewCtrlProc (HWND hwnd, int message, WPARAM wParam, LPARAM lParam);
/*****************************************************************************
*****************************************************************************/
BOOL RegisterTreeViewCtrl (void)
{
WNDCLASS wc;
// wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_GLOBALCLASS;
wc.WndProc = (WNDPROC)TreeViewCtrlProc;
// wc.cbClsExtra = 0;
// wc.cbWndExtra = 10;
// wc.hInstance = hInstance;
// wc.hIcon = NULL;
// wc.hCursor = 0;
// wc.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
// wc.lpszMenuName = NULL;
wc.ClassName= "TREEVIEW";
return RegisterClass(&wc);
}
/*****************************************************************************
Initialize Treeview.
*****************************************************************************/
static BOOL tvInitTVData (HWND hwnd, PTVDATA pData, DWORD dwStyle)
{
PTVITEM tvRoot;
HDC hdc;
pData->dwStyle = dwStyle;
//创建根节点
if (!(tvRoot =(PTVITEM)PrMalloc(sizeof(TVITEM))))return FALSE;
tvRoot->text = strdup ("Root");
tvRoot->dwFlags = TVI_ROOT | TVIS_SELECTED;
tvRoot->child = tvRoot->next = NULL;
hdc = GetDC (hwnd);
pData->nItemHeight = MAX(16,GetSysCCharWidth(hwnd)); /*起码要比图标大*/
pData->nVisItemCount = 1;
pData->nItemCount = 1;
pData->root = tvRoot;
pData->pItemSelected = tvRoot;
pData->nItemTop = 0;
GetTextExtentPoint(hdc, tvRoot->text, -1, &tvRoot->text_ext);
pData->nWidth = TVBoxGap + pData->nItemHeight + tvRoot->text_ext.cx;
/*houzhif (pData->dwStyle & TVS_WITHICON)
pData->nWidth += pData->nItemHeight + TVICONGAP;*/
ReleaseDC (hwnd, hdc);
return TRUE;
}
/*****************************************************************************
*****************************************************************************/
static PTVITEM findParent (PTVITEM root, PTVITEM pChild)
{
PTVITEM q = root->child; // recursive function.
PTVITEM t;
while (q != NULL && q !=pChild)
{
if (( t = findParent (q, pChild)) != NULL)
return t;
q = q->next;
}
if (q == pChild)
return root;
else
return NULL;
}
/*****************************************************************************
*****************************************************************************/
static PTVITEM getParent (PTVDATA pData, PTVITEM pChild)
{
if (pChild == pData->root || pChild == NULL) // the given node.
return NULL;
return findParent (pData->root, pChild);
}
/*****************************************************************************
取前一节点
*****************************************************************************/
static PTVITEM getPrev (PTVDATA pData, PTVITEM pCur)
{
PTVITEM p,t; // sibling is current node.
p = getParent (pData, pCur);
if (p == NULL || p->child == pCur) return NULL;
t = p->child;
while (t->next != NULL && t->next != pCur)
t = t->next;
if (t->next != pCur)
return NULL;
return t;
}
/*****************************************************************************
展开全部节点
*****************************************************************************/
static void UnfoldAll (PTVITEM p)
{
PTVITEM t;
if (p == NULL) return;
p->dwFlags &= ~TVIS_BOLD;
t = p->child;
while (t)
{
UnfoldAll (t);
t = t->next;
}
}
/*****************************************************************************
计算p节点下显示项总数
*****************************************************************************/
static int VisItemCount (PTVITEM p, int c)
{
PTVITEM t;
static int count;
count = c;
count++;
if (!(p->dwFlags & TVIS_BOLD)) /*展开*/
{
t = p->child;
while (t)
{
VisItemCount (t, count);
t = t->next;
}
}
return count;
}
/*****************************************************************************
计算控件的显示项总数
*****************************************************************************/
static int getVisItemCount (PTVDATA pData)
{
if (pData->root == NULL)
return 0;
return VisItemCount (pData->root, 0);
}
/*****************************************************************************
取pcur 到pTgt 之间有多少行
*****************************************************************************/
static int Itemdeep (PTVITEM pCur, PTVITEM pTgt, int d)
{
static int deep;
int q = 0;
PTVITEM t;
deep = d;
if (pCur == pTgt)
return deep;
else
{
t = pCur->child;
deep++;
while (t != NULL && !(q = Itemdeep (t, pTgt, deep)))
t = t->next;
}
deep--;
return q;
}
/*****************************************************************************
取ptGt到根节点有多少行(不管是否展开)
*****************************************************************************/
static int getItemdeep (PTVDATA pData, PTVITEM pTgt)
{
if (pTgt == NULL || pTgt == pData->root)
return 0;
return Itemdeep (pData->root, pTgt, 0);
}
/*****************************************************************************
*****************************************************************************/
static int TVWidth (PTVDATA pData, PTVITEM p, int w)
{
PTVITEM t;
static int width;
int wtemp, h;
h = pData->nItemHeight;
width = w;
wtemp = TVBoxGap + h + TVBoxGap + getItemdeep (pData, p) * h + p->text_ext.cx;
if (pData->dwStyle & TVS_WITHICON) wtemp += h + TVICONGAP;
width = MAX (wtemp, width);
if (!(p->dwFlags & TVIF_FOLD))
{
t = p->child;
while (t)
{
TVWidth (pData, t, width);
t = t->next;
}
}
return width;
}
/*****************************************************************************
计算节点占据的最大宽度
*****************************************************************************/
static int getTVWidth (PTVDATA pData)
{
return TVWidth (pData, pData->root, 0);
}
/*****************************************************************************
删除节点
*****************************************************************************/
static void RemoveSubTree (PTVDATA pData, PTVITEM p) // Used by RemoveTree().
{
PTVITEM q, n;
if (p == NULL )
return; // recursive function.
q = p->child;
while (q != NULL) /*删除其下的子节点*/
{
n = q->next;
RemoveSubTree (pData, q);
q = n;
}
mwOsFreeMemory (p->text);
mwOsFreeMemory (p);
pData->nItemCount--;
}
/*****************************************************************************
*****************************************************************************/
static void RemoveTree (HWND hwnd, PTVDATA pData, PTVITEM pChild) // Remove a tree or subtree.
{
PTVITEM p, q;
if (pChild == NULL) return;
if (pChild == pData->root) /*根节点*/
{
pData->root = NULL;
pData->pItemSelected = NULL;
pData->nVisItemCount = 1;
pData->nWidth = 1;
pData->nItemTop = 0;
RemoveSubTree (pData, pChild);
}
else
{
p = pData->pItemSelected = getParent (pData, pChild); /*将父节点变为当前项*/
if (pChild == p->child)
p->child = pChild->next;
else
{
q = p->child;
while (q !=NULL && q->next != pChild)
q = q->next;
q->next = pChild->next;
}
RemoveSubTree (pData, pChild);
pData->nWidth = getTVWidth (pData);
pData->nVisItemCount = getVisItemCount (pData);
}
}
/*****************************************************************************
在p节点及子节点查找字符串
*****************************************************************************/
static PTVITEM findString (PTVITEM p, char* string)
{
PTVITEM q, t = NULL;
if (!strcmp (p->text, string))
return p;
else
{
q = p->child;
while (q != NULL && !(t = findString (q, string)))
q = q->next;
}
return t;
}
/*****************************************************************************
在整个树中查找字符串
*****************************************************************************/
static PTVITEM find (PTVDATA pData, char* string)
{
if (pData->root == NULL)
return NULL;
return findString (pData->root, string);
}
/*****************************************************************************
*****************************************************************************/
static int countPrevNext (PTVDATA pData, PTVITEM prev, int c)
{
static int count;
PTVITEM t;
count = c;
count++;
if (!(prev->dwFlags & TVIF_FOLD))
{
t = prev->child;
while (t)
{
countPrevNext (pData, t, count);
t = t->next;
}
}
return count;
}
/*****************************************************************************
取前一节点项目数
*****************************************************************************/
static int getItemsWithPrev (PTVDATA pData, PTVITEM pCur)
{
PTVITEM prev = getPrev(pData, pCur);
if (prev == NULL)
return 0;
return countPrevNext (pData, prev, 0) - 1;
}
/*****************************************************************************
取后一节点项目数
*****************************************************************************/
static int getItemsWithNext (PTVDATA pData, PTVITEM pCur)
{
if (pCur == NULL || pCur->next == NULL)
return 0;
return countPrevNext (pData, pCur, 0) - 1;
}
/*****************************************************************************
插入节点
input: parent-父节点, pchild-要插入的子节点
*****************************************************************************/
static void InsertChild (HWND hwnd, PTVDATA pData, PTVITEM pParent, PTVITEM pChild)
{
PTVITEM p, t = NULL; // Add a node.
int deep, h, w;
HDC hdc;
if (pChild == NULL) return;
pChild->child = pChild->next = NULL;
if (pParent == NULL) pParent = pData->pItemSelected; /*如果父为空,则父为当前选中项*/
if (pParent->child == NULL)
pParent->child = pChild;
else if (pData->dwStyle & TVS_SORT)
{
p = pParent->child;
while (strcmp(pChild->text, p->text) > 0 && p->next != NULL)
{
t = p;
p = p->next;
}
if (strcmp(pChild->text, p->text) > 0)
p->next = pChild;
else if (t == NULL)
{
pParent->child = pChild;
pChild->next = p;
}
else
{
t->next = pChild;
pChild->next = p;
}
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -