box.zc
来自「实现树形结构」· ZC 代码 · 共 2,624 行 · 第 1/4 页
ZC
2,624 行
//[of]:description
//[c]The base object for the user interface
//[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"
import "base/memory-allocator"
import "collection/linked-collection"
import "text/string"
import "text/string-buffer"
//[c]
import "graphics/geometry"
import "graphics/graphics"
import "toolbox/clipboard"
import "toolbox/timer"
import "user/keyboard"
import "user/command"
//[c]
import "win32/windows"
import "win32/winerror"
import "win32/commctrl"
import "private/sys-graphics"
import "private/sys-command"
//[cf]
//[c]
//[of]:win32
//[of]:description
//[c]This part contains win32 specific code.
//[c]
//[c]The definitions of this part must only be used by the win32 specific
//[c]components.
//[cf]
//[of]:sys box class
private typedef proc = {->void, UINT, WPARAM, LPARAM} LRESULT
//[c]
public struct sys box class
// first level: entry point
window proc: proc
// second level: message type decoded
wm create: proc
wm destroy: proc
wm command: proc
wm notify: proc
wm size: proc
wm paint: proc
wm close: proc
wm hscroll: proc
wm vscroll: proc
wm set cursor: proc
wm activate: proc
wm key down: proc
wm key up: proc
wm char: proc
wm copy data: proc
// third level: arguments decoded
command: {object, WORD} void
notify: {object, LPNMHDR} LRESULT
hscroll: {object, int, int} bool
vscroll: {object, int, int} bool
move: {box, rectangle, bool} void
set read only: {box, bool} void
set enable: {box, bool} void
end
//[c]
//[cf]
//[of]:sys box
//[of]:type
public struct sys box
// Handle to window
hwnd: HWND
// parent procedure
parent proc: WNDPROC
// cursor for this window
cursor: object
visible: bool
read only: bool
enabled: bool
accept drop files: bool
last key event processed: bool
end
//[cf]
//[c]
//[of]:send messages
//[of]:send message (msg, wparam, lparam)
public func send message (box: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
return SendMessageA (hwnd (box), msg, wParam, lParam)
end
//[cf]
//[of]:send message (msg, wParam)
public func send message (box: box, msg: UINT, wParam: WPARAM)
return send message (box, msg, wParam, 0:LPARAM)
end
//[cf]
//[of]:send message (msg)
public func send message (box: box, msg: UINT)
return send message (box, msg, 0:WPARAM, 0:LPARAM)
end
//[cf]
//[cf]
//[of]:create window
//[of]:create managed window ex (...)
//[c]
public func create managed window ex (
m: box,
dwExStyle: DWORD,
lpClassName: LPCTSTR,
lpWindowName: LPCTSTR,
dwStyle: DWORD,
hMenu: HMENU,
lpParam: LPVOID)
def hwnd = create window ex(
m,
dwExStyle,
lpClassName,
lpWindowName,
dwStyle,
hMenu,
lpParam)
parent proc (m) = GetWindowLongA (hwnd, GWL_WNDPROC):WNDPROC
SetWindowLongA (hwnd, GWL_WNDPROC, ^route window proc (HWND, UINT, WPARAM, LPARAM):LONG)
return hwnd
end
//[cf]
//[of]:create window ex (...)
//[c]
public func create window ex (
m: box,
dwExStyle: DWORD,
lpClassName: LPCTSTR,
lpWindowName: LPCTSTR,
dwStyle: DWORD,
hMenu: HMENU,
lpParam: LPVOID)
def parent = parent (m)
def hwnd parent = nil:HWND
if not nil (parent)
hwnd parent = hwnd (parent)
end
return create window ex(
m,
dwExStyle,
lpClassName,
lpWindowName,
dwStyle,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hwnd parent,
hMenu,
hinstance,
lpParam)
end
//[cf]
//[of]:create window ex (...)
//[c]
public func create window ex (
m: box,
dwExStyle: DWORD,
lpClassName: LPCTSTR,
lpWindowName: LPCTSTR,
dwStyle: DWORD,
x: int,
y: int,
nWidth: int,
nHeight: int,
hWndParent: HWND,
hMenu: HMENU,
hInstance: HINSTANCE,
lpParam: LPVOID)
// set global boc being created to self
def old = box being created
box being created = m
def hwnd = CreateWindowExA (
dwExStyle,
lpClassName,
lpWindowName,
dwStyle,
x,
y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam)
hwnd (m) = hwnd
// the user data should be set when invoking
// the first time the RouteWndProc, but controls
// that does not invoke this procedure need
// to update user data now.
SetWindowLongA (hwnd, GWL_USERDATA, m:LONG)
// restore previous state
box being created = old
return hwnd
end
//[cf]
//[c]
//[of]:route window proc (hwnd, msg, wparam, lparam)
//[c]All windows events for all widget classes arrive here.
//[c]
public [call="__stdcall"] func route window proc (
hwnd: HWND,
msg: UINT,
wParam: WPARAM,
lParam: LPARAM)
// Redirect the WindowProc messages
def m = box from hwnd (hwnd)
if is nil (m)
SetWindowLongA (hwnd, GWL_USERDATA, box being created:LONG)
if is nil (box being created)
return 0
end
m = box being created
hwnd (m) = hwnd
end
return window proc (class (m)) {m, msg, wParam, lParam}
end
//[cf]
//[cf]
//[of]:catch events
//[of]:actual command (notify code)
public func actual command (b: box, wNotifyCode: WORD)
end
//[cf]
//[of]:actual notify (pnmh)
//[c]
public func actual notify (b: box, pnmh: LPNMHDR) : int
// in some case the notification is sent to the wrong control
// e.g. notebook sent notif to parent but with 'from' as
// child page
// to fix that (we want the notebook receives the event),
// the notif is propagated trough parents
def parent = parent (b)
if is nil (parent)
return 0
else
return notify (class (parent)) {parent, pnmh}
end
end
//[cf]
//[of]:actual create (msg, wParam, lParam)
//[c]The control is beeing activated
//[c]
public func actual create (m: box, msg:UINT, wParam: WPARAM, lParam: LPARAM)
if accept drop files (m)
DragAcceptFiles (hwnd (m), 1)
end
return default window proc (m, WM_CREATE, wParam, lParam)
end
//[cf]
//[of]:ignore scroll (int, int)
//[c]Default handling for hscroll and vscroll
//[c]
public func ignore scroll (m: box, code: int, pos: int)
return false
end
//[cf]
//[cf]
//[of]:window procedures
//[of]:default window proc
//[c]Default procedures
//[c]
public func default window proc (m: box, message: UINT, wParam: WPARAM, lParam: LPARAM)
return CallWindowProcA (
parent proc (m),
hwnd (m),
message,
wParam,
lParam)
end
//[cf]
//[c]
//[of]:wm key down
//[c]Standard key-down procedure
//[c]
public func wm key down (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
def processed = on key down (m, key event (key down event type, wParam: int, get key flags))
last key event processed (m) = processed
if processed
return 0
end
return default window proc (m, msg, wParam, lParam)
end
//[cf]
//[of]:wm key up
//[c]Standard key-up procedure
//[c]
public func wm key up (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
if on key up (m, key event (key up event type, wParam: int, get key flags))
return 0
end
return default window proc (m, msg, wParam, lParam)
end
//[cf]
//[of]:wm char
//[c]Standard char procedure
//[c]
public func wm char (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
if last key event processed (m)
last key event processed (m) = false
return 0
end
if on char (m, char event (wParam: TCHAR, get key flags))
return 0
end
return default window proc (m, msg, wParam, lParam)
end
//[cf]
//[of]:wm size
//[c]Standard size procedure
//[c]- replicate the window's size into the box's size
//[c]- send notification
//[c]
public func wm size (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
// compare with current size
def r = client rect (m)
def w = LOWORD (lParam) : int
def h = HIWORD (lParam) : int
if w (r) <> w || h (r) <> h
// replicate the window's size into the box's size
left (r) = 0
top (r) = 0
width (r) = w
height (r) = h
// send notification
on size (m)
// on size has been invoked, no need to invoke
// adjust () anymore
valid size (m) = true
end
return default window proc (m, msg, wParam, lParam)
end
//[cf]
//[of]:wm command
//[c]Standard command procedure
//[c]
public func wm command (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
def hwnd src = lParam : HWND
if not nil (hwnd src)
def t = box from hwnd (hwnd src)
if not nil (t)
// widget command: send the command
// back to the child
command (class (t)) {t, HIWORD (wParam)}
end
else
// it is a menu command
def cmd = system command from id (LOWORD (wParam)):command
if not nil (cmd)
run (cmd)
end
end
return 0
end
//[cf]
//[of]:wm notify
//[c]Standard notify procedure
//[c]
public func wm notify (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
def pnmh = lParam:LPNMHDR
def hwndFrom = hwndFrom (pnmh)
def receiver = box from hwnd (hwndFrom)
// The notification can be emitted by a non managed child control.
// For instance the scroll buttons in the tab bar of a notebook.
if is nil (receiver)
return 0
end
return notify (class (receiver)) {receiver, pnmh}
end
//[cf]
//[of]:wm hscroll
//[c]
public func wm hscroll (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
def hwnd src = lParam : HWND
if not nil (hwnd src)
def t = box from hwnd (hwnd src)
if not nil (t)
def code = LOWORD (wParam) : int
def pos = HIWORD (wParam) : int
if hscroll (class (t)) {t, code, pos}
return 0
end
end
end
return default window proc (m, msg, wParam, lParam)
end
//[cf]
//[of]:wm vscroll
//[c]
public func wm vscroll (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
def hwnd src = lParam : HWND
if not nil (hwnd src)
def t = box from hwnd (hwnd src)
if not nil (t)
def code = LOWORD (wParam) : int
def pos = HIWORD (wParam) : int
if vscroll (class (t)) {t, code, pos}
return 0
end
end
end
return default window proc (m, msg, wParam, lParam)
end
//[cf]
//[of]:wm set cursor
//[c]
public func wm set cursor (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
def c = cursor (m) : cursor
if not nil (c)
SetCursor (hCursor (c))
return TRUE
end
return default window proc (m, msg, wParam, lParam)
end
//[cf]
//[c]
//[of]:window proc
//[c]All windows events for all widget classes arrive here.
//[c]
private equ WM_DELAY_ACTIVATE = WM_USER+1
//[c]
public func window proc (m: box, msg: UINT, wParam: WPARAM, lParam: LPARAM)
switch msg
case WM_CREATE
return wm create (class (m)) {m, msg, wParam, lParam}
case WM_DESTROY
return wm destroy (class (m)) {m, msg, wParam, lParam}
case WM_SIZE
return wm size (class (m)) {m, msg, wParam, lParam}
case WM_COMMAND
return wm command (class (m)) {m, msg, wParam, lParam}
case WM_PAINT
return wm paint (class (m)) {m, msg, wParam, lParam}
case WM_CLOSE
return wm close (class (m)) {m, msg, wParam, lParam}
case WM_NOTIFY
return wm notify (class (m)) {m, msg, wParam, lParam}
case WM_HSCROLL
return wm hscroll (class (m)) {m, msg, wParam, lParam}
case WM_VSCROLL
return wm vscroll (class (m)) {m, msg, wParam, lParam}
case WM_SETCURSOR
return wm set cursor (class (m)) {m, msg, wParam, lParam}
case WM_DELAY_ACTIVATE
return wm activate (class (m)) {m, msg, wParam, lParam}
case WM_KEYDOWN, WM_SYSKEYDOWN
return wm key down (class (m)) {m, msg, wParam, lParam}
case WM_KEYUP, WM_SYSKEYUP
return wm key up (class (m)) {m, msg, wParam, lParam}
case WM_CHAR, WM_SYSCHAR
return wm char (class (m)) {m, msg, wParam, lParam}
case WM_COPYDATA
return wm copy data (class (m)) {m, msg, wParam, lParam}
//[of]: WM_SETFOCUS
case WM_SETFOCUS
if on focus (m)
return 0
end
//[cf]
//[of]: WM_KILLFOCUS
case WM_KILLFOCUS
if on blur (m)
return 0
end
//[cf]
//[of]: WM_ENTERMENULOOP
case WM_ENTERMENULOOP
def active box = get focus box
if not nil (active box)
on enter menu (active box)
end
//[cf]
//[of]: WM_EXITMENULOOP
case WM_EXITMENULOOP
def active box = get focus box
if not nil (active box)
on leave menu (active box)
end
//[cf]
//[of]: WM_CUT
case WM_CUT
cut (m)
return 0
//[cf]
//[of]: WM_COPY
case WM_COPY
def copied = copy (m)
// The edit control seems to expect the number of char copied
// in clipboard (>0 value seems sufficient)
if copied
return 1
else
return 0
end
//[cf]
//[of]: WM_PASTE
case WM_PASTE
paste (m)
return 0
//[cf]
//[of]: WM_CLEAR
case WM_CLEAR
clear (m)
return 0
//[cf]
//[c]
//[of]: WM_MOUSEMOVE
case WM_MOUSEMOVE
def e: local mouse move event
type (e) = mouse move event type
status (e) = get key flags
x (position (e)) = LOWORD (lParam) : short : int
y (position (e)) = HIWORD (lParam) : short : int
if on mouse move (m, e)
return 0
end
//[cf]
//[of]: WM_MOUSEWHEEL
case WM_MOUSEWHEEL
def e: local mouse wheel event
type (e) = mouse wheel event type
status (e) = get key flags
x (position (e)) = LOWORD (lParam) : short : int
y (position (e)) = HIWORD (lParam) : short : int
delta (e) = HIWORD (wParam) : short : int / 120
if on mouse wheel (m, e)
return 0
end
//[cf]
//[of]: WM_CANCELMODE
case WM_CANCELMODE
def active box = get focus box
if not nil (active box)
if on mouse cancel (active box)
return 0
end
end
//[cf]
//[of]: WM_LBUTTONDOWN
case WM_LBUTTONDOWN
def e: local mouse button event
type (e) = mouse down event type
button (e) = left mouse button
status (e) = get key flags
x (position (e)) = LOWORD (lParam) : short : int
y (position (e)) = HIWORD (lParam) : short : int
if on mouse down (m, e)
return 0
end
//[cf]
//[of]: WM_LBUTTONUP
case WM_LBUTTONUP
def e: local mouse button event
type (e) = mouse up event type
button (e) = left mouse button
status (e) = get key flags
x (position (e)) = LOWORD (lParam) : short : int
y (position (e)) = HIWORD (lParam) : short : int
if on mouse up (m, e)
return 0
end
//[cf]
//[of]: WM_LBUTTONDBLCLK
case WM_LBUTTONDBLCLK
def e: local mouse button event
type (e) = mouse double click event type
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?