drop-down-edit-box.zc

来自「实现树形结构」· ZC 代码 · 共 579 行

ZC
579
字号
//[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/string"
import "text/vector-of-strings"
import "text/string-buffer"
//[c]
import "graphics/geometry"
import "graphics/graphics"
import "user/box"
import "toolbox/clipboard"
//[c]
import "win32/windows"
//[cf]
//[c]
//[of]:drop down edit box
//[of]:type
public struct drop down edit box : local box

	private 
		edit hwnd : HWND
		edit proc : WNDPROC
	
		starting position: DWORD
		ending position: DWORD
		content: string

end
//[cf]
//[of]:instance creation
//[of]:new drop down edit box (parent)
public func new drop down edit box (parent: box)

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

end
//[cf]
//[cf]
//[of]:text
//[of]:text
//[c]Returns the content of the drop down edit box
//[c]
public func text (m: drop down edit box)

	// update the member attribute from the control
	def stream := temp string buffer
	def size = GetWindowTextLengthA (hwnd (m))
	def p = buffer (stream, size)
	GetWindowTextA (hwnd (m), p, size+1)
	set content (m, as string (stream))
	release (stream)
		
	return content (m)

end
//[cf]
//[of]:set text (text)
//[c]Changes the content of the drop down edit box
//[c]
public func set text (m: drop down edit box, text: string)

	set content (m, text)
	set window text (m, text)
	reset selection save (m)
	on value changed (m)

end
//[cf]
//[cf]
//[of]:selection
//[of]:select (starting pos, ending pos)
//[c]Selects a part of the text
//[c]
public func select (m: drop down edit box, starting pos: int, ending pos: int)
	send message (m, CB_SETEDITSEL, 0:WPARAM, MAKELPARAM(starting pos, ending pos))
end
//[cf]
//[of]:is selection empty
//[c]Tests if the current selection is empty
//[c]
public func is selection empty (m: drop down edit box)
	def l = send message (m, CB_GETEDITSEL): DWORD
	return HIWORD (l) == LOWORD (l)
end
//[cf]
//[cf]
//[of]:list
//[of]:size of list
public func size of list (m: drop down edit box)
	return send message (m, CB_GETCOUNT): int
end
//[cf]
//[of]:set list (vector)
//[c]
public func set list (m: drop down edit box, v: vector of strings)
	each (v) ? s
		send message (m, CB_ADDSTRING, 0:WPARAM, s:LPARAM)
	end
end
//[cf]
//[cf]
//[c]
//[of]:restricted
//[of]:initialize (parent)
public func initialize (m: drop down edit box, parent: box)

	initialize (super (m), parent)
	class (m) = drop down edit box class
	starting position (m) = 0
	ending position (m) = 0
	content (m) = empty string

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

	set edit font (m)
	
	// Capture the messages of the edit control
	def edit hwnd = FindWindowExA (hwnd (m), nil, "edit", nil)
	SetWindowLongA (edit hwnd, GWL_USERDATA, m:LONG)
	edit proc (m) = GetWindowLongA (edit hwnd, GWL_WNDPROC):WNDPROC
	SetWindowLongA (edit hwnd, GWL_WNDPROC, ^edit window proc (HWND, UINT, WPARAM, LPARAM):LONG)
	edit hwnd (m) = edit hwnd

end
//[cf]
//[c]
//[of]:actual cut
public func actual cut (m: drop down edit box)
	default window proc (m, WM_CUT, 0, 0)
	return true
end
//[cf]
//[of]:actual copy
public func actual copy (m: drop down edit box)
	return default window proc (m, WM_COPY, 0, 0) > 0
end
//[cf]
//[of]:actual paste
public func actual paste (m: drop down edit box)
	default window proc (m, WM_PASTE, 0, 0)
	return true
end
//[cf]
//[of]:actual clear
public func actual clear (m: drop down edit box)
	default window proc (m, WM_CLEAR, 0, 0)
	return true
end
//[cf]
//[of]:actual select all
public func actual select all (m: drop down edit box)
	select (m, 0, -1)
	return true
end
//[cf]
//[of]:actual can copy
public func actual can copy (m: drop down edit box)
	return ~ is selection empty (m)
end
//[cf]
//[of]:actual can paste
public func actual can paste (m: drop down edit box)

	if is read only (m)
		return false
	end
	
	def can paste = false
	each clipboard format ? fmt
		if fmt == CF_TEXT
			can paste = true
			break
		end
	end
	return can paste

end
//[cf]
//[of]:actual can clear
func actual can clear (m: drop down edit box)
	return ~ is read only (m) && ~ is selection empty (m)
end
//[cf]
//[of]:actual release
public func actual release (m: drop down edit box)
	delete (content (m))
	actual release (super (m))
end
//[cf]
//[of]:actual compute min size
public func actual compute min size (m: drop down edit box)

	def a: local area
	def canvas: local canvas
	initialize (canvas)
	set font (canvas, edit font (style (m)))
	text extent (canvas, "X", 1, a)
	release (canvas)

	def rect : local LPRECT
	left (rect) = 0
	top (rect) = 0
	right (rect) = w (a)
	bottom (rect) = h (a)
	AdjustWindowRectEx (rect, get style (m), 0, get ex style (m))
	
	def w = 120
	def h = bottom (rect) - top (rect)
	if edit border (style (m)) <> border none
		h += 2
	end
	set min size(m, w, h)

end
//[cf]
//[of]:actual set read only (ro)
public func actual set read only (m: drop down edit box, ro: bool)

	// exit if unchanged
	if read only (m) == ro
		return
	end
	
	//send message (m, EM_SETREADONLY, ro:BOOL:WPARAM, 0)
	read only (m) = ro

end
//[cf]
//[of]:actual move (rectangle, repaint)
//[c]Move the box
//[c]
//[c]The position of a box should be changed only by its parent from
//[c]the on size or adjust event.
//[c]
public func actual move (m: drop down edit box, r: rectangle, repaint: bool)
	MoveWindow (
		hwnd (m),
		x (r),
		y (r),
		w (r),
		100,
		BOOL (repaint))
end
//[cf]
//[c]
//[of]:handle focus
public func handle focus (m: drop down edit box, e: event)
	select all (m)
	return handle focus (super (m), e)
end
//[cf]
//[cf]
//[of]:private
//[of]:edit window proc
//[c]
public [call="__stdcall"] func edit window proc (
		hwnd: HWND, 
		msg: UINT, 
		wParam: WPARAM, 
		lParam: LPARAM)
						
	def m = box from hwnd (hwnd): drop down edit box
	def res = edit window proc (m, msg, wParam, lParam)
	
	switch msg
	case WM_SETFOCUS,
		WM_KILLFOCUS,
		WM_KEYDOWN, WM_SYSKEYDOWN,
		WM_LBUTTONDOWN,
		WM_MBUTTONDOWN,
		WM_RBUTTONDOWN,
		WM_LBUTTONUP,
		WM_MBUTTONUP,
		WM_RBUTTONUP,
		WM_LBUTTONDBLCLK,
		WM_MBUTTONDBLCLK,
		WM_RBUTTONDBLCLK,
		WM_MOUSEMOVE

		check selection changed (m)
	end
	
	return res
end
//[c]
public func edit window proc (
		m: drop down edit box, 
		msg: UINT, 
		wParam: WPARAM, 
		lParam: LPARAM)

	switch msg
	case WM_SETFOCUS
		if on focus (m)
			return 0
		end

	case WM_KILLFOCUS
		if on blur (m)
			return 0
		end

	case WM_KEYDOWN, WM_SYSKEYDOWN
		equ key = wParam: int
		
		if (key == VK_ESCAPE || key == VK_RETURN) && is dropped down (m)
			last key event processed (m) = true
			show drop down (m, false)
			return 0
		end

		def processed = on key down (m, key event (key down event type, key, get key flags))
		last key event processed (m) = processed
		if processed
			return 0
		end
	
	case WM_CHAR, WM_SYSCHAR
		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

	end
	
	return CallWindowProcA (edit proc (m),  edit hwnd (m), msg, wParam, lParam)
end
//[cf]
//[c]
//[of]:wm key down
private func wm key down (m: drop down edit box, msg: UINT, wParam: WPARAM, lParam: LPARAM)

	wm key down (super (m), msg, wParam, lParam)
	check selection changed (m)
	return 0

end
//[cf]
//[of]:wm char
private func wm char (m: drop down edit box, msg: UINT, wParam: WPARAM, lParam: LPARAM)

	wm char (super (m), msg, wParam, lParam)
	check selection changed (m)
	return 0

end
//[cf]
//[of]:wm size
//[c]It seems windows selects the text when resizing.
//[c]
//[c]This method save and restore the selection when resizing.
//[c]
func wm size (
		m: drop down edit box, 
		msg: UINT, 
		wParam: WPARAM, 
		lParam: LPARAM)

	// Save selection
	def s: [1] DWORD	
	def e: [1] DWORD
	send message (m, CB_GETEDITSEL, s:WPARAM, e:LPARAM)

	// Save content
	def stream := temp string buffer
	def size = GetWindowTextLengthA (hwnd (m))
	def p = buffer (stream, size)
	GetWindowTextA (hwnd (m), p, size+1)
	
	// Call parent proc
	def res = wm size (super (m), msg, wParam, lParam)

	// Restore content
	SetWindowTextA  (hwnd (m), p)
	release (stream)

	// Restore selection	
	send message (m, CB_SETEDITSEL, 0, (e[] << 16 | s[]):LPARAM)

	return res
end
//[cf]
//[of]:actual win command (code)
private func actual win command (m: drop down edit box, notify code: WORD)

	if notify code == CBN_EDITCHANGE:WORD

		on value changed (m)
		check selection changed (m)

	elsif notify code == CBN_SELCHANGE:WORD

		// Force updating text before sending events
		def index = send message (m, CB_GETCURSEL)
		if index <> CB_ERR
			send message (m, CB_SETCURSEL, index)
		end

		on value changed (m)		
		check selection changed (m)

	end

end
//[cf]
//[c]
//[of]:set content (text)
private func set content (m: drop down edit box, text: string)

	delete (content (m))
	content (m) = new string (text)

end
//[cf]
//[of]:reset selection save
//[c]Resets the selection save
//[c]
private func reset selection save (m: drop down edit box)

	def starting position: [1] DWORD	
	def ending position: [1] DWORD
	
	send message (
		m, 
		CB_GETEDITSEL, 
		starting position : WPARAM, 
		ending position : LPARAM)

	starting position (m) = starting position []
	ending position (m) = ending position []

end
//[cf]
//[of]:check selection changed
//[c]Checks if the selection has changed.
//[c]Compare the current selection to the last saved.
//[c]
private func check selection changed (m: drop down edit box)

	def starting position: [1] DWORD	
	def ending position: [1] DWORD
	
	send message (
		m, 
		CB_GETEDITSEL, 
		starting position: WPARAM, 
		ending position: LPARAM)
		
	def changed = 
		starting position [] <> starting position (m) ||
		ending position [] <> ending position (m)
		
	// reset before sending event
	starting position (m) = starting position []
	ending position (m) = ending position []

	if changed
		on selection changed (m)
	end

end
//[cf]
//[of]:get style
private func get style (m: drop down edit box)

	def style = base style (m) | CBS_AUTOHSCROLL | CBS_DROPDOWN | WS_VSCROLL
	
	//if is read only (m)
	//	style |= ES_READONLY
	//end
	
	if edit border (style (m)) == border single
		style |= WS_BORDER
	end
	
	return style

end
//[cf]
//[of]:get ex style
private func get ex style (m: drop down edit box)

	if edit border (style (m)) == border sunken
		return WS_EX_CLIENTEDGE
	else
		return 0:d
	end
	
end
//[cf]
//[c]
//[of]:is dropped down
func is dropped down (m: drop down edit box)
	return send message (m, CB_GETDROPPEDSTATE) == 1
end
//[cf]
//[of]:show drop down (show)
//[c]Show / Hide the drop down list
//[c]
func show drop down (m: drop down edit box, show: bool)
	send message (m, CB_SHOWDROPDOWN, show:WPARAM)
end
//[cf]
//[cf]
//[cf]
//[of]:drop down edit box class
//[of]:type
public struct drop down edit box class : local box class
	// empty
end
//[cf]
//[of]:drop down edit box class
public func drop down edit box class

	def c = the drop down edit box class
	if ~ initialized
		initialized = true
		c . copy (box class)
		c . release = ^actual release (drop down edit box)
		c . compute min size = ^actual compute min size (drop down edit box)
		c . on focus = ^handle focus (drop down edit box, event)
		c . cut = ^actual cut (drop down edit box)
		c . copy = ^actual copy (drop down edit box)
		c . paste = ^actual paste (drop down edit box)
		c . clear = ^actual clear (drop down edit box)
		c . select all = ^actual select all (drop down edit box)
		c . can copy = ^actual can copy (drop down edit box)
		c . can paste = ^actual can paste (drop down edit box)
		c . can clear = ^actual can clear (drop down edit box)
		c . can select all = ^yes (box)
		c . set read only = ^actual set read only (drop down edit box, bool)
		c . accept focus = ^yes (box)
		c . wm key down = ^wm key down (drop down edit box, UINT, WPARAM, LPARAM)
		c . wm char = ^wm char (drop down edit box, UINT, WPARAM, LPARAM)
		c . wm size = ^wm size (drop down edit box, UINT, WPARAM, LPARAM)
		c . command = ^actual win command (drop down edit box, WORD)
		c . move = ^actual move (drop down edit box, rectangle, bool)
	end
	return c

end

def initialized = false
def the drop down edit box class: local drop down edit box class
//[cf]
//[cf]

⌨️ 快捷键说明

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