📄 menu.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 + -