; --------------------------------------------------------------------------------------------; Copyright (c) Fantaisie Software. All rights reserved.; Dual licensed under the GPL and Fantaisie Software licenses.; See LICENSE and LICENSE-FANTAISIE in the project root for license information.; --------------------------------------------------------------------------------------------; describes one entry in the gadget;Structure VariableGadget_EntryKind.b ; 0=normal, or #TYPE_ARRAY, #TYPE_LINKEDLIST or #TYPE_MAPType.b ; type (normal debugger type value)Node.w ; 0=no node, 1=node (closed), 2=node (open)Sublevel.w ; structure sublevelParent.l ; index of parent item (-1 if none), needed for sortingName$ ; variable name (as displayed in the gadget)Value$ ; variable value (as displayed in the gadget)Extra$ ; info in the extra column(s)EndStructure; Sort order of types in the gadget; We cannot use the debugger types directly as they have a different numerical orderEnumeration#SORTTYPE_Unknown#SORTTYPE_Byte#SORTTYPE_Ascii#SORTTYPE_Character#SORTTYPE_Unicode#SORTTYPE_Word#SORTTYPE_Long#SORTTYPE_Integer#SORTTYPE_Quad#SORTTYPE_Pointer#SORTTYPE_Float#SORTTYPE_Double#SORTTYPE_String#SORTTYPE_FixedString#SORTTYPE_StructureEndEnumeration; a dummy structure with an empty array, to make access; to the Entry list (which is a memory area) easy.;Structure VariableGadget_ItemListitem.VariableGadget_Entry[0]EndStructure; SetGadgetData() stores the VariableGadget pointer; SetGadgetItemData() contains the real index in the Entry array (this never needs to be changed); structure representing one gadget;Structure VariableGadgetGadget.i ; purebasic #Gadget (can be #PB_Any)ExtraColumns.l ; number of extra columns in the gadgetItemCount.l ; number of itemsItems.i ; memory area for the itemsCustomData.i ; free to be used by the callerIsLocked.l ; if locked, no events get processed to not mess things up (FlushEvents() may be called while adding items to the gadget!)CurrentParent.l; current parent item while adding itemsCurrentSublevel.l ; current sublevel while addingSortColumn.l ; -1 if noneSortDirection.l ; 1 or -1IndexSort.l ; true if the main level should be sorted by index rather than nameCompilerIf #CompileLinuxGtkTreeModel.i ; While the gadget is locked, store the model hereCompilerEndIfEndStructureGlobal NewList VariableGadget_List.VariableGadget() ; currently created gadgetsGlobal Dim VariableGadget_Icons(#TYPE_MAX) ; icons for the variable typesGlobal VariableGadget_NodeOpen, VariableGadget_NodeClose; internal function to catch the 12x12 images and put them in the right size; (ie 16x16 on windows);UsePNGImageDecoder()Procedure VariableGadget_CatchIcon(*Address)CompilerIf #CompileMac; TODO: implement DrawImage() on MacOSresult = CatchImage(#PB_Any, *Address)CompilerElserealImage = CatchImage(#PB_Any, *Address)result = CreateImage(#PB_Any, #DEFAULT_ListIconImageSize, #DEFAULT_ListIconImageSize)If result And realImage And StartDrawing(ImageOutput(result))Box(0, 0, #DEFAULT_ListIconImageSize, #DEFAULT_ListIconImageSize, $FFFFFF)DrawImage(ImageID(realImage), #DEFAULT_ListIconImageOffset, #DEFAULT_ListIconImageOffset)StopDrawing()EndIfCompilerEndIfProcedureReturn resultEndProcedure; Get the #SORTTYPE_xxx value for the given debugger type; No List/Array types allowed (these are not displayed in the gadget anyway);Procedure VariableGadget_SortType(type)If IS_POINTER(type)ProcedureReturn #SORTTYPE_PointerElseSelect type & #TYPEMASKCase #TYPE_BYTE: ProcedureReturn #SORTTYPE_ByteCase #TYPE_ASCII: ProcedureReturn #SORTTYPE_AsciiCase #TYPE_CHARACTER: ProcedureReturn #SORTTYPE_CharacterCase #TYPE_UNICODE: ProcedureReturn #SORTTYPE_UnicodeCase #TYPE_WORD: ProcedureReturn #SORTTYPE_WordCase #TYPE_LONG: ProcedureReturn #SORTTYPE_LongCase #TYPE_INTEGER: ProcedureReturn #SORTTYPE_IntegerCase #TYPE_QUAD: ProcedureReturn #SORTTYPE_QuadCase #TYPE_FLOAT: ProcedureReturn #SORTTYPE_FloatCase #TYPE_DOUBLE: ProcedureReturn #SORTTYPE_DoubleCase #TYPE_STRING: ProcedureReturn #SORTTYPE_StringCase #TYPE_FIXEDSTRING: ProcedureReturn #SORTTYPE_FixedStringCase #TYPE_STRUCTURE: ProcedureReturn #SORTTYPE_StructureDefault: ProcedureReturn #SORTTYPE_UnknownEndSelectEndIfEndProcedure; Compare two items in the gadget (for sorting, returns >0, 0, <0);; Note:; Array, List, Map are only possible inside structures (where they always sort by order),; So we do not have to take care of these in the compare proc;Procedure VariableGadget_Compare(*Gadget.VariableGadget, index1, index2)*items.VariableGadget_ItemList = *Gadget\Items*entry1.VariableGadget_Entry = @*items\item[index1]*entry2.VariableGadget_Entry = @*items\item[index2]If *entry1\Parent = -1 And *entry2\Parent = -1; both are toplevel items, so compare them; since we only compare toplevel items, there are no spaces at the names; Get the result for the name compare always, as it is a fallback below;If *Gadget\IndexSortNameResult = (index1 - index2) * *Gadget\SortDirection ; compare indexes instead of names for the main levelElse; ignore the * in front of names*Name1 = @*entry1\Name$If PeekC(*Name1) = '*'*Name1 + SizeOf(Character)EndIf*Name2 = @*entry2\Name$If PeekC(*Name2) = '*'*Name2 + SizeOf(Character)EndIfNameResult = CompareMemoryString(*Name1, *Name2, #PB_String_NoCase) * *Gadget\SortDirection ; PB is case insensitiveEndIfIf *Gadget\SortColumn = *Gadget\ExtraColumns ; Name columnProcedureReturn NameResultElseIf *Gadget\SortColumn = *Gadget\ExtraColumns+1 ; value column; Spechial thing for the Watchlist. List all out of scope values at the endIf *entry1\Value$ = "---"If *entry2\Value$ <> "---"ProcedureReturn 1EndIfElseIf *entry2\Value$ = "---"ProcedureReturn -1EndIf; sort first by type, then by valueType1 = VariableGadget_SortType(*entry1\Type)Type2 = VariableGadget_SortType(*entry2\Type)If Type1 <> Type2ProcedureReturn (Type1 - Type2) * *Gadget\SortDirectionElseIf Type1 = #SORTTYPE_Structure ; structure. compare structure typesStruct1$ = StringField(*entry1\Name,ドル 2, ".")Struct2$ = StringField(*entry2\Name,ドル 2, ".")Result = CompareMemoryString(@Struct1,ドル @Struct2,ドル #PB_String_NoCase) * *Gadget\SortDirectionIf Result = 0ProcedureReturn NameResultElseProcedureReturn ResultEndIfElseIf *entry1\Value$ = *entry2\Value$ Or Type1 = #SORTTYPE_Unknown ; equal values, use name thenProcedureReturn NameResultElseIf Type1 <= #SORTTYPE_Pointer ; integer typesIf VariableIsHexQuad1.q = Val("$" + *entry1\Value$)Quad2.q = Val("$" + *entry2\Value$)ElseQuad1.q = Val(*entry1\Value$)Quad2.q = Val(*entry2\Value$)EndIf; cannot just do "ProcedureReturn Quad1-Quad2" as that could exceed the returnvalue size on x86If Quad1 = Quad2ProcedureReturn 0ElseIf Quad1 < Quad2ProcedureReturn (-1) * *Gadget\SortDirectionElseProcedureReturn *Gadget\SortDirectionEndIfElseIf Type1 <= #SORTTYPE_Double ; float typesDouble1.d = ValD(*entry1\Value$)Double2.d = ValD(*entry2\Value$)If Double1 = Double2ProcedureReturn 0ElseIf Double1 < Double2ProcedureReturn (-1) * *Gadget\SortDirectionElseProcedureReturn *Gadget\SortDirectionEndIfElse ; string typesProcedureReturn CompareMemoryString(@*entry1\Value,ドル @*entry2\Value$) * *Gadget\SortDirection ; use case sensitive hereEndIfElse ; any of the extra columnsExtra1$ = StringField(*entry1\Extra,ドル *Gadget\SortColumn+1, Chr(10))Extra2$ = StringField(*entry2\Extra,ドル *Gadget\SortColumn+1, Chr(10))Result = CompareMemoryString(@Extra1,ドル @Extra2,ドル #PB_String_NoCase)If Result = #PB_String_EqualProcedureReturn NameResultElseProcedureReturn Result * *Gadget\SortDirectionEndIfEndIfElse; at least one is not a toplevel one; find the index of the toplevel item for both itemstopindex1 = index1While *items\item[topindex1]\Parent <> -1topindex1 = *items\item[topindex1]\ParentWendtopindex2 = index2While *items\item[topindex2]\Parent <> -1topindex2 = *items\item[topindex2]\ParentWendIf topindex1 = topindex2; both are in the same toplevel node, so just compare by index to keep the; structures correct (do not apply sort direction); this also applies if one entry is the direct parent of the otherProcedureReturn index1 - index2Else; both are in different toplevel nodes. compare theseProcedureReturn VariableGadget_Compare(*Gadget, topindex1, topindex2)EndIfEndIfProcedureReturn ResultEndProcedure; Platform specific sort implementation stuff;CompilerIf #CompileWindowsStructure ListIconData ; LPARAM data structure for ListIconGadgetUserData.iEndStructureProcedure VariableGadget_SortProc(*data1.ListIconData, *data2.ListIconData, *Gadget.VariableGadget)If *data1 = 0 Or *data2 = 0ProcedureReturn 0 ; this may not happen, as we use SetGadgetItemData() to set all index valuesElseProcedureReturn VariableGadget_Compare(*Gadget, *data1\UserData, *data2\UserData)EndIfEndProcedureProcedure VariableGadget_ParentCallback(Window, Message, wParam, lParam)Callback = GetProp_(Window, "Variable_Callback")If Message = #WM_NCDESTROY; remove our prop, this is the last message, so no problemRemoveProp_(Window, "Variable_Callback")ElseIf Message = #WM_NOTIFY*nmv.NM_LISTVIEW = lParamIf *nmv\hdr\code = #LVN_COLUMNCLICK; find the right gadget (if it is a variablegadget at all)ForEach VariableGadget_List()If *nmv\hdr\hwndFrom = GadgetID(VariableGadget_List()\Gadget); set new column/directionIf VariableGadget_List()\SortColumn = *nmv\iSubItemVariableGadget_List()\SortDirection * -1ElseVariableGadget_List()\SortColumn = *nmv\iSubItemVariableGadget_List()\SortDirection = 1EndIf; sortSendMessage_(*nmv\hdr\hwndFrom, #LVM_SORTITEMS, @VariableGadget_List(), @VariableGadget_SortProc())SetSortArrow(VariableGadget_List()\Gadget, VariableGadget_List()\SortColumn, VariableGadget_List()\SortDirection)ProcedureReturn 0EndIfNext VariableGadget_List()EndIfEndIfIf CallbackProcedureReturn CallWindowProc_(Callback, Window, Message, wParam, lParam)ElseProcedureReturn DefWindowProc_(Window, Message, wParam, lParam)EndIfEndProcedureCompilerEndIfCompilerIf 0;#CompileMacGlobal ItemCompareUPP;; Problem with this implementation:; The sorting itself works well here, but structured items do not work, as we cannot ensure that they are always sorted top-down; as on Windows. The reason is that we have no control over the SortDirection. OSX just asks us to order the items, but the direction; is handled by the DataBrowser. There is no re-sort when simply reversing items in the list, as OSX caches the sort information.; Because of this, we cannot swap structure items if the sort order changes to remain top-down. So in the end, when sorting; bottom-up, structures get reversed in the view.;; The only solution to this is to have real containers in the DataBrowser which means customly implement the whole gadget for the IDE. :(;#kDataBrowserOrderIncreasing = 1#kDataBrowserOrderDecreasing = 2#kDataBrowserListViewSortableColumn = 1 << (16 + 2); To get the PB GadgetID from the ControlRefImportC ""PB_Gadget_GetProperty(Gadget, Property)EndImport#ID_Property = 'ID'; Must return true if itemOne < itemTwo, and false if itemOne >= itemTwo;ProcedureC VariableGadget_ItemCompareCallback(Gadget, itemOne, itemTwo, sortProperty)GadgetID = PB_Gadget_GetProperty(Gadget, #ID_Property)*Gadget.VariableGadget = GetGadgetData(GadgetID)RealIndex1 = GetGadgetItemData(GadgetID, itemOne-1) ; The itemID values are the index+1 on OSXRealIndex2 = GetGadgetItemData(GadgetID, itemTwo-1); Find out the ColumnIndex which is being sorted; Note: There is a separate image column, as the VAriableGadget always includes imagesSortColumn = -1For i = 1 To *Gadget\ExtraColumns+2If GetDataBrowserTableViewColumnProperty_(Gadget, i, @ColumnProperty) = #noErrIf ColumnProperty = sortPropertySortColumn = i-1BreakEndIfEndIfNext i; Update the Column+Direction in the structure so the compare function knows them, and a future; VariableGadget_Sort() uses the correct data;SortDirection = #kDataBrowserOrderIncreasing ; fallback;GetDataBrowserSortOrder_(Gadget, @SortDirection)*Gadget\SortColumn = SortColumnIf SortDirection = #kDataBrowserOrderIncreasing*Gadget\SortDirection = 1Else*Gadget\SortDirection = -1EndIf; Note: The callback always should not take the direction into account (the Gadget does that),; so in case of decreasing sort, we must reverse the result to get the correct output.; We cannot just have SortDirection fixed at 1, as structures are treated specially (always by index),; so they come out wrong if the compare function is not aware of the true direction;If SortColumn = -1ProcedureReturn #False ; return >= (should never happen)ElseIf (VariableGadget_Compare(*Gadget, RealIndex1, RealIndex2) * *Gadget\SortDirection) < 0ProcedureReturn #True ; <ElseProcedureReturn #False ; >=EndIfEndProcedureCompilerEndIf; Sort the entire gadget with the given settings; Does nothing if SortColumn=-1, so this can be called after all changes;Procedure VariableGadget_Sort(Gadget)*Gadget.VariableGadget = GetGadgetData(Gadget)CompilerIf #CompileWindowsIf *Gadget\SortColumn <> -1SendMessage_(GadgetID(Gadget), #LVM_SORTITEMS, *Gadget, @VariableGadget_SortProc())EndIfSetSortArrow(Gadget, *Gadget\SortColumn, *Gadget\SortDirection)CompilerEndIfCompilerIf #CompileMac; Even though OSX takes care of most of the sorting stuff itself (column arrow etc), we still must; re-initiate a sort after we made changes, because the PB ListIconGadget always adds items at the end; and only maps the internal linkedlist through the data callback, so a single AddGadgetItem() in the middle; messes up the cached sort data that OSX seems to be keeping;; If *Gadget\SortColumn <> -1; ; +1, as the VariableGadget always has an image column!; If GetDataBrowserTableViewColumnProperty_(GadgetID(Gadget), *Gadget\SortColumn+1, @SortColumnID) = #noErr; SetDataBrowserSortProperty_(GadgetID(Gadget), SortColumnID); If *Gadget\SortDirection > 0; SetDataBrowserSortOrder_(GadgetID(Gadget), #kDataBrowserOrderIncreasing); Else; SetDataBrowserSortOrder_(GadgetID(Gadget), #kDataBrowserOrderDecreasing); EndIf; EndIf; EndIfCompilerEndIfEndProcedure; creates a new gadget; returns the result of ListIconGadget(); so you can use the result with ResizeGadget(), HideGadget(), etc, but also; with the VariableGadget_...() functionsProcedure VariableGadget_Create(Gadget, x, y, Width, Height, ExtraColumn,ドル DefaultSort, IndexSort)Static IsInitializedIf IsInitialized = 0VariableGadget_Icons(#TYPE_BYTE) = VariableGadget_CatchIcon(?VariableGadget_Byte)VariableGadget_Icons(#TYPE_WORD) = VariableGadget_CatchIcon(?VariableGadget_Word)VariableGadget_Icons(#TYPE_LONG) = VariableGadget_CatchIcon(?VariableGadget_Long)VariableGadget_Icons(#TYPE_STRUCTURE) = VariableGadget_CatchIcon(?VariableGadget_Struct)VariableGadget_Icons(#TYPE_STRING) = VariableGadget_CatchIcon(?VariableGadget_String)VariableGadget_Icons(#TYPE_FLOAT) = VariableGadget_CatchIcon(?VariableGadget_Float)VariableGadget_Icons(#TYPE_FIXEDSTRING)= VariableGadget_CatchIcon(?VariableGadget_Fixed)VariableGadget_Icons(#TYPE_CHARACTER) = VariableGadget_CatchIcon(?VariableGadget_Char)VariableGadget_Icons(#TYPE_DOUBLE) = VariableGadget_CatchIcon(?VariableGadget_Double)VariableGadget_Icons(#TYPE_QUAD) = VariableGadget_CatchIcon(?VariableGadget_Quad)VariableGadget_Icons(#TYPE_INTEGER) = VariableGadget_CatchIcon(?VariableGadget_Integer)VariableGadget_Icons(#TYPE_ASCII) = VariableGadget_CatchIcon(?VariableGadget_Ascii)VariableGadget_Icons(#TYPE_UNICODE) = VariableGadget_CatchIcon(?VariableGadget_Unicode)VariableGadget_NodeOpen = VariableGadget_CatchIcon(?VariableGadget_NodeOpen)VariableGadget_NodeClose = VariableGadget_CatchIcon(?VariableGadget_NodeClose)IsInitialized = 1EndIfIf AddElement(VariableGadget_List())If ExtraColumn$ <> ""Result = ListIconGadget(Gadget, x, y, Width, Height, StringField(ExtraColumn,ドル 1, Chr(10)), 100, #PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)If Gadget = #PB_AnyVariableGadget_List()\Gadget = ResultElseVariableGadget_List()\Gadget = GadgetEndIfExtraColumns = 1While StringField(ExtraColumn,ドル ExtraColumns+1, Chr(10)) <> ""AddGadgetColumn(VariableGadget_List()\Gadget, ExtraColumns, StringField(ExtraColumn,ドル ExtraColumns+1, Chr(10)), 100)ExtraColumns + 1WendAddGadgetColumn(VariableGadget_List()\Gadget, ExtraColumns, Language("Debugger","Name"), 200)AddGadgetColumn(VariableGadget_List()\Gadget, ExtraColumns+1, Language("Debugger","Value"), 800)VariableGadget_List()\ExtraColumns = ExtraColumnsElseResult = ListIconGadget(Gadget, x, y, Width, Height, Language("Debugger","Name"), 200, #PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)If Gadget = #PB_AnyVariableGadget_List()\Gadget = ResultElseVariableGadget_List()\Gadget = GadgetEndIfAddGadgetColumn(VariableGadget_List()\Gadget, 1, Language("Debugger","Value"), 800)VariableGadget_List()\ExtraColumns = 0EndIfVariableGadget_List()\IndexSort = IndexSortIf DefaultSortVariableGadget_List()\SortColumn = VariableGadget_List()\ExtraColumnsVariableGadget_List()\SortDirection = 1ElseVariableGadget_List()\SortColumn = -1EndIf; Setup Header click monitoring for the sort;CompilerIf #CompileWindowsParent = GetParent_(GadgetID(VariableGadget_List()\Gadget))If GetProp_(Parent, "Variable_Callback") = 0 ; no monitoring callback yetSetProp_(Parent, @"Variable_Callback", SetWindowLongPtr_(Parent, #GWL_WNDPROC, @VariableGadget_ParentCallback()))EndIfCompilerEndIf; Setup the sort callback for OSX;CompilerIf #CompileMac; If ItemCompareUPP = 0; ItemCompareUPP = NewDataBrowserItemCompareUPP_(@VariableGadget_ItemCompareCallback()); EndIf;; If ItemCompareUPP; ; add our sort callback to the listicon's callbacks; Callbacks.DataBrowserCallbacks\version = #kDataBrowserLatestCallbacks ; in MacExtensions.pb;; If GetDataBrowserCallbacks_(GadgetID(VariableGadget_List()\Gadget), @Callbacks) = #noErr; Callbacks\itemCompareCallback = ItemCompareUPP; SetDataBrowserCallbacks_(GadgetID(VariableGadget_List()\Gadget), @Callbacks); EndIf;; ; set all columns to sortable; For i = 0 To VariableGadget_List()\ExtraColumns+1 ; the ImageColumn is only present after the first AddGadgetItem; If GetDataBrowserTableViewColumnProperty_(GadgetID(VariableGadget_List()\Gadget), i, @ColumnProperty) = #noErr; If GetDataBrowserPropertyFlags_(GadgetID(VariableGadget_List()\Gadget), ColumnProperty, @PropertyFlags) = #noErr; PropertyFlags | #kDataBrowserListViewSortableColumn; SetDataBrowserPropertyFlags_(GadgetID(VariableGadget_List()\Gadget), ColumnProperty, PropertyFlags); EndIf; EndIf; Next i; EndIfCompilerEndIfSetGadgetData(VariableGadget_List()\Gadget, @VariableGadget_List())ProcedureReturn ResultElseProcedureReturn 0EndIfEndProcedure; use this instead of "FreeGadget()" so that the item list is properly freed;Procedure VariableGadget_Free(Gadget)*VariableGadget.VariableGadget = GetGadgetData(Gadget)ChangeCurrentElement(VariableGadget_List(), *VariableGadget)If VariableGadget_List()\Items*items.VariableGadget_ItemList = VariableGadget_List()\ItemsFor i = 0 To VariableGadget_List()\ItemCount-1FreePBString(@*items\item[i]\Name$)FreePBString(@*items\item[i]\Value$)FreePBString(@*items\item[i]\Extra$)Next iFreeMemory(VariableGadget_List()\Items)EndIfFreeGadget(Gadget)DeleteElement(VariableGadget_List())EndProcedure; Lock variablegadget display updates (to speed up inserting); You MUST NOT call SetGadgetState() on the gadget while it is locked! (Linux thing);; This also locks the processing of VariableGadget_Event(), so there is no accidental; expand done while not all items are added to the gadget.;Procedure VariableGadget_Lock(Gadget)*VariableGadget.VariableGadget = GetGadgetData(Gadget)*VariableGadget\IsLocked = #TrueCompilerIf #CompileWindowsSendMessage_(GadgetID(Gadget), #WM_SETREDRAW, #False, 0)CompilerEndIfCompilerIf #CompileLinuxGtk*VariableGadget.VariableGadget = GetGadgetData(Gadget)*VariableGadget\TreeModel = gtk_tree_view_get_model_(GadgetID(Gadget))g_object_ref_(*VariableGadget\TreeModel) ; must be ref'ed or it is destroyedgtk_tree_view_set_model_(GadgetID(Gadget), #Null) ; disconnect the model for a faster updateCompilerEndIfEndProcedureProcedure VariableGadget_Unlock(Gadget)*VariableGadget.VariableGadget = GetGadgetData(Gadget)*VariableGadget\IsLocked = #FalseCompilerIf #CompileWindowsSendMessage_(GadgetID(Gadget), #WM_SETREDRAW, #True, 0)InvalidateRect_(GadgetID(Gadget), #Null, #True);CompilerEndIfCompilerIf #CompileLinuxGtk*VariableGadget.VariableGadget = GetGadgetData(Gadget)gtk_tree_view_set_model_(GadgetID(Gadget), *VariableGadget\TreeModel) ; reconnect the modelg_object_unref_(*VariableGadget\TreeModel) ; release referenceCompilerEndIfEndProcedure; Get the Chr(10) separated text for an item in the VariableGadget; (handles Array, List, Map stuff);Procedure.s VariableGadget_EntryText(*VariableGadget.VariableGadget, realindex)*items.VariableGadget_ItemList = *VariableGadget\ItemsText$ = *items\item[realindex]\Extra$ + *items\item[realindex]\Name$Select *items\item[realindex]\KindCase #TYPE_ARRAY; For Arrays, we include the dimensions (in Value$); directly on the name because it just looks betterText$ + "(" + *items\item[realindex]\Value$ + ")"Case #TYPE_LINKEDLIST, #TYPE_MAP; For List, Map we set the info in the Value column, but add the ()Text$ + "()" + Chr(10) + *items\item[realindex]\Value$Default; Normal itemText$ + Chr(10) + *items\item[realindex]\Value$EndSelectProcedureReturn Text$EndProcedure; you MUST call this for every event you receive for the gadget;Procedure VariableGadget_Event(Gadget)DoSort = 0If EventType() = #PB_EventType_LeftDoubleClickindex = GetGadgetState(Gadget)If index <> -1*VariableGadget.VariableGadget = GetGadgetData(Gadget)ChangeCurrentElement(VariableGadget_List(), *VariableGadget)If VariableGadget_List()\IsLocked = #False And VariableGadget_List()\Items*items.VariableGadget_ItemList = VariableGadget_List()\Itemsrealindex = GetGadgetItemData(Gadget, index)indexbefore = indexVariableGadget_Lock(Gadget)If *items\item[realindex]\Node = 1RemoveGadgetItem(Gadget, index) ; re-add this item to change the imageAddGadgetItem(Gadget, index, VariableGadget_EntryText(*VariableGadget, realindex), ImageID(VariableGadget_NodeClose))SetGadgetItemData(Gadget, index, realindex)*items\item[realindex]\Node = 2sublevel = *items\item[realindex]\Sublevelindex + 1realindex + 1While realindex < VariableGadget_List()\ItemCount And *items\item[realindex]\sublevel > sublevelIf *items\item[realindex]\Node = 1AddGadgetItem(Gadget, index, VariableGadget_EntryText(*VariableGadget, realindex), ImageID(VariableGadget_NodeOpen))SetGadgetItemData(Gadget, index, realindex)index + 1; skip node contentssublevel2 = *items\item[realindex]\Sublevelrealindex + 1While realindex < VariableGadget_List()\ItemCount And *items\item[realindex]\sublevel > sublevel2realindex + 1WendElseIf *items\item[realindex]\Node = 2Image = VariableGadget_NodeCloseElseImage = VariableGadget_Icons(*items\item[realindex]\Type & #TYPEMASK)EndIfAddGadgetItem(Gadget, index, VariableGadget_EntryText(*VariableGadget, realindex), ImageID(Image))SetGadgetItemData(Gadget, index, realindex)index + 1realindex + 1EndIfWendDoSort = 1ElseIf *items\item[realindex]\Node = 2RemoveGadgetItem(Gadget, index) ; re-add this item to change the imageAddGadgetItem(Gadget, index, VariableGadget_EntryText(*VariableGadget, realindex), ImageID(VariableGadget_NodeOpen))SetGadgetItemData(Gadget, index, realindex)*items\item[realindex]\Node = 1sublevel = *items\item[realindex]\Sublevelindex + 1realindex + 1While realindex < VariableGadget_List()\ItemCount And *items\item[realindex]\sublevel > sublevelIf *items\item[realindex]\Node = 1RemoveGadgetItem(Gadget, index); skip node contents (because they are not visible in the gadget)sublevel2 = *items\item[realindex]\Sublevelrealindex + 1While realindex < VariableGadget_List()\ItemCount And *items\item[realindex]\sublevel > sublevel2realindex + 1WendElseRemoveGadgetItem(Gadget, index)realindex + 1EndIfWendEndIfVariableGadget_Unlock(Gadget)SetGadgetState(Gadget, indexbefore)If DoSort; must be after the SetGadgetState, as the index is wrong else!VariableGadget_Sort(Gadget)EndIfEndIfEndIfEndIfEndProcedure; this must be called before adding any items to the gadget; to allocate the space for them; (it also clears the old gadget item list); VariableGadget_Allocate(Gadget, 0) will just clear the gadget;Procedure VariableGadget_Allocate(Gadget, NbItems)*VariableGadget.VariableGadget = GetGadgetData(Gadget)ChangeCurrentElement(VariableGadget_List(), *VariableGadget); free the old variable list;If VariableGadget_List()\Items*items.VariableGadget_ItemList = VariableGadget_List()\ItemsFor i = 0 To VariableGadget_List()\ItemCount-1FreePBString(@*items\item[i]\Name$)FreePBString(@*items\item[i]\Value$)FreePBString(@*items\item[i]\Extra$)Next iFreeMemory(VariableGadget_List()\Items)VariableGadget_List()\Items = 0EndIf; set the current count to 0, and reset parent index;VariableGadget_List()\ItemCount = 0VariableGadget_List()\CurrentParent = -1VariableGadget_List()\CurrentSublevel = 0; allocate new space for the items;If NbItems > 0VariableGadget_List()\Items = AllocateMemory(NbItems * SizeOf(VariableGadget_Entry))EndIfClearGadgetItems(Gadget) ; clear the items in the gadgetEndProcedure; call this function to expand all primary nodes an collapse all others; (used for array display for example);Procedure VariableGadget_Expand(Gadget)*VariableGadget.VariableGadget = GetGadgetData(Gadget)ChangeCurrentElement(VariableGadget_List(), *VariableGadget)If VariableGadget_List()\ItemsClearGadgetItems(Gadget)Index = 0*items.VariableGadget_ItemList = VariableGadget_List()\ItemsFor i = 0 To VariableGadget_List()\ItemCount-1If *items\item[i]\sublevel < 2 ; display all items of sublevel 0 and 1If *items\item[i]\Node <> 0 And *items\item[i]\sublevel = 0Image = VariableGadget_NodeClose*items\item[i]\Node = 2ElseIf *items\item[i]\Node <> 0Image = VariableGadget_NodeOpen*items\item[i]\Node = 1ElseImage = VariableGadget_Icons(*items\item[i]\Type & #TYPEMASK)EndIfAddGadgetItem(Gadget, Index, VariableGadget_EntryText(*VariableGadget, i), ImageID(Image))SetGadgetItemData(Gadget, Index, i)Index + 1ElseIf *items\item[i]\Node <> 0 ; a node -> set to collapsed*items\item[i]\Node = 1EndIfEndIfNext iEndIfEndProcedure; this sets the gadget to be used in the following _Add / _Set calls; this is to speed up the list modification;Procedure VariableGadget_Use(Gadget)Shared *VariableGadget_Used.VariableGadget*VariableGadget_Used = GetGadgetData(Gadget)EndProcedure; add a variable To the gadget; if *Value is a 0-pointer, the value field will be left empty;Procedure VariableGadget_Add(Type, DynamicType, Sublevel, Extra,ドル Name,ドル ModuleName,ドル *Value, Is64bit)Shared *VariableGadget_Used.VariableGadget; prefix the module nameIf ModuleName$ <> ""Name$ = ModuleName$ + "::" + Name$EndIfIf IS_ARRAY(Type) Or IS_LINKEDLIST(Type) Or IS_MAP(Type)Kind = TypeType = DynamicTypeElseKind = 0EndIfType & #IGNORE_PARAM ; remove the "direct param" flag if it is setindex = *VariableGadget_Used\ItemCount*items.VariableGadget_ItemList = *VariableGadget_Used\Items; add the separating chr(10) to the extra textIf *VariableGadget_Used\ExtraColumns > 0If Extra$ = ""Extra$ = RSet("", *VariableGadget_Used\ExtraColumns, Chr(10))ElseExtra$ + Chr(10)EndIfEndIfIf *items; find the current parent, if we ended a previous nodeWhile *VariableGadget_Used\CurrentSublevel > Sublevel And *VariableGadget_Used\CurrentParent <> -1*VariableGadget_Used\CurrentParent = *items\item[*VariableGadget_Used\CurrentParent]\Parent*VariableGadget_Used\CurrentSublevel - 1Wend*VariableGadget_Used\CurrentSublevel = Sublevel*items\item[index]\Kind = Kind*items\item[index]\Type = Type*items\item[index]\Node = 0*items\item[index]\SubLevel = SubLevel*items\item[index]\Parent = *VariableGadget_Used\CurrentParent*items\item[index]\Name$ = Name$*items\item[index]\Extra$ = Extra$*items\item[index]\Value$ = ""If IS_ARRAY(Kind)If *Value*items\item[index]\Value$ = PeekAscii(*Value) ; array dimensionsElse*items\item[index]\Value$ = ""EndIfElseIf IS_LINKEDLIST(Kind)If *ValueIf Is64bitIf PeekQ(*Value) = -1Size$ = "-"ElseSize$ = Str(PeekQ(*Value))EndIfIf PeekQ(*Value+8) = -1Current$ = "-"ElseCurrent$ = Str(PeekQ(*Value+8))EndIfElseIf PeekL(*Value) = -1Size$ = "-"ElseSize$ = Str(PeekL(*Value))EndIfIf PeekL(*Value+4) = -1Current$ = "-"ElseCurrent$ = Str(PeekL(*Value+4))EndIfEndIf*items\item[index]\Value$ = Language("Debugger","Size") + ": " + Size$ + " " + Language("Debugger","Current") + ": " + Current$Else*items\item[index]\Value$ = ""EndIfElseIf IS_MAP(Kind)If *Value*items\item[index]\Value$ = Language("Debugger", "Size")+": "If Is64bitIf PeekQ(*Value) = -1*items\item[index]\Value$ + "-"Else*items\item[index]\Value$ + Str(PeekQ(*Value))EndIf*Value + 8ElseIf PeekL(*Value) = -1*items\item[index]\Value$ + "-"Else*items\item[index]\Value$ + Str(PeekL(*Value))EndIf*Value + 4EndIf*items\item[index]\Value$ + " " + Language("Debugger","Current")+": "If PeekB(*Value) ; IsCurrent*items\item[index]\Value$ + Chr(34)+PeekS(*Value+1)+Chr(34) ; in external debugger formatElse*items\item[index]\Value$ + "-"EndIfElse*items\item[index]\Value$ = ""EndIfElseIf IS_POINTER(Type)*items\item[index]\Name$ = "*" + *items\item[index]\Name$If *ValueIf Is64bit And VariableIsHex*items\item[index]\Value$ = Hex(PeekQ(*Value), #PB_Quad)ElseIf Is64bit*items\item[index]\Value$ = Str(PeekQ(*Value))ElseIf VariableIsHex*items\item[index]\Value$ = Hex(PeekL(*Value), #PB_Long)Else*items\item[index]\Value$ = Str(PeekL(*Value))EndIfEndIfElse ; not a pointerIf Type = #TYPE_STRUCTURE ; structure, not a pointer*items\item[index]\Node = 1*VariableGadget_Used\CurrentParent = index ; this is the new parentElseIf *ValueSelect Type & #TYPEMASKCase #TYPE_BYTEIf VariableIsHex*items\item[index]\Value$ = Hex(PeekB(*Value), #PB_Byte)Else*items\item[index]\Value$ = Str(PeekB(*Value))EndIfCase #TYPE_ASCIIIf VariableIsHex*items\item[index]\Value$ = Hex(PeekB(*Value) & $FF) ; todoElse*items\item[index]\Value$ = Str(PeekB(*Value) & $FF)EndIfCase #TYPE_UNICODEIf VariableIsHex*items\item[index]\Value$ = Hex(PeekW(*Value) & $FFFF) ; todoElse*items\item[index]\Value$ = Str(PeekW(*Value) & $FFFF)EndIfCase #TYPE_WORDIf VariableIsHex*items\item[index]\Value$ = Hex(PeekW(*Value), #PB_Word)Else*items\item[index]\Value$ = Str(PeekW(*Value))EndIfCase #TYPE_LONG, #TYPE_CHARACTER ; chars are passed as longsIf VariableIsHex*items\item[index]\Value$ = Hex(PeekL(*Value), #PB_Long)Else*items\item[index]\Value$ = Str(PeekL(*Value))EndIfCase #TYPE_STRING, #TYPE_FIXEDSTRING*items\item[index]\Value$ = Chr(34) + PeekS(*Value) + Chr(34)Case #TYPE_FLOAT*items\item[index]\Value$ = StrF_Debug(PeekF(*Value))Case #TYPE_DOUBLE*items\item[index]\Value$ = StrD_Debug(PeekD(*Value))Case #TYPE_QUADIf VariableIsHex*items\item[index]\Value$ = Hex(PeekQ(*Value), #PB_Quad)Else*items\item[index]\Value$ = Str(PeekQ(*Value))EndIfCase #TYPE_INTEGERIf Is64bit And VariableIsHex*items\item[index]\Value$ = Hex(PeekQ(*Value), #PB_Quad)ElseIf Is64bit*items\item[index]\Value$ = Str(PeekQ(*Value))ElseIf VariableIsHex*items\item[index]\Value$ = Hex(PeekL(*Value), #PB_Long)Else*items\item[index]\Value$ = Str(PeekL(*Value))EndIfEndSelectEndIfEndIfIf Sublevel = 0 ; only the main level is visible when adding!If *items\item[index]\Node = 1Image = VariableGadget_NodeOpenElseImage = VariableGadget_Icons(Type & #TYPEMASK)EndIfgadgetindex = CountGadgetItems(*VariableGadget_Used\Gadget)AddGadgetItem(*VariableGadget_Used\Gadget, gadgetindex, VariableGadget_EntryText(*VariableGadget_Used, index), ImageID(Image))SetGadgetItemData(*VariableGadget_Used\Gadget, gadgetindex, index)EndIf*items\item[index]\Name$ = Space(SubLevel * 3) + *items\item[index]\Name$*VariableGadget_Used\ItemCount + 1EndIfEndProcedure; After a number of VariableGadget_Set() with AutoSync=#False, call this; to update the entire gadget content. (Use this when updating the whole list anyway);Procedure VariableGadget_SyncAll()Shared *VariableGadget_Used.VariableGadget*items.VariableGadget_ItemList = *VariableGadget_Used\ItemsIf *itemsGadget = *VariableGadget_Used\GadgetLast = CountGadgetItems(Gadget) - 1For i = 0 To Lastindex = GetGadgetItemData(Gadget, i)If *items\item[index]\Kind = #TYPE_ARRAY; special handling for array typeSetGadgetItemText(Gadget, i, *items\item[index]\Name$ + "(" + *items\item[index]\Value$ + ")", *VariableGadget_Used\ExtraColumns)ElseSetGadgetItemText(Gadget, i, *items\item[index]\Value,ドル *VariableGadget_Used\ExtraColumns+1)EndIfNext iEndIfEndProcedure; Called internally: Sync only a single item to the gadget display;; NOTE: This is slow for gadgets with a large number of items, that's why; only the watchlist actually uses it. (The VariableViewer does SyncAll());Procedure VariableGadget_SyncItem(ListIndex)Shared *VariableGadget_Used.VariableGadget*items.VariableGadget_ItemList = *VariableGadget_Used\ItemsIf *itemsGadget = *VariableGadget_Used\GadgetLast = CountGadgetItems(Gadget) - 1For i = 0 To Lastindex = GetGadgetItemData(Gadget, i)If index = ListIndex ; found the itemIf *items\item[index]\Kind = #TYPE_ARRAY; special handling for array typeSetGadgetItemText(Gadget, i, *items\item[index]\Name$ + "(" + *items\item[index]\Value$ + ")", *VariableGadget_Used\ExtraColumns)ElseSetGadgetItemText(Gadget, i, *items\item[index]\Value,ドル *VariableGadget_Used\ExtraColumns+1)EndIfBreakEndIfNext iEndIfEndProcedure; set the value for the given variable; (a 0-pointer for *Value empties the field);; AutoSync: If true, directly update the gadget display, if false; this has to be done manually with SyncAll() or SyncItem();Procedure VariableGadget_Set(index, *Value, Is64bit, AutoSync)Shared *VariableGadget_Used.VariableGadget*items.VariableGadget_ItemList = *VariableGadget_Used\ItemsIf *items And index < *VariableGadget_Used\ItemCount And *ValueType = *items\item[index]\TypeIf IS_ARRAY(*items\item[index]\Kind)*items\item[index]\Value$ = PeekAscii(*Value) ; dimensionsElseIf IS_LINKEDLIST(*items\item[index]\Kind)If Is64bitIf PeekQ(*Value) = -1Size$ = "-"ElseSize$ = Str(PeekQ(*Value))EndIfIf PeekQ(*Value+8) = -1Current$ = "-"ElseCurrent$ = Str(PeekQ(*Value+8))EndIfElseIf PeekL(*Value) = -1Size$ = "-"ElseSize$ = Str(PeekL(*Value))EndIfIf PeekL(*Value+4) = -1Current$ = "-"ElseCurrent$ = Str(PeekL(*Value+4))EndIfEndIf*items\item[index]\Value$ = Language("Debugger","Size") + ": " + Size$ + " " + Language("Debugger","Current") + ": " + Current$ElseIf IS_MAP(*items\item[index]\Kind)*items\item[index]\Value$ = Language("Debugger", "Size")+": "If Is64bitIf PeekQ(*Value) = -1*items\item[index]\Value$ + "-"Else*items\item[index]\Value$ + Str(PeekQ(*Value))EndIf*Value + 8ElseIf PeekL(*Value) = -1*items\item[index]\Value$ + "-"Else*items\item[index]\Value$ + Str(PeekL(*Value))EndIf*Value + 4EndIf*items\item[index]\Value$ + " " + Language("Debugger","Current")+": "If PeekB(*Value) ; IsCurrent*items\item[index]\Value$ + Chr(34)+PeekS(*Value+1)+Chr(34) ; in external debugger formatElse*items\item[index]\Value$ + "-"EndIfElseIf IS_POINTER(Type)If Is64bit And VariableIsHex*items\item[index]\Value$ = Hex(PeekQ(*Value), #PB_Quad)ElseIf Is64bit*items\item[index]\Value$ = Str(PeekQ(*Value))ElseIf VariableIsHex*items\item[index]\Value$ = Hex(PeekL(*Value), #PB_Long)Else*items\item[index]\Value$ = Str(PeekL(*Value))EndIfElseSelect Type & #TYPEMASKCase #TYPE_BYTEIf VariableIsHex*items\item[index]\Value$ = Hex(PeekB(*Value), #PB_Byte)Else*items\item[index]\Value$ = Str(PeekB(*Value))EndIfCase #TYPE_ASCIIIf VariableIsHex*items\item[index]\Value$ = Hex(PeekB(*Value) & $FF)Else*items\item[index]\Value$ = Str(PeekB(*Value) & $FF)EndIfCase #TYPE_UNICODEIf VariableIsHex*items\item[index]\Value$ = Hex(PeekW(*Value) & $FFFF)Else*items\item[index]\Value$ = Str(PeekW(*Value) & $FFFF)EndIfCase #TYPE_WORDIf VariableIsHex*items\item[index]\Value$ = Hex(PeekW(*Value), #PB_Word)Else*items\item[index]\Value$ = Str(PeekW(*Value))EndIfCase #TYPE_LONG, #TYPE_CHARACTER ; chars are passed as longsIf VariableIsHex*items\item[index]\Value$ = Hex(PeekL(*Value), #PB_Long)Else*items\item[index]\Value$ = Str(PeekL(*Value))EndIfCase #TYPE_STRING, #TYPE_FIXEDSTRING*items\item[index]\Value$ = Chr(34) + PeekS(*Value) + Chr(34)Case #TYPE_FLOAT*items\item[index]\Value$ = StrF_Debug(PeekF(*Value))Case #TYPE_DOUBLE*items\item[index]\Value$ = StrD_Debug(PeekD(*Value))Case #TYPE_QUADIf VariableIsHex*items\item[index]\Value$ = Hex(PeekQ(*Value), #PB_Quad)Else*items\item[index]\Value$ = Str(PeekQ(*Value))EndIfCase #TYPE_INTEGERIf Is64bit And VariableIsHex*items\item[index]\Value$ = Hex(PeekQ(*Value), #PB_Quad)ElseIf Is64bit*items\item[index]\Value$ = Str(PeekQ(*Value))ElseIf VariableIsHex*items\item[index]\Value$ = Hex(PeekL(*Value), #PB_Long)Else*items\item[index]\Value$ = Str(PeekL(*Value))EndIfEndSelectEndIf; update the text if the item is visible;If AutoSyncVariableGadget_SyncItem(index)EndIfEndIfEndProcedure; set the "Value" field of the given variable to the given string; used to not existing variables (ie out of scope for watchlist);; AutoSync: If true, directly update the gadget display, if false; this has to be done manually with SyncAll() or SyncItem();Procedure VariableGadget_SetString(index, String,ドル AutoSync)Shared *VariableGadget_Used.VariableGadget*items.VariableGadget_ItemList = *VariableGadget_Used\ItemsIf *items And index < *VariableGadget_Used\ItemCount*items\item[index]\Value$ = String$If AutoSyncVariableGadget_SyncItem(index)EndIfEndIfEndProcedure; get the real index in the data list from the gadget index;Procedure VariableGadget_GadgetIndexToReal(Gadget, index)If index = -1ProcedureReturn -1ElseProcedureReturn GetGadgetItemData(Gadget, index)EndIfEndProcedure; returns the index of the current selected item in the full list;Procedure VariableGadget_GetState(Gadget)index = GetGadgetState(Gadget)If index = -1ProcedureReturn -1ElseProcedureReturn GetGadgetItemData(Gadget, index)EndIfEndProcedure; countgadgetitems on th virtual item list;Procedure VariableGadget_GetCount(Gadget)*VariableGadget.VariableGadget = GetGadgetData(Gadget)ProcedureReturn *VariableGadget\ItemCountEndProcedureDataSectionVariableGadget_Byte: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "byte.png"VariableGadget_Word: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "word.png"VariableGadget_Long: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "long.png"VariableGadget_Struct: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "struct.png"VariableGadget_String: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "string.png"VariableGadget_Float: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "float.png"VariableGadget_NodeOpen: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "struct1.png"VariableGadget_NodeClose: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "struct2.png"VariableGadget_Char: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "char.png"VariableGadget_Fixed: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "fixed.png"VariableGadget_Double: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "double.png"VariableGadget_Quad: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "quad.png"VariableGadget_Integer: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "integer.png"VariableGadget_Ascii: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "ascii.png"VariableGadget_Unicode: : IncludeBinary #DEFAULT_DebuggerSource + "Data" + #Separator + "unicode.png"EndDataSection
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。