majkinetor wrote:
The only thing I didn't wrap are notification handlers for text change, button clicks etc. This is fairly trivial to add, but I didn't have time now.
I was recently using this control for something, & needed to wrap the notification interface for some simple stuff.
Code:
;----------------------------------------------------------------------------------------------------
; Function: SetEvents
; Set notification events
;
; Parameters:
; func - Subroutine that will be called on events.
; e - White space separated list of events to monitor (by default, null).
;
; Globals:
; RG_EVENT - Specifies event that occurred. Event must be registered to be able to monitor them.
; RG_ROW - String containing zero based row number.
; RG_COLUMN - String containing zero based column number.
; Events & Infos:
; HEADERCLICK - Sent when user clicks header.
; BUTTONCLICK - Sent when user clicks the button in a button cell.
; CHECKCLICK - Sent when user double clicks the checkbox in a checkbox cell.
; IMAGECLICK - Sent when user double clicks the image in an image cell.
; BEFORESELCHANGE - (not implemented) Sent when user request a selection change.
; AFTERSELCHANGE - Sent after a selection change.
; BEFOREEDIT - Sent before the cell edit control shows.
; AFTEREDIT - Sent when the cell edit control is about to close.
; BEFOREUPDATE - (not implemented) Sent before a cell updates grid data.
; AFTERUPDATE - (not implemented) Sent after grid data has been updated.
; USERCONVERT - (not implemented) Sent when user cell needs to be converted.
;
; Returns:
; "OK" if succesiful, error string otherwise
;
RG_SetEvents(hGrd, func, e=""){
local old, hmask
static GN_HEADERCLICK=0x1,GN_BUTTONCLICK=0x2,GN_CHECKCLICK=0x3,GN_IMAGECLICK=0x4
,GN_BEFORESELCHANGE=0x5,GN_AFTERSELCHANGE=0x6,GN_BEFOREEDIT=0x7,GN_AFTEREDIT=0x8
,GN_BEFOREUPDATE=0x9,GN_AFTERUPDATE=0xa,GN_USERCONVERT=0xb, WM_NOTIFY:=0x4E
static events="HEADERCLICK,BUTTONCLICK,CHECKCLICK,IMAGECLICK,BEFORESELCHANGE,AFTERSELCHANGE,BEFOREEDIT,AFTEREDIT,BEFOREUPDATE,AFTERUPDATE,USERCONVERT"
if !IsLabel(func)
return "Err: label doesn't exist`n`n" func
RG_%hGrd%_mask := "" ; clear any previous set mask
loop, parse, e, %A_Tab%%A_Space%
{
IfEqual, A_LoopField, , continue
if A_LoopField not in %events%
return "Err: unknown event - '" A_LoopField "'"
RG_%hGrd%_mask .= RG_%hGrd%_mask ? "," . GN_%A_LOOPFIELD% : GN_%A_LOOPFIELD%
}
IfEqual, RG_%hGrd%_mask,, return ; not monitoring any events
old := OnMessage(WM_NOTIFY, "RG_onNotify") ; set RaGrid msg handler and remember old one
if (old != "RG_onNotify")
RG_oldNotify := RegisterCallback(old) ; store callable old message handler
hGrd += 0
RG_%hGrd%_func := func
return "OK"
}
RG_onNotify(wparam, lparam, msg, hwnd) {
local code, hw, row,col,mask
static pInfo
static GN_HEADERCLICK=0x1,GN_BUTTONCLICK=0x2,GN_CHECKCLICK=0x3,GN_IMAGECLICK=0x4
,GN_BEFORESELCHANGE=0x5,GN_AFTERSELCHANGE=0x6,GN_BEFOREEDIT=0x7
,GN_AFTEREDIT=0x8,GN_BEFOREUPDATE=0x9,GN_AFTERUPDATE=0xa,GN_USERCONVERT=0xb
; Call previous set WM_NOTIFY
RG_oldNotify ? DllCall(RG_oldNotify, "uint", wparam, "uint", lparam, "uint", msg, "uint", hwnd) : ""
hw := NumGet(lparam+0) ; control sending the message - this RaGrid
mask := RG_%hw%_mask ; current events monitoring for
SetFormat, integer, hex
code := NumGet(lparam+8) ;-
SetFormat, integer, d
if code not in %mask%
return
RG_ROW := NumGet(lparam+16), RG_COLUMN := NumGet(lparam+12)
if (code = GN_HEADERCLICK) {
RG_EVENT := "HEADERCLICK", RG_ROW := ""
GoSub % RG_%hw%_func
return
}
if (code = GN_BUTTONCLICK) {
RG_EVENT := "BUTTONCLICK"
GoSub % RG_%hw%_func
return
}
if (code = GN_CHECKCLICK) {
RG_EVENT := "CHECKCLICK"
GoSub % RG_%hw%_func
return
}
if (code = GN_IMAGECLICK) {
RG_EVENT := "IMAGECLICK"
GoSub % RG_%hw%_func
return
}
; if (code = GN_BEFORESELCHANGE) {
; RG_EVENT := "BEFORESELCHANGE"
; GoSub % RG_%hw%_func
; return
; }
if (code = GN_AFTERSELCHANGE) {
IfEqual, pInfo, %RG_ROW%|%RG_COLUMN%, return ; filter out mutiple dup message calls
pInfo = %RG_ROW%|%RG_COLUMN% ; store info for comparison in next iteration
RG_EVENT := "AFTERSELCHANGE"
GoSub % RG_%hw%_func
return
}
if (code = GN_BEFOREEDIT) {
RG_EVENT := "BEFOREEDIT"
GoSub % RG_%hw%_func
return
}
if (code = GN_AFTEREDIT) {
RG_EVENT := "AFTEREDIT"
GoSub % RG_%hw%_func
return
}
; if (code = GN_BEFOREUPDATE) {
; RG_EVENT := "BEFOREUPDATE"
; GoSub % RG_%hw%_func
; return
; }
; if (code = GN_AFTERUPDATE) {
; RG_EVENT := "AFTERUPDATE"
; GoSub % RG_%hw%_func
; return
; }
}
I tried implementing your
stacking techniques, as not to screw up any other wrappers that use
WM_NOTIFY message. It seems to test out okay, but you may want to double check it though, to make sure I got it right (if you get a chance that is..)
Code:
#Include RaGrid.ahk
#SingleInstance, force
Gui, +LastFound
hwnd := WinExist()
;EDITTEXT,EDITLONG, CHECKBOX, COMBOBOX, HOTKEY, BUTTON, IMAGE, DATE, TIME, USER, EDITBUTTON
hGrd := RG_Add(hwnd, 0, 30, 800, 500, "GRIDFRAME VGRIDLINES NOSEL" )
RG_AddColumn(hGrd, "cap=zero" , "w=150", "ha=1", "ca=0", "type=EditText" )
RG_AddColumn(hGrd, "cap=one" , "w=150" ,"ha=1", "ca=0", "type=EditText" )
RG_AddColumn(hGrd, "cap=two" , "w=180" ,"ha=1", "ca=0", "type=EditText" )
RG_AddColumn(hGrd, "cap=three", "w=150" ,"ha=1", "ca=0", "type=EditText" )
RG_SetFont(hGrd, "s10 bold, Arial")
RG_SetHdrHeight(hGrd, 30), RG_SetRowHeight(hGrd, 22)
Loop, 20
{
aCol1 := aCol2 := aCol3 := aCol4 := "Row=" A_Index - 1 " Col="
aCol1 .= 0, aCol2 .= 1, aCol3 .= 2, aCol4 .= 3
RG_AddRow(hGrd, "aCol")
}
Gui, Show, h500 w800
; -- Set events...
; "HEADERCLICK,BUTTONCLICK,CHECKCLICK,IMAGECLICK,BEFORESELCHANGE,AFTERSELCHANGE,BEFOREEDIT
; ,AFTEREDIT,BEFOREUPDATE,AFTERUPDATE,USERCONVERT"
RG_SetEvents(hGrd, "OnRgEvent", "HEADERCLICK AFTERSELCHANGE BEFOREEDIT AFTEREDIT")
;-- Demonstrate that WM_NOTIFY events are stacked: Experiment w/ the order to see
Alternate_WM_NOTIFY(func, 1, 0, 0)
RG_SetEvents(hGrd, "OnRgEvent", "AFTERSELCHANGE AFTEREDIT") ; Change previous set event notifiers
Alternate_WM_NOTIFY2(func, 1, 0, 0)
; RG_SetEvents(hGrd, "OnRgEvent", "") ; Turn event notification off (or change)
return
^l::reload
OnRgEvent:
ToolTip, % A_Now " - " RG_EVENT " | " RG_ROW " " RG_COLUMN, 20, 40, 1
; OutputDebug % RG_EVENT " | " RG_ROW " " RG_COLUMN
return
Alternate_WM_NOTIFY(wparam, lparam, msg, hwnd){
static WM_NOTIFY := 0x4E, old=0, user
if !old {
old := OnMessage(WM_NOTIFY, "Alternate_WM_NOTIFY"), user := wparam
old := old = "Alternate_WM_NOTIFY" ? "-" : RegisterCallback(old, "", 4)
return
}
if old != -
DllCall(old, "uint", wparam, "uint", lparam, "uint", msg, "uint", hwnd)
;Test message handler here ....
ToolTip, % A_Now " - Message stacking test notifier", 20, 20, 2
}
Alternate_WM_NOTIFY2(wparam, lparam, msg, hwnd){
static WM_NOTIFY := 0x4E, old=0, user
if !old {
old := OnMessage(WM_NOTIFY, "Alternate_WM_NOTIFY2"), user := wparam
old := old = "Alternate_WM_NOTIFY2" ? "-" : RegisterCallback(old, "", 4)
return
}
if old != -
DllCall(old, "uint", wparam, "uint", lparam, "uint", msg, "uint", hwnd)
;Test message handler here ....
ToolTip, % A_Now " - Message stacking test notifier2", 20, 60, 3
}
;- still used within in RaGrid.ahk..
InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
{
Loop %pSize% ; Copy each byte in the integer into the structure as raw binary data.
DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}
ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
{
Loop %pSize% ; Build the integer by adding up its bytes.
result += *(&pSource + pOffset + A_Index-1) << 8*(A_Index-1)
if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
return result ; Signed vs. unsigned doesn't matter in these cases.
; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
return -(0xFFFFFFFF - result + 1)
}