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

📄 menu.zc

📁 实现树形结构
💻 ZC
字号:
//[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
//[c]
import "base/types"
import "base/memory-allocator"
import "text/string"
import "text/string-buffer"
import "collection/vector"
import "graphics/geometry"
import "graphics/graphics"
import "user/box"

import "win32/windows"
import "private/sys-menu"
import "private/sys-command"
import "user/command"
import "user/accelerator"
//[cf]
//[of]:structures
//[of]:menu base
//[c]
//[c]	Common ancestor to menu and menu item
//[c]
public struct menu base

	public id : int
	public is menu : bool
	public is separator : bool

end
//[cf]
//[of]:menu
//[c]
//[c]	Menu
//[c]
public struct menu: local menu base

	peer: local system menu

	destroy: bool

	// for popup menu in the main menu
	// (not displayed for contextual menus)
	caption: string

	children: local vector

end
//[cf]
//[of]:menu item
//[c]
//[c]	Menu item
//[c]
public struct menu item: local menu base

	// the menu containing the item
	parent: menu
	
	// the command
	cmd: command
	
	// the event handler
	listener: local command listener

	// the caption
	// It is the caption of the command plus the
	// description of the accelerator
	caption: string

end
//[cf]
//[of]:menu separator
//[c]
public struct menu separator: local menu base
end
//[cf]
//[cf]
//[c]
//[of]:menu
//[of]:instance creation
//[of]:new menu
//[c]
public func new menu

	def hmenu = CreateMenu
	if hmenu == 0:HMENU
		return nil
	end

	def menu = allocate memory (sizeof local menu): menu
	id (menu) = 0
	is menu (menu) = true
	is separator (menu) = false
	handle (peer (menu)) = hmenu
	destroy (menu) = false
	
	initialize (children (menu), 8)
	return menu

end
//[cf]
//[of]:new popup menu (id, caption)
//[c]
public func new popup menu (id: int, caption: string)

	def hmenu = CreatePopupMenu
	if hmenu == 0:HMENU
		return nil
	end

	def menu = allocate memory (sizeof local menu): menu
	id (menu) = id
	is menu (menu) = true
	is separator (menu) = false
	handle (peer (menu)) = hmenu
	destroy (menu) = true
	caption (menu) = caption
	initialize (children (menu), 8)
	return menu

end
//[cf]
//[c]
//[of]:delete (m)
//[c]
public func delete (menu: menu) : void

	if destroy (menu)
		def res = DestroyMenu (handle (peer(menu)))
		if res == 0
			trap
		end

	end

	each (menu) ? child
		delete (child)
	end
	release (children (menu))
	free memory (menu)

end
//[cf]
//[cf]
//[of]:initialization macros
//[of]:new (i top menu, recipient, components)
//[c]
//[c]DESCRIPTION
//[c]	Creates a menu from a menu initializer structure.
//[c]	
//[c]ARGUMENTS
//[c]	i is a pointer to the structures describing the menu.
//[c]	recipient is the object that will be passed to all commands defined in this menu.
//[c]	c is an array to store labels
//[c]
//[c]RETURN VALUE
//[c]	Returns a newly created menu object
//[c]
public func new (i: i top menu, recipient: object, c: [] object)

	def menu = new menu
	def items = items (i)
	while not nil (items[])
		def item = items[]
		def type = type (item)
		if type == mit popup
			append menu (menu, new (item : i popup menu, recipient, c))
		else
			append menu (menu, new (item : i label popup, recipient, c))
		end		
		++items
	end

	return menu

end
//[cf]
//[of]:new (i popup menu, recipient, components)
//[c]Creates a popup menu from a popup menu initializer
//[c]
public func new (i: i popup menu, recipient: object, comp: [] object): menu

	def menu = new popup menu (id (i), caption (i))
	def items = items (i)

	while not nil (items[])
		def c = items[]
		def type = type (c)
		if type == mit command
			append menu (menu, new (c:i command, recipient))
		elsif type == mit popup
			append menu (menu, new (c:i popup menu, recipient, comp))
		elsif type == mit label command
			append menu (menu, new (c:i label command, recipient, comp))
		elsif type == mit label popup
			append menu (menu, new (c:i label popup, recipient, comp))
		else
			append separator (menu)
		end
		++ items
	end

	return menu

end
//[cf]
//[c]
//[of]:top menu (items)
//[c]
public equ top menu (items: [] i menu) = 
	const i top menu (items)
//[cf]
//[of]:popup menu (caption, items)
//[c]
public equ popup menu (id: int, caption: string, items: [] i menu) = 
	const i popup menu (mit popup, id, caption, items)
//[cf]
//[of]:command (name, caption, description, run)
//[c]
public equ command (name: string, caption: string, description: string, run: {box} void) = 
	const i command (mit command, name, caption, description, 0, 0, true, false, run)
//[cf]
//[of]:command (name, caption, description, flags, key, run)
//[c]
public equ command (
		name: string,
		caption: string, 
		description: string, 
		flags: int,
		key: int,
		run: {box} void) = 

	const i command (mit command, name, caption, description, flags, key, true, false, run)
//[cf]
//[of]:command (name, caption, description, enabled, checked, run)
//[c]
public equ command (
		name: string,
		caption: string, 
		description: string, 
		enabled: bool,
		checked: bool,
		run: {box} void) = 

	const i command (mit command, name, caption, description, 0, 0, enabled, checked, run)
//[cf]
//[of]:command (name, caption, description, flags, key, enabled, checked, run)
//[c]
public equ command (
		name: string,
		caption: string, 
		description: string, 
		flags: int,
		key: int,
		enabled: bool,
		checked: bool,
		run: {box} void) = 

	const i command (mit command, name, caption, description, flags, key, enabled, checked, run)
//[cf]
//[of]:separator
//[c]
public equ separator = 
	const i menu (mit separator)
//[cf]
//[c]
//[of]:label << popup
//[c]This macros is used to save the pointer of the generated popup
//[c]
public equ @shl (label: int, obj: i popup menu) = 
	const i label popup (mit label popup, label, obj)
//[cf]
//[of]:label << command
//[c]This macros is used to save the pointer to the command generated
//[c]from the initializer object.
//[c]
//[c]	Example:
//[c]	
//[c]	enum
//[c]		open cmd
//[c]		close cmd
//[c]		...
//[c]	end
//[c]	
//[c]	...
//[c]	open cmd << command ("Open...", "Open a new file", nil)
//[c]	...
//[c]	
//[c]	The assignation will take effect when creating actual commands
//[c]
public equ @shl (label: int, obj: i command) = 
	const i label command (mit label command, label, obj)
//[cf]
//[c]
//[of]:private
//[c]
//[of]:i menu
//[c]
struct i menu

	type: 
		enum
			mit separator
			mit command
			mit popup
			mit label command
			mit label popup
		end

end
//[cf]
//[of]:i command
//[c]
struct i command: local i menu

	name: string
	caption: string
	description: string
	flags: int
	key: int
	enabled: bool
	checked: bool
	run: {box} void

end
//[cf]
//[of]:i popup menu
//[c]
struct i popup menu: local i menu

	id : int
	caption : string
	items : [] i menu

end
//[cf]
//[of]:i label command
//[c]
struct i label command : local i menu

	label: int
	cmd: i command

end
//[cf]
//[of]:i label popup
//[c]
struct i label popup : local i menu

	label: int
	popup: i popup menu

end
//[cf]
//[of]:i top menu
//[c]
public struct i top menu

	items: [] i menu

end
//[cf]
//[of]:menu items
//[c]
public typedef menu items = [] i menu
//[cf]
//[c]
//[of]:new (i command, recipient)
//[c]
func new (i: i command, recipient: object)

	return new command (
		name (i),
		caption (i), 
		description (i), 
		flags (i): byte,
		key (i),
		enabled (i), 
		checked (i), 
		run (i),
		recipient)

end
//[cf]
//[of]:new (i label popup, recipient, components)
//[c]
//[c]DESCRIPTION
//[c]	Creates a menu from a label popup initializer structure.
//[c]	
//[c]ARGUMENTS
//[c]	i is a pointer to the structures describing the label.
//[c]	recipient is the object that will be passed to all commands defined in this menu.
//[c]	c is an array to store labels
//[c]
//[c]RETURN VALUE
//[c]	Returns a newly created popup object
//[c]
private func new (i: i label popup, recipient: object, c: [] object)

	def popup = new (popup (i), recipient, c)
	c [label (i)] = popup
	return popup

end
//[cf]
//[of]:new (i label command, recipient, components)
//[c]
//[c]DESCRIPTION
//[c]	Creates a command from a label command initializer structure.
//[c]	
//[c]ARGUMENTS
//[c]	i is a pointer to the structures describing the label.
//[c]	recipient is the object that will be passed to all commands defined in this menu.
//[c]	c is an array to store labels
//[c]
//[c]RETURN VALUE
//[c]	Returns a newly created popup object
//[c]
private func new (i: i label command, recipient: object, c: [] object)

	def cmd = new (cmd (i), recipient)
	c [label (i)] = cmd
	return cmd

end
//[cf]
//[cf]
//[cf]
//[c]
//[of]:popup
//[of]:show popup (menu, pos, box)
//[c]
public func show popup (menu: menu, pos: point, owner: box)

	def arrow cursor : local cursor
	initialize (arrow cursor, cursor arrow)
	def previous cursor = set cursor (owner, arrow cursor)

	def screen pos: POINT
	x (screen pos) = x (pos)
	y (screen pos) = y (pos)
	ClientToScreen (hwnd (owner), screen pos)

	TrackPopupMenu (
		handle (peer (menu)),
		TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY,
		x (screen pos),
		y (screen pos),
		0,
		hwnd (owner),
		nil)

	set cursor (owner, previous cursor)

end
//[cf]
//[cf]
//[of]:searching
//[of]:menu (m, id)
//[c]Returns the first child with given id
//[c]
public func menu (m: menu, id: int)

	each (m) ? menu
		if id == id (menu)
			return menu
		end
	end

	return nil

end
//[cf]
//[cf]
//[of]:enumerating
//[of]:each (m)
//[c]Enumerates children
//[c]
public equ each (menu: menu)

	each (children (menu)) ? m
		yield (m:menu base)
	end

end
//[cf]
//[cf]
//[of]:adding - removing
//[of]:append menu (m, child menu)
//[c]
public func append menu (menu: menu, child: menu)

	def hmenu = handle (peer (menu))
	def hmenu child = handle (peer (child))
	add (children (menu), child)
	destroy (child) = false

	AppendMenuA (
		hmenu, 
		MF_STRING | MF_POPUP, 
		hmenu child:UINT, 
		caption (child))

end
//[cf]
//[of]:append menu (m, cmd)
//[c]
public func append menu (menu: menu, cmd: command)

	def hmenu = handle (peer (menu))
	def flags = MF_STRING
	if ~ is enabled (cmd)
		flags |= MF_DISABLED | MF_GRAYED
	end
	if is checked (cmd)
		flags |= MF_CHECKED
	end
	def item = new menu item (cmd, menu)
	add (children (menu), item)

	AppendMenuA (hmenu, flags, id (cmd):UINT, caption (item))

end
//[cf]
//[of]:append separator (m)
//[c]
public func append separator (menu: menu)

	add (children (menu), menu separator)

	def hmenu = handle (peer (menu))
	AppendMenuA (hmenu, MF_SEPARATOR, 0:UINT, nil)

end
//[cf]
//[c]
//[of]:remove menu (m, index)
//[c]
public func remove menu (menu: menu, index: dword)

	def hmenu = handle (peer (menu))
	RemoveMenu (hmenu, index, MF_BYPOSITION)

	def child = children (menu) [index] : menu base
	remove (children (menu), index)
	delete (child)

end
//[cf]
//[cf]
//[of]:accessing
//[of]:child (m, index)
//[c]
public func child (m: menu, index: dword)
	return children (m) [index] : menu base
end
//[cf]
//[of]:number of children (m)
//[c]
public func number of children (m: menu)
	return size (children (m))
end
//[cf]
//[cf]
//[cf]
//[c]
//[c]private:
//[of]:menu base
//[of]:instance creation
//[c]
func delete (m: menu base)

	if is menu (m)
		delete (m: menu)
	elsif ~ is separator (m)
		delete (m: menu item)
	end

end
//[cf]
//[cf]
//[of]:menu item
//[of]:instance creation
//[of]:new menu item (command, parent menu)
//[c]
private func new menu item (cmd: command, parent: menu)

	def item = allocate memory (sizeof local menu item): menu item
	id (item) = 0
	is menu (item) = false
	is separator (item) = false
	cmd (item) = cmd
	parent (item) = parent
	caption (item) = nil
	update caption (item)
	
	// register the menu item as a listener on the command
	initialize (listener (item), item, ^command event (menu item, command, command event))
	add listener (cmd, listener (item))

	return item

end
//[cf]
//[of]:delete (m)
//[c]
private func delete (item: menu item)

	remove listener (cmd (item), listener (item))
	if not nil (caption (item))
		delete (caption (item))
	end
	free memory (item)

end
//[cf]
//[cf]
//[of]:updating
//[of]:update caption (m)
//[c]Updates the caption of the menu
//[c]
private func update caption (item: menu item)

	def s = temp string buffer
	
	// compute the new string in the buffer
	s << caption (cmd (item)) << \t << accelerator (cmd (item))

	// update only if there is no previous value or if the
	// new value differ from the previous one
	def old = caption (item)
	if is nil (old) || old <> as string (s)
		caption (item) = new string (base (s), size (s))
		if not nil (old)
			delete (old)
		end
	end

	release (s)

end
//[cf]
//[of]:command event (m, cmd)
//[c]Updates the menu according to the new state of the command.
//[c]
//[c]	The following properties may have changed:
//[c]	- caption
//[c]	- enabled
//[c]	- checked
//[c]
private func command event (item: menu item, cmd: command, event: command event)

	update caption (item)

	def flags = MF_BYCOMMAND | MF_STRING
	if ~ is enabled (cmd)
		flags |= MF_DISABLED | MF_GRAYED
	end
	if is checked (cmd)
		flags |= MF_CHECKED
	end

	ModifyMenuA (
		handle (peer (parent (item))),
		id (cmd):UINT,
		flags,
		id (cmd):UINT,
		caption (item))

end
//[cf]
//[cf]
//[c]
//[cf]
//[of]:menu separator
//[of]:instance creation
//[of]:menu separator
//[c]
def menu separator = const menu separator (0, false, true)
//[cf]
//[cf]
//[c]
//[cf]

⌨️ 快捷键说明

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