Jump to content

Bug in GuiCtrlDelete or working as intended?


Recommended Posts

I am in the process of writing a media player, and I have run into something that I'm not sure is a bug or not. In the script below, if you run it and delete an item from the listview and select any remaining item in the listing, you should be able to get to the next item in the list by pressing the Next button. Unfortunately that isn't what happens. I have included 2 different methods used to delete an item in a ListView tied to different buttons on the GUI.

The first one marked LVM_DELETEITEM uses this command

_SendMessage($hListView, $LVM_DELETEITEM, _GUICtrlListView_GetSelectedIndices($hListView, 0))

The second button, marked GUICtrlDelete uses this command

Local $ctrlID = _GUICtrlListView_GetItemParam($ListView, _GUICtrlListView_GetSelectedIndices($ListView, 0))
If $ctrlID Then GUICtrlDelete($ctrlID)

After selecting a row in the LV and clicking the first button, it will delete the item from the listview, and then runs the RebuildLV function that I created. After deleting an item with the first button, you can go from one item to the next item in the LV with the Next button without a problem.

If you do the same thing with the GUICtrlDelete button, you can't do that. It will delete the item, the RebuildLV function gets run as before, but you can't use the Next button, the indexes are all screwed up. It won't work correctly unless you press the Rebuild button, so that the RebuildLV function gets run a second time.

Some of you may recognize where these command lines came from in regards to deleting an item from a LV, and this is what led me to believe that there may be a problem with the GUICtrlDelete command. I couldn't for the life of me figure out why my media player wouldn't go to the Next and Previous songs in the song list after I deleted them. I was using check boxes to mark which items I wanted to delete, and running through a For...Next loop to delete them using _GUICtrlListView_DeleteItem. When I deleted one item from the LV I used the _GUICtrlListView_DeleteItemsSelected, and this worked perfectly, but not when deleting multiple items, one at a time. The ONLY time that _GUICtrlListView_DeleteItem worked was when I called the UDF using a Handle to the Listview, and not when using a ControlID even though the Helpfile says both can be used. The function is written to use 2 different procedures to delete an item from a listview depending upon whether you call it with a handle or a controlID and this causes problems.

So, is there a bug in GUICtrlDelete, or is there something going on behind the scenes that I don't see? Please let me know what you think.

Here's an example script to demonstrate the bug/feature.

#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <GUIConstantsEx.Au3>
#include <GUIListView.Au3>
#include <GUIMenu.Au3>
Global $hOpenLVItem[30]
Opt("GUIOnEventMode", 1)
$hGUI = GUICreate("Test GUI", 400, 400, -1, -1)
GUISetOnEvent($GUI_EVENT_CLOSE, "hGUIClose")
Const $Next = GUICtrlCreateButton("Next", 10, 10)
GUICtrlSetOnEvent(-1, "Next1")
Const $Delete1 = GUICtrlCreateButton("LVM_DELETEITEM", 50, 10)
GUICtrlSetOnEvent(-1, "Delete1")
Const $Delete2 = GUICtrlCreateButton("GUICtrlDelete", 170, 10)
GUICtrlSetOnEvent(-1, "Delete2")
Const $Rebuild = GUICtrlCreateButton("Rebuild", 270, 10)
GUICtrlSetOnEvent($Rebuild, "RebuildLV")
Const $ListView = GUICtrlCreateListView("Column 1| Column 2| Column 3", 20, 60, 360, 300)
Const $hListView = GUICtrlGetHandle($ListView)
For $I = 1 To 12
    $hOpenLVItem[$I] = GUICtrlCreateListViewItem("Section 1-" & $I & "|Section 2-" & $I & "|Section 3-" & $I, $ListView)
Next
$hOpenLVItem[0] = 12
RebuildLV()
GUISetState()
GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")
_GUICtrlListView_RegisterSortCallBack($ListView)
While 1
    Sleep(200)
WEnd
Func _WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $I
    Global $hWndFrom, $iCode, $tNMHDR, $hWndListView, $lParam
    $hWndListView = $hListView
    If Not IsHWnd($ListView) Then $hWndListView = GUICtrlGetHandle($ListView)
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndListView
            Switch $iCode
                Case $LVN_COLUMNCLICK ; A column was clicked
                    Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
                    _GUICtrlListView_SortItems($hWndFrom, DllStructGetData($tInfo, "SubItem"))
                Case $LVN_ITEMACTIVATE
                    Local $nmia = DllStructCreate($tagNMITEMACTIVATE, $lParam)
                    $I = DllStructGetData($nmia, "Index")
                    Play()
            EndSwitch
    EndSwitch
    Return $__LISTVIEWCONSTANT_GUI_RUNDEFMSG
EndFunc   ;==>_WM_NOTIFY
Func Delete1()
    ConsoleWrite("Delete 1")
    _SendMessage($hListView, $LVM_DELETEITEM, _GUICtrlListView_GetSelectedIndices($hListView, 0))
    RebuildLV()
EndFunc   ;==>Delete1
Func Delete2()
    ConsoleWrite("Delete 2")
    Local $ctrlID = _GUICtrlListView_GetItemParam($ListView, _GUICtrlListView_GetSelectedIndices($ListView, 0))
    If $ctrlID Then GUICtrlDelete($ctrlID)
    RebuildLV()
EndFunc   ;==>Delete2
Func hGUIClose()
    Exit
EndFunc   ;==>hGUIClose
Func Next1()
    $Current = GUICtrlRead($ListView)
    If $hOpenLVItem[0] <> "" Then
        $Skip = $Current - ($hOpenLVItem[1] - 1)
    EndIf
    If $Skip = _GUICtrlListView_GetItemCount($ListView) Then
        $Skip = 0
    EndIf
    ConsoleWrite("$Skip = " & $Skip & @LF & @LF)
    _GUICtrlListView_SetItemSelected($ListView, $Skip)
    _GUICtrlListView_EnsureVisible($ListView, $Skip)
EndFunc   ;==>Next1
Func RebuildLV()
    ConsoleWrite("RebuildLV")
    Local $Read1, $LVItems[100]
    For $I = 1 To _GUICtrlListView_GetItemCount($ListView)
        _GUICtrlListView_SetItemState($ListView, $I - 1, $LVIS_selected, $LVIS_selected)
        $LVItems[$I] = GUICtrlRead(GUICtrlRead($ListView))
    Next
    $LVItems[0] = $I - 1
    Global $hOpenLVItem[$LVItems[0] + 1]
    _GUICtrlListView_DeleteAllItems($hListView)
    For $I = 1 To ($LVItems[0])
        $hOpenLVItem[$I] = GUICtrlCreateListViewItem($LVItems[$I], $ListView)
    Next
    $hOpenLVItem[0] = $I - 1
EndFunc   ;==>RebuildLV

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

  • Moderators

BrewManNH,

You are mixing native and UDF commands throughout that script - which usually ends in tears, so I am not surprised you are running into problems. :(

My preferred way to do something like this is to keep the data in an array and act on the array for deletion, addition, moving etc of items. Rewriting the ListView from the array is then easy. :D

This post has some code - taken incidentally from my own media player script - which shows how I go about it. :graduated:

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

I've tried building a listview with an array and acting upon the array to delete, add etc. Unfortunately once you sort the listview you lose track of where the indexes end up. So I had to resort to deleting everything in the listview, and then rebuiding it. That was the only way that I could get the Next and Previous buttons to work correctly.

Also unfortunately, using the GUICtrlDelete function doesn't work doing it that way. It causes the Next and Previous buttons to jump all over the listview once it's been destroyed and rebuilt, unless I delete everything and rebuild it twice. Have you run the example I posted? Is there a flaw in what I am doing that would say that GUICtrlDelete has an issue with LV controls or not? Because that one command is the only thing that is messing up the Listview next and previous functions in my media player. If the _GUICtrlListview_DeleteItem worked with control ids the same way it worked with handle's then I wouldn't have found the problem in the first place.

Also, I'm aware that mixing the native commands and the UDF commands can cause issues, but I'm also aware that there are some things that just can't be done as easily with the built-in commands that have been done with a UDF. I have found workarounds or dropped some ideas to avoid using a UDF when a built-in would work just as well. But, if you look at what I'm doing in rebuilding the LV, then it should be obvious that all I'm doing is reading every entry in the LV and storing it in an array, deleting everything in the LV, and then rebuilding the LV with the array's elements. This SHOULD rebuild all of the indexes and control IDs, and allow me to use the Next and Previous buttons on my media player without issue.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

  • Moderators

BrewManNH,

Does this help you see how you might do what you want? :graduated:

As I suggested, this script uses an array to hold the data and rewrites the ListView each time, so you get the ControlIDs in the correct order after sorting or deletion and the "Next" button works as expected:

#include <GUIConstantsEx.Au3>
#include <WindowsConstants.au3>
#include <GUIListView.Au3>
#include <Array.au3>

Opt("GUIOnEventMode", 1)

; ListView content
Global $aLV_Content[13][3] = [ _
    ["", "", ""], _
    ["Item 1", "SubItem Q", "SubItem J"], _
    ["Item 2", "SubItem W", "SubItem H"], _
    ["Item 3", "SubItem E", "SubItem G"], _
    ["Item 4", "SubItem R", "SubItem K"], _
    ["Item 5", "SubItem T", "SubItem L"], _
    ["Item 6", "SubItem Y", "SubItem Z"], _
    ["Item 7", "SubItem U", "SubItem X"], _
    ["Item 8", "SubItem I", "SubItem C"], _
    ["Item 9", "SubItem O", "SubItem V"], _
    ["Item 10", "SubItem P", "SubItem B"], _
    ["Item 11", "SubItem A", "SubItem N"], _
    ["Item 12", "SubItem S", "SubItem M"]]

; ListView item handles
Global $aLV_Items[13] = [12]
; Track sort order for the columns
Global $aColOrder[3] = [1, 1, 1]

; Create GUI
$hGUI = GUICreate("Test GUI", 400, 400, -1, -1)
GUISetOnEvent($GUI_EVENT_CLOSE, "_GUIClose")

; Crete buttons
$Next = GUICtrlCreateButton("Next", 10, 10)
GUICtrlSetOnEvent(-1, "_Next")
$Delete = GUICtrlCreateButton("Delete", 170, 10)
GUICtrlSetOnEvent(-1, "_Delete")

; Create ListView
$hListView = GUICtrlCreateListView("Column 1| Column 2| Column 3", 20, 60, 360, 300)
$LV_Handle = GUICtrlGetHandle($hListView)
; And fill it
_FillListView()

GUISetState()

GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")

; If you do not need the arrow on the column header remove this
_GUICtrlListView_RegisterSortCallBack($hListView)

While 1
    Sleep(200)
WEnd

Func _WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)

    #forceref $hWnd, $iMsg, $iwParam

    Global $hWndFrom, $iCode, $tNMHDR, $hWndListView, $lParam
    $hWndListView = $LV_Handle
    If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndListView
            Switch $iCode
                Case $LVN_COLUMNCLICK ; A column was clicked
                    Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
                    $iCol = DllStructGetData($tInfo, "SubItem")

                    ; If you do not need the arrow on the column header remove this
                    _GUICtrlListView_SortItems($hWndFrom, $iCol)
                    
                    ; Reverse sort order for the column
                    $aColOrder[$iCol] = Not($aColOrder[$iCol])
                    ; Sort the array on the column
                    _ArraySort($aLV_Content, $aColOrder[$iCol], 1, 0, $iCol)
                    ; Refill the ListView
                    _FillListView()

                Case $LVN_ITEMACTIVATE
                    Local $nmia = DllStructCreate($tagNMITEMACTIVATE, $lParam)
                    $I = DllStructGetData($nmia, "Index")
                    ;Play()
            EndSwitch
    EndSwitch

    Return $__LISTVIEWCONSTANT_GUI_RUNDEFMSG

EndFunc   ;==>_WM_NOTIFY

Func _GUIClose()
    Exit
EndFunc   ;==>hGUIClose

Func _Next()
    ; Get current selected item
    Local $iCurr = GUICtrlRead($hListView)
    ; Convert to the index and reloop if required
    Local $iNext = _ArraySearch($aLV_Items, $iCurr, 1)
    If $iNext = $aLV_Items[0] Then $iNext = 0
    ; Show we have the correct next item
    ConsoleWrite(_GUICtrlListView_GetItemText($hListView, $iNext) & @CRLF)
    ; Select it
    _GUICtrlListView_SetItemSelected($hListView, $iNext)
    _GUICtrlListView_EnsureVisible($hListView, $iNext)
EndFunc   ;==>Next1


Func _FillListView()
    _GUICtrlListView_DeleteAllItems($LV_Handle)
    For $i = 1 To $aLV_Items[0]
        Local $sItem = $aLV_Content[$i][0] & "|" & $aLV_Content[$i][1] & "|" & $aLV_Content[$i][2]
        $aLV_Items[$i] = GUICtrlCreateListViewItem($sItem, $hListView)
    Next
EndFunc

Func _Delete()
    ; Get current selection
    Local $iCurr = GUICtrlRead($hListView)
    ; Convert to index
    $iIndex = _ArraySearch($aLV_Items, $iCurr)
    ; Delete that index from data and ControlID arrays
    _ArrayDelete($aLV_Items, $iIndex)
    $aLV_Items[0] -= 1
    _ArrayDelete($aLV_Content, $iIndex)
    ; Refill the ListView
    _FillListView()
EndFunc

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

That works as it should. But, it still doesn't answer the question as to whether or not the GUICtrlDelete function is working incorrectly, mainly because you're not using it in your example.

I will look at your code and see if it makes any difference in the media player I'm working on to see if it works better than what I'm doing now. It looks a lot cleaner than what I'm doing. :graduated:

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

  • Moderators

BrewManNH,

whether or not the GUICtrlDelete function is working incorrectly

You have a real bug about this (pun fully intended!). :D

The GUICtrlDelete function works perfectly. The problem in your earlier script was caused by the sorting you were doing on the columns. Each "row" of the ListView is given a handle and a ControlID which Windows and AutoIt use to track them. When you sorted the rows, you mixed them up and so neither UDF (using the handles) nor AutoIt (using ControlIDs) could get a sensible order. As the example I posted above shows, the ONLY way to get the order re-established is to destroy and then recreate the ListView items so that the rows are in the correct order for that sorted state - deleting rows just further confused the issue. :graduated:

ListViews are complex beasts and my experience is that deletion and recreation of the data which is actually help in an array is the best way to go about any form of manipulation other than very simple "list and select" tasks. As soon as you get into insertion, deletion or (as in this case) sorting, everything goes to pot unless you use the array as a basis. :(

So please do not jump into any more threads claiming there is a problem with GUICtrlDelete - it works just fine. :D

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

I would agree that the method you showed is much easier than the way I was doing it. Basically what I was doing, after deleting the row or sorting the listview, was reading every line in the listview into an array, deleting all items in the Listview with _GUICtrlListView_DeleteAllItems($Listviewhandle), and then recreating the Listview from the array that I created. Your method is much faster than the way I was doing it, considering I had to read every row one at a time and storing it in the array. This worked fine for every operation that changed the order of the listview items except for deleting the rows with GUICtrlDelete, then and only then did I have problems. I've come to the conclusion that doing it another way is better and faster, and we'll just have to agree to disagree on anything else. :graduated:

BTW, I am in the process of incorporating your array method into the media player I'm writing, mostly to see how to do it correctly. Although the sorting method used isn't giving the same results, as of right now, that using _GUICtrlListView_SortItems does, I am working with it to see if I can tweak the results. Thank you for posting it as it has greatly sped up the process for a very large listview.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...