Text menu: updating check marks

This lesson demonstrates how to update check marks when an item in a menu is selected to un-selected.

The mouseDown message

The mouseDown message is sent when the user clicks. When the user clicks a button menu, the message is sent before the menu is displayed, so if you make changes to the button in the mouseDown handler, the changes appear in the resulting menu. Remember that in LiveCode, menus are usually implemented as buttons:  the button's style and menuMode properties control how it is displayed, and the button's text property is used as the list of menu items.

Cross-platform note: On Mac OS and OS X systems, when the user pulls down a menu in the menu bar, the individual menu buttons don't receive the mouseDown message. Instead, the menu bar group receives the message. If you're writing software for these platforms and you want to automatically update a menu that's in the menu bar, place the mouseDown handler in the menu bar group's script instead of in the button's script. This difference applies only to the menu bar, not to menus in the stack window.

The mouseDown handler

The mouseDown handler works with a button that's set up as a hierarchical menu, with Font, Size, and Color submenus, plus menu items for "Plain", "Bold", "Italic", and "Underline" at the bottom of the menu.

Note: To ensure that this handler can be used either in a button's script or in the script of a group containing the button, the handler refers to the button throughout by name, button "Text", instead of using the me keyword. If you use this handler in the menu button's own script, you can use me instead of button "Text".

The first thing the handler does is remove any checkmarks from the menu. When a menu item is checkmarked, the characters "!c" are placed at the start of that menu item in the button contents. For example, if the second menu item has a checkmark, the second line of the button contents starts with "!c". You checkmark a menu item by adding "!c" at the start of the corresponding line, and remove the checkmark by deleting these characters. By deleting all occurrences of "!c" in the button's contents, we remove all the checkmarks in the menu.

replace "!c" with empty in button "Text"

Checking the current font

Next, the handler searches for the menu item containing the current font, and puts a checkmark in front of that line. To find out what the current font is, the handler uses the form the effective textFont. Remember that all objects inherit font properties from the object's owner, so if the field doesn't have a specific font set, it will inherit the font of its card (and the card inherits from its stack, and finally the main stack inherits from LiveCode). In this case, the field's textFont is empty. However, obviously the text is displayed in some installed font, even if the textFont is inherited from another object. The effective keyword lets us find out what font the field is actually displayed in, regardless of whether it's set for that field or inherited from another object.

## put a checkmark next to the current font:
set the wholeMatches to true
put lineOffset(tab & the effective textFont of field "Example Text",button "Text") into tCurrentFontLine
if tCurrentFontLine is not zero then
	put "!c" before line tCurrentFontLine of button "Text"
end if

Menu items in submenus start with a tab character, so we include the leading tab in the string to find. And to prevent finding the wrong line when we have two font names, one of which is contained in the other (for example, "Courier" and "Courier New"), the handler first sets the wholeMatches property to true. The lineOffset function gets the line number where the font name is found, and we add the characters "!c" to the start of that line to place a checkmark next to that menu item. The handler uses the same procedure to checkmark the correct size and color.

Checking the current style

Finally, the handler checkmarks the current style or styles. This part needs to be handled a little differently, since text can have more than one style (for example, if the text is bold italic, both the "Bold" and "Italic" menu items should be checkmarked). The textStyle of text therefore can include multiple styles, separated by commas. If the textStyle is "plain", the "Plain" menu item is checkmarked; otherwise the handler goes through each of the possible styles and checkmarks those that apply.

put the effective textStyle of field "Example Text" into tStyleList
if tStyleList is "plain" then
	## (4th-from-last line in the menu)
	put "!c" before line -4 of button "Text"
else 
	## may have more than one style checked:
	if "bold" is among the items of tStyleList then 
		put "!c" before line -3 of button "Text"
	end if
      
	if "italic" is among the items of tStyleList then 
		put "!c" before line -2 of button "Text"
	end if
      
	if "underline" is among the items of tStyleList then 
		put "!c" before line -1 of button "Text"
	end if
end if

We could use the same technique with the lineOffset function to find the menu line numbers, but it's not necessary, since we've built the menu so that the four style options are the last four lines of the menu.

The mouseDown handler code

on mouseDown
	local tCurrentFontLine, tCurrentSizeLine, tCurrentColorLine, tStyleList
	## goes in the menu button's script
	## remove old checkmarks:
	replace "!c" with empty in button "Text"
   
	## put a checkmark next to the current font:
	set the wholeMatches to true
	put lineOffset(tab & the effective textFont of field "Example Text",button "Text") into tCurrentFontLine
	if tCurrentFontLine is not zero then
		put "!c" before line tCurrentFontLine of button "Text"
	end if
   
	## put a checkmark next to the current size:
	put lineOffset(tab & the effective textSize of field "Example Text",button "Text") into tCurrentSizeLine
	if tCurrentSizeLine is not zero then
		put "!c" before line tCurrentSizeLine of button "Text"
	end if
   
	## put a checkmark next to the current color:
	put lineOffset(tab & the effective textColor of field "Example Text",button "Text") into tCurrentColorLine
	if tCurrentColorLine is not zero then
		put "!c" before line tCurrentColorLine of button "Text"
	end if
   
	## put checkmarks next to current style(s):
	put the effective textStyle of field "Example Text" into tStyleList
	if tStyleList is "plain" then
		## (4th-from-last line in the menu)
		put "!c" before line -4 of button "Text"
	else 
		## may have more than one style checked:
		if "bold" is among the items of tStyleList then 
			put "!c" before line -3 of button "Text"
		end if
      
		if "italic" is among the items of tStyleList then 
			put "!c" before line -2 of button "Text"
		end if
      
		if "underline" is among the items of tStyleList then 
			put "!c" before line -1 of button "Text"
		end if
	end if
end mouseDown

An alternative

We might have taken a different approach to setting the checkmarks. Instead of updating the menu in a mouseDown handler, we could have instead set the checkmarks in the menuPick handler that responds to choosing a menu item from the menu. For example, if the user chooses "Bold", the same handler that boldfaces the text can add a checkmark next to the "Bold" menu item. That way, the next time the menu was displayed, it would already have been updated.

However, that approach can be less reliable. For example, suppose the application offers some other method of choosing a font, size, style, and color. In this case, you could change the field's font properties without choosing an item from the menu. In this case, the menuPick handler wouldn't be executed, and the menu wouldn't know about the change, so it wouldn't show the properly updated checkmarks. Updating all the checkmarks at the moment the menu is displayed avoids this sort of problem.

Tip: To check the text properties of the selected portion of the field, instead of the entire field, use an expression like the effective textFont of the selectedChunk.

0 Comments

Add your comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.