[futurebasic] Re: [FB] Clickable Static Text or something?

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : April 2007 : Group Archive : Group : All Groups

From: Robert Purves <listrp@...>
Date: Wed, 4 Apr 2007 17:20:14 +1200

>> Another possible improvement (not sure if this is HIG approved,  
>> but it would offer the user more feedback) would be to install a  
>> mouse tracking area to change the cursor to a pointing hand (i.e.  
>> SetThemeCursor( _kThemePointingHandCursor )) when over the URL.
>
> Yes, this refinement could be added. Personally I find the  
> (improved) CarbonEvent method sufficiently convincing even without  
> a cursor change.

Steve Van Voorst's modification changes the cursor.

> I was going to work on mouse tracking regions (10.2), but note that  
> they have already been "deprecated" in favor of HIView based  
> tracking regions in 10.4.

Friendly rivalry motivated me to seek out that HIView tracking  
thingummy (whose crucial part turns out to be HIViewNewTrackingArea)  
and add it to my previously posted clickable URL demo.

Robert P.

'---------------------
/*
Clickable URL, using the tracking method of Apple's QA1380.
Robert P.   April 2007

Installing a handler for the appropriate CarbonEvents has
advantages over old programming techniques for clickable URLs
- a click on the link is tracked, and can therefore be
   cancelled by moving the mouse away before releasing the button.
- any number of clickable URLs can be set up without change to
   the rest of the program. A call to MakeClickableURL and you're done.
- nothing needs disposing when the control or window is closed.

This version
- allows link text to be different from the URL.
- displays the link in red while it is tracked.
- shows how to specify the font/size of the link.
- changes cursor when over link (in 10.4 or later).
*/
include "Tlbx HIView.incl"
include "Tlbx CoreGraphics.incl"
include "Tlbx ControlDefinitions.incl"
end globals

_kMyURLTextTag = _"URLT"

// we get here when any link is clicked
local fn DoURLClick( c as ControlRef )
'~'1
dim as Str255 url

// retrieve the url string from the control
call GetControlProperty( c, 0, _kMyURLTextTag, 256, #0, @url )
// The 'open' command is a handy way to open URLs as well as files
open "unix", 222, "open " + url
close 222
end fn


local fn InstallClickableURLHandler( c as ControlRef )
'~'1
dim as EventTypeSpec myEvents(4)
dim as long nEvents
begin globals
dim as proc sURLEventUPP // 'static' var
end globals

// The events we intercept are all for the control
// itself (not its window or other enclosing HIViews).
nEvents = 3
myEvents.eventClass(0) = _kEventClassControl
myEvents.eventKind(0) = _kEventControlHitTest
myEvents.eventClass(1) = _kEventClassControl
myEvents.eventKind(1) = _kEventControlHit
myEvents.eventClass(2) = _kEventClassControl
myEvents.eventKind(2) = _kEventControlDraw

/*
Prepare events and TrackingArea for cursor change.
This refinement requires 10.4 or later.
On older systems the cursor simply won't change.
*/
long if ( system( _sysVers ) >= 1040 )
nEvents = 5
myEvents.eventClass(3) = _kEventClassControl
myEvents.eventKind(3) = _kEventControlTrackingAreaEntered
myEvents.eventClass(4) = _kEventClassControl
myEvents.eventKind(4) = _kEventControlTrackingAreaExited
call HIViewNewTrackingArea( c, 0, 0, 0, #0 )
end if

// allocate a 'universal procedure pointer' pointing to our handler  
enterproc
long if ( sURLEventUPP == 0 )
sURLEventUPP = fn NewEventHandlerUPP( [proc "ClickableURLHandler" +  
_FBprocToProcPtrOffset] )
end if
// install the handler with the array of events
end fn = fn InstallEventHandler( fn GetControlEventTarget( c ),  
sURLEventUPP, nEvents, @myEvents(0), #0, #0 )


long if 0
"ClickableURLHandler"
enterproc fn ClickableURLHandler( nextHandler as EventHandlerCallRef,  
theEvent as EventRef, userData as ptr )
'~'1
dim as OSStatus result, ignore
dim as ControlRef @ c
dim as HIRect bounds
dim as HIPoint pt
dim as ControlPartCode @ part
dim as ControlFontStyleRec cfs

result = _eventNotHandledErr
call GetEventParameter( theEvent, _kEventParamDirectObject,  
_typeControlRef, #0, sizeof( c ), #0, @c )

select fn GetEventKind( theEvent )

case _kEventControlHitTest
// static text control requires this handler in order to track the mouse
call HIViewGetBounds( c, @bounds )
call GetEventParameter( theEvent, _kEventParamMouseLocation,  
_typeHIPoint, #0, sizeof( pt ), #0, @pt )
part = _kControlNoPart
// if mouse over the control, send kControlButtonPart
if ( fn CGRectContainsPoint( bounds, pt ) ) then part =  
_kControlButtonPart
call SetEventParameter( theEvent, _kEventParamControlPart,  
_typeControlPartCode, sizeof( part ), @part )
result = _noErr // we handled the event

case _kEventControlDraw
// Draw the link text either visibly-clickable (blue) or pressed (red).
// Retrieve the existing ControlFontStyleRec
ignore = fn GetControlData( c, _kControlEditTextPart,  
_kControlStaticTextStyleTag, sizeof( cfs ), @cfs, #0 )
// set the foreColor field
long if ( fn GetControlHilite( c ) == _kControlButtonPart )
cfs.foreColor.red = 0xffff // pressed link red
cfs.foreColor.blue = 0
xelse
cfs.foreColor.red = 0
cfs.foreColor.blue = 0xeeee // special "url blue"
end if
cfs.foreColor.green = 0
ignore = fn SetControlFontStyle( c, cfs )
// let the default handler (i.e. The System) draw the text
result = fn CallNextEventHandler( nextHandler, theEvent )

case _kEventControlTrackingAreaEntered
// self-explanatory
call SetThemeCursor( _kThemePointingHandCursor )

case _kEventControlTrackingAreaExited
// self-explanatory
call SetThemeCursor( _kThemeArrowCursor )

case _kEventControlHit
// act on a completed click-and-release, like a button click
fn DoURLClick( c )
result = _noErr // we handled the event

end select
exitproc = result
end if


local fn MakeClickableURL( btnNum as long, linkTxt as Str255, url as  
Str255, r as ^Rect )
'~'1
dim as OSStatus ignore
dim as Rect rCopy
dim as ControlFontStyleRec cfs
dim as ControlRef c

rCopy = r
// make the text control
appearance button btnNum,,,,,, @rCopy, _kControlStaticTextProc

cfs.flags = _kControlUseFaceMask _kControlUseForeColorMask
cfs.style = _ulineBit% // underlined
// uncomment to specify font & size (Courier 12 as a demo)
/*
cfs.flags = cfs.flags || _kControlUseFontMask || _kControlUseSizeMask
cfs.size = 12
cfs.font = _courier
*/
c = button&( btnNum )
ignore = fn SetControlFontStyle( c, cfs )
def SetButtonTextString( btnNum, linkTxt )
call SetControlProperty( c, 0, _kMyURLTextTag, 256, @url )
// install Carbon event handler on the control
fn InstallClickableURLHandler( c )
end fn


dim as Str255 url
dim as Rect r
window 1, "Clickable URLs"

SetRect( r, 20, 15, 380, 35 )
url = "http://developer.apple.com/qa/qa2004/qa1380.html"
fn MakeClickableURL( 1, url, url, r ) // link text and URL are the same

SetRect( r, 20, 55, 130, 75 )
fn MakeClickableURL( 2, "reply to author",  
"mailto:nobody@...", r )

SetRect( r, 20, 95, 110, 115 )
fn MakeClickableURL( 3, "ftp to Apple", "ftp://ftp.apple.com", r )


do
HandleEvents
until 0
'---------------------