AllowLVEdits 2.10 Beta
Posted: Tue Jun 19, 2007 11:45 pm
Some work has been done on this library, specifically keyboard control is added to the editable cells, along with auto-scrolling. Arrow keys save the edit and move to the next cell in the direction.
Code: Select all
;=========================================================
; Library: AllowLVEdits 2.10
; Author: netmaestro
; Date: June 19, 2007
; Target OS: Microsoft Windows All
; Target Compiler: PureBasic version 4.0+
; License: Free, unrestricted, no warranty
;==========================================================
#LVM_GETSUBITEMRECT = #LVM_FIRST + 56
#LVM_SUBITEMHITTEST = #LVM_FIRST + 57
#LVM_GETHEADER = #LVM_FIRST + 31
Global _edits210_oldlist,_edits210_EditActive, _edits210_oldstring, _edits210_string, _edits210_decimal, _edits210_container
Global _edits210_itemrect.RECT, _edits210_window, _edits210_item, _edits210_subitem, _edits210_gadget
Global Dim MoneyColumn(100)
Global Dim Masked(100)
Declare.s GetNewText()
Procedure SaveAndExit()
tmp$ = GetGadgetText(_edits210_string)
crlf = FindString(tmp$, #CRLF$, 1)
If crlf
SetGadgetText(_edits210_string,ReplaceString(tmp$,#CRLF$,""))
SendMessage_(sg,#EM_SETSEL,crlf-1,crlf-1)
EndIf
If Moneycolumn(_edits210_subitem)
tmpout.s = Trim(GetGadgetText(_edits210_string))
ploc = FindString(tmpout,Chr(_edits210_decimal),1)
If ploc
If ploc = 1
tmpout = "0" + tmpout
EndIf
While Len(tmpout) - FindString(tmpout,Chr(_edits210_decimal),1) < 2
tmpout+"0"
SetGadgetText(_edits210_string, tmpout)
Wend
Else
If tmpout <> ""
tmpout + Chr(_edits210_decimal) + "00"
SetGadgetText(_edits210_string, tmpout)
EndIf
EndIf
SetGadgetItemText(_edits210_gadget,_edits210_item, RSet(Trim(tmpout),Moneycolumn(_edits210_subitem)+3," "), _edits210_subitem)
Else
SetGadgetItemText(_edits210_gadget,_edits210_item, GetGadgetText(_edits210_string), _edits210_subitem)
EndIf
FreeGadget(_edits210_string)
FreeGadget(_edits210_container)
_edits210_EditActive = #False
EndProcedure
Procedure SubClass_String(hwnd, Message, wparam, lparam)
Protected blocking=0, ploc, tmpout.s
result = CallWindowProc_(_edits210_oldlist, hwnd, Message, wparam, lparam)
Select Message
Case #WM_KEYDOWN
Select wparam
Case 37
SendMessage_(hwnd, #EM_GETSEL, @first.l, @last.l)
If first = 0
SaveAndExit()
currentsubitem = _edits210_subitem
_edits210_subitem - 1
If _edits210_subitem >= 1
While masked(_edits210_subitem) And _edits210_subitem >= 0
_edits210_subitem - 1
If _edits210_subitem < 1
_edits210_subitem = currentsubitem
EndIf
Wend
Else
_edits210_subitem + 1
EndIf
RtlZeroMemory_(@_edits210_itemrect,SizeOf(RECT))
_edits210_itemrect\top = _edits210_subitem
SendMessage_(GadgetID(_edits210_gadget), #LVM_GETSUBITEMRECT, _edits210_item, @_edits210_itemrect)
GetNewText()
EndIf
Case 39
SendMessage_(hwnd, #EM_GETSEL, @first.l, @last.l)
If Len(GetGadgetText(_edits210_string)) = last
headerhWnd=SendMessage_(GadgetID(_edits210_gadget),#LVM_GETHEADER,0,0)
numcolumns = SendMessage_(headerhWnd, #HDM_GETITEMCOUNT,0,0)
SaveAndExit()
currentsubitem = _edits210_subitem
_edits210_subitem + 1
If _edits210_subitem < numcolumns
While masked(_edits210_subitem) And _edits210_subitem <= numcolumns
_edits210_subitem + 1
If _edits210_subitem >= numcolumns
_edits210_subitem = currentsubitem
EndIf
Wend
Else
_edits210_subitem -1
EndIf
RtlZeroMemory_(@_edits210_itemrect,SizeOf(RECT))
_edits210_itemrect\top = _edits210_subitem
SendMessage_(GadgetID(_edits210_gadget), #LVM_GETSUBITEMRECT, _edits210_item, @_edits210_itemrect)
GetNewText()
EndIf
Case 38
SaveAndExit()
_edits210_item - 1 : If _edits210_item <= 0 : _edits210_item = 0 : EndIf
RtlZeroMemory_(@_edits210_itemrect,SizeOf(RECT))
_edits210_itemrect\top = _edits210_subitem
SendMessage_(GadgetID(_edits210_gadget), #LVM_GETSUBITEMRECT, _edits210_item, @_edits210_itemrect)
GetNewText()
Case 40
SaveAndExit()
_edits210_item + 1:If _edits210_item >= CountGadgetItems(_edits210_gadget):_edits210_item - 1 : EndIf
RtlZeroMemory_(@_edits210_itemrect,SizeOf(RECT))
_edits210_itemrect\top = _edits210_subitem
SendMessage_(GadgetID(_edits210_gadget), #LVM_GETSUBITEMRECT, _edits210_item, @_edits210_itemrect)
GetNewText()
EndSelect
Case #WM_KEYUP
Select wparam
Case 13
SaveAndExit()
Case 27
FreeGadget(_edits210_string)
FreeGadget(_edits210_container)
_edits210_EditActive = #False
EndSelect
Case #WM_CHAR
If MoneyColumn(_edits210_subitem)
blocking = 1
Select wparam
Case _edits210_decimal, 48 To 57
tmpout.s = GetGadgetText(_edits210_string)
If FindString(tmpout, Chr(_edits210_decimal), 1) = 0
If Len(tmpout) > MoneyColumn(_edits210_subitem)
If wparam <> _edits210_decimal
SendMessage_(hwnd, #EM_GETSEL, 0, @pos)
SetGadgetText(_edits210_string, Left(tmpout,Len(tmpout)-1))
SendMessage_(hwnd, #EM_SETSEL, pos-1, pos-1)
EndIf
EndIf
EndIf
If wparam = _edits210_decimal
If CountString(tmpout, Chr(_edits210_decimal)) > 1
SendMessage_(hwnd, #EM_GETSEL, 0, @pos)
SetGadgetText(_edits210_string, Left(tmpout,Len(tmpout)-1))
SendMessage_(hwnd, #EM_SETSEL, pos-1, pos-1)
EndIf
EndIf
If FindString(tmpout,Chr(_edits210_decimal),1)
If Len(tmpout) - FindString(tmpout,Chr(_edits210_decimal),1) > 2
SendMessage_(hwnd, #EM_GETSEL, 0, @pos)
SetGadgetText(_edits210_string, Left(tmpout,Len(tmpout)-1))
SendMessage_(hwnd, #EM_SETSEL, pos-1, pos-1)
EndIf
EndIf
Default
If wparam <> 8 And wparam <> 13
tmpout.s = GetGadgetText(_edits210_string)
SendMessage_(hwnd, #EM_GETSEL, 0, @pos)
SetGadgetText(_edits210_string, Left(tmpout,Len(tmpout)-1))
SendMessage_(hwnd, #EM_SETSEL, pos-1, pos-1)
EndIf
EndSelect
EndIf
Case #WM_PASTE
If MoneyColumn(_edits210_subitem)
tmpout.s = GetGadgetText(_edits210_string)
If FindString(tmpout,Chr(_edits210_decimal),1)
validlength = MoneyColumn(_edits210_subitem)+3
Else
validlength = MoneyColumn(_edits210_subitem)
EndIf
If Len(tmpout)<=validlength
ok = #True
*cc.CHARACTER = @tmpout
While *cc\c
Select *cc\c
Case '0' To '9', _edits210_decimal
Default
ok = #False
EndSelect
*cc+1
Wend
Else
ok = #False
EndIf
If Not ok
SetGadgetText(_edits210_string, "")
EndIf
EndIf
EndSelect
ProcedureReturn result
EndProcedure
Procedure.s GetNewText()
_edits210_EditActive = #True
Protected grect.rect
twleft = _edits210_itemrect\left+1
twtop = _edits210_itemrect\top
winwidth = _edits210_itemrect\right-_edits210_itemrect\left-1
winheight = _edits210_itemrect\bottom-_edits210_itemrect\top-1
CreateGadgetList(GadgetID(_edits210_gadget))
_edits210_container = ContainerGadget(#PB_Any, twleft-2,twtop-2,winwidth+4,winheight+4)
HideGadget(_edits210_container, 1)
SetGadgetColor(_edits210_container,#PB_Gadget_BackColor, #Black)
If MoneyColumn(_edits210_subitem)
_edits210_string = StringGadget(#PB_Any,2,2,winwidth,winheight,RemoveString(GetGadgetItemText(_edits210_gadget,_edits210_item,_edits210_subitem)," "),#PB_String_BorderLess|#ES_CENTER|#ES_MULTILINE|#ES_AUTOVSCROLL)
Else
_edits210_string = StringGadget(#PB_Any,2,2,winwidth,winheight,GetGadgetItemText(_edits210_gadget,_edits210_item,_edits210_subitem),#PB_String_BorderLess|#ES_CENTER|#ES_MULTILINE|#ES_AUTOVSCROLL)
EndIf
CloseGadgetList()
SetGadgetFont(_edits210_string, GetGadgetFont(_edits210_gadget))
UseGadgetList(WindowID(_edits210_window))
SetActiveGadget(_edits210_string)
_edits210_oldstring=SetWindowLong_(GadgetID(_edits210_string), #GWL_WNDPROC, @SubClass_String())
SendMessage_(GadgetID(_edits210_string),#EM_SETSEL,0,-1)
HideGadget(_edits210_container, 0)
GetWindowRect_(GadgetID(_edits210_gadget), @gr.RECT)
GetWindowRect_(GadgetID(_edits210_container), @cr.RECT)
GetClientRect_(GadgetID(_edits210_gadget), @grc.RECT)
If cr\top - gr\top < winheight
SendMessage_(GadgetID(_edits210_gadget), #WM_VSCROLL, #SB_LINEUP ,0)
ElseIf cr\top - gr\top > grc\bottom-grc\top-winheight
SendMessage_(GadgetID(_edits210_gadget), #WM_VSCROLL, #SB_LINEDOWN ,0)
EndIf
If GadgetWidth(_edits210_gadget)-twleft < winwidth
SendMessage_(GadgetID(_edits210_gadget), #WM_HSCROLL, #SB_RIGHT, 0)
ElseIf twleft<0
SendMessage_(GadgetID(_edits210_gadget), #WM_HSCROLL, #SB_LEFT, 0)
EndIf
EndProcedure
Procedure ResizeEdit(hwnd)
RtlZeroMemory_(@_edits210_itemrect,SizeOf(RECT))
_edits210_itemrect\top = _edits210_subitem
SendMessage_(hwnd, #LVM_GETSUBITEMRECT, _edits210_item, @_edits210_itemrect)
twleft = _edits210_itemrect\left+1
twtop = _edits210_itemrect\top
winwidth = _edits210_itemrect\right-_edits210_itemrect\left-1
winheight = _edits210_itemrect\bottom-_edits210_itemrect\top-1
ResizeGadget(_edits210_container,twleft-2,twtop-2,winwidth+4,winheight+4)
ResizeGadget(_edits210_string, 2,2, GadgetWidth(_edits210_container)-4, GadgetHeight(_edits210_container)-4)
InvalidateRect_(GadgetID(_edits210_container),0,1)
If GadgetY(_edits210_container) < winheight
HideGadget(_edits210_container, 1)
Else
HideGadget(_edits210_container, 0)
SetActiveGadget(_edits210_string)
EndIf
EndProcedure
Procedure SubClass_LV(hwnd, Message, wparam, lparam)
result = CallWindowProc_(_edits210_oldlist, hwnd, Message, wparam, lparam)
If message = #WM_KEYUP
If wparam = #VK_TAB
If GetAsyncKeyState_(#VK_SHIFT) & 32768
SaveAndExit()
currentsubitem = _edits210_subitem
_edits210_subitem - 1
If _edits210_subitem >= 1
While masked(_edits210_subitem) And _edits210_subitem >= 0
_edits210_subitem - 1
If _edits210_subitem < 1
_edits210_subitem = currentsubitem
EndIf
Wend
Else
_edits210_subitem + 1
EndIf
RtlZeroMemory_(@_edits210_itemrect,SizeOf(RECT))
_edits210_itemrect\top = _edits210_subitem
SendMessage_(GadgetID(_edits210_gadget), #LVM_GETSUBITEMRECT, _edits210_item, @_edits210_itemrect)
GetNewText()
Else
If IsGadget(_edits210_string)
headerhWnd=SendMessage_(GadgetID(_edits210_gadget),#LVM_GETHEADER,0,0)
numcolumns = SendMessage_(headerhWnd, #HDM_GETITEMCOUNT,0,0)
SaveAndExit()
currentsubitem = _edits210_subitem
_edits210_subitem + 1
If _edits210_subitem < numcolumns
While masked(_edits210_subitem) And _edits210_subitem <= numcolumns
_edits210_subitem + 1
If _edits210_subitem >= numcolumns
_edits210_subitem = currentsubitem
EndIf
Wend
Else
_edits210_subitem -1
EndIf
RtlZeroMemory_(@_edits210_itemrect,SizeOf(RECT))
_edits210_itemrect\top = _edits210_subitem
SendMessage_(GadgetID(_edits210_gadget), #LVM_GETSUBITEMRECT, _edits210_item, @_edits210_itemrect)
GetNewText()
EndIf
EndIf
EndIf
EndIf
If message = #WM_VSCROLL Or message = #WM_HSCROLL
If IsGadget(_edits210_container) And _edits210_container <> 0
ResizeEdit(hwnd)
EndIf
EndIf
If message=#WM_NOTIFY
If IsGadget(_edits210_container) And _edits210_container <> 0
*nmHEADER.HD_NOTIFY = lParam
Select *nmHEADER\hdr\code
Case #HDN_ITEMCHANGING
ResizeEdit(hwnd)
EndSelect
EndIf
EndIf
If Message = #WM_RBUTTONDOWN
If Not _edits210_EditActive
GetCursorPos_(@cp.POINT)
MapWindowPoints_(0,hwnd,@cp,1)
HitInfo.LVHITTESTINFO
Hitinfo\pt\x = cp\x
HitInfo\pt\y = cp\y
SendMessage_(hwnd,#LVM_SUBITEMHITTEST ,0,@HitInfo)
If hitinfo\isubitem > 0 And HitInfo\iItem >= 0
RtlZeroMemory_(@_edits210_itemrect,SizeOf(RECT))
_edits210_itemrect\top = hitinfo\iSubItem
SendMessage_(hwnd,#LVM_GETSUBITEMRECT, hitinfo\iitem, @_edits210_itemrect)
_edits210_item = hitinfo\iitem
_edits210_subitem = hitinfo\iSubItem
If Not Masked(_edits210_subitem)
GetNewText()
EndIf
EndIf
Else
FreeGadget(_edits210_string)
FreeGadget(_edits210_container)
_edits210_EditActive = #False
EndIf
EndIf
If Message = #WM_LBUTTONDOWN
If _edits210_EditActive
FreeGadget(_edits210_string)
FreeGadget(_edits210_container)
_edits210_EditActive = #False
EndIf
EndIf
ProcedureReturn result
EndProcedure
ProcedureDLL StartEditing(WindowNumber, GadgetNumber); Make ListIcon gadget cells editable
_edits210_window=WindowNumber
Protected cn$ = Space(100)
GetClassName_(GadgetID(GadgetNumber),@cn$,99)
If UCase(Trim(cn$)) = "SYSLISTVIEW32" And _edits210_oldlist = 0
_edits210_oldlist=SetWindowLong_(GadgetID(GadgetNumber), #GWL_WNDPROC, @SubClass_LV())
_edits210_gadget = GadgetNumber
Global Dim Masked(100)
Global Dim MoneyColumn(100)
_edits210_decimal = 46
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
ProcedureDLL StopEditing(GadgetNumber); Take ListIcon gadget out of editable mode
SetWindowLong_(GadgetID(GadgetNumber), #GWL_WNDPROC, _edits210_oldlist)
_edits210_oldlist = 0
EndProcedure
ProcedureDLL SetMoneyColumn(Column, Width) ; Width is number of digits before the decimal place
If _edits210_oldlist
If width >= 1
MoneyColumn(Column) = width
Else
MoneyColumn(Column) = 1
EndIf
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
ProcedureDLL DecimalMask(char) ; Char is the character you wish to use for decimal point, usually '.' or ',' (46 or 44)
_edits210_decimal = char
EndProcedure
ProcedureDLL MaskColumn(Column) ; Disallows edits for the passed column
If _edits210_oldlist
Masked(Column) = 1
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
Code: Select all
;=======================================================
; Program: AllowLVEdits 2.1 beta Demo program
; Author: netmaestro
;=======================================================
;
IncludeFile "AllowLVEdits210.pbi"
w = OpenWindow(0,0,0,800,700,"AllowLVEdits 2.1 Demo",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
CreateGadgetList(w)
ListIconGadget(0,0,0,800,700,"",0,#PB_ListIcon_GridLines)
For i=1 To 26
AddGadgetColumn(0,i,Chr(64+i),60)
Next
For i=1 To 50
AddGadgetItem(0, -1, Chr(10)+RSet(Str(i),2,"0"))
Next
For i=0 To CountGadgetItems(0)-1
SetGadgetItemColor(0,i,#PB_Gadget_FrontColor,#Black,1)
SetGadgetItemColor(0,i,#PB_Gadget_BackColor,RGB(246,247,244),1)
Next
StartEditing(0,0)
MaskColumn(1)
For i=1 To 15
SetMoneyColumn(i,4)
Next
Repeat:Until WaitWindowEvent()=#WM_CLOSE
StopEditing(0)