Listicon With Tooltips Per Line Item

Share your advanced PureBasic knowledge/code with the community.
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Listicon With Tooltips Per Line Item

Post by Xombie »

I used the code from my previous example (right-click header detection) and extended it to include a way to show unique tooltips for any line in a listview control. err... listicon. Whatever :D I also cleaned it up a little bit and added a few dividers and such.

Code: Select all

;- Notes
; -   Coded by Xombie 9/8/2005
; -   Tooltip code provided by Sparkie and Andre (http://forums.purebasic.com/english/viewtopic.php?t=14482&highlight=changetooltip)
;     with a *very* slight modification by me.
; -   Right-click header detection based on code found at (http://groups.google.com/group/microsoft.public.vb.controls/browse_frm/thread/63486daff309aab0/e1ad74ef5b0575b8?lnk=st&q=Displaying+pop-up+menu+on+right-click+ListView&rnum=1&hl=en#e1ad74ef5b0575b8)
;
;- Constants
#LVM_GETHEADER = 4127
;- Structures
Structure HDHITTESTINFO
   pt.POINT
   flags.l
   iItem.l
EndStructure

Enumeration ; Window IDs
   #WindowMain
EndEnumeration

Enumeration ; Menu IDs
   #MenuPrimary
   #MenuPrimaryTest
   #MenuSecondary
   #MenuSecondaryTest
EndEnumeration

Enumeration ; Gadget IDs
   #ListPrimary
   #ListSecondary
   #ButtonClose
EndEnumeration
;- Global Variables
Global TooltipPrimaryRow.l
; Current row containing the tooltip text for our primary listview control.
Global TooltipPrimary.l
; Pointer to the tooltip used in the primary listview control.
Global TooltipSecondaryRow.l
Global TooltipSecondary.l
; Ditto for the secondary listview control.
;/
; I use global variables for these but if you're maintaining a lot of listview controls, you may want to think about
; some sort of structure of something.  Otherwise, it'd get ugly quickly.  Also, you may have a better idea than me
; about how to store these.  I'm just doing this for my example.
;/
;- Tooltip Functions
Procedure.l AddTooltip(Gadget, Tooltext$, maxW) 
  ;--> Remove the #TTS_BALLOON flag in the next line if you want the rectangular Tooltip 
  hToolTip = CreateWindowEx_(0, "ToolTips_Class32", "", #TTS_NOPREFIX | #TTS_BALLOON, 0, 0, 0, 0, 0, 0, GetModuleHandle_(0), 0) 
  SendMessage_(hToolTip, #TTM_SETTIPTEXTCOLOR, GetSysColor_(#COLOR_INFOTEXT), 0) 
  SendMessage_(hToolTip, #TTM_SETTIPBKCOLOR, GetSysColor_(#COLOR_INFOBK), 0) 
  ttAdd.TOOLINFO\cbSize = SizeOf(TOOLINFO) 
  ttAdd\uFlags = #TTF_SUBCLASS | #TTF_IDISHWND 
  ;--> Here's where the multiline comes into play by setting the maxWidth 
  SendMessage_(hToolTip, #TTM_SETMAXTIPWIDTH, 0, maxW) 
  ttAdd\hWnd = WindowID() 
  ttAdd\uId = GadgetID(Gadget) 
  ttAdd\hinst = 0 
  ttAdd\lpszText = @Tooltext$ 
  SendMessage_(hToolTip, #TTM_ADDTOOL, 0, ttAdd) 
  SendMessage_(hToolTip, #TTM_SETDELAYTIME, #TTDT_AUTOPOP, 15000) 
  ;/
  ; SendMessage_(hToolTip, #TTM_UPDATE , 0, 0) 
  ;/
  ; The #TTM_UPDATE forces a redraw of the tooltip - causes it to popup immediate upon creation.  Disabled here so there is some
  ; delay in the initial time required to 'popup'.
  ProcedureReturn hToolTip 
EndProcedure 
Procedure.l RemoveToolTip(hTT.l, Gadget.l) 
  ttRemove.TOOLINFO\cbSize = SizeOf(TOOLINFO) 
  ttRemove\hWnd = WindowID() 
  ttRemove\uId = GadgetID(Gadget) 
  SendMessage_(hTT, #TTM_DELTOOL, 0, ttRemove) 
EndProcedure 
Procedure.l ChangeToolTip(hTT.l, Gadget.l, Tooltext$) 
  ttChange.TOOLINFO\cbSize = SizeOf(TOOLINFO) 
  ttChange\hWnd = WindowID() 
  ttChange\uId = GadgetID(Gadget) 
  ttChange\lpszText = @Tooltext$ 
  SendMessage_(hTT, #TTM_UPDATETIPTEXT, 0, ttChange) 
EndProcedure 
;- Callback
Procedure.l WindowCallback(HandleWindow, Message, wParam, lParam) 
   ; Main form callback procedure.
   HandleHeader.l
   ; Store the handle for the listview control's header.
   *NotifyHeader.NMHDR
   ; Notification message header.
   TestHit.HDHITTESTINFO
   ; Store information about header hit testing.
   IndexColumn.l
   ; Store the column index from our header.
   Protected iLoop.l
   ;
   Protected lResult.l
   ;
   lResult = #PB_ProcessPureBasicEvents 
   ;
   If Message = #WM_SETCURSOR
      ; Event caused when the cursor moves within a window and mouse input is not captured.
      If wParam = GadgetID(#ListPrimary)
         ; wParam returns the handle of the window that generates the event.  Check it against our listview control.
         GetCursorPos_(TestHit\pt)
         ; Retrieve the cursor position.
         ScreenToClient_(wParam, TestHit\pt)
         ; Translate our coordinates to screen coordinates.
         SendMessage_(wParam, #LVM_HITTEST, 0, TestHit)
         ; Retrieve the listview item index.  The call uses the coordinate information we retrieved previously.
         If TestHit\iItem = 0
            ; Over the first row.
            If TooltipPrimary
               ; Tooltip already exists.  Either the tooltip exists for the first row or a different row.
               If TooltipPrimaryRow <> TestHit\iItem
                  ; Tooltip was set to a previous row's text.
                  RemoveToolTip(TooltipPrimary, #ListPrimary)
                  ; Destroy the previous tooltip.
                  TooltipPrimary = AddTooltip(#ListPrimary, "First Row", 200)
                  ; Add the new tooltip.  Notice we don't use the 'changetooltip' function.  By destroying and then adding
                  ; the tooltip again, we assure that the previous tooltip will go away and the new tooltip will popup after a delay.
               EndIf
               ;
            Else
               ; Tooltip does not exist.
               TooltipPrimary = AddTooltip(#ListPrimary, "First Row", 200)
               ; Add the new tooltip.
            EndIf
            ;
         ElseIf TestHit\iItem = 1
            ; Hovering over the second line.
            If TooltipPrimary
               ; Tooltip already exists.  Either the tooltip exists for the second row or a different row.
               If TooltipPrimaryRow <> TestHit\iItem
                  ; Tooltip was set to a previous row's text.
                  RemoveToolTip(TooltipPrimary, #ListPrimary)
                  ; Destroy the previous tooltip.
                  TooltipPrimary = AddTooltip(#ListPrimary, "Second Row", 200)
                  ; Add the new tooltip.  Notice we don't use the 'changetooltip' function.  By destroying and then adding
                  ; the tooltip again, we assure that the previous tooltip will go away and the new tooltip will popup after a delay.
               EndIf
               ;
            Else
               ; Tooltip does not exist.
               TooltipPrimary = AddTooltip(#ListPrimary, "Second Row", 200)
               ; Add the new tooltip.
            EndIf
            ;
         ElseIf TestHit\iItem = 3
            ; Hovering over the fourth line.  Notice we skipped the third line on purpose.
            If TooltipPrimary
               ; Tooltip already exists.  Either the tooltip exists for the fourth row or a different row.
               If TooltipPrimaryRow <> TestHit\iItem
                  ; Tooltip was set to a previous row's text.
                  RemoveToolTip(TooltipPrimary, #ListPrimary)
                  ; Destroy the previous tooltip.
                  TooltipPrimary = AddTooltip(#ListPrimary, "Really super duper long row text so we can check out the wrapping function so nicely provided by Sparkie and Andre.  By the way, this is for the fourth row.  We skipped the third row entirely.  Hello from Xombie ^_^", 200)
                  ; Add the new tooltip.  Notice we don't use the 'changetooltip' function.  By destroying and then adding
                  ; the tooltip again, we assure that the previous tooltip will go away and the new tooltip will popup after a delay.
               EndIf
               ;
            Else
               ; Tooltip does not exist.
               TooltipPrimary = AddTooltip(#ListPrimary, "Really super duper long row text so we can check out the wrapping function so nicely provided by Sparkie and Andre.  By the way, this is for the fourth row.  We skipped the third row entirely.  Hello from Xombie ^_^", 200)
               ; Add the new tooltip.
            EndIf
            ;
         Else
            ; At this point, we should've already checked lines that we *want* to have tooltips.  So now we're either not
            ; hovering over a listview line or we're hovering over a line that has no tooltip.  Remove the current tooltip.
            If TooltipPrimary : TooltipPrimary = RemoveToolTip(TooltipPrimary, #ListPrimary) : TooltipPrimary = 0 : EndIf
            ; Remove the previous tooltip and set our global variable to 0 so we know to recreate it later.
         EndIf
         ;
         TooltipPrimaryRow = TestHit\iItem
         ; Update our global row value so we know whether to destroy or change the current primary listview item text.
      ElseIf wParam = GadgetID(#ListSecondary)
         ; wParam returns the handle of the window that generates the event.  Check it against our listview control.
         GetCursorPos_(TestHit\pt)
         ; Retrieve the cursor position.
         ScreenToClient_(wParam, TestHit\pt)
         ; Translate our coordinates to screen coordinates.
         SendMessage_(wParam, #LVM_HITTEST, 0, TestHit)
         ; Retrieve the listview item index.  The call uses the coordinate information we retrieved previously.
         If TestHit\iItem = 2
            ; Over the third row.
            If TooltipSecondary
               ; Tooltip already exists.  Either the tooltip exists for the first row or a different row.
               If TooltipSecondaryRow <> TestHit\iItem
                  ; Tooltip was set to a previous row's text.
                  RemoveToolTip(TooltipSecondary, #ListSecondary)
                  ; Destroy the previous tooltip.
                  TooltipSecondary = AddTooltip(#ListSecondary, "Congratulations!  You've found the hidden tooltip in the secondary listview control!  You win NO prize!  :D", 200)
                  ; Add the new tooltip.  Notice we don't use the 'changetooltip' function.  By destroying and then adding
                  ; the tooltip again, we assure that the previous tooltip will go away and the new tooltip will popup after a delay.
               EndIf
               ;
            Else
               ; Tooltip does not exist.
               TooltipSecondary = AddTooltip(#ListSecondary, "Congratulations!  You've found the hidden tooltip in the secondary listview control!  You win NO prize!  :D", 200)
               ; Add the new tooltip.
            EndIf
            ;
         Else
            ; At this point, we should've already checked lines that we *want* to have tooltips.  So now we're either not
            ; hovering over a listview line or we're hovering over a line that has no tooltip.  Remove the current tooltip.
            If TooltipSecondary : TooltipSecondary = RemoveToolTip(TooltipSecondary, #ListSecondary) : TooltipSecondary = 0 : EndIf
            ; Remove the previous tooltip and set our global variable to 0 so we know to recreate it later.
         EndIf
         ;
         TooltipSecondaryRow = TestHit\iItem
         ; Update our global row value so we know whether to destroy or change the current secondary listview item text.
      EndIf
      ;
   ElseIf Message = #WM_NOTIFY
      ; Received a notify event.  Usually passed to the parent container for a control.
      *NotifyHeader = lParam
      ; Receive the message header information passed by the notify event.
      If *NotifyHeader\code = #NM_RCLICK
         ; Right-click event was received.
         GetCursorPos_(TestHit\pt)
         ; Retrieve the cursor position.
         ScreenToClient_(*NotifyHeader\hwndFrom, TestHit\pt)
         ; Translate our coordinates to screen coordinates.
         IndexColumn = SendMessage_(*NotifyHeader\hwndFrom, #HDM_HITTEST, 0, TestHit)
         ; Retrieve the column index from our header control.  The call uses the coordinate information we retrieved previously.
         If *NotifyHeader\hwndFrom = SendMessage_(GadgetID(#ListPrimary), #LVM_GETHEADER, 0, 0)
            ; Test if the header clicked is from the 'primary' listview control.  #LVM_GETHEADER returns the handle to the header
            ; control used in the listview control.  This is the same handle used as part of the NMHDR (*messageheader) variable.
            If IndexColumn = 0
               ; Right-clicked on the first column.
               HoldNumber.s = InputRequester("Number Search", "Please enter a number to search for (eg., '1', '2', '3' or '4')", "")
               ; For our test, prompt the user for a number used in the primary listview control.  We'll search for it.
               For iLoop = 0 To CountGadgetItems(#ListPrimary) - 1
                  ; Loop through the number of items in our primary listview control.
                  If HoldNumber = GetGadgetItemText(#ListPrimary, iLoop, 0)
                     ; Check if the entered number is the same as the one in the listview.
                     SetGadgetItemState(#ListPrimary, iLoop, #PB_ListIcon_Selected)
                     ; Select the item.
                     SendMessage_(GadgetID(#ListPrimary), #LVM_ENSUREVISIBLE, iLoop, #False)
                     ; Make sure the newly selected item is visible.  Not useful in this example but only if we have many more items.
                     Break
                     ; We found the item.  Break from our loop.
                  EndIf
                  ;
               Next iLoop
               ;
            ElseIf IndexColumn = 1
               ; User right-clicked on the second column.
               DisplayPopupMenu(#MenuPrimary, WindowID())
               ; Display a popup menu.
            EndIf 
            ;
         ElseIf *NotifyHeader\hwndFrom = SendMessage_(GadgetID(#ListSecondary), #LVM_GETHEADER, 0, 0)
            ;
            If IndexColumn = 0
               ; Right-clicked on the first column.
               DisplayPopupMenu(#MenuSecondary, WindowID())
               ; Display a popup menu.
            ElseIf IndexColumn = 2
               ; Right-clicked on the first column.
               HoldString.s = InputRequester("Text Search", "Please enter text to search in the 3rd column (eg. 'fo').", "")
               ; For our test, prompt the user for a number used in the primary listview control.  We'll search for it.
               For iLoop = 0 To CountGadgetItems(#ListSecondary) - 1
                  ; Loop through the number of items in our primary listview control.
                  If FindString(LCase(GetGadgetItemText(#ListSecondary, iLoop, 2)), LCase(HoldString), 1)
                     ; Check if the 3rd column contains the text we search for.
                     SetGadgetItemState(#ListSecondary, iLoop, #PB_ListIcon_Selected)
                     ; Select the item.
                     SendMessage_(GadgetID(#ListSecondary), #LVM_ENSUREVISIBLE, iLoop, #False)
                     ; Make sure the newly selected item is visible.  Not useful in this example but only if we have many more items.
                     Break
                     ; We found the item.  Break from our loop.
                  EndIf
                  ;
               Next iLoop
               ;
            EndIf
            ;
         EndIf
         ;
      EndIf
      ;
   EndIf
   ;
   ProcedureReturn lResult
   ;
EndProcedure
;- Main Program Start
EventID.l
; Variable to hold the window message.
DoQuit.b
; Variable to control whether we quit the window or not.  Automatically set to #False.
If OpenWindow(#WindowMain, 0, 0, 400, 120, #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_TitleBar, "Listview Header Test")
   ; Create the main window.
   If CreateGadgetList(WindowID())
      ;
      AdvancedGadgetEvents(#True)
      ; Enable advanced gadget events.
      ListIconGadget(#ListPrimary, 0, 0, 200, 100, "First", 50, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_FullRowSelect | #PB_ListIcon_GridLines)
      ; Create our primary listview control.
      ListIconGadget(#ListSecondary, GadgetX(#ListPrimary) + GadgetWidth(#ListPrimary) + 1, GadgetY(#ListPrimary), 200, 100, "First", 50, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_FullRowSelect | #PB_ListIcon_GridLines)
      ; Create our secondary listview control.
      ButtonGadget(#ButtonClose, GadgetX(#ListSecondary) + GadgetWidth(#ListSecondary) - 100, GadgetY(#ListSecondary) + GadgetHeight(#ListSecondary) + 1, 100, 20, "Close")
      ; Create our close button.
   EndIf
   ;
   SetWindowCallback(@WindowCallback()) 
   ; Set the main window callback.
   AddGadgetColumn(#ListPrimary, 1, "Second", 50)
   AddGadgetColumn(#ListPrimary, 2, "Third", 50)
   ; Add some dummy columns to our primary listicon.
   AddGadgetColumn(#ListSecondary, 1, "Second", 50)
   AddGadgetColumn(#ListSecondary, 2, "Third", 50)
   ; Add some dummy columns to our secondary listicon.
   If CreatePopupMenu(#MenuPrimary)
      ; Create the popup menu used on our primary listview.
      MenuItem(#MenuPrimaryTest, "Show Primary Header Info")
      ; Create a test sub-menu item.
   EndIf
   ;
   If CreatePopupMenu(#MenuSecondary)
      ; Create the popup menu used on our secondary listview.
      MenuItem(#MenuSecondaryTest, "Show Secondary Header Info")
      ; Create a test sub-menu item.
   EndIf
   ;
   AddGadgetItem(#ListPrimary, -1, "1" + Chr(10) + "One" + Chr(10) + "This")
   AddGadgetItem(#ListPrimary, -1, "2" + Chr(10) + "Two" + Chr(10) + "is")
   AddGadgetItem(#ListPrimary, -1, "3" + Chr(10) + "Three" + Chr(10) + "a")
   AddGadgetItem(#ListPrimary, -1, "4" + Chr(10) + "Four" + Chr(10) + "test.")
   ; Add some items to our primary listview control.
   AddGadgetItem(#ListSecondary, -1, "1978" + Chr(10) + "The" + Chr(10) + "quick")
   AddGadgetItem(#ListSecondary, -1, "2001" + Chr(10) + "brown" + Chr(10) + "fox")
   AddGadgetItem(#ListSecondary, -1, "2005" + Chr(10) + "jumped" + Chr(10) + "over")
   AddGadgetItem(#ListSecondary, -1, "2050" + Chr(10) + "the" + Chr(10) + "two")
   AddGadgetItem(#ListSecondary, -1, "3009" + Chr(10) + "lazy" + Chr(10) + "dogs.")
   ; Add some items to our secondary listview control.
   Repeat
      ;
      EventID = WaitWindowEvent()
      ;
      If EventID = #PB_Event_CloseWindow
         ; Close the program.
         DoQuit = #True
         ;
      ElseIf EventID = #PB_Event_Menu
         ; Menu Events
         If EventMenuID() = #MenuPrimaryTest
            ;
            MessageRequester("Primary Test", "The user clicked the second column in the primary listview control.", #PB_MessageRequester_Ok)
            ;
         ElseIf EventMenuID() = #MenuSecondaryTest
            ;
            MessageRequester("Secondary Test", "The user clicked the first column in the secondary listview control.", #PB_MessageRequester_Ok)
            ;
         EndIf
         ;
      ElseIf EventID = #PB_Event_Gadget
         ; Control Events
         If EventGadgetID() = #ButtonClose And EventType() = #PB_EventType_LeftClick : DoQuit = #True : EndIf
         ; Clicked the close button, close the window.
      EndIf
      ;
   Until DoQuit = #True
   ;
EndIf
So, this should should unique tooltips for the two listviews. The first listview has tooltips only for rows 1, 2 and 4. I skipped row 3 so you can see that you control which rows contain the tooltip. Hover over row 3 and you can see what happens. There's a tooltip for the second listview but it's "hidden" so good luck finding it :D

I tried to give credit where credit is due on the original tooltip functions so correct me if I missed something. I also tried to add decent comments so you can understand what's happening and how to adapt for your code.

Hope this helps! ^_^

EDIT:

Incidentally, you can tweak the tooltip in order to add some additional delays. In the AddTooltip() function look for the line...

Code: Select all

SendMessage_(hToolTip, #TTM_SETDELAYTIME, #TTDT_AUTOPOP, 15000)
That determines (in milliseconds) how long the tooltip will be shown. So when the tooltip is displayed, it will be active for 15 seconds before going away.

You can add the next two lines to gain more control over the tooltip.

Code: Select all

SendMessage_(hToolTip, #TTM_SETDELAYTIME, #TTDT_INITIAL, 2000)
SendMessage_(hToolTip, #TTM_SETDELAYTIME, #TTDT_RESHOW, 1000)
TTDT_INITIAL is how much time to allow before the tooltip is displayed. In this example, the tooltip will display after you hover the mouse stationery for 2 seconds (2000 ms). TTDT_RESHOW is how much time to allow before showing it again. For example, if you move the mouse and it vanishes, it will show again after 1 second (1000 ms).

These are pretty good values to keep so you don't get immediate tooltip popups.
Blade
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Aug 06, 2003 2:49 pm
Location: Venice - Italy, Japan when possible.
Contact:

Post by Blade »

Great, with detailed comments too! :)
SoulReaper
Enthusiast
Enthusiast
Posts: 372
Joined: Sun Apr 03, 2005 2:14 am
Location: England

Post by SoulReaper »

hello Xombie :)

Great work I enjoyed looking at this very much :) :lol:
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

wonderful contribution - many thanks
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

Xombie,

Really nice job. Thnx
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Post by Xombie »

Here's a pretty big update to this code.

http://www.seijin.net/Storage/Code/Tips/xTips.pb

xTips.pb is the code to actually handle tooltips for listicons.

http://www.seijin.net/Storage/Code/Tips/Main.pb

Main.pb is the test form I use.

Now all you have to do to add a tooltip to ... say... line 2

Code: Select all

ttAdd(#WindowMain, #ListPrimary, 1, -1, "PureBasic Is Great!", 250)
And now you'll have a tooltip on line 2 (index 0 so line 2 is "1"). To add a tooltip to line 3 in the same list just call...

Code: Select all

ttAdd(#WindowMain, #ListPrimary, 2, -1, "New Tooltip", 250)
And you'll now have two tooltips for that listicon. You can add as many as you want and they will be handled by the code.

There is also a special case where if you set row to "-1" and a positive column value. I call this autotext. If you do this...

Code: Select all

ttAdd(#WindowMain, #ListSecondary, -1, 2, "The text is '{%1}'.", 250)
"{%1}" will be replaced with whatever is in column 2 (remember 0 index) of the listicon. You only call this version once per listicon as it will give a tooltip for every row and only the text for {%1} will change.

This was primarily for Fangles (Hi!) but I will also be able to use it a lot in my project. There are three ways to remove tooltips. You can remove one single tooltip, all the tooltips for a listicon or every single tooltip stored. Take a look at Main.pb for how it all works.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4789
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

???

Post by Fangbeast »

And what was I supposed to do with it???????
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Re: ???

Post by Xombie »

Fangbeast wrote:And what was I supposed to do with it???????
You know... stuff >_> Important stuff <_<

So, I updated this code to add two new things.

#1 - Now has the ability to set tooltips per cell in the listicon.
#2 - A text callback feature. This tells the listicon to call a special user defined function that tells the listicon what tooltip text to use.

For #2, the tooltip functions will call your function and pass the row/column currently under the cursor. You could then have your function run some code to make some custom tooltip based on several columns or other fields that you want. This way you can have custom tooltips without having to add a tooltip to the array for every single line and column. Saves space and lets you do all kinds of neat tooltips.

#1 would be useful for a lot of things. One that comes to mind is if (say) you were making a grid control out of a listicon and want to add notes to each "cell". Or whatever.

So... I left the code for this at work. If anyone is interested in these functions, I'll update the code here. Otherwise, no worries. I'll just keep it for myself :D

Happy New Year :)
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Very nice, Mr Xombie!
@}--`--,-- A rose by any other name ..
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4789
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Post by Fangbeast »

Okay damn it, I get the hint!!! I'll try to add it to my appointment manager first (grumble, moan, whinge a lot)


:lol: :lol: :lol:

*EDIT* Is the custom callback code in there? Was going to try it out but don't know where to look
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Post by Xombie »

Okay! Another update. I finally got around to uploading the code I was talking about.

Now there are four different ways you can create a listicon tooltip.

#1: You can create a tooltip for the entire row by simply setting row to 0 or greater and column to -1.

Code: Select all

ttAdd(#WindowMain, #ListPrimary, 0, -1, "First Row ToolTip", 250)
#2: You can create a tooltip for a specific cell (column and row) by setting both column and row to 0 or greater.

Code: Select all

ttAdd(#WindowMain, #ListPrimary, 0, 1, "Row 1 Column 2 Tooltip", 250)
#3: Use the text from a specific column as the tooltip. This is accomplished by setting row to -1 and column to greater than or equal to 0. This could be useful for columns that contain a lot of text but not enough space to display and you just want to display the whole line.

Code: Select all

ttAdd(#WindowMain, #ListPrimary, -1, 1, "", 250)
#4: Ask the "library" to request the text. This is accomplished by setting both column and row to -1 and then calling ttAddTextCallback() to set a custom function to generate text. The library will call your function and pass the gadget id, column and row currently under the mouse cursor. You then pass back the string you would like to display as a tooltip.

Code: Select all

   ttAdd(#WindowMain, #ListSecondary, -1, -1, "", 250)
ttAddTextCallback(#ListSecondary, @fMainCustomText())
And then your example callback function might look like this.

Code: Select all

Procedure fMainCustomText(Row.l, Column.l, *Text.l, *MaximumWidth.l)
   ;
   HoldString.s
   ;
   HoldString = GetGadgetItemText(#ListSecondary, Row, Column)
   ;
   PokeL(*MaximumWidth, 250)
   ;
   PokeS(*Text, "The text under the cursor is '"+HoldString+"'")
   ;
EndProcedure
You can use whatever function name you like but unless you modify xTips.pb then you must have 4 parameters of the type shown. Also notice that the address of the string is passed so you must PokeS() the text into the string.

Hope that works for everyone interested!

http://www.seijin.net/Storage/Code/Tips/xTips.pb
http://www.seijin.net/Storage/Code/Tips/Main.pb

Download from there ^

:D
Sub-Routine
User
User
Posts: 82
Joined: Tue May 03, 2005 2:51 am
Location: Wheeling, Illinois, USA
Contact:

Post by Sub-Routine »

Thank you very much!

Rand
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Listicon With Tooltips Per Line Item

Post by rsts »

Mr Xombie,

If the aforementioned download still available somewhere?

cheers
Randy Walker
Addict
Addict
Posts: 989
Joined: Sun Jul 25, 2004 4:21 pm
Location: USoA

Re: Listicon With Tooltips Per Line Item

Post by Randy Walker »

Wowww!!! I guess so, but sooooo much code, and callbacks, and stuff, and other things :shock:
How about a simpler less elegant solution?... without callback and stuff and other things? :wink:

Code: Select all

Define.l
Import ""
  PB_Object_GetThreadMemory(*mem)
  PB_Gadget_Globals.i
EndImport

Procedure.s SetToolTipText(id,NewText.s) 
  Protected Buffer.s,ti.TOOLINFO 
  Protected win_info.i
  
  win_info = PB_Object_GetThreadMemory(PB_Gadget_Globals)
  
  Buffer      = NewText.s
  ti\cbSize   = SizeOf(TOOLINFO) 
  ti\hwnd     = PeekI(win_info)
  ti\uId      = GadgetID(id) 
  ti\lpszText = @Buffer
  
  SendMessage_(PeekI(win_info + 24),#TTM_UPDATETIPTEXT,0,@ti) 
  
  ProcedureReturn Buffer    
EndProcedure 
; 
#MyWindow = 0
#MyGadget = 1
Global re.RECT
Global p.POINT
Procedure IsMouseOver(wnd)
  GetWindowRect_(wnd,re)
  ; GetWindowRect_(wnd,re.RECT)
  ; re\left = re\left
  ; re\top  = re\top
  ; re\right  = re\right
  ; re\bottom  = re\bottom
  GetCursorPos_(@p.POINT)
  Result = PtInRect_(re,p.POINT)
  ProcedureReturn Result
EndProcedure
hwnd= OpenWindow(#MyWindow,100,100,500,400,"ListIcon Example",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CreateStatusBar(0,hwnd)
AddStatusBarField(100)
AddStatusBarField(100)

If CreateGadgetList(hwnd)
  LIG_Yval = 100
  hGad=ListIconGadget(#MyGadget,100,LIG_Yval,390,90,"Name",100,#PB_ListIcon_FullRowSelect|#PB_ListIcon_GridLines|#PB_ListIcon_AlwaysShowSelection)
  AddGadgetColumn(#MyGadget,1,"Address",250)
  AddGadgetItem(#MyGadget,-1,"Harry Rannit"+Chr(10)+"12 Parliament Way, Battle Street, By the Bay")
  AddGadgetItem(#MyGadget,-1,"Ginger Brokeit"+Chr(10)+"130 PureBasic Road, BigTown, CodeCity")
  AddGadgetItem(#MyGadget,-1,"Docter Sewdit"+Chr(10)+"101 PureBasic Road, SameTown, CodeCity")
  AddGadgetItem(#MyGadget,-1,"Harry Fainted"+Chr(10)+"86 PureBasic Road, FuzzyTown, CodeCity")
  GadgetToolTip(#MyGadget, "This is my tip.")
  lastLine = 6969 ; arbitrary dummy value to get things rolling below
  
  Repeat
    Ev = WindowEvent()
    GetCursorPos_(@CursorPosition.POINT) 
    a1.l = WindowFromPoint_(CursorPosition\y<<  32 + CursorPosition\x) ;where on the screen?
    If a1 = hGad  ;  using a1 to validate mouse inside #MyGadget
      y = ((WindowMouseY(#MyWindow)) - LIG_Yval)
      If y > 19 ; Adjust y value to compensate for column_header_height
        y - 20  ; Adjust y value to compensate for column_header_height 
        itemLine = y / 14  ; Divide y by pixel_height given to single_line_item.
        If lastLine <> itemLine ; Anti-Flicker -- update tooltip only if required
          If itemLine < CountGadgetItems(#MyGadget) ; Range restriction
            s$ = GetGadgetItemText(#MyGadget, itemLine , 1)
          Else ; out of range
            s$ = "This line is blank"
          EndIf
          Debug itemLine
          SetToolTipText(#MyGadget,s$)
        EndIf
        lastLine = itemLine
      EndIf
    EndIf
  Until Ev = #PB_Event_CloseWindow And EventWindow() = #MyWindow
EndIf 
Hey!!! Before you say anything... I did says a less elegant solution :lol:
- - - - - - - - - - - - - - - -
Randy
I *never* claimed to be a programmer.
quasiperfect
Enthusiast
Enthusiast
Posts: 157
Joined: Tue Feb 13, 2007 6:16 pm
Location: Romania
Contact:

Re: Listicon With Tooltips Per Line Item

Post by quasiperfect »

can someone please repost @Xombie's code (files) ?
Registered user of PureBasic
Post Reply