New Lexer:
/* Title:    Splitter
			 Splitter control.

			 (see splitter.png)

			 Splitter is control that is created between controls that need to have dynamic separation.
			 To use it, you first need to create the splitter (<Add>), then you have to activate it when all controls
			 that it separates are created (<Set>).
			 You can set splitter position with <SetPos> and obtain it with <GetPos>. 
			 You can also limit splitter movement with <Limit> function if you don't want controls it separates to be set completely invisible by the user.
			 
 Dependency:
			<Win> 1.24

 Effects:	
			- While user moves splitter, CoordMode of mouse is always returned to relative.
			- Upon movement, splitter will reset <Attach> for the parent, if present.			
 */

/*
 Function:	Add
 			Add new Splitter.
 
 Parameters:
 			Opt	    - Splitter Gui options. Splitter is subclassed Text control (Static), so it accepts any Text options.
					plus one the following: blackframe, blackrect, grayframe, grayrect, whiteframe, whiterect, sunken.
			Text    - Text to set.
			Handler - Notification function. See bellow.
			
 Handler:
 >			OnSplitter(Hwnd, Event, Pos)
		
			P - Triggered when user changes the position by dragging the splitter with mouse.
			D - User doubleclicked the splitter.
			R - User right clicked the splitter.

 Returns:
			Splitter handle.

 Remarks:
			This function adds a new splitter on the given position. User is responsible for correct position of the splitter.
			Splitter is inactive until you call <Set> function.
			When setting dimension of the splitter (width or height) use even numbers.
 */
Splitter_Add(Opt="", Text="", Handler="") {
	static SS_NOTIFY=0x100, SS_CENTER=0x200, SS_SUNKEN=0x1000, SS_BLACKRECT=4, SS_GRAYRECT=5, SS_WHITERECT=6, SS_BLACKFRAME=7, SS_GRAYFRAM=8, SS_WHITEFRAME=9

	hStyle := 0
	loop, parse, Opt, %A_Space%
			if A_LoopField in blackframe,blackrect,grayframe,grayrect,sunken,whiteframe,whiterect,sunken,center
			hStyle |= SS_%A_LoopField%
		else Opt .= A_LoopField " "

		Gui, Add, Text, HWNDhSep -hscroll -vscroll %SS_CENTERIMAGE% %SS_NOTIFY% center %Opt% %hStyle%, %Text%	
		hSep+=0
	if IsFunc(Handler)
		Splitter(hSep "Handler", Handler)
	return hSep
}

/*
 Function:	Add2Form
 			Add Splitter into the form. 

 Options:
			handler	- Splitter handler name.
			extra	- Extra parameters are transmited to <Add> Opt parameter.
 
 Remarks:
			Function is required by the Forms framework.
 */
Splitter_Add2Form(HParent, Txt, Opt){
	static parse = "Form_Parse"
	%parse%(Opt, "handler", handler, extra)
	DllCall("SetParent", "uint", hCtrl := Splitter_Add(extra, Txt, handler), "uint", HParent)
	return hCtrl
}

/*
 Function:	GetMax
 			Returns maximum position of the splitter.

 Remarks:
			Maximum position of the splitter will change if parent control is resized.
 */
Splitter_GetMax(HSep) {
	Win_Get( Win_Get(HSep, "P") , "Lwh", plw, plh)
	return (Splitter(HSep "bVert") ? plw : plh) - Splitter_getSize(HSep) - Splitter(HSep "L2")
}

Splitter_GetMin(HSep) {
	return Splitter(HSep "L1")
}

/*
 Function:	GetPos
 			Get position of the splitter.

 Parameters:
			Flag	- Set to "%" to return procentage instead position.

 Remarks:
			Position of the splitter is its x or y coordinate inside the parent window.
 */
Splitter_GetPos( HSep, Flag="" ) {
	pos := Win_GetRect(HSep, Splitter(HSep "bVert") ? "*x" : "*y")
	if (Flag = "%"){
		min := Splitter_GetMin(HSep), max := Splitter_GetMax(HSep)
		return 100*(pos-min)/(max-min)
	} else return pos
}

/*
 Function:	GetSize
 			Get size of the splitter.
 */
Splitter_GetSize(HSep) {
	Win_GetRect(HSep, "wh", w, h)
	return Splitter( HSep "bVert") ? w : h
}

/*
 Function:	Set
 			Initiates separation of controls.
 
 Parameters:
 			HSep - Splitter handle.
			Def	 - Splitter definition or words "off" or "on". The syntax of splitter definition is given bellow.
			Pos	 - Position of the splitter to apply upon initialization (optional).
			Limit - Decimal, sets start and end limits for splitter movement. The minimum and maximum splitter value will
					be adjusted by this value. For instance, .100 means that maximum value will be less by 100.

 Splitter Defintion:
 >		c11 c12 c13 ... Type c21 c22 c23 ...
		
		c1n - Controls left or top of the splitter.
		Type - Splitter type: " | " vertical or " - " horizontal.
		c2n	- Controls right or bottom of the splitter.
 */
Splitter_Set( HSep, Def, Pos="", Limit=0.0 ) {
	static

	if Def=off
		return Win_subclass(HSep, old)
	else if Def=on
			return Win_subclass(HSep, wndProc)

	if bVert := (InStr(Def, "|") != 0)
		Splitter(HSep "bVert", bVert)

	old := Win_subclass(HSep, wnadProc = "" ? "Splitter_wndProc" : wndProc, "", wndProc)

	StringSplit, L, Limit, .
		Splitter(HSep "Def", Def),  Splitter(HSep "L1", L1),  Splitter(HSep "L2", L2)
	return 	Splitter_SetPos(HSep, Pos)
}
/*
 Function:	SetPos
			Set splitter position.
 
 Parameters:
   			HSep - Splitter handle.
			Pos	 - Position to set. Position is the client x/y coordinate of the splitter control. 
				   If followed by the sign %, position is set using procentage of splitter range. 
				   If Pos is empty, function returns without any action. 

 Remarks:
			Due to the rounding, if you set position using procentage, actuall position may be slightly different.
			You can find out what is exact position set if you use <GetPos> with Flag set to "%".
 */
Splitter_SetPos(HSep, Pos, bInternal=false) {
	ifEqual, Pos,, return
	min := Splitter_GetMin(HSep), max := Splitter_GetMax(HSep)

	if SubStr(Pos, 0) = "%"
		Pos := min + SubStr(Pos, 1, -1)*(max-min)//100

	bVert := Splitter(HSep "bVert"),  Def := Splitter(HSep "Def")

	ifLess, Pos, %min%, SetEnv, Pos, %min%
	StringSplit, s, Def, %A_Space%

		Delta := Pos - Splitter_GetPos(HSep)
	v := bVert ? Delta : "",  h := bVert ? "" : Delta
	loop, %s0%
		{
		s := s%A_Index%
		if !otherSide
		{
			Win_MoveDelta(s, "", "", v, h)
			if s in |,-
				otherSide := true, Win_MoveDelta(HSep, v, h)
		} else 	Win_MoveDelta(s, v, h, -v, -h)
	}		
					
	Win_Redraw( Win_Get(HSep, "A") )						;redrawing imediate parent was not that good.
	IsFunc(f := "Attach") ? %f%( Win_Get(HSep, "P") ) : ""	;reset attach for parent of HSep

	if (handler := Splitter(HSep "Handler")) && bInternal
		%handler%(HSep, "P", Splitter_GetPos(HSep))
}

;=============================================== PRIVATE ===============================================

Splitter_wndProc(Hwnd, UMsg, WParam, LParam) {	
	static
	static WM_SETCURSOR := 0x20, WM_MOUSEMOVE := 0x200, WM_LBUTTONDOWN=0x201, WM_LBUTTONUP=0x202, WM_LBUTTONDBLCLK=515, WM_RBUTTONUP=517, SIZENS := 32645, SIZEWE := 32644

	If (UMsg = WM_SETCURSOR)
		return 1 
	
	if (UMsg = WM_MOUSEMOVE) {
		if !%Hwnd%_cursor
			%Hwnd%_bVert := Splitter(Hwnd "bVert"), %Hwnd%_cursor := DllCall("LoadCursor", "Uint", 0, "Int", %Hwnd%_bVert ? SIZEWE : SIZENS, "Uint")

		critical 	;safe, always in new thread.
				DllCall("SetCursor", "uint", %Hwnd%_cursor)
		if moving 
			Splitter_updateFocus(Hwnd)
	}

	if (UMsg = WM_LBUTTONDOWN) {
		DllCall("SetCapture", "uint", Hwnd),  parent := DllCall("GetParent", "uint", Hwnd, "Uint")
		VarSetCapacity(RECT, 16), DllCall("GetWindowRect", "uint", parent, "uint", &RECT)

		sz := Win_GetRect(Hwnd, %Hwnd%_bVert ? "w" : "h") // 2
		ch := Win_Get(parent, "Nh" )			;get caption size of parent window

	  ;prevent user from going offscreen with separator
		NumPut( NumGet(RECT, 0) + sz-1	,RECT, 0)
		NumPut( NumGet(RECT, 4) + sz+ch ,RECT, 4)
		NumPut( NumGet(RECT, 8) - sz+4 	,RECT, 8)
		NumPut( NumGet(RECT, 12)- sz+4	,RECT, 12)
				
		DllCall("ClipCursor", "uint", &RECT), DllCall("SetCursor", "uint", %Hwnd%_cursor)
		moving := true
	}
	if (UMsg = WM_LBUTTONUP){
		moving := false
	
		DllCall("ClipCursor", "uint", 0),  DllCall("ReleaseCapture")
		Splitter_SetPos(Hwnd, Splitter_updateFocus(), true)
	}

	if UMsg in %WM_LBUTTONDBLCLK%,%WM_RBUTTONUP%
	{
		handler := Splitter(Hwnd "Handler")
		ifEqual, handler,,return

		ifEqual, UMsg, %WM_LBUTTONDBLCLK%, SetEnv, Event, D
		else ifEqual, UMsg, %WM_RBUTTONUP%, SetEnv, Event, R
			
			%handler%(Hwnd, Event, Splitter_GetPos(Hwnd))
	}

	return DllCall("CallWindowProc","uint",A_EventInfo,"uint",hwnd,"uint",uMsg,"uint",wParam,"uint",lParam)
}

;Updates focus rectangle while mouse is moving. 
;If called without arguments it returns latest focus rectangle position.
Splitter_updateFocus( HSep="" ) {
	static

	if !HSep
		return pos - offset, dc := 0
	
	MouseGetPos, mx, my
		if !dc 
	{
		ifEqual, adrDrawFocusRect,, SetEnv, adrDrawFocusRect, % DllCall("GetProcAddress", uint, DllCall("GetModuleHandle", str, "user32"), str, "DrawFocusRect")
		CoordMode, mouse, relative

	   ;initialize dc, RECT, idx, delta(distance between mouse and splitter position), sz, pos & max when user starts moving.
		dc := Win_Get( HSep, "0D")		; take root DC, for some reason it doesn't work good on parent's DC

		Win_GetRect(HSep, "!xywh", sx, sy, sw, sh)
		VarSetCapacity(RECT, 16), NumPut(sx, RECT), NumPut(sy, RECT, 4), NumPut(sx+sw, RECT, 8), NumPut(sy+sh, RECT, 12) , sz := sh
		
		if bVert := Splitter( HSep "bVert" )
			 idx := 0,   delta := mx-sx,   sz := sw
		else idx := 4,   delta := my-sy,   sz := sh

       ;if in Panel, there will be offset to mouse movement according to its position.
		parent := Win_Get(HSep, "P")
		WinGetClass, cls, ahk_id %parent%
			offset :=  cls != "Panel" ? 0 : Win_GetRect( parent, bVert ? "!x" : "!y")

		pos := Splitter_GetPos(HSep),  
		max := offset + Splitter_getMax(HSep),	 min := offset + Splitter_getMin(HSep)
		return DllCall(adrDrawFocusRect, "uint", dc, "uint", &RECT)
	}
	pos := bVert ? mx-delta : my-delta
	ifLess, pos, %min%, SetEnv, pos, %min%
	else ifGreater, pos, %max%, SetEnv, pos, %max%

		DllCall(adrDrawFocusRect, "uint", dc, "uint", &RECT)
	NumPut(pos, RECT, idx),   NumPut(pos+sz, RECT, idx+8),  DllCall(adrDrawFocusRect, "uint", dc, "uint", &RECT)
}

;storage
Splitter(Var="", Value="~`a ", ByRef o1="", ByRef o2="", ByRef o3="", ByRef o4="", ByRef o5="", ByRef o6="") {
	static
	_ := %var%
	ifNotEqual, value,~`a , SetEnv, %var%, %value%
	return _
}

#include *i Win.ahk

/* Group: Examples
 (start code)
		w := 500, h := 600, sep := 5
		w1 := w//3, w2 := w-w1 , h1 := h // 2, h2 := h // 3

		Gui, Margin, 0, 0
		Gui, Add, Edit, HWNDc11 w%w1% h%h1%
		Gui, Add, Edit, HWNDc12 w%w1% h%h1%
		hSepV := Splitter_Add( "x+0 y0 h" h " w" sep )
		Gui, Add, Monthcal, HWNDc21 w%w2% h%h2% x+0
		Gui, Add, ListView, HWNDc22 w%w2% h%h2%, c1|c2|c3
		Gui, Add, ListBox,  HWNDc23 w%w2% h%h2% , 1|2|3

		sdef = %c11% %c12% | %c21% %c22% %c23%			;vertical splitter.
		Splitter_Set( hSepV, sdef )

		Gui, show, w%w% h%h%	
	return
 (end code)
 */

/* Group: About
	o Ver 1.6 by majkinetor.
	o Licenced under BSD <http://creativecommons.org/licenses/BSD/>.
 */