AllowLVEdits Version 2.2

Developed or developing a new product in PureBasic? Tell the world about it.
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: AllowLVEdits Version 2.0

Post by IdeasVacuum »

....Nothing to apologise for! Thank you for sharing the pbi file, I will study the methods carefully, my own efforts were reliable but way too slow with huge lists.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
electrochrisso
Addict
Addict
Posts: 980
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

Re: AllowLVEdits Version 2.0

Post by electrochrisso »

Ripper piece of coding there NM. :wink:
PureBasic! Purely one of the best 8)
Zach
Addict
Addict
Posts: 1654
Joined: Sun Dec 12, 2010 12:36 am
Location: Somewhere in the midwest
Contact:

Re: AllowLVEdits Version 2.0

Post by Zach »

Wow this is a pretty neat .pbi !

I wonder if I could use this. :mrgreen:
Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8425
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: AllowLVEdits Version 2.2

Post by netmaestro »

Update today, current version is 2.20.

While using the cashflow sample provided in the first post, I noticed that there was a delay in the edit box coming up. I traced it to too many recalcs being done, and this turned out to be happening because the library was sending #PB_EventType_Change to the calling program when a cell was edited. I had assumed that #PB_EventType_Change for the ListIcon meant cell contents were changed. I was wrong, it turns out that event type means only that the currently selected item is changed. Since there is no event type for cell changes, I had to make a custom one for this library. Also, I added three new commands useful to the programmer for when edits happen. Upon receiving the message #PB_Event_Gadget with EventType() = #Ale_Cellcontents_Changed, these commands are available:

Ale_ColumnChanged()
Ale_RowChanged()
Ale_OriginalText()

Details are in the preamble to the code in the first post, code is updated and the cashflow example is updated with undo/redo demonstration.
BERESHEIT
User avatar
electrochrisso
Addict
Addict
Posts: 980
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

Re: AllowLVEdits Version 2.2

Post by electrochrisso »

I noticed that too NM, I thought it was happening with updating the file, but still I only had a quick look at the code.
Those extra commands are a great edition. :D
Anyway thanks for the code to play with. :wink:
PureBasic! Purely one of the best 8)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8425
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: AllowLVEdits Version 2.2

Post by netmaestro »

I thought it was happening with updating the file
You are on the mark with that observation, that was half of the problem. I reworked it so that it only saves to the file if you click the save toolbar icon and on exit. All these years I've been misunderstanding #PB_EventType_Change for the listicon, it makes me wonder if I'm losing my mind :shock: Thanks for the testing and feedback, it's appreciated!
BERESHEIT
User avatar
GeBonet
Enthusiast
Enthusiast
Posts: 135
Joined: Fri Apr 04, 2008 6:20 pm
Location: Belgium

Re: AllowLVEdits Version 2.2

Post by GeBonet »

Very good job ... :D :D
If I had one suggestion it would be able to create multiple line for each date if necessary ... This would be a perfect time to log movements household budget.
But hey, it's just an idea ... :wink:
Sorry for my english :wink: ! (Windows Xp, Vista and Windows 7, Windows 10)
User avatar
Tomi
Enthusiast
Enthusiast
Posts: 270
Joined: Wed Sep 03, 2008 9:29 am

Re: AllowLVEdits Version 2.2

Post by Tomi »

Thanks for update, very useful
please me if maybe it and you find a bit free^free time:
if i paste from clipboard into a cell and then click on other cell , i need my pasted things remain into cell and don't remove in event, sorry for my bad English :D
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8425
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: AllowLVEdits Version 2.2

Post by netmaestro »

@Tomi: If you hit <Enter> after the paste the data will stay.
GeBonet wrote:If I had one suggestion it would be able to create multiple line for each date if necessary ... This would be a perfect time to log movements household budget.
Excellent suggestion. I had been trying to keep the demo code as simple as possible but this idea is too good not to implement. Cashflow demo is now updated as follows:

-Left doubleclick a date and a duplicate is inserted below it
-Right doubleclick a duplicated date and the row is deleted.

Right-doubleclicks for deletions are bulletproof because they are only executed if the date in the row above is identical. This way you can't accidentally remove a date altogether or remove the wrong date.

Thanks for the suggestion, it makes the program much more usable as a cashflow worksheet :mrgreen:
BERESHEIT
User avatar
GeBonet
Enthusiast
Enthusiast
Posts: 135
Joined: Fri Apr 04, 2008 6:20 pm
Location: Belgium

Re: AllowLVEdits Version 2.2

Post by GeBonet »

Well now, I am glad it is useful ... And thank you! :lol:
A thousand apologies if this shows the reality of balances :cry: :mrgreen:
Very good job. :lol: :lol:
Sorry for my english :wink: ! (Windows Xp, Vista and Windows 7, Windows 10)
User avatar
electrochrisso
Addict
Addict
Posts: 980
Joined: Mon May 14, 2007 2:13 am
Location: Darling River

Re: AllowLVEdits Version 2.2

Post by electrochrisso »

All these years I've been misunderstanding #PB_EventType_Change for the listicon, it makes me wonder if I'm losing my mind :shock: Thanks for the testing and feedback, it's appreciated!
Nah, I think PB getting many new features on each update to have time to test every option in every situation. :)
PureBasic! Purely one of the best 8)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8425
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: AllowLVEdits Version 2.2

Post by netmaestro »

This program is updated to use the new module library. Here's the code:

Code: Select all

;======================================================================================================================
; Library:           AllowLVEdits 3.0
; Author:            netmaestro 
; Date:              June 19, 2007 last update July 7, 2013
; Target OS:         Microsoft Windows All
; Target Compiler:   PureBasic version 5.20+
; License:           Free, unrestricted, no warranty
;
; This library allows the user to edit the contents of ListIcon cells
; by right-clicking on them.
;
; EXPORTED COMMANDS:
;
; StartEditing(WindowNumber, GadgetNumber); Make ListIcon gadget cells editable
;
; StopEditing(); Take ListIcon gadget out of editable mode
;
; SetMoneyColumn(Column, Width) ; Width is number of digits before the decimal place
;
; DecimalMask(char) ; Char is the character you wish to use for decimal point, usually '.' or ',' (46 or 44)
;
; MaskColumn(Column) ; Disallows edits for the passed column
;
; Ale_RowChanged() ; Returns the row of the last-edited item
;
; Ale_ColumnChanged() ; Returns the column of the last-edited item
;
; Ale_OriginalText() ; Returns a string containing the original item text before the edit
;
; DETECTING CHANGES:
;
; When this library detects an edit to a listicon cell, it will send a #PB_Event_Gadget message
; to your WaitWindowEvent() loop with the EventType() of #Ale_Cellcontents_Changed. When you receive
; this message, three commands are available to you:
;
;   - Ale_RowChanged()
;   - Ale_ColumnChanged()
;   - Ale_OriginalText()
;
; These commands may only be called after receiving #PB_Event_Gadget with event type = #Ale_Cellcontents_Changed.
; Additionally, they may only be called once as calling them clears their contents. So if you need them later you
; must save their return values in a variable of your own.
;
; Using these three commands and a linked-list or array of stored changes, you can easily provide a user with
; the option of cancelling all changes or stepping through an undo list.
;
; This version of the program is contstructed using the Module library which is available beginning with v5.20
;
; Include this file in your program and if it's the only module you'll be using in your project you can do:
;
; Usemodule LVEdit
;   ... call the commands as needed
; Unusemodule LVEdit
;
; If you are using other modules in your project the commands must be qualified with the module name like so:
;
; LVEdit::StartEditing(<window>, <listicon>)
;
;
;======================================================================================================================

DeclareModule LVEdit
  
  Enumeration #PB_Event_FirstCustomValue
    #Ale_Cellcontents_Changed 
  EndEnumeration
  
  Declare Ale_ColumnChanged(cell = -1)
  Declare Ale_RowChanged(Item = -1)
  Declare.s Ale_OriginalText(orig$ = "")
  Declare SaveAndExit()
  Declare SaveAndExit_Desc(newtext$)
  Declare SubClass_String(hwnd, Message, wparam, lparam)
  Declare.s GetNewText()
  Declare ResizeEdit(hwnd)
  Declare hookproc(nCode, wparam, lparam)
  Declare SubClass_LV(hwnd, Message, wparam, lparam)
  Declare StopEditing(); Take ListIcon gadget out of editable mode
  Declare StartEditing(WindowNumber, GadgetNumber); Make ListIcon gadget editable
  Declare SetMoneyColumn(Column, Width) ; Width is number of digits before the decimal place
  Declare DecimalMask(char) ;Char is the symbol to use For decimal point, usually '.' Or ',' (46 Or 44)
  Declare MaskColumn(Column) ; Disallows edits for the passed column, the lib will gray it out
  
EndDeclareModule

Module LVEdit
  
  Import ""
    PB_Gadget_SendGadgetCommand(hWnd, EventType)
  EndImport
  
  Structure EDITDATA
    Array MoneyColumn.i(100)
    Array Masked.i(100)
    _edits210_oldlist.i
    _edits210_EditActive.i
    _edits210_oldstring.i
    _edits210_string.i 
    _edits210_decimal.i
    _edits210_container.i 
    _edits210_window.i 
    _edits210_item.i 
    _edits210_subitem.i 
    _edits210_gadget.i
    _edits210_itemrect.RECT
    _edits210_menuhook.i
  EndStructure
  
  Global descpopup = CreatePopupMenu(#PB_Any) ; Scope is limited to the module
  
  MenuItem(10, "Opening Balance")
  MenuItem(11, "Deposit")
  MenuItem(12, "Campsite Fees")
  MenuItem(13, "Firewood Sales")
  MenuBar()
  MenuItem(14, "Fuel Receipt")
  MenuItem(15, "Propane Receipt")
  MenuItem(16, "Tools/Supplies Receipt")
  MenuItem(17, "Withdrawal")
  MenuBar()
  MenuItem(18, "<leave blank>")
  
  *LVEdits.EDITDATA = AllocateMemory(SizeOf(EDITDATA))
  InitializeStructure(*LVEdits, EDITDATA)
  
  Procedure Ale_ColumnChanged(cell = -1)
    Static cellchanged
    If cell<> -1
      cellchanged = cell
      ProcedureReturn
    Else
      result = cellchanged
      cellchanged = -1
      ProcedureReturn result
    EndIf
  EndProcedure
  
  Procedure Ale_RowChanged(Item = -1)
    Static Itemchanged
    If Item<> -1
      Itemchanged = Item
      ProcedureReturn
    Else
      result = Itemchanged
      Itemchanged = -1
      ProcedureReturn result
    EndIf
  EndProcedure
  
  Procedure.s Ale_OriginalText(orig$ = "")
    Static originaltext$
    If orig$ <> ""
      originaltext$ = orig$
      ProcedureReturn
    Else
      result$ = originaltext$
      originaltext$ = ""
      ProcedureReturn result$
    EndIf
  EndProcedure
  
  Procedure SaveAndExit()
    
    Shared *LVEdits.EDITDATA
    
    tmp$ = GetGadgetText(*LVEdits\_edits210_string)
    orig$ = GetGadgetItemText(*LVEdits\_edits210_gadget,*LVEdits\_edits210_item,*LVEdits\_edits210_subitem)
    If Trim(tmp$) <> Trim(orig$)
      SendChange = #True
      Ale_OriginalText(orig$)
    Else
      SendChange = #False
    EndIf
    If *LVEdits\_edits210_item >= 0
      SetGadgetState(*LVEdits\_edits210_gadget, *LVEdits\_edits210_item)
    EndIf
    crlf = FindString(tmp$, #CRLF$, 1)
    If crlf
      SetGadgetText(*LVEdits\_edits210_string,ReplaceString(tmp$,#CRLF$,""))
      SendMessage_(sg,#EM_SETSEL,crlf-1,crlf-1)
    EndIf
    If *LVEdits\MoneyColumn(*LVEdits\_edits210_subitem)
      tmpout.s  = Trim(GetGadgetText(*LVEdits\_edits210_string))
      ploc = FindString(tmpout,Chr(*LVEdits\_edits210_decimal),1)
      If ploc
        If ploc = 1
          tmpout = "0" + tmpout
        EndIf
        While Len(tmpout) - FindString(tmpout,Chr(*LVEdits\_edits210_decimal),1) < 2
          tmpout+"0"
          SetGadgetText(*LVEdits\_edits210_string, tmpout)
        Wend   
      Else
        If tmpout <> ""
          tmpout + Chr(*LVEdits\_edits210_decimal) + "00"
          SetGadgetText(*LVEdits\_edits210_string, tmpout)
        EndIf
      EndIf
      If Val(tmpout) = 0
        tmpout= ""
      EndIf
      SetGadgetItemText(*LVEdits\_edits210_gadget,*LVEdits\_edits210_item, RSet(Trim(tmpout),*LVEdits\MoneyColumn(*LVEdits\_edits210_subitem)+3," "), *LVEdits\_edits210_subitem)
    Else
      SetGadgetItemText(*LVEdits\_edits210_gadget,*LVEdits\_edits210_item, GetGadgetText(*LVEdits\_edits210_string), *LVEdits\_edits210_subitem)
    EndIf
    
    FreeGadget(*LVEdits\_edits210_string)
    FreeGadget(*LVEdits\_edits210_container)
    *LVEdits\_edits210_EditActive = #False
    
    If SendChange
      Ale_ColumnChanged(*LVEdits\_edits210_subitem)
      Ale_RowChanged(*LVEdits\_edits210_item)
      PB_Gadget_SendGadgetCommand(GadgetID(*LVEdits\_edits210_gadget), #Ale_Cellcontents_Changed)
    EndIf
    
    ;UnhookWindowsHookEx_(*LVEdits\_edits210_menuhook)
    
  EndProcedure
  
  Procedure SaveAndExit_Desc(newtext$)
    Shared *LVEdits.EDITDATA
    tmp$ = newtext$
    orig$ = GetGadgetItemText(*LVEdits\_edits210_gadget,*LVEdits\_edits210_item,*LVEdits\_edits210_subitem)
    If Trim(tmp$) <> Trim(orig$)
      SendChange = #True
      Ale_OriginalText(orig$)
    Else
      SendChange = #False
    EndIf
    SetGadgetItemText(*LVEdits\_edits210_gadget,*LVEdits\_edits210_item, newtext$, *LVEdits\_edits210_subitem)
    If SendChange
      Ale_ColumnChanged(*LVEdits\_edits210_subitem)
      Ale_RowChanged(*LVEdits\_edits210_item)
      PB_Gadget_SendGadgetCommand(GadgetID(*LVEdits\_edits210_gadget), #Ale_Cellcontents_Changed)
    EndIf
  EndProcedure
  
  Procedure.s GetNewDescription()
    Shared *LVEdits.EDITDATA
    DisplayPopupMenu(descpopup, WindowID(*LVEdits\_edits210_window))
  EndProcedure
  
  Procedure SubClass_String(hwnd, Message, wparam, lparam)
    
    Shared *LVEdits.EDITDATA
    Protected blocking=0, ploc, tmpout.s
    result = CallWindowProc_(*LVEdits\_edits210_oldlist, hwnd, Message, wparam, lparam)
    
    Select Message
        
      Case #WM_RBUTTONDOWN
        *LVEdits\_edits210_menuhook = SetWindowsHookEx_(#WH_MOUSE, @hookproc(), 0, GetCurrentThreadId_())
        
      Case #WM_DESTROY
        UnhookWindowsHookEx_(*LVEdits\_edits210_menuhook)
        
      Case #WM_KEYDOWN
        Select wparam
          Case #VK_RETURN
            SaveAndExit()
            If *LVEdits\_edits210_window <> 1 ; <------ Change for Summit
              *LVEdits\_edits210_item + 1
              If *LVEdits\_edits210_item < CountGadgetItems(*LVEdits\_edits210_gadget)
                RtlZeroMemory_(@*LVEdits\_edits210_itemrect,SizeOf(RECT))
                *LVEdits\_edits210_itemrect\top = *LVEdits\_edits210_subitem
                SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #LVM_GETSUBITEMRECT, *LVEdits\_edits210_item, @*LVEdits\_edits210_itemrect)
                GetNewText()
              EndIf   
            EndIf
            
          Case #VK_ESCAPE
            FreeGadget(*LVEdits\_edits210_string)
            FreeGadget(*LVEdits\_edits210_container)
            *LVEdits\_edits210_EditActive = #False
            
          Case #VK_LEFT
            SendMessage_(hwnd, #EM_GETSEL, @first.l, @last.l)
            If first = 0
              SaveAndExit()
              currentsubitem = *LVEdits\_edits210_subitem
              *LVEdits\_edits210_subitem - 1
              If *LVEdits\_edits210_subitem >= 1
                While *LVEdits\Masked(*LVEdits\_edits210_subitem) And *LVEdits\_edits210_subitem >= 0
                  *LVEdits\_edits210_subitem - 1
                  If *LVEdits\_edits210_subitem < 1
                    *LVEdits\_edits210_subitem = currentsubitem
                  EndIf
                Wend
              Else
                *LVEdits\_edits210_subitem + 1
              EndIf
              RtlZeroMemory_(@*LVEdits\_edits210_itemrect,SizeOf(RECT))
              *LVEdits\_edits210_itemrect\top = *LVEdits\_edits210_subitem
              SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #LVM_GETSUBITEMRECT, *LVEdits\_edits210_item, @*LVEdits\_edits210_itemrect)
              GetNewText()
            EndIf
            
          Case #VK_RIGHT
            SendMessage_(hwnd, #EM_GETSEL, @first.l, @last.l)
            If Len(GetGadgetText(*LVEdits\_edits210_string)) = last
              headerhWnd=SendMessage_(GadgetID(*LVEdits\_edits210_gadget),#LVM_GETHEADER,0,0)
              numcolumns = SendMessage_(headerhWnd, #HDM_GETITEMCOUNT,0,0)
              If *LVEdits\_edits210_subitem < numcolumns-1
                SaveAndExit()
                currentsubitem = *LVEdits\_edits210_subitem
                *LVEdits\_edits210_subitem + 1
                If *LVEdits\_edits210_subitem < numcolumns
                  While *LVEdits\Masked(*LVEdits\_edits210_subitem) And *LVEdits\_edits210_subitem <= numcolumns
                    *LVEdits\_edits210_subitem + 1
                    If *LVEdits\_edits210_subitem >= numcolumns
                      *LVEdits\_edits210_subitem = currentsubitem
                    EndIf
                  Wend
                Else
                  *LVEdits\_edits210_subitem -1
                EndIf
                RtlZeroMemory_(@*LVEdits\_edits210_itemrect,SizeOf(RECT))
                *LVEdits\_edits210_itemrect\top = *LVEdits\_edits210_subitem
                SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #LVM_GETSUBITEMRECT, *LVEdits\_edits210_item, @*LVEdits\_edits210_itemrect)
                GetNewText()
              EndIf
            EndIf
            
          Case #VK_UP
            SaveAndExit()
            *LVEdits\_edits210_item - 1 : If *LVEdits\_edits210_item <= 0 : *LVEdits\_edits210_item = 0 : EndIf
            RtlZeroMemory_(@*LVEdits\_edits210_itemrect,SizeOf(RECT))
            *LVEdits\_edits210_itemrect\top = *LVEdits\_edits210_subitem
            SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #LVM_GETSUBITEMRECT, *LVEdits\_edits210_item, @*LVEdits\_edits210_itemrect)
            GetNewText()
            
          Case #VK_DOWN
            SaveAndExit()
            *LVEdits\_edits210_item + 1:If *LVEdits\_edits210_item >= CountGadgetItems(*LVEdits\_edits210_gadget):*LVEdits\_edits210_item - 1 : EndIf
            RtlZeroMemory_(@*LVEdits\_edits210_itemrect,SizeOf(RECT))
            *LVEdits\_edits210_itemrect\top = *LVEdits\_edits210_subitem
            SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #LVM_GETSUBITEMRECT, *LVEdits\_edits210_item, @*LVEdits\_edits210_itemrect)
            GetNewText()
            
        EndSelect
        
      Case #WM_CHAR
        
        If *LVEdits\MoneyColumn(*LVEdits\_edits210_subitem)
          blocking = 1
          Select wparam
            Case *LVEdits\_edits210_decimal, 48 To 57
              tmpout.s = GetGadgetText(*LVEdits\_edits210_string)
              If FindString(tmpout, Chr(*LVEdits\_edits210_decimal), 1) = 0
                If Len(tmpout) > *LVEdits\MoneyColumn(*LVEdits\_edits210_subitem)
                  If wparam <> *LVEdits\_edits210_decimal
                    SendMessage_(hwnd, #EM_GETSEL, 0, @pos)
                    SetGadgetText(*LVEdits\_edits210_string, Left(tmpout,Len(tmpout)-1))
                    SendMessage_(hwnd, #EM_SETSEL, pos-1, pos-1)
                  EndIf
                EndIf
              EndIf 
              If wparam = *LVEdits\_edits210_decimal
                If CountString(tmpout, Chr(*LVEdits\_edits210_decimal)) > 1
                  SendMessage_(hwnd, #EM_GETSEL, 0, @pos)
                  SetGadgetText(*LVEdits\_edits210_string, Left(tmpout,Len(tmpout)-1))
                  SendMessage_(hwnd, #EM_SETSEL, pos-1, pos-1)
                EndIf       
              EndIf
              If FindString(tmpout,Chr(*LVEdits\_edits210_decimal),1)
                If Len(tmpout) - FindString(tmpout,Chr(*LVEdits\_edits210_decimal),1) > 2
                  SendMessage_(hwnd, #EM_GETSEL, 0, @pos)
                  SetGadgetText(*LVEdits\_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(*LVEdits\_edits210_string)
                SendMessage_(hwnd, #EM_GETSEL, 0, @pos)
                SetGadgetText(*LVEdits\_edits210_string, Left(tmpout,Len(tmpout)-1))
                SendMessage_(hwnd, #EM_SETSEL, pos-1, pos-1)
              EndIf
          EndSelect
        EndIf
        
      Case #WM_PASTE
        If *LVEdits\MoneyColumn(*LVEdits\_edits210_subitem)
          tmpout.s = GetGadgetText(*LVEdits\_edits210_string)
          If FindString(tmpout,Chr(*LVEdits\_edits210_decimal),1)
            validlength = *LVEdits\MoneyColumn(*LVEdits\_edits210_subitem)+3
          Else
            validlength = *LVEdits\MoneyColumn(*LVEdits\_edits210_subitem)
          EndIf
          If Len(tmpout)<=validlength
            ok = #True
            *cc.CHARACTER = @tmpout
            While *cc\c
              Select *cc\c
                Case '0' To '9', *LVEdits\_edits210_decimal
                Default
                  ok = #False
              EndSelect
              *cc+1
            Wend
          Else
            ok = #False
          EndIf
          If Not ok
            SetGadgetText(*LVEdits\_edits210_string, "")
          EndIf
        EndIf
    EndSelect
    
    ProcedureReturn result
  EndProcedure
  
  Procedure hookproc(ncode, wparam, lparam)
    Shared *LVEdits.EDITDATA
    
    If ncode<0 Or IsGadget(*LVEdits\_edits210_string) = 0
      result = CallNextHookEx_(*LVEdits\_edits210_menuhook, ncode, wparam, lparam)
      ProcedureReturn result
    EndIf
    
    If wparam = #WM_RBUTTONUP
      If IsGadget(*LVEdits\_edits210_string)
        *mhs.MOUSEHOOKSTRUCT = lparam
        If *mhs\hwnd = GadgetID(*LVEdits\_edits210_string)
          ProcedureReturn #True
        EndIf
      EndIf
    EndIf
    
    ProcedureReturn CallNextHookEx_(*LVEdits\_edits210_menuhook, ncode, wparam, lparam)
  EndProcedure
  
  Procedure.s GetNewText()
    Shared *LVEdits.EDITDATA
    
    *LVEdits\_edits210_EditActive = #True
    Protected grect.rect
    twleft  =   *LVEdits\_edits210_itemrect\left+6
    twtop   =   *LVEdits\_edits210_itemrect\top
    winwidth =  *LVEdits\_edits210_itemrect\right-*LVEdits\_edits210_itemrect\left-8
    winheight = *LVEdits\_edits210_itemrect\bottom-*LVEdits\_edits210_itemrect\top-1
    oldgadgetlist = UseGadgetList(GadgetID(*LVEdits\_edits210_gadget))
    *LVEdits\_edits210_container = ContainerGadget(#PB_Any, twleft-2,twtop-2,winwidth+4,winheight+4)
    HideGadget(*LVEdits\_edits210_container, 1)
    SetGadgetColor(*LVEdits\_edits210_container,#PB_Gadget_BackColor, #Black)
    If *LVEdits\MoneyColumn(*LVEdits\_edits210_subitem)
      *LVEdits\_edits210_string  = StringGadget(#PB_Any,2,2,winwidth,winheight,RemoveString(GetGadgetItemText(*LVEdits\_edits210_gadget,*LVEdits\_edits210_item,*LVEdits\_edits210_subitem)," "),#PB_String_BorderLess|#ES_MULTILINE|#ES_AUTOVSCROLL)
    Else
      *LVEdits\_edits210_string  = StringGadget(#PB_Any,2,2,winwidth,winheight,GetGadgetItemText(*LVEdits\_edits210_gadget,*LVEdits\_edits210_item,*LVEdits\_edits210_subitem),#PB_String_BorderLess|#ES_MULTILINE|#ES_AUTOVSCROLL|#PB_String_UpperCase)
    EndIf   
    CloseGadgetList()   
    SetGadgetFont(*LVEdits\_edits210_string, GetGadgetFont(*LVEdits\_edits210_gadget))
    UseGadgetList(oldgadgetlist)
    SetActiveGadget(*LVEdits\_edits210_string)
    *LVEdits\_edits210_oldstring=SetWindowLong_(GadgetID(*LVEdits\_edits210_string), #GWL_WNDPROC, @SubClass_String())
    SetWindowLong_(GadgetID(*LVEdits\_edits210_string), #GWL_EXSTYLE, GetWindowLong_(GadgetID(*LVEdits\_edits210_string), #GWL_EXSTYLE) &~ #WS_EX_CONTEXTHELP)
    SendMessage_(GadgetID(*LVEdits\_edits210_string),#EM_SETSEL,0,-1)
    HideGadget(*LVEdits\_edits210_container, 0)
    GetWindowRect_(GadgetID(*LVEdits\_edits210_gadget), @gr.RECT)
    GetWindowRect_(GadgetID(*LVEdits\_edits210_container), @cr.RECT)
    GetClientRect_(GadgetID(*LVEdits\_edits210_gadget), @grc.RECT)
    If cr\top - gr\top < winheight
      SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #WM_VSCROLL, #SB_LINEUP ,0)
    ElseIf cr\top - gr\top > grc\bottom-grc\top-winheight
      SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #WM_VSCROLL, #SB_LINEDOWN ,0)
    EndIf
    If GadgetWidth(*LVEdits\_edits210_gadget)-twleft < winwidth
      SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #WM_HSCROLL, #SB_RIGHT, 0)
    ElseIf twleft<0
      SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #WM_HSCROLL, #SB_LEFT, 0)
    EndIf
    
  EndProcedure
  
  Procedure ResizeEdit(hwnd)
    Shared *LVEdits.EDITDATA
    RtlZeroMemory_(@*LVEdits\_edits210_itemrect,SizeOf(RECT))
    *LVEdits\_edits210_itemrect\top = *LVEdits\_edits210_subitem
    SendMessage_(hwnd, #LVM_GETSUBITEMRECT, *LVEdits\_edits210_item, @*LVEdits\_edits210_itemrect)     
    twleft    = *LVEdits\_edits210_itemrect\left+6
    twtop     = *LVEdits\_edits210_itemrect\top
    winwidth  = *LVEdits\_edits210_itemrect\right-*LVEdits\_edits210_itemrect\left-8
    winheight = *LVEdits\_edits210_itemrect\bottom-*LVEdits\_edits210_itemrect\top-1
    ResizeGadget(*LVEdits\_edits210_container,twleft-2,twtop-2,winwidth+4,winheight+4)
    ResizeGadget(*LVEdits\_edits210_string, 2,2, GadgetWidth(*LVEdits\_edits210_container)-4, GadgetHeight(*LVEdits\_edits210_container)-4)
    InvalidateRect_(GadgetID(*LVEdits\_edits210_container),0,1)
    If GadgetY(*LVEdits\_edits210_container) < winheight
      HideGadget(*LVEdits\_edits210_container, 1)
    Else
      HideGadget(*LVEdits\_edits210_container, 0)
      SetActiveGadget(*LVEdits\_edits210_string)
    EndIf         
  EndProcedure
  
  Procedure SubClass_LV(hwnd, Message, wparam, lparam)
    Shared *LVEdits.EDITDATA
    result = CallWindowProc_(*LVEdits\_edits210_oldlist, hwnd, Message, wparam, lparam)
    
    If message = #WM_KEYUP
      If wparam = #VK_TAB
        If GetAsyncKeyState_(#VK_SHIFT) & 32768
          SaveAndExit()
          currentsubitem = *LVEdits\_edits210_subitem
          *LVEdits\_edits210_subitem - 1
          If *LVEdits\_edits210_subitem >= 1
            While *LVEdits\Masked(*LVEdits\_edits210_subitem) And *LVEdits\_edits210_subitem >= 0
              *LVEdits\_edits210_subitem - 1
              If *LVEdits\_edits210_subitem < 1
                *LVEdits\_edits210_subitem = currentsubitem
              EndIf
            Wend
          Else
            *LVEdits\_edits210_subitem + 1
          EndIf
          RtlZeroMemory_(@*LVEdits\_edits210_itemrect,SizeOf(RECT))
          *LVEdits\_edits210_itemrect\top = *LVEdits\_edits210_subitem
          SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #LVM_GETSUBITEMRECT, *LVEdits\_edits210_item, @*LVEdits\_edits210_itemrect)
          GetNewText()       
        Else
          If IsGadget(*LVEdits\_edits210_string)
            headerhWnd=SendMessage_(GadgetID(*LVEdits\_edits210_gadget),#LVM_GETHEADER,0,0)
            numcolumns = SendMessage_(headerhWnd, #HDM_GETITEMCOUNT,0,0)
            SaveAndExit()
            currentsubitem = *LVEdits\_edits210_subitem
            *LVEdits\_edits210_subitem + 1
            If *LVEdits\_edits210_subitem < numcolumns
              While *LVEdits\Masked(*LVEdits\_edits210_subitem) And *LVEdits\_edits210_subitem <= numcolumns
                *LVEdits\_edits210_subitem + 1
                If *LVEdits\_edits210_subitem >= numcolumns
                  *LVEdits\_edits210_subitem = currentsubitem
                EndIf
              Wend
            Else
              *LVEdits\_edits210_subitem -1
            EndIf
            RtlZeroMemory_(@*LVEdits\_edits210_itemrect,SizeOf(RECT))
            *LVEdits\_edits210_itemrect\top = *LVEdits\_edits210_subitem
            SendMessage_(GadgetID(*LVEdits\_edits210_gadget), #LVM_GETSUBITEMRECT, *LVEdits\_edits210_item, @*LVEdits\_edits210_itemrect)
            GetNewText()
          EndIf
        EndIf
      EndIf
    EndIf
    
    If message = #WM_VSCROLL Or message = #WM_HSCROLL
      If IsGadget(*LVEdits\_edits210_container) And *LVEdits\_edits210_container <> 0
        ResizeEdit(hwnd)
      EndIf
    EndIf
    
    If message=#WM_NOTIFY
      If IsGadget(*LVEdits\_edits210_container) And *LVEdits\_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 *LVEdits\_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)
        SetGadgetState(*LVEdits\_edits210_gadget, hitinfo\iitem)
        If hitinfo\isubitem > 0 And HitInfo\iItem >= 0
          RtlZeroMemory_(@*LVEdits\_edits210_itemrect,SizeOf(RECT))
          *LVEdits\_edits210_itemrect\top = hitinfo\iSubItem
          SendMessage_(hwnd,#LVM_GETSUBITEMRECT, hitinfo\iitem, @*LVEdits\_edits210_itemrect)
          *LVEdits\_edits210_item = hitinfo\iitem
          *LVEdits\_edits210_subitem = hitinfo\iSubItem
          If Not *LVEdits\Masked(*LVEdits\_edits210_subitem)
            If *LVEdits\_edits210_subitem = 2 And *LVEdits\_edits210_window = 2
              GetNewDescription()
            Else
              GetNewText()
            EndIf
          EndIf
        EndIf
      Else
        FreeGadget(*LVEdits\_edits210_string)
        FreeGadget(*LVEdits\_edits210_container)
        *LVEdits\_edits210_EditActive = #False
      EndIf
    EndIf
    
    If Message = #WM_LBUTTONDOWN
      If *LVEdits\_edits210_EditActive
        FreeGadget(*LVEdits\_edits210_string)
        FreeGadget(*LVEdits\_edits210_container)
        *LVEdits\_edits210_EditActive = #False
      EndIf
    EndIf
    ProcedureReturn result
  EndProcedure
  
  Procedure StopEditing(); Take ListIcon gadget out of editable mode
    Shared *LVEdits.EDITDATA
    *LVEdits\_edits210_editactive = #False
    If *LVEdits\_edits210_string
      If IsGadget(*LVEdits\_edits210_string) : FreeGadget(*LVEdits\_edits210_string) : EndIf
    EndIf
    If *LVEdits\_edits210_container
      If IsGadget(*LVEdits\_edits210_container) : FreeGadget(*LVEdits\_edits210_container) : EndIf
    EndIf
    If *LVEdits\_edits210_oldlist
      If IsGadget(*LVEdits\_edits210_gadget)
        SetWindowLong_(GadgetID(*LVEdits\_edits210_gadget), #GWL_WNDPROC, *LVEdits\_edits210_oldlist)
        *LVEdits\_edits210_oldlist = 0
      EndIf
    EndIf
  EndProcedure
  
  Procedure StartEditing(WindowNumber, GadgetNumber); Make ListIcon gadget cells editable
    Shared *LVEdits.EDITDATA
    StopEditing()
    *LVEdits\_edits210_window=WindowNumber
    Protected cn$ = Space(100)
    GetClassName_(GadgetID(GadgetNumber),@cn$,99)
    If UCase(Trim(cn$)) = "SYSLISTVIEW32" And *LVEdits\_edits210_oldlist = 0
      *LVEdits\_edits210_oldlist=SetWindowLong_(GadgetID(GadgetNumber), #GWL_WNDPROC, @SubClass_LV())
      *LVEdits\_edits210_gadget = GadgetNumber
      *LVEdits\_edits210_decimal = 46
      ProcedureReturn 1
    Else
      ProcedureReturn 0
    EndIf
  EndProcedure
  
  Procedure SetMoneyColumn(Column, Width) ; Width is number of digits before the decimal place
    Shared *LVEdits.EDITDATA
    If *LVEdits\_edits210_oldlist
      With lvc.LV_COLUMN
        \Mask = #LVCF_FMT
        \fmt=#LVCFMT_RIGHT
      EndWith
      SendMessage_(GadgetID(*LVEdits\_edits210_gadget),#LVM_SETCOLUMN,column,@lvc)
      If width >= 1
        *LVEdits\MoneyColumn(Column) = width
      Else
        *LVEdits\MoneyColumn(Column) = 1
      EndIf
      ProcedureReturn 1
    Else
      ProcedureReturn 0
    EndIf
  EndProcedure
  
  Procedure DecimalMask(char) ; Char is the character you wish to use for decimal point, usually '.' or ',' (46 or 44)
    Shared *LVEdits.EDITDATA
    *LVEdits\_edits210_decimal = char
  EndProcedure
  
  Procedure MaskColumn(Column) ; Disallows edits for the passed column
    Shared *LVEdits.EDITDATA
    If *LVEdits\_edits210_oldlist
      *LVEdits\Masked(Column) = 1
      ProcedureReturn 1
    Else
      ProcedureReturn 0
    EndIf
  EndProcedure
  
EndModule
I should mention that this version I pulled from a project and it has special processing for window# 2 and column# 2, it pops up a menu to make a choice from. You won't need this so just find SaveAndExitDesc() and use SaveAndExit() for everything.
BERESHEIT
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 794
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

Re: AllowLVEdits Version 2.2 Updated for V3.0

Post by Zebuddi123 »

Updated this example cause i needed the Pbi. Hope I`ve got it correct (this new fangle Module stuff) :shock: my poor little brain hurts :lol:

Big Thanks for the V3.0 Update netmaestro :D :D :D

Code: Select all

;=======================================================
; Program:        AllowLVEdits 3.0 Demo program
; Author:         netmaestro
;=======================================================
;
IncludeFile "allowlveditsV3.pbi"
UseModule LVEdit
Structure editrecord
  row.i 
  col.i
  newtext$
  oldtext$
EndStructure

Global NewList edits.editrecord()
AddElement(edits())

Procedure$ DayStr(day)
  ProcedureReturn Mid("SunMonTueWedThuFriSat", day*3+1, 3)
EndProcedure 

Procedure Recalc()
  runningtotal.d = 0
  For i = 0 To CountGadgetItems(0)-1
    tmp$ = GetGadgetItemText(0,i,2)
    If tmp$<>"" : runningtotal+ValD(tmp$) : EndIf
    tmp$ = GetGadgetItemText(0,i,3)
    If tmp$<>"" : runningtotal-ValD(tmp$) : EndIf
    If runningtotal < 0
      txtout.s="("+StrD(runningtotal,2)+")"
    Else
      txtout.s = StrD(runningtotal,2)
    EndIf
    SetGadgetItemText(0,i,txtout,4)
    If runningtotal < 0
      SetGadgetItemColor(0,i,#PB_Gadget_FrontColor, #Red, 4)
    EndIf
  Next
EndProcedure

Procedure Load()
  If ReadFile(0, "cashflow.dat")
    SendMessage_(GadgetID(0), #WM_SETREDRAW, 0,0)
    While Not Eof(0)
      AddGadgetItem(0, -1, ReplaceString(ReadString(0),"|",Chr(10)))
    Wend
    CloseFile(0)
    SendMessage_(GadgetID(0), #WM_SETREDRAW, 1, 0)
  Else     
    SendMessage_(GadgetID(0), #WM_SETREDRAW, 0,0)
    For i=0 To 365*5
      date = AddDate(ParseDate("%mm/%dd/%yyyy","11/01/2011") , #PB_Date_Day, i)
      date$ = DayStr(DayOfWeek(date))+FormatDate("%mm/%dd/%yyyy", date)
      AddGadgetItem(0, -1, Chr(10)+RSet(date$,14," ")+Chr(10)+Space(0)+Chr(10)+Space(0)+Chr(10)+Space(0)+Chr(10)+Space(0)+Chr(10))
    Next
    SendMessage_(GadgetID(0), #WM_SETREDRAW, 1,0)
  EndIf
  For i=0 To CountGadgetItems(0)-1
    SetGadgetItemColor(0,i,#PB_Gadget_BackColor,RGB(240,240,240),1)
    If FindString(GetGadgetItemText(0,i,4), "(", 1) 
      SetGadgetItemColor(0,i,#PB_Gadget_FrontColor,#Red,4)
    EndIf
    SetGadgetItemColor(0,i,#PB_Gadget_BackColor,RGB(240,240,240),4)  
  Next
EndProcedure

Procedure Save()
  Dim t.s(5)
  If CreateFile(0, "CashFlow.dat")
    For i = 0 To CountGadgetItems(0)-1
      For j=1 To 5
        t(j) = GetGadgetItemText(0,i,j)
      Next
      WriteStringN(0, "|"+t(1)+"|"+t(2)+"|"+t(3)+"|"+t(4)+"|"+t(5)+"|" )
    Next
    CloseFile(0)
  EndIf
EndProcedure

LoadFont(0, "Courier New",9)
w = OpenWindow(0,0,0,840,700,"Cash Flow Budget",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)

CreateToolBar(0, WindowID(0))
ToolBarStandardButton(0, #PB_ToolBarIcon_Save)
ToolBarStandardButton(1, #PB_ToolBarIcon_Undo)
ToolBarStandardButton(2, #PB_ToolBarIcon_Redo)

ListIconGadget(0,0,ToolBarHeight(0),840,700-ToolBarHeight(0),"",0,#PB_ListIcon_GridLines)
SetGadgetColor(0, #PB_Gadget_LineColor, RGB(210,210,210))
AddGadgetColumn(0,1,"Date",        150)
AddGadgetColumn(0,2,"Income",      130)
AddGadgetColumn(0,3,"Expense",     130)
AddGadgetColumn(0,4,"Balance",     130)
AddGadgetColumn(0,5,"Description", 275)
SetGadgetFont(0,FontID(0))

LVEdit::StartEditing(0,0)
LVEdit::SetMoneyColumn(2,12)
LVEdit::SetMoneyColumn(3,12)
LVEdit::SetMoneyColumn(4,12)
LVEdit::MaskColumn(1)
LVEdit::MaskColumn(4)

Load()

Repeat
  EventID = WaitWindowEvent()
  Select EventID
    Case #PB_Event_Gadget
      If EventGadget() = 0
        Select EventType() 
          Case #Ale_Cellcontents_Changed
            
            ; store undo infos
            AddElement(edits())
            With edits()
              \col = Ale_ColumnChanged()
              \row = Ale_RowChanged()
              \oldtext$ = Ale_OriginalText()
              \newtext$ = GetGadgetItemText(0, edits()\row, edits()\col)
            EndWith
            current=ListIndex(edits())
            LastElement(edits())
            While ListIndex(edits())<>current
              DeleteElement(edits())
            Wend
            
            ; recalculate the worksheet
            Recalc()
            
          Case #PB_EventType_LeftDoubleClick
            GetCursorPos_(@cp.POINT)
            MapWindowPoints_(0,GadgetID(0),@cp.POINT,1)
            HitInfo.LVHITTESTINFO\pt = cp.POINT
            SendMessage_(GadgetID(0),#LVM_SUBITEMHITTEST ,0,@HitInfo)
            If hitinfo\isubitem = 1
              AddGadgetItem(0, hitinfo\iItem+1, Chr(10)+GetGadgetItemText(0,hitinfo\iItem,1))
              SetGadgetItemColor(0, hitinfo\iItem+1, #PB_Gadget_BackColor, RGB(240,240,240), 1)
              SetGadgetItemColor(0, hitinfo\iItem+1, #PB_Gadget_BackColor, RGB(240,240,240), 4)
              recalc()
            EndIf
            
          Case #PB_EventType_RightDoubleClick
            GetCursorPos_(@cp.POINT)
            MapWindowPoints_(0,GadgetID(0),@cp.POINT,1)
            HitInfo.LVHITTESTINFO\pt = cp.POINT
            SendMessage_(GadgetID(0),#LVM_SUBITEMHITTEST ,0,@HitInfo)
            If hitinfo\isubitem = 1
              If GetGadgetItemText(0, hitinfo\iItem, 1) = GetGadgetItemText(0, hitinfo\iItem-1, 1)
                RemoveGadgetItem(0, hitinfo\iItem)
                recalc()
              EndIf
            EndIf
            
        EndSelect
      EndIf
      
    Case #PB_Event_Menu
      Select EventMenu()
        Case 0
          Save()
          
        Case 1
          If ListIndex(edits())>0
            SetGadgetItemText(0, edits()\row, edits()\oldtext$, edits()\col)
            PreviousElement(edits())
            recalc()
          EndIf
          
        Case 2
          NextElement(edits())
          SetGadgetItemText(0, edits()\row, edits()\newtext$, edits()\col)
          recalc()
          
      EndSelect
  EndSelect
Until EventID = #WM_CLOSE
Save()
LVEdit::StopEditing()
Zebuddi :D
malleo, caput, bang. Ego, comprehendunt in tempore
loulou
User
User
Posts: 38
Joined: Tue Dec 08, 2009 7:42 am

Re: AllowLVEdits Version 2.2

Post by loulou »

It seems that allowedit consume a lot of memeory ? Is there a way to avoid that
Thanks in advance
User avatar
dobro
Enthusiast
Enthusiast
Posts: 766
Joined: Sun Oct 31, 2004 10:54 am
Location: France
Contact:

Re: AllowLVEdits Version 2.2

Post by dobro »

hum :)
why the function: LVEdit::StartEditing()
edite the Listicon only In capital letters ?? :shock:
Image
Windows 98/7/10 - PB 5.42
■ sites : http://michel.dobro.free.fr/
Post Reply