Chapter 24
Scanning and Constructing Tooltips 459
Run the following code in-game:
local numSets = GetNumEquipmentSets()
local inSet = {}
for i=1,numSets do
local name, icon, setID = GetEquipmentSetInfo(i)
local items = GetEquipmentSetItemIDs(name)
for slot,item in pairs(items) do
if inSet[item] then
inSet[item] = inSet[item] .. “, “ .. name
else
inSet[item] = name
end
end
end
local function OnTooltipSetItem(self)
local name, link = self:GetItem()
if name then
local equippable = IsEquippableItem(link)
local item = link:match(“Hitem:(%d+)“)
item = tonumber(item)
if not equippable then
-- Do nothing
elseif inSet[item] then
GameTooltip:AddLine(“Equipment Set: “ .. inSet[item], 0.2, 1, i
0.2)
else
GameTooltip:AddLine(“Item not in an equipment set“, 1, 0.2, i
0.2)
end
cleared = true
end
end
GameTooltip:HookScript(“OnTooltipSetItem“, OnTooltipSetItem)
The first section of code loops through all of the equipment sets and creates
astring for each item that lists the sets to which it belongs. The second section
sets an
OnTooltipSetItem
widget script that will be run anytime an item is
displayed in the tooltip. It checks to see which item is being shown, and then
adds a line indicating which equipment sets the item is in, if any.
The last line hooks the
OnTooltipSetItem
script on the contextual tooltip
GameTooltip
. As a result, the script will run anytime you move your
mouse over an item in-game—loot windows, trade windows, and the player
inspect window, for instance. It will not run when you click on an item
link in the chat window because that utilizes the
ItemRefTooltip
,which
hasn’t been hooked here.
Pdf change page order acrobat - re-order PDF pages in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
Support Customizing Page Order of PDF Document in C# Project
how to move pages in a pdf document; reorder pdf page
Pdf change page order acrobat - VB.NET PDF Page Move Library: re-order PDF pages in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
Sort PDF Document Pages Using VB.NET Demo Code
move pages in a pdf; reorder pdf pages in preview
460
Part III
Advanced Addon Techniques
Getting Information from Tooltips
The client API has technical limitations that make some information available
onlyin the various gametooltips.Forexample,noAPI function currentlyexists
that can indicate whether an item is soulbound to the player character—this
information can only be found in the item’s tooltip. This is one of the more
difficult things to do because you have to deal with localized values and can’t
always be sure of the order in which information will appear. For instance,
Figure 24-8 shows three different item tooltips.
Figure 24-8: Example item tooltips
You can see that the bound status of each tooltip appears in the second line
of text in the left-hand column if the itemis bound in some way.The difficulty
is when working with items that aren’t bound because other information will
be in that place.
Accessing Individual Tooltip Lines
Atooltip is just a special sort of frame that contains a series of font strings.
There are two columns in the tooltip and as many lines as needed to display
the information. For the
GameTooltip
and
ItemRefTooltip
(and indeed, any
tooltip that inherits from
GameTooltipTemplate
)frames, these font strings are
regularly named:
GameTooltipTextLeft1
GameTooltipTextLeft2
GameTooltipTextRight1
GameTooltipTextRight2
You can get the contents of the second tooltip line in the left column by
calling
GameTooltipTextLeft2:GetText()
.
.NET PDF Document Viewing, Annotation, Conversion & Processing
Insert, delete PDF pages. Re-order, rotate PDF pages. PDF Read. Print. Support for all the print modes in Acrobat PDF. Print only specified page ranges.
reorder pages in pdf reader; reorder pages of pdf
VB.NET PDF: How to Create Watermark on PDF Document within
create a watermark to PDF file in order to help or image (such as business's logo) on any desired PDF page. And with our PDF Watermark Creator, users need no
how to move pages in pdf converter professional; move pages in pdf document
Chapter 24
Scanning and Constructing Tooltips 461
Checking Soulbound Status
Here you write a simple snippet of code that changes the border color
of the tooltips when an item is soulbound. To accomplish this, use the
OnTooltipSetItem
script to detect items being loaded. Then access the indi-
vidual tooltip lines toseeifthe itemis soulbound,andchange the bordercolor.
Run the following code:
GameTooltip:SetScript(“OnTooltipSetItem“, function(self)
local boundText = GameTooltipTextLeft2:GetText()
if boundText == ITEM_SOULBOUND or
boundText == ITEM_ACCOUNTBOUND then
self:SetBackdropBorderColor(0, 0, 0)
end
end)
Using Global Strings for Localization
You might be tempted to use the strings
Soulbound
and
Account Bound
,but
then your addon will work only on English clients. Instead, this code uses the
globally defined strings
ITEM_SOULBOUND
and
ITEM_ACCOUNTBOUND
.The strings
are defined in
FrameXML/GlobalStrings.lua
as follows:
ITEM_SOULBOUND = “Soulbound“;
ITEM_ACCOUNTBOUND = “Account Bound“;
These localized strings are loaded by the default user interface, and differ
depending on which locale the clientis using. By comparingthetooltipagainst
the global values, you can ensure the code works properly regardless of what
language the user interface is displayed in.
Thebestplace to lookforthe global stringsfor some partof the userinterface
is the
GlobalStrings.lua
file; search bythe contents of thestringused in your
version of the client.
Replacing a Script Instead of Hooking a Script
In this example, the code uses the
SetScript
method to set the widget script
handler on the frame directly, ratherthan using the
HookScript
method. Each
frame can have only one handler for each widget script, so this will overwrite
any script that is already set. It’s generally better to use
HookScript()
for an
addon released to to the public because
SetScript()
may destroy handlers
placed by otheraddons, leading to runtime errors.
You could alter the snippet to use
HookScript()
,but if you want to tweak
it and run it multiple times, you’ll notice that every version of your script that
you run is called every time the tooltip is loaded. If these versions conflict
GIF to PDF Converter | Convert GIF to PDF, Convert PDF to GIF
as easy as printing; Support both single-page and batch Drop image to process GIF to PDF image conversion; Provide filter option to change brightness, color and
how to rearrange pdf pages; how to reorder pdf pages in
JPEG to PDF Converter | Convert JPEG to PDF, Convert PDF to JPEG
It can be used standalone. JPEG to PDF Converter is able to convert image files to PDF directly without the software Adobe Acrobat Reader for conversion.
reorder pages in pdf preview; reorder pages in pdf document
462
Part III
Advanced Addon Techniques
with each other, they might give you very confusing results. In development,
using
SetScript()
is fine, but more often than not you will want to use
HookScript()
.
Summary
In this chapter you learned how tooltips are constructed and how to add
your own information to them. In addition, you were introduced to a simple
technique for scanning information from a game tooltip. In the next chapter,
you learn how to use the secure snippets functionality of secure templates to
take protected action in combat.
PDF to WORD Converter | Convert PDF to Word, Convert Word to PDF
PDF to Word Converter has accurate output, and PDF to Word Converter doesn't need the support of Adobe Acrobat & Microsoft Word.
rearrange pages in pdf; how to move pages in pdf acrobat
TIFF to PDF Converter | Convert TIFF to PDF, Convert PDF to TIFF
PDF to TIFF Converter doesn't require other third-party such as Adobe Acrobat. Completely free for use and upgrade; Easy to convert multi-page PDF files to multi
rearrange pages in pdf document; change pdf page order online
CH A P T E R
25
Taking Protected Action
in Combat
In Chapter 15, you learned how the secure template system protects WoW
game play from being automated through the user interface, by preventing
protected frames from being moved, shown or hidden, created, or having
theirbehaviorchanged during combat. However, several legitimate occasions
exist when it might be desirable for these things to happen during combat; for
instance, if someone’s target dies or is deselected during combat, the target
frame shouldbe hidden,and shown again when the player picks a new target.
The stock target frame can rely on the fact that Blizzard wrote it and its code
is secure, but an addon that wants to provide a similar feature needs to use
adifferent mechanism.
Just beforetheWrath oftheLich King expansion was released,a newsystem
was introduced to allow addons toloadcode of their own forsecureexecution,
and for Blizzard to strictly control what information and actions are available
tocode that is being run securely. These chunks of controlled,authorized code
are referred to as snippets.
Snippets: The Basis of Secure Action
Of course, the whole system of protected game actions is founded on the
principlethataddon codeis ‘‘tainted,’’ andthatsecurecode becomes tainted as
soon asaddon codetriestointerferewithit.Snippetssolvepartof this problem.
How Can Addon Code Be Secure?
Asnippet is a string containing Lua source code, typically stored in a frame
attribute. Because it is stored in a frame attribute, secure code can retrieve it
463
DICOM to PDF Converter | Convert DICOM to PDF, Convert PDF to
Adobe Acrobat or any other print drivers when they use DICOM to PDF Converter. Additionally, high-quality image conversion of DICOM & PDF files in single page
rearrange pages in pdf document; how to rearrange pages in pdf using reader
BMP to PDF Converter | Convert Bitmap to PDF, Convert PDF to BMP
interface; Powerful image converter for Bitmap and PDF files; No need for Adobe Acrobat Reader & print driver during conversion; Support
how to move pages around in pdf file; move pages in pdf acrobat
464
Part III
Advanced Addon Techniques
without becoming tainted; and because that code can remain secure, it can
compile the attribute contents into an executable function that is also secure.
When itcompiles this function,itcan alsorestrictits accesstospecific functions
andvariables so that thesecurefunction can’tuse information thatthe Blizzard
designers don’t want influencing sensitive decisions.
Writing a Snippet
Asnippet is the body of a function, without the
function (args, ...)
and
final
end
tags. These elements are provided by the secure code that compiles
thesnippetintoa usablefunction.Becausemanysnippets emulateframe script
handlers (
OnClick
,
OnShow
,and so on), the argument list is generally the same
as it would be in the equivalentXMLscript
<OnClick>
,
<OnShow>
,and soforth.
Snippets often contain code comprised of quotes, line breaks, and other
characters that normally need to be escaped inside Lua string literals. Because
of this, there is an emerging convention to enclose snippet literals in [[long
brackets,]] which ignore all special characters (except the end of the bracket).
This has the advantage of allowing you to format yourcode in a more natural
fashion, as well as often making it easier for youto distinguish the secure and
insecure parts of your addon code.
You can demo a very simple snippet with the following line:
/run SecureHandlerExecute(PlayerFrame, [[self:Hide()]])
By itself, this isn’t terribly exciting. Insecure code can’t use
SecureHandler
Execute
during combat, and that code could always hide the player frame
directly.
SecureHandlerExecute
ismostlyusedtoperformsetupon morecom-
plex secure handler frames. The real power of snippets and secure execution
comes fromthe ability to attach snippets to frames that will run themsecurely
in response to user input orselected state changes. Before we move on to that,
though, put the player frame back by running the following code (snippets
can be stored in variables as well as in string literals):
local showAction = [[self:Show()]]; i
SecureHandlerExecute(PlayerFrame, showAction)
Secure Handler Frames
To get WoW to compile and run your snippets, you have to store and attach
them correctly. The most common mechanism for this is a set of protected
templates called the secure handlers.
Much the same way as
SecureActionButtonTemplate
provides a secure
function as its
OnClick
handler, these templates each provide one or two
secure functions as various script handlers. Each of these functions looks for
Chapter 25
Taking Protected Action in Combat 465
asnippet in a fixed relevant attribute and executes it when its corresponding
handler is triggered; for example, when someone clicks a button inheriting
from
SecureHandlerClickTemplate
,that button’s
OnClick
function looks for
asnippet in its
_onclick
frame attribute and tries to execute it. Italso passes a
reference to the button clicked and copies of the
button
and
down
arguments
to the script as arguments to the snippet.
Secure handler templates are available formost scripts thatrepresent a user
interaction (
OnClick
,
OnDoubleClick
,
OnMouseUp/OnMouseDown
,
OnMouseWheel
,
OnEnter/OnLeave
, and
OnDragStart/OnReceiveDrag
), as well as scripts for
responding to certain actions that can only be triggered by protected code
(
OnShow/OnHide
and
OnAttributeChanged
),which are discussed in more detail
laterin the chapter.
As an example, you can create an addon that modifies the stock UI’s extra
action bars (the ones that can be turned on around the bottom and right edges
ofthe UI),so that each oneonly appears when you’remousing overit.Because
the frames you have to create will have no visual elements of their own, and
you are primarily trying to interact with existing UI elements, this is easier to
do fromLua. Run the following code in-game:
local mousein = [[
self:GetFrameRef(“subject“):Show()
]]
local mouseout = [[
self:GetFrameRef(“subject“):Hide()
]]
for i, bar in ipairs{MultiBarRight, MultiBarLeft, i
MultiBarBottomRight, MultiBarBottomLeft} do
local watcher = CreateFrame(“Frame“, “ShyBarsWatcher“..i, i
bar:GetParent(), “SecureHandlerEnterLeaveTemplate“)
watcher:SetFrameLevel(bar:GetFrameLevel() - 1)
watcher:SetAllPoints(bar)
bar:SetParent(watcher)
bar:Hide()
watcher:SetAttribute(“_onenter“, mousein)
watcher:SetAttribute(“_onleave“, mouseout)
SecureHandlerSetFrameRef(watcher, “subject“, bar)
end
This code loops over each of the supplemental action bars, and attaches a
frameto each bar that will ‘‘watch’’ formouseoverevents.The only really new
part here is the use of the
SecureHandlerEnterLeaveTemplate
to create the
new frames. This is the template that triggers certain snippets when someone
mouses in or out ofit. The rest ofthe code uses the
SetAllPoints()
methodto
make sure that the frame is watching the same area thatthe bartakes up when
it’s present and makes sure that the watcher frame will not cover its bar when
shown (this could make the action bar difficult to click).
466
Part III
Advanced Addon Techniques
This isn’t a perfect example of making the action bars hide (for instance, if
your mouse leaves the area while being over one of the extra action bars, they
might not hide), but it’s a good first approximation that shows the basics of
the snippets system.
WARNING
The game stores a character’s preferred setting for which action
bars should be shown on the server, and they aren’t available to the client until
the VARIABLES_LOADED eventhas fired. If you were loading this into an addon,
you would want to delay hiding the bars until then, because the stock UI would
reshow them.
Now, let’s break down the two chunks of code that are less familiar. The
mousein
and
mouseout
local variables at the beginning of the file are chunks
of code in string form; that is, snippets.
SetAttribute()
calls attach these
snippets to the attributes that the template’s
OnEnter
and
OnLeave
handlers
will invoke. The other issue is that to make sure that secure snippets can’t
use disallowed information, they are run with a limited version of the global
environment that only includes certain functions, and frames don’t normally
exist there. So, to make the action bar frame that will be shown and hidden
available to the snippets, you have to store it in something called a frame
reference; this is basically a sanitized version of the frame (called a frame
handle, discussed more later), stored in the first frame’s
frameref-subject
attribute (or whatever name you supplied when you set the frame reference).
Because the
_onenter
and
_onleave
scripts will be called with
watcher
as
self
,the frame can then be retrievedwith
self:GetFrameRef(“subject“)
.
Handler Template Reference
The simpler, and more common, secure templates respond directly to vari-
ous sorts of user interaction; these are generally triggered with the mouse, but
somecanalsobetriggeredfromkeybindingactionsbyusing
SetBindingClick
.
Table 25-1shows alistofthevalid templates.Each template in thefirst column
suppliesahandlerfortheframescriptthatcallsthesnippetnamedin thesecond
column, providing the arguments listed in the third column. For these tem-
plates, the arguments provided to the snippetare in the same order, and have
thesamenames,as wouldbesuppliedtotheequivalentscriptelementcontents
in an XML frame definition; that is, an_onclick
snippet receives the same set
of implicit arguments as the code in an
<OnClick>...</OnClick>
element.
The last ‘‘interaction’’ template is slightly more complicated. Dragging a
frame through the
StartMoving()
method call is not a protected operation
(because it is inherently interactive), so
SecureHandlerDragTemplate
is pri-
marily intended for buttons that you can drag things in or out of, such as
customizable action buttons. The
button
argument is the button that was
Chapter 25
Taking Protected Action in Combat 467
held down to initiate the drag action, but the other arguments are the same
information returned by
GetCursorInfo()
—the kind of action or resource
held on the cursor, the identifier or value of the cursor’s contents (such as the
amount of money or the ID of the spell or item), and possible supplemental
information (such as whether a spell is a
“BOOK“
spell or a
“PET“
spell) passed
in vararg argument(s).
Table 25-1: Secure Handler Templates and Their Snippets
TEMPLATE
SNIPPETS
ARGUMENTS
SecureHandler
ClickTemplate
_onclick
self, button, down
SecureHandler
DoubleClickTemplate
_ondoubleclick
self, button, down
SecureHandler
MouseUpDownTemplate
_onmouseup
self, button
_onmousedown
self, button
SecureHandler
MouseWheelTemplate
_onmousewheel
self, delta
SecureHandler
EnterLeaveTemplate
_onenter
self
_onleave
self
SecureHandler
DragTemplate
_ondragstart
self, button, kind, value,
...
_onreceivedrag
self, button, kind, value,
...
SecureHandler
ShowHideTemplate
_onshow
self
_onhide
self
SecureHandler
AttributeTemplate
_onattribute
changed
self, name, value
SecureHandler
StateTemplate
_onstate-*
self, stateid, newstate
Moreover,the
_ondragstart
and
_onreceivedrag
snippets mayusea
return
statement to have the game load the cursor with something new or exchange
its current contents. For instance, if you want to write a button that uses
the action slots to store its content much like the stock buttons do, you
can have the button inherit from both
SecureActionButtonTemplate
and
468
Part III
Advanced Addon Techniques
SecureHandlerDragTemplate
,and use the following snippet in the button’s
_ondragstart
and
_onreceivedrag
attributes:
local pickupAction = [[return “action“, self:GetAttribute(“action“)]]
button:SetAttribute(“_ondragstart“, pickupAction)
button:SetAttribute(“_onreceivedrag“, pickupAction)
Your drag handlers can return any of the following sequences:
return “action“, actionSlot
return “bag“, equippedBag
return “bagslot“, bagID, slotNumber
return “inventory“, inventorySlot
return “item“, name or itemID
return “macro“, name or macroIndex
return “petaction“, petSlot
return “spell“, index, “BOOK“ or “PET“
return “spell“, name or spellID
return “companion“, “MOUNT“ or “CRITTER“, index
return “equipmentset“, name
return “money“, amount
return “merchant“, slot
You can also add
“clear“
to the beginning of any of these lists to clear the
cursor first, such as to pick upthe contents of an action slot without dropping
anythinginto itthatwas already on the cursor.Forinstance,you mightchange
the drag-start handler to
button:SetAttribute(“_ondragstart“, [[return “clear“, “action“, i
self:GetAttribute(“action“)]])
The last group of templates are intended to react to changes in frame
visibilityor attribute values. These changes can be triggered by othersnippets
acting on frames securely, or by state drivers that you have registered for the
frame (discussed in more detail later in the chapter).
Integrating a Click Handler with a Secure Action Button
One other facility offered by
SecureActionButtonTemplate
is the ability to
run click snippets for undefined
“type“
attributes. If, for instance,
button:
GetAttribute(“type“) == “menu“
and
button:GetAttribute(“_menu“)
con-
tains a snippet, the secure action button will run it as a click handler, with
self
,
button
, and
down
arguments. This means that you can intermingle
secure actions with other secure behaviors on a single button by using modi-
fier and mouse button selection. For instance, you can easily create menus for
Documents you may be interested
Documents you may be interested