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

📄 tree-box.zc

📁 实现树形结构
💻 ZC
📖 第 1 页 / 共 2 页
字号:
//[of]:description
//[c]Display a tree view. The widget is based on a model/view scheme:
//[c]there is an observable model to implement.
//[c]
//[c]Classes:
//[c]tree model -- the model object
//[c]tree item -- the nodes of the model
//[c]tree listener -- interface to listen events from the model 
//[c]tree box -- the graphical component
//[c]
//[cf]
//[of]:license
//[c]Code Browser - a folding text editor for programmers
//[c]Copyright (C) 2003-07 Marc Kerbiquet
//[c]
//[c]This program is free software; you can redistribute it and/or modify
//[c]it under the terms of the GNU General Public License as published by
//[c]the Free Software Foundation; either version 2 of the License, or
//[c](at your option) any later version.
//[c]
//[c]This program is distributed in the hope that it will be useful,
//[c]but WITHOUT ANY WARRANTY; without even the implied warranty of
//[c]MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//[c]GNU General Public License for more details.
//[c]
//[c]You should have received a copy of the GNU General Public License
//[c]along with this program; if not, write to the Free Software
//[c]Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//[cf]
//[of]:imports
import "base/types"
import "base/memory-allocator"
import "text/vector-of-strings"
import "text/string"
import "text/string-buffer"
//[c]
import "graphics/geometry"
import "graphics/graphics"
import "user/box"
import "user/image-list"
//[c]
import "win32/windows"
import "win32/commctrl"
//[cf]
//[c]
//[of]:tree model
//[of]:type
public struct tree model
	class: tree model class
end

public struct tree model class
	root: {tree model} tree item
	add listener: {tree model, tree listener} void
	remove listener: {tree model, tree listener} void
end
//[cf]
//[c]
//[of]:root
public func root (m: tree model)
	return root (class (m)) {m}
end
//[cf]
//[of]:add listener (listener)
//[c]
func add listener (m: tree model, listener: tree listener)
	add listener (class (m)) {m, listener}
end
//[cf]
//[of]:remove listener (listener)
//[c]
func remove listener (m: tree model, listener: tree listener)
	remove listener (class (m)) {m, listener}
end
//[cf]
//[cf]
//[of]:tree item
//[of]:type
public struct tree item
	class: tree item class
end

public struct tree item class
	append text: {tree item, string buffer} void
	parent: {tree item} tree item
	first child: {tree item} tree item
	next sibling: {tree item} tree item
	open: {tree item} void
	close: {tree item} void
	has children: {tree item} bool
	image: {tree item} int
end
//[c]
//[cf]
//[c]
//[of]:append text
public func append text (m: tree item, s: string buffer)
	append text (class (m)) {m, s}
end
//[cf]
//[of]:parent
public func parent (m: tree item)
	return parent (class (m)) {m}
end
//[cf]
//[of]:first child
public func first child (m: tree item)
	return first child (class (m)) {m}
end
//[cf]
//[of]:next sibling
public func next sibling (m: tree item)
	return next sibling (class (m)) {m}
end
//[cf]
//[of]:open
public func open (m: tree item)
	open (class (m)) {m}
end
//[cf]
//[of]:close
public func close (m: tree item)
	close (class (m)) {m}
end
//[cf]
//[of]:has children
//[c]
public func has children (m: tree item)
	return has children (class (m)) {m}
end
//[cf]
//[of]:image
//[c]
public func image (m: tree item)
	return image (class (m)) {m}
end
//[cf]
//[cf]
//[of]:tree listener
//[of]:definition
//[c]
public struct tree listener
	recipient: object
	text changed: {object, tree item} void
	data changed: {object, tree item} void
	has children changed: {object, tree item} void
	children replaced: {object, tree replace event} void
end
//[c]
public struct tree replace event
	parent: tree item
	index: dword
	removed: dword
	inserted: dword
end
//[c]
public func text changed (m: tree listener, item: tree item)
	text changed (m) {recipient (m), item}
end
//[c]
public func data changed (m: tree listener, item: tree item)
	data changed (m) {recipient (m), item}
end
//[c]
public func has children changed (m: tree listener, item: tree item)
	has children changed (m) {recipient (m), item}
end
//[c]
public func children replaced (m: tree listener, e: tree replace event)
	children replaced (m) {recipient (m), e}
end
//[cf]
//[cf]
//[of]:tree item changed event
//[c]
public struct tree item changed event : local event
	tree item : tree item
end
//[c]
public def tree item changed event type : local event type
//[cf]
//[c]
//[of]:tree box
//[of]:type
public struct tree box : local box

	private 
		tree model: tree model
		selected item: tree item
		synchronizing selection: bool
		listener: local tree listener
		image list: image list
		original selected item: tree item
	
end
//[cf]
//[of]:instance creation
//[of]:new tree box (parent)
public func new tree box (parent: box)

	equ s = sizeof local tree box
	def e = allocate memory (s): tree box
	initialize (e, parent)
	return e

end
//[cf]
//[cf]
//[of]:tree
//[of]:tree
public func tree (m: tree box)

	return tree model (m)

end
//[cf]
//[of]:set tree (tree)
public func set tree (m: tree box, tree: tree model)

	def selection = not nil (tree) -> root (tree), nil
	set tree (m, tree, selection)

end
//[cf]
//[of]:set tree (tree, selection)
//[c]Change the tree and selection
//[c]
//[c]ARGUMENTS
//[c]	tree -- the tree to show
//[c]	selection -- the node to select
//[c]
//[c]REMARKS
//[c]	tree must be the same as the one edited by the source box.
//[c]	
private func set tree (m: tree box, tree: tree model, selection: tree item)

	def old tree = tree model (m)
	tree model (m) = tree

	if not nil (old tree)
		remove listener (old tree, listener (m))
	end
	if not nil (tree)
		add listener (tree, listener (m))
	end

	// Delete the current tree
	if not nil (old tree)
		send message (m, TVM_DELETEITEM, 0:WPARAM, TVI_ROOT:LPARAM)
	end

	synchronize widget tree (m)

	selected item (m) = nil	// force update
	set selection (m, selection)

end
//[cf]
//[cf]
//[of]:selection
//[of]:selection
//[c]Returns the the currently selected item or nil
//[c]
public func selection (m: tree box)
	return selected item (m)
end
//[cf]
//[of]:set selection (item)
//[c]Changes the current selection
//[c]to unselect, use nil as item
//[c]
public func set selection (m: tree box, item: tree item)

	if item <> selected item (m)
		selected item (m) = item
		synchronize widget selection (m)
		on selection changed (m)
	end

end
//[cf]
//[cf]
//[of]:image list
//[of]:set image list (list)
public func set image list (m: tree box, list: image list)

	image list (m) = list
	synchronize image list (m)

end
//[cf]
//[cf]
//[of]:style
//[of]:set style (style)
//[c]
public func set style (m: tree box, style: box style)

	set style (super (m), style)
	update from style (m)

end
//[cf]
//[cf]
//[c]
//[of]:restricted
//[of]:initialize (parent)
public func initialize (m: tree box, parent: box)

	initialize (super (m), parent)
	class (m) = tree box class
	tree model (m) = nil
	selected item (m) = nil
	original selected item (m) = nil
	synchronizing selection (m) = false
	image list (m) = nil
	
	recipient (listener (m)) = m
	text changed (listener (m)) = ^text changed (tree box, tree item)
	data changed (listener (m)) = ^data changed (tree box, tree item)
	has children changed (listener (m)) = ^has children changed (tree box, tree item)
	children replaced (listener (m)) = ^children replaced (tree box, tree replace event)

	create managed window ex (
		m,
		get ex style (m),
		WC_TREEVIEW,
		nil,
		get style (m),
		m:HMENU,
		nil)

	update from style (m)

end
//[cf]
//[c]
//[of]:notify proc (pnmtv)
//[c]Standard notify procedure
//[c]
public func notify proc (m: tree box, pnmh: LPNMHDR)

	equ pnmtv = pnmh : LPNMTREEVIEW

	if code (pnmh) == TVN_ITEMEXPANDINGA && action (pnmtv) == TVE_EXPAND
		def hItem = hItem (itemNew (pnmtv))
		
		// Windows sends this notification even if the node is already expanded
		// when pressing the '+' key from the notepad. So we need to check
		// the expand status of the item before adding children.
		if ~ is expanded (m, hItem)
			def item = lParam (itemNew (pnmtv)) : tree item
			add children (m, hItem, item)
		end
		
	elsif code (pnmh) == TVN_ITEMEXPANDINGA && action (pnmtv) == TVE_COLLAPSE
		def hItem = hItem (itemNew (pnmtv))
		def item = lParam (itemNew (pnmtv)) : tree item
		
		// selection is changed, but SELCHANGED is not emitted: 
		// need to force selection
		def child = selected item (m)
		while not nil (child)
			if child == item
				set selection (m, item)
				break
			end
			child = parent (child)
		end
		
		send message (m, 
			TVM_EXPAND, 
			(TVE_COLLAPSE | TVE_COLLAPSERESET) : WPARAM, 
			hItem : LPARAM)
		close opened (m, hItem, item)

	elsif code (pnmh) == TVN_SELCHANGEDA
		if ~ synchronizing selection (m)
			def hItem = hItem (itemNew (pnmtv))
			def item = lParam (itemNew (pnmtv)) : tree item
			selected item (m) = item
			on selection changed (m)
		end		
	end
	
	return 0

end
//[c]
func close opened (m: tree box, hItem: HTREEITEM, item: tree item) : void
	
	def hChild = first child (m, hItem)
	if is nil (hChild)
		return
	end

	while not nil (hChild)
		close opened (m, hChild, tree item (m, hChild))
		hChild = next sibling (m, hChild)
	end
	
	close (item)

end
//[cf]
//[of]:window proc (msg, wparam, lparam)
public func window proc (
		m: tree box, 
		msg: UINT, 
		wParam: WPARAM, 
		lParam: LPARAM)

	if msg == WM_RBUTTONDOWN

		def ht: TVHITTESTINFO
		x (pt (ht)) = LOWORD (lParam) : int
		y (pt (ht)) = HIWORD (lParam) : int
		send message (m, TVM_HITTEST, 0:WPARAM, ht: LPARAM)
		if not nil (hItem (ht)) && (flags (ht) & (TVHT_ONITEMICON | TVHT_ONITEMLABEL)) <> 0

			original selected item (m) = selected item (m)
			selected item (m) = tree item (m, hItem (ht))
			synchronizing selection (m) = true
		
			def tvi: TVITEM
			mask (tvi) = TVIF_STATE
			hItem (tvi) = hItem (ht)
			stateMask (tvi) = TVIS_SELECTED
			send message (m, TVM_GETITEM, 0:WPARAM, tvi:LPARAM)
			if (state (tvi) & TVIS_SELECTED) == 0
				send message (m, TVM_SELECTITEM, TVGN_CARET:WPARAM, hItem (tvi):LPARAM)
			end

			synchronizing selection (m) = false
		end
		
		// process default		
	end

	return window proc (super (m), msg, wParam, lParam)

end
//[cf]
//[c]
//[of]:actual compute min size
public func actual compute min size (m: tree box)

	def w = 100
	def h = 100
	set min size(m, w, h)

end
//[cf]
//[of]:actual release
public func actual release (m: tree box)

	actual release (super (m))
	
	def tree = tree model (m)
	if not nil (tree)
		remove listener (tree, listener (m))
	end

end

⌨️ 快捷键说明

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