Page 1 of 1

[Include] Displaying a Balloon-Tip for StringGadgets

Posted: Thu Nov 25, 2010 6:44 am
by PureLust
Attached you will find an include with two small Procedures which enables you to show or hide a Balloon-Tip (or Balloon-Notification) for a String-Gadget.

A Ballon-Tip is not the same as a "normal" Balloon-ToolTip because it has a different Design and can be displayed and hidden anytime, independently from the actual position of the mouse.
Further Balloon-Tips are specially designed to show hints on Edit-Controls (StringGadgets) only.

Balloon-Tips allow you to show Notifications on StringGadgets which are conform to the Windows User Experience Interaction Guidelines:

Image

Image

The Include: "StringGadgetBalloon.pbi"

Code: Select all

;
; Include-File  : StringGadgetBalloon.pbi
;
; Version       : 1.0.4
; Date          : 25.Nov.2010
; Author        : Albert Cremers  (a.k.a PureLust @ Purebasic-Forum)
; PB-Version    : 4.51
;
; Forum-Thread  : http://www.purebasic.fr/english/viewtopic.php?f=12&t=44410
;
;
; Within this include you'll find two Procedures, to show and hide Balloon-Tip (or Balloon-Notifications) for a StringGadget().
;
; A Ballon-Tip is not the same as a Balloon-ToolTip because it is different in Design as well as it can be displayed and hidden anytime.
;
; With StringGadgetBalloon you can show Balloon-Notifications which are conform To the "Windows User Experience Interaction Guidelines" => http://msdn.microsoft.com/en-us/library/aa511451.aspx

; The usage is quite simple:

; use "ShowStringGadgetBalloon(GadgetID, Title.s, Text.s, Icon)" to display the Balloon-Tip
;      - GadgetID can be either the PB-#Gadget or a GadgetID()
;      - Title is the Top-Line, displayed in larger (mostly blue) characters
;      - Text is the Body-Text, displayed in smaller (mostly black) characters
;        Multiple-Line Text can be created by including '#CRLF' within the Text
;      - Icon can be one of the following values: #TTI_NONE, #TTI_INFO, #TTI_WARNING, #TTI_ERROR
;        In Windows-Vista and above you can further use #TTI_INFO_LARGE, #TTI_WARNING_LAGRE, #TTI_ERROR_LARGE, to display Balloon-Tips with larger Icons
;
;      If you show the Balloon-Tip for a StringGadget, it will become the active Gadget and will get the focus.
;      If the StringGadget will lose the focus, the Balloon-Tip for this Gadget will automatically disappear.

; use "HideStringGadgetBalloon(GadgetID)" to hide the Balloon-Tip at any time
;      - GadgetID can be either the PB-#Gadget or a GadgetID()
;

Structure EDITBALLOONTIP
	StructSize.l
	CompilerIf #PB_Compiler_Processor=#PB_Processor_x64 : _pad1.l : CompilerEndIf
	pTitle.i
	pText.i
	Icon.l
	CompilerIf #PB_Compiler_Processor=#PB_Processor_x64 : _pad2.l : CompilerEndIf
EndStructure

; ----- Only usable if OSVersion() >= #PB_OS_Windows_Vista
   #TTI_INFO_LARGE      = 4
   #TTI_WARNING_LARGE   = 5
   #TTI_ERROR_LARGE      = 6
   
Procedure ShowStringGadgetBalloon(GadgetID, Title.s, Text.s, Icon = #TTI_INFO)
   Protected Balloon.EDITBALLOONTIP 
   Protected TitleBuffer.l = StringByteLength(Title, #PB_Unicode) + 2
   Protected TextBuffer.l  = StringByteLength(Text , #PB_Unicode) + 2
   Protected *Buffer = AllocateMemory(TitleBuffer + TextBuffer)
   
   If IsGadget(GadgetID) And Not IsWindow_(GadgetID)     ; If you've passed a #Gadget instead of a GadgetID(), it will be convert automatically.
      GadgetID = GadgetID(GadgetID)
   EndIf
   
   If OSVersion() < #PB_OS_Windows_Vista And Icon > #TTI_ERROR      ; If Large-Icons are not supported by the OS, they will be convert to their smaller version
      Icon - 3
   EndIf
   
   If *Buffer
      Balloon\StructSize = SizeOf(EDITBALLOONTIP)
      PokeS(*Buffer, Title, Len(Title), #PB_Unicode)
      PokeS(*Buffer + TitleBuffer, Text, Len(Text), #PB_Unicode)
      Balloon\pTitle = *Buffer
      Balloon\pText  = *Buffer + TitleBuffer
      Balloon\Icon   = Icon
      SendMessage_(GadgetID, #EM_SHOWBALLOONTIP, 0, @Balloon)
      FreeMemory(*Buffer)
   EndIf
      
EndProcedure

Procedure HideStringGadgetBalloon(GadgetID)
   
   If IsGadget(GadgetID) And Not IsWindow_(GadgetID)     ; If you've passed a #Gadget instead of a GadgetID(), it will be convert automatically.
      GadgetID = GadgetID(GadgetID)
   EndIf
   
   SendMessage_(GadgetID, #EM_HIDEBALLOONTIP, 0, 0)
      
EndProcedure
And a little example-code:

Code: Select all

;
; File          : Demo_StringGadgetBalloon.pb
;
; Version       : 1.2.1
; Date          : 25.Nov.2010
; Author        : Albert Cremers
; PB-Version    : 4.51

XIncludeFile "..\Includes\StringGadgetBalloon.pbi"

If OSVersion() >= #PB_OS_Windows_Vista      ; On OS-Version >= Vista we can use larger Icons as well, so we need a lager Window to demonstrate them
   WinHeight = 210
Else
   WinHeight = 115
EndIf

OpenWindow(0,0,0,300,WinHeight,"StringGadget Balloon-Message", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
StringGadget(0, 5, 35,290,20,"type something")
StringGadget(1, 5, 60,290,20,"type something")
StringGadget(2, 5, 85,290,20,"type something")
ButtonGadget(7, 5,  5,290,20,"Hover mouse here to hide the Balloon-Tip")
SetActiveGadget(0)

If OSVersion() >= #PB_OS_Windows_Vista      ; On OS-Version >= Vista we can use larger Icons as well, so create more Gadgets to demonstrate them
   StringGadget(3,5,135,290,20,"type something")
   StringGadget(4,5,160,290,20,"type something")
   StringGadget(5,5,185,290,20,"type something")
   TextGadget(6,5,115,290,20,"(for Vista and above only)",#PB_Text_Center)
EndIf

Repeat
   Event = WaitWindowEvent()
   If Event = #PB_Event_Gadget
      If EventType() = #PB_EventType_Change
         
         Select EventGadget()
            Case 0
               ShowStringGadgetBalloon(0, "I'm a Balloon-Tip with an Error-Icon ...", "You've just changed my StringGadget at "+FormatDate("%hh:%ii:%ss", Date()) , #TTI_ERROR)
            Case 1
               ShowStringGadgetBalloon(1, "I'm a Balloon-Tip with an Info-Icon ...", "You've just changed my StringGadget at "+FormatDate("%hh:%ii:%ss", Date()) , #TTI_INFO)
            Case 2
               ShowStringGadgetBalloon(2, "I'm a Balloon-Tip with a Warning-Icon ...", "You've just changed my StringGadget at "+FormatDate("%hh:%ii:%ss", Date())+#CRLF$+"And this is a 2nd Line, created with '#CRLF'." , #TTI_WARNING)
            Case 3
               ShowStringGadgetBalloon(3, "I'm a Balloon-Tip with a large Error-Icon ...", "You've just changed my StringGadget at "+FormatDate("%hh:%ii:%ss", Date()) , #TTI_ERROR_LARGE)
            Case 4
               ShowStringGadgetBalloon(4, "I'm a Balloon-Tip with a large Info-Icon ...", "You've just changed my StringGadget at "+FormatDate("%hh:%ii:%ss", Date())+#CRLF$+"And this is a 2nd Line, created with '#CRLF'." , #TTI_INFO_LARGE)
            Case 5
               ShowStringGadgetBalloon(5, "I'm a Balloon-Tip with a large Warning-Icon ...", "You've just changed my StringGadget at "+FormatDate("%hh:%ii:%ss", Date()) , #TTI_WARNING_LARGE)
         EndSelect
         
      EndIf
      
   ElseIf Event = #WM_MOUSEMOVE      ; If the Mouse if above the Button, Hide the Balloon-Tip if an #WM_MOUSEMOVE-Event occurs
      
      If WindowFromPoint_(DesktopMouseY()<<32 | DesktopMouseX()) = GadgetID(7)
         For n = 0 To 5
            HideStringGadgetBalloon(n)
         Next
      EndIf
      
   EndIf

Until Event = #PB_Event_CloseWindow
Maybe it will fit someones needs. Image

[Edit:] Structure adapted to work with x64 as well (with help from cas - big thanks for that),

Re: [Include] Displaying a Balloon-Tip for StringGadgets

Posted: Thu Nov 25, 2010 3:09 pm
by Innesoft
Very useful, thanks for sharing.

Re: [Include] Displaying a Balloon-Tip for StringGadgets

Posted: Thu Nov 25, 2010 5:40 pm
by Rescator
*whips pureLust* common guys/gals, this is the 2nd posting in Tips in a short while where the x86 and x64 compile do not behave the same.
Here on PureBasic x64 the balloontips fail to work at all.

If both the x86 and x64 runs failed then at least the behavior would be consistent :P

Re: [Include] Displaying a Balloon-Tip for StringGadgets

Posted: Thu Nov 25, 2010 7:56 pm
by PureLust
Rescator wrote:Here on PureBasic x64 the balloontips fail to work at all.
Hmmmm, that's interesting ... indeed. Image
Just tested it on Win7-64Bit. Working fine with PB4.51-x86, but it doesn't with PB4.51-x64.

[Edit:] Problem solved. Code above adapted. See [Edit:]-Note.

Re: [Include] Displaying a Balloon-Tip for StringGadgets

Posted: Thu Nov 25, 2010 8:22 pm
by cas
Looks like your structure on x64 is too small, i just checked sizeof(EDITBALLOONTIP) and it is 32 bytes in x64 project in VS, yours is 24bytes in PB x64. Also, take a look at this post: viewtopic.php?p=336162#p336162
freak wrote:Keep this in mind:
All IsXXX() commands are expensive operations, because the only way to validate #PB_Any objects is to look at all of them and see if one matches. That won't matter if you have just two libraries open but if we are talking about a few hundred gadgets or images, things look different. So better don't get into that habit.

In fact: A correctly written program should have no need to call any IsXXX() function ever since you can always tell on object creation whether it succeeded or failed, and you know when you free the object so there is no reason for a confusion of weather an object is valid or not. These functions are a debugging tool, nothing else.
Anyway, thanks for posting this code snippet.

EDIT:
ok, here is structure compatible with x64:

Code: Select all

Macro AddPadding(_padding)
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64 : _padding : CompilerEndIf
EndMacro

Structure EDITBALLOONTIP
  StructSize.l
  AddPadding(_pad1.l)
  pTitle.i
  pText.i
  Icon.l
  AddPadding(_pad2.l)
EndStructure

Re: [Include] Displaying a Balloon-Tip for StringGadgets

Posted: Thu Nov 25, 2010 9:20 pm
by PureLust
cas wrote:Looks like your structure on x64 is too small, i just checked sizeof(EDITBALLOONTIP) and it is 32 bytes in x64 project in VS, yours is 24bytes in PB x64
Relating to MSDN, the Structure seems to be right: Image
cas wrote:Also, take a look at this post: viewtopic.php?p=336162#p336162
If you relay to this:

Code: Select all

   If IsGadget(GadgetID) And Not IsWindow_(GadgetID)     ; If you've passed a #Gadget instead of a GadgetID(), it will be convert automatically.
      GadgetID = GadgetID(GadgetID)
   EndIf
I don't think that this check will affect the system-performance in any noticeable way, especially in a GUI-related Program in which you will use these Balloons.
The system will bore itself anyway with about 1~2% of CPU-Usage while waiting for user input.
At this conditions I'd prefer to immolate a few microseconds, to keep a Proc more easy and more flexible in usage (especially for PB-Beginners, which are maybe confused by handles).

[Edit @cas:] Thanks a lot cas for the very helpful information about the padding. That made it working on x64 as well. Image
(Code in the first posting adapted, seems to work fine now on x64 as well.)